]> git.ipfire.org Git - people/ms/suricata.git/blame - src/runmode-af-packet.c
conf: introduce WithDefault function
[people/ms/suricata.git] / src / runmode-af-packet.c
CommitLineData
c78e112e 1/* Copyright (C) 2011,2012 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
33
c45d8985 34#include "suricata-common.h"
e80b30c0 35#include "config.h"
c45d8985
EL
36#include "tm-threads.h"
37#include "conf.h"
38#include "runmodes.h"
39#include "runmode-af-packet.h"
40#include "log-httplog.h"
41#include "output.h"
42#include "cuda-packet-batcher.h"
c45d8985
EL
43#include "detect-engine-mpm.h"
44
45#include "alert-fastlog.h"
46#include "alert-prelude.h"
c45d8985
EL
47#include "alert-unified2-alert.h"
48#include "alert-debuglog.h"
49
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"
c45d8985 56
e80b30c0
EL
57#include "source-af-packet.h"
58
8879df80
EL
59extern int max_pending_packets;
60
e80b30c0
EL
61static const char *default_mode_auto = NULL;
62static const char *default_mode_autofp = NULL;
c45d8985
EL
63
64const char *RunModeAFPGetDefaultMode(void)
65{
fbca1a4e 66 return default_mode_autofp;
c45d8985
EL
67}
68
69void RunModeIdsAFPRegister(void)
70{
8d1fe9f2 71 default_mode_auto = "autofp";
c45d8985
EL
72 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "auto",
73 "Multi threaded af-packet mode",
74 RunModeIdsAFPAuto);
e80b30c0
EL
75 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single",
76 "Single threaded af-packet mode",
77 RunModeIdsAFPSingle);
beaa909e
EL
78 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "workers",
79 "Workers af-packet mode, each thread does all"
80 " tasks from acquisition to logging",
81 RunModeIdsAFPWorkers);
e80b30c0
EL
82 default_mode_autofp = "autofp";
83 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp",
84 "Multi socket AF_PACKET mode. Packets from "
85 "each flow are assigned to a single detect "
86 "thread.",
87 RunModeIdsAFPAutoFp);
c45d8985
EL
88 return;
89}
90
45d5c3ca
EL
91void AFPDerefConfig(void *conf)
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
fbca1a4e
EL
100/**
101 * \brief extract information from config file
102 *
103 * The returned structure will be freed by the thread init function.
104 * This is thus necessary to or copy the structure before giving it
105 * to thread or to reparse the file for each thread (and thus have
106 * new structure.
107 *
108 * \return a AFPIfaceConfig corresponding to the interface name
109 */
75c875b1 110void *ParseAFPConfig(const char *iface)
fbca1a4e
EL
111{
112 char *threadsstr = NULL;
113 ConfNode *if_root;
114 ConfNode *af_packet_node;
115 AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf));
116 char *tmpclusterid;
117 char *tmpctype;
662dccd8 118 char *copymodestr;
fbca1a4e 119 intmax_t value;
67f791e8 120 int boolval;
f2a6fb8a 121 char *bpf_filter = NULL;
662dccd8 122 char *out_iface = NULL;
fbca1a4e 123
e176be6f 124 if (unlikely(aconf == NULL)) {
75c875b1
EL
125 return NULL;
126 }
127
11bdf483
VJ
128 if (iface == NULL) {
129 SCFree(aconf);
fbca1a4e
EL
130 return NULL;
131 }
11bdf483 132
fbca1a4e
EL
133 strlcpy(aconf->iface, iface, sizeof(aconf->iface));
134 aconf->threads = 1;
45d5c3ca 135 SC_ATOMIC_INIT(aconf->ref);
0227a87f 136 (void) SC_ATOMIC_ADD(aconf->ref, 1);
fbca1a4e
EL
137 aconf->buffer_size = 0;
138 aconf->cluster_id = 1;
139 aconf->cluster_type = PACKET_FANOUT_HASH;
df7dbe36 140 aconf->promisc = 1;
6062e00c 141 aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL;
45d5c3ca 142 aconf->DerefFunc = AFPDerefConfig;
49b7b00f 143 aconf->flags = 0;
f2a6fb8a 144 aconf->bpf_filter = NULL;
662dccd8 145 aconf->out_iface = NULL;
f2a6fb8a
EL
146
147 if (ConfGet("bpf-filter", &bpf_filter) == 1) {
148 if (strlen(bpf_filter) > 0) {
149 aconf->bpf_filter = bpf_filter;
150 SCLogInfo("Going to use command-line provided bpf filter '%s'",
151 aconf->bpf_filter);
152 }
153 }
fbca1a4e
EL
154
155 /* Find initial node */
156 af_packet_node = ConfGetNode("af-packet");
157 if (af_packet_node == NULL) {
158 SCLogInfo("Unable to find af-packet config using default value");
159 return aconf;
160 }
161
162 if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface);
163 if (if_root == NULL) {
164 SCLogInfo("Unable to find af-packet config for "
165 "interface %s, using default value",
166 iface);
167 return aconf;
168 }
169
170 if (ConfGetChildValue(if_root, "threads", &threadsstr) != 1) {
171 aconf->threads = 1;
172 } else {
173 if (threadsstr != NULL) {
174 aconf->threads = (uint8_t)atoi(threadsstr);
175 }
176 }
177 if (aconf->threads == 0) {
178 aconf->threads = 1;
179 }
45d5c3ca 180
662dccd8
EL
181 if (ConfGetChildValue(if_root, "copy-iface", &out_iface) == 1) {
182 if (strlen(out_iface) > 0) {
183 aconf->out_iface = out_iface;
184 }
185 }
186
187 (void)ConfGetChildValueBool(if_root, "use-mmap", (int *)&boolval);
188 if (boolval) {
189 SCLogInfo("Enabling mmaped capture on iface %s",
190 aconf->iface);
191 aconf->flags |= AFP_RING_MODE;
192 }
27b5136b
EL
193 (void)ConfGetChildValueBool(if_root, "use-emergency-flush", (int *)&boolval);
194 if (boolval) {
195 SCLogInfo("Enabling ring emergency flush on iface %s",
196 aconf->iface);
197 aconf->flags |= AFP_EMERGENCY_MODE;
198 }
199
662dccd8
EL
200
201 aconf->copy_mode = AFP_COPY_MODE_NONE;
202 if (ConfGetChildValue(if_root, "copy-mode", &copymodestr) == 1) {
203 if (aconf->out_iface == NULL) {
204 SCLogInfo("Copy mode activated but no destination"
205 " iface. Disabling feature");
206 } else if (!(aconf->flags & AFP_RING_MODE)) {
207 SCLogInfo("Copy mode activated but use-mmap "
208 "set to no. Disabling feature");
209 } else if (strlen(copymodestr) <= 0) {
210 aconf->out_iface = NULL;
211 } else if (strcmp(copymodestr, "ips") == 0) {
212 SCLogInfo("AF_PACKET IPS mode activated %s->%s",
213 iface,
214 aconf->out_iface);
215 aconf->copy_mode = AFP_COPY_MODE_IPS;
216 } else if (strcmp(copymodestr, "tap") == 0) {
217 SCLogInfo("AF_PACKET TAP mode activated %s->%s",
218 iface,
219 aconf->out_iface);
220 aconf->copy_mode = AFP_COPY_MODE_TAP;
221 } else {
222 SCLogInfo("Invalid mode (not in tap, ips)");
223 }
224 }
225
45d5c3ca 226 SC_ATOMIC_RESET(aconf->ref);
0227a87f 227 (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
45d5c3ca 228
fbca1a4e
EL
229 if (ConfGetChildValue(if_root, "cluster-id", &tmpclusterid) != 1) {
230 SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config");
231 } else {
232 aconf->cluster_id = (uint16_t)atoi(tmpclusterid);
233 SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id);
234 }
235
236 if (ConfGetChildValue(if_root, "cluster-type", &tmpctype) != 1) {
623bb38d 237 SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type from config");
fbca1a4e
EL
238 } else if (strcmp(tmpctype, "cluster_round_robin") == 0) {
239 SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)",
240 aconf->iface);
241 aconf->cluster_type = PACKET_FANOUT_LB;
242 } else if (strcmp(tmpctype, "cluster_flow") == 0) {
243 /* In hash mode, we also ask for defragmentation needed to
244 * compute the hash */
245 uint16_t defrag = 0;
246 SCLogInfo("Using flow cluster mode for AF_PACKET (iface %s)",
247 aconf->iface);
248 ConfGetChildValueBool(if_root, "defrag", (int *)&defrag);
249 if (defrag) {
0df4c583 250 SCLogInfo("Using defrag kernel functionality for AF_PACKET (iface %s)",
fbca1a4e
EL
251 aconf->iface);
252 defrag = PACKET_FANOUT_FLAG_DEFRAG;
253 }
254 aconf->cluster_type = PACKET_FANOUT_HASH | defrag;
255 } else if (strcmp(tmpctype, "cluster_cpu") == 0) {
256 SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)",
257 aconf->iface);
258 aconf->cluster_type = PACKET_FANOUT_CPU;
259 } else {
260 SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype);
11bdf483 261 SCFree(aconf);
fbca1a4e
EL
262 return NULL;
263 }
264
f2a6fb8a
EL
265 /*load af_packet bpf filter*/
266 /* command line value has precedence */
267 if (ConfGet("bpf-filter", &bpf_filter) != 1) {
268 if (ConfGetChildValue(if_root, "bpf-filter", &bpf_filter) == 1) {
269 if (strlen(bpf_filter) > 0) {
270 aconf->bpf_filter = bpf_filter;
271 SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter);
272 }
273 }
274 }
275
fbca1a4e
EL
276 if ((ConfGetChildValueInt(if_root, "buffer-size", &value)) == 1) {
277 aconf->buffer_size = value;
278 } else {
279 aconf->buffer_size = 0;
280 }
8879df80
EL
281 if ((ConfGetChildValueInt(if_root, "ring-size", &value)) == 1) {
282 aconf->ring_size = value;
283 if (value * aconf->threads < max_pending_packets) {
284 aconf->ring_size = max_pending_packets / aconf->threads + 1;
285 SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. "
286 "Resetting to decent value %d.", aconf->ring_size);
287 /* We want at least that max_pending_packets packets can be handled by the
288 * interface. This is generous if we have multiple interfaces listening. */
289 }
290 } else {
291 /* We want that max_pending_packets packets can be handled by suricata
292 * for this interface. To take burst into account we multiply the obtained
293 * size by 2. */
294 aconf->ring_size = max_pending_packets * 2 / aconf->threads;
295 }
fbca1a4e 296
2179ac25 297 (void)ConfGetChildValueBool(if_root, "disable-promisc", (int *)&boolval);
67f791e8 298 if (boolval) {
df7dbe36
EL
299 SCLogInfo("Disabling promiscuous mode on iface %s",
300 aconf->iface);
301 aconf->promisc = 0;
302 }
67f791e8 303
d24b3a0e 304 if (ConfGetChildValue(if_root, "checksum-checks", &tmpctype) == 1) {
6062e00c 305 if (strcmp(tmpctype, "auto") == 0) {
6062e00c 306 aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO;
6062e00c
EL
307 } else if (strcmp(tmpctype, "yes") == 0) {
308 aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
309 } else if (strcmp(tmpctype, "no") == 0) {
310 aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
311 } else if (strcmp(tmpctype, "kernel") == 0) {
312 aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL;
313 } else {
314 SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface);
315 }
316 }
df7dbe36 317
fbca1a4e
EL
318 return aconf;
319}
320
75c875b1
EL
321int AFPConfigGeThreadsCount(void *conf)
322{
323 AFPIfaceConfig *afp = (AFPIfaceConfig *)conf;
324 return afp->threads;
325}
fbca1a4e 326
c45d8985
EL
327/**
328 * \brief RunModeIdsAFPAuto set up the following thread packet handlers:
e80b30c0 329 * - Receive thread (from live iface)
c45d8985
EL
330 * - Decode thread
331 * - Stream thread
332 * - Detect: If we have only 1 cpu, it will setup one Detect thread
333 * If we have more than one, it will setup num_cpus - 1
334 * starting from the second cpu available.
335 * - Respond/Reject thread
336 * - Outputs thread
337 * By default the threads will use the first cpu available
338 * except the Detection threads if we have more than one cpu.
339 *
340 * \param de_ctx Pointer to the Detection Engine.
341 *
342 * \retval 0 If all goes well. (If any problem is detected the engine will
343 * exit()).
344 */
345int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx)
346{
347 SCEnter();
e80b30c0
EL
348
349#ifdef HAVE_AF_PACKET
75c875b1
EL
350 int ret;
351 char *live_dev = NULL;
c45d8985
EL
352
353 RunModeInitialize();
c45d8985 354
75c875b1 355 TimeModeSetLive();
c45d8985 356
2179ac25 357 (void)ConfGet("af-packet.live-interface", &live_dev);
c45d8985 358
662dccd8
EL
359 if (AFPPeersListInit() != TM_ECODE_OK) {
360 SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
361 exit(EXIT_FAILURE);
362 }
363
75c875b1 364 ret = RunModeSetLiveCaptureAuto(de_ctx,
6c55af84
EL
365 ParseAFPConfig,
366 AFPConfigGeThreadsCount,
367 "ReceiveAFP",
75c875b1
EL
368 "DecodeAFP", "RecvAFP",
369 live_dev);
370 if (ret != 0) {
625a1e07 371 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
c45d8985
EL
372 exit(EXIT_FAILURE);
373 }
374
662dccd8
EL
375 /* In IPS mode each threads must have a peer */
376 if (AFPPeersListCheck() != TM_ECODE_OK) {
377 SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
378 exit(EXIT_FAILURE);
379 }
380
75c875b1 381 SCLogInfo("RunModeIdsAFPAuto initialised");
e80b30c0
EL
382#endif
383 SCReturnInt(0);
384}
385
386int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx)
387{
388 SCEnter();
389
390/* We include only if AF_PACKET is enabled */
391#ifdef HAVE_AF_PACKET
75c875b1 392 int ret;
e80b30c0 393 char *live_dev = NULL;
e80b30c0 394
fbca1a4e
EL
395 RunModeInitialize();
396
397 TimeModeSetLive();
398
2179ac25 399 (void)ConfGet("af-packet.live-interface", &live_dev);
fbca1a4e 400
75c875b1 401 SCLogDebug("live_dev %s", live_dev);
e80b30c0 402
662dccd8
EL
403 if (AFPPeersListInit() != TM_ECODE_OK) {
404 SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
405 exit(EXIT_FAILURE);
406 }
407
75c875b1
EL
408 ret = RunModeSetLiveCaptureAutoFp(de_ctx,
409 ParseAFPConfig,
410 AFPConfigGeThreadsCount,
411 "ReceiveAFP",
412 "DecodeAFP", "RxAFP",
413 live_dev);
414 if (ret != 0) {
625a1e07 415 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
75c875b1 416 exit(EXIT_FAILURE);
e80b30c0
EL
417 }
418
662dccd8
EL
419 /* In IPS mode each threads must have a peer */
420 if (AFPPeersListCheck() != TM_ECODE_OK) {
421 SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
422 exit(EXIT_FAILURE);
423 }
e80b30c0 424
662dccd8 425 SCLogInfo("RunModeIdsAFPAutoFp initialised");
e80b30c0
EL
426#endif /* HAVE_AF_PACKET */
427
428 SCReturnInt(0);
429}
430
431/**
432 * \brief Single thread version of the AF_PACKET processing.
433 */
434int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx)
435{
1aab2470
EL
436#ifdef HAVE_AF_PACKET
437 int ret;
438 char *live_dev = NULL;
439#endif
3801e004
AS
440 SCEnter();
441#ifdef HAVE_AF_PACKET
e80b30c0
EL
442
443 RunModeInitialize();
444 TimeModeSetLive();
445
2179ac25 446 (void)ConfGet("af-packet.live-interface", &live_dev);
e80b30c0 447
662dccd8
EL
448 if (AFPPeersListInit() != TM_ECODE_OK) {
449 SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
450 exit(EXIT_FAILURE);
451 }
452
1aab2470 453 ret = RunModeSetLiveCaptureSingle(de_ctx,
77869a2d
EL
454 ParseAFPConfig,
455 AFPConfigGeThreadsCount,
456 "ReceiveAFP",
1aab2470
EL
457 "DecodeAFP", "AFPacket",
458 live_dev);
459 if (ret != 0) {
625a1e07 460 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
e80b30c0
EL
461 exit(EXIT_FAILURE);
462 }
e80b30c0 463
662dccd8
EL
464 /* In IPS mode each threads must have a peer */
465 if (AFPPeersListCheck() != TM_ECODE_OK) {
466 SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
467 exit(EXIT_FAILURE);
468 }
469
1aab2470 470 SCLogInfo("RunModeIdsAFPSingle initialised");
e80b30c0
EL
471
472#endif /* HAVE_AF_PACKET */
473 SCReturnInt(0);
c45d8985 474}
beaa909e
EL
475
476/**
477 * \brief Workers version of the AF_PACKET processing.
478 *
479 * Start N threads with each thread doing all the work.
480 *
481 */
482int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx)
483{
484#ifdef HAVE_AF_PACKET
485 int ret;
486 char *live_dev = NULL;
487#endif
488 SCEnter();
489#ifdef HAVE_AF_PACKET
490
491 RunModeInitialize();
492 TimeModeSetLive();
493
2179ac25 494 (void)ConfGet("af-packet.live-interface", &live_dev);
beaa909e 495
662dccd8
EL
496 if (AFPPeersListInit() != TM_ECODE_OK) {
497 SCLogError(SC_ERR_RUNMODE, "Unable to init peers list.");
498 exit(EXIT_FAILURE);
499 }
500
beaa909e
EL
501 ret = RunModeSetLiveCaptureWorkers(de_ctx,
502 ParseAFPConfig,
503 AFPConfigGeThreadsCount,
504 "ReceiveAFP",
505 "DecodeAFP", "AFPacket",
506 live_dev);
507 if (ret != 0) {
625a1e07 508 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
beaa909e
EL
509 exit(EXIT_FAILURE);
510 }
511
662dccd8
EL
512 /* In IPS mode each threads must have a peer */
513 if (AFPPeersListCheck() != TM_ECODE_OK) {
514 SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer.");
515 exit(EXIT_FAILURE);
516 }
517
1ea80952 518 SCLogInfo("RunModeIdsAFPWorkers initialised");
beaa909e
EL
519
520#endif /* HAVE_AF_PACKET */
521 SCReturnInt(0);
522}
a6457262
EL
523
524/**
525 * @}
526 */