Reputation: 23
I know how to attach xdp with netlink, but I don't want to use that since the attaching keep existing even if the loader exits. Then I found another way to attach the xdp in the official documents, which is by BPF_LINK_CREATE, here is the link and original statement:
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.
The description about attaching xdp with BPF_LINK_CREATE is too simple for me to write a workable loader, and I still didn't find a official demo about its usage, but I tried, here are my codes:
test.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;
}
test.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();
}
Makefile
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
When I run make
, the program works fine, but the bpf_printk("hello xdp")
wasn't called, here is the fd table of loader:
# 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
output of bpftool net list
# bpftool net list
xdp:
lo(1) generic id 528
tc:
flow_dissector:
netfilter:
The fd anon_inode:bpf_link
shows that the link is established successfully, but why the xdp hook isn't invoked(tested by ping 127.0.0.1
), where might be the problem?
Upvotes: 1
Views: 89
Reputation: 23
I've solved it myself, it was a mistake, the tracing_on was turned off by me accidently, waste my a whole day. Turn it on, and everything works as expected.
Upvotes: 0