第 4 章 bpf() 系统调用
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
正如你在第1章中所看到的,当用户空间应用程序希望内核代表它们做一些事情时,它们会使用系统调用API提出请求。因此,如果用户空间应用程序想要将 eBPF 程序加载到内核中,就必须涉及一些系统调用。事实上,有一个名为bpf() 的系统调用,在本章中,我将向你展示如何使用它来加载 eBPF 程序和映射并与之交互。
值得注意的是,内核中运行的 eBPF 代码不使用系统调用访问映射。只有用户空间应用程序才使用系统调用接口。相反,eBPF 程序使用辅助函数来读写映射;在前两章中,我们已经看到了这方面的例子。
如果你要自己编写 eBPF 程序,很有可能不会直接调用这些bpf() 系统调用。我将在本书后面讨论一些库,它们提供了更高级别的抽象,让事情变得更简单。尽管如此,这些抽象通常会直接映射到你在本章中看到的底层系统调用命令。无论使用哪种库,你都需要掌握本章将介绍的底层操作--加载程序、创建和访问映射等。
在向大家展示bpf() 系统调用的示例之前,让我们先看看 bpf() 的手册是怎么说的,即bpf() 是用来 "在扩展的 BPF 映射或程序上执行命令 "的。它还告诉我们,bpf()的签名如下:
intbpf(intcmd,unionbpf_attr*attr,unsignedintsize);
bpf() 的第一个参数cmd 指定要执行的命令。bpf() 系统调用不只做一件事--有许多不同的命令可以用来操作 eBPF 程序和地图。图 4-1显示了用户空间代码可能使用的一些常用命令,这些命令用于加载 eBPF 程序、创建映射、将程序附加到事件以及访问映射中的键值对。
图 4-1. 用户空间程序通过系统调用与内核中的 eBPF 程序和映射进行交互
bpf() 系统调用的attr 参数包含指定命令参数所需的任何数据,而size 则表示attr 中的数据字节数。
在第 1 章中,我们已经认识了strace ,当时我用它来演示用户空间代码是如何在系统调用 API 中进行多次请求的。在本章中,我将用它来演示如何使用bpf() 系统调用。strace 的输出包括每个系统调用的参数,但为了使本章的示例输出不至于过于杂乱,我将省略attr 参数中的许多细节,除非它们特别有趣。
备注
你可以在github.com/lizrice/learning-ebpf 上找到代码,以及设置运行环境的说明。本章的代码位于chapter4目录中。
在本例中,我将使用一个名为hello-buffer-config.py 的 BCC 程序,它是在第 2 章示例的基础上编写的。与hello-buffer.py示例一样,这个程序每次运行都会向 perf buffer 发送一条信息,向用户空间传达内核关于execve() syscall 事件的信息。这个版本的新功能是允许为每个用户 ID 配置不同的信息。
下面是 eBPF 的源代码:
structuser_msg_t{charmessage[12];};BPF_HASH(config,u32,structuser_msg_t);BPF_PERF_OUTPUT ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access