diff --git a/advanced02-BTF/Makefile b/advanced02-BTF/Makefile new file mode 100644 index 00000000..9fea1961 --- /dev/null +++ b/advanced02-BTF/Makefile @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) + +XDP_BTF_TARGETS := xdp_prog_kern +XDP_BTF_OBJ = ${XDP_BTF_TARGETS:=.o} + +_all: llvm-check pahole-check $(XDP_BTF_OBJ) xdp_loader + +COPY_LOADER := xdp_loader + +COMMON_DIR = ../common/ +include $(COMMON_DIR)/common.mk + +PAHOLE ?= pahole + +.PHONY: $(PAHOLE) + +TEST_PAHOLE := "$(PAHOLE) --help 2>&1 | grep BTF" + +pahole-check: $(PAHOLE) + @for TOOL in $^ ; do \ + if [ ! $$(command -v $${TOOL} 2>/dev/null) ]; then \ + echo "*** ERROR: Cannot find tool $${TOOL}" ;\ + exit 1; \ + else true; fi; \ + done + @if [ ! $(TEST_PAHOLE) > /dev/null 2>&1 ]; then \ + echo "Tool pahole too old, missing BTF support" ;\ + exit 1; \ + else \ + echo "Using pahole to encode BTF info in ELF-object"; \ + fi + +#LLC_FLAGS += -mcpu=probe +LLC_FLAGS += -mattr=dwarfris + +$(XDP_BTF_OBJ): %.o: %.c Makefile $(COMMON_MK) + $(CLANG) -S \ + -target bpf \ + -D __BPF_TRACING__ \ + $(CFLAGS) \ + -Wall \ + -Wno-unused-value \ + -Wno-pointer-sign \ + -Wno-compare-distinct-pointer-types \ + -Werror \ + -O2 -emit-llvm -c -g $< + $(LLC) -march=bpf $(LLC_FLAGS) -filetype=obj -o $@ ${@:.o=.ll} + $(PAHOLE) -V --btf_encode $@ > ${@:.o=.pahole-btf-info} diff --git a/advanced02-BTF/common_kern_user.h b/advanced02-BTF/common_kern_user.h new file mode 100644 index 00000000..04f3344b --- /dev/null +++ b/advanced02-BTF/common_kern_user.h @@ -0,0 +1,17 @@ +/* This common_kern_user.h is used by kernel side BPF-progs and + * userspace programs, for sharing common struct's and DEFINEs. + */ +#ifndef __COMMON_KERN_USER_H +#define __COMMON_KERN_USER_H + +/* This is the data record stored in the map */ +struct datarec { + __u64 rx_packets; + __u64 rx_bytes; +}; + +#ifndef XDP_ACTION_MAX +#define XDP_ACTION_MAX (XDP_REDIRECT + 1) +#endif + +#endif /* __COMMON_KERN_USER_H */ diff --git a/advanced02-BTF/xdp_prog_kern.c b/advanced02-BTF/xdp_prog_kern.c new file mode 100644 index 00000000..a3e97951 --- /dev/null +++ b/advanced02-BTF/xdp_prog_kern.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include "bpf_helpers.h" + +#include "common_kern_user.h" /* defines: struct datarec; */ + +#define _BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ + struct ____btf_map_##name { \ + type_key key; \ + type_val value; \ + }; \ + struct ____btf_map_##name \ + __attribute__ ((section(".maps." #name), used)) \ + ____btf_map_##name = { } + +struct bpf_map_def SEC("maps") xdp_stats_map = { + .type = BPF_MAP_TYPE_PERCPU_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(struct datarec), + .max_entries = XDP_ACTION_MAX, +}; +_BPF_ANNOTATE_KV_PAIR(xdp_stats_map, int, struct datarec); + +static __always_inline +__u32 record_xdp_stats_action(struct xdp_md *ctx, __u32 action) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + + if (action >= XDP_ACTION_MAX) + return XDP_ABORTED; + + /* Lookup in kernel BPF-side return pointer to actual data record */ + struct datarec *rec = bpf_map_lookup_elem(&xdp_stats_map, &action); + if (!rec) + return XDP_ABORTED; + + /* Calculate packet length */ + __u64 bytes = data_end - data; + + /* BPF_MAP_TYPE_PERCPU_ARRAY returns a data record specific to current + * CPU and XDP hooks runs under Softirq, which makes it safe to update + * without atomic operations. + */ + rec->rx_packets++; + rec->rx_bytes += bytes; + + return action; +} + +SEC("xdp_pass") +int xdp_pass_func(struct xdp_md *ctx) +{ + __u32 action = XDP_PASS; /* XDP_PASS = 2 */ + + return record_xdp_stats_action(ctx, action); +} + +char _license[] SEC("license") = "GPL"; diff --git a/headers/bpf_helpers.h b/headers/bpf_helpers.h index 98d6496c..8aa89e4d 100644 --- a/headers/bpf_helpers.h +++ b/headers/bpf_helpers.h @@ -88,6 +88,15 @@ struct bpf_map_def { unsigned int inner_map_idx; }; +#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ + struct ____btf_map_##name { \ + type_key key; \ + type_val value; \ + }; \ + struct ____btf_map_##name \ + __attribute__ ((section(".maps." #name), used)) \ + ____btf_map_##name = { } + static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = (void *) BPF_FUNC_skb_load_bytes; static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =