]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
af-packet: better accounting and error handling
authorEric Leblond <eric@regit.org>
Mon, 10 Jun 2019 14:40:47 +0000 (16:40 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 18 Jun 2019 05:07:02 +0000 (07:07 +0200)
This patch improves the bypass error handling add adds more counters
to the interface so it is possible to get a view on success and
failure of insertion in the eBPF maps via the `iface-bypassed-stat`
command.

src/source-af-packet.c
src/util-device.c
src/util-device.h
src/util-ebpf.c
src/util-ebpf.h

index 68ad9acfd3c8fca017326f2ea236d5e5daced7b6..31eb5f654789b06186f3ef39f4075cdc5bae47d5 100644 (file)
@@ -2331,12 +2331,16 @@ static int AFPInsertHalfFlow(int mapd, void *key, unsigned int nr_cpus)
     return 1;
 }
 
-static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void* key1)
+static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void* key1,
+                             int family)
 {
     FlowBypassInfo *fc = FlowGetStorageById(p->flow, GetFlowBypassInfoID());
     if (fc) {
         EBPFBypassData *eb = SCCalloc(1, sizeof(EBPFBypassData));
         if (eb == NULL) {
+            EBPFDeleteKey(map_fd, key0);
+            EBPFDeleteKey(map_fd, key1);
+            LiveDevAddBypassFail(p->livedev, 1, family);
             SCFree(key0);
             SCFree(key1);
             return 0;
@@ -2348,7 +2352,16 @@ static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void* key1)
         fc->BypassUpdate = EBPFBypassUpdate;
         fc->BypassFree = EBPFBypassFree;
         fc->bypass_data = eb;
+    } else {
+        EBPFDeleteKey(map_fd, key0);
+        EBPFDeleteKey(map_fd, key1);
+        LiveDevAddBypassFail(p->livedev, 1, family);
+        SCFree(key0);
+        SCFree(key1);
+        return 0;
     }
+
+    LiveDevAddBypassStats(p->livedev, 1, family);
     return 1;
 }
 
@@ -2413,11 +2426,14 @@ static int AFPBypassCallback(Packet *p)
         }
         if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0],
                               p->afp_v.nr_cpus) == 0) {
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET);
             SCFree(keys[0]);
             return 0;
         }
         keys[1]= SCCalloc(1, sizeof(struct flowv4_keys));
         if (keys[1] == NULL) {
+            EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET);
             SCFree(keys[0]);
             return 0;
         }
@@ -2431,13 +2447,14 @@ static int AFPBypassCallback(Packet *p)
         keys[1]->ip_proto = keys[0]->ip_proto;
         if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1],
                               p->afp_v.nr_cpus) == 0) {
+            EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET);
             SCFree(keys[0]);
             SCFree(keys[1]);
             return 0;
         }
         EBPFUpdateFlow(p->flow, p, NULL);
-        LiveDevAddBypassStats(p->livedev, 1, AF_INET);
-        return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1]);
+        return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1], AF_INET);
     }
     /* For IPv6 case we don't handle extended header in eBPF */
     if (PKT_IS_IPV6(p) &&
@@ -2450,6 +2467,7 @@ static int AFPBypassCallback(Packet *p)
         struct flowv6_keys *keys[2];
         keys[0] = SCCalloc(1, sizeof(struct flowv6_keys));
         if (keys[0] == NULL) {
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET6);
             return 0;
         }
         for (i = 0; i < 4; i++) {
@@ -2468,11 +2486,14 @@ static int AFPBypassCallback(Packet *p)
         }
         if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0],
                               p->afp_v.nr_cpus) == 0) {
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET6);
             SCFree(keys[0]);
             return 0;
         }
         keys[1]= SCCalloc(1, sizeof(struct flowv6_keys));
         if (keys[1] == NULL) {
+            EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET6);
             SCFree(keys[0]);
             return 0;
         }
@@ -2488,14 +2509,15 @@ static int AFPBypassCallback(Packet *p)
         keys[1]->ip_proto = keys[0]->ip_proto;
         if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1],
                               p->afp_v.nr_cpus) == 0) {
+            EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET6);
             SCFree(keys[0]);
             SCFree(keys[1]);
             return 0;
         }
         if (p->flow)
             EBPFUpdateFlow(p->flow, p, NULL);
-        LiveDevAddBypassStats(p->livedev, 1, AF_INET6);
-        return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1]);
+        return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1], AF_INET6);
     }
 #endif
     return 0;
@@ -2537,6 +2559,7 @@ static int AFPXDPBypassCallback(Packet *p)
         struct flowv4_keys *keys[2];
         keys[0]= SCCalloc(1, sizeof(struct flowv4_keys));
         if (keys[0] == NULL) {
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET);
             return 0;
         }
         if (p->afp_v.v4_map_fd == -1) {
@@ -2558,11 +2581,14 @@ static int AFPXDPBypassCallback(Packet *p)
         }
         if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0],
                               p->afp_v.nr_cpus) == 0) {
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET);
             SCFree(keys[0]);
             return 0;
         }
         keys[1]= SCCalloc(1, sizeof(struct flowv4_keys));
         if (keys[1] == NULL) {
+            EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET);
             SCFree(keys[0]);
             return 0;
         }
@@ -2575,12 +2601,13 @@ static int AFPXDPBypassCallback(Packet *p)
         keys[1]->ip_proto = keys[0]->ip_proto;
         if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1],
                               p->afp_v.nr_cpus) == 0) {
+            EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET);
             SCFree(keys[0]);
             SCFree(keys[1]);
             return 0;
         }
-        LiveDevAddBypassStats(p->livedev, 1, AF_INET);
-        return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1]);
+        return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1], AF_INET);
     }
     /* For IPv6 case we don't handle extended header in eBPF */
     if (PKT_IS_IPV6(p) &&
@@ -2611,11 +2638,14 @@ static int AFPXDPBypassCallback(Packet *p)
         }
         if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0],
                               p->afp_v.nr_cpus) == 0) {
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET6);
             SCFree(keys[0]);
             return 0;
         }
         keys[1]= SCCalloc(1, sizeof(struct flowv6_keys));
         if (keys[1] == NULL) {
+            EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET6);
             SCFree(keys[0]);
             return 0;
         }
@@ -2630,12 +2660,13 @@ static int AFPXDPBypassCallback(Packet *p)
         keys[1]->ip_proto = keys[0]->ip_proto;
         if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1],
                               p->afp_v.nr_cpus) == 0) {
+            EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]);
+            LiveDevAddBypassFail(p->livedev, 1, AF_INET6);
             SCFree(keys[0]);
             SCFree(keys[1]);
             return 0;
         }
-        LiveDevAddBypassStats(p->livedev, 1, AF_INET6);
-        return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1]);
+        return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1], AF_INET6);
     }
 #endif
     return 0;
index fd4b598a0745505600ab22ca93a3811903f117a1..73d7c0a867386850f37381fabdc029dc3bcf49de 100644 (file)
@@ -49,7 +49,11 @@ static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices =
 
 typedef struct BypassInfo_ {
     SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count);
+    SC_ATOMIC_DECLARE(uint64_t, ipv4_fail);
+    SC_ATOMIC_DECLARE(uint64_t, ipv4_success);
     SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count);
+    SC_ATOMIC_DECLARE(uint64_t, ipv6_fail);
+    SC_ATOMIC_DECLARE(uint64_t, ipv6_success);
 } BypassInfo;
 
 /** if set to 0 when we don't have real devices */
