在阅读了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会导致没有创建任何映射。
UPDATE I用strace调试了它,发现在这两种情况下,即使用bpf_map_lookup_elem和没有bpf_map_lookup_elem,bpftool确实调用了bpf(BPF_MAP_CREATE, ...),并且显然成功了。然后,在bpf_map_lookup_elem遗漏的情况下,我使用bpftool map show,bpf(BPF_MAP_GET_NEXT_ID, ..)立即返回ENOENT,它永远无法转储地图。所以很明显,有些东西并没有完成地图的创建。
所以我想知道这是否是预期的行为?
谢谢。
发布于 2018-01-03 10:03:43
正如antiduh所解释的,并通过您的strace检查确认了,bpftool是在本例中创建映射的用户空间程序。它从libbpf (在tools/lib/bpf/下)调用函数bpf_prog_load(),然后执行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);换句话说:从创建在对象文件中找到的所有映射开始。然后执行映射重定位(即将映射索引与eBPF指令相关联),最后加载程序指令。
因此,关于您的问题:在这两种情况下,无论是否使用bpf_map_lookup_elem(),映射都是用bpf(BPF_MAP_CREATE, ...) syscall创建的。在此之后,重新定位就会发生,如果需要的话,程序指令将被调整为指向新创建的映射。然后,一旦完成所有步骤并加载程序,bpftool就会退出。eBPF程序应该是固定的,并且仍然加载在内核中。据我所知,如果它确实使用了映射(如果使用了bpf_map_lookup_elem() ),那么映射仍然被加载的程序引用,并保存在内核中。另一方面,如果程序不使用映射,那么就没有什么可以阻止它们的了,所以当bpftool持有的文件描述符关闭时,当bpftool返回时,映射就会被销毁。
因此,最后,当bpftool完成时,如果程序使用它,就会在内核中加载一个映射,但是如果没有程序依赖它,则没有映射。在我看来,这听起来像是一种预期的行为;但是,如果您在bpftool中遇到了奇怪的事情,那么请以这样或那样的方式执行ping操作,我就是这个实用程序的工作人员之一。最后一个一般性的观察是:地图也可以固定在内核中,即使没有程序使用它们,如果需要保持它们在一起的话。
发布于 2018-01-02 20:52:10
我当时的印象是,地图只能由用户进程创建。
您完全正确--用户程序是调用bpf系统调用以加载eBPF程序和创建eBPF映射的程序。
你就是这么做的:
所以我用工具/bpf/bpftool加载程序.
bpftool程序是调用bpf syscall的用户进程,因此是创建eBPF映射的用户进程。
当创建BPF程序的用户程序可能使用此机制时,就不必卸载BPF程序。
一些相关的位从手册页连接点:
用户进程可以创建多个映射..。并通过文件描述符访问它们。 通常,eBPF程序由用户进程加载,并在进程退出时自动卸载。在某些情况下..。即使在加载程序的进程退出之后,程序仍将在内核中保持活跃。 每个eBPF程序都是一组安全运行直到完成的指令。..。在验证过程中,内核会增加eBPF程序使用的每个映射的引用计数,以便在卸载程序之前不能删除附加的映射。
https://stackoverflow.com/questions/48067163
复制相似问题