]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
bypass: generalize iface bypass stats
authorEric Leblond <eric@regit.org>
Tue, 23 Apr 2019 07:40:47 +0000 (09:40 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 18 Jun 2019 05:07:02 +0000 (07:07 +0200)
Introduce functions in util-device.c to be able to manage the
flow bypassed count stats.

src/suricata.c
src/unix-manager.c
src/util-device.c
src/util-device.h
src/util-ebpf.c

index 08ad01dec4e76ebb5fc25d95ab8133b77a458b49..c5d6d22b6aab1b11aa6539ebd26b65c157b20fe3 100644 (file)
@@ -2703,6 +2703,7 @@ static int PostConfLoadedSetup(SCInstance *suri)
     StorageInit();
 #ifdef HAVE_PACKET_EBPF
     EBPFRegisterExtension();
+    LiveDevRegisterExtension();
 #endif
     AppLayerSetup();
 
index b328227a76205c6f7c241276f99f13f1fbafb867..882bbde75c3de5c6051267b33e5f0f819d80467d 100644 (file)
@@ -1190,10 +1190,12 @@ void UnixManagerThreadSpawnNonRunmode(void)
             UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL,
                     UNIX_CMD_TAKE_ARGS);
             UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0);
+            UnixManagerRegisterCommand("iface-bypassed-stat",
+                                       LiveDeviceGetBypassedStats, NULL, 0);
+            /* For backward compatibility */
+            UnixManagerRegisterCommand("ebpf-bypassed-stat",
+                                       LiveDeviceGetBypassedStats, NULL, 0);
             UnixManagerThreadSpawn(0);
-#ifdef HAVE_PACKET_EBPF
-            UnixManagerRegisterCommand("ebpf-bypassed-stats", EBPFGetBypassedStats, NULL, 0);
-#endif
         }
     }
 }
index 551a398963f1e99e8cd532d5e79f94933bacf82a..2eecc11f9c11c3834bfdb3b2a63866d51f393269 100644 (file)
@@ -24,6 +24,8 @@
 
 #define MAX_DEVNAME 10
 
+static int g_bypass_storage_id = -1;
+
 /**
  * \file
  *
@@ -45,9 +47,15 @@ static TAILQ_HEAD(, LiveDevice_) live_devices =
 static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices =
     TAILQ_HEAD_INITIALIZER(pre_live_devices);
 
+typedef struct BypassInfo_ {
+    SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count);
+    SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count);
+} BypassInfo;
+
 /** if set to 0 when we don't have real devices */
 static int live_devices_stats = 1;
 
+
 static int LiveSafeDeviceName(const char *devname,
                               char *newdevname, size_t destlen);
 
@@ -452,3 +460,91 @@ void LiveDeviceFinalize(void)
         SCFree(ld);
     }
 }
