From: Eric Leblond Date: Tue, 26 Dec 2017 21:55:55 +0000 (+0100) Subject: af-packet: add support for multi iface bypass X-Git-Tag: suricata-4.1.0-beta1~204 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=126488f74dbaf1121fcf614b3f75a77e97562604;p=thirdparty%2Fsuricata.git af-packet: add support for multi iface bypass --- diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 1ad138d2a1..1b15a28d00 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -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, diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 1453509fec..fa4bacd5ca 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -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"); } diff --git a/src/suricata.c b/src/suricata.c index dae12f0d10..a2d64eac7e 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -127,6 +127,7 @@ #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 diff --git a/src/util-ebpf.c b/src/util-ebpf.c index 4ec0139436..4344b651fe 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -43,6 +43,9 @@ #include "util-ebpf.h" #include "util-cpu.h" +#include "util-device.h" + +#include "device-storage.h" #include #include @@ -53,31 +56,61 @@ #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 diff --git a/src/util-ebpf.h b/src/util-ebpf.h index 21d7e55ae9..2d5a0d6186 100644 --- a/src/util-ebpf.h +++ b/src/util-ebpf.h @@ -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