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