c - 像 "bpf_map_update_elem"这样的bps API map 助手的详细过程是什么?

标签 c linux ebpf

据我了解,当用户空间使用 bpf_map_update_elem(int fd, void *key, void *value, __u64 flags),

首先,用户空间通过fd找到 map ;

第二,用户空间在用户空间创建一个内存;

还有......

知道一点,但具体流程还不清楚。

所以我想知道用户空间运行 API map 助手时的详细信息。

最佳答案

因为你提到“用户空间”,我不确定你到底在说什么。因此,让我们首先进行一些澄清。

BPF 映射(或者至少大多数现有类型,包括 HashMap 和数组)可以通过两种方式访问​​:

  • 来自用户空间,由系统上运行且具有足够权限的任何应用程序实现
  • 来自内核空间,来自 BPF 程序

从用户空间来看,没有“帮助程序”功能。与 map 的交互完全 (*) 通过 bpf() 完成系统调用(将 BPF_MAP_LOOKUP_ELEMBPF_MAP_UPDATE_ELEMBPF_MAP_DELETE_ELEM 命令传递给系统调用作为其第一个参数)。请参阅bpf(2)手册页了解更多详细信息。这就是您在加载和管理 BPF 程序和映射的用户空间应用程序中使用的内容,例如 bpftool例如。

从内核空间,即从 BPF 程序,事情的工作方式有所不同,并且访问是通过 BPF“助手”之一完成的,例如 bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) 。请参阅bpf-helpers(7)有关现有助手的详细信息的手册页。您可以在 Cilium guide 中找到有关这些帮助程序调用的详细信息。 ,或者显然通过阅读内核代码(例如 for array maps )。它们看起来像低级 C 函数调用,使用 BPF 寄存器传递必要的参数,然后从 BPF 程序指令调用到编译为内核二进制文件一部分的帮助程序。

所以你提到了bpf_map_update_elem()和用户空间。虽然这是内核端帮助程序的名称,但我怀疑您可能正在谈论 libbpf 库提供的同名函数,以提供 wrapper around the bpf() system call 。所以这个函数发生的事情相当简单。

  • 不需要从用户空间的文件描述符中查找映射:实际上相反的情况发生,文件描述符是从用户空间的映射中打开的(从其映射ID,或从其/sys下的固定路径)例如/fs/bpf 虚拟文件系统)。所以fd被传递到bpf()系统调用并被内核用作对映射的引用。
  • 我不确定你的意思,但“用户空间在用户空间中创建内存”。这里不需要分配任何内存:keyvalue此时应该已经被填充,并且它们通过bpf()传递到内核。系统调用来告诉要更新哪些条目以及更新什么值。旗帜也是如此。
  • 一次bpf()已经被调用了,内核端发生的事情相当简单。主要是内核 check permissions ,验证参数(以确保它们安全且与 map 一致),然后更新实际数据。对于数组映射,array_map_update_elem() (也与内核端的 BPF 帮助器一起使用,请参阅上面的链接)最终被调用。

(*) 某些交互实际上可能在没有 bpf() 的情况下完成系统调用,我相信通过存储在 BPF 映射中的“全局数据”,使用应用程序 mmap()到内核​​内存。但这超出了数组和映射的基本使用范围。

关于c - 像 "bpf_map_update_elem"这样的bps API map 助手的详细过程是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59782101/

相关文章:

每种类型的 ebpf 程序的上下文

c - 尝试加载 BPF 程序时参数无效 (EINVAL)

c - 什么时候将内存分配给C中的局部变量

linux - 如何制作 Bash 函数来终止访问端口的进程

python - 如果从源代码构建 BCC 后 "sudo/usr/share/bcc/tools/execsnoop"失败,我该怎么办?

linux - 为 ARM 架构使用 objdump : Disassembling to ARM

linux - 将驱动程序添加到 Yocto 树莓派镜像

c - 确定每个元素在数组中出现的频率?

在 C 中将 long long 转换为字符串?

c - 在C中,是否保证数组起始地址小于其他元素的地址?