加载《Learning eBPF》示例eBPF/XDP程序至内核失败,求解决方案
问题描述
尝试加载《Learning eBPF》中的XDP示例程序时失败,执行加载命令:
sudo bpftool prog load hello.bpf.o /sys/fs/bpf/hello
核心报错信息:
libbpf: bpf: relocation: not yet supported relo for non-static global 'counter' variable found in insns[0].code 0x18
原示例代码:
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> int counter = 0; SEC("xdp") int hello(struct xdp_md *ctx) { bpf_printk("Hello World %d", counter); counter++; return XDP_PASS; } char LICENSE[] SEC("license") = "Dual BSD/GPL";
解决方法
1. 修改代码适配eBPF状态存储规则
内核不支持非静态全局变量的重定位,且普通全局变量无法跨eBPF调用持久化状态,需改用eBPF数组Map存储计数器。修改后的代码:
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> // 定义数组Map,用于存储计数器,仅需1个条目 struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, 1); __type(key, int); __type(value, int); } counter_map SEC(".maps"); SEC("xdp") int hello(struct xdp_md *ctx) { int key = 0; int *counter = bpf_map_lookup_elem(&counter_map, &key); // 确保成功获取计数器指针后再操作 if (counter) { bpf_printk("Hello World %d", *counter); (*counter)++; } return XDP_PASS; } char LICENSE[] SEC("license") = "Dual BSD/GPL";
2. 重新编译与加载
用clang重新编译代码(以x86架构为例):
clang -target bpf -D__TARGET_ARCH_x86_64 -I/usr/include/x86_64-linux-gnu -O2 -c hello.bpf.c -o hello.bpf.o
执行加载命令:
sudo bpftool prog load hello.bpf.o /sys/fs/bpf/hello
3. 验证运行效果
通过内核日志查看程序输出:
sudo dmesg -w
当有数据包流经绑定该XDP程序的网卡时,会看到递增的Hello World X日志。
关键原因
- eBPF内核加载器不支持非静态全局变量的重定位操作,必须改用静态变量或Map存储数据。
- 普通静态全局变量无法在eBPF程序的多次调用间保持状态,而eBPF Map是内核维护的持久化存储结构,适合跨调用保存计数这类状态数据。
内容的提问来源于stack exchange,提问作者Andy R
相关产品推荐
相关产品推荐

