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