af-packet: add support for multi iface bypass

pull/3221/head
Eric Leblond 8 years ago
parent 4474889667
commit 126488f74d

@ -381,7 +381,7 @@ static void *ParseAFPConfig(const char *iface)
#ifdef HAVE_PACKET_EBPF #ifdef HAVE_PACKET_EBPF
/* One shot loading of the eBPF file */ /* One shot loading of the eBPF file */
if (aconf->ebpf_lb_file && cluster_type == PACKET_FANOUT_EBPF) { 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); &aconf->ebpf_lb_fd, EBPF_SOCKET_FILTER);
if (ret != 0) { if (ret != 0) {
SCLogWarning(SC_ERR_INVALID_VALUE, "Error when loading eBPF lb file"); 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 */ /* One shot loading of the eBPF file */
if (aconf->ebpf_filter_file) { if (aconf->ebpf_filter_file) {
#ifdef HAVE_PACKET_EBPF #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); &aconf->ebpf_filter_fd, EBPF_SOCKET_FILTER);
if (ret != 0) { if (ret != 0) {
SCLogWarning(SC_ERR_INVALID_VALUE, SCLogWarning(SC_ERR_INVALID_VALUE,
@ -469,7 +469,7 @@ static void *ParseAFPConfig(const char *iface)
/* One shot loading of the eBPF file */ /* One shot loading of the eBPF file */
if (aconf->xdp_filter_file) { if (aconf->xdp_filter_file) {
#ifdef HAVE_PACKET_XDP #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); &aconf->xdp_filter_fd, EBPF_XDP_CODE);
if (ret != 0) { if (ret != 0) {
SCLogWarning(SC_ERR_INVALID_VALUE, SCLogWarning(SC_ERR_INVALID_VALUE,

@ -2514,11 +2514,11 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data)
#ifdef HAVE_PACKET_EBPF #ifdef HAVE_PACKET_EBPF
if (ptv->flags & (AFP_BYPASS|AFP_XDPBYPASS)) { 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) { if (ptv->v4_map_fd == -1) {
SCLogError(SC_ERR_INVALID_VALUE, "Can't find eBPF map fd for '%s'", "flow_table_v4"); 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) { if (ptv->v6_map_fd == -1) {
SCLogError(SC_ERR_INVALID_VALUE, "Can't find eBPF map fd for '%s'", "flow_table_v6"); SCLogError(SC_ERR_INVALID_VALUE, "Can't find eBPF map fd for '%s'", "flow_table_v6");
} }

@ -127,6 +127,7 @@
#include "app-layer-dnp3.h" #include "app-layer-dnp3.h"
#include "util-decode-der.h" #include "util-decode-der.h"
#include "util-ebpf.h"
#include "util-radix-tree.h" #include "util-radix-tree.h"
#include "util-host-os-info.h" #include "util-host-os-info.h"
#include "util-cidr.h" #include "util-cidr.h"
@ -2568,6 +2569,9 @@ static int PostConfLoadedSetup(SCInstance *suri)
} }
StorageInit(); StorageInit();
#ifdef HAVE_PACKET_EBPF
EBPFRegisterExtension();
#endif
AppLayerSetup(); AppLayerSetup();
/* Check for the existance of the default logging directory which we pick /* Check for the existance of the default logging directory which we pick

@ -43,6 +43,9 @@
#include "util-ebpf.h" #include "util-ebpf.h"
#include "util-cpu.h" #include "util-cpu.h"
#include "util-device.h"
#include "device-storage.h"
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include <bpf/bpf.h> #include <bpf/bpf.h>
@ -53,31 +56,61 @@
#define BYPASSED_FLOW_TIMEOUT 60 #define BYPASSED_FLOW_TIMEOUT 60
static int g_livedev_storage_id = -1;
struct bpf_map_item { struct bpf_map_item {
const char * name; char * name;
int fd; int fd;
}; };
static struct bpf_map_item bpf_map_array[BPF_MAP_MAX_COUNT]; struct bpf_maps_info {
static int bpf_map_last = 0; 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) static void EBPFDeleteKey(int fd, void *key)
{ {
bpf_map_delete_elem(fd, 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; 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; return -1;
for (i = 0; i < BPF_MAP_MAX_COUNT; i++) { for (i = 0; i < BPF_MAP_MAX_COUNT; i++) {
if (!bpf_map_array[i].name) if (!bpf_maps->array[i].name)
continue; continue;
if (!strcmp(bpf_map_array[i].name, name)) { if (!strcmp(bpf_maps->array[i].name, name)) {
SCLogDebug("Got fd %d for eBPF map '%s'", bpf_map_array[i].fd, name); SCLogDebug("Got fd %d for eBPF map '%s'", bpf_maps->array[i].fd, name);
return bpf_map_array[i].fd; return bpf_maps->array[i].fd;
} }
} }
return -1; return -1;
@ -98,14 +131,21 @@ int EBPFGetMapFDByName(const char *name)
* \param val a pointer to an integer that will be the file desc * \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 * \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; int err, pfd;
bool found = false; bool found = false;
struct bpf_object *bpfobj = NULL; struct bpf_object *bpfobj = NULL;
struct bpf_program *bpfprog = NULL; struct bpf_program *bpfprog = NULL;
struct bpf_map *map = 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) { if (! path) {
SCLogError(SC_ERR_INVALID_VALUE, "No file defined to load eBPF from"); SCLogError(SC_ERR_INVALID_VALUE, "No file defined to load eBPF from");
return -1; return -1;
@ -172,22 +212,31 @@ int EBPFLoadFile(const char *path, const char * section, int *val, uint8_t flags
return -1; 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 */ /* store the map in our array */
bpf_map__for_each(map, bpfobj) { 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)); 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_data->array[bpf_map_data->last].fd = bpf_map__fd(map);
bpf_map_array[bpf_map_last].name = SCStrdup(bpf_map__name(map)); bpf_map_data->array[bpf_map_data->last].name = SCStrdup(bpf_map__name(map));
if (!bpf_map_array[bpf_map_last].name) { if (!bpf_map_data->array[bpf_map_data->last].name) {
SCLogError(SC_ERR_MEM_ALLOC, "Unable to duplicate map name"); SCLogError(SC_ERR_MEM_ALLOC, "Unable to duplicate map name");
BpfMapsInfoFree(bpf_map_data);
return -1; return -1;
} }
bpf_map_last++; bpf_map_data->last++;
if (bpf_map_last == BPF_MAP_MAX_COUNT) {
SCLogError(SC_ERR_NOT_SUPPORTED, "Too many BPF maps in eBPF files");
return -1;
}
} }
LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data);
pfd = bpf_program__fd(bpfprog); pfd = bpf_program__fd(bpfprog);
if (pfd == -1) { if (pfd == -1) {
SCLogError(SC_ERR_INVALID_VALUE, 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), int (*FlowCallback)(int fd, struct flowv4_keys *key, struct pair *value, void *data),
struct flows_stats *flowstats, struct flows_stats *flowstats,
void *data) void *data)
{ {
int mapfd = EBPFGetMapFDByName(name); int mapfd = EBPFGetMapFDByName(iface, name);
struct flowv4_keys key = {}, next_key; struct flowv4_keys key = {}, next_key;
int found = 0; int found = 0;
unsigned int i; unsigned int i;
@ -275,12 +324,12 @@ static int EBPFForEachFlowV4Table(const char *name,
return found; 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), int (*FlowCallback)(int fd, struct flowv6_keys *key, struct pair *value, void *data),
struct flows_stats *flowstats, struct flows_stats *flowstats,
void *data) void *data)
{ {
int mapfd = EBPFGetMapFDByName(name); int mapfd = EBPFGetMapFDByName(iface, name);
struct flowv6_keys key = {}, next_key; struct flowv6_keys key = {}, next_key;
int found = 0; int found = 0;
unsigned int i; unsigned int i;
@ -358,24 +407,33 @@ int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
struct flows_stats l_bypassstats = { 0, 0, 0}; struct flows_stats l_bypassstats = { 0, 0, 0};
int ret = 0; int ret = 0;
int tcount = 0; int tcount = 0;
tcount = EBPFForEachFlowV4Table("flow_table_v4", EBPFBypassedFlowV4Timeout, LiveDevice *ldev = NULL, *ndev;
&l_bypassstats, curtime);
if (tcount) { while(LiveDeviceForEach(&ldev, &ndev)) {
bypassstats->count = l_bypassstats.count; tcount = EBPFForEachFlowV4Table(ldev->dev, "flow_table_v4", EBPFBypassedFlowV4Timeout,
bypassstats->packets = l_bypassstats.packets ; &l_bypassstats, curtime);
bypassstats->bytes = l_bypassstats.bytes; if (tcount) {
ret = 1; bypassstats->count = l_bypassstats.count;
} bypassstats->packets = l_bypassstats.packets ;
memset(&l_bypassstats, 0, sizeof(l_bypassstats)); bypassstats->bytes = l_bypassstats.bytes;
tcount = EBPFForEachFlowV6Table("flow_table_v6", EBPFBypassedFlowV6Timeout, ret = 1;
&l_bypassstats, curtime); }
if (tcount) { memset(&l_bypassstats, 0, sizeof(l_bypassstats));
bypassstats->count += l_bypassstats.count; tcount = EBPFForEachFlowV6Table(ldev->dev, "flow_table_v6", EBPFBypassedFlowV6Timeout,
bypassstats->packets += l_bypassstats.packets ; &l_bypassstats, curtime);
bypassstats->bytes += l_bypassstats.bytes; if (tcount) {
ret = 1; bypassstats->count += l_bypassstats.count;
bypassstats->packets += l_bypassstats.packets ;
bypassstats->bytes += l_bypassstats.bytes;
ret = 1;
}
} }
return ret; return ret;
} }
void EBPFRegisterExtension(void)
{
g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree);
}
#endif #endif

@ -62,13 +62,16 @@ struct pair {
#define EBPF_SOCKET_FILTER (1<<0) #define EBPF_SOCKET_FILTER (1<<0)
#define EBPF_XDP_CODE (1<<1) #define EBPF_XDP_CODE (1<<1)
int EBPFGetMapFDByName(const char *name); int EBPFGetMapFDByName(const char *iface, const char *name);
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 EBPFSetupXDP(const char *iface, int fd, uint8_t flags); int EBPFSetupXDP(const char *iface, int fd, uint8_t flags);
int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats, int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
struct timespec *curtime); struct timespec *curtime);
void EBPFRegisterExtension(void);
#endif #endif
#endif #endif

Loading…
Cancel
Save