.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)
{
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;
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) {
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;
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;
aconf->flags |= AFP_BYPASS;
RunModeEnablesBypassManager();
BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
+ BypassedFlowManagerRegisterUpdateFunc(EBPFUpdateFlow);
#else
SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in");
#endif
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");
#include "util-device.h"
#include "device-storage.h"
+#include "flow-storage.h"
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#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;
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;
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);
void EBPFRegisterExtension(void)
{
g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree);
+ g_flow_storage_id = FlowStorageRegister("bypassedlist", sizeof(void *), NULL, BypassedListFree);
}
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