+
+static void LiveDevExtensionFree(void *x)
+{
+    if (x)
+        SCFree(x);
+}
+
+/**
+ * Register bypass stats storage
+ */
+void LiveDevRegisterExtension(void)
+{
+    g_bypass_storage_id = LiveDevStorageRegister("bypass_stats", sizeof(void *),
+                                                 NULL, LiveDevExtensionFree);
+}
+
+/**
+ * Prepare a LiveDevice so we can set bypass stats
+ */
+int LiveDevUseBypass(LiveDevice *dev)
+{
+    BypassInfo *bpinfo = SCCalloc(1, sizeof(*bpinfo));
+    if (bpinfo == NULL) {
+        SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate bypass info structure");
+        return -1;
+    }
+
+    SC_ATOMIC_INIT(bpinfo->ipv4_hash_count);
+    SC_ATOMIC_INIT(bpinfo->ipv4_hash_count);
+
+    LiveDevSetStorageById(dev, g_bypass_storage_id, bpinfo);
+    return 0;
+}
+
+/**
+ * Set number of currently bypassed flows for a protocol family
+ *
+ * \param dev pointer to LiveDevice to set stats for
+ * \param cnt number of currently bypassed flows
+ * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count
+ */
+void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family)
+{
+    BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id);
+    if (bpfdata) {
+        if (family == AF_INET) {
+            SC_ATOMIC_SET(bpfdata->ipv4_hash_count, cnt);
+        } else if (family == AF_INET6) {
+            SC_ATOMIC_SET(bpfdata->ipv6_hash_count, cnt);
+        }
+    }
+}
+
+#ifdef BUILD_UNIX_SOCKET
+TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data)
+{
+    LiveDevice *ldev = NULL, *ndev;
+
+    json_t *ifaces = NULL;
+    while(LiveDeviceForEach(&ldev, &ndev)) {
+        BypassInfo *bpinfo = LiveDevGetStorageById(ldev, g_bypass_storage_id);
+        if (bpinfo) {
+            uint64_t ipv4_hash_count = SC_ATOMIC_GET(bpinfo->ipv4_hash_count);
+            uint64_t ipv6_hash_count = SC_ATOMIC_GET(bpinfo->ipv6_hash_count);
+            json_t *iface = json_object();
+            if (ifaces == NULL) {
+                ifaces = json_object();
+                if (ifaces == NULL) {
+                    json_object_set_new(answer, "message",
+                            json_string("internal error at json object creation"));
+                    return TM_ECODE_FAILED;
+                }
+            }
+            json_object_set_new(iface, "ipv4_count", json_integer(ipv4_hash_count));
+            json_object_set_new(iface, "ipv6_count", json_integer(ipv6_hash_count));
+            json_object_set_new(ifaces, ldev->dev, iface);
+        }
+    }
+    if (ifaces) {
+        json_object_set_new(answer, "message", ifaces);
+        SCReturnInt(TM_ECODE_OK);
+    }
+
+    json_object_set_new(answer, "message",
+                        json_string("No interface using bypass"));
+    SCReturnInt(TM_ECODE_FAILED);
+}
+#endif
index d14825b1b4379a16faa9f2f4a633166c13e97ce2..a8991af97ca08c027e34708185e4fe3d43aed75b 100644 (file)
@@ -60,8 +60,12 @@ typedef struct LiveDeviceName_ {
     TAILQ_ENTRY(LiveDeviceName_) next;
 } LiveDeviceName;
 
+void LiveDevRegisterExtension(void);
+
 int LiveRegisterDeviceName(const char *dev);
 int LiveRegisterDevice(const char *dev);
+int LiveDevUseBypass(LiveDevice *dev);
+void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family);
 int LiveGetDeviceCount(void);
 const char *LiveGetDeviceName(int number);
 LiveDevice *LiveGetDevice(const char *dev);
@@ -78,6 +82,7 @@ void LiveDeviceFinalize(void);
 #ifdef BUILD_UNIX_SOCKET
 TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *server_msg, void *data);
 TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *server_msg, void *data);
+TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data);
 #endif
 
 #endif /* __UTIL_DEVICE_H__ */
index 92c998d4a6b49344e8723db986dcb7ac9a83d9b5..149af41828c29bf8362c003155f2e1b9e3a574a7 100644 (file)
@@ -71,8 +71,6 @@ struct bpf_map_item {
 
 struct bpf_maps_info {
     struct bpf_map_item array[BPF_MAP_MAX_COUNT];
-    SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count);
-    SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count);
     int last;
 };
 
@@ -221,8 +219,7 @@ static int EBPFLoadPinnedMaps(LiveDevice *livedev, struct ebpf_timeout_config *c
         SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate bpf map array");
         return -1;
     }
-    SC_ATOMIC_INIT(bpf_map_data->ipv4_hash_count);
-    SC_ATOMIC_INIT(bpf_map_data->ipv6_hash_count);
+
     if (config->mode == AFP_MODE_XDP_BYPASS) {
         bpf_map_data->array[0].fd = fd_v4;
         bpf_map_data->array[0].name = SCStrdup("flow_table_v4");
@@ -279,6 +276,8 @@ static int EBPFLoadPinnedMaps(LiveDevice *livedev, struct ebpf_timeout_config *c
 
     /* Attach the bpf_maps_info to the LiveDevice via the device storage */
     LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data);
+    /* Declare that device will use bypass stats */
+    LiveDevUseBypass(livedev);
 
     return 0;
 
@@ -411,8 +410,6 @@ int EBPFLoadFile(const char *iface, const char *path, const char * section,
         SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate bpf map array");
         return -1;
     }
-    SC_ATOMIC_INIT(bpf_map_data->ipv4_hash_count);
-    SC_ATOMIC_INIT(bpf_map_data->ipv6_hash_count);
 
     /* Store the maps in bpf_maps_info:: */
     bpf_map__for_each(map, bpfobj) {
@@ -453,6 +450,7 @@ int EBPFLoadFile(const char *iface, const char *path, const char * section,
 
     /* Attach the bpf_maps_info to the LiveDevice via the device storage */
     LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data);
+    LiveDevUseBypass(livedev);
 
     /* Finally we get the file descriptor for our eBPF program. We will use
      * the fd to attach the program to the socket (eBPF case) or to the device
@@ -655,10 +653,7 @@ static int EBPFForEachFlowV4Table(LiveDevice *dev, const char *name,
     }
     SC_ATOMIC_ADD(dev->bypassed, flowstats->packets);
 
-    struct bpf_maps_info *bpfdata = LiveDevGetStorageById(dev, g_livedev_storage_id);
-    if (bpfdata) {
-        SC_ATOMIC_SET(bpfdata->ipv4_hash_count, hash_cnt);
-    }
+    LiveDevSetBypassStats(dev, hash_cnt, AF_INET);
 
     return found;
 }
@@ -750,10 +745,7 @@ static int EBPFForEachFlowV6Table(LiveDevice *dev, const char *name,
     }
     SC_ATOMIC_ADD(dev->bypassed, flowstats->packets);
 
-    struct bpf_maps_info *bpfdata = LiveDevGetStorageById(dev, g_livedev_storage_id);
-    if (bpfdata) {
-        SC_ATOMIC_SET(bpfdata->ipv6_hash_count, hash_cnt);
-    }
+    LiveDevSetBypassStats(dev, hash_cnt, AF_INET6);
     return found;
 }
 
@@ -819,42 +811,6 @@ int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
     return ret;
 }
 
-#ifdef BUILD_UNIX_SOCKET
-TmEcode EBPFGetBypassedStats(json_t *cmd, json_t *answer, void *data)
-{
-    LiveDevice *ldev = NULL, *ndev;
-
-    json_t *ifaces = NULL;
-    while(LiveDeviceForEach(&ldev, &ndev)) {
-        struct bpf_maps_info *bpfdata = LiveDevGetStorageById(ldev, g_livedev_storage_id);
-        if (bpfdata) {
-            uint64_t ipv4_hash_count = SC_ATOMIC_GET(bpfdata->ipv4_hash_count);
-            uint64_t ipv6_hash_count = SC_ATOMIC_GET(bpfdata->ipv6_hash_count);
-            json_t *iface = json_object();
-            if (ifaces == NULL) {
-                ifaces = json_object();
-                if (ifaces == NULL) {
-                    json_object_set_new(answer, "message",
-                            json_string("internal error at json object creation"));
-                    return TM_ECODE_FAILED;
-                }
-            }
-            json_object_set_new(iface, "ipv4_count", json_integer(ipv4_hash_count));
-            json_object_set_new(iface, "ipv6_count", json_integer(ipv6_hash_count));
-            json_object_set_new(ifaces, ldev->dev, iface);
-        }
-    }
-    if (ifaces) {
-        json_object_set_new(answer, "message", ifaces);
-        SCReturnInt(TM_ECODE_OK);
-    }
-
-    json_object_set_new(answer, "message",
-                        json_string("No interface using eBPF bypass"));
-    SCReturnInt(TM_ECODE_FAILED);
-}
-#endif
-
 void EBPFRegisterExtension(void)
 {
     g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree);