af-packet: XDP bypass in IPS mode

Implement XDP bypass in IPS mode by using XDP redirect to send
packets from bypassed flow directly to the transmission interface.
pull/3221/head
Eric Leblond 9 years ago
parent 7bec54158f
commit f04391031f

@ -102,6 +102,20 @@ struct bpf_map_def SEC("maps") cpus_count = {
.max_entries = 1,
};
struct bpf_map_def SEC("maps") tx_peer = {
.type = BPF_MAP_TYPE_DEVMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 1,
};
struct bpf_map_def SEC("maps") tx_peer_int = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 1,
};
static __always_inline int get_sport(void *trans_data, void *data_end,
uint8_t protocol)
{
@ -157,6 +171,8 @@ static int __always_inline filter_ipv4(void *data, __u64 nh_off, void *data_end)
uint32_t key0 = 0;
uint32_t *cpu_max = bpf_map_lookup_elem(&cpus_count, &key0);
uint32_t *cpu_selected;
int *iface_peer;
int tx_port = 0;
if ((void *)(iph + 1) > data_end)
return XDP_PASS;
@ -195,7 +211,12 @@ static int __always_inline filter_ipv4(void *data, __u64 nh_off, void *data_end)
value->packets++;
value->bytes += data_end - data;
return XDP_DROP;
iface_peer = bpf_map_lookup_elem(&tx_peer_int, &key0);
if (!iface_peer) {
return XDP_DROP;
} else {
return bpf_redirect_map(&tx_peer, tx_port, 0);
}
}
if (cpu_max && *cpu_max) {
@ -221,6 +242,8 @@ static int __always_inline filter_ipv6(void *data, __u64 nh_off, void *data_end)
uint32_t key0 = 0;
int *cpu_max = bpf_map_lookup_elem(&cpus_count, &key0);
uint32_t *cpu_selected;
int tx_port = 0;
int *iface_peer;
if ((void *)(ip6h + 1) > data_end)
return 0;
@ -250,7 +273,13 @@ static int __always_inline filter_ipv6(void *data, __u64 nh_off, void *data_end)
value->packets++;
value->bytes += data_end - data;
value->time = bpf_ktime_get_ns();
return XDP_DROP;
iface_peer = bpf_map_lookup_elem(&tx_peer_int, &key0);
if (!iface_peer) {
return XDP_DROP;
} else {
return bpf_redirect_map(&tx_peer, tx_port, 0);
}
}
if (cpu_max && *cpu_max) {
cpu_dest = (tuple.src[0] + tuple.dst[0] + tuple.src[3] + tuple.dst[3]) % *cpu_max;

@ -409,6 +409,7 @@ static void *ParseAFPConfig(const char *iface)
aconf->flags |= AFP_BYPASS;
RunModeEnablesBypassManager();
BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow);
#else
SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in");
#endif
@ -496,6 +497,10 @@ static void *ParseAFPConfig(const char *iface)
EBPFBuildCPUSet(NULL, aconf->iface);
}
}
/* we have a peer and we use bypass so we can set up XDP iface redirect */
if (aconf->out_iface) {
EBPFSetPeerIface(aconf->iface, aconf->out_iface);
}
}
#else
SCLogError(SC_ERR_UNIMPLEMENTED, "XDP support is not built-in");

@ -2360,6 +2360,7 @@ static int AFPBypassCallback(Packet *p)
if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, &key, inittime) == 0) {
return 0;
}
EBPFUpdateFlow(p->flow, p);
return 1;
}
/* For IPv6 case we don't handle extended header in eBPF */
@ -2390,6 +2391,7 @@ static int AFPBypassCallback(Packet *p)
if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, &key, inittime) == 0) {
return 0;
}
EBPFUpdateFlow(p->flow, p);
return 1;
}
#endif

@ -46,6 +46,7 @@
#include "util-device.h"
#include "device-storage.h"
#include "flow-storage.h"
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
@ -57,6 +58,7 @@
#define BYPASSED_FLOW_TIMEOUT 60
static int g_livedev_storage_id = -1;
static int g_flow_storage_id = -1;
struct bpf_map_item {
char * name;
@ -68,6 +70,11 @@ struct bpf_maps_info {
int last;
};
typedef struct BypassedIfaceList_ {
LiveDevice *dev;
struct BypassedIfaceList_ *next;
} BypassedIfaceList;
static void BpfMapsInfoFree(void *bpf)
{
struct bpf_maps_info *bpfinfo = (struct bpf_maps_info *)bpf;
@ -80,6 +87,17 @@ static void BpfMapsInfoFree(void *bpf)
SCFree(bpfinfo);
}
static void BypassedListFree(void *ifl)
{
BypassedIfaceList *mifl = (BypassedIfaceList *)ifl;
BypassedIfaceList *nifl;
while (mifl) {
nifl = mifl->next;
SCFree(mifl);
mifl = nifl;
}
}
static void EBPFDeleteKey(int fd, void *key)
{
bpf_map_delete_elem(fd, key);
@ -517,6 +535,7 @@ int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
void EBPFRegisterExtension(void)
{
g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree);
g_flow_storage_id = FlowStorageRegister("bypassedlist", sizeof(void *), NULL, BypassedListFree);
}
@ -585,6 +604,74 @@ void EBPFBuildCPUSet(ConfNode *node, char *iface)
BPF_ANY);
}
int EBPFSetPeerIface(const char *iface, const char *out_iface)
{
int mapfd = EBPFGetMapFDByName(iface, "tx_peer");
if (mapfd < 0) {
SCLogError(SC_ERR_INVALID_VALUE,
"Unable to find 'tx_peer' map");
return -1;
}
int intmapfd = EBPFGetMapFDByName(iface, "tx_peer_int");
if (intmapfd < 0) {
SCLogError(SC_ERR_INVALID_VALUE,
"Unable to find 'tx_peer_int' map");
return -1;
}
int key0 = 0;
unsigned int peer_index = if_nametoindex(out_iface);
if (peer_index == 0) {
SCLogError(SC_ERR_INVALID_VALUE, "No iface '%s'", out_iface);
return -1;
}
int ret = bpf_map_update_elem(mapfd, &key0, &peer_index, BPF_ANY);
if (ret) {
SCLogError(SC_ERR_AFP_CREATE, "Create peer entry failed (err:%d)", ret);
return -1;
}
ret = bpf_map_update_elem(intmapfd, &key0, &peer_index, BPF_ANY);
if (ret) {
SCLogError(SC_ERR_AFP_CREATE, "Create peer entry failed (err:%d)", ret);
return -1;
}
return 0;
}
int EBPFUpdateFlow(Flow *f, Packet *p)
{
BypassedIfaceList *ifl = (BypassedIfaceList *)FlowGetStorageById(f, g_flow_storage_id);
if (ifl == NULL) {
ifl = SCCalloc(1, sizeof(*ifl));
if (ifl == NULL) {
return 0;
}
ifl->dev = p->livedev;
FlowSetStorageById(f, g_flow_storage_id, ifl);
return 1;
}
/* Look for packet iface in the list */
BypassedIfaceList *ldev = ifl;
while (ldev) {
if (p->livedev == ldev->dev) {
return 1;
}
ldev = ldev->next;
}
/* Call bypass function if ever not in the list */
p->BypassPacketsFlow(p);
/* Add iface to the list */
BypassedIfaceList *nifl = SCCalloc(1, sizeof(*nifl));
if (nifl == NULL) {
return 0;
}
nifl->dev = p->livedev;
nifl->next = ifl;
FlowSetStorageById(f, g_flow_storage_id, nifl);
return 1;
}
#endif /* HAVE_PACKET_XDP */
#endif

@ -74,6 +74,10 @@ void EBPFRegisterExtension(void);
void EBPFBuildCPUSet(ConfNode *node, char *iface);
int EBPFSetPeerIface(const char *iface, const char *out_iface);
int EBPFUpdateFlow(Flow *f, Packet *p);
#endif
#endif

Loading…
Cancel
Save