一个元素的 eBPF 映射。地图类型与kernel/userspace通讯
eBPF maps for one element. Map type and kernel/user space communication
我会创建一个映射来仅存储一个元素(端口号),它应该是来自用户space 和内核space 的read/written。
我应该使用哪种地图类型?哪个键和值的大小合适,我怎样才能从两边write/read?
_user.c
/* create array map with one element */
map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 1, 0);
...
/* update map */
ret = bpf_map_update_elem(map_fd, &key, &i, BPF_ANY);
_kern.c
如何参考map_fd并在同一张地图上操作?
编辑:
我只能通过一种方式成功创建地图并与之交互:
在 _kern.c
文件中定义地图,如下所示:
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(uint32_t),
.value_size = sizeof(uint32_t),
.max_entries = 1,
};
该定义允许使用 bpf 助手直接在地图上操作 bpf_map_lookup_elem
。
通过bpf_prog_load
将_kern.o
ebpf程序加载到内核后,我在_user.c
中使用了
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
检索与地图关联的文件描述符(我错过了这一点)。一旦获得要执行的文件描述符,例如,您可以调用地图更新
ret = bpf_map_update_elem(map_fd, &key, &value, BPF_ANY);
问题: 在这种情况下,我使用 libbpf 从用户 space 检索 fd,但是如果我使用 [=22 从 _user.c
创建映射=] 那么如何从 ebpf 程序中检索 fd 呢?
如果您知道只有一个元素,那么最简单的方法可能就是使用数组映射。在这种情况下,您可以通过其在数组中的索引轻松访问您的地图条目:0
.
如果您这样做,键的大小将是 4 字节整数 (sizeof(uint32_t)
) 的大小,它始终用于数组索引。该值的大小将是您存储端口号所需的大小:很可能是 sizeof(uint16_t)
.
然后您可以通过调用相关的 BPF 辅助函数从您的 BPF 程序 read/write:bpf_map_lookup_elem()
或 bpf_map_update_elem()
(有关详细信息,请参阅 man page)。它们通常在 bpf_helpers.h
中定义,通常不会安装在您的系统上,您可以在 bcc 或内核 repo 中找到它的版本。
从用户 space,您可以使用 bpf()
系统调用及其相关命令更新条目:BPF_MAP_LOOKUP_ELEM()
和 BPF_MAP_UPDATE_ELEM()
(请参阅 man page). But you don't necessarily have to re-implement the calls yourself: if you write a program, you should probably have a look at libbpf that provides wrappers. If you want to update your map from the command line, this is easy to do with bpftool
(see man page),类似于 bpftool map <map_ref> update key 0 0 0 0 value 0x37 0x13
(更新)或 bpftool map <map_ref> lookup key 0 0 0 0
(查找)。
我会创建一个映射来仅存储一个元素(端口号),它应该是来自用户space 和内核space 的read/written。 我应该使用哪种地图类型?哪个键和值的大小合适,我怎样才能从两边write/read?
_user.c
/* create array map with one element */
map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 1, 0);
...
/* update map */
ret = bpf_map_update_elem(map_fd, &key, &i, BPF_ANY);
_kern.c
如何参考map_fd并在同一张地图上操作?
编辑:
我只能通过一种方式成功创建地图并与之交互:
在 _kern.c
文件中定义地图,如下所示:
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(uint32_t),
.value_size = sizeof(uint32_t),
.max_entries = 1,
};
该定义允许使用 bpf 助手直接在地图上操作 bpf_map_lookup_elem
。
通过bpf_prog_load
将_kern.o
ebpf程序加载到内核后,我在_user.c
中使用了
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
检索与地图关联的文件描述符(我错过了这一点)。一旦获得要执行的文件描述符,例如,您可以调用地图更新
ret = bpf_map_update_elem(map_fd, &key, &value, BPF_ANY);
问题: 在这种情况下,我使用 libbpf 从用户 space 检索 fd,但是如果我使用 [=22 从 _user.c
创建映射=] 那么如何从 ebpf 程序中检索 fd 呢?
如果您知道只有一个元素,那么最简单的方法可能就是使用数组映射。在这种情况下,您可以通过其在数组中的索引轻松访问您的地图条目:0
.
如果您这样做,键的大小将是 4 字节整数 (sizeof(uint32_t)
) 的大小,它始终用于数组索引。该值的大小将是您存储端口号所需的大小:很可能是 sizeof(uint16_t)
.
然后您可以通过调用相关的 BPF 辅助函数从您的 BPF 程序 read/write:bpf_map_lookup_elem()
或 bpf_map_update_elem()
(有关详细信息,请参阅 man page)。它们通常在 bpf_helpers.h
中定义,通常不会安装在您的系统上,您可以在 bcc 或内核 repo 中找到它的版本。
从用户 space,您可以使用 bpf()
系统调用及其相关命令更新条目:BPF_MAP_LOOKUP_ELEM()
和 BPF_MAP_UPDATE_ELEM()
(请参阅 man page). But you don't necessarily have to re-implement the calls yourself: if you write a program, you should probably have a look at libbpf that provides wrappers. If you want to update your map from the command line, this is easy to do with bpftool
(see man page),类似于 bpftool map <map_ref> update key 0 0 0 0 value 0x37 0x13
(更新)或 bpftool map <map_ref> lookup key 0 0 0 0
(查找)。