]> git.ipfire.org Git - people/ms/suricata.git/blame - src/runmode-af-packet.c
doc: Add byte_math documentation
[people/ms/suricata.git] / src / runmode-af-packet.c
CommitLineData
c594d0c1 1/* Copyright (C) 2011-2020 Open Information Security Foundation
c45d8985
EL
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
a6457262
EL
18/**
19 * \ingroup afppacket
20 *
21 * @{
22 */
23
e80b30c0
EL
24/**
25 * \file
26 *
27 * \author Eric Leblond <eric@regit.org>
28 *
29 * AF_PACKET socket runmode
30 *
31 */
32
c45d8985 33#include "suricata-common.h"
e80b30c0 34#include "config.h"
c45d8985
EL
35#include "tm-threads.h"
36#include "conf.h"
37#include "runmodes.h"
38#include "runmode-af-packet.h"
c45d8985 39#include "output.h"
00e6cd4c 40#include "log-httplog.h"
c45d8985
EL
41#include "detect-engine-mpm.h"
42
43#include "alert-fastlog.h"
44#include "alert-prelude.h"
c45d8985
EL
45#include "alert-debuglog.h"
46
08eec083
EL
47#include "flow-bypass.h"
48
c45d8985
EL
49#include "util-debug.h"
50#include "util-time.h"
51#include "util-cpu.h"
52#include "util-affinity.h"
871b2189 53#include "util-device.h"
75c875b1 54#include "util-runmodes.h"
56373e5b 55#include "util-ioctl.h"
91e1256b 56#include "util-ebpf.h"
e7c0f0ad 57#include "util-byte.h"
c45d8985 58
e80b30c0
EL
59#include "source-af-packet.h"
60
8879df80
EL
61extern int max_pending_packets;
62
c45d8985
EL
63const char *RunModeAFPGetDefaultMode(void)
64{
8c6251ea 65 return "workers";
c45d8985
EL
66}
67
68void RunModeIdsAFPRegister(void)
69{
e80b30c0
EL
70 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single",
71 "Single threaded af-packet mode",
72 RunModeIdsAFPSingle);
beaa909e
EL
73 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "workers",
74 "Workers af-packet mode, each thread does all"
75 " tasks from acquisition to logging",
76 RunModeIdsAFPWorkers);
e80b30c0
EL
77 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp",
78 "Multi socket AF_PACKET mode. Packets from "
79 "each flow are assigned to a single detect "
80 "thread.",
81 RunModeIdsAFPAutoFp);
c45d8985
EL
82 return;
83}
84
994bc15c
EL
85
86#ifdef HAVE_AF_PACKET
87
ab1200fb 88static void AFPDerefConfig(void *conf)
45d5c3ca
EL
89{
90 AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf;
91 /* Pcap config is used only once but cost of this low. */
531ff3dd 92 if (SC_ATOMIC_SUB(pfp->ref, 1) == 1) {
45d5c3ca
EL
93 SCFree(pfp);
94 }
95}
96
f89a4219
VJ
97/* if cluster id is not set, assign it automagically, uniq value per
98 * interface. */
99static int cluster_id_auto = 1;
100
fbca1a4e
EL
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 */
ab1200fb 111static void *ParseAFPConfig(const char *iface)
fbca1a4e 112{
ab1200fb 113 const char *threadsstr = NULL;
fbca1a4e 114 ConfNode *if_root;
4ae27756 115 ConfNode *if_default = NULL;
fbca1a4e 116 ConfNode *af_packet_node;
ab1200fb
VJ
117 const char *tmpclusterid;
118 const char *tmpctype;
119 const char *copymodestr;
fbca1a4e 120 intmax_t value;
67f791e8 121 int boolval;
ab1200fb
VJ
122 const char *bpf_filter = NULL;
123 const char *out_iface = NULL;
3bb40894 124 int cluster_type = PACKET_FANOUT_HASH;
91e1256b 125 const char *ebpf_file = NULL;
fbca1a4e 126
9f7ba071 127 if (iface == NULL) {
75c875b1
EL
128 return NULL;
129 }
130
9f7ba071
VJ
131 AFPIfaceConfig *aconf = SCCalloc(1, sizeof(*aconf));
132 if (unlikely(aconf == NULL)) {
fbca1a4e
EL
133 return NULL;
134 }
11bdf483 135
fbca1a4e 136 strlcpy(aconf->iface, iface, sizeof(aconf->iface));
9f7ba071 137 aconf->threads = 0;
45d5c3ca 138 SC_ATOMIC_INIT(aconf->ref);
0227a87f 139 (void) SC_ATOMIC_ADD(aconf->ref, 1);
fbca1a4e
EL
140 aconf->buffer_size = 0;
141 aconf->cluster_id = 1;
3bb40894 142 aconf->cluster_type = cluster_type | PACKET_FANOUT_FLAG_DEFRAG;
df7dbe36 143 aconf->promisc = 1;
6062e00c 144 aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL;
45d5c3ca 145 aconf->DerefFunc = AFPDerefConfig;
f7124b11 146 aconf->flags = AFP_RING_MODE;
f2a6fb8a 147 aconf->bpf_filter = NULL;
91e1256b
EL
148 aconf->ebpf_lb_file = NULL;
149 aconf->ebpf_lb_fd = -1;
150 aconf->ebpf_filter_file = NULL;
151 aconf->ebpf_filter_fd = -1;
662dccd8 152 aconf->out_iface = NULL;
c8b3f441 153 aconf->copy_mode = AFP_COPY_MODE_NONE;
9f7ba071
VJ
154 aconf->block_timeout = 10;
155 aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER;
315c29a8
EL
156#ifdef HAVE_PACKET_EBPF
157 aconf->ebpf_t_config.cpus_count = UtilCpuGetNumProcessorsConfigured();
158#endif
f2a6fb8a
EL
159
160 if (ConfGet("bpf-filter", &bpf_filter) == 1) {
161 if (strlen(bpf_filter) > 0) {
162 aconf->bpf_filter = bpf_filter;
b3bf7a57 163 SCLogConfig("Going to use command-line provided bpf filter '%s'",
f2a6fb8a
EL
164 aconf->bpf_filter);
165 }
166 }
fbca1a4e
EL
167
168 /* Find initial node */
169 af_packet_node = ConfGetNode("af-packet");
170 if (af_packet_node == NULL) {
9f7ba071
VJ
171 SCLogInfo("unable to find af-packet config using default values");
172 goto finalize;
fbca1a4e
EL
173 }
174
aa8e747e 175 if_root = ConfFindDeviceConfig(af_packet_node, iface);
aa8e747e 176 if_default = ConfFindDeviceConfig(af_packet_node, "default");
4ae27756
EL
177
178 if (if_root == NULL && if_default == NULL) {
9f7ba071
VJ
179 SCLogInfo("unable to find af-packet config for "
180 "interface \"%s\" or \"default\", using default values",
fbca1a4e 181 iface);
9f7ba071 182 goto finalize;
fbca1a4e
EL
183 }
184
4ae27756
EL
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) {
c174c9d7 192 aconf->threads = 0;
fbca1a4e
EL
193 } else {
194 if (threadsstr != NULL) {
c174c9d7
VJ
195 if (strcmp(threadsstr, "auto") == 0) {
196 aconf->threads = 0;
197 } else {
e7c0f0ad
SB
198 if (StringParseInt32(&aconf->threads, 10, 0, (const char *)threadsstr) < 0) {
199 SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid number of "
200 "threads, resetting to default");
201 aconf->threads = 0;
202 }
c174c9d7 203 }
fbca1a4e
EL
204 }
205 }
45d5c3ca 206
4ae27756 207 if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) {
662dccd8
EL
208 if (strlen(out_iface) > 0) {
209 aconf->out_iface = out_iface;
210 }
211 }
212
876b356b 213 if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval) == 1) {
f7124b11 214 if (!boolval) {
b3bf7a57 215 SCLogConfig("Disabling mmaped capture on iface %s",
876b356b 216 aconf->iface);
f7124b11 217 aconf->flags &= ~(AFP_RING_MODE|AFP_TPACKET_V3);
876b356b 218 }
662dccd8 219 }
876b356b 220
8035d834
EL
221 if (aconf->flags & AFP_RING_MODE) {
222 (void)ConfGetChildValueBoolWithDefault(if_root, if_default,
223 "mmap-locked", (int *)&boolval);
224 if (boolval) {
b3bf7a57 225 SCLogConfig("Enabling locked memory for mmap on iface %s",
bae1b03c 226 aconf->iface);
8035d834
EL
227 aconf->flags |= AFP_MMAP_LOCKED;
228 }
f7124b11
VJ
229
230 if (ConfGetChildValueBoolWithDefault(if_root, if_default,
231 "tpacket-v3", (int *)&boolval) == 1)
232 {
233 if (boolval) {
234 if (strcasecmp(RunmodeGetActive(), "workers") == 0) {
8035d834 235#ifdef HAVE_TPACKET_V3
f7124b11
VJ
236 SCLogConfig("Enabling tpacket v3 capture on iface %s",
237 aconf->iface);
238 aconf->flags |= AFP_TPACKET_V3;
c2d0d938 239#else
f7124b11
VJ
240 SCLogNotice("System too old for tpacket v3 switching to v2");
241 aconf->flags &= ~AFP_TPACKET_V3;
c2d0d938 242#endif
f7124b11
VJ
243 } else {
244 SCLogWarning(SC_ERR_RUNMODE,
245 "tpacket v3 is only implemented for 'workers' runmode."
246 " Switching to tpacket v2.");
247 aconf->flags &= ~AFP_TPACKET_V3;
248 }
8035d834 249 } else {
9f7ba071 250 aconf->flags &= ~AFP_TPACKET_V3;
8035d834
EL
251 }
252 }
f7124b11 253
8035d834
EL
254 (void)ConfGetChildValueBoolWithDefault(if_root, if_default,
255 "use-emergency-flush", (int *)&boolval);
256 if (boolval) {
b3bf7a57 257 SCLogConfig("Enabling ring emergency flush on iface %s",
8035d834
EL
258 aconf->iface);
259 aconf->flags |= AFP_EMERGENCY_MODE;
bae1b03c 260 }
27b5136b
EL
261 }
262
662dccd8 263 aconf->copy_mode = AFP_COPY_MODE_NONE;
4ae27756 264 if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
662dccd8
EL
265 if (aconf->out_iface == NULL) {
266 SCLogInfo("Copy mode activated but no destination"
267 " iface. Disabling feature");
268 } else if (!(aconf->flags & AFP_RING_MODE)) {
269 SCLogInfo("Copy mode activated but use-mmap "
270 "set to no. Disabling feature");
271 } else if (strlen(copymodestr) <= 0) {
272 aconf->out_iface = NULL;
273 } else if (strcmp(copymodestr, "ips") == 0) {
274 SCLogInfo("AF_PACKET IPS mode activated %s->%s",
275 iface,
276 aconf->out_iface);
277 aconf->copy_mode = AFP_COPY_MODE_IPS;
050d8f78
EL
278 if (aconf->flags & AFP_TPACKET_V3) {
279 SCLogWarning(SC_ERR_RUNMODE, "Using tpacket_v3 in IPS mode will result in high latency");
280 }
662dccd8
EL
281 } else if (strcmp(copymodestr, "tap") == 0) {
282 SCLogInfo("AF_PACKET TAP mode activated %s->%s",
283 iface,
284 aconf->out_iface);
285 aconf->copy_mode = AFP_COPY_MODE_TAP;
050d8f78
EL
286 if (aconf->flags & AFP_TPACKET_V3) {
287 SCLogWarning(SC_ERR_RUNMODE, "Using tpacket_v3 in TAP mode will result in high latency");
288 }
662dccd8
EL
289 } else {
290 SCLogInfo("Invalid mode (not in tap, ips)");
291 }
292 }
293
4ae27756 294 if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) {
f89a4219 295 aconf->cluster_id = (uint16_t)(cluster_id_auto++);
fbca1a4e 296 } else {
e22b345b 297 if (StringParseUint16(&aconf->cluster_id, 10, 0, (const char *)tmpclusterid) < 0) {
e7c0f0ad
SB
298 SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid cluster_id, resetting to 0");
299 aconf->cluster_id = 0;
300 }
e22b345b 301 SCLogDebug("Going to use cluster-id %" PRIu16, aconf->cluster_id);
fbca1a4e
EL
302 }
303
4ae27756 304 if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) {
f89a4219
VJ
305 /* default to our safest choice: flow hashing + defrag enabled */
306 aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG;
3bb40894 307 cluster_type = PACKET_FANOUT_HASH;
fbca1a4e 308 } else if (strcmp(tmpctype, "cluster_round_robin") == 0) {
b3bf7a57 309 SCLogConfig("Using round-robin cluster mode for AF_PACKET (iface %s)",
fbca1a4e
EL
310 aconf->iface);
311 aconf->cluster_type = PACKET_FANOUT_LB;
3bb40894 312 cluster_type = PACKET_FANOUT_LB;
fbca1a4e
EL
313 } else if (strcmp(tmpctype, "cluster_flow") == 0) {
314 /* In hash mode, we also ask for defragmentation needed to
315 * compute the hash */
316 uint16_t defrag = 0;
4c6595f4 317 int conf_val = 0;
b3bf7a57 318 SCLogConfig("Using flow cluster mode for AF_PACKET (iface %s)",
fbca1a4e 319 aconf->iface);
4c6595f4
EL
320 ConfGetChildValueBoolWithDefault(if_root, if_default, "defrag", &conf_val);
321 if (conf_val) {
b3bf7a57 322 SCLogConfig("Using defrag kernel functionality for AF_PACKET (iface %s)",
fbca1a4e
EL
323 aconf->iface);
324 defrag = PACKET_FANOUT_FLAG_DEFRAG;
325 }
326 aconf->cluster_type = PACKET_FANOUT_HASH | defrag;
3bb40894 327 cluster_type = PACKET_FANOUT_HASH;
fbca1a4e 328 } else if (strcmp(tmpctype, "cluster_cpu") == 0) {
b3bf7a57 329 SCLogConfig("Using cpu cluster mode for AF_PACKET (iface %s)",
fbca1a4e
EL
330 aconf->iface);
331 aconf->cluster_type = PACKET_FANOUT_CPU;
3bb40894 332 cluster_type = PACKET_FANOUT_CPU;
dc306f3b 333 } else if (strcmp(tmpctype, "cluster_qm") == 0) {
b3bf7a57 334 SCLogConfig("Using queue based cluster mode for AF_PACKET (iface %s)",
dc306f3b
EL
335 aconf->iface);
336 aconf->cluster_type = PACKET_FANOUT_QM;
3bb40894 337 cluster_type = PACKET_FANOUT_QM;
dc306f3b 338 } else if (strcmp(tmpctype, "cluster_random") == 0) {
b3bf7a57 339 SCLogConfig("Using random based cluster mode for AF_PACKET (iface %s)",
dc306f3b
EL
340 aconf->iface);
341 aconf->cluster_type = PACKET_FANOUT_RND;
3bb40894 342 cluster_type = PACKET_FANOUT_RND;
dc306f3b 343 } else if (strcmp(tmpctype, "cluster_rollover") == 0) {
b3bf7a57 344 SCLogConfig("Using rollover based cluster mode for AF_PACKET (iface %s)",
dc306f3b 345 aconf->iface);
5d76f089
EL
346 SCLogWarning(SC_WARN_UNCOMMON, "Rollover mode is causing severe flow "
347 "tracking issues, use it at your own risk.");
dc306f3b 348 aconf->cluster_type = PACKET_FANOUT_ROLLOVER;
3bb40894 349 cluster_type = PACKET_FANOUT_ROLLOVER;
91e1256b
EL
350#ifdef HAVE_PACKET_EBPF
351 } else if (strcmp(tmpctype, "cluster_ebpf") == 0) {
352 SCLogInfo("Using ebpf based cluster mode for AF_PACKET (iface %s)",
353 aconf->iface);
354 aconf->cluster_type = PACKET_FANOUT_EBPF;
355 cluster_type = PACKET_FANOUT_EBPF;
356#endif
fbca1a4e 357 } else {
9f7ba071 358 SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype);
fbca1a4e
EL
359 }
360
8fde842f
EL
361 int conf_val = 0;
362 ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val);
363 if (conf_val) {
b3bf7a57 364 SCLogConfig("Using rollover kernel functionality for AF_PACKET (iface %s)",
8fde842f
EL
365 aconf->iface);
366 aconf->cluster_type |= PACKET_FANOUT_FLAG_ROLLOVER;
5d76f089
EL
367 SCLogWarning(SC_WARN_UNCOMMON, "Rollover option is causing severe flow "
368 "tracking issues, use it at your own risk.");
8fde842f
EL
369 }
370
f2a6fb8a
EL
371 /*load af_packet bpf filter*/
372 /* command line value has precedence */
373 if (ConfGet("bpf-filter", &bpf_filter) != 1) {
4ae27756 374 if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) {
f2a6fb8a
EL
375 if (strlen(bpf_filter) > 0) {
376 aconf->bpf_filter = bpf_filter;
b3bf7a57 377 SCLogConfig("Going to use bpf filter %s", aconf->bpf_filter);
f2a6fb8a
EL
378 }
379 }
380 }
381
91e1256b
EL
382 if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-lb-file", &ebpf_file) != 1) {
383 aconf->ebpf_lb_file = NULL;
384 } else {
385#ifdef HAVE_PACKET_EBPF
2598078e 386 SCLogConfig("af-packet will use '%s' as eBPF load balancing file",
91e1256b 387 ebpf_file);
91e1256b 388 aconf->ebpf_lb_file = ebpf_file;
4f48c457
EL
389 aconf->ebpf_t_config.flags |= EBPF_SOCKET_FILTER;
390#endif
391 }
392
36838017 393#ifdef HAVE_PACKET_EBPF
6fdcb127
EL
394 boolval = false;
395 if (ConfGetChildValueBoolWithDefault(if_root, if_default, "pinned-maps", (int *)&boolval) == 1) {
4f48c457
EL
396 if (boolval) {
397 SCLogConfig("Using pinned maps on iface %s",
398 aconf->iface);
399 aconf->ebpf_t_config.flags |= EBPF_PINNED_MAPS;
400 }
5b056c15 401 const char *pinned_maps_name = NULL;
d25e8dbf
EL
402 if (ConfGetChildValueWithDefault(if_root, if_default,
403 "pinned-maps-name",
404 &pinned_maps_name) != 1) {
405 aconf->ebpf_t_config.pinned_maps_name = pinned_maps_name;
406 } else {
407 aconf->ebpf_t_config.pinned_maps_name = NULL;
408 }
eff56acc
EL
409 } else {
410 aconf->ebpf_t_config.pinned_maps_name = NULL;
91e1256b 411 }
36838017 412#endif
91e1256b 413
06173267 414#ifdef HAVE_PACKET_EBPF
91e1256b
EL
415 /* One shot loading of the eBPF file */
416 if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) {
126488f7 417 int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_lb_file, "loadbalancer",
4f48c457 418 &aconf->ebpf_lb_fd,
d25e8dbf 419 &aconf->ebpf_t_config);
91e1256b
EL
420 if (ret != 0) {
421 SCLogWarning(SC_ERR_INVALID_VALUE, "Error when loading eBPF lb file");
422 }
06173267 423 }
91e1256b 424#else
06173267 425 if (aconf->ebpf_lb_file) {
91e1256b 426 SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
91e1256b 427 }
06173267 428#endif
91e1256b
EL
429
430 if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-filter-file", &ebpf_file) != 1) {
431 aconf->ebpf_filter_file = NULL;
432 } else {
433#ifdef HAVE_PACKET_EBPF
2598078e 434 SCLogConfig("af-packet will use '%s' as eBPF filter file",
91e1256b 435 ebpf_file);
91e1256b 436 aconf->ebpf_filter_file = ebpf_file;
315c29a8 437 aconf->ebpf_t_config.mode = AFP_MODE_EBPF_BYPASS;
bd28f77a 438 aconf->ebpf_t_config.flags |= EBPF_SOCKET_FILTER;
36838017 439#endif
06173267
EL
440 ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
441 if (conf_val) {
08eec083 442#ifdef HAVE_PACKET_EBPF
06173267
EL
443 SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
444 aconf->iface);
445 aconf->flags |= AFP_BYPASS;
b07bda7a 446 BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow, NULL);
08eec083
EL
447#else
448 SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in");
449#endif
06173267 450 }
91e1256b
EL
451 }
452
453 /* One shot loading of the eBPF file */
454 if (aconf->ebpf_filter_file) {
455#ifdef HAVE_PACKET_EBPF
126488f7 456 int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_filter_file, "filter",
4f48c457 457 &aconf->ebpf_filter_fd,
d25e8dbf 458 &aconf->ebpf_t_config);
91e1256b
EL
459 if (ret != 0) {
460 SCLogWarning(SC_ERR_INVALID_VALUE,
461 "Error when loading eBPF filter file");
462 }
463#else
464 SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in");
465#endif
466 }
467
8c880879
EL
468 if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-filter-file", &ebpf_file) != 1) {
469 aconf->xdp_filter_file = NULL;
470 } else {
36838017 471#ifdef HAVE_PACKET_XDP
315c29a8 472 aconf->ebpf_t_config.mode = AFP_MODE_XDP_BYPASS;
4f48c457 473 aconf->ebpf_t_config.flags |= EBPF_XDP_CODE;
8c880879
EL
474 aconf->xdp_filter_file = ebpf_file;
475 ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
476 if (conf_val) {
477 SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
478 aconf->iface);
479 aconf->flags |= AFP_XDPBYPASS;
7df30070
EL
480 /* if maps are pinned we need to read them at start */
481 if (aconf->ebpf_t_config.flags & EBPF_PINNED_MAPS) {
482 RunModeEnablesBypassManager();
483 struct ebpf_timeout_config *ebt = SCCalloc(1, sizeof(struct ebpf_timeout_config));
484 if (ebt == NULL) {
485 SCLogError(SC_ERR_MEM_ALLOC, "Flow bypass alloc error");
486 } else {
487 memcpy(ebt, &(aconf->ebpf_t_config), sizeof(struct ebpf_timeout_config));
488 BypassedFlowManagerRegisterCheckFunc(NULL,
489 EBPFCheckBypassedFlowCreate,
490 (void *)ebt);
491 }
492 }
315c29a8 493 BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow, NULL);
36838017 494 }
08eec083 495#else
0f6b1297 496 SCLogWarning(SC_ERR_UNIMPLEMENTED, "XDP filter set but XDP support is not built-in");
08eec083 497#endif
8c880879
EL
498#ifdef HAVE_PACKET_XDP
499 const char *xdp_mode;
500 if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-mode", &xdp_mode) != 1) {
501 aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
502 } else {
503 if (!strcmp(xdp_mode, "soft")) {
504 aconf->xdp_mode = XDP_FLAGS_SKB_MODE;
505 } else if (!strcmp(xdp_mode, "driver")) {
506 aconf->xdp_mode = XDP_FLAGS_DRV_MODE;
507 } else if (!strcmp(xdp_mode, "hw")) {
508 aconf->xdp_mode = XDP_FLAGS_HW_MODE;
0c3e1e85 509 aconf->ebpf_t_config.flags |= EBPF_XDP_HW_MODE;
8c880879
EL
510 } else {
511 SCLogWarning(SC_ERR_INVALID_VALUE,
512 "Invalid xdp-mode value: '%s'", xdp_mode);
513 }
514 }
315c29a8 515
567b5ee1
EL
516 boolval = true;
517 if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-percpu-hash", (int *)&boolval) == 1) {
518 if (boolval == false) {
315c29a8
EL
519 SCLogConfig("Not using percpu hash on iface %s",
520 aconf->iface);
521 aconf->ebpf_t_config.cpus_count = 1;
522 }
523 }
8c880879
EL
524#endif
525 }
526
527 /* One shot loading of the eBPF file */
528 if (aconf->xdp_filter_file) {
529#ifdef HAVE_PACKET_XDP
126488f7 530 int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp",
4f48c457 531 &aconf->xdp_filter_fd,
d25e8dbf 532 &aconf->ebpf_t_config);
6fdcb127
EL
533 switch (ret) {
534 case 1:
535 SCLogInfo("Loaded pinned maps from sysfs");
536 break;
537 case -1:
8c880879 538 SCLogWarning(SC_ERR_INVALID_VALUE,
6fdcb127
EL
539 "Error when loading XDP filter file");
540 break;
541 case 0:
542 ret = EBPFSetupXDP(aconf->iface, aconf->xdp_filter_fd, aconf->xdp_mode);
543 if (ret != 0) {
544 SCLogWarning(SC_ERR_INVALID_VALUE,
545 "Error when setting up XDP");
4f57008a 546 } else {
6fdcb127
EL
547 /* Try to get the xdp-cpu-redirect key */
548 const char *cpuset;
549 if (ConfGetChildValueWithDefault(if_root, if_default,
550 "xdp-cpu-redirect", &cpuset) == 1) {
551 SCLogConfig("Setting up CPU map XDP");
552 ConfNode *node = ConfGetChildWithDefault(if_root, if_default, "xdp-cpu-redirect");
553 if (node == NULL) {
edf2db4e
EL
554 SCLogError(SC_ERR_INVALID_VALUE,
555 "Previously found node has disappeared");
6fdcb127
EL
556 } else {
557 EBPFBuildCPUSet(node, aconf->iface);
558 }
559 } else {
4f57008a
EL
560 /* It will just set CPU count to 0 */
561 EBPFBuildCPUSet(NULL, aconf->iface);
6fdcb127
EL
562 }
563 }
564 /* we have a peer and we use bypass so we can set up XDP iface redirect */
565 if (aconf->out_iface) {
566 EBPFSetPeerIface(aconf->iface, aconf->out_iface);
4f57008a 567 }
8c880879
EL
568 }
569#else
570 SCLogError(SC_ERR_UNIMPLEMENTED, "XDP support is not built-in");
571#endif
572 }
573
4ae27756 574 if ((ConfGetChildValueIntWithDefault(if_root, if_default, "buffer-size", &value)) == 1) {
fbca1a4e
EL
575 aconf->buffer_size = value;
576 } else {
577 aconf->buffer_size = 0;
578 }
4ae27756 579 if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) {
8879df80 580 aconf->ring_size = value;
8879df80 581 }
fbca1a4e 582
fa902abe
EL
583 if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) {
584 if (value % getpagesize()) {
585 SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize.");
586 } else {
587 aconf->block_size = value;
588 }
589 }
590
234aefdf 591 if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) {
fa902abe
EL
592 aconf->block_timeout = value;
593 } else {
594 aconf->block_timeout = 10;
595 }
596
4ae27756 597 (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval);
67f791e8 598 if (boolval) {
b3bf7a57 599 SCLogConfig("Disabling promiscuous mode on iface %s",
df7dbe36
EL
600 aconf->iface);
601 aconf->promisc = 0;
602 }
67f791e8 603
4ae27756 604 if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) {
6062e00c 605 if (strcmp(tmpctype, "auto") == 0) {
6062e00c 606 aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO;
d18e2f6e 607 } else if (ConfValIsTrue(tmpctype)) {
6062e00c 608 aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
d18e2f6e 609 } else if (ConfValIsFalse(tmpctype)) {
6062e00c
EL
610 aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
611 } else if (strcmp(tmpctype, "kernel") == 0) {
612 aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL;
613 } else {
614 SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface);
615 }
616 }
df7dbe36 617
9f7ba071
VJ
618finalize:
619
402bdf9b
VJ
620 /* if the number of threads is not 1, we need to first check if fanout
621 * functions on this system. */
622 if (aconf->threads != 1) {
8940a9d3 623 if (AFPIsFanoutSupported(aconf->cluster_id) == 0) {
402bdf9b
VJ
624 if (aconf->threads != 0) {
625 SCLogNotice("fanout not supported on this system, falling "
626 "back to 1 capture thread");
627 }
628 aconf->threads = 1;
629 }
630 }
631
632 /* try to automagically set the proper number of threads */
9f7ba071 633 if (aconf->threads == 0) {
3bb40894
VJ
634 /* for cluster_flow use core count */
635 if (cluster_type == PACKET_FANOUT_HASH) {
636 aconf->threads = (int)UtilCpuGetNumProcessorsOnline();
637 SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads);
638
639 /* for cluster_qm use RSS queue count */
640 } else if (cluster_type == PACKET_FANOUT_QM) {
641 int rss_queues = GetIfaceRSSQueuesNum(iface);
642 if (rss_queues > 0) {
9f7ba071 643 aconf->threads = rss_queues;
3bb40894 644 SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads);
9f7ba071
VJ
645 }
646 }
3bb40894 647
4111331a
VJ
648 if (aconf->threads) {
649 SCLogPerf("Using %d AF_PACKET threads for interface %s",
650 aconf->threads, iface);
651 }
9f7ba071
VJ
652 }
653 if (aconf->threads <= 0) {
654 aconf->threads = 1;
655 }
656 SC_ATOMIC_RESET(aconf->ref);
657 (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
658
659 if (aconf->ring_size != 0) {
660 if (aconf->ring_size * aconf->threads < max_pending_packets) {
661 aconf->ring_size = max_pending_packets / aconf->threads + 1;
662 SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. "
663 "Resetting to decent value %d.", aconf->ring_size);
664 /* We want at least that max_pending_packets packets can be handled by the
665 * interface. This is generous if we have multiple interfaces listening. */
666 }
667 } else {
668 /* We want that max_pending_packets packets can be handled by suricata
669 * for this interface. To take burst into account we multiply the obtained
670 * size by 2. */
671 aconf->ring_size = max_pending_packets * 2 / aconf->threads;
672 }
b7bf299e
EL
673
674 int ltype = AFPGetLinkType(iface);
675 switch (ltype) {
676 case LINKTYPE_ETHERNET:
9b80c21d 677 /* af-packet can handle csum offloading */
9d48720f
VJ
678 if (LiveGetOffload() == 0) {
679 if (GetIfaceOffloading(iface, 0, 1) == 1) {
680 SCLogWarning(SC_ERR_AFP_CREATE,
681 "Using AF_PACKET with offloading activated leads to capture problems");
682 }
683 } else {
499e27de 684 DisableIfaceOffloading(LiveGetDevice(iface), 0, 1);
b7bf299e 685 }
9d48720f 686 break;
b7bf299e
EL
687 case -1:
688 default:
689 break;
e951afb9
VJ
690 }
691
bed18678
VJ
692 char *active_runmode = RunmodeGetActive();
693 if (active_runmode && !strcmp("workers", active_runmode)) {
694 aconf->flags |= AFP_ZERO_COPY;
bed18678
VJ
695 } else {
696 /* If we are using copy mode we need a lock */
697 aconf->flags |= AFP_SOCK_PROTECT;
698 }
699
700 /* If we are in RING mode, then we can use ZERO copy
701 * by using the data release mechanism */
702 if (aconf->flags & AFP_RING_MODE) {
703 aconf->flags |= AFP_ZERO_COPY;
9f7ba071
VJ
704 }
705
706 if (aconf->flags & AFP_ZERO_COPY) {
b3bf7a57 707 SCLogConfig("%s: enabling zero copy mode by using data release call", iface);
bed18678
VJ
708 }
709
fbca1a4e
EL
710 return aconf;
711}
712
ab1200fb 713static int AFPConfigGeThreadsCount(void *conf)
75c875b1
EL
714{
715 AFPIfaceConfig *afp = (AFPIfaceConfig *)conf;
716 return afp->threads;
717}
fbca1a4e 718
1e36053e
EL
719int AFPRunModeIsIPS()
720{
721 int nlive = LiveGetDeviceCount();
722 int ldev;
723 ConfNode *if_root;
724 ConfNode *if_default = NULL;
725 ConfNode *af_packet_node;
726 int has_ips = 0;
727 int has_ids = 0;
728
729 /* Find initial node */
730 af_packet_node = ConfGetNode("af-packet");
731 if (af_packet_node == NULL) {
732 return 0;
733 }
734
735 if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default");
736
737 for (ldev = 0; ldev < nlive; ldev++) {
5c974f92 738 const char *live_dev = LiveGetDeviceName(ldev);
7cdc5706
VJ
739 if (live_dev == NULL) {
740 SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
741 return 0;
742 }
ab1200fb 743 const char *copymodestr = NULL;
aa8e747e 744 if_root = ConfFindDeviceConfig(af_packet_node, live_dev);
1e36053e
EL
745
746 if (if_root == NULL) {
747 if (if_default == NULL) {
748 SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
749 return 0;
750 }
751 if_root = if_default;
752 }
753
754 if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
755 if (strcmp(copymodestr, "ips") == 0) {
756 has_ips = 1;
757 } else {
758 has_ids = 1;
759 }
760 } else {
761 has_ids = 1;
762 }
763 }
764
765 if (has_ids && has_ips) {
766 SCLogInfo("AF_PACKET mode using IPS and IDS mode");
767 for (ldev = 0; ldev < nlive; ldev++) {
5c974f92 768 const char *live_dev = LiveGetDeviceName(ldev);
7cdc5706
VJ
769 if (live_dev == NULL) {
770 SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
771 return 0;
772 }
1e36053e 773 if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev);
ab1200fb 774 const char *copymodestr = NULL;
1e36053e
EL
775
776 if (if_root == NULL) {
777 if (if_default == NULL) {
778 SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
779 return 0;
780 }
781 if_root = if_default;
782 }
783
784 if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) &&
785 (strcmp(copymodestr, "ips") == 0))) {
786 SCLogError(SC_ERR_INVALID_ARGUMENT,
787 "AF_PACKET IPS mode used and interface '%s' is in IDS or TAP mode. "
788 "Sniffing '%s' but expect bad result as stream-inline is activated.",
789 live_dev, live_dev);
790 }
791 }
792 }
793
794 return has_ips;
795}
796
994bc15c
EL
797#endif
798
799
38b349af 800int RunModeIdsAFPAutoFp(void)
e80b30c0
EL
801{
802 SCEnter();
803
804/* We include only if AF_PACKET is enabled */
805#ifdef HAVE_AF_PACKET
75c875b1 806 int ret;
ab1200fb 807 const char *live_dev = NULL;
e80b30c0 808
fbca1a4e
EL
809 RunModeInitialize();
810
811 TimeModeSetLive();
812
2179ac25 813 (void)ConfGet("af-packet.live-interface", &live_dev);
fbca1a4e 814
75c875b1 815 SCLogDebug("live_dev %s", live_dev);
e80b30c0 816
662dccd8
EL
817 if (AFPPeersListInit() != TM_ECODE_OK) {
818 SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
819 exit(EXIT_FAILURE);
820 }
821
38b349af 822 ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig,
75c875b1
EL
823 AFPConfigGeThreadsCount,
824 "ReceiveAFP",
41c768ce 825 "DecodeAFP", thread_name_autofp,
75c875b1
EL
826 live_dev);
827 if (ret != 0) {
625a1e07 828 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
75c875b1 829 exit(EXIT_FAILURE);
e80b30c0
EL
830 }
831
662dccd8
EL
832 /* In IPS mode each threads must have a peer */
833 if (AFPPeersListCheck() != TM_ECODE_OK) {
834 SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
835 exit(EXIT_FAILURE);
836 }
e80b30c0 837
86a3f064 838 SCLogDebug("RunModeIdsAFPAutoFp initialised");
e80b30c0
EL
839#endif /* HAVE_AF_PACKET */
840
841 SCReturnInt(0);
842}
843
844/**
845 * \brief Single thread version of the AF_PACKET processing.
846 */
38b349af 847int RunModeIdsAFPSingle(void)
e80b30c0 848{
38b349af 849 SCEnter();
1aab2470
EL
850#ifdef HAVE_AF_PACKET
851 int ret;
ab1200fb 852 const char *live_dev = NULL;
e80b30c0
EL
853
854 RunModeInitialize();
855 TimeModeSetLive();
856
2179ac25 857 (void)ConfGet("af-packet.live-interface", &live_dev);
e80b30c0 858
662dccd8
EL
859 if (AFPPeersListInit() != TM_ECODE_OK) {
860 SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
861 exit(EXIT_FAILURE);
862 }
863
38b349af 864 ret = RunModeSetLiveCaptureSingle(ParseAFPConfig,
77869a2d
EL
865 AFPConfigGeThreadsCount,
866 "ReceiveAFP",
41c768ce 867 "DecodeAFP", thread_name_single,
1aab2470
EL
868 live_dev);
869 if (ret != 0) {
625a1e07 870 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
e80b30c0
EL
871 exit(EXIT_FAILURE);
872 }
e80b30c0 873
662dccd8
EL
874 /* In IPS mode each threads must have a peer */
875 if (AFPPeersListCheck() != TM_ECODE_OK) {
876 SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
877 exit(EXIT_FAILURE);
878 }
879
86a3f064 880 SCLogDebug("RunModeIdsAFPSingle initialised");
e80b30c0
EL
881
882#endif /* HAVE_AF_PACKET */
883 SCReturnInt(0);
c45d8985 884}
beaa909e
EL
885
886/**
887 * \brief Workers version of the AF_PACKET processing.
888 *
889 * Start N threads with each thread doing all the work.
890 *
891 */
38b349af 892int RunModeIdsAFPWorkers(void)
beaa909e 893{
38b349af 894 SCEnter();
beaa909e
EL
895#ifdef HAVE_AF_PACKET
896 int ret;
ab1200fb 897 const char *live_dev = NULL;
beaa909e
EL
898
899 RunModeInitialize();
900 TimeModeSetLive();
901
2179ac25 902 (void)ConfGet("af-packet.live-interface", &live_dev);
beaa909e 903
662dccd8
EL
904 if (AFPPeersListInit() != TM_ECODE_OK) {
905 SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
906 exit(EXIT_FAILURE);
907 }
908
38b349af 909 ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig,
beaa909e
EL
910 AFPConfigGeThreadsCount,
911 "ReceiveAFP",
41c768ce 912 "DecodeAFP", thread_name_workers,
beaa909e
EL
913 live_dev);
914 if (ret != 0) {
625a1e07 915 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
beaa909e
EL
916 exit(EXIT_FAILURE);
917 }
918
662dccd8
EL
919 /* In IPS mode each threads must have a peer */
920 if (AFPPeersListCheck() != TM_ECODE_OK) {
921 SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
922 exit(EXIT_FAILURE);
923 }
924
86a3f064 925 SCLogDebug("RunModeIdsAFPWorkers initialised");
beaa909e
EL
926
927#endif /* HAVE_AF_PACKET */
928 SCReturnInt(0);
929}
a6457262
EL
930
931/**
932 * @}
933 */