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