我知道如何使用 netlink 附加 xdp,但我不想使用它,因为即使加载程序退出,附加仍然存在。然后我在官方文档中找到了另一种附加xdp的方法,那就是通过BPF_LINK_CREATE,这是链接和原始声明:
There are two ways of attaching XDP programs to network devices, the legacy way of doing
is is via a netlink socket the details of which are complex. Examples of libraries that
implement netlink XDP attaching are vishvananda/netlink and libbpf.
The modern and recommended way is to use BPF links. Doing so is as easy as calling
BPF_LINK_CREATE with the target_ifindex set to the network interface target, attach_type
set to BPF_LINK_TYPE_XDP and the same flags as would be used for the netlink approach.
关于用BPF_LINK_CREATE附加xdp的描述对我来说太简单了,无法编写一个可行的加载器,而且我仍然没有找到关于其用法的官方演示,但我尝试了,这是我的代码:
测试.bpf.c
// bpf code
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
char _license[] SEC("license") = "GPL";
SEC("xdp")
int xdp_func(struct xdp_md *ctx) {
bpf_printk("hello xdp");
return XDP_PASS;
}
测试.cpp
// loader
#include <stdio.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>
#include <net/if.h>
#include "test.skel.h"
#define error(fmt, args...) printf("error: " fmt, ##args)
static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
unsigned int size)
{
return syscall(__NR_bpf, cmd, attr, size);
}
#define bpf_syscall(cmd, attr) \
({ \
int fd; \
fd = sys_bpf(cmd, &attr, sizeof(attr)); \
if (fd < 0) \
{ \
error("bpf syscall failure(%s): cmd: " #cmd \
" line: %d\n", \
strerror(errno), __LINE__); \
exit(-1); \
} \
(fd); \
})
#define bpf_get_prog_fd(prog) \
({ \
int fd; \
fd = bpf_program__fd(prog); \
if (fd < 0) \
{ \
error("fail to get bpf program fd " #prog "\n"); \
exit(-1); \
} \
fd; \
})
void read_trace_pipe(FILE *fp = nullptr)
{
int trace_fd = open("/sys/kernel/debug/tracing/trace_pipe", O_RDONLY, 0);
assert(trace_fd > 0);
if (fp == nullptr)
fp = stdout;
while (1)
{
static char buf[4096];
ssize_t sz = read(trace_fd, buf, sizeof(buf));
if (sz > 0)
fwrite(buf, 1, sz, fp);
if (sz < 0)
break;
}
}
int main(void)
{
test_bpf *obj = test_bpf::open_and_load();
assert(obj);
assert(test_bpf::attach(obj) == 0);
union bpf_attr attr = {};
int ifindex = if_nametoindex("lo");
printf("ifindex: %d\n", ifindex);
attr.link_create.target_ifindex = ifindex;
attr.link_create.attach_type = BPF_XDP;
attr.link_create.prog_fd = bpf_get_prog_fd(obj->progs.xdp_func);
bpf_syscall(BPF_LINK_CREATE, attr);
read_trace_pipe();
}
生成文件
all: test
sudo ./test
test: test.cpp test.skel.h
g++ -g $< -o $@ -lbpf
test.bpf.o: test.bpf.c vmlinux.h
clang -g -O2 -D__x86_64__ -target bpf -c $< -o $@
test.skel.h: test.bpf.o
bpftool gen skeleton $< > $@
vmlinux.h: /sys/kernel/btf/vmlinux
bpftool btf dump file $< format c > $@
clean:
rm -f vmlinux.h test.skel.h test.bpf.o test
当我运行
make
时,程序运行正常,但是bpf_printk("hello xdp")
没有被调用,这是loader的fd表:
# ll /proc/`pgrep test`/fd
total 0
lrwx------ 1 root root 64 Dec 10 13:38 0 -> /dev/pts/2
lrwx------ 1 root root 64 Dec 10 13:38 1 -> /dev/pts/2
lrwx------ 1 root root 64 Dec 10 13:38 2 -> /dev/pts/2
lrwx------ 1 root root 64 Dec 10 13:38 3 -> anon_inode:bpf-map
lr-x------ 1 root root 64 Dec 10 13:38 4 -> anon_inode:btf
lrwx------ 1 root root 64 Dec 10 13:38 5 -> anon_inode:bpf-prog
lr-x------ 1 root root 64 Dec 10 13:38 6 -> anon_inode:bpf_link
lr-x------ 1 root root 64 Dec 10 13:38 7 -> /sys/kernel/debug/tracing/trace_pipe
输出
bpftool net list
# bpftool net list
xdp:
lo(1) generic id 528
tc:
flow_dissector:
netfilter:
fd
anon_inode:bpf_link
显示链接建立成功,但是为什么xdp hook没有被调用(经ping 127.0.0.1
测试),可能问题出在哪里?
我自己解决了,是一个错误,tracing_on被我不小心关掉了,浪费我一整天的时间。打开它,一切都按预期工作。