]>
Commit | Line | Data |
---|---|---|
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 |
53 | extern int max_pending_packets; |
54 | ||
e80b30c0 EL |
55 | static const char *default_mode_auto = NULL; |
56 | static const char *default_mode_autofp = NULL; | |
c45d8985 EL |
57 | |
58 | const char *RunModeAFPGetDefaultMode(void) | |
59 | { | |
fbca1a4e | 60 | return default_mode_autofp; |
c45d8985 EL |
61 | } |
62 | ||
63 | void 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 |
85 | void 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 | 104 | void *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 |
274 | int 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 | */ | |
298 | int 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 | ||
328 | int 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 | */ | |
366 | int 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 | */ | |
403 | int 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 | } |