libxdp实现原理

为了在同一个接口上支持多个 XDP 程序,libxdp 为每个 XDP 程序使用两个元数据:运行优先级和链式调用操作。

运行优先级

这是程序的优先级,是一个简单的整数,用于在将多个程序加载到同一界面时对程序进行排序。希望提前运行的程序(如数据包过滤器)应为此设置较低的值,而希望稍后运行的程序(如数据包转发器或计数器)应设置较高的值。请注意,仅当先前的程序以作为其链式调用操作的一部分的返回码结束时,以后的程序才会运行(见下文)。如果未指定,则默认优先级值为 50。

链式调用动作

这些是程序为应继续处理的数据包指示的程序返回代码。如果程序返回这些动作之一,调用链中的后续程序将运行,而如果它返回任何其他动作,则处理将被中断,XDP 调度程序将立即返回结果。如果未设置,则默认为 XDP_PASS,这可能是大多数程序应该使用的值。

指定元数据

上述元数据被指定为嵌入在包含 XDP 程序的 ELF 文件中的 BTF 信息。xdp_helpers.h附带的文件包含包含此信息的辅助宏,可按如下方式使用:

1
2
3
4
5
6
7
8
#include <bpf/bpf_helpers.h>
#include <xdp/xdp_helpers.h>

struct {
__uint(priority, 10);
__uint(XDP_PASS, 1);
__uint(XDP_DROP, 1);
} XDP_RUN_CONFIG(my_xdp_func);

这个例子指定 XDP 程序的my_xdp_func优先级应该是 10 并且它的链式调用动作是XDP_PASSand XDP_DROP。在同一个文件中包含多个 XDP 程序的源文件中,可以为每个程序(主要 XDP 函数)包含上述定义。任何未指定任何配置信息的程序都将使用上述默认值。

检查和修改元数据

libxdp公开了应用程序可用于检查和修改 XDP 程序上的元数据的以下函数。只有在程序附加到接口上之前才能进行修改。这些函数不会修改 BTF 信息本身,但新值将作为程序附件的一部分存储。

1
2
3
4
5
6
7
8
9
10
11
unsigned int xdp_program__run_prio(const struct xdp_program *xdp_prog);
int xdp_program__set_run_prio(struct xdp_program *xdp_prog,
unsigned int run_prio);
bool xdp_program__chain_call_enabled(const struct xdp_program *xdp_prog,
enum xdp_action action);
int xdp_program__set_chain_call_enabled(struct xdp_program *prog,
unsigned int action,
bool enabled);
int xdp_program__print_chain_call_actions(const struct xdp_program *prog,
char *buf,
size_t buf_len);

调度程序

为了在同一个网络接口上支持多个非卸载程序, libxdp使用一个调度程序,它是一个小的包装程序,它将依次调用每个组件程序,期望返回码,然后基于链调用链调用到下一个程序上一个程序的操作。

虽然使用的应用程序libxdp不需要知道调度程序的详细信息,只需将 XDP 程序加载到接口,libxdp但确实公开了调度程序及其附加的组件程序,可用于列出当前附加到接口的程序。

用于此的结构是struct xdp_multiprog,它只能由加载在基于 ifindex 的接口上的程序构建。用于获取 multiprog 引用并遍历附加程序的 API 如下所示:

1
2
3
4
5
6
7
8
9
struct xdp_multiprog *xdp_multiprog__get_from_ifindex(int ifindex);
struct xdp_program *xdp_multiprog__next_prog(const struct xdp_program *prog,
const struct xdp_multiprog *mp);
void xdp_multiprog__close(struct xdp_multiprog *mp);
int xdp_multiprog__detach(struct xdp_multiprog *mp, int ifindex);
enum xdp_attach_mode xdp_multiprog__attach_mode(const struct xdp_multiprog *mp);
struct xdp_program *xdp_multiprog__main_prog(const struct xdp_multiprog *mp);
struct xdp_program *xdp_multiprog__hw_prog(const struct xdp_multiprog *mp);
bool xdp_multiprog__is_legacy(const struct xdp_multiprog *mp);

如果未卸载程序附加到libxdp无法识别为调度程序的接口,xdp_multiprog则仍将返回一个结构,并将xdp_multiprog__is_legacy()对该程序返回 true(请注意,如果仅加载卸载程序,这也适用) . 可以通过 获得对该(常规)XDP 程序的引用 xdp_multiprog__main_prog()。如果附加到接口的程序调度程序,xdp_multiprog__main_prog()将返回对调度程序本身的引用,这主要用于获取有关该程序的其他数据(例如程序ID)。可以使用 获取对已卸载程序的引用xdp_multiprog_hw_prog()。功能 xdp_multiprog__attach_mode()返回非卸载程序的附加模式,是否附加卸载程序应通过xdp_multiprog_hw_prog().


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!