谁在BPF中创建地图 [英] who creates map in BPF

查看:429
本文介绍了谁在BPF中创建地图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读man bpf和其他一些文档来源后,我印象深刻的是map只能由用户进程创建.但是,以下小程序似乎神奇地创建了bpf映射:

After reading man bpf and a few other sources of documentation, I was under impression that a map can be only created by user process. However the following small program seems to magically create bpf map:

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加载了该​​程序,并还验证了该程序是否已加载:

So I load the program with the kernel's tools/bpf/bpftool and also verify that program is loaded:

$ 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不会创建任何地图.

Of course the map is empty. However, removing bpf_map_lookup_elem from the program results in no map being created.

更新 我用strace调试了它,发现在这两种情况下,即使用bpf_map_lookup_elem和不使用它时,bpftool都会调用bpf(BPF_MAP_CREATE, ...),并且显然可以成功.然后,如果遗漏了bpf_map_lookup_elem,我在bpftool map show上追踪,而bpf(BPF_MAP_GET_NEXT_ID, ..)立即返回ENOENT,并且它永远都不会转储地图.因此很明显,有些事情没有完成地图的创建.

UPDATE I debugged it with strace and found that in both cases, i.e. with bpf_map_lookup_elem and without it, bpftool does invoke bpf(BPF_MAP_CREATE, ...) and it apparently succeeds. Then, in case of bpf_map_lookup_elem left out, I strace on bpftool map show, and bpf(BPF_MAP_GET_NEXT_ID, ..) immediately returns ENOENT, and it never gets to dump a map. So obviously something is not completing the map creation.

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

So I wonder if this is expected behavior?

谢谢.

推荐答案

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

As explained by antiduh, and confirmed with your strace checks, bpftool is the user space program creating the maps in this case. It calls function bpf_prog_load() from libbpf (under tools/lib/bpf/), which in turn ends up performing the syscall. Then the program is pinned at the desired location (under a bpf virtual file system mount point), so that it is not unloaded when bpftool returns. Maps are not pinned.

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

Regarding map creation, the magic bits also take place in libbpf. When bpf_prog_load() is called, libbpf receives the name of the object file as an argument. bpftool does not ask to load this specific program or that specific map; instead, it provides the object file and libbpf has to deal with it. So the functions in libbpf parse this ELF object file, and eventually find a number of sections corresponding to maps and programs. Then it tries to load the first program.

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

Loading this program includes the following steps:

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指令相关联),并最后加载程序指令.

In other words: start by creating all maps we found in the object file. Then perform map relocation (i.e. associate map index to eBPF instructions), and at last load program instructions.

因此,关于您的问题:在两种情况下,无论是否使用bpf_map_lookup_elem(),都将使用bpf(BPF_MAP_CREATE, ...) syscall创建映射.此后,将发生重定位,并且如果需要,可以修改程序指令以指向新创建的地图.然后,完成所有步骤并加载程序后,bpftool退出. eBPF程序应固定,并仍加载在内核中.据我了解,如果确实使用了映射(如果使用了bpf_map_lookup_elem()),则映射仍然由加载的程序引用,并保留在内核中.另一方面,如果程序不使用这些映射,则没有其他东西可以阻止它们,因此,当bpftool保留的文件描述符关闭时,当bpftool返回.

So regarding your question: in both cases, with and without bpf_map_lookup_elem(), maps are created with a bpf(BPF_MAP_CREATE, ...) syscall. After that, relocation happens, and program instructions are adapted to point, if needed, to the newly created maps. Then once all steps are finished and the program is loaded, bpftool exits. The eBPF program should be pinned, and still loaded in the kernel. As far as I understand, if it does use the maps (if bpf_map_lookup_elem() was used), then maps are still referenced by a loaded program, and are kept in the kernel. On the other hand, if the program does not use the maps, then there is nothing more to hold them back, so the maps are destroyed when the file descriptors held by bpftool are closed, when bpftool returns.

因此,最后,当bpftool完成时,如果程序使用它,则在内核中加载了一个映射,但是如果没有程序依赖它,则没有映射.我认为这听起来像是预期的行为;但是如果您在bpftool上遇到奇怪的事情,请以一种或另一种方式执行ping操作,我是使用该实用程序的人之一.最后一个普遍的观察结果:即使没有程序使用地图,也可以将地图固定并保留在内核中.

So in the end, when bpftool has completed, you have a map loaded in the kernel if the program uses it, but no map if no program would rely on it. Sounds like expected behaviour in my opinion; but please do ping one way or another if you experience strange things with bpftool, I'm one of the guys working on the utility. One last generic observation: maps can also be pinned and remain in the kernel even if no program uses them, should one need to keep them around.

这篇关于谁在BPF中创建地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