我正在尝试创建一个简单的 BPF 程序来丢弃传入/传出数据包并仅接受转发的数据包,由
bpftool
加载。
我使用的是 Ubuntu 24.04 和 Linux 内核版本 6.8。这是我的程序:
#include <linux/bpf.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <linux/netfilter.h>
SEC("netfilter") /* hint to BPF loader that this is an netfilter BPF program */
int filter(const struct bpf_nf_ctx *ctx) {
const struct nf_hook_state *state = ctx->state;
unsigned int routing_decision = state->hook;
if (routing_decision == NF_INET_LOCAL_IN ||
routing_decision == NF_INET_LOCAL_OUT)
return NF_DROP;
return NF_ACCEPT;
}
char LICENSE[] SEC("license") = "GPL";
但是,当我尝试将其编译成目标文件时,我得到:
clang --target=bpf -O2 -Wall -I/usr/include/x86_64-linux-gnu -c filter.c -o filter.bpf.o
filter.c:8:27: warning: declaration of 'struct bpf_nf_ctx' will not be visible outside of this function [-Wvisibility]
8 | int filter(const struct bpf_nf_ctx *ctx) {
| ^
filter.c:9:42: error: incomplete definition of type 'struct bpf_nf_ctx'
9 | const struct nf_hook_state *state = ctx->state;
| ~~~^
filter.c:8:27: note: forward declaration of 'struct bpf_nf_ctx'
8 | int filter(const struct bpf_nf_ctx *ctx) {
| ^
filter.c:10:29: error: incomplete definition of type 'struct bpf_nf_ctx'
10 | int routing_decision = ctx->state->hook;
| ~~~^
filter.c:8:27: note: forward declaration of 'struct bpf_nf_ctx'
8 | int filter(const struct bpf_nf_ctx *ctx) {
| ^
1 warning and 2 errors generated.
意识到
struct bpf_nf_ctx
在nf_bpf_link.h
中定义后,我添加了正确的包含(#include <net/netfilter/nf_bpf_link.h>
,当完整路径为/usr/src/linux-headers-6.8.0-48/include/net/netfilter/nf_bpf_link.h
时),这就是输出:
clang --target=bpf -O2 -Wall -I/usr/include/x86_64-linux-gnu -I/usr/src/linux-headers-6.8.0-48/include -c filter.c -o filter.bpf.o
In file included from filter.c:1:
In file included from /usr/src/linux-headers-6.8.0-48/include/linux/bpf.h:8:
In file included from /usr/src/linux-headers-6.8.0-48/include/uapi/linux/filter.h:9:
/usr/src/linux-headers-6.8.0-48/include/linux/compiler.h:251:10: fatal error: 'asm/rwonce.h' file not found
251 | #include <asm/rwonce.h>
| ^~~~~~~~~~~~~~
1 error generated.
make: *** [Makefile:7: all] Error 1
如何正确设置环境以使用 netfilter hooks 编译 BPF 程序?
您正在包含内部内核标头(非 uapi 标头)。这些需要一堆生成的依赖项才能工作,这就是您遇到包含问题的原因。
对于 netfilter 程序,内核开发人员决定不使用像
__sk_buff
这样的投影类型,而是让您访问真实的内部 sk_buff
结构。为了获得这些的定义,他们希望您使用 vmlinux.h 或手动定义您需要的结构,就像编写访问内部内核类型的跟踪程序一样。
对于新手,您可以使用
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
从本地内核生成 vmlinux.h 文件
引用介绍它的补丁集:
新的程序类型是“跟踪式”,即没有上下文 由验证器完成的访问重写,函数参数(struct bpf_nf_ctx) 不稳定。 不支持直接数据包访问,应使用 dynptr api 相反。
这也意味着如果您需要此程序在未来的内核上运行,您应该使用 CO-RE do do read。