为何调用bpf_trace_printk会导致eBPF程序加载失败?
问题分析与解决方法
你的eBPF程序加载失败有两个核心原因:
- 直接使用全局可写变量
counter,eBPF验证器禁止这种操作 - 全局变量的非法访问导致后续
bpf_printk的调用验证失败
修复后的代码
#include <linux/bpf.h> #include <bpf/bpf_helpers.h> // 用BPF数组映射存储计数器,替代全局变量 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(void *ctx) { int key = 0; // 从映射中获取计数器指针 int *counter = bpf_map_lookup_elem(&counter_map, &key); // 空指针检查,避免验证器报错 if (!counter) return XDP_PASS; bpf_printk("Hello World %d", *counter); (*counter)++; return XDP_PASS; } char LICENSE[] SEC("license") = "Dual BSD/GPL";
关键修复点说明
- 替换全局变量为BPF映射:eBPF程序不能直接修改全局可写变量,必须通过BPF映射(map)来管理状态。这里用
BPF_MAP_TYPE_ARRAY类型的映射,仅存储一个整数值作为计数器。 - 空指针检查:调用
bpf_map_lookup_elem必须检查返回值,否则eBPF验证器会认为存在非法内存访问风险,拒绝加载程序。 - 正确使用
bpf_printk:修复全局变量问题后,bpf_printk的调用会自动通过验证,无需额外修改。
编译与加载步骤
- 编译程序:
clang -target bpf -D__TARGET_ARCH_x86_64 -I/usr/include/linux -I/usr/include/x86_64-linux-gnu -O2 -c hello.bpf.c -o hello.bpf.o
- 加载程序(若存在BTF问题,添加
--no-btf参数):
bpftool prog load hello.bpf.o /sys/fs/bpf/hello --no-btf
- 查看输出:
cat /sys/kernel/debug/tracing/trace_pipe
额外说明
若仍然遇到btf_vmlinux is malformed错误,检查内核是否开启了BTF支持(CONFIG_DEBUG_INFO_BTF=y)。如果内核未开启BTF,加载时必须添加--no-btf参数跳过BTF验证。
内容的提问来源于stack exchange,提问作者Shivam Kajaria
相关产品推荐
相关产品推荐