@@ -526,8 +530,10 @@ void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family)
     if (bpfdata) {
         if (family == AF_INET) {
             SC_ATOMIC_ADD(bpfdata->ipv4_hash_count, cnt);
+            SC_ATOMIC_ADD(bpfdata->ipv4_success, cnt);
         } else if (family == AF_INET6) {
             SC_ATOMIC_ADD(bpfdata->ipv6_hash_count, cnt);
+            SC_ATOMIC_ADD(bpfdata->ipv6_success, cnt);
         }
     }
 }
@@ -551,6 +557,27 @@ void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family)
     }
 }
 
+/**
+ * Increase number of failed captured flows for a protocol family
+ *
+ * \param dev pointer to LiveDevice to set stats for
+ * \param cnt number of flows to add
+ * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count
+ */
+void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family)
+{
+    BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id);
+    if (bpfdata) {
+        if (family == AF_INET) {
+            SC_ATOMIC_ADD(bpfdata->ipv4_fail, cnt);
+        } else if (family == AF_INET6) {
+            SC_ATOMIC_ADD(bpfdata->ipv6_fail, cnt);
+        }
+    }
+}
+
+
+
 #ifdef BUILD_UNIX_SOCKET
 TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data)
 {
@@ -562,6 +589,10 @@ TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data)
         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);
+            uint64_t ipv4_success = SC_ATOMIC_GET(bpinfo->ipv4_success);
+            uint64_t ipv4_fail = SC_ATOMIC_GET(bpinfo->ipv4_fail);
+            uint64_t ipv6_success = SC_ATOMIC_GET(bpinfo->ipv6_success);
+            uint64_t ipv6_fail = SC_ATOMIC_GET(bpinfo->ipv6_fail);
             json_t *iface = json_object();
             if (ifaces == NULL) {
                 ifaces = json_object();
@@ -571,8 +602,12 @@ TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data)
                     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(iface, "ipv4_maps_count", json_integer(ipv4_hash_count));
+            json_object_set_new(iface, "ipv4_success", json_integer(ipv4_success));
+            json_object_set_new(iface, "ipv4_fail", json_integer(ipv4_fail));
+            json_object_set_new(iface, "ipv6_maps_count", json_integer(ipv6_hash_count));
+            json_object_set_new(iface, "ipv6_success", json_integer(ipv6_success));
+            json_object_set_new(iface, "ipv6_fail", json_integer(ipv6_fail));
             json_object_set_new(ifaces, ldev->dev, iface);
         }
     }
index 9765ec224e063f1294d06e670f476a6f4b3edfac..27f60179ac86239936cb76d0c0946f2aec82f1ec 100644 (file)
@@ -68,6 +68,7 @@ int LiveDevUseBypass(LiveDevice *dev);
 void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family);
 void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family);
 void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family);
+void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family);
 int LiveGetDeviceCount(void);
 const char *LiveGetDeviceName(int number);
 LiveDevice *LiveGetDevice(const char *dev);
index 7117d0aa7ba8ca9ed434467fdb228304b84adb4f..59f434a4cf5788f75a73e17c168693dfe629d5a0 100644 (file)
@@ -125,7 +125,7 @@ static void BypassedListFree(void *ifl)
     }
 }
 
-static void EBPFDeleteKey(int fd, void *key)
+void EBPFDeleteKey(int fd, void *key)
 {
     int ret = bpf_map_delete_elem(fd, key);
     if (ret < 0) {
index f66cc7c95530ecff251741f5900e9e4f2c57f980..83e36f88a862b2b01016447b875a59601a3f3493 100644 (file)
@@ -93,6 +93,8 @@ int EBPFUpdateFlow(Flow *f, Packet *p, void *data);
 bool EBPFBypassUpdate(Flow *f, void *data, time_t tsec);
 void EBPFBypassFree(void *data);
 
+void EBPFDeleteKey(int fd, void *key);
+
 #ifdef BUILD_UNIX_SOCKET
 TmEcode EBPFGetBypassedStats(json_t *cmd, json_t *answer, void *data);
 #endif