Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tutorial: advanced BTF example #49

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
48 changes: 48 additions & 0 deletions advanced02-BTF/Makefile
Original file line number Diff line number Diff line change
@@ -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}
17 changes: 17 additions & 0 deletions advanced02-BTF/common_kern_user.h
Original file line number Diff line number Diff line change
@@ -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 */
59 changes: 59 additions & 0 deletions advanced02-BTF/xdp_prog_kern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/bpf.h>
#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";
9 changes: 9 additions & 0 deletions headers/bpf_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) =
Expand Down