]> git.ipfire.org Git - people/ms/suricata.git/blame - src/runmode-af-packet.c
capture: add data release mechanism
[people/ms/suricata.git] / src / runmode-af-packet.c
CommitLineData
c45d8985
EL
1/* Copyright (C) 2011 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
e80b30c0
EL
18/**
19 * \file
20 *
21 * \author Eric Leblond <eric@regit.org>
22 *
23 * AF_PACKET socket runmode
24 *
25 */
26
27
c45d8985 28#include "suricata-common.h"
e80b30c0 29#include "config.h"
c45d8985
EL
30#include "tm-threads.h"
31#include "conf.h"
32#include "runmodes.h"
33#include "runmode-af-packet.h"
34#include "log-httplog.h"
35#include "output.h"
36#include "cuda-packet-batcher.h"
c45d8985
EL
37#include "detect-engine-mpm.h"
38
39#include "alert-fastlog.h"
40#include "alert-prelude.h"
c45d8985
EL
41#include "alert-unified2-alert.h"
42#include "alert-debuglog.h"
43
44#include "util-debug.h"
45#include "util-time.h"
46#include "util-cpu.h"
47#include "util-affinity.h"
871b2189 48#include "util-device.h"
75c875b1 49#include "util-runmodes.h"
c45d8985 50
e80b30c0
EL
51#include "source-af-packet.h"
52
8879df80
EL
53extern int max_pending_packets;
54
e80b30c0
EL
55static const char *default_mode_auto = NULL;
56static const char *default_mode_autofp = NULL;
c45d8985
EL
57
58const char *RunModeAFPGetDefaultMode(void)
59{
fbca1a4e 60 return default_mode_autofp;
c45d8985
EL
61}
62
63void RunModeIdsAFPRegister(void)
64{
8d1fe9f2 65 default_mode_auto = "autofp";
c45d8985
EL
66 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "auto",
67 "Multi threaded af-packet mode",
68 RunModeIdsAFPAuto);
e80b30c0
EL
69 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single",
70 "Single threaded af-packet mode",
71 RunModeIdsAFPSingle);
beaa909e
EL
72 RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "workers",
73 "Workers af-packet mode, each thread does all"
74 " tasks from acquisition to logging",
75 RunModeIdsAFPWorkers);
e80b30c0
EL
76 default_mode_autofp = "autofp";
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
45d5c3ca
EL
85void AFPDerefConfig(void *conf)
86{
87 AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf;
88 /* Pcap config is used only once but cost of this low. */
89 if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) {
90 SCFree(pfp);
91 }
92}
93
fbca1a4e
EL
94/**
95 * \brief extract information from config file
96 *
97 * The returned structure will be freed by the thread init function.
98 * This is thus necessary to or copy the structure before giving it
99 * to thread or to reparse the file for each thread (and thus have
100 * new structure.
101 *
102 * \return a AFPIfaceConfig corresponding to the interface name
103 */
75c875b1 104void *ParseAFPConfig(const char *iface)
fbca1a4e
EL
105{
106 char *threadsstr = NULL;
107 ConfNode *if_root;
108 ConfNode *af_packet_node;
109 AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf));
110 char *tmpclusterid;
111 char *tmpctype;
112 intmax_t value;
67f791e8 113 int boolval;
f2a6fb8a 114 char *bpf_filter = NULL;
fbca1a4e 115
11bdf483 116 if (aconf == NULL) {
75c875b1
EL
117 return NULL;
118 }
119
11bdf483
VJ
120 if (iface == NULL) {
121 SCFree(aconf);
fbca1a4e
EL
122 return NULL;
123 }
11bdf483 124
fbca1a4e
EL
125 strlcpy(aconf->iface, iface, sizeof(aconf->iface));
126 aconf->threads = 1;
45d5c3ca 127 SC_ATOMIC_INIT(aconf->ref);
0227a87f 128 (void) SC_ATOMIC_ADD(aconf->ref, 1);
fbca1a4e
EL
129 aconf->buffer_size = 0;
130 aconf->cluster_id = 1;
131 aconf->cluster_type = PACKET_FANOUT_HASH;
df7dbe36 132 aconf->promisc = 1;
6062e00c 133 aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL;
45d5c3ca 134 aconf->DerefFunc = AFPDerefConfig;
49b7b00f 135 aconf->flags = 0;
f2a6fb8a
EL
136 aconf->bpf_filter = NULL;
137
138 if (ConfGet("bpf-filter", &bpf_filter) == 1) {
139 if (strlen(bpf_filter) > 0) {
140 aconf->bpf_filter = bpf_filter;
141 SCLogInfo("Going to use command-line provided bpf filter '%s'",
142 aconf->bpf_filter);
143 }
144 }
fbca1a4e
EL
145
146 /* Find initial node */
147 af_packet_node = ConfGetNode("af-packet");
148 if (af_packet_node == NULL) {
149 SCLogInfo("Unable to find af-packet config using default value");
150 return aconf;
151 }
152
153 if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface);
154 if (if_root == NULL) {
155 SCLogInfo("Unable to find af-packet config for "
156 "interface %s, using default value",
157 iface);
158 return aconf;
159 }
160
161 if (ConfGetChildValue(if_root, "threads", &threadsstr) != 1) {
162 aconf->threads = 1;
163 } else {
164 if (threadsstr != NULL) {
165 aconf->threads = (uint8_t)atoi(threadsstr);
166 }
167 }
168 if (aconf->threads == 0) {
169 aconf->threads = 1;
170 }
45d5c3ca
EL
171
172 SC_ATOMIC_RESET(aconf->ref);
0227a87f 173 (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
45d5c3ca 174
fbca1a4e
EL
175 if (ConfGetChildValue(if_root, "cluster-id", &tmpclusterid) != 1) {
176 SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config");
177 } else {
178 aconf->cluster_id = (uint16_t)atoi(tmpclusterid);
179 SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id);
180 }
181
182 if (ConfGetChildValue(if_root, "cluster-type", &tmpctype) != 1) {
623bb38d 183 SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type from config");
fbca1a4e
EL
184 } else if (strcmp(tmpctype, "cluster_round_robin") == 0) {
185 SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)",
186 aconf->iface);
187 aconf->cluster_type = PACKET_FANOUT_LB;
188 } else if (strcmp(tmpctype, "cluster_flow") == 0) {
189 /* In hash mode, we also ask for defragmentation needed to
190 * compute the hash */
191 uint16_t defrag = 0;
192 SCLogInfo("Using flow cluster mode for AF_PACKET (iface %s)",
193 aconf->iface);
194 ConfGetChildValueBool(if_root, "defrag", (int *)&defrag);
195 if (defrag) {
0df4c583 196 SCLogInfo("Using defrag kernel functionality for AF_PACKET (iface %s)",
fbca1a4e
EL
197 aconf->iface);
198 defrag = PACKET_FANOUT_FLAG_DEFRAG;
199 }
200 aconf->cluster_type = PACKET_FANOUT_HASH | defrag;
201 } else if (strcmp(tmpctype, "cluster_cpu") == 0) {
202 SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)",
203 aconf->iface);
204 aconf->cluster_type = PACKET_FANOUT_CPU;
205 } else {
206 SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype);
11bdf483 207 SCFree(aconf);
fbca1a4e
EL
208 return NULL;
209 }
210
f2a6fb8a
EL
211 /*load af_packet bpf filter*/
212 /* command line value has precedence */
213 if (ConfGet("bpf-filter", &bpf_filter) != 1) {
214 if (ConfGetChildValue(if_root, "bpf-filter", &bpf_filter) == 1) {
215 if (strlen(bpf_filter) > 0) {
216 aconf->bpf_filter = bpf_filter;
217 SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter);
218 }
219 }
220 }
221
fbca1a4e
EL
222 if ((ConfGetChildValueInt(if_root, "buffer-size", &value)) == 1) {
223 aconf->buffer_size = value;
224 } else {
225 aconf->buffer_size = 0;
226 }
8879df80
EL
227 if ((ConfGetChildValueInt(if_root, "ring-size", &value)) == 1) {
228 aconf->ring_size = value;
229 if (value * aconf->threads < max_pending_packets) {
230 aconf->ring_size = max_pending_packets / aconf->threads + 1;
231 SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. "
232 "Resetting to decent value %d.", aconf->ring_size);
233 /* We want at least that max_pending_packets packets can be handled by the
234 * interface. This is generous if we have multiple interfaces listening. */
235 }
236 } else {
237 /* We want that max_pending_packets packets can be handled by suricata
238 * for this interface. To take burst into account we multiply the obtained
239 * size by 2. */
240 aconf->ring_size = max_pending_packets * 2 / aconf->threads;
241 }
fbca1a4e 242
2179ac25 243 (void)ConfGetChildValueBool(if_root, "disable-promisc", (int *)&boolval);
67f791e8 244 if (boolval) {
df7dbe36
EL
245 SCLogInfo("Disabling promiscuous mode on iface %s",
246 aconf->iface);
247 aconf->promisc = 0;
248 }
2179ac25 249 (void)ConfGetChildValueBool(if_root, "use-mmap", (int *)&boolval);
49b7b00f
EL
250 if (boolval) {
251 SCLogInfo("Enabling mmaped capture on iface %s",
252 aconf->iface);
253 aconf->flags |= AFP_RING_MODE;
254 }
255
67f791e8 256
d24b3a0e 257 if (ConfGetChildValue(if_root, "checksum-checks", &tmpctype) == 1) {
6062e00c 258 if (strcmp(tmpctype, "auto") == 0) {
6062e00c 259 aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO;
6062e00c
EL
260 } else if (strcmp(tmpctype, "yes") == 0) {
261 aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE;
262 } else if (strcmp(tmpctype, "no") == 0) {
263 aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
264 } else if (strcmp(tmpctype, "kernel") == 0) {
265 aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL;
266 } else {
267 SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface);
268 }
269 }
df7dbe36 270
fbca1a4e
EL
271 return aconf;
272}
273
75c875b1
EL
274int AFPConfigGeThreadsCount(void *conf)
275{
276 AFPIfaceConfig *afp = (AFPIfaceConfig *)conf;
277 return afp->threads;
278}
fbca1a4e 279
c45d8985
EL
280/**
281 * \brief RunModeIdsAFPAuto set up the following thread packet handlers:
e80b30c0 282 * - Receive thread (from live iface)
c45d8985
EL
283 * - Decode thread
284 * - Stream thread
285 * - Detect: If we have only 1 cpu, it will setup one Detect thread
286 * If we have more than one, it will setup num_cpus - 1
287 * starting from the second cpu available.
288 * - Respond/Reject thread
289 * - Outputs thread
290 * By default the threads will use the first cpu available
291 * except the Detection threads if we have more than one cpu.
292 *
293 * \param de_ctx Pointer to the Detection Engine.
294 *
295 * \retval 0 If all goes well. (If any problem is detected the engine will
296 * exit()).
297 */
298int RunModeIdsAFPAuto(DetectEngineCtx *de_ctx)
299{
300 SCEnter();
e80b30c0
EL
301
302#ifdef HAVE_AF_PACKET
75c875b1
EL
303 int ret;
304 char *live_dev = NULL;
c45d8985
EL
305
306 RunModeInitialize();
c45d8985 307
75c875b1 308 TimeModeSetLive();
c45d8985 309
2179ac25 310 (void)ConfGet("af-packet.live-interface", &live_dev);
c45d8985 311
75c875b1 312 ret = RunModeSetLiveCaptureAuto(de_ctx,
6c55af84
EL
313 ParseAFPConfig,
314 AFPConfigGeThreadsCount,
315 "ReceiveAFP",
75c875b1
EL
316 "DecodeAFP", "RecvAFP",
317 live_dev);
318 if (ret != 0) {
625a1e07 319 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
c45d8985
EL
320 exit(EXIT_FAILURE);
321 }
322
75c875b1 323 SCLogInfo("RunModeIdsAFPAuto initialised");
e80b30c0
EL
324#endif
325 SCReturnInt(0);
326}
327
328int RunModeIdsAFPAutoFp(DetectEngineCtx *de_ctx)
329{
330 SCEnter();
331
332/* We include only if AF_PACKET is enabled */
333#ifdef HAVE_AF_PACKET
75c875b1 334 int ret;
e80b30c0 335 char *live_dev = NULL;
e80b30c0 336
fbca1a4e
EL
337 RunModeInitialize();
338
339 TimeModeSetLive();
340
2179ac25 341 (void)ConfGet("af-packet.live-interface", &live_dev);
fbca1a4e 342
75c875b1 343 SCLogDebug("live_dev %s", live_dev);
e80b30c0 344
75c875b1
EL
345 ret = RunModeSetLiveCaptureAutoFp(de_ctx,
346 ParseAFPConfig,
347 AFPConfigGeThreadsCount,
348 "ReceiveAFP",
349 "DecodeAFP", "RxAFP",
350 live_dev);
351 if (ret != 0) {
625a1e07 352 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
75c875b1 353 exit(EXIT_FAILURE);
e80b30c0
EL
354 }
355
75c875b1 356 SCLogInfo("RunModeIdsAFPAutoFp initialised");
e80b30c0
EL
357
358#endif /* HAVE_AF_PACKET */
359
360 SCReturnInt(0);
361}
362
363/**
364 * \brief Single thread version of the AF_PACKET processing.
365 */
366int RunModeIdsAFPSingle(DetectEngineCtx *de_ctx)
367{
1aab2470
EL
368#ifdef HAVE_AF_PACKET
369 int ret;
370 char *live_dev = NULL;
371#endif
3801e004
AS
372 SCEnter();
373#ifdef HAVE_AF_PACKET
e80b30c0
EL
374
375 RunModeInitialize();
376 TimeModeSetLive();
377
2179ac25 378 (void)ConfGet("af-packet.live-interface", &live_dev);
e80b30c0 379
1aab2470 380 ret = RunModeSetLiveCaptureSingle(de_ctx,
77869a2d
EL
381 ParseAFPConfig,
382 AFPConfigGeThreadsCount,
383 "ReceiveAFP",
1aab2470
EL
384 "DecodeAFP", "AFPacket",
385 live_dev);
386 if (ret != 0) {
625a1e07 387 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
e80b30c0
EL
388 exit(EXIT_FAILURE);
389 }
e80b30c0 390
1aab2470 391 SCLogInfo("RunModeIdsAFPSingle initialised");
e80b30c0
EL
392
393#endif /* HAVE_AF_PACKET */
394 SCReturnInt(0);
c45d8985 395}
beaa909e
EL
396
397/**
398 * \brief Workers version of the AF_PACKET processing.
399 *
400 * Start N threads with each thread doing all the work.
401 *
402 */
403int RunModeIdsAFPWorkers(DetectEngineCtx *de_ctx)
404{
405#ifdef HAVE_AF_PACKET
406 int ret;
407 char *live_dev = NULL;
408#endif
409 SCEnter();
410#ifdef HAVE_AF_PACKET
411
412 RunModeInitialize();
413 TimeModeSetLive();
414
2179ac25 415 (void)ConfGet("af-packet.live-interface", &live_dev);
beaa909e
EL
416
417 ret = RunModeSetLiveCaptureWorkers(de_ctx,
418 ParseAFPConfig,
419 AFPConfigGeThreadsCount,
420 "ReceiveAFP",
421 "DecodeAFP", "AFPacket",
422 live_dev);
423 if (ret != 0) {
625a1e07 424 SCLogError(SC_ERR_RUNMODE, "Unable to start runmode");
beaa909e
EL
425 exit(EXIT_FAILURE);
426 }
427
428 SCLogInfo("RunModeIdsAFPSingle initialised");
429
430#endif /* HAVE_AF_PACKET */
431 SCReturnInt(0);
432}