BPF 二进制文件:BTF、CO-RE 和 BPF 性能工具的未来

BTF 和 CO-RE 两项新技术正在为 BPF 成为价值十亿美元的产业铺平道路。现在有许多 BPF (eBPF) 初创公司构建网络、安全和性能产品(以及更多隐蔽产品),但要求客户安装 LLVM、Clang 和内核头依赖项——这可能会消耗超过 100 MB 的存储空间——是收养拖累。BTF 和 CO-RE 在运行时消除了这些依赖关系,不仅使 BPF 在嵌入式 Linux 环境中更实用,而且在任何地方都可以采用。
这些技术是:
BTF:BPF 类型格式,提供结构信息以避免需要 Clang 和内核头文件。
CO-RE:BPF Compile-Once Run-Everywhere,它允许编译后的 BPF 字节码可重定位,避免 LLVM 重新编译的需要。
编译仍然需要 Clang 和 LLVM,但结果是一个轻量级的 ELF 二进制文件,其中包含预编译的 BPF 字节码,可以在任何地方运行。BCC 项目有一个集合,称为libbpf 工具。例如,我移植了我的 opensnoop(8) 工具:

./opensnoop

PID COMM FD ERR 路径
27974 打开窥探 28 0 /etc/localtime
1482 redis服务器7 0 /proc/1482/stat
1657 atlas-system-ag 3 0 /proc/stat
[…]
这个 opensnoop(8) 是一个不使用 libLLVM 或 libclang 的 ELF 二进制文件:
#文件打开窥探
opensnoop:ELF 64 位 LSB 共享对象,x86-64,版本 1 (SYSV),动态链接,解释器 /lib64/l,适用于 GNU/Linux 3.2.0,BuildID[sha1]=b4b5320c39e5ad2313e8a371baf5e8241bb4e4ed,带 debug_info,未剥离

ldd opensnoop

linux-vdso.so.1 (0x00007ffddf3f1000)
libelf.so.1 => /usr/lib/x86_64-linux-gnu/libelf.so.1 (0x00007f9fb7836000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f9fb7619000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9fb7228000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9fb7c76000)

ls -lh opensnoop opensnoop.stripped

-rwxr-xr-x 1 root root 645K Feb 28 23:18 opensnoop
-rwxr-xr-x 1 根 151K 2 月 28 日 23:33 opensnoop.stripped
…剥离后只有 151 KB。
现在想象一个 BPF 产品:不再要求客户安装各种重量级(和脆弱的)依赖项,BPF 代理现在可能是一个可以在任何具有 BTF 的内核上工作的小型二进制文件。
这是如何工作的
这不仅仅是将 BPF 字节码保存在 ELF 中然后将其发送到任何其他内核的问题。许多 BPF 程序会遍历内核结构,这些结构可以从一个内核版本更改为另一个内核版本。你的 BPF 字节码可能仍然在不同的内核上执行,但它可能会读取错误的结构偏移量并打印垃圾输出!opensnoop(8) 不会遍历内核结构,因为它检测稳定的跟踪点及其参数,但许多其他工具可以。
这是一个relocation问题,BTF 和 CO-RE 都为 BPF 二进制文件解决了这个问题。BTF 提供类型信息,以便可以根据需要查询结构偏移量和其他详细信息,并且 CO-RE 记录 BPF 程序的哪些部分需要重写,以及如何重写。CO-RE 开发人员 Andrii Nakryiko 写了长篇文章更深入地解释了这一点:BPF Portability and CO-RE and BTF Type Information。
CONFIG_DEBUG_INFO_BTF=y
这些新的 BPF 二进制文件只有在设置了这个内核配置选项时才有可能。它为内核映像增加了大约 1.5 MB(与 DWARF debuginfo 相比,它可能是数百 MB)。Ubuntu 20.10 已经将此配置选项设为默认值,所有其他发行版都应遵循。发行版维护者注意:它需要 pahole >= 1.16。
BPF 性能工具、BCC Python 和 bpftrace 的未来
对于 BPF 性能工具,您应该从运行BCC和bpftrace工具开始,然后在 bpftrace 中进行编码。BCC 工具最终应该在底层从 Python 切换到 libbpf C,但工作方式相同。BCC Python 中的编码性能工具现在被认为已弃用,因为我们转向带有 BTF 和 CO-RE 的 libbpf C(尽管我们仍有库工作要做,例如 USDT 支持,因此暂时需要 Python 版本)。请注意,还有其他 BCC 用例可能会继续使用 Python 接口;BPF 共同维护者 Alexei Starovoitov 和我本人在iovisor-dev上简要讨论了这个问题。
我的BPF 性能工具书专注于在 bpftrace 中运行 BCC 工具和编码,这并没有改变。但是,附录 C 的 Python 编程示例现在被视为已弃用。造成的不便,深表歉意。幸运的是,这本 880 页的书中只有 15 页的附录材料。
bpftrace 呢?它确实支持 BTF,并且在未来我们也在考虑减少它的安装占用空间(它目前可以达到29 MB,我们认为它可以变得更小)。给定平均 229 KB 的 libbpf 程序大小(基于当前的 libbpf 工具,已剥离)和 1 KB 的平均 bpftrace 程序大小(我的书工具),大量 bpftrace 工具和 bpftrace 二进制文件可能会变成更小的安装足迹比 libbpf 中的等价物。此外,可以即时修改 bpftrace 版本。libbpf 更适合需要自定义参数和库的更复杂和成熟的工具。
如截图所示,BPF 性能工具的未来是这样的:

