Created
January 19, 2019 13:07
-
-
Save higebu/d3f61b01545c62a2a0a043f5c8416850 to your computer and use it in GitHub Desktop.
Simple XDP example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
LLVM_PREFIX ?= /usr/bin | |
CLANG ?= $(LLVM_PREFIX)/clang | |
LLC ?= $(LLVM_PREFIX)/llc | |
INCLUDEFLAGS = -I/usr/include | |
all: xdp_prog.elf | |
clean: | |
-$(RM) *.elf | |
%.elf : %.o | |
$(LLC) -march=bpf -filetype=obj -o $@ $< | |
%.o : %.c | |
$(CLANG) $(INCLUDEFLAGS) -target bpf -O2 -emit-llvm -g \ | |
-Wall -Werror \ | |
-Wno-unused-variable \ | |
-Wno-compare-distinct-pointer-types \ | |
-Wno-implicit-function-declaration \ | |
-c $< -o $@ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/bpf.h> | |
#include <linux/in.h> | |
#include <linux/if_ether.h> | |
#include <linux/ip.h> | |
#include <linux/ipv6.h> | |
typedef unsigned short u16; | |
typedef unsigned int u32; | |
typedef unsigned long u64; | |
#define BPF_FUNC_map_lookup_elem 1 | |
static void *(*bpf_map_lookup_elem)(void *map, void *key) = | |
(void *) BPF_FUNC_map_lookup_elem; | |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | |
# define __bpf_htons(x) __builtin_bswap16(x) | |
# define __bpf_constant_htons(x) ___constant_swab16(x) | |
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |
# define __bpf_htons(x) (x) | |
# define __bpf_constant_htons(x) (x) | |
#else | |
# error "Fix your compiler's __BYTE_ORDER__?!" | |
#endif | |
# define bpf_htons(x) \ | |
(__builtin_constant_p(x) ? \ | |
__bpf_constant_htons(x) : __bpf_htons(x)) | |
struct bpf_map_def { | |
u32 type; | |
u32 key_size; | |
u32 value_size; | |
u32 max_entries; | |
u32 flags; | |
u32 inner_map_idx; | |
}; | |
#define SEC(NAME) __attribute__((section(NAME), used)) | |
struct bpf_map_def SEC("maps") rxcnt = { | |
.type = BPF_MAP_TYPE_ARRAY, | |
.key_size = sizeof(u32), | |
.value_size = sizeof(long), | |
.max_entries = 256, | |
}; | |
static int parse_ipv4(void *data, u64 nh_off, void *data_end) | |
{ | |
struct iphdr *iph = data + nh_off; | |
if (iph + 1 > data_end) | |
return 0; | |
return iph->protocol; | |
} | |
static int parse_ipv6(void *data, u64 nh_off, void *data_end) | |
{ | |
struct ipv6hdr *ip6h = data + nh_off; | |
if (ip6h + 1 > data_end) | |
return 0; | |
return ip6h->nexthdr; | |
} | |
SEC("xdp") | |
int xdp_prog(struct xdp_md *ctx) | |
{ | |
void *data_end = (void *)(long)ctx->data_end; | |
void *data = (void *)(long)ctx->data; | |
struct ethhdr *eth = data; | |
long *value; | |
u16 h_proto; | |
u64 nh_off; | |
u32 ipproto; | |
nh_off = sizeof(*eth); | |
if (data + nh_off > data_end) | |
return XDP_DROP; | |
h_proto = eth->h_proto; | |
if (h_proto == bpf_htons(ETH_P_IP)) | |
ipproto = parse_ipv4(data, nh_off, data_end); | |
else if (h_proto == bpf_htons(ETH_P_IPV6)) | |
ipproto = parse_ipv6(data, nh_off, data_end); | |
else | |
ipproto = 0; | |
value = bpf_map_lookup_elem(&rxcnt, &ipproto); | |
if (value) | |
*value += 1; | |
return XDP_PASS; | |
} | |
char _license[] SEC("license") = "MIT"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment