/src/suricata7/src/util-device.c
Line | Count | Source |
1 | | /* Copyright (C) 2011-2021 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | #include "suricata-common.h" |
19 | | #include "conf.h" |
20 | | #include "util-device.h" |
21 | | #include "util-ioctl.h" |
22 | | #include "util-misc.h" |
23 | | #include "util-dpdk.h" |
24 | | |
25 | | #include "device-storage.h" |
26 | | #include "util-debug.h" |
27 | | |
28 | 0 | #define MAX_DEVNAME 10 |
29 | | |
30 | | static LiveDevStorageId g_bypass_storage_id = { .id = -1 }; |
31 | | |
32 | | /** |
33 | | * \file |
34 | | * |
35 | | * \author Eric Leblond <eric@regit.org> |
36 | | * |
37 | | * \brief Utility functions to handle device list |
38 | | */ |
39 | | |
40 | | /** private device list */ |
41 | | static TAILQ_HEAD(, LiveDevice_) live_devices = |
42 | | TAILQ_HEAD_INITIALIZER(live_devices); |
43 | | |
44 | | /** List of the name of devices |
45 | | * |
46 | | * As we don't know the size of the Storage on devices |
47 | | * before the parsing we need to wait and use this list |
48 | | * to create later the LiveDevice via LiveDeviceFinalize() |
49 | | */ |
50 | | static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices = |
51 | | TAILQ_HEAD_INITIALIZER(pre_live_devices); |
52 | | |
53 | | typedef struct BypassInfo_ { |
54 | | SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count); |
55 | | SC_ATOMIC_DECLARE(uint64_t, ipv4_fail); |
56 | | SC_ATOMIC_DECLARE(uint64_t, ipv4_success); |
57 | | SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count); |
58 | | SC_ATOMIC_DECLARE(uint64_t, ipv6_fail); |
59 | | SC_ATOMIC_DECLARE(uint64_t, ipv6_success); |
60 | | } BypassInfo; |
61 | | |
62 | | /** if set to 0 when we don't have real devices */ |
63 | | static int live_devices_stats = 1; |
64 | | |
65 | | |
66 | | static int LiveSafeDeviceName(const char *devname, |
67 | | char *newdevname, size_t destlen); |
68 | | |
69 | | static int g_live_devices_disable_offloading = 1; |
70 | | |
71 | | void LiveSetOffloadDisable(void) |
72 | 71 | { |
73 | 71 | g_live_devices_disable_offloading = 1; |
74 | 71 | } |
75 | | |
76 | | void LiveSetOffloadWarn(void) |
77 | 0 | { |
78 | 0 | g_live_devices_disable_offloading = 0; |
79 | 0 | } |
80 | | |
81 | | int LiveGetOffload(void) |
82 | 0 | { |
83 | 0 | return g_live_devices_disable_offloading; |
84 | 0 | } |
85 | | |
86 | | /** |
87 | | * \brief Add a device for monitoring |
88 | | * |
89 | | * To be used during option parsing. When a device has |
90 | | * to be created during runmode init, use LiveRegisterDevice() |
91 | | * |
92 | | * \param dev string with the device name |
93 | | * |
94 | | * \retval 0 on success. |
95 | | * \retval -1 on failure. |
96 | | */ |
97 | | int LiveRegisterDeviceName(const char *dev) |
98 | 0 | { |
99 | 0 | LiveDeviceName *pd = NULL; |
100 | |
|
101 | 0 | pd = SCCalloc(1, sizeof(LiveDeviceName)); |
102 | 0 | if (unlikely(pd == NULL)) { |
103 | 0 | return -1; |
104 | 0 | } |
105 | | |
106 | 0 | pd->dev = SCStrdup(dev); |
107 | 0 | if (unlikely(pd->dev == NULL)) { |
108 | 0 | SCFree(pd); |
109 | 0 | return -1; |
110 | 0 | } |
111 | | |
112 | 0 | TAILQ_INSERT_TAIL(&pre_live_devices, pd, next); |
113 | |
|
114 | 0 | SCLogDebug("Device \"%s\" registered.", dev); |
115 | 0 | return 0; |
116 | 0 | } |
117 | | |
118 | | /** |
119 | | * \brief Add a pcap device for monitoring and create structure |
120 | | * |
121 | | * \param dev string with the device name |
122 | | * |
123 | | * \retval 0 on success. |
124 | | * \retval -1 on failure. |
125 | | */ |
126 | | int LiveRegisterDevice(const char *dev) |
127 | 0 | { |
128 | 0 | LiveDevice *pd = NULL; |
129 | |
|
130 | 0 | pd = SCCalloc(1, sizeof(LiveDevice) + LiveDevStorageSize()); |
131 | 0 | if (unlikely(pd == NULL)) { |
132 | 0 | return -1; |
133 | 0 | } |
134 | | |
135 | 0 | int id = LiveGetDeviceCount(); |
136 | 0 | if (id > UINT16_MAX) { |
137 | 0 | SCFree(pd); |
138 | 0 | return -1; |
139 | 0 | } |
140 | | |
141 | 0 | pd->dev = SCStrdup(dev); |
142 | 0 | if (unlikely(pd->dev == NULL)) { |
143 | 0 | SCFree(pd); |
144 | 0 | return -1; |
145 | 0 | } |
146 | | /* create a short version to be used in thread names */ |
147 | 0 | LiveSafeDeviceName(pd->dev, pd->dev_short, sizeof(pd->dev_short)); |
148 | |
|
149 | 0 | SC_ATOMIC_INIT(pd->pkts); |
150 | 0 | SC_ATOMIC_INIT(pd->drop); |
151 | 0 | SC_ATOMIC_INIT(pd->invalid_checksums); |
152 | 0 | pd->id = (uint16_t)id; |
153 | 0 | TAILQ_INSERT_TAIL(&live_devices, pd, next); |
154 | |
|
155 | 0 | SCLogDebug("Device \"%s\" registered and created.", dev); |
156 | 0 | return 0; |
157 | 0 | } |
158 | | |
159 | | /** |
160 | | * \brief Get the number of registered devices |
161 | | * |
162 | | * \retval cnt the number of registered devices |
163 | | */ |
164 | | int LiveGetDeviceCount(void) |
165 | 0 | { |
166 | 0 | int i = 0; |
167 | 0 | LiveDevice *pd; |
168 | |
|
169 | 0 | TAILQ_FOREACH(pd, &live_devices, next) { |
170 | 0 | i++; |
171 | 0 | } |
172 | |
|
173 | 0 | return i; |
174 | 0 | } |
175 | | |
176 | | /** |
177 | | * \brief Get a pointer to the device name at idx |
178 | | * |
179 | | * \param number idx of the device in our list |
180 | | * |
181 | | * \retval ptr pointer to the string containing the device |
182 | | * \retval NULL on error |
183 | | */ |
184 | | const char *LiveGetDeviceName(int number) |
185 | 0 | { |
186 | 0 | int i = 0; |
187 | 0 | LiveDevice *pd; |
188 | |
|
189 | 0 | TAILQ_FOREACH(pd, &live_devices, next) { |
190 | 0 | if (i == number) { |
191 | 0 | return pd->dev; |
192 | 0 | } |
193 | | |
194 | 0 | i++; |
195 | 0 | } |
196 | | |
197 | 0 | return NULL; |
198 | 0 | } |
199 | | |
200 | | /** \internal |
201 | | * \brief Shorten a device name that is to long |
202 | | * |
203 | | * \param device name from config and destination for modified |
204 | | * |
205 | | * \retval None, is added to destination char *newdevname |
206 | | */ |
207 | | static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen) |
208 | 0 | { |
209 | 0 | const size_t devnamelen = strlen(devname); |
210 | | |
211 | | /* If we have to shorten the interface name */ |
212 | 0 | if (devnamelen > MAX_DEVNAME) { |
213 | | /* special mode for DPDK pci addresses */ |
214 | 0 | if (devnamelen >= 5 && strncmp(devname, "0000:", 5) == 0) { |
215 | 0 | strlcpy(newdevname, devname + 5, destlen); |
216 | 0 | return 0; |
217 | 0 | } |
218 | | |
219 | | /* IF the dest length is over 10 chars long it will not do any |
220 | | * good for the shortening. The shortening is done due to the |
221 | | * max length of pthread names (15 chars) and we use 3 chars |
222 | | * for the threadname indicator eg. "W#-" and one-two chars for |
223 | | * the thread number. And if the destination buffer is under |
224 | | * 6 chars there is no point in shortening it since we must at |
225 | | * least enter two periods (.) into the string. |
226 | | */ |
227 | 0 | if ((destlen-1) > 10 || (destlen-1) < 6) { |
228 | 0 | return 1; |
229 | 0 | } |
230 | | |
231 | 0 | ShortenString(devname, newdevname, destlen, '.'); |
232 | |
|
233 | 0 | SCLogInfo("%s: shortening device name to %s", devname, newdevname); |
234 | 0 | } else { |
235 | 0 | strlcpy(newdevname, devname, destlen); |
236 | 0 | } |
237 | 0 | return 0; |
238 | 0 | } |
239 | | |
240 | | /** |
241 | | * \brief Get a pointer to the device at idx |
242 | | * |
243 | | * \param number idx of the device in our list |
244 | | * |
245 | | * \retval ptr pointer to the string containing the device |
246 | | * \retval NULL on error |
247 | | */ |
248 | | LiveDevice *LiveGetDevice(const char *name) |
249 | 0 | { |
250 | 0 | LiveDevice *pd; |
251 | |
|
252 | 0 | if (name == NULL) { |
253 | 0 | SCLogWarning("Name of device should not be null"); |
254 | 0 | return NULL; |
255 | 0 | } |
256 | | |
257 | 0 | TAILQ_FOREACH(pd, &live_devices, next) { |
258 | 0 | if (!strcmp(name, pd->dev)) { |
259 | 0 | return pd; |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | 0 | return NULL; |
264 | 0 | } |
265 | | |
266 | | const char *LiveGetShortName(const char *dev) |
267 | 0 | { |
268 | 0 | LiveDevice *live_dev = LiveGetDevice(dev); |
269 | 0 | if (live_dev == NULL) |
270 | 0 | return NULL; |
271 | 0 | return live_dev->dev_short; |
272 | 0 | } |
273 | | |
274 | | int LiveBuildDeviceList(const char *runmode) |
275 | 0 | { |
276 | 0 | return LiveBuildDeviceListCustom(runmode, "interface"); |
277 | 0 | } |
278 | | |
279 | | int LiveBuildDeviceListCustom(const char *runmode, const char *itemname) |
280 | 0 | { |
281 | 0 | ConfNode *base = ConfGetNode(runmode); |
282 | 0 | ConfNode *child; |
283 | 0 | int i = 0; |
284 | |
|
285 | 0 | if (base == NULL) |
286 | 0 | return 0; |
287 | | |
288 | 0 | TAILQ_FOREACH(child, &base->head, next) { |
289 | 0 | ConfNode *subchild; |
290 | 0 | TAILQ_FOREACH(subchild, &child->head, next) { |
291 | 0 | if ((!strcmp(subchild->name, itemname))) { |
292 | 0 | if (!strcmp(subchild->val, "default")) |
293 | 0 | break; |
294 | 0 | SCLogConfig("Adding %s %s from config file", |
295 | 0 | itemname, subchild->val); |
296 | 0 | LiveRegisterDeviceName(subchild->val); |
297 | 0 | i++; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | } |
301 | |
|
302 | 0 | return i; |
303 | 0 | } |
304 | | |
305 | | /** Call this function to disable stat on live devices |
306 | | * |
307 | | * This can be useful in the case, this is not a real interface. |
308 | | */ |
309 | | void LiveDeviceHasNoStats(void) |
310 | 0 | { |
311 | 0 | live_devices_stats = 0; |
312 | 0 | } |
313 | | |
314 | | int LiveDeviceListClean(void) |
315 | 0 | { |
316 | 0 | SCEnter(); |
317 | 0 | LiveDevice *pd, *tpd; |
318 | | |
319 | | /* dpdk: need to close all devices before freeing them. */ |
320 | 0 | TAILQ_FOREACH (pd, &live_devices, next) { |
321 | 0 | DPDKCloseDevice(pd); |
322 | 0 | } |
323 | 0 | TAILQ_FOREACH_SAFE(pd, &live_devices, next, tpd) { |
324 | 0 | if (live_devices_stats) { |
325 | 0 | SCLogNotice("%s: packets: %" PRIu64 ", drops: %" PRIu64 |
326 | 0 | " (%.2f%%), invalid chksum: %" PRIu64, |
327 | 0 | pd->dev, SC_ATOMIC_GET(pd->pkts), SC_ATOMIC_GET(pd->drop), |
328 | 0 | SC_ATOMIC_GET(pd->pkts) > 0 ? 100 * ((double)SC_ATOMIC_GET(pd->drop)) / |
329 | 0 | (double)SC_ATOMIC_GET(pd->pkts) |
330 | 0 | : 0, |
331 | 0 | SC_ATOMIC_GET(pd->invalid_checksums)); |
332 | 0 | } |
333 | |
|
334 | 0 | RestoreIfaceOffloading(pd); |
335 | 0 | DPDKFreeDevice(pd); |
336 | |
|
337 | 0 | if (pd->dev) |
338 | 0 | SCFree(pd->dev); |
339 | 0 | LiveDevFreeStorage(pd); |
340 | 0 | SCFree(pd); |
341 | 0 | } |
342 | |
|
343 | 0 | SCReturnInt(TM_ECODE_OK); |
344 | 0 | } |
345 | | |
346 | | #ifdef BUILD_UNIX_SOCKET |
347 | | TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *answer, void *data) |
348 | 0 | { |
349 | 0 | SCEnter(); |
350 | 0 | LiveDevice *pd; |
351 | 0 | const char * name = NULL; |
352 | 0 | json_t *jarg = json_object_get(cmd, "iface"); |
353 | 0 | if(!json_is_string(jarg)) { |
354 | 0 | json_object_set_new(answer, "message", json_string("Iface is not a string")); |
355 | 0 | SCReturnInt(TM_ECODE_FAILED); |
356 | 0 | } |
357 | 0 | name = json_string_value(jarg); |
358 | 0 | if (name == NULL) { |
359 | 0 | json_object_set_new(answer, "message", json_string("Iface name is NULL")); |
360 | 0 | SCReturnInt(TM_ECODE_FAILED); |
361 | 0 | } |
362 | | |
363 | 0 | TAILQ_FOREACH(pd, &live_devices, next) { |
364 | 0 | if (!strcmp(name, pd->dev)) { |
365 | 0 | json_t *jdata = json_object(); |
366 | 0 | if (jdata == NULL) { |
367 | 0 | json_object_set_new(answer, "message", |
368 | 0 | json_string("internal error at json object creation")); |
369 | 0 | SCReturnInt(TM_ECODE_FAILED); |
370 | 0 | } |
371 | 0 | json_object_set_new(jdata, "pkts", |
372 | 0 | json_integer(SC_ATOMIC_GET(pd->pkts))); |
373 | 0 | json_object_set_new(jdata, "invalid-checksums", |
374 | 0 | json_integer(SC_ATOMIC_GET(pd->invalid_checksums))); |
375 | 0 | json_object_set_new(jdata, "drop", |
376 | 0 | json_integer(SC_ATOMIC_GET(pd->drop))); |
377 | 0 | json_object_set_new(jdata, "bypassed", |
378 | 0 | json_integer(SC_ATOMIC_GET(pd->bypassed))); |
379 | 0 | json_object_set_new(answer, "message", jdata); |
380 | 0 | SCReturnInt(TM_ECODE_OK); |
381 | 0 | } |
382 | 0 | } |
383 | 0 | json_object_set_new(answer, "message", json_string("Iface does not exist")); |
384 | 0 | SCReturnInt(TM_ECODE_FAILED); |
385 | 0 | } |
386 | | |
387 | | TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *answer, void *data) |
388 | 0 | { |
389 | 0 | SCEnter(); |
390 | 0 | json_t *jdata; |
391 | 0 | json_t *jarray; |
392 | 0 | LiveDevice *pd; |
393 | 0 | int i = 0; |
394 | |
|
395 | 0 | jdata = json_object(); |
396 | 0 | if (jdata == NULL) { |
397 | 0 | json_object_set_new(answer, "message", |
398 | 0 | json_string("internal error at json object creation")); |
399 | 0 | return TM_ECODE_FAILED; |
400 | 0 | } |
401 | 0 | jarray = json_array(); |
402 | 0 | if (jarray == NULL) { |
403 | 0 | json_object_set_new(answer, "message", |
404 | 0 | json_string("internal error at json object creation")); |
405 | 0 | return TM_ECODE_FAILED; |
406 | 0 | } |
407 | 0 | TAILQ_FOREACH(pd, &live_devices, next) { |
408 | 0 | json_array_append_new(jarray, json_string(pd->dev)); |
409 | 0 | i++; |
410 | 0 | } |
411 | |
|
412 | 0 | json_object_set_new(jdata, "count", json_integer(i)); |
413 | 0 | json_object_set_new(jdata, "ifaces", jarray); |
414 | 0 | json_object_set_new(answer, "message", jdata); |
415 | 0 | SCReturnInt(TM_ECODE_OK); |
416 | 0 | } |
417 | | |
418 | | #endif /* BUILD_UNIX_SOCKET */ |
419 | | |
420 | | LiveDevice *LiveDeviceForEach(LiveDevice **ldev, LiveDevice **ndev) |
421 | 0 | { |
422 | 0 | if (*ldev == NULL) { |
423 | 0 | *ldev = TAILQ_FIRST(&live_devices); |
424 | 0 | *ndev = TAILQ_NEXT(*ldev, next); |
425 | 0 | return *ldev; |
426 | 0 | } else { |
427 | 0 | *ldev = *ndev; |
428 | 0 | if (*ldev) { |
429 | 0 | *ndev = TAILQ_NEXT(*ldev, next); |
430 | 0 | } |
431 | 0 | return *ldev; |
432 | 0 | } |
433 | 0 | return NULL; |
434 | 0 | } |
435 | | |
436 | | /** |
437 | | * Create registered devices |
438 | | * |
439 | | * This function creates all needed LiveDevice from |
440 | | * the LiveDeviceName list created via LiveRegisterDevice() |
441 | | */ |
442 | | void LiveDeviceFinalize(void) |
443 | 71 | { |
444 | 71 | LiveDeviceName *ld, *pld; |
445 | 71 | SCLogDebug("Finalize live device"); |
446 | | /* Iter on devices and register them */ |
447 | 71 | TAILQ_FOREACH_SAFE(ld, &pre_live_devices, next, pld) { |
448 | 0 | if (ld->dev) { |
449 | 0 | LiveRegisterDevice(ld->dev); |
450 | 0 | SCFree(ld->dev); |
451 | 0 | } |
452 | 0 | SCFree(ld); |
453 | 0 | } |
454 | 71 | } |
455 | | |
456 | | static void LiveDevExtensionFree(void *x) |
457 | 0 | { |
458 | 0 | if (x) |
459 | 0 | SCFree(x); |
460 | 0 | } |
461 | | |
462 | | /** |
463 | | * Register bypass stats storage |
464 | | */ |
465 | | void LiveDevRegisterExtension(void) |
466 | 0 | { |
467 | 0 | g_bypass_storage_id = LiveDevStorageRegister("bypass_stats", sizeof(void *), |
468 | 0 | NULL, LiveDevExtensionFree); |
469 | 0 | } |
470 | | |
471 | | /** |
472 | | * Prepare a LiveDevice so we can set bypass stats |
473 | | */ |
474 | | int LiveDevUseBypass(LiveDevice *dev) |
475 | 0 | { |
476 | 0 | BypassInfo *bpinfo = SCCalloc(1, sizeof(*bpinfo)); |
477 | 0 | if (bpinfo == NULL) { |
478 | 0 | SCLogError("Can't allocate bypass info structure"); |
479 | 0 | return -1; |
480 | 0 | } |
481 | | |
482 | 0 | SC_ATOMIC_INIT(bpinfo->ipv4_hash_count); |
483 | 0 | SC_ATOMIC_INIT(bpinfo->ipv4_hash_count); |
484 | |
|
485 | 0 | LiveDevSetStorageById(dev, g_bypass_storage_id, bpinfo); |
486 | 0 | return 0; |
487 | 0 | } |
488 | | |
489 | | /** |
490 | | * Set number of currently bypassed flows for a protocol family |
491 | | * |
492 | | * \param dev pointer to LiveDevice to set stats for |
493 | | * \param cnt number of currently bypassed flows |
494 | | * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count |
495 | | */ |
496 | | void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family) |
497 | 0 | { |
498 | 0 | BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); |
499 | 0 | if (bpfdata) { |
500 | 0 | if (family == AF_INET) { |
501 | 0 | SC_ATOMIC_SET(bpfdata->ipv4_hash_count, cnt); |
502 | 0 | } else if (family == AF_INET6) { |
503 | 0 | SC_ATOMIC_SET(bpfdata->ipv6_hash_count, cnt); |
504 | 0 | } |
505 | 0 | } |
506 | 0 | } |
507 | | |
508 | | /** |
509 | | * Increase number of currently bypassed flows for a protocol family |
510 | | * |
511 | | * \param dev pointer to LiveDevice to set stats for |
512 | | * \param cnt number of flows to add |
513 | | * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count |
514 | | */ |
515 | | void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family) |
516 | 0 | { |
517 | 0 | BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); |
518 | 0 | if (bpfdata) { |
519 | 0 | if (family == AF_INET) { |
520 | 0 | SC_ATOMIC_ADD(bpfdata->ipv4_hash_count, cnt); |
521 | 0 | } else if (family == AF_INET6) { |
522 | 0 | SC_ATOMIC_ADD(bpfdata->ipv6_hash_count, cnt); |
523 | 0 | } |
524 | 0 | } |
525 | 0 | } |
526 | | |
527 | | /** |
528 | | * Decrease number of currently bypassed flows for a protocol family |
529 | | * |
530 | | * \param dev pointer to LiveDevice to set stats for |
531 | | * \param cnt number of flows to remove |
532 | | * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count |
533 | | */ |
534 | | void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family) |
535 | 0 | { |
536 | 0 | BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); |
537 | 0 | if (bpfdata) { |
538 | 0 | if (family == AF_INET) { |
539 | 0 | SC_ATOMIC_SUB(bpfdata->ipv4_hash_count, cnt); |
540 | 0 | } else if (family == AF_INET6) { |
541 | 0 | SC_ATOMIC_SUB(bpfdata->ipv6_hash_count, cnt); |
542 | 0 | } |
543 | 0 | } |
544 | 0 | } |
545 | | |
546 | | /** |
547 | | * Increase number of failed captured flows for a protocol family |
548 | | * |
549 | | * \param dev pointer to LiveDevice to set stats for |
550 | | * \param cnt number of flows to add |
551 | | * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count |
552 | | */ |
553 | | void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family) |
554 | 0 | { |
555 | 0 | BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); |
556 | 0 | if (bpfdata) { |
557 | 0 | if (family == AF_INET) { |
558 | 0 | SC_ATOMIC_ADD(bpfdata->ipv4_fail, cnt); |
559 | 0 | } else if (family == AF_INET6) { |
560 | 0 | SC_ATOMIC_ADD(bpfdata->ipv6_fail, cnt); |
561 | 0 | } |
562 | 0 | } |
563 | 0 | } |
564 | | |
565 | | /** |
566 | | * Increase number of currently successfully bypassed flows for a protocol family |
567 | | * |
568 | | * \param dev pointer to LiveDevice to set stats for |
569 | | * \param cnt number of flows to add |
570 | | * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count |
571 | | */ |
572 | | void LiveDevAddBypassSuccess(LiveDevice *dev, uint64_t cnt, int family) |
573 | 0 | { |
574 | 0 | BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); |
575 | 0 | if (bpfdata) { |
576 | 0 | if (family == AF_INET) { |
577 | 0 | SC_ATOMIC_ADD(bpfdata->ipv4_success, cnt); |
578 | 0 | } else if (family == AF_INET6) { |
579 | 0 | SC_ATOMIC_ADD(bpfdata->ipv6_success, cnt); |
580 | 0 | } |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | | #ifdef BUILD_UNIX_SOCKET |
585 | | TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data) |
586 | 0 | { |
587 | 0 | if (g_bypass_storage_id.id < 0) { |
588 | 0 | json_object_set_new(answer, "message", json_string("Bypass not enabled")); |
589 | 0 | SCReturnInt(TM_ECODE_FAILED); |
590 | 0 | } |
591 | 0 | LiveDevice *ldev = NULL, *ndev = NULL; |
592 | 0 | json_t *ifaces = NULL; |
593 | 0 | while(LiveDeviceForEach(&ldev, &ndev)) { |
594 | 0 | BypassInfo *bpinfo = LiveDevGetStorageById(ldev, g_bypass_storage_id); |
595 | 0 | if (bpinfo) { |
596 | 0 | uint64_t ipv4_hash_count = SC_ATOMIC_GET(bpinfo->ipv4_hash_count); |
597 | 0 | uint64_t ipv6_hash_count = SC_ATOMIC_GET(bpinfo->ipv6_hash_count); |
598 | 0 | uint64_t ipv4_success = SC_ATOMIC_GET(bpinfo->ipv4_success); |
599 | 0 | uint64_t ipv4_fail = SC_ATOMIC_GET(bpinfo->ipv4_fail); |
600 | 0 | uint64_t ipv6_success = SC_ATOMIC_GET(bpinfo->ipv6_success); |
601 | 0 | uint64_t ipv6_fail = SC_ATOMIC_GET(bpinfo->ipv6_fail); |
602 | 0 | json_t *iface = json_object(); |
603 | 0 | if (ifaces == NULL) { |
604 | 0 | ifaces = json_object(); |
605 | 0 | if (ifaces == NULL) { |
606 | 0 | json_object_set_new(answer, "message", |
607 | 0 | json_string("internal error at json object creation")); |
608 | 0 | return TM_ECODE_FAILED; |
609 | 0 | } |
610 | 0 | } |
611 | 0 | json_object_set_new(iface, "ipv4_maps_count", json_integer(ipv4_hash_count)); |
612 | 0 | json_object_set_new(iface, "ipv4_success", json_integer(ipv4_success)); |
613 | 0 | json_object_set_new(iface, "ipv4_fail", json_integer(ipv4_fail)); |
614 | 0 | json_object_set_new(iface, "ipv6_maps_count", json_integer(ipv6_hash_count)); |
615 | 0 | json_object_set_new(iface, "ipv6_success", json_integer(ipv6_success)); |
616 | 0 | json_object_set_new(iface, "ipv6_fail", json_integer(ipv6_fail)); |
617 | 0 | json_object_set_new(ifaces, ldev->dev, iface); |
618 | 0 | } |
619 | 0 | } |
620 | 0 | if (ifaces) { |
621 | 0 | json_object_set_new(answer, "message", ifaces); |
622 | 0 | SCReturnInt(TM_ECODE_OK); |
623 | 0 | } |
624 | | |
625 | 0 | json_object_set_new(answer, "message", |
626 | 0 | json_string("No interface using bypass")); |
627 | 0 | SCReturnInt(TM_ECODE_FAILED); |
628 | 0 | } |
629 | | #endif |