2020-12-15 16:49:57 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/bpf.h> /* struct bpf_cpumap_val */
|
|
|
|
#include <bpf/bpf_helpers.h>
|
|
|
|
#include <bpf/compiler.h>
|
|
|
|
|
2020-12-16 21:09:28 +01:00
|
|
|
#define INITVAL 15485863
|
|
|
|
#include "hash_func01.h" /* SuperFastHash */
|
2020-12-15 16:49:57 +01:00
|
|
|
|
|
|
|
#include <bpf/bpf_helpers.h>
|
|
|
|
|
|
|
|
#define VLAN_MAX_DEPTH 2
|
|
|
|
#include <xdp/parsing_helpers.h>
|
|
|
|
|
|
|
|
#define MAX_CPUS 24
|
|
|
|
|
2020-12-16 16:40:15 +01:00
|
|
|
/* This global variable is used for limiting CPU that can be selected */
|
|
|
|
__u32 global_max_cpus = 12; /* TODO: Allow userspace to adjust this */
|
|
|
|
|
2020-12-15 16:49:57 +01:00
|
|
|
/* Special map type that can XDP_REDIRECT frames to another CPU */
|
|
|
|
struct {
|
|
|
|
__uint(type, BPF_MAP_TYPE_CPUMAP);
|
|
|
|
__uint(key_size, sizeof(__u32));
|
|
|
|
__uint(value_size, sizeof(struct bpf_cpumap_val));
|
|
|
|
__uint(max_entries, MAX_CPUS);
|
|
|
|
} cpumap SEC(".maps");
|
|
|
|
|
2020-12-16 16:40:15 +01:00
|
|
|
static __always_inline
|
2020-12-16 21:09:28 +01:00
|
|
|
__u32 extract_vlan_key(struct collect_vlans *vlans)
|
2020-12-16 16:40:15 +01:00
|
|
|
{
|
2020-12-16 21:09:28 +01:00
|
|
|
/* Combine inner and outer VLAN as a key */
|
|
|
|
__u32 vlan_key = (vlans->id[1] << 16) | vlans->id[0];
|
2020-12-16 16:40:15 +01:00
|
|
|
return vlan_key;
|
|
|
|
}
|
|
|
|
|
2020-12-15 16:49:57 +01:00
|
|
|
SEC("xdp")
|
|
|
|
int xdp_cpumap_qinq(struct xdp_md *ctx)
|
|
|
|
{
|
|
|
|
void *data = (void *)(long)ctx->data;
|
|
|
|
void *data_end = (void *)(long)ctx->data_end;
|
|
|
|
struct collect_vlans vlans = { 0 };
|
2020-12-16 21:09:28 +01:00
|
|
|
__u32 hash_key, vlan_key;
|
2020-12-15 16:49:57 +01:00
|
|
|
struct ethhdr *eth;
|
|
|
|
__u32 cpu_dest = 0;
|
|
|
|
__u64 action;
|
|
|
|
|
|
|
|
/* These keep track of the next header type and iterator pointer */
|
|
|
|
struct hdr_cursor nh;
|
|
|
|
int eth_type;
|
|
|
|
nh.pos = data;
|
|
|
|
|
|
|
|
eth_type = parse_ethhdr_vlan(&nh, data_end, ð, &vlans);
|
|
|
|
if (eth_type < 0) {
|
|
|
|
action = XDP_ABORTED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Keep ARP resolution working */
|
|
|
|
if (eth_type == bpf_htons(ETH_P_ARP)) {
|
|
|
|
action = XDP_PASS;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!proto_is_vlan(eth->h_proto)) {
|
|
|
|
/* Skip non-VLAN frames */
|
|
|
|
action = XDP_PASS;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-12-16 21:09:28 +01:00
|
|
|
/* Use inner+outer VLAN as key and hash based on max_cpus */
|
|
|
|
vlan_key = extract_vlan_key(&vlans);
|
|
|
|
hash_key = SuperFastHash((char *)&vlan_key, 4, INITVAL);
|
|
|
|
cpu_dest = hash_key % global_max_cpus;
|
2020-12-16 16:40:15 +01:00
|
|
|
|
|
|
|
/* Notice: Userspace MUST insert entries into cpumap */
|
2020-12-15 16:49:57 +01:00
|
|
|
action = bpf_redirect_map(&cpumap, cpu_dest, XDP_PASS);
|
|
|
|
out:
|
|
|
|
return action;
|
|
|
|
}
|