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