谁在BPF中创建地图

时间:2018-01-02 20:05:15

标签: linux-kernel bpf ebpf

在阅读man bpf和其他一些文档来源后,我的印象是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;
}

所以我用内核的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

当然地图是空的。但是,从程序中删除bpf_map_lookup_elem会导致无法创建地图。

更新 我使用strace对其进行了调试,发现在两种情况下,即使用bpf_map_lookup_elem并且没有它,bpftool会调用bpf(BPF_MAP_CREATE, ...),但它显然会成功。然后,如果省略bpf_map_lookup_elem,我就会bpftool map showbpf(BPF_MAP_GET_NEXT_ID, ..)立即返回ENOENT,它永远不会转储地图。显然有些事情没有完成地图创作。

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

感谢。

2 个答案:

答案 0 :(得分:5)

正如antiduh所解释,并通过strace检查确认,bpftool是用户空间程序,在这种情况下创建地图。它从libbpf(在bpf_prog_load()下)调用函数tools/lib/bpf/,后者最终执行系统调用。然后程序被固定在所需的位置(在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);

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

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

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

答案 1 :(得分:2)

  

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

你是完全正确的 - 用户程序是调用bpf系统调用以加载eBPF程序和创建eBPF地图的程序。

你做到了这一点:

  

所以我用tools / bpf / bpftool和...

加载程序

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

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

用于连接点的一些相关位from the man page

  

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

     

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

     

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