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 const char *RunModeAFPGetDefaultMode(void)
64 {
65  return "workers";
66 }
67 
69 {
71  "Single threaded af-packet mode",
74  "Workers af-packet mode, each thread does all"
75  " tasks from acquisition to logging",
78  "Multi socket AF_PACKET mode. Packets from "
79  "each flow are assigned to a single detect "
80  "thread.",
82  return;
83 }
84 
85 
86 #ifdef HAVE_AF_PACKET
87 
88 static void AFPDerefConfig(void *conf)
89 {
90  AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf;
91  /* Pcap config is used only once but cost of this low. */
92  if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) {
93  SCFree(pfp);
94  }
95 }
96 
97 /* if cluster id is not set, assign it automagically, uniq value per
98  * interface. */
99 static int cluster_id_auto = 1;
100 
101 /**
102  * \brief extract information from config file
103  *
104  * The returned structure will be freed by the thread init function.
105  * This is thus necessary to or copy the structure before giving it
106  * to thread or to reparse the file for each thread (and thus have
107  * new structure.
108  *
109  * \return a AFPIfaceConfig corresponding to the interface name
110  */
111 static void *ParseAFPConfig(const char *iface)
112 {
113  const char *threadsstr = NULL;
114  ConfNode *if_root;
115  ConfNode *if_default = NULL;
116  ConfNode *af_packet_node;
117  const char *tmpclusterid;
118  const char *tmpctype;
119  const char *copymodestr;
120  intmax_t value;
121  int boolval;
122  const char *bpf_filter = NULL;
123  const char *out_iface = NULL;
124  int cluster_type = PACKET_FANOUT_HASH;
125  const char *ebpf_file = NULL;
126 
127  if (iface == NULL) {
128  return NULL;
129  }
130 
131  AFPIfaceConfig *aconf = SCCalloc(1, sizeof(*aconf));
132  if (unlikely(aconf == NULL)) {
133  return NULL;
134  }
135 
136  strlcpy(aconf->iface, iface, sizeof(aconf->iface));
137  aconf->threads = 0;
138  SC_ATOMIC_INIT(aconf->ref);
139  (void) SC_ATOMIC_ADD(aconf->ref, 1);
140  aconf->buffer_size = 0;
141  aconf->cluster_id = 1;
142  aconf->cluster_type = cluster_type | PACKET_FANOUT_FLAG_DEFRAG;
143  aconf->promisc = 1;
145  aconf->DerefFunc = AFPDerefConfig;
146  aconf->flags = AFP_RING_MODE;
147  aconf->bpf_filter = NULL;
148  aconf->ebpf_lb_file = NULL;
149  aconf->ebpf_lb_fd = -1;
150  aconf->ebpf_filter_file = NULL;
151  aconf->ebpf_filter_fd = -1;
152  aconf->out_iface = NULL;
153  aconf->copy_mode = AFP_COPY_MODE_NONE;
154  aconf->block_timeout = 10;
155  aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER;
156 #ifdef HAVE_PACKET_EBPF
157  aconf->ebpf_t_config.cpus_count = UtilCpuGetNumProcessorsConfigured();
158 #endif
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  aconf->ebpf_lb_file = ebpf_file;
382  aconf->ebpf_t_config.flags |= EBPF_SOCKET_FILTER;
383 #endif
384  }
385 
386 #ifdef HAVE_PACKET_EBPF
387  boolval = false;
388  if (ConfGetChildValueBoolWithDefault(if_root, if_default, "pinned-maps", (int *)&boolval) == 1) {
389  if (boolval) {
390  SCLogConfig("Using pinned maps on iface %s",
391  aconf->iface);
392  aconf->ebpf_t_config.flags |= EBPF_PINNED_MAPS;
393  }
394  const char *pinned_maps_name = NULL;
395  if (ConfGetChildValueWithDefault(if_root, if_default,
396  "pinned-maps-name",
397  &pinned_maps_name) != 1) {
398  aconf->ebpf_t_config.pinned_maps_name = pinned_maps_name;
399  } else {
400  aconf->ebpf_t_config.pinned_maps_name = NULL;
401  }
402  } else {
403  aconf->ebpf_t_config.pinned_maps_name = NULL;
404  }
405 #endif
406 
407 #ifdef HAVE_PACKET_EBPF
408  /* One shot loading of the eBPF file */
409  if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) {
410  int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_lb_file, "loadbalancer",
411  &aconf->ebpf_lb_fd,
412  &aconf->ebpf_t_config);
413  if (ret != 0) {
414  SCLogWarning(SC_ERR_INVALID_VALUE, "Error when loading eBPF lb file");
415  }
416  }
417 #else
418  if (aconf->ebpf_lb_file) {
419  SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
420  }
421 #endif
422 
423  if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-filter-file", &ebpf_file) != 1) {
424  aconf->ebpf_filter_file = NULL;
425  } else {
426 #ifdef HAVE_PACKET_EBPF
427  SCLogConfig("af-packet will use '%s' as eBPF filter file",
428  ebpf_file);
429  aconf->ebpf_filter_file = ebpf_file;
430  aconf->ebpf_t_config.mode = AFP_MODE_EBPF_BYPASS;
431  aconf->ebpf_t_config.flags |= EBPF_SOCKET_FILTER;
432 #endif
433  ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
434  if (conf_val) {
435 #ifdef HAVE_PACKET_EBPF
436  SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
437  aconf->iface);
438  aconf->flags |= AFP_BYPASS;
439  BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow, NULL);
440 #else
441  SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in");
442 #endif
443  }
444  }
445 
446  /* One shot loading of the eBPF file */
447  if (aconf->ebpf_filter_file) {
448 #ifdef HAVE_PACKET_EBPF
449  int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_filter_file, "filter",
450  &aconf->ebpf_filter_fd,
451  &aconf->ebpf_t_config);
452  if (ret != 0) {
454  "Error when loading eBPF filter file");
455  }
456 #else
457  SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
458 #endif
459  }
460 
461  if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-filter-file", &ebpf_file) != 1) {
462  aconf->xdp_filter_file = NULL;
463  } else {
464 #ifdef HAVE_PACKET_XDP
465  aconf->ebpf_t_config.mode = AFP_MODE_XDP_BYPASS;
466  aconf->ebpf_t_config.flags |= EBPF_XDP_CODE;
467  aconf->xdp_filter_file = ebpf_file;
468  ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
469  if (conf_val) {
470  SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
471  aconf->iface);
472  aconf->flags |= AFP_XDPBYPASS;
473  /* if maps are pinned we need to read them at start */
474  if (aconf->ebpf_t_config.flags & EBPF_PINNED_MAPS) {
476  struct ebpf_timeout_config *ebt = SCCalloc(1, sizeof(struct ebpf_timeout_config));
477  if (ebt == NULL) {
478  SCLogError(SC_ERR_MEM_ALLOC, "Flow bypass alloc error");
479  } else {
480  memcpy(ebt, &(aconf->ebpf_t_config), sizeof(struct ebpf_timeout_config));
482  EBPFCheckBypassedFlowCreate,
483  (void *)ebt);
484  }
485  }
486  BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow, NULL);
487  }
488 #else
489  SCLogWarning(SC_ERR_UNIMPLEMENTED, "XDP filter set but XDP support is not built-in");
490 #endif
491 #ifdef HAVE_PACKET_XDP
492  const char *xdp_mode;
493  if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-mode", &xdp_mode) != 1) {
494  aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
495  } else {
496  if (!strcmp(xdp_mode, "soft")) {
497  aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
498  } else if (!strcmp(xdp_mode, "driver")) {
499  aconf->xdp_mode = XDP_FLAGS_DRV_MODE;
500  } else if (!strcmp(xdp_mode, "hw")) {
501  aconf->xdp_mode = XDP_FLAGS_HW_MODE;
502  aconf->ebpf_t_config.flags |= EBPF_XDP_HW_MODE;
503  } else {
505  "Invalid xdp-mode value: '%s'", xdp_mode);
506  }
507  }
508 
509  boolval = true;
510  if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-percpu-hash", (int *)&boolval) == 1) {
511  if (boolval == false) {
512  SCLogConfig("Not using percpu hash on iface %s",
513  aconf->iface);
514  aconf->ebpf_t_config.cpus_count = 1;
515  }
516  }
517 #endif
518  }
519 
520  /* One shot loading of the eBPF file */
521  if (aconf->xdp_filter_file) {
522 #ifdef HAVE_PACKET_XDP
523  int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp",
524  &aconf->xdp_filter_fd,
525  &aconf->ebpf_t_config);
526  switch (ret) {
527  case 1:
528  SCLogInfo("Loaded pinned maps from sysfs");
529  break;
530  case -1:
532  "Error when loading XDP filter file");
533  break;
534  case 0:
535  ret = EBPFSetupXDP(aconf->iface, aconf->xdp_filter_fd, aconf->xdp_mode);
536  if (ret != 0) {
538  "Error when setting up XDP");
539  } else {
540  /* Try to get the xdp-cpu-redirect key */
541  const char *cpuset;
542  if (ConfGetChildValueWithDefault(if_root, if_default,
543  "xdp-cpu-redirect", &cpuset) == 1) {
544  SCLogConfig("Setting up CPU map XDP");
545  ConfNode *node = ConfGetChildWithDefault(if_root, if_default, "xdp-cpu-redirect");
546  if (node == NULL) {
548  "Previously found node has disappeared");
549  } else {
550  EBPFBuildCPUSet(node, aconf->iface);
551  }
552  } else {
553  /* It will just set CPU count to 0 */
554  EBPFBuildCPUSet(NULL, aconf->iface);
555  }
556  }
557  /* we have a peer and we use bypass so we can set up XDP iface redirect */
558  if (aconf->out_iface) {
559  EBPFSetPeerIface(aconf->iface, aconf->out_iface);
560  }
561  }
562 #else
563  SCLogError(SC_ERR_UNIMPLEMENTED, "XDP support is not built-in");
564 #endif
565  }
566 
567  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "buffer-size", &value)) == 1) {
568  aconf->buffer_size = value;
569  } else {
570  aconf->buffer_size = 0;
571  }
572  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) {
573  aconf->ring_size = value;
574  }
575 
576  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) {
577  if (value % getpagesize()) {
578  SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize.");
579  } else {
580  aconf->block_size = value;
581  }
582  }
583 
584  if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) {
585  aconf->block_timeout = value;
586  } else {
587  aconf->block_timeout = 10;
588  }
589 
590  (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval);
591  if (boolval) {
592  SCLogConfig("Disabling promiscuous mode on iface %s",
593  aconf->iface);
594  aconf->promisc = 0;
595  }
596 
597  if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) {
598  if (strcmp(tmpctype, "auto") == 0) {
600  } else if (ConfValIsTrue(tmpctype)) {
602  } else if (ConfValIsFalse(tmpctype)) {
604  } else if (strcmp(tmpctype, "kernel") == 0) {
606  } else {
607  SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface);
608  }
609  }
610 
611 finalize:
612 
613  /* if the number of threads is not 1, we need to first check if fanout
614  * functions on this system. */
615  if (aconf->threads != 1) {
616  if (AFPIsFanoutSupported(aconf->cluster_id) == 0) {
617  if (aconf->threads != 0) {
618  SCLogNotice("fanout not supported on this system, falling "
619  "back to 1 capture thread");
620  }
621  aconf->threads = 1;
622  }
623  }
624 
625  /* try to automagically set the proper number of threads */
626  if (aconf->threads == 0) {
627  /* for cluster_flow use core count */
628  if (cluster_type == PACKET_FANOUT_HASH) {
629  aconf->threads = (int)UtilCpuGetNumProcessorsOnline();
630  SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads);
631 
632  /* for cluster_qm use RSS queue count */
633  } else if (cluster_type == PACKET_FANOUT_QM) {
634  int rss_queues = GetIfaceRSSQueuesNum(iface);
635  if (rss_queues > 0) {
636  aconf->threads = rss_queues;
637  SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads);
638  }
639  }
640 
641  if (aconf->threads) {
642  SCLogPerf("Using %d AF_PACKET threads for interface %s",
643  aconf->threads, iface);
644  }
645  }
646  if (aconf->threads <= 0) {
647  aconf->threads = 1;
648  }
649  SC_ATOMIC_RESET(aconf->ref);
650  (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
651 
652  if (aconf->ring_size != 0) {
653  if (aconf->ring_size * aconf->threads < max_pending_packets) {
654  aconf->ring_size = max_pending_packets / aconf->threads + 1;
655  SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. "
656  "Resetting to decent value %d.", aconf->ring_size);
657  /* We want at least that max_pending_packets packets can be handled by the
658  * interface. This is generous if we have multiple interfaces listening. */
659  }
660  } else {
661  /* We want that max_pending_packets packets can be handled by suricata
662  * for this interface. To take burst into account we multiply the obtained
663  * size by 2. */
664  aconf->ring_size = max_pending_packets * 2 / aconf->threads;
665  }
666 
667  int ltype = AFPGetLinkType(iface);
668  switch (ltype) {
669  case LINKTYPE_ETHERNET:
670  /* af-packet can handle csum offloading */
671  if (LiveGetOffload() == 0) {
672  if (GetIfaceOffloading(iface, 0, 1) == 1) {
674  "Using AF_PACKET with offloading activated leads to capture problems");
675  }
676  } else {
678  }
679  break;
680  case -1:
681  default:
682  break;
683  }
684 
685  char *active_runmode = RunmodeGetActive();
686  if (active_runmode && !strcmp("workers", active_runmode)) {
687  aconf->flags |= AFP_ZERO_COPY;
688  } else {
689  /* If we are using copy mode we need a lock */
690  aconf->flags |= AFP_SOCK_PROTECT;
691  }
692 
693  /* If we are in RING mode, then we can use ZERO copy
694  * by using the data release mechanism */
695  if (aconf->flags & AFP_RING_MODE) {
696  aconf->flags |= AFP_ZERO_COPY;
697  }
698 
699  if (aconf->flags & AFP_ZERO_COPY) {
700  SCLogConfig("%s: enabling zero copy mode by using data release call", iface);
701  }
702 
703  return aconf;
704 }
705 
706 static int AFPConfigGeThreadsCount(void *conf)
707 {
708  AFPIfaceConfig *afp = (AFPIfaceConfig *)conf;
709  return afp->threads;
710 }
711 
713 {
714  int nlive = LiveGetDeviceCount();
715  int ldev;
716  ConfNode *if_root;
717  ConfNode *if_default = NULL;
718  ConfNode *af_packet_node;
719  int has_ips = 0;
720  int has_ids = 0;
721 
722  /* Find initial node */
723  af_packet_node = ConfGetNode("af-packet");
724  if (af_packet_node == NULL) {
725  return 0;
726  }
727 
728  if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default");
729 
730  for (ldev = 0; ldev < nlive; ldev++) {
731  const char *live_dev = LiveGetDeviceName(ldev);
732  if (live_dev == NULL) {
733  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
734  return 0;
735  }
736  const char *copymodestr = NULL;
737  if_root = ConfFindDeviceConfig(af_packet_node, live_dev);
738 
739  if (if_root == NULL) {
740  if (if_default == NULL) {
741  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
742  return 0;
743  }
744  if_root = if_default;
745  }
746 
747  if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
748  if (strcmp(copymodestr, "ips") == 0) {
749  has_ips = 1;
750  } else {
751  has_ids = 1;
752  }
753  } else {
754  has_ids = 1;
755  }
756  }
757 
758  if (has_ids && has_ips) {
759  SCLogInfo("AF_PACKET mode using IPS and IDS mode");
760  for (ldev = 0; ldev < nlive; ldev++) {
761  const char *live_dev = LiveGetDeviceName(ldev);
762  if (live_dev == NULL) {
763  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
764  return 0;
765  }
766  if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev);
767  const char *copymodestr = NULL;
768 
769  if (if_root == NULL) {
770  if (if_default == NULL) {
771  SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
772  return 0;
773  }
774  if_root = if_default;
775  }
776 
777  if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) &&
778  (strcmp(copymodestr, "ips") == 0))) {
780  "AF_PACKET IPS mode used and interface '%s' is in IDS or TAP mode. "
781  "Sniffing '%s' but expect bad result as stream-inline is activated.",
782  live_dev, live_dev);
783  }
784  }
785  }
786 
787  return has_ips;
788 }
789 
790 #endif
791 
792 
794 {
795  SCEnter();
796 
797 /* We include only if AF_PACKET is enabled */
798 #ifdef HAVE_AF_PACKET
799  int ret;
800  const char *live_dev = NULL;
801 
803 
804  TimeModeSetLive();
805 
806  (void)ConfGet("af-packet.live-interface", &live_dev);
807 
808  SCLogDebug("live_dev %s", live_dev);
809 
810  if (AFPPeersListInit() != TM_ECODE_OK) {
811  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
812  exit(EXIT_FAILURE);
813  }
814 
815  ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig,
816  AFPConfigGeThreadsCount,
817  "ReceiveAFP",
818  "DecodeAFP", thread_name_autofp,
819  live_dev);
820  if (ret != 0) {
821  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
822  exit(EXIT_FAILURE);
823  }
824 
825  /* In IPS mode each threads must have a peer */
826  if (AFPPeersListCheck() != TM_ECODE_OK) {
827  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
828  exit(EXIT_FAILURE);
829  }
830 
831  SCLogDebug("RunModeIdsAFPAutoFp initialised");
832 #endif /* HAVE_AF_PACKET */
833 
834  SCReturnInt(0);
835 }
836 
837 /**
838  * \brief Single thread version of the AF_PACKET processing.
839  */
841 {
842  SCEnter();
843 #ifdef HAVE_AF_PACKET
844  int ret;
845  const char *live_dev = NULL;
846 
848  TimeModeSetLive();
849 
850  (void)ConfGet("af-packet.live-interface", &live_dev);
851 
852  if (AFPPeersListInit() != TM_ECODE_OK) {
853  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
854  exit(EXIT_FAILURE);
855  }
856 
857  ret = RunModeSetLiveCaptureSingle(ParseAFPConfig,
858  AFPConfigGeThreadsCount,
859  "ReceiveAFP",
860  "DecodeAFP", thread_name_single,
861  live_dev);
862  if (ret != 0) {
863  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
864  exit(EXIT_FAILURE);
865  }
866 
867  /* In IPS mode each threads must have a peer */
868  if (AFPPeersListCheck() != TM_ECODE_OK) {
869  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
870  exit(EXIT_FAILURE);
871  }
872 
873  SCLogDebug("RunModeIdsAFPSingle initialised");
874 
875 #endif /* HAVE_AF_PACKET */
876  SCReturnInt(0);
877 }
878 
879 /**
880  * \brief Workers version of the AF_PACKET processing.
881  *
882  * Start N threads with each thread doing all the work.
883  *
884  */
886 {
887  SCEnter();
888 #ifdef HAVE_AF_PACKET
889  int ret;
890  const char *live_dev = NULL;
891 
893  TimeModeSetLive();
894 
895  (void)ConfGet("af-packet.live-interface", &live_dev);
896 
897  if (AFPPeersListInit() != TM_ECODE_OK) {
898  SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
899  exit(EXIT_FAILURE);
900  }
901 
902  ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig,
903  AFPConfigGeThreadsCount,
904  "ReceiveAFP",
905  "DecodeAFP", thread_name_workers,
906  live_dev);
907  if (ret != 0) {
908  SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
909  exit(EXIT_FAILURE);
910  }
911 
912  /* In IPS mode each threads must have a peer */
913  if (AFPPeersListCheck() != TM_ECODE_OK) {
914  SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
915  exit(EXIT_FAILURE);
916  }
917 
918  SCLogDebug("RunModeIdsAFPWorkers initialised");
919 
920 #endif /* HAVE_AF_PACKET */
921  SCReturnInt(0);
922 }
923 
924 /**
925  * @}
926  */
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:177
#define SCLogDebug(...)
Definition: util-debug.h:335
#define AFP_BLOCK_SIZE_DEFAULT_ORDER
uint16_t UtilCpuGetNumProcessorsConfigured(void)
Get the number of cpus configured in the system.
Definition: util-cpu.c:58
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:900
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
#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:90
#define AFP_ZERO_COPY
int BypassedFlowManagerRegisterUpdateFunc(BypassedUpdateFunc UpdateFunc, void *data)
int AFPRunModeIsIPS()
int max_pending_packets
Definition: suricata.c:215
int LiveGetDeviceCount(void)
Get the number of registered devices.
Definition: util-device.c:157
#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
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
char * RunmodeGetActive(void)
Definition: runmodes.c:187
int GetIfaceOffloading(const char *dev, int csum, int other)
output offloading status of the link
Definition: util-ioctl.c:694
int AFPIsFanoutSupported(int cluster_id)
test if we can use FANOUT. Older kernels like those in CentOS6 have HAVE_PACKET_FANOUT defined but fa...
#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:129
#define SCCalloc(nm, a)
Definition: util-mem.h:253
#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
int BypassedFlowManagerRegisterCheckFunc(BypassedCheckFunc CheckFunc, BypassedCheckFuncInit CheckFuncInit, void *data)
#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:279
#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:322
#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 RunModeRegisterNewRunMode(enum RunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void))
Registers a new runmode.
Definition: runmodes.c:419
void RunModeEnablesBypassManager(void)
Definition: runmodes.c:398
const char * xdp_filter_file
ChecksumValidationMode checksum_mode
#define LINKTYPE_ETHERNET
Definition: decode.h:1074
#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:79
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