谁在BPF中创建地图

Mar*_*ark 4 linux-kernel bpf ebpf

在阅读man bpf了一些其他文档来源后,我的印象是a map只能由用户进程创建.然而,以下小程序似乎神奇地创建了bpf地图:

struct bpf_map_def SEC("maps") my_map = {
        .type = BPF_MAP_TYPE_ARRAY,
        .key_size = sizeof(u32),
        .value_size = sizeof(long),
        .max_entries = 10,
};

SEC("sockops")
int my_prog(struct bpf_sock_ops *skops)
{
   u32 key = 1;
   long *value;
   ...

   value = bpf_map_lookup_elem(&my_map, &key);
   ...
   return 1;
}
Run Code Online (Sandbox Code Playgroud)

所以我用内核加载程序,tools/bpf/bpftool并验证程序是否已加载:

$ bpftool prog show
1: sock_ops  name my_prog  tag f3a3583cdd82ae8d
        loaded_at Jan 02/18:46  uid 0
        xlated 728B  not jited  memlock 4096B

$ bpftool map show
1: array  name my_map  flags 0x0
        key 4B  value 8B  max_entries 10  memlock 4096B
Run Code Online (Sandbox Code Playgroud)

当然地图是空的.但是,bpf_map_lookup_elem从程序中删除不会导致创建任何地图.

更新 我调试它并发现在strace两种情况下,即有bpf_map_lookup_elem和没有它,bpftool确实调用bpf(BPF_MAP_CREATE, ...)它显然成功.然后,在bpf_map_lookup_elem的情况下离开了,我与strace上bpftool map show,并bpf(BPF_MAP_GET_NEXT_ID, ..)立即返回ENOENT,它从来没有得到倾倒地图.所以显然有些东西没有完成地图创建.

所以我想知道这是否是预期的行为?

谢谢.

Qeo*_*ole 6

正如antiduh所解释的,并且通过您的strace检查确认,bpftool是用户空间程序在这种情况下创建地图.它bpf_prog_load()从libbpf(under tools/lib/bpf/)调用函数,后者最终执行syscall.然后程序被固定在所需位置(在bpf虚拟文件系统安装点下),以便在bpftool返回时不会卸载它.地图未固定.

关于地图创建,魔术位也发生在libbpf中.当bpf_prog_load()被调用时,libbpf接收对象文件作为参数的名称.bpftool不要求加载特定程序或特定地图; 相反,它提供了目标文件,libbpf必须处理它.因此libbpf中的函数解析此ELF目标文件,并最终找到与地图和程序相对应的许多部分.然后它尝试加载第一个程序.

加载此程序包括以下步骤:

CHECK_ERR(bpf_object__create_maps(obj), err, out);
CHECK_ERR(bpf_object__relocate(obj), err, out);
CHECK_ERR(bpf_object__load_progs(obj), err, out);
Run Code Online (Sandbox Code Playgroud)

换句话说:首先创建我们在目标文件中找到的所有地图.然后执行映射重定位(即将映射索引关联到eBPF指令),并最后加载程序指令.

所以关于你的问题:在两种情况下,无论有没有bpf_map_lookup_elem(),地图都是用bpf(BPF_MAP_CREATE, ...)系统调用创建的.之后,重新定位发生,并且程序指令适于在需要时指向新创建的地图.然后,一旦完成所有步骤并加载程序,bpftool退出.应该固定eBPF程序,并且仍然在内核中加载.据我所知,如果它确实使用了地图(如果使用了地图bpf_map_lookup_elem()),那么地图仍然被加载的程序引用,并保存在内核中.在另一方面,如果程序使用的地图,那么就没有什么更多的把它们抱,所以当所持文件描述符地图被破坏bpftool被关闭,何时bpftool恢复.

所以最后,当bpftool完成时,如果程序使用了地图,你就会在内核中加载一个地图,但如果程序没有依赖它就没有地图.在我看来,听起来像预期的行为; 但如果你遇到奇怪的事情,请以这种或那种方式ping bpftool,我是从事该实用程序的人之一.最后一个通用观察:即使没有程序使用它们,地图也可以固定并保留在内核中,如果需要保留它们.

  • 谢谢你的全面解答!我是否正确,为了完全卸载固定的 BPF 程序,`umount /sys/fs/bpf/xxx` 就足够了吗?这是否保证 bpf blob 将从内存中删除? (2认同)

ant*_*duh 5

我的印象是地图只能由用户进程创建。

您完全正确 - 用户程序是调用bpf系统调用以加载 eBPF 程序并创建 eBPF 映射的程序。

而你就是这样做的:

所以我用tools/bpf/bpftool加载程序并且......

您的bpftool程序是调用系统调用的用户进程bpf,因此也是创建 eBPF 映射的用户进程。

当创建 BPF 程序的用户程序退出时,不必卸载它 - bpftool 可能使用这种机制。

手册页中的一些相关内容用于连接这些点:

用户进程可以创建多个映射...并通过文件描述符访问它们。

一般情况下,eBPF程序由用户进程加载,并在进程退出时自动卸载。在某些情况下......即使加载程序的进程退出后,程序仍将在内核中继续保持活动状态。

每个 eBPF 程序都是一组可以安全运行直到完成的指令。...在验证期间,内核会增加 eBPF 程序使用的每个映射的引用计数,以便在卸载程序之前无法删除附加的映射。