]>
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 | 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-debuglog.h" |
46 | ||
08eec083 EL |
47 | #include "flow-bypass.h" |
48 | ||
c45d8985 EL |
49 | #include "util-debug.h" |
50 | #include "util-time.h" | |
51 | #include "util-cpu.h" | |
52 | #include "util-affinity.h" | |
871b2189 | 53 | #include "util-device.h" |
75c875b1 | 54 | #include "util-runmodes.h" |
56373e5b | 55 | #include "util-ioctl.h" |
91e1256b | 56 | #include "util-ebpf.h" |
e7c0f0ad | 57 | #include "util-byte.h" |
c45d8985 | 58 | |
e80b30c0 EL |
59 | #include "source-af-packet.h" |
60 | ||
8879df80 EL |
61 | extern int max_pending_packets; |
62 | ||
c45d8985 EL |
63 | const char *RunModeAFPGetDefaultMode(void) |
64 | { | |
8c6251ea | 65 | return "workers"; |
c45d8985 EL |
66 | } |
67 | ||
68 | void RunModeIdsAFPRegister(void) | |
69 | { | |
e80b30c0 EL |
70 | RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single", |
71 | "Single threaded af-packet mode", | |
72 | RunModeIdsAFPSingle); | |
beaa909e EL |
73 | RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "workers", |
74 | "Workers af-packet mode, each thread does all" | |
75 | " tasks from acquisition to logging", | |
76 | RunModeIdsAFPWorkers); | |
e80b30c0 EL |
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 | ||
994bc15c EL |
85 | |
86 | #ifdef HAVE_AF_PACKET | |
87 | ||
ab1200fb | 88 | static void AFPDerefConfig(void *conf) |
45d5c3ca EL |
89 | { |
90 | AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf; | |
91 | /* Pcap config is used only once but cost of this low. */ | |
531ff3dd | 92 | if (SC_ATOMIC_SUB(pfp->ref, 1) == 1) { |
45d5c3ca EL |
93 | SCFree(pfp); |
94 | } | |
95 | } | |
96 | ||
f89a4219 VJ |
97 | /* if cluster id is not set, assign it automagically, uniq value per |
98 | * interface. */ | |
99 | static int cluster_id_auto = 1; | |
100 | ||
fbca1a4e EL |
101 | /** |
102 | * \brief extract information from config file | |
103 | * | |
104 | * The returned structure will be freed by the thread init function. | |
105 | * This is thus necessary to or copy the structure before giving it | |
106 | * to thread or to reparse the file for each thread (and thus have | |
107 | * new structure. | |
108 | * | |
109 | * \return a AFPIfaceConfig corresponding to the interface name | |
110 | */ | |
ab1200fb | 111 | static void *ParseAFPConfig(const char *iface) |
fbca1a4e | 112 | { |
ab1200fb | 113 | const char *threadsstr = NULL; |
fbca1a4e | 114 | ConfNode *if_root; |
4ae27756 | 115 | ConfNode *if_default = NULL; |
fbca1a4e | 116 | ConfNode *af_packet_node; |
ab1200fb VJ |
117 | const char *tmpclusterid; |
118 | const char *tmpctype; | |
119 | const char *copymodestr; | |
fbca1a4e | 120 | intmax_t value; |
67f791e8 | 121 | int boolval; |
ab1200fb VJ |
122 | const char *bpf_filter = NULL; |
123 | const char *out_iface = NULL; | |
3bb40894 | 124 | int cluster_type = PACKET_FANOUT_HASH; |
91e1256b | 125 | const char *ebpf_file = NULL; |
fbca1a4e | 126 | |
9f7ba071 | 127 | if (iface == NULL) { |
75c875b1 EL |
128 | return NULL; |
129 | } | |
130 | ||
9f7ba071 VJ |
131 | AFPIfaceConfig *aconf = SCCalloc(1, sizeof(*aconf)); |
132 | if (unlikely(aconf == NULL)) { | |
fbca1a4e EL |
133 | return NULL; |
134 | } | |
11bdf483 | 135 | |
fbca1a4e | 136 | strlcpy(aconf->iface, iface, sizeof(aconf->iface)); |
9f7ba071 | 137 | aconf->threads = 0; |
45d5c3ca | 138 | SC_ATOMIC_INIT(aconf->ref); |
0227a87f | 139 | (void) SC_ATOMIC_ADD(aconf->ref, 1); |
fbca1a4e EL |
140 | aconf->buffer_size = 0; |
141 | aconf->cluster_id = 1; | |
3bb40894 | 142 | aconf->cluster_type = cluster_type | PACKET_FANOUT_FLAG_DEFRAG; |
df7dbe36 | 143 | aconf->promisc = 1; |
6062e00c | 144 | aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; |
45d5c3ca | 145 | aconf->DerefFunc = AFPDerefConfig; |
f7124b11 | 146 | aconf->flags = AFP_RING_MODE; |
f2a6fb8a | 147 | aconf->bpf_filter = NULL; |
91e1256b EL |
148 | aconf->ebpf_lb_file = NULL; |
149 | aconf->ebpf_lb_fd = -1; | |
150 | aconf->ebpf_filter_file = NULL; | |
151 | aconf->ebpf_filter_fd = -1; | |
662dccd8 | 152 | aconf->out_iface = NULL; |
c8b3f441 | 153 | aconf->copy_mode = AFP_COPY_MODE_NONE; |
9f7ba071 VJ |
154 | aconf->block_timeout = 10; |
155 | aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER; | |
315c29a8 EL |
156 | #ifdef HAVE_PACKET_EBPF |
157 | aconf->ebpf_t_config.cpus_count = UtilCpuGetNumProcessorsConfigured(); | |
158 | #endif | |
f2a6fb8a EL |
159 | |
160 | if (ConfGet("bpf-filter", &bpf_filter) == 1) { | |
161 | if (strlen(bpf_filter) > 0) { | |
162 | aconf->bpf_filter = bpf_filter; | |
b3bf7a57 | 163 | SCLogConfig("Going to use command-line provided bpf filter '%s'", |
f2a6fb8a EL |
164 | aconf->bpf_filter); |
165 | } | |
166 | } | |
fbca1a4e EL |
167 | |
168 | /* Find initial node */ | |
169 | af_packet_node = ConfGetNode("af-packet"); | |
170 | if (af_packet_node == NULL) { | |
9f7ba071 VJ |
171 | SCLogInfo("unable to find af-packet config using default values"); |
172 | goto finalize; | |
fbca1a4e EL |
173 | } |
174 | ||
aa8e747e | 175 | if_root = ConfFindDeviceConfig(af_packet_node, iface); |
aa8e747e | 176 | if_default = ConfFindDeviceConfig(af_packet_node, "default"); |
4ae27756 EL |
177 | |
178 | if (if_root == NULL && if_default == NULL) { | |
9f7ba071 VJ |
179 | SCLogInfo("unable to find af-packet config for " |
180 | "interface \"%s\" or \"default\", using default values", | |
fbca1a4e | 181 | iface); |
9f7ba071 | 182 | goto finalize; |
fbca1a4e EL |
183 | } |
184 | ||
4ae27756 EL |
185 | /* If there is no setting for current interface use default one as main iface */ |
186 | if (if_root == NULL) { | |
187 | if_root = if_default; | |
188 | if_default = NULL; | |
189 | } | |
190 | ||
191 | if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { | |
c174c9d7 | 192 | aconf->threads = 0; |
fbca1a4e EL |
193 | } else { |
194 | if (threadsstr != NULL) { | |
c174c9d7 VJ |
195 | if (strcmp(threadsstr, "auto") == 0) { |
196 | aconf->threads = 0; | |
197 | } else { | |
e7c0f0ad SB |
198 | if (StringParseInt32(&aconf->threads, 10, 0, (const char *)threadsstr) < 0) { |
199 | SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid number of " | |
200 | "threads, resetting to default"); | |
201 | aconf->threads = 0; | |
202 | } | |
c174c9d7 | 203 | } |
fbca1a4e EL |
204 | } |
205 | } | |
45d5c3ca | 206 | |
4ae27756 | 207 | if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { |
662dccd8 EL |
208 | if (strlen(out_iface) > 0) { |
209 | aconf->out_iface = out_iface; | |
210 | } | |
211 | } | |
212 | ||
876b356b | 213 | if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval) == 1) { |
f7124b11 | 214 | if (!boolval) { |
b3bf7a57 | 215 | SCLogConfig("Disabling mmaped capture on iface %s", |
876b356b | 216 | aconf->iface); |
f7124b11 | 217 | aconf->flags &= ~(AFP_RING_MODE|AFP_TPACKET_V3); |
876b356b | 218 | } |
662dccd8 | 219 | } |
876b356b | 220 | |
8035d834 EL |
221 | if (aconf->flags & AFP_RING_MODE) { |
222 | (void)ConfGetChildValueBoolWithDefault(if_root, if_default, | |
223 | "mmap-locked", (int *)&boolval); | |
224 | if (boolval) { | |
b3bf7a57 | 225 | SCLogConfig("Enabling locked memory for mmap on iface %s", |
bae1b03c | 226 | aconf->iface); |
8035d834 EL |
227 | aconf->flags |= AFP_MMAP_LOCKED; |
228 | } | |
f7124b11 VJ |
229 | |
230 | if (ConfGetChildValueBoolWithDefault(if_root, if_default, | |
231 | "tpacket-v3", (int *)&boolval) == 1) | |
232 | { | |
233 | if (boolval) { | |
234 | if (strcasecmp(RunmodeGetActive(), "workers") == 0) { | |
8035d834 | 235 | #ifdef HAVE_TPACKET_V3 |
f7124b11 VJ |
236 | SCLogConfig("Enabling tpacket v3 capture on iface %s", |
237 | aconf->iface); | |
238 | aconf->flags |= AFP_TPACKET_V3; | |
c2d0d938 | 239 | #else |
f7124b11 VJ |
240 | SCLogNotice("System too old for tpacket v3 switching to v2"); |
241 | aconf->flags &= ~AFP_TPACKET_V3; | |
c2d0d938 | 242 | #endif |
f7124b11 VJ |
243 | } else { |
244 | SCLogWarning(SC_ERR_RUNMODE, | |
245 | "tpacket v3 is only implemented for 'workers' runmode." | |
246 | " Switching to tpacket v2."); | |
247 | aconf->flags &= ~AFP_TPACKET_V3; | |
248 | } | |
8035d834 | 249 | } else { |
9f7ba071 | 250 | aconf->flags &= ~AFP_TPACKET_V3; |
8035d834 EL |
251 | } |
252 | } | |
f7124b11 | 253 | |
8035d834 EL |
254 | (void)ConfGetChildValueBoolWithDefault(if_root, if_default, |
255 | "use-emergency-flush", (int *)&boolval); | |
256 | if (boolval) { | |
b3bf7a57 | 257 | SCLogConfig("Enabling ring emergency flush on iface %s", |
8035d834 EL |
258 | aconf->iface); |
259 | aconf->flags |= AFP_EMERGENCY_MODE; | |
bae1b03c | 260 | } |
27b5136b EL |
261 | } |
262 | ||
662dccd8 | 263 | aconf->copy_mode = AFP_COPY_MODE_NONE; |
4ae27756 | 264 | if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { |
662dccd8 EL |
265 | if (aconf->out_iface == NULL) { |
266 | SCLogInfo("Copy mode activated but no destination" | |
267 | " iface. Disabling feature"); | |
268 | } else if (!(aconf->flags & AFP_RING_MODE)) { | |
269 | SCLogInfo("Copy mode activated but use-mmap " | |
270 | "set to no. Disabling feature"); | |
271 | } else if (strlen(copymodestr) <= 0) { | |
272 | aconf->out_iface = NULL; | |
273 | } else if (strcmp(copymodestr, "ips") == 0) { | |
274 | SCLogInfo("AF_PACKET IPS mode activated %s->%s", | |
275 | iface, | |
276 | aconf->out_iface); | |
277 | aconf->copy_mode = AFP_COPY_MODE_IPS; | |
050d8f78 EL |
278 | if (aconf->flags & AFP_TPACKET_V3) { |
279 | SCLogWarning(SC_ERR_RUNMODE, "Using tpacket_v3 in IPS mode will result in high latency"); | |
280 | } | |
662dccd8 EL |
281 | } else if (strcmp(copymodestr, "tap") == 0) { |
282 | SCLogInfo("AF_PACKET TAP mode activated %s->%s", | |
283 | iface, | |
284 | aconf->out_iface); | |
285 | aconf->copy_mode = AFP_COPY_MODE_TAP; | |
050d8f78 EL |
286 | if (aconf->flags & AFP_TPACKET_V3) { |
287 | SCLogWarning(SC_ERR_RUNMODE, "Using tpacket_v3 in TAP mode will result in high latency"); | |
288 | } | |
662dccd8 EL |
289 | } else { |
290 | SCLogInfo("Invalid mode (not in tap, ips)"); | |
291 | } | |
292 | } | |
293 | ||
4ae27756 | 294 | if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { |
f89a4219 | 295 | aconf->cluster_id = (uint16_t)(cluster_id_auto++); |
fbca1a4e | 296 | } else { |
e22b345b | 297 | if (StringParseUint16(&aconf->cluster_id, 10, 0, (const char *)tmpclusterid) < 0) { |
e7c0f0ad SB |
298 | SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid cluster_id, resetting to 0"); |
299 | aconf->cluster_id = 0; | |
300 | } | |
e22b345b | 301 | SCLogDebug("Going to use cluster-id %" PRIu16, aconf->cluster_id); |
fbca1a4e EL |
302 | } |
303 | ||
4ae27756 | 304 | if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { |
f89a4219 VJ |
305 | /* default to our safest choice: flow hashing + defrag enabled */ |
306 | aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; | |
3bb40894 | 307 | cluster_type = PACKET_FANOUT_HASH; |
fbca1a4e | 308 | } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { |
b3bf7a57 | 309 | SCLogConfig("Using round-robin cluster mode for AF_PACKET (iface %s)", |
fbca1a4e EL |
310 | aconf->iface); |
311 | aconf->cluster_type = PACKET_FANOUT_LB; | |
3bb40894 | 312 | cluster_type = PACKET_FANOUT_LB; |
fbca1a4e EL |
313 | } else if (strcmp(tmpctype, "cluster_flow") == 0) { |
314 | /* In hash mode, we also ask for defragmentation needed to | |
315 | * compute the hash */ | |
316 | uint16_t defrag = 0; | |
4c6595f4 | 317 | int conf_val = 0; |
b3bf7a57 | 318 | SCLogConfig("Using flow cluster mode for AF_PACKET (iface %s)", |
fbca1a4e | 319 | aconf->iface); |
4c6595f4 EL |
320 | ConfGetChildValueBoolWithDefault(if_root, if_default, "defrag", &conf_val); |
321 | if (conf_val) { | |
b3bf7a57 | 322 | SCLogConfig("Using defrag kernel functionality for AF_PACKET (iface %s)", |
fbca1a4e EL |
323 | aconf->iface); |
324 | defrag = PACKET_FANOUT_FLAG_DEFRAG; | |
325 | } | |
326 | aconf->cluster_type = PACKET_FANOUT_HASH | defrag; | |
3bb40894 | 327 | cluster_type = PACKET_FANOUT_HASH; |
fbca1a4e | 328 | } else if (strcmp(tmpctype, "cluster_cpu") == 0) { |
b3bf7a57 | 329 | SCLogConfig("Using cpu cluster mode for AF_PACKET (iface %s)", |
fbca1a4e EL |
330 | aconf->iface); |
331 | aconf->cluster_type = PACKET_FANOUT_CPU; | |
3bb40894 | 332 | cluster_type = PACKET_FANOUT_CPU; |
dc306f3b | 333 | } else if (strcmp(tmpctype, "cluster_qm") == 0) { |
b3bf7a57 | 334 | SCLogConfig("Using queue based cluster mode for AF_PACKET (iface %s)", |
dc306f3b EL |
335 | aconf->iface); |
336 | aconf->cluster_type = PACKET_FANOUT_QM; | |
3bb40894 | 337 | cluster_type = PACKET_FANOUT_QM; |
dc306f3b | 338 | } else if (strcmp(tmpctype, "cluster_random") == 0) { |
b3bf7a57 | 339 | SCLogConfig("Using random based cluster mode for AF_PACKET (iface %s)", |
dc306f3b EL |
340 | aconf->iface); |
341 | aconf->cluster_type = PACKET_FANOUT_RND; | |
3bb40894 | 342 | cluster_type = PACKET_FANOUT_RND; |
dc306f3b | 343 | } else if (strcmp(tmpctype, "cluster_rollover") == 0) { |
b3bf7a57 | 344 | SCLogConfig("Using rollover based cluster mode for AF_PACKET (iface %s)", |
dc306f3b | 345 | aconf->iface); |
5d76f089 EL |
346 | SCLogWarning(SC_WARN_UNCOMMON, "Rollover mode is causing severe flow " |
347 | "tracking issues, use it at your own risk."); | |
dc306f3b | 348 | aconf->cluster_type = PACKET_FANOUT_ROLLOVER; |
3bb40894 | 349 | cluster_type = PACKET_FANOUT_ROLLOVER; |
91e1256b EL |
350 | #ifdef HAVE_PACKET_EBPF |
351 | } else if (strcmp(tmpctype, "cluster_ebpf") == 0) { | |
352 | SCLogInfo("Using ebpf based cluster mode for AF_PACKET (iface %s)", | |
353 | aconf->iface); | |
354 | aconf->cluster_type = PACKET_FANOUT_EBPF; | |
355 | cluster_type = PACKET_FANOUT_EBPF; | |
356 | #endif | |
fbca1a4e | 357 | } else { |
9f7ba071 | 358 | SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); |
fbca1a4e EL |
359 | } |
360 | ||
8fde842f EL |
361 | int conf_val = 0; |
362 | ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val); | |
363 | if (conf_val) { | |
b3bf7a57 | 364 | SCLogConfig("Using rollover kernel functionality for AF_PACKET (iface %s)", |
8fde842f EL |
365 | aconf->iface); |
366 | aconf->cluster_type |= PACKET_FANOUT_FLAG_ROLLOVER; | |
5d76f089 EL |
367 | SCLogWarning(SC_WARN_UNCOMMON, "Rollover option is causing severe flow " |
368 | "tracking issues, use it at your own risk."); | |
8fde842f EL |
369 | } |
370 | ||
f2a6fb8a EL |
371 | /*load af_packet bpf filter*/ |
372 | /* command line value has precedence */ | |
373 | if (ConfGet("bpf-filter", &bpf_filter) != 1) { | |
4ae27756 | 374 | if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { |
f2a6fb8a EL |
375 | if (strlen(bpf_filter) > 0) { |
376 | aconf->bpf_filter = bpf_filter; | |
b3bf7a57 | 377 | SCLogConfig("Going to use bpf filter %s", aconf->bpf_filter); |
f2a6fb8a EL |
378 | } |
379 | } | |
380 | } | |
381 | ||
91e1256b EL |
382 | if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-lb-file", &ebpf_file) != 1) { |
383 | aconf->ebpf_lb_file = NULL; | |
384 | } else { | |
385 | #ifdef HAVE_PACKET_EBPF | |
2598078e | 386 | SCLogConfig("af-packet will use '%s' as eBPF load balancing file", |
91e1256b | 387 | ebpf_file); |
91e1256b | 388 | aconf->ebpf_lb_file = ebpf_file; |
4f48c457 EL |
389 | aconf->ebpf_t_config.flags |= EBPF_SOCKET_FILTER; |
390 | #endif | |
391 | } | |
392 | ||
36838017 | 393 | #ifdef HAVE_PACKET_EBPF |
6fdcb127 EL |
394 | boolval = false; |
395 | if (ConfGetChildValueBoolWithDefault(if_root, if_default, "pinned-maps", (int *)&boolval) == 1) { | |
4f48c457 EL |
396 | if (boolval) { |
397 | SCLogConfig("Using pinned maps on iface %s", | |
398 | aconf->iface); | |
399 | aconf->ebpf_t_config.flags |= EBPF_PINNED_MAPS; | |
400 | } | |
5b056c15 | 401 | const char *pinned_maps_name = NULL; |
d25e8dbf EL |
402 | if (ConfGetChildValueWithDefault(if_root, if_default, |
403 | "pinned-maps-name", | |
404 | &pinned_maps_name) != 1) { | |
405 | aconf->ebpf_t_config.pinned_maps_name = pinned_maps_name; | |
406 | } else { | |
407 | aconf->ebpf_t_config.pinned_maps_name = NULL; | |
408 | } | |
eff56acc EL |
409 | } else { |
410 | aconf->ebpf_t_config.pinned_maps_name = NULL; | |
91e1256b | 411 | } |
36838017 | 412 | #endif |
91e1256b | 413 | |
06173267 | 414 | #ifdef HAVE_PACKET_EBPF |
91e1256b EL |
415 | /* One shot loading of the eBPF file */ |
416 | if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) { | |
126488f7 | 417 | int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_lb_file, "loadbalancer", |
4f48c457 | 418 | &aconf->ebpf_lb_fd, |
d25e8dbf | 419 | &aconf->ebpf_t_config); |
91e1256b EL |
420 | if (ret != 0) { |
421 | SCLogWarning(SC_ERR_INVALID_VALUE, "Error when loading eBPF lb file"); | |
422 | } | |
06173267 | 423 | } |
91e1256b | 424 | #else |
06173267 | 425 | if (aconf->ebpf_lb_file) { |
91e1256b | 426 | SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in"); |
91e1256b | 427 | } |
06173267 | 428 | #endif |
91e1256b EL |
429 | |
430 | if (ConfGetChildValueWithDefault(if_root, if_default, "ebpf-filter-file", &ebpf_file) != 1) { | |
431 | aconf->ebpf_filter_file = NULL; | |
432 | } else { | |
433 | #ifdef HAVE_PACKET_EBPF | |
2598078e | 434 | SCLogConfig("af-packet will use '%s' as eBPF filter file", |
91e1256b | 435 | ebpf_file); |
91e1256b | 436 | aconf->ebpf_filter_file = ebpf_file; |
315c29a8 | 437 | aconf->ebpf_t_config.mode = AFP_MODE_EBPF_BYPASS; |
bd28f77a | 438 | aconf->ebpf_t_config.flags |= EBPF_SOCKET_FILTER; |
36838017 | 439 | #endif |
06173267 EL |
440 | ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val); |
441 | if (conf_val) { | |
08eec083 | 442 | #ifdef HAVE_PACKET_EBPF |
06173267 EL |
443 | SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)", |
444 | aconf->iface); | |
445 | aconf->flags |= AFP_BYPASS; | |
b07bda7a | 446 | BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow, NULL); |
08eec083 EL |
447 | #else |
448 | SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in"); | |
449 | #endif | |
06173267 | 450 | } |
91e1256b EL |
451 | } |
452 | ||
453 | /* One shot loading of the eBPF file */ | |
454 | if (aconf->ebpf_filter_file) { | |
455 | #ifdef HAVE_PACKET_EBPF | |
126488f7 | 456 | int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_filter_file, "filter", |
4f48c457 | 457 | &aconf->ebpf_filter_fd, |
d25e8dbf | 458 | &aconf->ebpf_t_config); |
91e1256b EL |
459 | if (ret != 0) { |
460 | SCLogWarning(SC_ERR_INVALID_VALUE, | |
461 | "Error when loading eBPF filter file"); | |
462 | } | |
463 | #else | |
464 | SCLogError(SC_ERR_UNIMPLEMENTED, "eBPF support is not build-in"); | |
465 | #endif | |
466 | } | |
467 | ||
8c880879 EL |
468 | if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-filter-file", &ebpf_file) != 1) { |
469 | aconf->xdp_filter_file = NULL; | |
470 | } else { | |
36838017 | 471 | #ifdef HAVE_PACKET_XDP |
315c29a8 | 472 | aconf->ebpf_t_config.mode = AFP_MODE_XDP_BYPASS; |
4f48c457 | 473 | aconf->ebpf_t_config.flags |= EBPF_XDP_CODE; |
8c880879 EL |
474 | aconf->xdp_filter_file = ebpf_file; |
475 | ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val); | |
476 | if (conf_val) { | |
477 | SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)", | |
478 | aconf->iface); | |
479 | aconf->flags |= AFP_XDPBYPASS; | |
7df30070 EL |
480 | /* if maps are pinned we need to read them at start */ |
481 | if (aconf->ebpf_t_config.flags & EBPF_PINNED_MAPS) { | |
482 | RunModeEnablesBypassManager(); | |
483 | struct ebpf_timeout_config *ebt = SCCalloc(1, sizeof(struct ebpf_timeout_config)); | |
484 | if (ebt == NULL) { | |
485 | SCLogError(SC_ERR_MEM_ALLOC, "Flow bypass alloc error"); | |
486 | } else { | |
487 | memcpy(ebt, &(aconf->ebpf_t_config), sizeof(struct ebpf_timeout_config)); | |
488 | BypassedFlowManagerRegisterCheckFunc(NULL, | |
489 | EBPFCheckBypassedFlowCreate, | |
490 | (void *)ebt); | |
491 | } | |
492 | } | |
315c29a8 | 493 | BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow, NULL); |
36838017 | 494 | } |
08eec083 | 495 | #else |
0f6b1297 | 496 | SCLogWarning(SC_ERR_UNIMPLEMENTED, "XDP filter set but XDP support is not built-in"); |
08eec083 | 497 | #endif |
8c880879 EL |
498 | #ifdef HAVE_PACKET_XDP |
499 | const char *xdp_mode; | |
500 | if (ConfGetChildValueWithDefault(if_root, if_default, "xdp-mode", &xdp_mode) != 1) { | |
501 | aconf->xdp_mode = XDP_FLAGS_SKB_MODE; | |
502 | } else { | |
503 | if (!strcmp(xdp_mode, "soft")) { | |
504 | aconf->xdp_mode = XDP_FLAGS_SKB_MODE; | |
505 | } else if (!strcmp(xdp_mode, "driver")) { | |
506 | aconf->xdp_mode = XDP_FLAGS_DRV_MODE; | |
507 | } else if (!strcmp(xdp_mode, "hw")) { | |
508 | aconf->xdp_mode = XDP_FLAGS_HW_MODE; | |
0c3e1e85 | 509 | aconf->ebpf_t_config.flags |= EBPF_XDP_HW_MODE; |
8c880879 EL |
510 | } else { |
511 | SCLogWarning(SC_ERR_INVALID_VALUE, | |
512 | "Invalid xdp-mode value: '%s'", xdp_mode); | |
513 | } | |
514 | } | |
315c29a8 | 515 | |
567b5ee1 EL |
516 | boolval = true; |
517 | if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-percpu-hash", (int *)&boolval) == 1) { | |
518 | if (boolval == false) { | |
315c29a8 EL |
519 | SCLogConfig("Not using percpu hash on iface %s", |
520 | aconf->iface); | |
521 | aconf->ebpf_t_config.cpus_count = 1; | |
522 | } | |
523 | } | |
8c880879 EL |
524 | #endif |
525 | } | |
526 | ||
527 | /* One shot loading of the eBPF file */ | |
528 | if (aconf->xdp_filter_file) { | |
529 | #ifdef HAVE_PACKET_XDP | |
126488f7 | 530 | int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp", |
4f48c457 | 531 | &aconf->xdp_filter_fd, |
d25e8dbf | 532 | &aconf->ebpf_t_config); |
6fdcb127 EL |
533 | switch (ret) { |
534 | case 1: | |
535 | SCLogInfo("Loaded pinned maps from sysfs"); | |
536 | break; | |
537 | case -1: | |
8c880879 | 538 | SCLogWarning(SC_ERR_INVALID_VALUE, |
6fdcb127 EL |
539 | "Error when loading XDP filter file"); |
540 | break; | |
541 | case 0: | |
542 | ret = EBPFSetupXDP(aconf->iface, aconf->xdp_filter_fd, aconf->xdp_mode); | |
543 | if (ret != 0) { | |
544 | SCLogWarning(SC_ERR_INVALID_VALUE, | |
545 | "Error when setting up XDP"); | |
4f57008a | 546 | } else { |
6fdcb127 EL |
547 | /* Try to get the xdp-cpu-redirect key */ |
548 | const char *cpuset; | |
549 | if (ConfGetChildValueWithDefault(if_root, if_default, | |
550 | "xdp-cpu-redirect", &cpuset) == 1) { | |
551 | SCLogConfig("Setting up CPU map XDP"); | |
552 | ConfNode *node = ConfGetChildWithDefault(if_root, if_default, "xdp-cpu-redirect"); | |
553 | if (node == NULL) { | |
edf2db4e EL |
554 | SCLogError(SC_ERR_INVALID_VALUE, |
555 | "Previously found node has disappeared"); | |
6fdcb127 EL |
556 | } else { |
557 | EBPFBuildCPUSet(node, aconf->iface); | |
558 | } | |
559 | } else { | |
4f57008a EL |
560 | /* It will just set CPU count to 0 */ |
561 | EBPFBuildCPUSet(NULL, aconf->iface); | |
6fdcb127 EL |
562 | } |
563 | } | |
564 | /* we have a peer and we use bypass so we can set up XDP iface redirect */ | |
565 | if (aconf->out_iface) { | |
566 | EBPFSetPeerIface(aconf->iface, aconf->out_iface); | |
4f57008a | 567 | } |
8c880879 EL |
568 | } |
569 | #else | |
570 | SCLogError(SC_ERR_UNIMPLEMENTED, "XDP support is not built-in"); | |
571 | #endif | |
572 | } | |
573 | ||
4ae27756 | 574 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "buffer-size", &value)) == 1) { |
fbca1a4e EL |
575 | aconf->buffer_size = value; |
576 | } else { | |
577 | aconf->buffer_size = 0; | |
578 | } | |
4ae27756 | 579 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) { |
8879df80 | 580 | aconf->ring_size = value; |
8879df80 | 581 | } |
fbca1a4e | 582 | |
fa902abe EL |
583 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) { |
584 | if (value % getpagesize()) { | |
585 | SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize."); | |
586 | } else { | |
587 | aconf->block_size = value; | |
588 | } | |
589 | } | |
590 | ||
234aefdf | 591 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { |
fa902abe EL |
592 | aconf->block_timeout = value; |
593 | } else { | |
594 | aconf->block_timeout = 10; | |
595 | } | |
596 | ||
4ae27756 | 597 | (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); |
67f791e8 | 598 | if (boolval) { |
b3bf7a57 | 599 | SCLogConfig("Disabling promiscuous mode on iface %s", |
df7dbe36 EL |
600 | aconf->iface); |
601 | aconf->promisc = 0; | |
602 | } | |
67f791e8 | 603 | |
4ae27756 | 604 | if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { |
6062e00c | 605 | if (strcmp(tmpctype, "auto") == 0) { |
6062e00c | 606 | aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; |
d18e2f6e | 607 | } else if (ConfValIsTrue(tmpctype)) { |
6062e00c | 608 | aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; |
d18e2f6e | 609 | } else if (ConfValIsFalse(tmpctype)) { |
6062e00c EL |
610 | aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; |
611 | } else if (strcmp(tmpctype, "kernel") == 0) { | |
612 | aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; | |
613 | } else { | |
614 | SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); | |
615 | } | |
616 | } | |
df7dbe36 | 617 | |
9f7ba071 VJ |
618 | finalize: |
619 | ||
402bdf9b VJ |
620 | /* if the number of threads is not 1, we need to first check if fanout |
621 | * functions on this system. */ | |
622 | if (aconf->threads != 1) { | |
8940a9d3 | 623 | if (AFPIsFanoutSupported(aconf->cluster_id) == 0) { |
402bdf9b VJ |
624 | if (aconf->threads != 0) { |
625 | SCLogNotice("fanout not supported on this system, falling " | |
626 | "back to 1 capture thread"); | |
627 | } | |
628 | aconf->threads = 1; | |
629 | } | |
630 | } | |
631 | ||
632 | /* try to automagically set the proper number of threads */ | |
9f7ba071 | 633 | if (aconf->threads == 0) { |
3bb40894 VJ |
634 | /* for cluster_flow use core count */ |
635 | if (cluster_type == PACKET_FANOUT_HASH) { | |
636 | aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); | |
637 | SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads); | |
638 | ||
639 | /* for cluster_qm use RSS queue count */ | |
640 | } else if (cluster_type == PACKET_FANOUT_QM) { | |
641 | int rss_queues = GetIfaceRSSQueuesNum(iface); | |
642 | if (rss_queues > 0) { | |
9f7ba071 | 643 | aconf->threads = rss_queues; |
3bb40894 | 644 | SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads); |
9f7ba071 VJ |
645 | } |
646 | } | |
3bb40894 | 647 | |
4111331a VJ |
648 | if (aconf->threads) { |
649 | SCLogPerf("Using %d AF_PACKET threads for interface %s", | |
650 | aconf->threads, iface); | |
651 | } | |
9f7ba071 VJ |
652 | } |
653 | if (aconf->threads <= 0) { | |
654 | aconf->threads = 1; | |
655 | } | |
656 | SC_ATOMIC_RESET(aconf->ref); | |
657 | (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); | |
658 | ||
659 | if (aconf->ring_size != 0) { | |
660 | if (aconf->ring_size * aconf->threads < max_pending_packets) { | |
661 | aconf->ring_size = max_pending_packets / aconf->threads + 1; | |
662 | SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " | |
663 | "Resetting to decent value %d.", aconf->ring_size); | |
664 | /* We want at least that max_pending_packets packets can be handled by the | |
665 | * interface. This is generous if we have multiple interfaces listening. */ | |
666 | } | |
667 | } else { | |
668 | /* We want that max_pending_packets packets can be handled by suricata | |
669 | * for this interface. To take burst into account we multiply the obtained | |
670 | * size by 2. */ | |
671 | aconf->ring_size = max_pending_packets * 2 / aconf->threads; | |
672 | } | |
b7bf299e EL |
673 | |
674 | int ltype = AFPGetLinkType(iface); | |
675 | switch (ltype) { | |
676 | case LINKTYPE_ETHERNET: | |
9b80c21d | 677 | /* af-packet can handle csum offloading */ |
9d48720f VJ |
678 | if (LiveGetOffload() == 0) { |
679 | if (GetIfaceOffloading(iface, 0, 1) == 1) { | |
680 | SCLogWarning(SC_ERR_AFP_CREATE, | |
681 | "Using AF_PACKET with offloading activated leads to capture problems"); | |
682 | } | |
683 | } else { | |
499e27de | 684 | DisableIfaceOffloading(LiveGetDevice(iface), 0, 1); |
b7bf299e | 685 | } |
9d48720f | 686 | break; |
b7bf299e EL |
687 | case -1: |
688 | default: | |
689 | break; | |
e951afb9 VJ |
690 | } |
691 | ||
bed18678 VJ |
692 | char *active_runmode = RunmodeGetActive(); |
693 | if (active_runmode && !strcmp("workers", active_runmode)) { | |
694 | aconf->flags |= AFP_ZERO_COPY; | |
bed18678 VJ |
695 | } else { |
696 | /* If we are using copy mode we need a lock */ | |
697 | aconf->flags |= AFP_SOCK_PROTECT; | |
698 | } | |
699 | ||
700 | /* If we are in RING mode, then we can use ZERO copy | |
701 | * by using the data release mechanism */ | |
702 | if (aconf->flags & AFP_RING_MODE) { | |
703 | aconf->flags |= AFP_ZERO_COPY; | |
9f7ba071 VJ |
704 | } |
705 | ||
706 | if (aconf->flags & AFP_ZERO_COPY) { | |
b3bf7a57 | 707 | SCLogConfig("%s: enabling zero copy mode by using data release call", iface); |
bed18678 VJ |
708 | } |
709 | ||
fbca1a4e EL |
710 | return aconf; |
711 | } | |
712 | ||
ab1200fb | 713 | static int AFPConfigGeThreadsCount(void *conf) |
75c875b1 EL |
714 | { |
715 | AFPIfaceConfig *afp = (AFPIfaceConfig *)conf; | |
716 | return afp->threads; | |
717 | } | |
fbca1a4e | 718 | |
1e36053e EL |
719 | int AFPRunModeIsIPS() |
720 | { | |
721 | int nlive = LiveGetDeviceCount(); | |
722 | int ldev; | |
723 | ConfNode *if_root; | |
724 | ConfNode *if_default = NULL; | |
725 | ConfNode *af_packet_node; | |
726 | int has_ips = 0; | |
727 | int has_ids = 0; | |
728 | ||
729 | /* Find initial node */ | |
730 | af_packet_node = ConfGetNode("af-packet"); | |
731 | if (af_packet_node == NULL) { | |
732 | return 0; | |
733 | } | |
734 | ||
735 | if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default"); | |
736 | ||
737 | for (ldev = 0; ldev < nlive; ldev++) { | |
5c974f92 | 738 | const char *live_dev = LiveGetDeviceName(ldev); |
7cdc5706 VJ |
739 | if (live_dev == NULL) { |
740 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
741 | return 0; | |
742 | } | |
ab1200fb | 743 | const char *copymodestr = NULL; |
aa8e747e | 744 | if_root = ConfFindDeviceConfig(af_packet_node, live_dev); |
1e36053e EL |
745 | |
746 | if (if_root == NULL) { | |
747 | if (if_default == NULL) { | |
748 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
749 | return 0; | |
750 | } | |
751 | if_root = if_default; | |
752 | } | |
753 | ||
754 | if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { | |
755 | if (strcmp(copymodestr, "ips") == 0) { | |
756 | has_ips = 1; | |
757 | } else { | |
758 | has_ids = 1; | |
759 | } | |
760 | } else { | |
761 | has_ids = 1; | |
762 | } | |
763 | } | |
764 | ||
765 | if (has_ids && has_ips) { | |
766 | SCLogInfo("AF_PACKET mode using IPS and IDS mode"); | |
767 | for (ldev = 0; ldev < nlive; ldev++) { | |
5c974f92 | 768 | const char *live_dev = LiveGetDeviceName(ldev); |
7cdc5706 VJ |
769 | if (live_dev == NULL) { |
770 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
771 | return 0; | |
772 | } | |
1e36053e | 773 | if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev); |
ab1200fb | 774 | const char *copymodestr = NULL; |
1e36053e EL |
775 | |
776 | if (if_root == NULL) { | |
777 | if (if_default == NULL) { | |
778 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
779 | return 0; | |
780 | } | |
781 | if_root = if_default; | |
782 | } | |
783 | ||
784 | if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) && | |
785 | (strcmp(copymodestr, "ips") == 0))) { | |
786 | SCLogError(SC_ERR_INVALID_ARGUMENT, | |
787 | "AF_PACKET IPS mode used and interface '%s' is in IDS or TAP mode. " | |
788 | "Sniffing '%s' but expect bad result as stream-inline is activated.", | |
789 | live_dev, live_dev); | |
790 | } | |
791 | } | |
792 | } | |
793 | ||
794 | return has_ips; | |
795 | } | |
796 | ||
994bc15c EL |
797 | #endif |
798 | ||
799 | ||
38b349af | 800 | int RunModeIdsAFPAutoFp(void) |
e80b30c0 EL |
801 | { |
802 | SCEnter(); | |
803 | ||
804 | /* We include only if AF_PACKET is enabled */ | |
805 | #ifdef HAVE_AF_PACKET | |
75c875b1 | 806 | int ret; |
ab1200fb | 807 | const char *live_dev = NULL; |
e80b30c0 | 808 | |
fbca1a4e EL |
809 | RunModeInitialize(); |
810 | ||
811 | TimeModeSetLive(); | |
812 | ||
2179ac25 | 813 | (void)ConfGet("af-packet.live-interface", &live_dev); |
fbca1a4e | 814 | |
75c875b1 | 815 | SCLogDebug("live_dev %s", live_dev); |
e80b30c0 | 816 | |
662dccd8 EL |
817 | if (AFPPeersListInit() != TM_ECODE_OK) { |
818 | SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); | |
819 | exit(EXIT_FAILURE); | |
820 | } | |
821 | ||
38b349af | 822 | ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig, |
75c875b1 EL |
823 | AFPConfigGeThreadsCount, |
824 | "ReceiveAFP", | |
41c768ce | 825 | "DecodeAFP", thread_name_autofp, |
75c875b1 EL |
826 | live_dev); |
827 | if (ret != 0) { | |
625a1e07 | 828 | SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); |
75c875b1 | 829 | exit(EXIT_FAILURE); |
e80b30c0 EL |
830 | } |
831 | ||
662dccd8 EL |
832 | /* In IPS mode each threads must have a peer */ |
833 | if (AFPPeersListCheck() != TM_ECODE_OK) { | |
834 | SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); | |
835 | exit(EXIT_FAILURE); | |
836 | } | |
e80b30c0 | 837 | |
86a3f064 | 838 | SCLogDebug("RunModeIdsAFPAutoFp initialised"); |
e80b30c0 EL |
839 | #endif /* HAVE_AF_PACKET */ |
840 | ||
841 | SCReturnInt(0); | |
842 | } | |
843 | ||
844 | /** | |
845 | * \brief Single thread version of the AF_PACKET processing. | |
846 | */ | |
38b349af | 847 | int RunModeIdsAFPSingle(void) |
e80b30c0 | 848 | { |
38b349af | 849 | SCEnter(); |
1aab2470 EL |
850 | #ifdef HAVE_AF_PACKET |
851 | int ret; | |
ab1200fb | 852 | const char *live_dev = NULL; |
e80b30c0 EL |
853 | |
854 | RunModeInitialize(); | |
855 | TimeModeSetLive(); | |
856 | ||
2179ac25 | 857 | (void)ConfGet("af-packet.live-interface", &live_dev); |
e80b30c0 | 858 | |
662dccd8 EL |
859 | if (AFPPeersListInit() != TM_ECODE_OK) { |
860 | SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); | |
861 | exit(EXIT_FAILURE); | |
862 | } | |
863 | ||
38b349af | 864 | ret = RunModeSetLiveCaptureSingle(ParseAFPConfig, |
77869a2d EL |
865 | AFPConfigGeThreadsCount, |
866 | "ReceiveAFP", | |
41c768ce | 867 | "DecodeAFP", thread_name_single, |
1aab2470 EL |
868 | live_dev); |
869 | if (ret != 0) { | |
625a1e07 | 870 | SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); |
e80b30c0 EL |
871 | exit(EXIT_FAILURE); |
872 | } | |
e80b30c0 | 873 | |
662dccd8 EL |
874 | /* In IPS mode each threads must have a peer */ |
875 | if (AFPPeersListCheck() != TM_ECODE_OK) { | |
876 | SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); | |
877 | exit(EXIT_FAILURE); | |
878 | } | |
879 | ||
86a3f064 | 880 | SCLogDebug("RunModeIdsAFPSingle initialised"); |
e80b30c0 EL |
881 | |
882 | #endif /* HAVE_AF_PACKET */ | |
883 | SCReturnInt(0); | |
c45d8985 | 884 | } |
beaa909e EL |
885 | |
886 | /** | |
887 | * \brief Workers version of the AF_PACKET processing. | |
888 | * | |
889 | * Start N threads with each thread doing all the work. | |
890 | * | |
891 | */ | |
38b349af | 892 | int RunModeIdsAFPWorkers(void) |
beaa909e | 893 | { |
38b349af | 894 | SCEnter(); |
beaa909e EL |
895 | #ifdef HAVE_AF_PACKET |
896 | int ret; | |
ab1200fb | 897 | const char *live_dev = NULL; |
beaa909e EL |
898 | |
899 | RunModeInitialize(); | |
900 | TimeModeSetLive(); | |
901 | ||
2179ac25 | 902 | (void)ConfGet("af-packet.live-interface", &live_dev); |
beaa909e | 903 | |
662dccd8 EL |
904 | if (AFPPeersListInit() != TM_ECODE_OK) { |
905 | SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); | |
906 | exit(EXIT_FAILURE); | |
907 | } | |
908 | ||
38b349af | 909 | ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig, |
beaa909e EL |
910 | AFPConfigGeThreadsCount, |
911 | "ReceiveAFP", | |
41c768ce | 912 | "DecodeAFP", thread_name_workers, |
beaa909e EL |
913 | live_dev); |
914 | if (ret != 0) { | |
625a1e07 | 915 | SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); |
beaa909e EL |
916 | exit(EXIT_FAILURE); |
917 | } | |
918 | ||
662dccd8 EL |
919 | /* In IPS mode each threads must have a peer */ |
920 | if (AFPPeersListCheck() != TM_ECODE_OK) { | |
921 | SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); | |
922 | exit(EXIT_FAILURE); | |
923 | } | |
924 | ||
86a3f064 | 925 | SCLogDebug("RunModeIdsAFPWorkers initialised"); |
beaa909e EL |
926 | |
927 | #endif /* HAVE_AF_PACKET */ | |
928 | SCReturnInt(0); | |
929 | } | |
a6457262 EL |
930 | |
931 | /** | |
932 | * @} | |
933 | */ |