2

eBPF中的vmlinux

 11 months ago
source link: https://blog.spoock.com/2023/08/27/eBPF-vmlinux/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在 BPF CO-RE 框架下,vmlinux.h 文件包含了内核的数据结构定义,这些定义是通过解析内核 BTF(BPF Type Format)信息自动生成的。BTF 是一种新的内核数据类型格式,它为内核提供了一种描述数据类型的方法,这对于 BPF CO-RE 的运行至关重要。
在编写 eBPF 程序时,vmlinux.h 文件使得开发者可以在用户空间程序中直接使用内核的数据结构,而无需关心内核版本的差异。这是因为 BPF CO-RE 可以在编译时解析这些数据结构,并生成可以在任何内核版本上运行的 eBPF 字节码。
例如,假设你在 eBPF 程序中需要访问 task_struct 结构,你可以在你的 eBPF 程序中包含 vmlinux.h,然后直接使用 struct task_struct

所以,vmlinux.h 是对于BPF CO-RE编程必不可少的文件。

vmlinux

vmlinux 是未压缩的 Linux 内核映像。它是在 Linux 内核编译过程中生成的一个文件,包含了整个内核的代码(包括内核模式和用户模式的代码)。vmlinux 包含了内核的符号表,因此它经常被用于调试目的。

vmlinux.h 是一个由 BPF CO-RE(Compile Once, Run Everywhere)框架自动生成的头文件。它包含了内核的数据结构定义,这些定义是通过解析 vmlinux 中的 BTF(BPF Type Format)信息自动生成的。

BTF 是一种新的内核数据类型格式,它为内核提供了一种描述数据类型的方法。通过 BTF,BPF CO-RE 可以解析 vmlinux 中的数据结构定义,并将这些定义写入 vmlinux.h 文件。

因此,vmlinuxvmlinux.h 之间的关系是:vmlinux.h 是通过解析 vmlinux 中的 BTF 信息生成的。vmlinux 包含了内核的代码和数据结构定义,而 vmlinux.h 包含了这些数据结构定义的副本,可以在编写 eBPF 程序时使用。

在编写 eBPF 程序时,vmlinux.h 文件使得开发者可以在用户空间程序中直接使用内核的数据结构,而无需关心内核版本的差异。这是因为 BPF CO-RE 可以在编译时解析这些数据结构,并生成可以在任何内核版本上运行的 eBPF 字节码。具体的原理结构图如下所是:

202308221532948.png

生成vmlinux.h文件

下面的命令是在Ubuntu 20.04上生成的,其他系统可能会有所不同。

安装bpftool

sudo apt install linux-tools-common

成功安装之后提示:

$bpftool --help
WARNING: bpftool not found for kernel 5.15.0-76

You may need to install the following packages for this specific kernel:
linux-tools-5.15.0-76-generic
linux-cloud-tools-5.15.0-76-generic

You may also want to install one of the following packages to keep up to date:
linux-tools-generic
linux-cloud-tools-generic

按照要求安装:

sudo apt install linux-tools-5.15.0-76-generic

生成vmlinux.h文件

bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

由于 vmlinux.h 文件是从本机安装的内核生成的,如果试在另一台运行不同内核版本的机器上运行它而不重新编译,程序可能会出现问题。这是因为在不同版本之间,Linux 源代码中的内部结构定义会发生变化。

然而,通过使用 libbpf,可以启用称为CO:RECompile once, run everywhere)的功能。在 libbpf 中定义了一些宏(例如 BPF_CORE_READ),它们将分析您在 vmlinux.h 中定义的类型中尝试访问的字段。如果您要访问的字段已经在运行内核使用的结构体定义中移动,这些宏/辅助函数将为您找到它。无论您是否使用从自己的内核生成的 vmlinux.h 文件编译 bpf 程序,然后在不同的内核上运行,都没有关系。

vmlinux.h的顶部还存在如下的宏定义:

#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)
#endif

__attribute__((preserve_access_index)) 是 Clang 编译器提供的一个属性,用于告诉编译器在生成代码时保留对结构体成员的访问索引。这个属性通常用于与 eBPF 相关的代码中,以确保结构体成员的访问索引在 eBPF 程序中保持一致。

#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
#pragma clang attribute pop
#endif

这个特性也会在最后一行被关闭。

在 Linux 中定义的宏并没有在 DWARF/BTF 中定义,并且不会成为生成的 vmlinux.h 文件的一部分。

https://yanhang.me/post/2021-vmlinux/
https://www.ebpf.top/post/intro_vmlinux_h/
https://www.grant.pizza/blog/vmlinux-header/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK