可以在不同类型的程序之间共享对 eBPF 映射的访问。
struct bpf_elf_map
首先,您可以忘记和之间的差异struct bpf_map_def
。它们是用户空间中用于构建传递给内核的对象的结构。Iproute2 和 libbpf 可能不使用相同的结构/属性名称,但它们最终都会以bpf()
相同的格式将映射元数据传递给系统调用,否则内核将无法理解要创建的映射。
当它们被加载到内核时,eBPF 程序通过文件描述符引用给定的映射到这个映射。这意味着调用bpf()
系统调用来加载程序的进程首先必须将文件描述符检索到要使用的映射。所以可能会出现以下两种情况:
用户空间应用程序(ip、tc、bpftool...)解析 ELF 对象文件并收集与地图相关的元数据。它没有识别(甚至可能没有尝试识别)任何应该为程序重用的现有地图。因此它使用系统调用创建一个新映射,该bpf()
系统调用将一个文件描述符返回到这个新创建的映射。该文件描述符用于涉及映射访问的程序指令中(一旦程序加载到内核中,这些文件描述符将被映射地址替换),然后使用bpf()
系统调用加载程序。这就是您的 tc 程序发生的情况,在您的情况下,您的 cgroup 程序似乎正在创建第二个地图。
或者用户应用程序解析 ELF 目标文件,并以某种方式发现已经存在程序应该使用的映射。例如,它会找到 id 为 1337 的地图,或者在/sys/fs/bpf/
. 在这种情况下,它会检索到该映射的文件描述符(从带有bpf()
系统调用的 id,从带有 的固定路径open()
)。然后和第一种情况一样,它使用这个文件描述符来准备然后加载程序。
Libbpf 提供了一种方法来重用给定映射的文件描述符以与程序一起使用。参见例如bpf_map__reuse_fd()
。Bpftool使用它来支持重用现有地图,并带有map
参数 for bpftool prog load
(请参阅参考资料man bpftool-prog
)。例如,加载一个程序foo.o
并告诉它为27
在目标文件中找到的第一个地图重用 id 地图,然后将地图固定在目标文件中/sys/fs/bpf/foomap
命名的地图上foomap
:
# bpftool prog load foo.o /sys/fs/bpf/foo_prog \
map idx 0 id 27 \
map foomap stats pinned /sys/fs/bpf/foomap