]>
Commit | Line | Data |
---|---|---|
c78e112e | 1 | /* Copyright (C) 2011,2012 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 | ||
33 | ||
c45d8985 | 34 | #include "suricata-common.h" |
e80b30c0 | 35 | #include "config.h" |
c45d8985 EL |
36 | #include "tm-threads.h" |
37 | #include "conf.h" | |
38 | #include "runmodes.h" | |
39 | #include "runmode-af-packet.h" | |
40 | #include "log-httplog.h" | |
41 | #include "output.h" | |
c45d8985 EL |
42 | #include "detect-engine-mpm.h" |
43 | ||
44 | #include "alert-fastlog.h" | |
45 | #include "alert-prelude.h" | |
c45d8985 EL |
46 | #include "alert-unified2-alert.h" |
47 | #include "alert-debuglog.h" | |
48 | ||
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" |
c45d8985 | 56 | |
e80b30c0 EL |
57 | #include "source-af-packet.h" |
58 | ||
8879df80 EL |
59 | extern int max_pending_packets; |
60 | ||
c174c9d7 | 61 | static const char *default_mode_workers = NULL; |
c45d8985 EL |
62 | |
63 | const char *RunModeAFPGetDefaultMode(void) | |
64 | { | |
c174c9d7 | 65 | return default_mode_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); | |
c174c9d7 | 77 | default_mode_workers = "workers"; |
e80b30c0 EL |
78 | RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp", |
79 | "Multi socket AF_PACKET mode. Packets from " | |
80 | "each flow are assigned to a single detect " | |
81 | "thread.", | |
82 | RunModeIdsAFPAutoFp); | |
c45d8985 EL |
83 | return; |
84 | } | |
85 | ||
994bc15c EL |
86 | |
87 | #ifdef HAVE_AF_PACKET | |
88 | ||
ab1200fb | 89 | static void AFPDerefConfig(void *conf) |
45d5c3ca EL |
90 | { |
91 | AFPIfaceConfig *pfp = (AFPIfaceConfig *)conf; | |
92 | /* Pcap config is used only once but cost of this low. */ | |
93 | if (SC_ATOMIC_SUB(pfp->ref, 1) == 0) { | |
94 | SCFree(pfp); | |
95 | } | |
96 | } | |
97 | ||
f89a4219 VJ |
98 | /* if cluster id is not set, assign it automagically, uniq value per |
99 | * interface. */ | |
100 | static int cluster_id_auto = 1; | |
101 | ||
fbca1a4e EL |
102 | /** |
103 | * \brief extract information from config file | |
104 | * | |
105 | * The returned structure will be freed by the thread init function. | |
106 | * This is thus necessary to or copy the structure before giving it | |
107 | * to thread or to reparse the file for each thread (and thus have | |
108 | * new structure. | |
109 | * | |
110 | * \return a AFPIfaceConfig corresponding to the interface name | |
111 | */ | |
ab1200fb | 112 | static void *ParseAFPConfig(const char *iface) |
fbca1a4e | 113 | { |
ab1200fb | 114 | const char *threadsstr = NULL; |
fbca1a4e | 115 | ConfNode *if_root; |
4ae27756 | 116 | ConfNode *if_default = NULL; |
fbca1a4e | 117 | ConfNode *af_packet_node; |
ab1200fb VJ |
118 | const char *tmpclusterid; |
119 | const char *tmpctype; | |
120 | const char *copymodestr; | |
fbca1a4e | 121 | intmax_t value; |
67f791e8 | 122 | int boolval; |
ab1200fb VJ |
123 | const char *bpf_filter = NULL; |
124 | const char *out_iface = NULL; | |
3bb40894 | 125 | int cluster_type = PACKET_FANOUT_HASH; |
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; |
662dccd8 | 148 | aconf->out_iface = NULL; |
c8b3f441 | 149 | aconf->copy_mode = AFP_COPY_MODE_NONE; |
9f7ba071 VJ |
150 | aconf->block_timeout = 10; |
151 | aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER; | |
f2a6fb8a EL |
152 | |
153 | if (ConfGet("bpf-filter", &bpf_filter) == 1) { | |
154 | if (strlen(bpf_filter) > 0) { | |
155 | aconf->bpf_filter = bpf_filter; | |
b3bf7a57 | 156 | SCLogConfig("Going to use command-line provided bpf filter '%s'", |
f2a6fb8a EL |
157 | aconf->bpf_filter); |
158 | } | |
159 | } | |
fbca1a4e EL |
160 | |
161 | /* Find initial node */ | |
162 | af_packet_node = ConfGetNode("af-packet"); | |
163 | if (af_packet_node == NULL) { | |
9f7ba071 VJ |
164 | SCLogInfo("unable to find af-packet config using default values"); |
165 | goto finalize; | |
fbca1a4e EL |
166 | } |
167 | ||
aa8e747e | 168 | if_root = ConfFindDeviceConfig(af_packet_node, iface); |
aa8e747e | 169 | if_default = ConfFindDeviceConfig(af_packet_node, "default"); |
4ae27756 EL |
170 | |
171 | if (if_root == NULL && if_default == NULL) { | |
9f7ba071 VJ |
172 | SCLogInfo("unable to find af-packet config for " |
173 | "interface \"%s\" or \"default\", using default values", | |
fbca1a4e | 174 | iface); |
9f7ba071 | 175 | goto finalize; |
fbca1a4e EL |
176 | } |
177 | ||
4ae27756 EL |
178 | /* If there is no setting for current interface use default one as main iface */ |
179 | if (if_root == NULL) { | |
180 | if_root = if_default; | |
181 | if_default = NULL; | |
182 | } | |
183 | ||
184 | if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { | |
c174c9d7 | 185 | aconf->threads = 0; |
fbca1a4e EL |
186 | } else { |
187 | if (threadsstr != NULL) { | |
c174c9d7 VJ |
188 | if (strcmp(threadsstr, "auto") == 0) { |
189 | aconf->threads = 0; | |
190 | } else { | |
191 | aconf->threads = (uint8_t)atoi(threadsstr); | |
192 | } | |
fbca1a4e EL |
193 | } |
194 | } | |
45d5c3ca | 195 | |
4ae27756 | 196 | if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { |
662dccd8 EL |
197 | if (strlen(out_iface) > 0) { |
198 | aconf->out_iface = out_iface; | |
199 | } | |
200 | } | |
201 | ||
876b356b | 202 | if (ConfGetChildValueBoolWithDefault(if_root, if_default, "use-mmap", (int *)&boolval) == 1) { |
f7124b11 | 203 | if (!boolval) { |
b3bf7a57 | 204 | SCLogConfig("Disabling mmaped capture on iface %s", |
876b356b | 205 | aconf->iface); |
f7124b11 | 206 | aconf->flags &= ~(AFP_RING_MODE|AFP_TPACKET_V3); |
876b356b | 207 | } |
662dccd8 | 208 | } |
876b356b | 209 | |
8035d834 EL |
210 | if (aconf->flags & AFP_RING_MODE) { |
211 | (void)ConfGetChildValueBoolWithDefault(if_root, if_default, | |
212 | "mmap-locked", (int *)&boolval); | |
213 | if (boolval) { | |
b3bf7a57 | 214 | SCLogConfig("Enabling locked memory for mmap on iface %s", |
bae1b03c | 215 | aconf->iface); |
8035d834 EL |
216 | aconf->flags |= AFP_MMAP_LOCKED; |
217 | } | |
f7124b11 VJ |
218 | |
219 | if (ConfGetChildValueBoolWithDefault(if_root, if_default, | |
220 | "tpacket-v3", (int *)&boolval) == 1) | |
221 | { | |
222 | if (boolval) { | |
223 | if (strcasecmp(RunmodeGetActive(), "workers") == 0) { | |
8035d834 | 224 | #ifdef HAVE_TPACKET_V3 |
f7124b11 VJ |
225 | SCLogConfig("Enabling tpacket v3 capture on iface %s", |
226 | aconf->iface); | |
227 | aconf->flags |= AFP_TPACKET_V3; | |
c2d0d938 | 228 | #else |
f7124b11 VJ |
229 | SCLogNotice("System too old for tpacket v3 switching to v2"); |
230 | aconf->flags &= ~AFP_TPACKET_V3; | |
c2d0d938 | 231 | #endif |
f7124b11 VJ |
232 | } else { |
233 | SCLogWarning(SC_ERR_RUNMODE, | |
234 | "tpacket v3 is only implemented for 'workers' runmode." | |
235 | " Switching to tpacket v2."); | |
236 | aconf->flags &= ~AFP_TPACKET_V3; | |
237 | } | |
8035d834 | 238 | } else { |
9f7ba071 | 239 | aconf->flags &= ~AFP_TPACKET_V3; |
8035d834 EL |
240 | } |
241 | } | |
f7124b11 | 242 | |
8035d834 EL |
243 | (void)ConfGetChildValueBoolWithDefault(if_root, if_default, |
244 | "use-emergency-flush", (int *)&boolval); | |
245 | if (boolval) { | |
b3bf7a57 | 246 | SCLogConfig("Enabling ring emergency flush on iface %s", |
8035d834 EL |
247 | aconf->iface); |
248 | aconf->flags |= AFP_EMERGENCY_MODE; | |
bae1b03c | 249 | } |
27b5136b EL |
250 | } |
251 | ||
662dccd8 | 252 | aconf->copy_mode = AFP_COPY_MODE_NONE; |
4ae27756 | 253 | if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { |
662dccd8 EL |
254 | if (aconf->out_iface == NULL) { |
255 | SCLogInfo("Copy mode activated but no destination" | |
256 | " iface. Disabling feature"); | |
257 | } else if (!(aconf->flags & AFP_RING_MODE)) { | |
258 | SCLogInfo("Copy mode activated but use-mmap " | |
259 | "set to no. Disabling feature"); | |
260 | } else if (strlen(copymodestr) <= 0) { | |
261 | aconf->out_iface = NULL; | |
262 | } else if (strcmp(copymodestr, "ips") == 0) { | |
263 | SCLogInfo("AF_PACKET IPS mode activated %s->%s", | |
264 | iface, | |
265 | aconf->out_iface); | |
266 | aconf->copy_mode = AFP_COPY_MODE_IPS; | |
267 | } else if (strcmp(copymodestr, "tap") == 0) { | |
268 | SCLogInfo("AF_PACKET TAP mode activated %s->%s", | |
269 | iface, | |
270 | aconf->out_iface); | |
271 | aconf->copy_mode = AFP_COPY_MODE_TAP; | |
272 | } else { | |
273 | SCLogInfo("Invalid mode (not in tap, ips)"); | |
274 | } | |
275 | } | |
276 | ||
4ae27756 | 277 | if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { |
f89a4219 | 278 | aconf->cluster_id = (uint16_t)(cluster_id_auto++); |
fbca1a4e EL |
279 | } else { |
280 | aconf->cluster_id = (uint16_t)atoi(tmpclusterid); | |
281 | SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id); | |
282 | } | |
283 | ||
4ae27756 | 284 | if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { |
f89a4219 VJ |
285 | /* default to our safest choice: flow hashing + defrag enabled */ |
286 | aconf->cluster_type = PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_DEFRAG; | |
3bb40894 | 287 | cluster_type = PACKET_FANOUT_HASH; |
fbca1a4e | 288 | } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { |
b3bf7a57 | 289 | SCLogConfig("Using round-robin cluster mode for AF_PACKET (iface %s)", |
fbca1a4e EL |
290 | aconf->iface); |
291 | aconf->cluster_type = PACKET_FANOUT_LB; | |
3bb40894 | 292 | cluster_type = PACKET_FANOUT_LB; |
fbca1a4e EL |
293 | } else if (strcmp(tmpctype, "cluster_flow") == 0) { |
294 | /* In hash mode, we also ask for defragmentation needed to | |
295 | * compute the hash */ | |
296 | uint16_t defrag = 0; | |
4c6595f4 | 297 | int conf_val = 0; |
b3bf7a57 | 298 | SCLogConfig("Using flow cluster mode for AF_PACKET (iface %s)", |
fbca1a4e | 299 | aconf->iface); |
4c6595f4 EL |
300 | ConfGetChildValueBoolWithDefault(if_root, if_default, "defrag", &conf_val); |
301 | if (conf_val) { | |
b3bf7a57 | 302 | SCLogConfig("Using defrag kernel functionality for AF_PACKET (iface %s)", |
fbca1a4e EL |
303 | aconf->iface); |
304 | defrag = PACKET_FANOUT_FLAG_DEFRAG; | |
305 | } | |
306 | aconf->cluster_type = PACKET_FANOUT_HASH | defrag; | |
3bb40894 | 307 | cluster_type = PACKET_FANOUT_HASH; |
fbca1a4e | 308 | } else if (strcmp(tmpctype, "cluster_cpu") == 0) { |
b3bf7a57 | 309 | SCLogConfig("Using cpu cluster mode for AF_PACKET (iface %s)", |
fbca1a4e EL |
310 | aconf->iface); |
311 | aconf->cluster_type = PACKET_FANOUT_CPU; | |
3bb40894 | 312 | cluster_type = PACKET_FANOUT_CPU; |
dc306f3b | 313 | } else if (strcmp(tmpctype, "cluster_qm") == 0) { |
b3bf7a57 | 314 | SCLogConfig("Using queue based cluster mode for AF_PACKET (iface %s)", |
dc306f3b EL |
315 | aconf->iface); |
316 | aconf->cluster_type = PACKET_FANOUT_QM; | |
3bb40894 | 317 | cluster_type = PACKET_FANOUT_QM; |
dc306f3b | 318 | } else if (strcmp(tmpctype, "cluster_random") == 0) { |
b3bf7a57 | 319 | SCLogConfig("Using random based cluster mode for AF_PACKET (iface %s)", |
dc306f3b EL |
320 | aconf->iface); |
321 | aconf->cluster_type = PACKET_FANOUT_RND; | |
3bb40894 | 322 | cluster_type = PACKET_FANOUT_RND; |
dc306f3b | 323 | } else if (strcmp(tmpctype, "cluster_rollover") == 0) { |
b3bf7a57 | 324 | SCLogConfig("Using rollover based cluster mode for AF_PACKET (iface %s)", |
dc306f3b EL |
325 | aconf->iface); |
326 | aconf->cluster_type = PACKET_FANOUT_ROLLOVER; | |
3bb40894 | 327 | cluster_type = PACKET_FANOUT_ROLLOVER; |
dc306f3b | 328 | |
fbca1a4e | 329 | } else { |
9f7ba071 | 330 | SCLogWarning(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); |
fbca1a4e EL |
331 | } |
332 | ||
8fde842f EL |
333 | int conf_val = 0; |
334 | ConfGetChildValueBoolWithDefault(if_root, if_default, "rollover", &conf_val); | |
335 | if (conf_val) { | |
b3bf7a57 | 336 | SCLogConfig("Using rollover kernel functionality for AF_PACKET (iface %s)", |
8fde842f EL |
337 | aconf->iface); |
338 | aconf->cluster_type |= PACKET_FANOUT_FLAG_ROLLOVER; | |
339 | } | |
340 | ||
f2a6fb8a EL |
341 | /*load af_packet bpf filter*/ |
342 | /* command line value has precedence */ | |
343 | if (ConfGet("bpf-filter", &bpf_filter) != 1) { | |
4ae27756 | 344 | if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { |
f2a6fb8a EL |
345 | if (strlen(bpf_filter) > 0) { |
346 | aconf->bpf_filter = bpf_filter; | |
b3bf7a57 | 347 | SCLogConfig("Going to use bpf filter %s", aconf->bpf_filter); |
f2a6fb8a EL |
348 | } |
349 | } | |
350 | } | |
351 | ||
4ae27756 | 352 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "buffer-size", &value)) == 1) { |
fbca1a4e EL |
353 | aconf->buffer_size = value; |
354 | } else { | |
355 | aconf->buffer_size = 0; | |
356 | } | |
4ae27756 | 357 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "ring-size", &value)) == 1) { |
8879df80 | 358 | aconf->ring_size = value; |
8879df80 | 359 | } |
fbca1a4e | 360 | |
fa902abe EL |
361 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-size", &value)) == 1) { |
362 | if (value % getpagesize()) { | |
363 | SCLogError(SC_ERR_INVALID_VALUE, "Block-size must be a multiple of pagesize."); | |
364 | } else { | |
365 | aconf->block_size = value; | |
366 | } | |
367 | } | |
368 | ||
234aefdf | 369 | if ((ConfGetChildValueIntWithDefault(if_root, if_default, "block-timeout", &value)) == 1) { |
fa902abe EL |
370 | aconf->block_timeout = value; |
371 | } else { | |
372 | aconf->block_timeout = 10; | |
373 | } | |
374 | ||
4ae27756 | 375 | (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); |
67f791e8 | 376 | if (boolval) { |
b3bf7a57 | 377 | SCLogConfig("Disabling promiscuous mode on iface %s", |
df7dbe36 EL |
378 | aconf->iface); |
379 | aconf->promisc = 0; | |
380 | } | |
67f791e8 | 381 | |
4ae27756 | 382 | if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { |
6062e00c | 383 | if (strcmp(tmpctype, "auto") == 0) { |
6062e00c | 384 | aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; |
d18e2f6e | 385 | } else if (ConfValIsTrue(tmpctype)) { |
6062e00c | 386 | aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; |
d18e2f6e | 387 | } else if (ConfValIsFalse(tmpctype)) { |
6062e00c EL |
388 | aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; |
389 | } else if (strcmp(tmpctype, "kernel") == 0) { | |
390 | aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; | |
391 | } else { | |
392 | SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); | |
393 | } | |
394 | } | |
df7dbe36 | 395 | |
9f7ba071 VJ |
396 | finalize: |
397 | ||
402bdf9b VJ |
398 | /* if the number of threads is not 1, we need to first check if fanout |
399 | * functions on this system. */ | |
400 | if (aconf->threads != 1) { | |
401 | if (AFPIsFanoutSupported() == 0) { | |
402 | if (aconf->threads != 0) { | |
403 | SCLogNotice("fanout not supported on this system, falling " | |
404 | "back to 1 capture thread"); | |
405 | } | |
406 | aconf->threads = 1; | |
407 | } | |
408 | } | |
409 | ||
410 | /* try to automagically set the proper number of threads */ | |
9f7ba071 | 411 | if (aconf->threads == 0) { |
3bb40894 VJ |
412 | /* for cluster_flow use core count */ |
413 | if (cluster_type == PACKET_FANOUT_HASH) { | |
414 | aconf->threads = (int)UtilCpuGetNumProcessorsOnline(); | |
415 | SCLogPerf("%u cores, so using %u threads", aconf->threads, aconf->threads); | |
416 | ||
417 | /* for cluster_qm use RSS queue count */ | |
418 | } else if (cluster_type == PACKET_FANOUT_QM) { | |
419 | int rss_queues = GetIfaceRSSQueuesNum(iface); | |
420 | if (rss_queues > 0) { | |
9f7ba071 | 421 | aconf->threads = rss_queues; |
3bb40894 | 422 | SCLogPerf("%d RSS queues, so using %u threads", rss_queues, aconf->threads); |
9f7ba071 VJ |
423 | } |
424 | } | |
3bb40894 | 425 | |
4111331a VJ |
426 | if (aconf->threads) { |
427 | SCLogPerf("Using %d AF_PACKET threads for interface %s", | |
428 | aconf->threads, iface); | |
429 | } | |
9f7ba071 VJ |
430 | } |
431 | if (aconf->threads <= 0) { | |
432 | aconf->threads = 1; | |
433 | } | |
434 | SC_ATOMIC_RESET(aconf->ref); | |
435 | (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); | |
436 | ||
437 | if (aconf->ring_size != 0) { | |
438 | if (aconf->ring_size * aconf->threads < max_pending_packets) { | |
439 | aconf->ring_size = max_pending_packets / aconf->threads + 1; | |
440 | SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " | |
441 | "Resetting to decent value %d.", aconf->ring_size); | |
442 | /* We want at least that max_pending_packets packets can be handled by the | |
443 | * interface. This is generous if we have multiple interfaces listening. */ | |
444 | } | |
445 | } else { | |
446 | /* We want that max_pending_packets packets can be handled by suricata | |
447 | * for this interface. To take burst into account we multiply the obtained | |
448 | * size by 2. */ | |
449 | aconf->ring_size = max_pending_packets * 2 / aconf->threads; | |
450 | } | |
b7bf299e EL |
451 | |
452 | int ltype = AFPGetLinkType(iface); | |
453 | switch (ltype) { | |
454 | case LINKTYPE_ETHERNET: | |
9b80c21d | 455 | /* af-packet can handle csum offloading */ |
9d48720f VJ |
456 | if (LiveGetOffload() == 0) { |
457 | if (GetIfaceOffloading(iface, 0, 1) == 1) { | |
458 | SCLogWarning(SC_ERR_AFP_CREATE, | |
459 | "Using AF_PACKET with offloading activated leads to capture problems"); | |
460 | } | |
461 | } else { | |
499e27de | 462 | DisableIfaceOffloading(LiveGetDevice(iface), 0, 1); |
b7bf299e | 463 | } |
9d48720f | 464 | break; |
b7bf299e EL |
465 | case -1: |
466 | default: | |
467 | break; | |
e951afb9 VJ |
468 | } |
469 | ||
bed18678 VJ |
470 | char *active_runmode = RunmodeGetActive(); |
471 | if (active_runmode && !strcmp("workers", active_runmode)) { | |
472 | aconf->flags |= AFP_ZERO_COPY; | |
bed18678 VJ |
473 | } else { |
474 | /* If we are using copy mode we need a lock */ | |
475 | aconf->flags |= AFP_SOCK_PROTECT; | |
476 | } | |
477 | ||
478 | /* If we are in RING mode, then we can use ZERO copy | |
479 | * by using the data release mechanism */ | |
480 | if (aconf->flags & AFP_RING_MODE) { | |
481 | aconf->flags |= AFP_ZERO_COPY; | |
9f7ba071 VJ |
482 | } |
483 | ||
484 | if (aconf->flags & AFP_ZERO_COPY) { | |
b3bf7a57 | 485 | SCLogConfig("%s: enabling zero copy mode by using data release call", iface); |
bed18678 VJ |
486 | } |
487 | ||
fbca1a4e EL |
488 | return aconf; |
489 | } | |
490 | ||
ab1200fb | 491 | static int AFPConfigGeThreadsCount(void *conf) |
75c875b1 EL |
492 | { |
493 | AFPIfaceConfig *afp = (AFPIfaceConfig *)conf; | |
494 | return afp->threads; | |
495 | } | |
fbca1a4e | 496 | |
1e36053e EL |
497 | int AFPRunModeIsIPS() |
498 | { | |
499 | int nlive = LiveGetDeviceCount(); | |
500 | int ldev; | |
501 | ConfNode *if_root; | |
502 | ConfNode *if_default = NULL; | |
503 | ConfNode *af_packet_node; | |
504 | int has_ips = 0; | |
505 | int has_ids = 0; | |
506 | ||
507 | /* Find initial node */ | |
508 | af_packet_node = ConfGetNode("af-packet"); | |
509 | if (af_packet_node == NULL) { | |
510 | return 0; | |
511 | } | |
512 | ||
513 | if_default = ConfNodeLookupKeyValue(af_packet_node, "interface", "default"); | |
514 | ||
515 | for (ldev = 0; ldev < nlive; ldev++) { | |
5c974f92 | 516 | const char *live_dev = LiveGetDeviceName(ldev); |
7cdc5706 VJ |
517 | if (live_dev == NULL) { |
518 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
519 | return 0; | |
520 | } | |
ab1200fb | 521 | const char *copymodestr = NULL; |
aa8e747e | 522 | if_root = ConfFindDeviceConfig(af_packet_node, live_dev); |
1e36053e EL |
523 | |
524 | if (if_root == NULL) { | |
525 | if (if_default == NULL) { | |
526 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
527 | return 0; | |
528 | } | |
529 | if_root = if_default; | |
530 | } | |
531 | ||
532 | if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { | |
533 | if (strcmp(copymodestr, "ips") == 0) { | |
534 | has_ips = 1; | |
535 | } else { | |
536 | has_ids = 1; | |
537 | } | |
538 | } else { | |
539 | has_ids = 1; | |
540 | } | |
541 | } | |
542 | ||
543 | if (has_ids && has_ips) { | |
544 | SCLogInfo("AF_PACKET mode using IPS and IDS mode"); | |
545 | for (ldev = 0; ldev < nlive; ldev++) { | |
5c974f92 | 546 | const char *live_dev = LiveGetDeviceName(ldev); |
7cdc5706 VJ |
547 | if (live_dev == NULL) { |
548 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
549 | return 0; | |
550 | } | |
1e36053e | 551 | if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", live_dev); |
ab1200fb | 552 | const char *copymodestr = NULL; |
1e36053e EL |
553 | |
554 | if (if_root == NULL) { | |
555 | if (if_default == NULL) { | |
556 | SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file"); | |
557 | return 0; | |
558 | } | |
559 | if_root = if_default; | |
560 | } | |
561 | ||
562 | if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) && | |
563 | (strcmp(copymodestr, "ips") == 0))) { | |
564 | SCLogError(SC_ERR_INVALID_ARGUMENT, | |
565 | "AF_PACKET IPS mode used and interface '%s' is in IDS or TAP mode. " | |
566 | "Sniffing '%s' but expect bad result as stream-inline is activated.", | |
567 | live_dev, live_dev); | |
568 | } | |
569 | } | |
570 | } | |
571 | ||
572 | return has_ips; | |
573 | } | |
574 | ||
994bc15c EL |
575 | #endif |
576 | ||
577 | ||
38b349af | 578 | int RunModeIdsAFPAutoFp(void) |
e80b30c0 EL |
579 | { |
580 | SCEnter(); | |
581 | ||
582 | /* We include only if AF_PACKET is enabled */ | |
583 | #ifdef HAVE_AF_PACKET | |
75c875b1 | 584 | int ret; |
ab1200fb | 585 | const char *live_dev = NULL; |
e80b30c0 | 586 | |
fbca1a4e EL |
587 | RunModeInitialize(); |
588 | ||
589 | TimeModeSetLive(); | |
590 | ||
2179ac25 | 591 | (void)ConfGet("af-packet.live-interface", &live_dev); |
fbca1a4e | 592 | |
75c875b1 | 593 | SCLogDebug("live_dev %s", live_dev); |
e80b30c0 | 594 | |
662dccd8 EL |
595 | if (AFPPeersListInit() != TM_ECODE_OK) { |
596 | SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); | |
597 | exit(EXIT_FAILURE); | |
598 | } | |
599 | ||
38b349af | 600 | ret = RunModeSetLiveCaptureAutoFp(ParseAFPConfig, |
75c875b1 EL |
601 | AFPConfigGeThreadsCount, |
602 | "ReceiveAFP", | |
41c768ce | 603 | "DecodeAFP", thread_name_autofp, |
75c875b1 EL |
604 | live_dev); |
605 | if (ret != 0) { | |
625a1e07 | 606 | SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); |
75c875b1 | 607 | exit(EXIT_FAILURE); |
e80b30c0 EL |
608 | } |
609 | ||
662dccd8 EL |
610 | /* In IPS mode each threads must have a peer */ |
611 | if (AFPPeersListCheck() != TM_ECODE_OK) { | |
612 | SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); | |
613 | exit(EXIT_FAILURE); | |
614 | } | |
e80b30c0 | 615 | |
86a3f064 | 616 | SCLogDebug("RunModeIdsAFPAutoFp initialised"); |
e80b30c0 EL |
617 | #endif /* HAVE_AF_PACKET */ |
618 | ||
619 | SCReturnInt(0); | |
620 | } | |
621 | ||
622 | /** | |
623 | * \brief Single thread version of the AF_PACKET processing. | |
624 | */ | |
38b349af | 625 | int RunModeIdsAFPSingle(void) |
e80b30c0 | 626 | { |
38b349af | 627 | SCEnter(); |
1aab2470 EL |
628 | #ifdef HAVE_AF_PACKET |
629 | int ret; | |
ab1200fb | 630 | const char *live_dev = NULL; |
e80b30c0 EL |
631 | |
632 | RunModeInitialize(); | |
633 | TimeModeSetLive(); | |
634 | ||
2179ac25 | 635 | (void)ConfGet("af-packet.live-interface", &live_dev); |
e80b30c0 | 636 | |
662dccd8 EL |
637 | if (AFPPeersListInit() != TM_ECODE_OK) { |
638 | SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); | |
639 | exit(EXIT_FAILURE); | |
640 | } | |
641 | ||
38b349af | 642 | ret = RunModeSetLiveCaptureSingle(ParseAFPConfig, |
77869a2d EL |
643 | AFPConfigGeThreadsCount, |
644 | "ReceiveAFP", | |
41c768ce | 645 | "DecodeAFP", thread_name_single, |
1aab2470 EL |
646 | live_dev); |
647 | if (ret != 0) { | |
625a1e07 | 648 | SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); |
e80b30c0 EL |
649 | exit(EXIT_FAILURE); |
650 | } | |
e80b30c0 | 651 | |
662dccd8 EL |
652 | /* In IPS mode each threads must have a peer */ |
653 | if (AFPPeersListCheck() != TM_ECODE_OK) { | |
654 | SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); | |
655 | exit(EXIT_FAILURE); | |
656 | } | |
657 | ||
86a3f064 | 658 | SCLogDebug("RunModeIdsAFPSingle initialised"); |
e80b30c0 EL |
659 | |
660 | #endif /* HAVE_AF_PACKET */ | |
661 | SCReturnInt(0); | |
c45d8985 | 662 | } |
beaa909e EL |
663 | |
664 | /** | |
665 | * \brief Workers version of the AF_PACKET processing. | |
666 | * | |
667 | * Start N threads with each thread doing all the work. | |
668 | * | |
669 | */ | |
38b349af | 670 | int RunModeIdsAFPWorkers(void) |
beaa909e | 671 | { |
38b349af | 672 | SCEnter(); |
beaa909e EL |
673 | #ifdef HAVE_AF_PACKET |
674 | int ret; | |
ab1200fb | 675 | const char *live_dev = NULL; |
beaa909e EL |
676 | |
677 | RunModeInitialize(); | |
678 | TimeModeSetLive(); | |
679 | ||
2179ac25 | 680 | (void)ConfGet("af-packet.live-interface", &live_dev); |
beaa909e | 681 | |
662dccd8 EL |
682 | if (AFPPeersListInit() != TM_ECODE_OK) { |
683 | SCLogError(SC_ERR_RUNMODE, "Unable to init peers list."); | |
684 | exit(EXIT_FAILURE); | |
685 | } | |
686 | ||
38b349af | 687 | ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig, |
beaa909e EL |
688 | AFPConfigGeThreadsCount, |
689 | "ReceiveAFP", | |
41c768ce | 690 | "DecodeAFP", thread_name_workers, |
beaa909e EL |
691 | live_dev); |
692 | if (ret != 0) { | |
625a1e07 | 693 | SCLogError(SC_ERR_RUNMODE, "Unable to start runmode"); |
beaa909e EL |
694 | exit(EXIT_FAILURE); |
695 | } | |
696 | ||
662dccd8 EL |
697 | /* In IPS mode each threads must have a peer */ |
698 | if (AFPPeersListCheck() != TM_ECODE_OK) { | |
699 | SCLogError(SC_ERR_RUNMODE, "Some IPS capture threads did not peer."); | |
700 | exit(EXIT_FAILURE); | |
701 | } | |
702 | ||
86a3f064 | 703 | SCLogDebug("RunModeIdsAFPWorkers initialised"); |
beaa909e EL |
704 | |
705 | #endif /* HAVE_AF_PACKET */ | |
706 | SCReturnInt(0); | |
707 | } | |
a6457262 EL |
708 | |
709 | /** | |
710 | * @} | |
711 | */ |