suricata
runmode-af-packet.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-2016 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \ingroup afppacket
20  *
21  * @{
22  */
23 
24 /**
25  * \file
26  *
27  * \author Eric Leblond <eric@regit.org>
28  *
29  * AF_PACKET socket runmode
30  *
31  */
32 
33 #include "suricata-common.h"
34 #include "config.h"
35 #include "tm-threads.h"
36 #include "conf.h"
37 #include "runmodes.h"
38 #include "runmode-af-packet.h"
39 #include "output.h"
40 #include "log-httplog.h"
41 #include "detect-engine-mpm.h"
42 
43 #include "alert-fastlog.h"
44 #include "alert-prelude.h"
45 #include "alert-unified2-alert.h"
46 #include "alert-debuglog.h"
47 
48 #include "flow-bypass.h"
49 
50 #include "util-debug.h"
51 #include "util-time.h"
52 #include "util-cpu.h"
53 #include "util-affinity.h"
54 #include "util-device.h"
55 #include "util-runmodes.h"
56 #include "util-ioctl.h"
57 #include "util-ebpf.h"
58 
59 #include "source-af-packet.h"
60 
61 extern int max_pending_packets;
62 
63 static const char *default_mode_workers = NULL;
64 
65 const char *RunModeAFPGetDefaultMode(void)
66 {
67  return default_mode_workers;
68 }
69 
71 {
73  "Single threaded af-packet mode",
76  "Workers af-packet mode, each thread does all"
77  " tasks from acquisition to logging",
79  default_mode_workers = "workers";
81  "Multi socket AF_PACKET mode. Packets from "
82  "each flow are assigned to a single detect "
83  "thread.",
85  return;
86 }
87 
88 
89 #ifdef HAVE_AF_PACKET
90 
91 static void AFPDerefConfig(void *conf)
92 {
93  AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf;
94  /* Pcap config is used only once but cost of this low. */
95  if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) {
96  SCFree(pfp);
97  }
98 }
99 
100 /* if cluster id is not set, assign it automagically, uniq value per
101  * interface. */
102 static int cluster_id_auto = 1;
103 
104 /**
105  * \brief extract information from config file
106  *
107  * The returned structure will be freed by the thread init function.
108  * This is thus necessary to or copy the structure before giving it
109  * to thread or to reparse the file for each thread (and thus have
110  * new structure.
111  *
112  * \return a AFPIfaceConfig corresponding to the interface name
113  */
114 static void *ParseAFPConfig(const char *iface)
115 {
116  const char *threadsstr = NULL;
117  ConfNode *if_root;
118  ConfNode *if_default = NULL;
119  ConfNode *af_packet_node;
120  const char *tmpclusterid;
121  const char *tmpctype;
122  const char *copymodestr;
123  intmax_t value;
124  int boolval;
125  const char *bpf_filter = NULL;
126  const char *out_iface = NULL;
127  int cluster_type = PACKET_FANOUT_HASH;
128  const char *ebpf_file = NULL;
129 
130  if (iface == NULL) {
131  return NULL;
132  }
133 
134  AFPIfaceConfig *aconf = SCCalloc(1, sizeof(*aconf));
135  if (unlikely(aconf == NULL)) {
136  return NULL;
137  }
138 
139  strlcpy(aconf->iface, iface, sizeof(aconf->iface));
140  aconf->threads = 0;
141  SC_ATOMIC_INIT(aconf->ref);
142  (void) SC_ATOMIC_ADD(aconf->ref, 1);
143  aconf->buffer_size = 0;
144  aconf->cluster_id = 1;
145  aconf->cluster_type = cluster_type | PACKET_FANOUT_FLAG_DEFRAG;
146  aconf->promisc = 1;
148  aconf->DerefFunc = AFPDerefConfig;
149  aconf->flags = AFP_RING_MODE;
150  aconf->bpf_filter = NULL;
151  aconf->ebpf_lb_file = NULL;
152  aconf->ebpf_lb_fd = -1;
153  aconf->ebpf_filter_file = NULL;
154  aconf->ebpf_filter_fd = -1;
155  aconf->out_iface = NULL;
156  aconf->copy_mode = AFP_COPY_MODE_NONE;
157  aconf->block_timeout = 10;
158  aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER;
159 
160  if (ConfGet("bpf-filter", &bpf_filter) == 1) {
161  if (strlen(bpf_filter) > 0) {
162  aconf->bpf_filter = bpf_filter;
163  SCLogConfig("Going to use command-line provided bpf filter '%s'",
164  aconf->bpf_filter);
165  }
166  }
167 
168  /* Find initial node */
169  af_packet_node = ConfGetNode("af-packet");
170  if (af_packet_node == NULL) {
171  SCLogInfo("unable to find af-packet config using default values");
172  goto finalize;
173  }
174 
175  if_root = ConfFindDeviceConfig(af_packet_node, iface);
176  if_default = ConfFindDeviceConfig(af_packet_node, "default");
177 
178  if (if_root == NULL && if_default == NULL) {
179  SCLogInfo("unable to find af-packet config for "
180  "interface \"%s\" or \"default\", using default values",
181  iface);
182  goto finalize;
183  }
184 
185  /* If there is no setting for current interface use default one as main iface */
186  if (if_root == NULL) {
187  if_root = if_default;
188  if_default = NULL;
189  }
190 
191  if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) {
192  aconf->threads = 0;
193  } else {
194  if (threadsstr != NULL) {
195  if (strcmp(threadsstr, "auto") == 0) {
196  aconf->threads = 0;
197  } else {
198  aconf->threads = atoi(threadsstr);
199  }
200  }
201  }
202 
203  if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) {
204  if (strlen(out_iface) > 0) {
205  aconf->out_iface = out_iface;
206  }
207  }
208 
209  if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval) == 1) {
210  if (!boolval) {
211  SCLogConfig("Disabling mmaped capture on iface %s",
212  aconf->iface);
213  aconf->flags &= ~(AFP_RING_MODE|AFP_TPACKET_V3);
214  }
215  }
216 
217  if (aconf->flags & AFP_RING_MODE) {
218  (void)ConfGetChildValueBoolWithDefault(if_root, if_default,
219  "mmap-locked", (int *)&boolval);
220  if (boolval) {
221  SCLogConfig("Enabling locked memory for mmap on iface %s",
222  aconf->iface);
223  aconf->flags |= AFP_MMAP_LOCKED;
224  }
225 
226  if (ConfGetChildValueBoolWithDefault(if_root, if_default,
227  "tpacket-v3", (int *)&boolval) == 1)
228  {
229  if (boolval) {
230  if (strcasecmp(RunmodeGetActive(), "workers") == 0) {
231 #ifdef HAVE_TPACKET_V3
232  SCLogConfig("Enabling tpacket v3 capture on iface %s",
233  aconf->iface);
234  aconf->flags |= AFP_TPACKET_V3;
235 #else
236  SCLogNotice("System too old for tpacket v3 switching to v2");
237  aconf->flags &= ~AFP_TPACKET_V3;
238 #endif
239  } else {
241  "tpacket v3 is only implemented for 'workers' runmode."
242  " Switching to tpacket v2.");
243  aconf->flags &= ~AFP_TPACKET_V3;
244  }
245  } else {
246  aconf->flags &= ~AFP_TPACKET_V3;
247  }
248  }
249 
250  (void)ConfGetChildValueBoolWithDefault(if_root, if_default,
251  "use-emergency-flush", (int *)&boolval);
252  if (boolval) {
253  SCLogConfig("Enabling ring emergency flush on iface %s",
254  aconf->iface);
255  aconf->flags |= AFP_EMERGENCY_MODE;
256  }
257  }
258 
259  aconf->copy_mode = AFP_COPY_MODE_NONE;
260  if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
261  if (aconf->out_iface == NULL) {
262  SCLogInfo("Copy mode activated but no destination"
263  " iface. Disabling feature");
264  } else if (!(aconf->flags & AFP_RING_MODE)) {
265  SCLogInfo("Copy mode activated but use-mmap "
266  "set to no. Disabling feature");
267  } else if (strlen(copymodestr) <= 0) {
268  aconf->out_iface = NULL;
269  } else if (strcmp(copymodestr, "ips") == 0) {
270  SCLogInfo("AF_PACKET IPS mode activated %s->%s",
271  iface,
272  aconf->out_iface);
273  aconf->copy_mode = AFP_COPY_MODE_IPS;
274  if (aconf->flags & AFP_TPACKET_V3) {
275  SCLogWarning(SC_ERR_RUNMODE, "Using tpacket_v3 in IPS mode will result in high latency");
276  }
277  } else if (strcmp(copymodestr, "tap") == 0) {
278  SCLogInfo("AF_PACKET TAP mode activated %s->%s",
279  iface,
280  aconf->out_iface);
281  aconf->copy_mode = AFP_COPY_MODE_TAP;
282  if (aconf->flags & AFP_TPACKET_V3) {
283  SCLogWarning(SC_ERR_RUNMODE, "Using tpacket_v3 in TAP mode will result in high latency");
284  }
285  } else {
286  SCLogInfo("Invalid mode (not in tap, ips)");
287  }
288  }
289 
290  if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) {
291  aconf->cluster_id = (uint16_t)(cluster_id_auto++);
292  } else {
293  aconf->cluster_id = (uint16_t)atoi(tmpclusterid);
294  SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id);
295  }
296 
297  if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) {
298  /* default to our safest choice: flow hashing + defrag enabled */
300  cluster_type = PACKET_FANOUT_HASH;
301  } else if (strcmp(tmpctype, "cluster_round_robin") == 0) {
302  SCLogConfig("Using round-robin cluster mode for AF_PACKET (iface %s)",
303  aconf->iface);
305  cluster_type = PACKET_FANOUT_LB;
306  } else if (strcmp(tmpctype, "cluster_flow") == 0) {
307  /* In hash mode, we also ask for defragmentation needed to
308  * compute the hash */
309  uint16_t defrag = 0;
310  int conf_val = 0;
311  SCLogConfig("Using flow cluster mode for AF_PACKET (iface %s)",
312  aconf->iface);
313  ConfGetChildValueBoolWithDefault(if_root, if_default, "defrag", &conf_val);
314  if (conf_val) {
315  SCLogConfig("Using defrag kernel functionality for AF_PACKET (iface %s)",
316  aconf->iface);
317  defrag = PACKET_FANOUT_FLAG_DEFRAG;
318  }
319  aconf->cluster_type = PACKET_FANOUT_HASH | defrag;
320  cluster_type = PACKET_FANOUT_HASH;
321  } else if (strcmp(tmpctype, "cluster_cpu") == 0) {
322  SCLogConfig("Using cpu cluster mode for AF_PACKET (iface %s)",
323  aconf->iface);
325  cluster_type = PACKET_FANOUT_CPU;
326  } else if (strcmp(tmpctype, "cluster_qm") == 0) {
327  SCLogConfig("Using queue based cluster mode for AF_PACKET (iface %s)",
328  aconf->iface);
330  cluster_type = PACKET_FANOUT_QM;
331  } else if (strcmp(tmpctype, "cluster_random") == 0) {
332  SCLogConfig("Using random based cluster mode for AF_PACKET (iface %s)",
333  aconf->iface);
335  cluster_type = PACKET_FANOUT_RND;
336  } else if (strcmp(tmpctype, "cluster_rollover") == 0) {
337  SCLogConfig("Using rollover based cluster mode for AF_PACKET (iface %s)",
338  aconf->iface);
339  SCLogWarning(SC_WARN_UNCOMMON, "Rollover mode is causing severe flow "
340  "tracking issues, use it at your own risk.");
342  cluster_type = PACKET_FANOUT_ROLLOVER;
343 #ifdef HAVE_PACKET_EBPF
344  } else if (strcmp(tmpctype, "cluster_ebpf") == 0) {
345  SCLogInfo("Using ebpf based cluster mode for AF_PACKET (iface %s)",
346  aconf->iface);
347  aconf->cluster_type = PACKET_FANOUT_EBPF;
348  cluster_type = PACKET_FANOUT_EBPF;
349 #endif
350  } else {
351  SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype);
352  }
353 
354  int conf_val = 0;
355  ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val);
356  if (conf_val) {
357  SCLogConfig("Using rollover kernel functionality for AF_PACKET (iface %s)",
358  aconf->iface);
360  SCLogWarning(SC_WARN_UNCOMMON, "Rollover option is causing severe flow "
361  "tracking issues, use it at your own risk.");
362  }
363 
364  /*load af_packet bpf filter*/
365  /* command line value has precedence */
366  if (ConfGet("bpf-filter", &bpf_filter) != 1) {
367  if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) {
368  if (strlen(bpf_filter) > 0) {
369  aconf->bpf_filter = bpf_filter;
370  SCLogConfig("Going to use bpf filter %s", aconf->bpf_filter);
371  }
372  }
373  }
374 
375  if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-lb-file", &ebpf_file) != 1) {
376  aconf->ebpf_lb_file = NULL;
377  } else {
378 #ifdef HAVE_PACKET_EBPF
379  SCLogConfig("af-packet will use '%s' as eBPF load balancing file",
380  ebpf_file);
381 #endif
382  aconf->ebpf_lb_file = ebpf_file;
383  }
384 
385 #ifdef HAVE_PACKET_EBPF
386  /* One shot loading of the eBPF file */
387  if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) {
388  int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_lb_file, "loadbalancer",
389  &aconf->ebpf_lb_fd, EBPF_SOCKET_FILTER);
390  if (ret != 0) {
391  SCLogWarning(SC_ERR_INVALID_VALUE, "Error when loading eBPF lb file");
392  }
393  }
394 #else
395  if (aconf->ebpf_lb_file) {
396  SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
397  }
398 #endif
399 
400  if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-filter-file", &ebpf_file) != 1) {
401  aconf->ebpf_filter_file = NULL;
402  } else {
403 #ifdef HAVE_PACKET_EBPF
404  SCLogConfig("af-packet will use '%s' as eBPF filter file",
405  ebpf_file);
406 #endif
407  aconf->ebpf_filter_file = ebpf_file;
408  ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
409  if (conf_val) {
410 #ifdef HAVE_PACKET_EBPF
411  SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
412  aconf->iface);
413  aconf->flags |= AFP_BYPASS;
415  BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
417 #else
418  SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in");
419 #endif
420  }
421  }
422 
423  /* One shot loading of the eBPF file */
424  if (aconf->ebpf_filter_file) {
425 #ifdef HAVE_PACKET_EBPF
426  int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_filter_file, "filter",
427  &aconf->ebpf_filter_fd, EBPF_SOCKET_FILTER);
428  if (ret != 0) {
430  "Error when loading eBPF filter file");
431  }
432 #else
433  SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
434 #endif
435  }
436 
437  if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-filter-file", &ebpf_file) != 1) {
438  aconf->xdp_filter_file = NULL;
439  } else {
440  SCLogInfo("af-packet will use '%s' as XDP filter file",
441  ebpf_file);
442  aconf->xdp_filter_file = ebpf_file;
443  ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
444  if (conf_val) {
445 #ifdef HAVE_PACKET_XDP
446  SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
447  aconf->iface);
448  aconf->flags |= AFP_XDPBYPASS;
450  BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
451 #else
452  SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but XDP support is not built-in");
453 #endif
454  }
455 #ifdef HAVE_PACKET_XDP
456  const char *xdp_mode;
457  if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-mode", &xdp_mode) != 1) {
458  aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
459  } else {
460  if (!strcmp(xdp_mode, "soft")) {
461  aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
462  } else if (!strcmp(xdp_mode, "driver")) {
463  aconf->xdp_mode = XDP_FLAGS_DRV_MODE;
464  } else if (!strcmp(xdp_mode, "hw")) {
465  aconf->xdp_mode = XDP_FLAGS_HW_MODE;
466  } else {
468  "Invalid xdp-mode value: '%s'", xdp_mode);
469  }
470  }
471 #endif
472  }
473 
474  /* One shot loading of the eBPF file */
475  if (aconf->xdp_filter_file) {
476 #ifdef HAVE_PACKET_XDP
477  int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp",
478  &aconf->xdp_filter_fd, EBPF_XDP_CODE);
479  if (ret != 0) {
481  "Error when loading XDP filter file");
482  } else {
483  ret = EBPFSetupXDP(aconf->iface, aconf->xdp_filter_fd, aconf->xdp_mode);
484  if (ret != 0) {
486  "Error when setting up XDP");
487  } else {
488  /* Try to get the xdp-cpu-redirect key */
489  const char *cpuset;
490  if (ConfGetChildValueWithDefault(if_root, if_default,
491  "xdp-cpu-redirect", &cpuset) == 1) {
492  SCLogConfig("Setting up CPU map XDP");
493  ConfNode *node = ConfGetChildWithDefault(if_root, if_default, "xdp-cpu-redirect");
494  if (node == NULL) {
495  SCLogError(SC_ERR_INVALID_VALUE, "Should not be there");
496  } else {
497  EBPFBuildCPUSet(node, aconf->iface);
498  }
499  } else {
500  /* It will just set CPU count to 0 */
501  EBPFBuildCPUSet(NULL, aconf->iface);
502  }
503  }
504  /* we have a peer and we use bypass so we can set up XDP iface redirect */
505  if (aconf->out_iface) {
506  EBPFSetPeerIface(aconf->iface, aconf->out_iface);
507  }
508  }
509 #else
510  SCLogError(SC_ERR_UNIMPLEMENTED, "XDP support is not built-in");
511 #endif
512  }
513 
514  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "buffer-size", &value)) == 1) {
515  aconf->buffer_size = value;
516  } else {
517  aconf->buffer_size = 0;
518  }
519  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) {
520  aconf->ring_size = value;
521  }
522 
523  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) {
524  if (value % getpagesize()) {
525  SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize.");
526  } else {
527  aconf->block_size = value;
528  }
529  }
530 
531  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) {
532  aconf->block_timeout = value;
533  } else {
534  aconf->block_timeout = 10;
535  }
536 
537  (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval);
538  if (boolval) {
539  SCLogConfig("Disabling promiscuous mode on iface %s",
540  aconf->iface);
541  aconf->promisc = 0;
542  }
543 
544  if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) {
545  if (strcmp(tmpctype, "auto") == 0) {
547  } else if (ConfValIsTrue(tmpctype)) {
549  } else if (ConfValIsFalse(tmpctype)) {
551  } else if (strcmp(tmpctype, "kernel") == 0) {
553  } else {
554  SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface);
555  }
556  }
557 
558 finalize:
559 
560  /* if the number of threads is not 1, we need to first check if fanout
561  * functions on this system. */
562  if (aconf->threads != 1) {
563  if (AFPIsFanoutSupported() == 0) {
564  if (aconf->threads != 0) {
565  SCLogNotice("fanout not supported on this system, falling "
566  "back to 1 capture thread");
567  }
568  aconf->threads = 1;
569  }
570  }
571 
572  /* try to automagically set the proper number of threads */
573  if (aconf->threads == 0) {
574  /* for cluster_flow use core count */
575  if (cluster_type == PACKET_FANOUT_HASH) {
576  aconf->threads = (int)UtilCpuGetNumProcessorsOnline();
577  SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads);
578 
579  /* for cluster_qm use RSS queue count */
580  } else if (cluster_type == PACKET_FANOUT_QM) {
581  int rss_queues = GetIfaceRSSQueuesNum(iface);
582  if (rss_queues > 0) {
583  aconf->threads = rss_queues;
584  SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads);
585  }
586  }
587 
588  if (aconf->threads) {
589  SCLogPerf("Using %d AF_PACKET threads for interface %s",
590  aconf->threads, iface);
591  }
592  }
593  if (aconf->threads <= 0) {
594  aconf->threads = 1;
595  }
596  SC_ATOMIC_RESET(aconf->ref);
597  (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
598 
599  if (aconf->ring_size != 0) {
600  if (aconf->ring_size * aconf->threads < max_pending_packets) {
601  aconf->ring_size = max_pending_packets / aconf->threads + 1;
602  SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. "
603  "Resetting to decent value %d.", aconf->ring_size);
604  /* We want at least that max_pending_packets packets can be handled by the
605  * interface. This is generous if we have multiple interfaces listening. */
606  }
607  } else {
608  /* We want that max_pending_packets packets can be handled by suricata
609  * for this interface. To take burst into account we multiply the obtained
610  * size by 2. */
611  aconf->ring_size = max_pending_packets * 2 / aconf->threads;
612  }
613 
614  int ltype = AFPGetLinkType(iface);
615  switch (ltype) {
616  case LINKTYPE_ETHERNET:
617  /* af-packet can handle csum offloading */
618  if (LiveGetOffload() == 0) {
619  if (GetIfaceOffloading(iface, 0, 1) == 1) {
621  "Using AF_PACKET with offloading activated leads to capture problems");
622  }
623  } else {
625  }
626  break;
627  case -1:
628  default:
629  break;
630  }
631 
632  char *active_runmode = RunmodeGetActive();
633  if (active_runmode && !strcmp("workers", active_runmode)) {
634  aconf->flags |= AFP_ZERO_COPY;
635  } else {
636  /* If we are using copy mode we need a lock */
637  aconf->flags |= AFP_SOCK_PROTECT;
638  }
639 
640  /* If we are in RING mode, then we can use ZERO copy
641  * by using the data release mechanism */
642  if (aconf->flags & AFP_RING_MODE) {
643  aconf->flags |= AFP_ZERO_COPY;
644  }
645 
646  if (aconf->flags & AFP_ZERO_COPY) {
647  SCLogConfig("%s: enabling zero copy mode by using data release call", iface);
648  }
649 
650  return aconf;
651 }
652 
653 static int AFPConfigGeThreadsCount(void *conf)
654 {
655  AFPIfaceConfig *afp = (AFPIfaceConfig *)conf;
656  return afp->threads;
657 }
658 
660 {
661  int nlive = LiveGetDeviceCount();
662  int ldev;
663  ConfNode *if_root;
664  ConfNode *if_default = NULL;
665  ConfNode *af_packet_node;
666  int has_ips = 0;
667  int has_ids = 0;
668 
669  /* Find initial node */
670  af_packet_node = ConfGetNode("af-packet");
671  if (af_packet_node == NULL) {
672  return 0;
673  }
674 
675  if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default");
676 
677  for (ldev = 0; ldev < nlive; ldev++) {
678  const char *live_dev = LiveGetDeviceName(ldev);
679  if (live_dev == NULL) {
680  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
681  return 0;
682  }
683  const char *copymodestr = NULL;
684  if_root = ConfFindDeviceConfig(af_packet_node, live_dev);
685 
686  if (if_root == NULL) {
687  if (if_default == NULL) {
688  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
689  return 0;
690  }
691  if_root = if_default;
692  }
693 
694  if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
695  if (strcmp(copymodestr, "ips") == 0) {
696  has_ips = 1;
697  } else {
698  has_ids = 1;
699  }
700  } else {
701  has_ids = 1;
702  }
703  }
704 
705  if (has_ids && has_ips) {
706  SCLogInfo("AF_PACKET mode using IPS and IDS mode");
707  for (ldev = 0; ldev < nlive; ldev++) {
708  const char *live_dev = LiveGetDeviceName(ldev);
709  if (live_dev == NULL) {
710  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
711  return 0;
712  }
713  if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev);
714  const char *copymodestr = NULL;
715 
716  if (if_root == NULL) {
717  if (if_default == NULL) {
718  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
719  return 0;
720  }
721  if_root = if_default;
722  }
723 
724  if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) &&
725  (strcmp(copymodestr, "ips") == 0))) {
727  "AF_PACKET IPS mode used and interface '%s' is in IDS or TAP mode. "
728  "Sniffing '%s' but expect bad result as stream-inline is activated.",
729  live_dev, live_dev);
730  }
731  }
732  }
733 
734  return has_ips;
735 }
736 
737 #endif
738 
739 
741 {
742  SCEnter();
743 
744 /* We include only if AF_PACKET is enabled */
745 #ifdef HAVE_AF_PACKET
746  int ret;
747  const char *live_dev = NULL;
748 
750 
751  TimeModeSetLive();
752 
753  (void)ConfGet("af-packet.live-interface", &live_dev);
754 
755  SCLogDebug("live_dev %s", live_dev);
756 
757  if (AFPPeersListInit() != TM_ECODE_OK) {
758  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
759  exit(EXIT_FAILURE);
760  }
761 
762  ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig,
763  AFPConfigGeThreadsCount,
764  "ReceiveAFP",
765  "DecodeAFP", thread_name_autofp,
766  live_dev);
767  if (ret != 0) {
768  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
769  exit(EXIT_FAILURE);
770  }
771 
772  /* In IPS mode each threads must have a peer */
773  if (AFPPeersListCheck() != TM_ECODE_OK) {
774  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
775  exit(EXIT_FAILURE);
776  }
777 
778  SCLogDebug("RunModeIdsAFPAutoFp initialised");
779 #endif /* HAVE_AF_PACKET */
780 
781  SCReturnInt(0);
782 }
783 
784 /**
785  * \brief Single thread version of the AF_PACKET processing.
786  */
788 {
789  SCEnter();
790 #ifdef HAVE_AF_PACKET
791  int ret;
792  const char *live_dev = NULL;
793 
795  TimeModeSetLive();
796 
797  (void)ConfGet("af-packet.live-interface", &live_dev);
798 
799  if (AFPPeersListInit() != TM_ECODE_OK) {
800  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
801  exit(EXIT_FAILURE);
802  }
803 
804  ret = RunModeSetLiveCaptureSingle(ParseAFPConfig,
805  AFPConfigGeThreadsCount,
806  "ReceiveAFP",
807  "DecodeAFP", thread_name_single,
808  live_dev);
809  if (ret != 0) {
810  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
811  exit(EXIT_FAILURE);
812  }
813 
814  /* In IPS mode each threads must have a peer */
815  if (AFPPeersListCheck() != TM_ECODE_OK) {
816  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
817  exit(EXIT_FAILURE);
818  }
819 
820  SCLogDebug("RunModeIdsAFPSingle initialised");
821 
822 #endif /* HAVE_AF_PACKET */
823  SCReturnInt(0);
824 }
825 
826 /**
827  * \brief Workers version of the AF_PACKET processing.
828  *
829  * Start N threads with each thread doing all the work.
830  *
831  */
833 {
834  SCEnter();
835 #ifdef HAVE_AF_PACKET
836  int ret;
837  const char *live_dev = NULL;
838 
840  TimeModeSetLive();
841 
842  (void)ConfGet("af-packet.live-interface", &live_dev);
843 
844  if (AFPPeersListInit() != TM_ECODE_OK) {
845  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
846  exit(EXIT_FAILURE);
847  }
848 
849  ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig,
850  AFPConfigGeThreadsCount,
851  "ReceiveAFP",
852  "DecodeAFP", thread_name_workers,
853  live_dev);
854  if (ret != 0) {
855  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
856  exit(EXIT_FAILURE);
857  }
858 
859  /* In IPS mode each threads must have a peer */
860  if (AFPPeersListCheck() != TM_ECODE_OK) {
861  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
862  exit(EXIT_FAILURE);
863  }
864 
865  SCLogDebug("RunModeIdsAFPWorkers initialised");
866 
867 #endif /* HAVE_AF_PACKET */
868  SCReturnInt(0);
869 }
870 
871 /**
872  * @}
873  */
char iface[AFP_IFACE_NAME_LENGTH]
TmEcode AFPPeersListInit()
Init the global list of AFPPeer.
const char * LiveGetDeviceName(int number)
Get a pointer to the device name at idx.
Definition: util-device.c:168
#define SCLogDebug(...)
Definition: util-debug.h:335
#define AFP_BLOCK_SIZE_DEFAULT_ORDER
int RunModeIdsAFPSingle(void)
Single thread version of the AF_PACKET processing.
ConfNode * ConfNodeLookupKeyValue(const ConfNode *base, const char *key, const char *value)
Lookup for a key value under a specific node.
Definition: conf.c:860
void RunModeInitialize(void)
Definition: runmodes.c:925
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
void RunModeRegisterNewRunMode(int runmode, const char *name, const char *description, int(*RunModeFunc)(void))
Registers a new runmode.
Definition: runmodes.c:421
#define AFP_COPY_MODE_TAP
TmEcode AFPPeersListCheck()
Check that all AFPPeer got a peer.
#define unlikely(expr)
Definition: util-optimize.h:35
int AFPGetLinkType(const char *ifname)
const char * thread_name_single
Definition: runmodes.c:62
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:107
#define PACKET_FANOUT_QM
#define PACKET_FANOUT_LB
#define SC_ATOMIC_RESET(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:90
void TimeModeSetLive(void)
Definition: util-time.c:82
#define AFP_ZERO_COPY
int AFPRunModeIsIPS()
int max_pending_packets
Definition: suricata.c:215
int LiveGetDeviceCount(void)
Get the number of registered devices.
Definition: util-device.c:148
#define PACKET_FANOUT_CPU
const char * ebpf_filter_file
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:124
int AFPIsFanoutSupported(void)
test if we can use FANOUT. Older kernels like those in CentOS6 have HAVE_PACKET_FANOUT defined but fa...
unsigned int flags
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
const char * out_iface
int BypassedFlowManagerRegisterCheckFunc(BypassedCheckFunc CheckFunc)
Definition: flow-bypass.c:143
char * RunmodeGetActive(void)
Definition: runmodes.c:189
int GetIfaceOffloading(const char *dev, int csum, int other)
output offloading status of the link
Definition: util-ioctl.c:694
int BypassedFlowManagerRegisterUpdateFunc(BypassedUpdateFunc UpdateFunc)
Definition: flow-bypass.c:157
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:81
ConfNode * ConfFindDeviceConfig(ConfNode *node, const char *iface)
Find the configuration node for a specific device.
Definition: util-conf.c:81
#define SCCalloc(nm, a)
Definition: util-mem.h:197
#define AFP_COPY_MODE_NONE
#define PACKET_FANOUT_HASH
int RunModeSetLiveCaptureAutoFp(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
Definition: util-runmodes.c:89
int RunModeIdsAFPAutoFp(void)
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
const char * RunModeAFPGetDefaultMode(void)
int ConfGetChildValueIntWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, intmax_t *val)
Definition: conf.c:495
int RunModeIdsAFPWorkers(void)
Workers version of the AF_PACKET processing.
#define SCEnter(...)
Definition: util-debug.h:337
int ConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:591
#define PACKET_FANOUT_ROLLOVER
#define SCReturnInt(x)
Definition: util-debug.h:341
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:248
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:566
int RunModeSetLiveCaptureSingle(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
Definition: conf.h:32
void(* DerefFunc)(void *)
int ConfGetChildValueWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, const char **vptr)
Definition: conf.c:416
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
#define SCFree(a)
Definition: util-mem.h:228
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
#define AFP_SOCK_PROTECT
int DisableIfaceOffloading(LiveDevice *dev, int csum, int other)
Definition: util-ioctl.c:707
const char * ebpf_lb_file
int GetIfaceRSSQueuesNum(const char *pcap_dev)
Definition: util-ioctl.c:737
const char * thread_name_autofp
Definition: runmodes.c:61
#define AFP_XDPBYPASS
#define SCLogPerf(...)
Definition: util-debug.h:261
#define AFP_MMAP_LOCKED
#define AFP_BYPASS
#define AFP_RING_MODE
#define PACKET_FANOUT_FLAG_DEFRAG
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:176
int ConfGetChildValueBoolWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name, int *val)
Definition: conf.c:543
void RunModeIdsAFPRegister(void)
void RunModeEnablesBypassManager(void)
Definition: runmodes.c:400
const char * xdp_filter_file
ChecksumValidationMode checksum_mode
#define LINKTYPE_ETHERNET
Definition: decode.h:1072
#define AFP_EMERGENCY_MODE
#define AFP_COPY_MODE_IPS
int RunModeSetLiveCaptureWorkers(ConfigIfaceParserFunc ConfigParser, ConfigIfaceThreadsCountFunc ModThreadsCount, const char *recv_mod_name, const char *decode_mod_name, const char *thread_name, const char *live_dev)
uint16_t UtilCpuGetNumProcessorsOnline(void)
Get the number of cpus online in the system.
Definition: util-cpu.c:99
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
ConfNode * ConfGetChildWithDefault(const ConfNode *base, const ConfNode *dflt, const char *name)
Definition: conf.c:402
int LiveGetOffload(void)
Definition: util-device.c:66
const char * bpf_filter
#define PACKET_FANOUT_RND
#define PACKET_FANOUT_FLAG_ROLLOVER
#define AFP_TPACKET_V3
const char * thread_name_workers
Definition: runmodes.c:63