eBPF:如何使用 BPF_LINK_CREATE 附加 xdp

问题描述 投票:0回答:1

我知道如何使用 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
测试),可能问题出在哪里?

c linux linux-kernel ebpf
1个回答
0
投票

我自己解决了,是一个错误,tracing_on被我不小心关掉了,浪费我一整天的时间。打开它,一切都按预期工作。

© www.soinside.com 2019 - 2024. All rights reserved.