]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
af-packet: add support for multi iface bypass
authorEric Leblond <eric@regit.org>
Tue, 26 Dec 2017 21:55:55 +0000 (22:55 +0100)
committerEric Leblond <eric@regit.org>
Tue, 6 Feb 2018 15:58:19 +0000 (16:58 +0100)
src/runmode-af-packet.c
src/source-af-packet.c
src/suricata.c
src/util-ebpf.c
src/util-ebpf.h

index 1ad138d2a12621edaca92a2358aa1d5f2e36e3fe..1b15a28d000b8d66be3ef5400e965632f6e20609 100644 (file)
@@ -381,7 +381,7 @@ static void *ParseAFPConfig(const char *iface)
 #ifdef HAVE_PACKET_EBPF
     /* One shot loading of the eBPF file */
     if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) {
-        int ret = EBPFLoadFile(aconf->ebpf_lb_file, "loadbalancer",
+        int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_lb_file, "loadbalancer",
                                &aconf->ebpf_lb_fd, EBPF_SOCKET_FILTER);
         if (ret != 0) {
             SCLogWarning(SC_ERR_INVALID_VALUE, "Error when loading eBPF lb file");
@@ -418,7 +418,7 @@ static void *ParseAFPConfig(const char *iface)
     /* One shot loading of the eBPF file */
     if (aconf->ebpf_filter_file) {
 #ifdef HAVE_PACKET_EBPF
-        int ret = EBPFLoadFile(aconf->ebpf_filter_file, "filter",
+        int ret = EBPFLoadFile(aconf->iface, aconf->ebpf_filter_file, "filter",
                                &aconf->ebpf_filter_fd, EBPF_SOCKET_FILTER);
         if (ret != 0) {
             SCLogWarning(SC_ERR_INVALID_VALUE,
@@ -469,7 +469,7 @@ static void *ParseAFPConfig(const char *iface)
     /* One shot loading of the eBPF file */
     if (aconf->xdp_filter_file) {
 #ifdef HAVE_PACKET_XDP
-        int ret = EBPFLoadFile(aconf->xdp_filter_file, "xdp",
+        int ret = EBPFLoadFile(aconf->iface, aconf->xdp_filter_file, "xdp",
                                &aconf->xdp_filter_fd, EBPF_XDP_CODE);
         if (ret != 0) {
             SCLogWarning(SC_ERR_INVALID_VALUE,
index 1453509fec25a4a051499066a77ab74c07fdbb53..fa4bacd5ca9d2d39c8ff2ce3b2a4c9c0840db874 100644 (file)
@@ -2514,11 +2514,11 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data)
 
 #ifdef HAVE_PACKET_EBPF
     if (ptv->flags & (AFP_BYPASS|AFP_XDPBYPASS)) {
-        ptv->v4_map_fd = EBPFGetMapFDByName("flow_table_v4");
+        ptv->v4_map_fd = EBPFGetMapFDByName(ptv->iface, "flow_table_v4");
         if (ptv->v4_map_fd == -1) {
             SCLogError(SC_ERR_INVALID_VALUE, "Can't find eBPF map fd for '%s'", "flow_table_v4");
         }
-        ptv->v6_map_fd = EBPFGetMapFDByName("flow_table_v6");
+        ptv->v6_map_fd = EBPFGetMapFDByName(ptv->iface, "flow_table_v6");
         if (ptv->v6_map_fd  == -1) {
             SCLogError(SC_ERR_INVALID_VALUE, "Can't find eBPF map fd for '%s'", "flow_table_v6");
         }
index dae12f0d1096d1f5c9d776ec5ad57aee590c7ac6..a2d64eac7e435e44746e9be7f8b36913b99adb9a 100644 (file)
 #include "app-layer-dnp3.h"
 
 #include "util-decode-der.h"
+#include "util-ebpf.h"
 #include "util-radix-tree.h"
 #include "util-host-os-info.h"
 #include "util-cidr.h"
@@ -2568,6 +2569,9 @@ static int PostConfLoadedSetup(SCInstance *suri)
     }
 
     StorageInit();
+#ifdef HAVE_PACKET_EBPF
+    EBPFRegisterExtension();
+#endif
     AppLayerSetup();
 
     /* Check for the existance of the default logging directory which we pick
index 4ec013943622e329d8c78ecb730a0a325a280335..4344b651fefcec45f53443c38f6e7a8f81f0ee4f 100644 (file)
@@ -43,6 +43,9 @@
 
 #include "util-ebpf.h"
 #include "util-cpu.h"
+#include "util-device.h"
+
+#include "device-storage.h"
 
 #include <bpf/libbpf.h>
 #include <bpf/bpf.h>
 
 #define BYPASSED_FLOW_TIMEOUT   60
 
+static int g_livedev_storage_id = -1;
+
 struct bpf_map_item {
-    const char * name;
+    char * name;
     int fd;
 };
 
-static struct bpf_map_item bpf_map_array[BPF_MAP_MAX_COUNT];
-static int bpf_map_last = 0;
+struct bpf_maps_info {
+    struct bpf_map_item array[BPF_MAP_MAX_COUNT];
+    int last;
+};
+
+static void BpfMapsInfoFree(void *bpf)
+{
+    struct bpf_maps_info *bpfinfo = (struct bpf_maps_info *)bpf;
+    int i;
+    for (i = 0; i < bpfinfo->last; i ++) {
+        if (bpfinfo->array[i].name) {
+            SCFree(bpfinfo->array[i].name);
+        }
+    }
+    SCFree(bpfinfo);
+}
 
 static void EBPFDeleteKey(int fd, void *key)
 {
     bpf_map_delete_elem(fd, key);
 }
 
-int EBPFGetMapFDByName(const char *name)
+static struct bpf_maps_info *EBPFGetBpfMap(const char *iface)
+{
+    LiveDevice *livedev = LiveGetDevice(iface);
+    if (livedev == NULL)
+        return NULL;
+    void *data = LiveDevGetStorageById(livedev, g_livedev_storage_id);
+
+    return (struct bpf_maps_info *)data;
+}
+
+int EBPFGetMapFDByName(const char *iface, const char *name)
 {
     int i;
 
-    if (name == NULL)
+    if (iface == NULL || name == NULL)
+        return -1;
+    struct bpf_maps_info *bpf_maps = EBPFGetBpfMap(iface);
+    if (bpf_maps == NULL)
         return -1;
+
     for (i = 0; i < BPF_MAP_MAX_COUNT; i++) {
-        if (!bpf_map_array[i].name)
+        if (!bpf_maps->array[i].name)
             continue;
-        if (!strcmp(bpf_map_array[i].name, name)) {
-            SCLogDebug("Got fd %d for eBPF map '%s'", bpf_map_array[i].fd, name);
-            return bpf_map_array[i].fd;
+        if (!strcmp(bpf_maps->array[i].name, name)) {
+            SCLogDebug("Got fd %d for eBPF map '%s'", bpf_maps->array[i].fd, name);
+            return bpf_maps->array[i].fd;
         }
     }
     return -1;
@@ -98,14 +131,21 @@ int EBPFGetMapFDByName(const char *name)
  * \param val a pointer to an integer that will be the file desc
  * \return -1 in case of error and 0 in case of success
  */
-int EBPFLoadFile(const char *path, const char * section, int *val, uint8_t flags)
+int EBPFLoadFile(const char *iface, const char *path, const char * section,
+                 int *val, uint8_t flags)
 {
     int err, pfd;
     bool found = false;
     struct bpf_object *bpfobj = NULL;
     struct bpf_program *bpfprog = NULL;
     struct bpf_map *map = NULL;
-    /* FIXME we will need to close BPF at exit of runmode */
+
+    if (iface == NULL)
+        return -1;
+    LiveDevice *livedev = LiveGetDevice(iface);
+    if (livedev == NULL)
+        return -1;
+
     if (! path) {
         SCLogError(SC_ERR_INVALID_VALUE, "No file defined to load eBPF from");
         return -1;
@@ -172,22 +212,31 @@ int EBPFLoadFile(const char *path, const char * section, int *val, uint8_t flags
         return -1;
     }
 
+    struct bpf_maps_info *bpf_map_data = SCCalloc(1, sizeof(*bpf_map_data));
+    if (bpf_map_data == NULL) {
+        SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate bpf map array");
+        return -1;
+    }
+
     /* store the map in our array */
     bpf_map__for_each(map, bpfobj) {
+        if (bpf_map_data->last == BPF_MAP_MAX_COUNT) {
+            SCLogError(SC_ERR_NOT_SUPPORTED, "Too many BPF maps in eBPF files");
+            break;
+        }
         SCLogDebug("Got a map '%s' with fd '%d'", bpf_map__name(map), bpf_map__fd(map));
-        bpf_map_array[bpf_map_last].fd = bpf_map__fd(map);
-        bpf_map_array[bpf_map_last].name = SCStrdup(bpf_map__name(map));
-        if (!bpf_map_array[bpf_map_last].name) {
+        bpf_map_data->array[bpf_map_data->last].fd = bpf_map__fd(map);
+        bpf_map_data->array[bpf_map_data->last].name = SCStrdup(bpf_map__name(map));
+        if (!bpf_map_data->array[bpf_map_data->last].name) {
             SCLogError(SC_ERR_MEM_ALLOC, "Unable to duplicate map name");
+            BpfMapsInfoFree(bpf_map_data);
             return -1;
         }
-        bpf_map_last++;
-        if (bpf_map_last == BPF_MAP_MAX_COUNT) {
-            SCLogError(SC_ERR_NOT_SUPPORTED, "Too many BPF maps in eBPF files");
-            return -1;
-        }
+        bpf_map_data->last++;
     }
 
+    LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data);
+
     pfd = bpf_program__fd(bpfprog);
     if (pfd == -1) {
         SCLogError(SC_ERR_INVALID_VALUE,
@@ -222,12 +271,12 @@ int EBPFSetupXDP(const char *iface, int fd, uint8_t flags)
 }
 
 
-static int EBPFForEachFlowV4Table(const char *name,
+static int EBPFForEachFlowV4Table(const char *iface, const char *name,
                               int (*FlowCallback)(int fd, struct flowv4_keys *key, struct pair *value, void *data),
                               struct flows_stats *flowstats,
                               void *data)
 {
-    int mapfd = EBPFGetMapFDByName(name);
+    int mapfd = EBPFGetMapFDByName(iface, name);
     struct flowv4_keys key = {}, next_key;
     int found = 0;
     unsigned int i;
@@ -275,12 +324,12 @@ static int EBPFForEachFlowV4Table(const char *name,
     return found;
 }
 
-static int EBPFForEachFlowV6Table(const char *name,
+static int EBPFForEachFlowV6Table(const char *iface, const char *name,
                               int (*FlowCallback)(int fd, struct flowv6_keys *key, struct pair *value, void *data),
                               struct flows_stats *flowstats,
                               void *data)
 {
-    int mapfd = EBPFGetMapFDByName(name);
+    int mapfd = EBPFGetMapFDByName(iface, name);
     struct flowv6_keys key = {}, next_key;
     int found = 0;
     unsigned int i;
@@ -358,24 +407,33 @@ int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
     struct flows_stats l_bypassstats = { 0, 0, 0};
     int ret = 0;
     int tcount = 0;
-    tcount = EBPFForEachFlowV4Table("flow_table_v4", EBPFBypassedFlowV4Timeout,
-                                    &l_bypassstats, curtime);
-    if (tcount) {
-        bypassstats->count = l_bypassstats.count;
-        bypassstats->packets = l_bypassstats.packets ;
-        bypassstats->bytes = l_bypassstats.bytes;
-        ret = 1;
-    }
-    memset(&l_bypassstats, 0, sizeof(l_bypassstats));
-    tcount = EBPFForEachFlowV6Table("flow_table_v6", EBPFBypassedFlowV6Timeout,
-                                    &l_bypassstats, curtime);
-    if (tcount) {
-        bypassstats->count += l_bypassstats.count;
-        bypassstats->packets += l_bypassstats.packets ;
-        bypassstats->bytes += l_bypassstats.bytes;
-        ret = 1;
+    LiveDevice *ldev = NULL, *ndev;
+
+    while(LiveDeviceForEach(&ldev, &ndev)) {
+        tcount = EBPFForEachFlowV4Table(ldev->dev, "flow_table_v4", EBPFBypassedFlowV4Timeout,
+                &l_bypassstats, curtime);
+        if (tcount) {
+            bypassstats->count = l_bypassstats.count;
+            bypassstats->packets = l_bypassstats.packets ;
+            bypassstats->bytes = l_bypassstats.bytes;
+            ret = 1;
+        }
+        memset(&l_bypassstats, 0, sizeof(l_bypassstats));
+        tcount = EBPFForEachFlowV6Table(ldev->dev, "flow_table_v6", EBPFBypassedFlowV6Timeout,
+                &l_bypassstats, curtime);
+        if (tcount) {
+            bypassstats->count += l_bypassstats.count;
+            bypassstats->packets += l_bypassstats.packets ;
+            bypassstats->bytes += l_bypassstats.bytes;
+            ret = 1;
+        }
     }
     return ret;
 }
 
+void EBPFRegisterExtension(void)
+{
+    g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree);
+}
+
 #endif
index 21d7e55ae94599c2c1596c3797c494bb406b9b55..2d5a0d61863a617ef46cd80bd1145dbddbaba80e 100644 (file)
@@ -62,13 +62,16 @@ struct pair {
 #define EBPF_SOCKET_FILTER  (1<<0)
 #define EBPF_XDP_CODE       (1<<1)
 
-int EBPFGetMapFDByName(const char *name);
-int EBPFLoadFile(const char *path, const char * section, int *val, uint8_t flags);
+int EBPFGetMapFDByName(const char *iface, const char *name);
+int EBPFLoadFile(const char *iface, const char *path, const char * section,
+                 int *val, uint8_t flags);
 int EBPFSetupXDP(const char *iface, int fd, uint8_t flags);
 
 int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
                                         struct timespec *curtime);
 
+void EBPFRegisterExtension(void);
+
 #endif
 
 #endif