]>
Commit | Line | Data |
---|---|---|
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 |
59 | extern int max_pending_packets; |
60 | ||
c45d8985 EL |
61 | const char *RunModeAFPGetDefaultMode(void) |
62 | { | |
8c6251ea | 63 | return "workers"; |
c45d8985 EL |
64 | } |
65 | ||
66 | void 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 | 86 | static 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. */ | |
97 | static 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 | 109 | static 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", ©modestr) == 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 |
605 | finalize: |
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 | 687 | static int AFPConfigGeThreadsCount(void *conf) |
75c875b1 EL |
688 | { |
689 | AFPIfaceConfig *afp = (AFPIfaceConfig *)conf; | |
690 | return afp->threads; | |
691 | } | |
fbca1a4e | 692 | |
1e36053e EL |
693 | int 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", ©modestr) == 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", ©modestr) == 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 | 774 | int 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 | 818 | int 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 | 860 | int 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 | */ |