挂载多个XDP

1. 为什么需要多个XDP

每个 netdev 只有一个 XDP hook,因此想要使用 XDP 的应用程序必须拥有 XDP hook。

但是如果用户想要安装多个这样的应用程序怎么办?

例如 - 应该可以同时运行所有这些:

  • XDP-基于 DDOS 保护*[1]*
  • XDP-加速 IDS(例如 Suricata)*[2]*
  • 自定义 XDP 程序

2. 如何运行多个XDP

libxdp使用AF_XDP sockets将XDP程序绑定到网络接口。libxdp相当轻量,依赖于libbpf处理eBPF等对象文件的工作。

libxdp基于libbpf之上,提供两个主要的功能:

  1. 在单个网络设备上,按顺序加载多个xdp程序的能力(内核本身不支持),这种支持依赖于内核中的freplace功能。这使得绑定一个eBPF程序来代替另一个已经加载的eBPF程序中的全局函数成为可能。
  2. 用于配置AF_XDP sockets以及从这些sockets读写数据包的辅助函数

2.1 从应用程序使用 libxdp

应用程序中 libxdp 的基本用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define IFINDEX 1

struct xdp_program *prog;
int err;

prog = xdp_program__open_file("my-program.o", "section_name", NULL);
# 加载XDP程序的接口
err = xdp_program__attach(prog, IFINDEX, XDP_MODE_NATIVE, 0);

# 加载失败了
if (!err)
# 卸载XDP程序的接口
xdp_program__detach(prog, IFINDEX, XDP_MODE_NATIVE, 0);

xdp_program__close(prog);

xdp_program结构是表示单个 XDP 程序结构。

libxdp包含如下三种创建此类结构体的函数:

  1. 从磁盘上的 BPF 对象文件
  2. libbpf的BPF 对象
  3. 已加载到内核中的程序标识符
1
2
3
4
5
6
7
8
9
10
11
struct xdp_program *xdp_program__from_bpf_obj(struct bpf_object *obj,
const char *section_name);
struct xdp_program *xdp_program__find_file(const char *filename,
const char *section_name,
struct bpf_object_open_opts *opts);
struct xdp_program *xdp_program__open_file(const char *filename,
const char *section_name,
struct bpf_object_open_opts *opts);
struct xdp_program *xdp_program__from_fd(int fd);
struct xdp_program *xdp_program__from_id(__u32 prog_id);
struct xdp_program *xdp_program__from_pin(const char *pin_path);

打开 BPF 对象或文件的函数需要 XDP 程序的函数名以及文件名或对象,因为一个 ELF 文件可以包含多个 XDP 程序。xdp_program__find_file()函数采用不带路径的文件名,并将查找LIBXDP_OBJECT_PATH上定义的对象,默认为/usr/lib/bpf(或/usr/lib64/bpf在使用拆分库路径的系统上)。这对于传送预编译的 eBPF 目标文件的应用程序来说很方便。

xdp_program__attach()函数将程序附加到一个接口,构建一个调度程序来执行它。可以一次附加多个程序xdp_program__attach_multi();它们将按照它们的运行优先级排序,并且从一个程序到下一个程序的执行将根据为每个程序定义的链调用动作进行。由于加载过程涉及修改程序的附加类型,因此附加函数仅适用于struct xdp_program尚未加载到内核中的对象。

当使用附加函数附加到已经加载了 XDP 程序的接口时,libxdp 将尝试将该程序添加到已加载程序的列表中。但是,这可能会失败,原因可能是缺少内核支持,或者是因为未使用与 libxdp 兼容的调度程序加载已附加的程序。如果缺少对增量附加(在内核 5.10 中合并)的内核支持,那么在单个接口上实际运行多个程序的唯一方法是使用 xdp_program__attach_multi(). 如果现有程序不是 XDP 调度程序,则必须先将该程序与接口分离,然后 libxdp 才能附加新程序。这可以通过调用来完成xdp_program__detach()引用加载的程序;但请注意,这当然会破坏任何依赖于存在的其他 XDP 程序的应用程序。

Reference


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