]>
Commit | Line | Data |
---|---|---|
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 |
61 | extern int max_pending_packets; |
62 | ||
c174c9d7 | 63 | static const char *default_mode_workers = NULL; |
c45d8985 EL |
64 | |
65 | const char *RunModeAFPGetDefaultMode(void) | |
66 | { | |
c174c9d7 | 67 | return default_mode_workers; |
c45d8985 EL |
68 | } |
69 | ||
70 | void 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 | 91 | static 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. */ | |
102 | static 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 | 114 | static 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", ©modestr) == 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 |
609 | finalize: |
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 | 704 | static int AFPConfigGeThreadsCount(void *conf) |
75c875b1 EL |
705 | { |
706 | AFPIfaceConfig *afp = (AFPIfaceConfig *)conf; | |
707 | return afp->threads; | |
708 | } | |
fbca1a4e | 709 | |
1e36053e EL |
710 | int 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", ©modestr) == 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", ©modestr) == 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 | 791 | int 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 | 838 | int 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 | 883 | int 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 | */ |