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);
340  cluster_type = PACKET_FANOUT_ROLLOVER;
341 #ifdef HAVE_PACKET_EBPF
342  } else if (strcmp(tmpctype, "cluster_ebpf") == 0) {
343  SCLogInfo("Using ebpf based cluster mode for AF_PACKET (iface %s)",
344  aconf->iface);
345  aconf->cluster_type = PACKET_FANOUT_EBPF;
346  cluster_type = PACKET_FANOUT_EBPF;
347 #endif
348  } else {
349  SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype);
350  }
351 
352  int conf_val = 0;
353  ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val);
354  if (conf_val) {
355  SCLogConfig("Using rollover kernel functionality for AF_PACKET (iface %s)",
356  aconf->iface);
358  }
359 
360  /*load af_packet bpf filter*/
361  /* command line value has precedence */
362  if (ConfGet("bpf-filter", &bpf_filter) != 1) {
363  if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) {
364  if (strlen(bpf_filter) > 0) {
365  aconf->bpf_filter = bpf_filter;
366  SCLogConfig("Going to use bpf filter %s", aconf->bpf_filter);
367  }
368  }
369  }
370 
371  if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-lb-file", &ebpf_file) != 1) {
372  aconf->ebpf_lb_file = NULL;
373  } else {
374 #ifdef HAVE_PACKET_EBPF
375  SCLogConfig("af-packet will use '%s' as eBPF load balancing file",
376  ebpf_file);
377 #endif
378  aconf->ebpf_lb_file = ebpf_file;
379  }
380 
381 #ifdef HAVE_PACKET_EBPF
382  /* One shot loading of the eBPF file */
383  if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) {
384  int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_lb_file, "loadbalancer",
385  &aconf->ebpf_lb_fd, EBPF_SOCKET_FILTER);
386  if (ret != 0) {
387  SCLogWarning(SC_ERR_INVALID_VALUE, "Error when loading eBPF lb file");
388  }
389  }
390 #else
391  if (aconf->ebpf_lb_file) {
392  SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
393  }
394 #endif
395 
396  if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-filter-file", &ebpf_file) != 1) {
397  aconf->ebpf_filter_file = NULL;
398  } else {
399 #ifdef HAVE_PACKET_EBPF
400  SCLogConfig("af-packet will use '%s' as eBPF filter file",
401  ebpf_file);
402 #endif
403  aconf->ebpf_filter_file = ebpf_file;
404  ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
405  if (conf_val) {
406 #ifdef HAVE_PACKET_EBPF
407  SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
408  aconf->iface);
409  aconf->flags |= AFP_BYPASS;
411  BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
413 #else
414  SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in");
415 #endif
416  }
417  }
418 
419  /* One shot loading of the eBPF file */
420  if (aconf->ebpf_filter_file) {
421 #ifdef HAVE_PACKET_EBPF
422  int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_filter_file, "filter",
423  &aconf->ebpf_filter_fd, EBPF_SOCKET_FILTER);
424  if (ret != 0) {
426  "Error when loading eBPF filter file");
427  }
428 #else
429  SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
430 #endif
431  }
432 
433  if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-filter-file", &ebpf_file) != 1) {
434  aconf->xdp_filter_file = NULL;
435  } else {
436  SCLogInfo("af-packet will use '%s' as XDP filter file",
437  ebpf_file);
438  aconf->xdp_filter_file = ebpf_file;
439  ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
440  if (conf_val) {
441 #ifdef HAVE_PACKET_XDP
442  SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
443  aconf->iface);
444  aconf->flags |= AFP_XDPBYPASS;
446  BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
447 #else
448  SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but XDP support is not built-in");
449 #endif
450  }
451 #ifdef HAVE_PACKET_XDP
452  const char *xdp_mode;
453  if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-mode", &xdp_mode) != 1) {
454  aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
455  } else {
456  if (!strcmp(xdp_mode, "soft")) {
457  aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
458  } else if (!strcmp(xdp_mode, "driver")) {
459  aconf->xdp_mode = XDP_FLAGS_DRV_MODE;
460  } else if (!strcmp(xdp_mode, "hw")) {
461  aconf->xdp_mode = XDP_FLAGS_HW_MODE;
462  } else {
464  "Invalid xdp-mode value: '%s'", xdp_mode);
465  }
466  }
467 #endif
468  }
469 
470  /* One shot loading of the eBPF file */
471  if (aconf->xdp_filter_file) {
472 #ifdef HAVE_PACKET_XDP
473  int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp",
474  &aconf->xdp_filter_fd, EBPF_XDP_CODE);
475  if (ret != 0) {
477  "Error when loading XDP filter file");
478  } else {
479  ret = EBPFSetupXDP(aconf->iface, aconf->xdp_filter_fd, aconf->xdp_mode);
480  if (ret != 0) {
482  "Error when setting up XDP");
483  } else {
484  /* Try to get the xdp-cpu-redirect key */
485  const char *cpuset;
486  if (ConfGetChildValueWithDefault(if_root, if_default,
487  "xdp-cpu-redirect", &cpuset) == 1) {
488  SCLogConfig("Setting up CPU map XDP");
489  ConfNode *node = ConfGetChildWithDefault(if_root, if_default, "xdp-cpu-redirect");
490  if (node == NULL) {
491  SCLogError(SC_ERR_INVALID_VALUE, "Should not be there");
492  } else {
493  EBPFBuildCPUSet(node, aconf->iface);
494  }
495  } else {
496  /* It will just set CPU count to 0 */
497  EBPFBuildCPUSet(NULL, aconf->iface);
498  }
499  }
500  /* we have a peer and we use bypass so we can set up XDP iface redirect */
501  if (aconf->out_iface) {
502  EBPFSetPeerIface(aconf->iface, aconf->out_iface);
503  }
504  }
505 #else
506  SCLogError(SC_ERR_UNIMPLEMENTED, "XDP support is not built-in");
507 #endif
508  }
509 
510  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "buffer-size", &value)) == 1) {
511  aconf->buffer_size = value;
512  } else {
513  aconf->buffer_size = 0;
514  }
515  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) {
516  aconf->ring_size = value;
517  }
518 
519  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) {
520  if (value % getpagesize()) {
521  SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize.");
522  } else {
523  aconf->block_size = value;
524  }
525  }
526 
527  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) {
528  aconf->block_timeout = value;
529  } else {
530  aconf->block_timeout = 10;
531  }
532 
533  (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval);
534  if (boolval) {
535  SCLogConfig("Disabling promiscuous mode on iface %s",
536  aconf->iface);
537  aconf->promisc = 0;
538  }
539 
540  if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) {
541  if (strcmp(tmpctype, "auto") == 0) {
543  } else if (ConfValIsTrue(tmpctype)) {
545  } else if (ConfValIsFalse(tmpctype)) {
547  } else if (strcmp(tmpctype, "kernel") == 0) {
549  } else {
550  SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface);
551  }
552  }
553 
554 finalize:
555 
556  /* if the number of threads is not 1, we need to first check if fanout
557  * functions on this system. */
558  if (aconf->threads != 1) {
559  if (AFPIsFanoutSupported() == 0) {
560  if (aconf->threads != 0) {
561  SCLogNotice("fanout not supported on this system, falling "
562  "back to 1 capture thread");
563  }
564  aconf->threads = 1;
565  }
566  }
567 
568  /* try to automagically set the proper number of threads */
569  if (aconf->threads == 0) {
570  /* for cluster_flow use core count */
571  if (cluster_type == PACKET_FANOUT_HASH) {
572  aconf->threads = (int)UtilCpuGetNumProcessorsOnline();
573  SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads);
574 
575  /* for cluster_qm use RSS queue count */
576  } else if (cluster_type == PACKET_FANOUT_QM) {
577  int rss_queues = GetIfaceRSSQueuesNum(iface);
578  if (rss_queues > 0) {
579  aconf->threads = rss_queues;
580  SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads);
581  }
582  }
583 
584  if (aconf->threads) {
585  SCLogPerf("Using %d AF_PACKET threads for interface %s",
586  aconf->threads, iface);
587  }
588  }
589  if (aconf->threads <= 0) {
590  aconf->threads = 1;
591  }
592  SC_ATOMIC_RESET(aconf->ref);
593  (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
594 
595  if (aconf->ring_size != 0) {
596  if (aconf->ring_size * aconf->threads < max_pending_packets) {
597  aconf->ring_size = max_pending_packets / aconf->threads + 1;
598  SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. "
599  "Resetting to decent value %d.", aconf->ring_size);
600  /* We want at least that max_pending_packets packets can be handled by the
601  * interface. This is generous if we have multiple interfaces listening. */
602  }
603  } else {
604  /* We want that max_pending_packets packets can be handled by suricata
605  * for this interface. To take burst into account we multiply the obtained
606  * size by 2. */
607  aconf->ring_size = max_pending_packets * 2 / aconf->threads;
608  }
609 
610  int ltype = AFPGetLinkType(iface);
611  switch (ltype) {
612  case LINKTYPE_ETHERNET:
613  /* af-packet can handle csum offloading */
614  if (LiveGetOffload() == 0) {
615  if (GetIfaceOffloading(iface, 0, 1) == 1) {
617  "Using AF_PACKET with offloading activated leads to capture problems");
618  }
619  } else {
621  }
622  break;
623  case -1:
624  default:
625  break;
626  }
627 
628  char *active_runmode = RunmodeGetActive();
629  if (active_runmode && !strcmp("workers", active_runmode)) {
630  aconf->flags |= AFP_ZERO_COPY;
631  } else {
632  /* If we are using copy mode we need a lock */
633  aconf->flags |= AFP_SOCK_PROTECT;
634  }
635 
636  /* If we are in RING mode, then we can use ZERO copy
637  * by using the data release mechanism */
638  if (aconf->flags & AFP_RING_MODE) {
639  aconf->flags |= AFP_ZERO_COPY;
640  }
641 
642  if (aconf->flags & AFP_ZERO_COPY) {
643  SCLogConfig("%s: enabling zero copy mode by using data release call", iface);
644  }
645 
646  return aconf;
647 }
648 
649 static int AFPConfigGeThreadsCount(void *conf)
650 {
651  AFPIfaceConfig *afp = (AFPIfaceConfig *)conf;
652  return afp->threads;
653 }
654 
656 {
657  int nlive = LiveGetDeviceCount();
658  int ldev;
659  ConfNode *if_root;
660  ConfNode *if_default = NULL;
661  ConfNode *af_packet_node;
662  int has_ips = 0;
663  int has_ids = 0;
664 
665  /* Find initial node */
666  af_packet_node = ConfGetNode("af-packet");
667  if (af_packet_node == NULL) {
668  return 0;
669  }
670 
671  if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default");
672 
673  for (ldev = 0; ldev < nlive; ldev++) {
674  const char *live_dev = LiveGetDeviceName(ldev);
675  if (live_dev == NULL) {
676  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
677  return 0;
678  }
679  const char *copymodestr = NULL;
680  if_root = ConfFindDeviceConfig(af_packet_node, live_dev);
681 
682  if (if_root == NULL) {
683  if (if_default == NULL) {
684  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
685  return 0;
686  }
687  if_root = if_default;
688  }
689 
690  if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
691  if (strcmp(copymodestr, "ips") == 0) {
692  has_ips = 1;
693  } else {
694  has_ids = 1;
695  }
696  } else {
697  has_ids = 1;
698  }
699  }
700 
701  if (has_ids && has_ips) {
702  SCLogInfo("AF_PACKET mode using IPS and IDS mode");
703  for (ldev = 0; ldev < nlive; ldev++) {
704  const char *live_dev = LiveGetDeviceName(ldev);
705  if (live_dev == NULL) {
706  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
707  return 0;
708  }
709  if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev);
710  const char *copymodestr = NULL;
711 
712  if (if_root == NULL) {
713  if (if_default == NULL) {
714  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
715  return 0;
716  }
717  if_root = if_default;
718  }
719 
720  if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) &&
721  (strcmp(copymodestr, "ips") == 0))) {
723  "AF_PACKET IPS mode used and interface '%s' is in IDS or TAP mode. "
724  "Sniffing '%s' but expect bad result as stream-inline is activated.",
725  live_dev, live_dev);
726  }
727  }
728  }
729 
730  return has_ips;
731 }
732 
733 #endif
734 
735 
737 {
738  SCEnter();
739 
740 /* We include only if AF_PACKET is enabled */
741 #ifdef HAVE_AF_PACKET
742  int ret;
743  const char *live_dev = NULL;
744 
746 
747  TimeModeSetLive();
748 
749  (void)ConfGet("af-packet.live-interface", &live_dev);
750 
751  SCLogDebug("live_dev %s", live_dev);
752 
753  if (AFPPeersListInit() != TM_ECODE_OK) {
754  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
755  exit(EXIT_FAILURE);
756  }
757 
758  ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig,
759  AFPConfigGeThreadsCount,
760  "ReceiveAFP",
761  "DecodeAFP", thread_name_autofp,
762  live_dev);
763  if (ret != 0) {
764  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
765  exit(EXIT_FAILURE);
766  }
767 
768  /* In IPS mode each threads must have a peer */
769  if (AFPPeersListCheck() != TM_ECODE_OK) {
770  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
771  exit(EXIT_FAILURE);
772  }
773 
774  SCLogDebug("RunModeIdsAFPAutoFp initialised");
775 #endif /* HAVE_AF_PACKET */
776 
777  SCReturnInt(0);
778 }
779 
780 /**
781  * \brief Single thread version of the AF_PACKET processing.
782  */
784 {
785  SCEnter();
786 #ifdef HAVE_AF_PACKET
787  int ret;
788  const char *live_dev = NULL;
789 
791  TimeModeSetLive();
792 
793  (void)ConfGet("af-packet.live-interface", &live_dev);
794 
795  if (AFPPeersListInit() != TM_ECODE_OK) {
796  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
797  exit(EXIT_FAILURE);
798  }
799 
800  ret = RunModeSetLiveCaptureSingle(ParseAFPConfig,
801  AFPConfigGeThreadsCount,
802  "ReceiveAFP",
803  "DecodeAFP", thread_name_single,
804  live_dev);
805  if (ret != 0) {
806  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
807  exit(EXIT_FAILURE);
808  }
809 
810  /* In IPS mode each threads must have a peer */
811  if (AFPPeersListCheck() != TM_ECODE_OK) {
812  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
813  exit(EXIT_FAILURE);
814  }
815 
816  SCLogDebug("RunModeIdsAFPSingle initialised");
817 
818 #endif /* HAVE_AF_PACKET */
819  SCReturnInt(0);
820 }
821 
822 /**
823  * \brief Workers version of the AF_PACKET processing.
824  *
825  * Start N threads with each thread doing all the work.
826  *
827  */
829 {
830  SCEnter();
831 #ifdef HAVE_AF_PACKET
832  int ret;
833  const char *live_dev = NULL;
834 
836  TimeModeSetLive();
837 
838  (void)ConfGet("af-packet.live-interface", &live_dev);
839 
840  if (AFPPeersListInit() != TM_ECODE_OK) {
841  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
842  exit(EXIT_FAILURE);
843  }
844 
845  ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig,
846  AFPConfigGeThreadsCount,
847  "ReceiveAFP",
848  "DecodeAFP", thread_name_workers,
849  live_dev);
850  if (ret != 0) {
851  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
852  exit(EXIT_FAILURE);
853  }
854 
855  /* In IPS mode each threads must have a peer */
856  if (AFPPeersListCheck() != TM_ECODE_OK) {
857  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
858  exit(EXIT_FAILURE);
859  }
860 
861  SCLogDebug("RunModeIdsAFPWorkers initialised");
862 
863 #endif /* HAVE_AF_PACKET */
864  SCReturnInt(0);
865 }
866 
867 /**
868  * @}
869  */
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:213
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