ls /usr/share/bcc/tools /usr/sbin/*.bt

argdist drsnoop mdflush pythongc tclobjnew
bashreadline execsnoop memleak pythonstat tclstat
[…]
/usr/sbin/bashreadline.bt /usr/sbin/mdflush.bt /usr/sbin/tcpaccept.bt
/usr/sbin/biolatency.bt /usr/sbin/naptime.bt /usr/sbin/tcpconnect.bt
[…]
… 和这个:

bpftrace -e ‘BEGIN { printf(“Hello, World!\n”); }’

连接 1 个探头…
你好世界!
^C
…而不是这个:
#!/usr/bin/python

从密件抄送导入 BPF
从 bcc.utils 导入 printb

编 = “”"
诠释你好(无效*ctx){
bpf_trace_printk(“你好,世界!\n”);
返回0;
}
“”"
[…]
感谢 Yonghong Song (Facebook) 领导 BTF 的开发、Andrii Nakryiko (Facebook) 领导 CO-RE 的开发,以及所有参与实现这一目标的人。

BPF 二进制文件:BTF、CO-RE 和 BPF 性能工具的未来
BTF 和 CO-RE 两项新技术正在为 BPF 成为价值十亿美元的产业铺平道路。现在有许多 BPF (eBPF) 初创公司构建网络、安全和性能产品(以及更多隐蔽产品),但要求客户安装 LLVM、Clang 和内核头依赖项——这可能会消耗超过 100 MB 的存储空间——是收养拖累。BTF 和 CO-RE 在运行时消除了这些依赖关系,不仅使 BPF 在嵌入式 Linux 环境中更实用,而且在任何地方都可以采用。
这些技术是:
BTF:BPF 类型格式,提供结构信息以避免需要 Clang 和内核头文件。
CO-RE:BPF Compile-Once Run-Everywhere,它允许编译后的 BPF 字节码可重定位,避免 LLVM 重新编译的需要。
编译仍然需要 Clang 和 LLVM,但结果是一个轻量级的 ELF 二进制文件,其中包含预编译的 BPF 字节码,可以在任何地方运行。BCC 项目有一个集合,称为libbpf 工具。例如,我移植了我的 opensnoop(8) 工具:

./opensnoop

PID COMM FD ERR 路径
27974 打开窥探 28 0 /etc/localtime
1482 redis服务器7 0 /proc/1482/stat
1657 atlas-system-ag 3 0 /proc/stat
[…]
这个 opensnoop(8) 是一个不使用 libLLVM 或 libclang 的 ELF 二进制文件:
#文件打开窥探
opensnoop:ELF 64 位 LSB 共享对象,x86-64,版本 1 (SYSV),动态链接,解释器 /lib64/l,适用于 GNU/Linux 3.2.0,BuildID[sha1]=b4b5320c39e5ad2313e8a371baf5e8241bb4e4ed,带 debug_info,未剥离

ldd opensnoop

linux-vdso.so.1 (0x00007ffddf3f1000)
libelf.so.1 => /usr/lib/x86_64-linux-gnu/libelf.so.1 (0x00007f9fb7836000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f9fb7619000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9fb7228000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9fb7c76000)

ls -lh opensnoop opensnoop.stripped

-rwxr-xr-x 1 root root 645K Feb 28 23:18 opensnoop
-rwxr-xr-x 1 根 151K 2 月 28 日 23:33 opensnoop.stripped
…剥离后只有 151 KB。
现在想象一个 BPF 产品:不再要求客户安装各种重量级(和脆弱的)依赖项,BPF 代理现在可能是一个可以在任何具有 BTF 的内核上工作的小型二进制文件。
这是如何工作的
这不仅仅是将 BPF 字节码保存在 ELF 中然后将其发送到任何其他内核的问题。许多 BPF 程序会遍历内核结构,这些结构可以从一个内核版本更改为另一个内核版本。你的 BPF 字节码可能仍然在不同的内核上执行,但它可能会读取错误的结构偏移量并打印垃圾输出!opensnoop(8) 不会遍历内核结构,因为它检测稳定的跟踪点及其参数,但许多其他工具可以。
这是一个relocation问题,BTF 和 CO-RE 都为 BPF 二进制文件解决了这个问题。BTF 提供类型信息,以便可以根据需要查询结构偏移量和其他详细信息,并且 CO-RE 记录 BPF 程序的哪些部分需要重写,以及如何重写。CO-RE 开发人员 Andrii Nakryiko 写了长篇文章更深入地解释了这一点:BPF Portability and CO-RE and BTF Type Information。
CONFIG_DEBUG_INFO_BTF=y
这些新的 BPF 二进制文件只有在设置了这个内核配置选项时才有可能。它为内核映像增加了大约 1.5 MB(与 DWARF debuginfo 相比,它可能是数百 MB)。Ubuntu 20.10 已经将此配置选项设为默认值,所有其他发行版都应遵循。发行版维护者注意:它需要 pahole >= 1.16。
BPF 性能工具、BCC Python 和 bpftrace 的未来
对于 BPF 性能工具,您应该从运行BCC和bpftrace工具开始,然后在 bpftrace 中进行编码。BCC 工具最终应该在底层从 Python 切换到 libbpf C,但工作方式相同。BCC Python 中的编码性能工具现在被认为已弃用,因为我们转向带有 BTF 和 CO-RE 的 libbpf C(尽管我们仍有库工作要做,例如 USDT 支持,因此暂时需要 Python 版本)。请注意,还有其他 BCC 用例可能会继续使用 Python 接口;BPF 共同维护者 Alexei Starovoitov 和我本人在iovisor-dev上简要讨论了这个问题。
我的BPF 性能工具书专注于在 bpftrace 中运行 BCC 工具和编码,这并没有改变。但是,附录 C 的 Python 编程示例现在被视为已弃用。造成的不便,深表歉意。幸运的是,这本 880 页的书中只有 15 页的附录材料。
bpftrace 呢?它确实支持 BTF,并且在未来我们也在考虑减少它的安装占用空间(它目前可以达到29 MB,我们认为它可以变得更小)。给定平均 229 KB 的 libbpf 程序大小(基于当前的 libbpf 工具,已剥离)和 1 KB 的平均 bpftrace 程序大小(我的书工具),大量 bpftrace 工具和 bpftrace 二进制文件可能会变成更小的安装足迹比 libbpf 中的等价物。此外,可以即时修改 bpftrace 版本。libbpf 更适合需要自定义参数和库的更复杂和成熟的工具。
如截图所示,BPF 性能工具的未来是这样的:

ls /usr/share/bcc/tools /usr/sbin/*.bt

argdist drsnoop mdflush pythongc tclobjnew
bashreadline execsnoop memleak pythonstat tclstat
[…]
/usr/sbin/bashreadline.bt /usr/sbin/mdflush.bt /usr/sbin/tcpaccept.bt
/usr/sbin/biolatency.bt /usr/sbin/naptime.bt /usr/sbin/tcpconnect.bt
[…]
… 和这个:

bpftrace -e ‘BEGIN { printf(“Hello, World!\n”); }’

连接 1 个探头…
你好世界!
^C
…而不是这个:
#!/usr/bin/python

从密件抄送导入 BPF
从 bcc.utils 导入 printb

编 = “”"
诠释你好(无效*ctx){
bpf_trace_printk(“你好,世界!\n”);
返回0;
}
“”"
[…]
感谢 Yonghong Song (Facebook) 领导 BTF 的开发、Andrii Nakryiko (Facebook) 领导 CO-RE 的开发,以及所有参与实现这一目标的人。

BPF 二进制文件:BTF、CO-RE 和 BPF 性能工具的未来
BTF 和 CO-RE 两项新技术正在为 BPF 成为价值十亿美元的产业铺平道路。现在有许多 BPF (eBPF) 初创公司构建网络、安全和性能产品(以及更多隐蔽产品),但要求客户安装 LLVM、Clang 和内核头依赖项——这可能会消耗超过 100 MB 的存储空间——是收养拖累。BTF 和 CO-RE 在运行时消除了这些依赖关系,不仅使 BPF 在嵌入式 Linux 环境中更实用,而且在任何地方都可以采用。
这些技术是:
BTF:BPF 类型格式,提供结构信息以避免需要 Clang 和内核头文件。
CO-RE:BPF Compile-Once Run-Everywhere,它允许编译后的 BPF 字节码可重定位,避免 LLVM 重新编译的需要。
编译仍然需要 Clang 和 LLVM,但结果是一个轻量级的 ELF 二进制文件,其中包含预编译的 BPF 字节码,可以在任何地方运行。BCC 项目有一个集合,称为libbpf 工具。例如,我移植了我的 opensnoop(8) 工具:

./opensnoop

PID COMM FD ERR 路径
27974 打开窥探 28 0 /etc/localtime
1482 redis服务器7 0 /proc/1482/stat
1657 atlas-system-ag 3 0 /proc/stat
[…]
这个 opensnoop(8) 是一个不使用 libLLVM 或 libclang 的 ELF 二进制文件:
#文件打开窥探
opensnoop:ELF 64 位 LSB 共享对象,x86-64,版本 1 (SYSV),动态链接,解释器 /lib64/l,适用于 GNU/Linux 3.2.0,BuildID[sha1]=b4b5320c39e5ad2313e8a371baf5e8241bb4e4ed,带 debug_info,未剥离

ldd opensnoop

linux-vdso.so.1 (0x00007ffddf3f1000)
libelf.so.1 => /usr/lib/x86_64-linux-gnu/libelf.so.1 (0x00007f9fb7836000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f9fb7619000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9fb7228000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9fb7c76000)

ls -lh opensnoop opensnoop.stripped

-rwxr-xr-x 1 root root 645K Feb 28 23:18 opensnoop
-rwxr-xr-x 1 根 151K 2 月 28 日 23:33 opensnoop.stripped
…剥离后只有 151 KB。
现在想象一个 BPF 产品:不再要求客户安装各种重量级(和脆弱的)依赖项,BPF 代理现在可能是一个可以在任何具有 BTF 的内核上工作的小型二进制文件。
这是如何工作的
这不仅仅是将 BPF 字节码保存在 ELF 中然后将其发送到任何其他内核的问题。许多 BPF 程序会遍历内核结构,这些结构可以从一个内核版本更改为另一个内核版本。你的 BPF 字节码可能仍然在不同的内核上执行,但它可能会读取错误的结构偏移量并打印垃圾输出!opensnoop(8) 不会遍历内核结构,因为它检测稳定的跟踪点及其参数,但许多其他工具可以。
这是一个relocation问题,BTF 和 CO-RE 都为 BPF 二进制文件解决了这个问题。BTF 提供类型信息,以便可以根据需要查询结构偏移量和其他详细信息,并且 CO-RE 记录 BPF 程序的哪些部分需要重写,以及如何重写。CO-RE 开发人员 Andrii Nakryiko 写了长篇文章更深入地解释了这一点:BPF Portability and CO-RE and BTF Type Information。
CONFIG_DEBUG_INFO_BTF=y
这些新的 BPF 二进制文件只有在设置了这个内核配置选项时才有可能。它为内核映像增加了大约 1.5 MB(与 DWARF debuginfo 相比,它可能是数百 MB)。Ubuntu 20.10 已经将此配置选项设为默认值,所有其他发行版都应遵循。发行版维护者注意:它需要 pahole >= 1.16。
BPF 性能工具、BCC Python 和 bpftrace 的未来
对于 BPF 性能工具,您应该从运行BCC和bpftrace工具开始,然后在 bpftrace 中进行编码。BCC 工具最终应该在底层从 Python 切换到 libbpf C,但工作方式相同。BCC Python 中的编码性能工具现在被认为已弃用,因为我们转向带有 BTF 和 CO-RE 的 libbpf C(尽管我们仍有库工作要做,例如 USDT 支持,因此暂时需要 Python 版本)。请注意,还有其他 BCC 用例可能会继续使用 Python 接口;BPF 共同维护者 Alexei Starovoitov 和我本人在iovisor-dev上简要讨论了这个问题。
我的BPF 性能工具书专注于在 bpftrace 中运行 BCC 工具和编码,这并没有改变。但是,附录 C 的 Python 编程示例现在被视为已弃用。造成的不便,深表歉意。幸运的是,这本 880 页的书中只有 15 页的附录材料。
bpftrace 呢?它确实支持 BTF,并且在未来我们也在考虑减少它的安装占用空间(它目前可以达到29 MB,我们认为它可以变得更小)。给定平均 229 KB 的 libbpf 程序大小(基于当前的 libbpf 工具,已剥离)和 1 KB 的平均 bpftrace 程序大小(我的书工具),大量 bpftrace 工具和 bpftrace 二进制文件可能会变成更小的安装足迹比 libbpf 中的等价物。此外,可以即时修改 bpftrace 版本。libbpf 更适合需要自定义参数和库的更复杂和成熟的工具。
如截图所示,BPF 性能工具的未来是这样的:

ls /usr/share/bcc/tools /usr/sbin/*.bt

argdist drsnoop mdflush pythongc tclobjnew
bashreadline execsnoop memleak pythonstat tclstat
[…]
/usr/sbin/bashreadline.bt /usr/sbin/mdflush.bt /usr/sbin/tcpaccept.bt
/usr/sbin/biolatency.bt /usr/sbin/naptime.bt /usr/sbin/tcpconnect.bt
[…]
… 和这个:

bpftrace -e ‘BEGIN { printf(“Hello, World!\n”); }’

连接 1 个探头…
你好世界!
^C
…而不是这个:
#!/usr/bin/python

从密件抄送导入 BPF
从 bcc.utils 导入 printb

编 = “”"
诠释你好(无效*ctx){
bpf_trace_printk(“你好,世界!\n”);
返回0;
}
“”"
[…]

感谢 Yonghong Song (Facebook) 领导 BTF 的开发、Andrii Nakryiko (Facebook) 领导 CO-RE 的开发,以及所有参与实现这一目标的人。