├── sample_3_1 ├── xdp_drop_common.h ├── Makefile ├── xdp_drop_user.c └── xdp_drop_kern.c ├── sample_3_2 ├── xdp_drop_common.h ├── Makefile ├── xdp_drop_kern.c └── xdp_drop_user.c ├── sample_1 ├── xdp_dummy.c └── Makefile ├── sample_4_1 ├── xdp_vxlan_common.h ├── Makefile ├── xdp_vxlan_user.c └── xdp_vxlan_kern.c ├── sample_2_2 ├── Makefile └── xdp_drop.c └── sample_2_1 ├── Makefile └── xdp_drop.c /sample_3_1/xdp_drop_common.h: -------------------------------------------------------------------------------- 1 | struct stats_entry { 2 | __u64 packets; 3 | __u64 bytes; 4 | }; 5 | -------------------------------------------------------------------------------- /sample_3_2/xdp_drop_common.h: -------------------------------------------------------------------------------- 1 | struct stats_entry { 2 | __u64 packets; 3 | __u64 bytes; 4 | }; 5 | -------------------------------------------------------------------------------- /sample_1/xdp_dummy.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | 3 | #define KBUILD_MODNAME "xdp_dummy" 4 | #include 5 | #include "bpf_helpers.h" 6 | 7 | SEC("prog") 8 | int xdp_dummy(struct xdp_md *ctx) 9 | { 10 | return XDP_PASS; 11 | } 12 | 13 | char _license[] SEC("license") = "GPL"; 14 | -------------------------------------------------------------------------------- /sample_4_1/xdp_vxlan_common.h: -------------------------------------------------------------------------------- 1 | struct vxlan_decap_key { 2 | __be32 addr; 3 | __be16 port; 4 | int id; 5 | }; 6 | 7 | struct vxlan_decap_entry { 8 | __u64 packets; 9 | __u64 bytes; 10 | int ifindex; 11 | }; 12 | 13 | struct vxlan_encap_entry { 14 | char hdrs[ETH_HLEN + 20 + 8 + 8]; 15 | int ifindex; 16 | __u64 packets; 17 | __u64 bytes; 18 | }; -------------------------------------------------------------------------------- /sample_4_1/Makefile: -------------------------------------------------------------------------------- 1 | CLANG ?= clang 2 | LLC ?= llc 3 | ARCH := $(subst x86_64,x86,$(shell arch)) 4 | 5 | BIN := xdp_vxlan_kern.o xdp_vxlan_user 6 | CLANG_FLAGS = -I. \ 7 | -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ 8 | -D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \ 9 | -Wno-gnu-variable-sized-type-not-at-end \ 10 | -Wno-address-of-packed-member -Wno-tautological-compare \ 11 | -Wno-unknown-warning-option \ 12 | -O2 -emit-llvm 13 | 14 | LDLIBS := -lelf -lbpf 15 | 16 | all: $(BIN) 17 | 18 | %_kern.o: %_kern.c 19 | $(CLANG) $(CLANG_FLAGS) -c $< -o - | \ 20 | $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ 21 | 22 | xdp_drop_user: xdp_drop_user.c 23 | 24 | clean:: 25 | $(RM) $(BIN) 26 | -------------------------------------------------------------------------------- /sample_1/Makefile: -------------------------------------------------------------------------------- 1 | KDIR ?= /lib/modules/$(shell uname -r)/source 2 | CLANG ?= clang 3 | LLC ?= llc 4 | ARCH := $(subst x86_64,x86,$(shell arch)) 5 | 6 | BIN := xdp_dummy.o 7 | CLANG_FLAGS = -I. -I$(KDIR)/arch/$(ARCH)/include \ 8 | -I$(KDIR)/arch/$(ARCH)/include/generated \ 9 | -I$(KDIR)/include \ 10 | -I$(KDIR)/arch/$(ARCH)/include/uapi \ 11 | -I$(KDIR)/arch/$(ARCH)/include/generated/uapi \ 12 | -I$(KDIR)/include/uapi \ 13 | -I$(KDIR)/include/generated/uapi \ 14 | -I$(KDIR)/tools/testing/selftests/bpf/ \ 15 | -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ 16 | -D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \ 17 | -Wno-gnu-variable-sized-type-not-at-end \ 18 | -Wno-address-of-packed-member -Wno-tautological-compare \ 19 | -Wno-unknown-warning-option \ 20 | -O2 -emit-llvm 21 | 22 | all: $(BIN) 23 | 24 | %.o: %.c 25 | $(CLANG) $(CLANG_FLAGS) -c $< -o - | \ 26 | $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ 27 | -------------------------------------------------------------------------------- /sample_2_2/Makefile: -------------------------------------------------------------------------------- 1 | KDIR ?= /lib/modules/$(shell uname -r)/source 2 | CLANG ?= clang 3 | LLC ?= llc 4 | ARCH := $(subst x86_64,x86,$(shell arch)) 5 | 6 | BIN := xdp_drop.o 7 | CLANG_FLAGS = -I. -I$(KDIR)/arch/$(ARCH)/include \ 8 | -I$(KDIR)/arch/$(ARCH)/include/generated \ 9 | -I$(KDIR)/include \ 10 | -I$(KDIR)/arch/x86/include/uapi \ 11 | -I$(KDIR)/arch/x86/include/generated/uapi \ 12 | -I$(KDIR)/include/uapi \ 13 | -I$(KDIR)/include/generated/uapi \ 14 | -include $(KDIR)/include/linux/kconfig.h \ 15 | -I$(KDIR)/tools/testing/selftests/bpf/ \ 16 | -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ 17 | -D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \ 18 | -Wno-gnu-variable-sized-type-not-at-end \ 19 | -Wno-address-of-packed-member -Wno-tautological-compare \ 20 | -Wno-unknown-warning-option \ 21 | -O2 -emit-llvm 22 | 23 | all: $(BIN) 24 | 25 | %.o: %.c 26 | $(CLANG) $(CLANG_FLAGS) -c $< -o - | \ 27 | $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ 28 | -------------------------------------------------------------------------------- /sample_2_1/Makefile: -------------------------------------------------------------------------------- 1 | KDIR ?= /lib/modules/$(shell uname -r)/source 2 | CLANG ?= clang 3 | LLC ?= llc 4 | ARCH := $(subst x86_64,x86,$(shell arch)) 5 | 6 | BIN := xdp_drop.o 7 | CLANG_FLAGS = -I. -I$(KDIR)/arch/$(ARCH)/include \ 8 | -I$(KDIR)/arch/$(ARCH)/include/generated \ 9 | -I$(KDIR)/include \ 10 | -I$(KDIR)/arch/$(ARCH)/include/uapi \ 11 | -I$(KDIR)/arch/$(ARCH)/include/generated/uapi \ 12 | -I$(KDIR)/include/uapi \ 13 | -I$(KDIR)/include/generated/uapi \ 14 | -include $(KDIR)/include/linux/kconfig.h \ 15 | -I$(KDIR)/tools/testing/selftests/bpf/ \ 16 | -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ 17 | -D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \ 18 | -Wno-gnu-variable-sized-type-not-at-end \ 19 | -Wno-address-of-packed-member -Wno-tautological-compare \ 20 | -Wno-unknown-warning-option \ 21 | -O2 -emit-llvm 22 | 23 | all: $(BIN) 24 | 25 | %.o: %.c 26 | $(CLANG) $(CLANG_FLAGS) -c $< -o - | \ 27 | $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ 28 | -------------------------------------------------------------------------------- /sample_3_1/Makefile: -------------------------------------------------------------------------------- 1 | KDIR ?= /lib/modules/$(shell uname -r)/source 2 | CLANG ?= clang 3 | LLC ?= llc 4 | ARCH := $(subst x86_64,x86,$(shell arch)) 5 | 6 | BIN := xdp_drop_kern.o xdp_drop_user 7 | CLANG_FLAGS = -I. -I$(KDIR)/arch/$(ARCH)/include \ 8 | -I$(KDIR)/arch/$(ARCH)/include/generated \ 9 | -I$(KDIR)/include \ 10 | -I$(KDIR)/arch/x86/include/uapi \ 11 | -I$(KDIR)/arch/x86/include/generated/uapi \ 12 | -I$(KDIR)/include/uapi \ 13 | -I$(KDIR)/include/generated/uapi \ 14 | -include $(KDIR)/include/linux/kconfig.h \ 15 | -I$(KDIR)/tools/testing/selftests/bpf/ \ 16 | -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ 17 | -D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \ 18 | -Wno-gnu-variable-sized-type-not-at-end \ 19 | -Wno-address-of-packed-member -Wno-tautological-compare \ 20 | -Wno-unknown-warning-option \ 21 | -O2 -emit-llvm 22 | 23 | CFLAGS = -I$(KDIR)/tools/lib/ -O2 24 | BPFDIR := $(KDIR)/tools/lib/bpf/ 25 | BPFOBJ := $(BPFDIR)/libbpf.a 26 | LDLIBS := -lelf 27 | 28 | all: $(BIN) 29 | 30 | %_kern.o: %_kern.c 31 | $(CLANG) $(CLANG_FLAGS) -c $< -o - | \ 32 | $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ 33 | 34 | xdp_drop_user: xdp_drop_user.c $(BPFOBJ) 35 | 36 | $(BPFOBJ):: 37 | $(MAKE) -C $(BPFDIR) OUTPUT=$(BPFDIR)/ 38 | 39 | clean:: 40 | $(RM) $(BIN) 41 | -------------------------------------------------------------------------------- /sample_3_2/Makefile: -------------------------------------------------------------------------------- 1 | KDIR ?= /lib/modules/$(shell uname -r)/source 2 | CLANG ?= clang 3 | LLC ?= llc 4 | ARCH := $(subst x86_64,x86,$(shell arch)) 5 | 6 | BIN := xdp_drop_kern.o xdp_drop_user 7 | CLANG_FLAGS = -I. -I$(KDIR)/arch/$(ARCH)/include \ 8 | -I$(KDIR)/arch/$(ARCH)/include/generated \ 9 | -I$(KDIR)/include \ 10 | -I$(KDIR)/arch/x86/include/uapi \ 11 | -I$(KDIR)/arch/x86/include/generated/uapi \ 12 | -I$(KDIR)/include/uapi \ 13 | -I$(KDIR)/include/generated/uapi \ 14 | -include $(KDIR)/include/linux/kconfig.h \ 15 | -I$(KDIR)/tools/testing/selftests/bpf/ \ 16 | -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ 17 | -D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \ 18 | -Wno-gnu-variable-sized-type-not-at-end \ 19 | -Wno-address-of-packed-member -Wno-tautological-compare \ 20 | -Wno-unknown-warning-option \ 21 | -O2 -emit-llvm 22 | 23 | CFLAGS = -I$(KDIR)/tools/lib/ -O2 24 | BPFDIR := $(KDIR)/tools/lib/bpf/ 25 | BPFOBJ := $(BPFDIR)/libbpf.a 26 | LDLIBS := -lelf 27 | 28 | all: $(BIN) 29 | 30 | %_kern.o: %_kern.c 31 | $(CLANG) $(CLANG_FLAGS) -c $< -o - | \ 32 | $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ 33 | 34 | xdp_drop_user: xdp_drop_user.c $(BPFOBJ) 35 | 36 | $(BPFOBJ):: 37 | $(MAKE) -C $(BPFDIR) OUTPUT=$(BPFDIR)/ 38 | 39 | clean:: 40 | $(RM) $(BIN) 41 | -------------------------------------------------------------------------------- /sample_2_1/xdp_drop.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | 3 | #define KBUILD_MODNAME "xdp_drop" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "bpf_helpers.h" 12 | 13 | 14 | /* Parse IPV4 packet to get SRC, DST IP and protocol */ 15 | static inline int parse_ipv4(void *data, __u64 nh_off, void *data_end, 16 | __be32 *src, __be32 *dest) 17 | { 18 | struct iphdr *iph = data + nh_off; 19 | 20 | *src = iph->saddr; 21 | *dest = iph->daddr; 22 | return iph->protocol; 23 | } 24 | 25 | SEC("prog") 26 | int xdp_drop(struct xdp_md *ctx) 27 | { 28 | void *data_end = (void *)(long)ctx->data_end; 29 | void *data = (void *)(long)ctx->data; 30 | struct ethhdr *eth = data; 31 | __be32 dest_ip, src_ip; 32 | __u16 h_proto; 33 | __u64 nh_off; 34 | int ipproto; 35 | 36 | nh_off = sizeof(*eth); 37 | 38 | /* parse vlan */ 39 | h_proto = eth->h_proto; 40 | if (h_proto == __constant_htons(ETH_P_8021Q) || 41 | h_proto == __constant_htons(ETH_P_8021AD)) { 42 | struct vlan_hdr *vhdr; 43 | 44 | vhdr = data + nh_off; 45 | nh_off += sizeof(struct vlan_hdr); 46 | h_proto = vhdr->h_vlan_encapsulated_proto; 47 | } 48 | if (h_proto != __constant_htons(ETH_P_IP)) 49 | goto pass; 50 | 51 | ipproto = parse_ipv4(data, nh_off, data_end, &src_ip, &dest_ip); 52 | if (src_ip & 1) 53 | return XDP_DROP; 54 | 55 | pass: 56 | return XDP_PASS; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /sample_2_2/xdp_drop.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | 3 | #define KBUILD_MODNAME "xdp_drop" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "bpf_helpers.h" 12 | 13 | 14 | /* Parse IPV4 packet to get SRC, DST IP and protocol */ 15 | static inline int parse_ipv4(void *data, __u64 nh_off, void *data_end, 16 | __be32 *src, __be32 *dest) 17 | { 18 | struct iphdr *iph = data + nh_off; 19 | 20 | if (iph + 1 > data_end) 21 | return 0; 22 | 23 | *src = iph->saddr; 24 | *dest = iph->daddr; 25 | return iph->protocol; 26 | } 27 | 28 | SEC("prog") 29 | int xdp_drop(struct xdp_md *ctx) 30 | { 31 | void *data_end = (void *)(long)ctx->data_end; 32 | void *data = (void *)(long)ctx->data; 33 | struct ethhdr *eth = data; 34 | __be32 dest_ip, src_ip; 35 | __u16 h_proto; 36 | __u64 nh_off; 37 | int ipproto; 38 | int i; 39 | 40 | nh_off = sizeof(*eth); 41 | if (data + nh_off > data_end) 42 | goto pass; 43 | 44 | /* parse vlan */ 45 | h_proto = eth->h_proto; 46 | if (h_proto == __constant_htons(ETH_P_8021Q) || 47 | h_proto == __constant_htons(ETH_P_8021AD)) { 48 | struct vlan_hdr *vhdr; 49 | 50 | vhdr = data + nh_off; 51 | nh_off += sizeof(struct vlan_hdr); 52 | if (data + nh_off > data_end) 53 | goto pass; 54 | h_proto = vhdr->h_vlan_encapsulated_proto; 55 | } 56 | if (h_proto != __constant_htons(ETH_P_IP)) 57 | goto pass; 58 | 59 | for (i=0; i < eth->h_proto; i++) { 60 | char *cur; 61 | if (data + i > data_end) 62 | goto pass; 63 | cur = data + 1; 64 | if (*cur) 65 | goto pass; 66 | } 67 | 68 | ipproto = parse_ipv4(data, nh_off, data_end, &src_ip, &dest_ip); 69 | if (src_ip & 1) 70 | return XDP_DROP; 71 | 72 | pass: 73 | return XDP_PASS; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /sample_3_1/xdp_drop_user.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "xdp_drop_common.h" 13 | 14 | #define MAX_ADDR 2 15 | 16 | static bool interrupted; 17 | 18 | static void sigint_handler(int signum) 19 | { 20 | printf("interrupted\n"); 21 | interrupted = true; 22 | } 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | struct bpf_prog_load_attr prog_load_attr = { 27 | .prog_type = BPF_PROG_TYPE_XDP, 28 | .file = "xdp_drop_kern.o", 29 | }; 30 | struct stats_entry entry; 31 | char *dev_name = argv[1]; 32 | struct bpf_object *obj; 33 | __be32 saddr[MAX_ADDR]; 34 | int prog_fd, map_fd; 35 | struct bpf_map *map; 36 | int saddr_nr = 0; 37 | int ifindex; 38 | int i; 39 | 40 | if (argc < 2) 41 | error(1, 0, "syntax:%s [..]"); 42 | 43 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) 44 | error(1, errno, "can't load file %s", prog_load_attr.file); 45 | 46 | ifindex = if_nametoindex(dev_name); 47 | if (!ifindex) 48 | error(1, errno, "unknown interface %s\n", dev_name); 49 | if (bpf_set_link_xdp_fd(ifindex, prog_fd, 0) < 0) 50 | error(1, errno, "can't attach xdp program to interface %s:%d: " 51 | "%d:%s\n", dev_name, ifindex, errno, strerror(errno)); 52 | 53 | map = bpf_object__find_map_by_name(obj, "drop_map"); 54 | if (!map) 55 | error(1, errno, "can't load drop_map"); 56 | map_fd = bpf_map__fd(map); 57 | if (map_fd < 0) 58 | error(1, errno, "can't get drop_map fd"); 59 | 60 | 61 | for (i = 2; i < argc && saddr_nr < MAX_ADDR; ++i) { 62 | __be32 ipv4_addr; 63 | if (inet_pton(AF_INET, argv[i], &ipv4_addr) != 1) 64 | error(1, errno, "invalid address %s\n", argv[i]); 65 | 66 | memset(&entry, 0, sizeof(entry)); 67 | if (bpf_map_update_elem(map_fd, &ipv4_addr, &entry, BPF_ANY)) 68 | error(1, errno, "can't add address %x\n", ipv4_addr); 69 | saddr[saddr_nr] = ipv4_addr; 70 | saddr_nr++; 71 | } 72 | 73 | signal(SIGINT, sigint_handler); 74 | signal(SIGPIPE, sigint_handler); 75 | 76 | while (!interrupted) { 77 | sleep(1); 78 | 79 | for (i = 0; i < saddr_nr; ++i) { 80 | __be32 ipv4_addr = saddr[i]; 81 | if (bpf_map_lookup_elem(map_fd, &ipv4_addr, &entry)) 82 | error(1, errno, "no stats for address %x\n", 83 | ipv4_addr); 84 | printf("addr %x drop %lld:%lld\n", ipv4_addr, 85 | entry.packets, entry.bytes); 86 | } 87 | } 88 | 89 | bpf_set_link_xdp_fd(ifindex, -1, 0); 90 | return 0; 91 | } -------------------------------------------------------------------------------- /sample_3_1/xdp_drop_kern.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | 3 | #define KBUILD_MODNAME "xdp_drop" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "bpf_helpers.h" 12 | #include "xdp_drop_common.h" 13 | 14 | /* forwarding map */ 15 | struct bpf_map_def SEC("maps") drop_map = { 16 | .type = BPF_MAP_TYPE_PERCPU_HASH, 17 | .key_size = sizeof(__be32), 18 | .value_size = sizeof(struct stats_entry), 19 | .max_entries = 100, 20 | }; 21 | 22 | /* Parse IPV4 packet to get SRC, DST IP and protocol */ 23 | static inline int parse_ipv4(void *data, __u64 nh_off, void *data_end, 24 | __be32 *src, __be32 *dest) 25 | { 26 | struct iphdr *iph = data + nh_off; 27 | 28 | if (iph + 1 > data_end) 29 | return 0; 30 | 31 | *src = iph->saddr; 32 | *dest = iph->daddr; 33 | return iph->protocol; 34 | } 35 | 36 | #define bpf_printk(fmt, ...) \ 37 | ({ \ 38 | char ____fmt[] = fmt; \ 39 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 40 | ##__VA_ARGS__); \ 41 | }) 42 | 43 | SEC("prog") 44 | int xdp_drop(struct xdp_md *ctx) 45 | { 46 | void *data_end = (void *)(long)ctx->data_end; 47 | void *data = (void *)(long)ctx->data; 48 | struct ethhdr *eth = data; 49 | struct stats_entry *stats; 50 | __be32 dest_ip, src_ip; 51 | __u16 h_proto; 52 | __u64 nh_off; 53 | int ipproto; 54 | 55 | bpf_printk("xdp_drop\n"); 56 | 57 | nh_off = sizeof(*eth); 58 | if (data + nh_off > data_end) 59 | goto pass; 60 | 61 | /* parse vlan */ 62 | h_proto = eth->h_proto; 63 | if (h_proto == __constant_htons(ETH_P_8021Q) || 64 | h_proto == __constant_htons(ETH_P_8021AD)) { 65 | struct vlan_hdr *vhdr; 66 | 67 | vhdr = data + nh_off; 68 | nh_off += sizeof(struct vlan_hdr); 69 | if (data + nh_off > data_end) 70 | goto pass; 71 | h_proto = vhdr->h_vlan_encapsulated_proto; 72 | } 73 | if (h_proto != __constant_htons(ETH_P_IP)) 74 | goto pass; 75 | 76 | ipproto = parse_ipv4(data, nh_off, data_end, &src_ip, &dest_ip); 77 | if (!ipproto) 78 | goto pass; 79 | 80 | stats = bpf_map_lookup_elem(&drop_map, &src_ip); 81 | if (!stats) 82 | goto pass; 83 | 84 | bpf_printk("xdp_drop pkts %lld:%lld\n", stats->packets, stats->bytes); 85 | 86 | stats->packets++; 87 | stats->bytes += ctx->data_end - ctx->data; 88 | return XDP_DROP; 89 | 90 | pass: 91 | return XDP_PASS; 92 | } 93 | 94 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /sample_3_2/xdp_drop_kern.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | 3 | #define KBUILD_MODNAME "xdp_drop" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "bpf_helpers.h" 12 | #include "xdp_drop_common.h" 13 | 14 | /* forwarding map */ 15 | struct bpf_map_def SEC("maps") drop_map = { 16 | .type = BPF_MAP_TYPE_PERCPU_HASH, 17 | .key_size = sizeof(__be32), 18 | .value_size = sizeof(struct stats_entry), 19 | .max_entries = 100, 20 | }; 21 | 22 | /* Parse IPV4 packet to get SRC, DST IP and protocol */ 23 | static inline int parse_ipv4(void *data, __u64 nh_off, void *data_end, 24 | __be32 *src, __be32 *dest) 25 | { 26 | struct iphdr *iph = data + nh_off; 27 | 28 | if (iph + 1 > data_end) 29 | return 0; 30 | 31 | *src = iph->saddr; 32 | *dest = iph->daddr; 33 | return iph->protocol; 34 | } 35 | 36 | #define bpf_printk(fmt, ...) \ 37 | ({ \ 38 | char ____fmt[] = fmt; \ 39 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 40 | ##__VA_ARGS__); \ 41 | }) 42 | 43 | SEC("prog") 44 | int xdp_drop(struct xdp_md *ctx) 45 | { 46 | void *data_end = (void *)(long)ctx->data_end; 47 | void *data = (void *)(long)ctx->data; 48 | struct ethhdr *eth = data; 49 | struct stats_entry *stats; 50 | __be32 dest_ip, src_ip; 51 | __u16 h_proto; 52 | __u64 nh_off; 53 | int ipproto; 54 | 55 | bpf_printk("xdp_drop\n"); 56 | 57 | nh_off = sizeof(*eth); 58 | if (data + nh_off > data_end) 59 | goto pass; 60 | 61 | /* parse vlan */ 62 | h_proto = eth->h_proto; 63 | if (h_proto == __constant_htons(ETH_P_8021Q) || 64 | h_proto == __constant_htons(ETH_P_8021AD)) { 65 | struct vlan_hdr *vhdr; 66 | 67 | vhdr = data + nh_off; 68 | nh_off += sizeof(struct vlan_hdr); 69 | if (data + nh_off > data_end) 70 | goto pass; 71 | h_proto = vhdr->h_vlan_encapsulated_proto; 72 | } 73 | if (h_proto != __constant_htons(ETH_P_IP)) 74 | goto pass; 75 | 76 | ipproto = parse_ipv4(data, nh_off, data_end, &src_ip, &dest_ip); 77 | if (!ipproto) 78 | goto pass; 79 | 80 | stats = bpf_map_lookup_elem(&drop_map, &src_ip); 81 | if (!stats) 82 | goto pass; 83 | 84 | bpf_printk("xdp_drop pkts %lld:%lld\n", stats->packets, stats->bytes); 85 | 86 | stats->packets++; 87 | stats->bytes += ctx->data_end - ctx->data; 88 | return XDP_DROP; 89 | 90 | pass: 91 | return XDP_PASS; 92 | } 93 | 94 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /sample_3_2/xdp_drop_user.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "xdp_drop_common.h" 14 | 15 | #define MAX_ADDR 2 16 | 17 | static bool interrupted; 18 | 19 | static void sigint_handler(int signum) 20 | { 21 | printf("interrupted\n"); 22 | interrupted = true; 23 | } 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | struct bpf_prog_load_attr prog_load_attr = { 28 | .prog_type = BPF_PROG_TYPE_XDP, 29 | .file = "xdp_drop_kern.o", 30 | }; 31 | int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 32 | struct stats_entry *entry; 33 | char *dev_name = argv[1]; 34 | struct bpf_object *obj; 35 | __be32 saddr[MAX_ADDR]; 36 | int prog_fd, map_fd; 37 | struct bpf_map *map; 38 | int saddr_nr = 0; 39 | int ifindex; 40 | int i, j; 41 | 42 | if (argc < 2) 43 | error(1, 0, "syntax:%s [..]"); 44 | 45 | entry = calloc(nr_cpus, sizeof(struct stats_entry)); 46 | if (!entry) 47 | error(1, 0, "can't allocate entry\n"); 48 | 49 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) 50 | error(1, errno, "can't load file %s", prog_load_attr.file); 51 | 52 | ifindex = if_nametoindex(dev_name); 53 | if (!ifindex) 54 | error(1, errno, "unknown interface %s\n", dev_name); 55 | if (bpf_set_link_xdp_fd(ifindex, prog_fd, 0) < 0) 56 | error(1, errno, "can't attach xdp program to interface %s:%d: " 57 | "%d:%s\n", dev_name, ifindex, errno, strerror(errno)); 58 | 59 | map = bpf_object__find_map_by_name(obj, "drop_map"); 60 | if (!map) 61 | error(1, errno, "can't load drop_map"); 62 | map_fd = bpf_map__fd(map); 63 | if (map_fd < 0) 64 | error(1, errno, "can't get drop_map fd"); 65 | 66 | for (i = 2; i < argc && saddr_nr < MAX_ADDR; ++i) { 67 | __be32 ipv4_addr; 68 | if (inet_pton(AF_INET, argv[i], &ipv4_addr) != 1) 69 | error(1, errno, "invalid address %s\n", argv[i]); 70 | 71 | if (bpf_map_update_elem(map_fd, &ipv4_addr, entry, BPF_ANY)) 72 | error(1, errno, "can't add address %x\n", ipv4_addr); 73 | saddr[saddr_nr] = ipv4_addr; 74 | saddr_nr++; 75 | } 76 | 77 | signal(SIGINT, sigint_handler); 78 | signal(SIGPIPE, sigint_handler); 79 | 80 | while (!interrupted) { 81 | sleep(1); 82 | 83 | for (i = 0; i < saddr_nr; ++i) { 84 | struct stats_entry all = { 0, 0}; 85 | __be32 ipv4_addr = saddr[i]; 86 | 87 | if (bpf_map_lookup_elem(map_fd, &ipv4_addr, entry)) 88 | error(1, errno, "no stats for address %x\n", 89 | ipv4_addr); 90 | 91 | for (j = 0; j < nr_cpus; j++) { 92 | all.packets += entry[j].packets; 93 | all.bytes += entry[j].bytes; 94 | } 95 | 96 | printf("addr %x drop %lld:%lld\n", ipv4_addr, 97 | all.packets, all.bytes); 98 | } 99 | } 100 | 101 | bpf_set_link_xdp_fd(ifindex, -1, 0); 102 | return 0; 103 | } -------------------------------------------------------------------------------- /sample_4_1/xdp_vxlan_user.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "xdp_vxlan_common.h" 15 | 16 | #define MAX_TUNNELS 2 17 | 18 | static bool interrupted; 19 | 20 | static void sigint_handler(int signum) 21 | { 22 | printf("interrupted\n"); 23 | interrupted = true; 24 | } 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | struct bpf_prog_load_attr prog_load_attr = { 29 | .prog_type = BPF_PROG_TYPE_XDP, 30 | .file = "xdp_drop_kern.o", 31 | }; 32 | struct vxlan_decap_key decap_key[MAX_TUNNELS]; 33 | int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 34 | struct vxlan_decap_entry *decap_entry; 35 | int decap_ifindex[MAX_TUNNELS]; 36 | struct bpf_object *obj; 37 | int prog_fd, map_fd; 38 | struct bpf_map *map; 39 | int tunnel_nr = 0; 40 | int ifindex; 41 | int i, j; 42 | 43 | if (argc < 2) 44 | error(1, 0, "syntax:%s "); 45 | 46 | decap_entry = calloc(nr_cpus, sizeof(struct vxlan_decap_entry)); 47 | if (!decap_entry) 48 | error(1, 0, "can't allocate entry\n"); 49 | 50 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) 51 | error(1, errno, "can't load file %s", prog_load_attr.file); 52 | 53 | for (i = 1; i < argc - 5 && tunnel_nr < MAX_TUNNELS; ++i) { 54 | struct vxlan_decap_key *key = &decap_key[tunnel_nr]; 55 | 56 | decap_ifindex[tunnel_nr] = if_nametoindex(argv[i]); 57 | if (!ifindex) 58 | error(1, errno, "unknown interface %s\n", argv[i]); 59 | if (bpf_set_link_xdp_fd(ifindex, prog_fd, 0) < 0) 60 | error(1, errno, "can't attach xdp program to interface %s:%d: " 61 | "%d:%s\n", argv[i], ifindex, errno, strerror(errno)); 62 | 63 | map = bpf_object__find_map_by_name(obj, "vxlan_decaps"); 64 | if (!map) 65 | error(1, errno, "can't load drop_map"); 66 | map_fd = bpf_map__fd(map); 67 | if (map_fd < 0) 68 | error(1, errno, "can't get drop_map fd"); 69 | 70 | ++i; 71 | decap_entry[0].ifindex = if_nametoindex(argv[i]); 72 | if (!decap_entry[0].ifindex) 73 | error(1, errno, "unknown interface %s\n", argv[i]); 74 | for (j = 1; j < nr_cpus; ++j) 75 | decap_entry[j].ifindex = decap_entry[0].ifindex; 76 | 77 | ++i; 78 | if (inet_pton(AF_INET, argv[i], &key->addr) != 1) 79 | error(1, errno, "invalid address %s\n", argv[i]); 80 | ++i; 81 | key->port = htons(atoi(argv[i])); 82 | ++i; 83 | key->id = atoi(argv[i]); 84 | 85 | /* likely broken: we need to attach a bpf on 86 | * decap_entry[0].ifindex to allow redirect working on such 87 | * device 88 | */ 89 | if (bpf_map_update_elem(map_fd, key, decap_entry, BPF_ANY)) 90 | error(1, errno, "can't add decap %x:%d:%d\n", key->addr, 91 | key->port, key->id); 92 | tunnel_nr++; 93 | } 94 | 95 | signal(SIGINT, sigint_handler); 96 | signal(SIGPIPE, sigint_handler); 97 | 98 | while (!interrupted) { 99 | sleep(1); 100 | 101 | for (i = 0; i < tunnel_nr; ++i) { 102 | struct vxlan_decap_key *key = &decap_key[i]; 103 | struct vxlan_decap_entry all = { 0, 0, 0}; 104 | 105 | if (bpf_map_lookup_elem(map_fd, key, decap_entry)) 106 | error(1, errno, "no stats for tunnel %x:%d:%d\n", 107 | key->addr, key->port, key->id); 108 | 109 | for (j = 0; j < nr_cpus; j++) { 110 | all.packets += decap_entry[j].packets; 111 | all.bytes += decap_entry[j].bytes; 112 | } 113 | 114 | printf("tunnel %x:%d:%d drop %lld:%lld\n", key->addr, 115 | key->port, key->id, all.packets, all.bytes); 116 | } 117 | } 118 | 119 | for (i = 0; i < tunnel_nr; ++i) 120 | bpf_set_link_xdp_fd(decap_ifindex[i], -1, 0); 121 | return 0; 122 | } -------------------------------------------------------------------------------- /sample_4_1/xdp_vxlan_kern.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | 3 | #define KBUILD_MODNAME "xdp_drop" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include "xdp_vxlan_common.h" 14 | 15 | struct vxlanhdr { 16 | __be32 vx_flags; 17 | __be32 vx_vni; 18 | }; 19 | 20 | struct bpf_map_def SEC("maps") vxlan_decaps = { 21 | .type = BPF_MAP_TYPE_PERCPU_HASH, 22 | .key_size = sizeof(struct vxlan_decap_key), 23 | .value_size = sizeof(struct vxlan_decap_entry), 24 | .max_entries = 16, 25 | }; 26 | 27 | struct bpf_map_def SEC("maps") vxlan_encaps = { 28 | .type = BPF_MAP_TYPE_PERCPU_HASH, 29 | .key_size = sizeof(int), 30 | .value_size = sizeof(struct vxlan_encap_entry), 31 | .max_entries = 16, 32 | }; 33 | 34 | /* Parse IPV4 packet to get SRC, DST IP and protocol */ 35 | static inline int parse_ipv4(void *data, __u64 *nh_off, void *data_end, 36 | __be32 *src, __be32 *dest) 37 | { 38 | struct iphdr *iph = data + *nh_off; 39 | 40 | if (iph + 1 > data_end) 41 | return 0; 42 | 43 | *nh_off += iph->ihl << 2; 44 | 45 | *src = iph->saddr; 46 | *dest = iph->daddr; 47 | return iph->protocol; 48 | } 49 | 50 | /* Parse UDP packet to get source port, destination port and UDP header size */ 51 | static inline int parse_udp(void *data, __u64 th_off, void *data_end, 52 | __be16 *src_port, __be16 *dest_port) 53 | { 54 | struct udphdr *uh = data + th_off; 55 | 56 | if (uh + 1 > data_end) 57 | return 0; 58 | 59 | /* keep life easy and require 0-checksum */ 60 | if (uh->check) 61 | return 0; 62 | 63 | *src_port = uh->source; 64 | *dest_port = uh->dest; 65 | return __constant_ntohs(uh->len); 66 | } 67 | 68 | static inline int parse_vxlan(void *data, __u64 offset, void *data_end) 69 | { 70 | struct vxlanhdr *vxlanh = data + offset; 71 | 72 | if (vxlanh + 1 > data_end) 73 | return 0; 74 | 75 | if (vxlanh->vx_flags) 76 | return 0; 77 | 78 | return __constant_ntohl(vxlanh->vx_vni); 79 | } 80 | 81 | 82 | #define bpf_printk(fmt, ...) \ 83 | ({ \ 84 | char ____fmt[] = fmt; \ 85 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 86 | ##__VA_ARGS__); \ 87 | }) 88 | 89 | SEC("prog") 90 | int xdp_drop(struct xdp_md *ctx) 91 | { 92 | void *data_end = (void *)(long)ctx->data_end; 93 | void *data = (void *)(long)ctx->data; 94 | struct vxlan_decap_entry *decap_entry; 95 | struct vxlan_decap_key decap_key; 96 | struct ethhdr *eth = data; 97 | struct stats_entry *stats; 98 | __u16 h_proto; 99 | __be32 src_ip; 100 | __be16 src_p; 101 | __u64 offset; 102 | unsigned len; 103 | int ipproto; 104 | 105 | bpf_printk("xdp_drop\n"); 106 | 107 | offset = sizeof(*eth); 108 | if (data + offset > data_end) 109 | goto pass; 110 | 111 | /* parse vlan */ 112 | h_proto = eth->h_proto; 113 | if (h_proto == __constant_htons(ETH_P_8021Q) || 114 | h_proto == __constant_htons(ETH_P_8021AD)) { 115 | struct vlan_hdr *vhdr; 116 | 117 | vhdr = data + offset; 118 | offset += sizeof(struct vlan_hdr); 119 | if (data + offset > data_end) 120 | goto pass; 121 | 122 | h_proto = vhdr->h_vlan_encapsulated_proto; 123 | } 124 | if (h_proto != __constant_htons(ETH_P_IP)) 125 | goto pass; 126 | 127 | ipproto = parse_ipv4(data, &offset, data_end, &src_ip, &decap_key.addr); 128 | if (ipproto != IPPROTO_UDP) 129 | goto pass; 130 | 131 | len = parse_udp(data, offset, data_end, &src_p, &decap_key.port); 132 | if (len < sizeof(struct vxlanhdr)) 133 | goto pass; 134 | if (len > data_end - data - offset) 135 | goto pass; 136 | 137 | offset += sizeof(struct udphdr); 138 | decap_key.id = parse_vxlan(data, offset, data_end); 139 | if (!decap_key.id) 140 | goto pass; 141 | 142 | decap_entry = bpf_map_lookup_elem(&vxlan_decaps, &decap_key); 143 | if (!decap_entry) 144 | goto pass; 145 | 146 | offset += sizeof(struct vxlanhdr); 147 | bpf_printk("xdp decap pkts %lld:%lld\n", decap_entry->packets, decap_entry->bytes); 148 | 149 | /* broken: no bytes are pulled from the packet */ 150 | ctx->data += offset; 151 | decap_entry->packets++; 152 | decap_entry->bytes += ctx->data_end - ctx->data; 153 | 154 | /* sub-optimal performance wise */ 155 | return bpf_redirect(decap_entry->ifindex, 0); 156 | 157 | pass: 158 | return XDP_PASS; 159 | } 160 | 161 | char _license[] SEC("license") = "GPL"; --------------------------------------------------------------------------------