BTF:实践指南

本文地址:BTF:实践指南 | 深入浅出 eBPF

  • 1. BPF 的常见限制
    • 1.1 调试限制
    • 1.2 可移植性
  • 2. BTF 是什么?
  • 3. BTF 快速入门
    • 3.1 BPF 快速入门
    • 3.1 BTF 和 CO-RE
  • 4. 结论

BPF 是 Linux 内核中基于寄存器的虚拟机,可安全、高效和事件驱动的方式执行加载至内核的字节码。与内核模块不同,BPF 程序经过验证以确保它们终止并且不包含任何可能锁定内核的循环。BPF 程序允许调用的内核函数也受到限制,以确保最大的安全性以防止非法的访问。

尽管 BPF 为编写事件驱动的内核空间代码提供了一种有效的解决方案,但开发人员的体验仍无法与其他编程语言或框架相提并论。BPF 开发的两个最重要的问题是缺乏简单的调试和可移植性。

为了缓解这些问题,我们转向 BTF。BTF 是针对 BPF 程序的类型信息进行编码文件格式,通过 BPF 程序的类型信息进行编码,为程序提供更好的内省(introspection)和可见性。本文我们将介绍 BPF 的典型局限性以及如何使用 BTF 来克服。

请注意,本文使用术语 BPF 来表示 eBPF(扩展的 Berkeley 数据包过滤器),eBPF 扩展 “ 经典 ” cBPF。

1. BPF 的常见限制

在 BPF 程序的开发和运行过程中,我们会经常会面临调试限制和可移植性问题,如前所述。

1.1 调试限制

几乎所有现代编程语言都有对应的调试器,通过调试器可以帮助我们更好了解正在运行的程序。例如,GDB 是 C 和 C++ 的常用调试器,除其他外,基于 GDB 我们可以打印正在运行的程序中的变量值。

GDB 漂亮打印变量的屏幕截图

​ 图 GDB 变量打印

但是很不幸,BPF 程序并没有类似的这样的工具。尽管检查数据只是调试的一小部分,但为 BPF 实现类似的结果可以为未来的广泛调试工具打开一扇门。为了实现这一点,BPF 需要知道关于程序的相关的部分元数据。

这类关于类型信息的元数据,正是 BTF 封装的内容。

1.2 可移植性

BPF 程序在内核空间中运行,可以访问内部内核状态和数据结构。但是,并没有办法保证内核数据结构和类型在不同内核版本是相同的,甚至相同内核版本的不同机器之间也可能不同(这可能取决于内核编译选项)。这意味着在一台机器上编译的 BPF 程序并不能保证在另一台机器上正确运行。

假设 BPF 程序正在从内核结构中读取一个字段,该字段位于距结构开头的偏移量 8 处。现在在更高版本的内核中,在该变量之前添加了其他字段,导致访问的字段的偏移量变成了 24,这会导致 BPF 程序在偏移量 8 读取的数据可能为垃圾数据。类似情况,也可能会发生某些字段最终得到在后续内核版本中的重命名。例如,在内核版本 4.6 和 4.7 之间,thread_struct 的 fs 字段可能会重命名为 fsbase 。最后,还可能是因为配置禁用了某些功能并编译了部分结构,导致可能 BPF 程序在不同的内核配置上运行。

所有上述这些场景的存在,意味着你不能在当前机器上编译 BPF 程序并将二进制文件分发到其他系统。

一个标准的解决方案是使用 BPF Compiler Collection (BCC)。使用 BCC,你通常将 BPF 程序作为纯字符串嵌入到用户空间程序(例如,Python 程序)中。在目标机器上执行期间,BCC 使用其嵌入式 Clang/LLVM 组合并使用本地安装的内核头文件动态编译程序。

然而,这种方法引入了更多问题。首先,Clang/LLVM 组合非常庞大,将其嵌入到应用程序中会导致二进制文件大小过大。它还占用大量资源,并且会在编译期间耗尽大量资源。最后,这种方法需要在目标机器上安装内核头文件,但情况可能并非总是如此。

解决方案是 BPF CO-RE(一次编译 —— 随处运行)。使用 BTF,我们可以消除在目标机器上安装内核头文件或将 Clang/LLVM 嵌入应用程序并在目标机器上编译的需要。

2. BTF 是什么?

如前所述,BTF 是编码 BPF 程序和 map 结构等相关的调试信息的元数据格式。BTF 可以将元数据数据类型、函数信息和行信息编码成一种紧凑的格式。

在非 BPF 程序中,这些元数据通常使用 DWARF 格式存储。但是,DWARF 格式的实现还是相当复杂和冗长,并且由于其在大小方面的开销,使其不适合包含在内核中。而 BTF 是一种紧凑而简单的格式,让其可以包含在内核镜像中。

BTF 使用少数类型描述 符之一表示每种数据类型:

  • BTF_KIND_INT
  • BTF_KIND_PTR
  • BTF_KIND_ARRAY
  • BTF_KIND_STRUCT
  • 等等

类型信息存储在生成的 ELF 的 .BTF 部分中。除了类型描述符之外,此部分还对字符串进行编码。函数和行信息存储在 .BTF.ext 部分中。

关于 BTF 的详细说明,可以查看 Linux Kernel 文档。

3. BTF 快速入门

3.1 BPF 快速入门

现在让我们通过使用 BTF 漂亮地打印 BPF map 的教程进行更多实践,从而显著改进调试。

要开始,我们需要在启用 CONFIG_DEBUG_INFO_BTF 选项的情况下编译 Linux 内核。大多数发行版都启用了此选项,但你可以通过运行以下命令进行检查:

$ zgrep CONFIG_DEBUG_INFO_BTF=y /proc/config.gz
# 可选: grep CONFIG_DEBUG_INFO_BTF=y  /boot/config*

当然,我们还需要在计算机上安装 Clang 和 LLVM。

由于我们需要将编写 XDP 程序来处理网络设备上的数据包,因此创建一个虚拟网络接口 是个好主意,这样就不会最终失去物理接口中的互联网连接。设置虚拟接口的最简单方法是使用此 repo。

克隆 repo 并设置一个名为 test1 的虚拟接口:

$ git clone git@github.com:xdp-project/xdp-tutorial.git
$ cd xdp-tutorial/testenv
$ sudo ./testenv.sh setup --name=test1 --legacy-ip

现在编写一个 BPF 程序来计算接口上接收到的 IPv4 和 IPv6 数据包的数量。文件 xdp_count.c 的文件内容如下:

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>struct bpf_map_def SEC("maps") cnt = {.type = BPF_MAP_TYPE_ARRAY,.key_size = sizeof(__u32),.value_size = sizeof(long),.max_entries = 2,
};SEC("xdp_count")
int xdp_count_prog(struct xdp_md *ctx)
{void *data_end = (void *)(long)ctx->data_end;void *data = (void *)(long)ctx->data;__u32 ipv6_key = 0;__u32 ipv4_key = 1;long *value;__u16 h_proto;struct ethhdr *eth = data;if (data + sizeof(struct ethhdr) > data_end) // This check is necessary to pass verificationreturn XDP_DROP;h_proto = eth->h_proto;if (h_proto == htons(ETH_P_IPV6)) { // Check if IPv6 packetvalue = bpf_map_lookup_elem(&cnt, &ipv6_key);if (value)*value += 1;return XDP_PASS;}value = bpf_map_lookup_elem(&cnt, &ipv4_key);if (value)*value += 1;return XDP_PASS;}char _license[] SEC("license") = "GPL";

在前面的代码中,名为 cnt 的 BPF map 存储数据包的数量。cnt 是两个元素的数组。IPv6 数据包的数量存储在 key 0 中,IPv4 数据包的数量存储在 key 1 中。

使用 Clang 编译代码:

$ clang -O2 -Wall -g -target bpf -c xdp_count.c -o xdp_count.o

接下来,使用 bpftool 加载程序:

$ sudo bpftool prog load xdp_count.o /sys/fs/bpf/xdp_count type xdp

运行以下命令并记下我们刚加载的程序的 ID 和程序正在使用的 map 的 ID:

$ sudo bpftool prog list

Output of bpftool prog list

​ 图 bpftool prog 列表的输出

我们还可以通过运行 sudo bpftool map list 来获取 map ID。

Output of the bpftool map list command

​ 图 bpftool map list 的内容输出

此命令为我们提供 map 的名称、类型、键大小、值大小和最大条目数。

现在,将 BPF 程序附加到网络设备。

$ sudo bpftool net attach xdpgeneric id <program_id> dev test1

将 program_id 替换为程序的 ID,并将 device_name 替换为程序附加到的网络设备的名称(例如 enp34s0)。

现在,向该设备发送一些数据包。测试环境脚本已经提供了一个方便的 ping 命令来执行此操作:

$ sudo ./testenv.sh ping # For IPv6
$ sudo ./testenv.sh ping --legacy-ip # For IPv4

打印 map 并检查处理的数据包情况:

$ sudo bpftool map dump id <map_id>

The dumped value of the map

​ 图 map 的打印值

如图所示,map 中有两个预期的元素。这些值采用十六进制格式,并且还取决于运行机器的字节顺序。在截图中,它是小端格式,这意味着已经处理了 22 个 IPv6 和 4 个 IPv4 数据包。

很明显,结果是十六进制的,小端格式,一看就不好调试。因此,我们需要使用 BTF 对 map 进行注释,以便更好地展示。

如下更改 cnt 的声明并将新代码保存在 xdp_count_btf.c 中 -

...
struct {__uint(type, BPF_MAP_TYPE_ARRAY);__type(key, __u32);__type(value, long);__uint(max_entries, 2);
} cnt SEC(".maps");
...

请注意,部分名称现在为 .maps,并且地图本身已使用启用 BTF 的宏 __uint 和 __type 进行了注释。

使用 Clang 编译代码:

clang -O2 -Wall -g -target bpf -c xdp_count_btf.c -o xdp_count_btf.o

使用 -g 标志将创建调试信息并生成 BTF。请注意,之前也使用了 -g 标志,因为 libbpf需要它 来加载程序;然而,以前 map 没有被 BTF 注释,所以 bpftool 不能够优雅地进行打印。

验证 BTF 部分是否存在于生成的目标文件中。

$ llvm-objdump -h xdp_count_btf.o

Output of llvm-objdump

​ 图 llvm-objdump 的输出

如前所述,.BTF 部分包含类型和字符串数据,.BTF.ext 部分对 func_info 和 line_info 数据进行编码。

首先,卸载前面的 BPF 程序。

1
$ sudo bpftool net detach xdpgeneric dev test1

然后按照类似的过程加载新程序并将其附加到接口,然后对接口发送一些数据:

$ sudo bpftool prog load xdp_count_btf.o /sys/fs/bpf/xdp_count_btf type xdp
$ sudo bpftool prog list
$ sudo bpftool net attach xdpgeneric id <program_id> dev test1
$ sudo ./testenv.sh ping
$ sudo ./testenv.sh ping --legacy-ip

最后,打印新程序对应的 map 。如果一切顺利,这一次的输出会有很大的不同。

映射的转储值

​ 图 map 的结构的打印值

它不仅以 JSON 格式打印得很漂亮,而且值也是十进制的,使其更具可读性和易懂性。

3.1 BTF 和 CO-RE

如前所述,BTF 可以启用 CO-RE 使 BPF 程序可移植到不同的内核版本或用户配置。我们也可以通过生成内核本身的 BTF 信息来消除对本地内核头文件的需求:

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

上述命令将创建一个巨大的 vmlinux.h 文件,其中包含所有内核类型,包括作为 UAPI 的一部分公开的类型、内部类型和通过 kernel-devel 可用的类型,以及一些其他地方不可用的更多内部类型。在 BPF 程序中,我们可以只 #include "vmlinux.h" 并删除其他内核头文件,如 <linux/fs.h>、<linux/sched.h>等。

摆脱内核头文件依赖性只是 BTF 可以实现的目标的冰山一角。如需 BTF 和 CO-RE 的详尽解释,可以阅读这篇文章。

4. 结论

BTF 是一个非常强大的工具,可以使 BPF 程序更易于调试和移植。由于它是一项相对较新的技术,因此开发仍在进行中,你可以期待在未来看到大量改进。

本文让你大致了解 BTF 可以实现什么。你可能已经了解了 BPF 的缺点、BPF 是什么以及如何使用 BTF 注解 map 和打印 map 结构。最后,你还了解了 BTF 如何充当通过 CO-RE 增强可移植性的起点。

原文地址:https://www.containiq.com/post/btf-bpf-type-format

作者:Aniket Bhattacharyea

时间: July 13, 2022

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python 混入类MixIn

写在前面 能把一件事情说的那么清楚明白&#xff0c;感谢廖雪峰的官方网站。 1.为什么要用混入类&#xff1f;&#xff08;小白入门&#xff09; 继承是面向对象编程的一个重要的方式&#xff0c;因为通过继承&#xff0c;子类就可以扩展父类的功能。 step1: 回忆一下Animal类层…

估计很多前端都没学过单元测试~

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。已进行四个月了&#xff0c;很多小伙伴表示收获颇丰。想学源码&#xff0c;极力推荐订阅我写的《学习…

xd可以用ui动效效果吗_通过动画使UI设计栩栩如生:Adobe XD和After Effects

xd可以用ui动效效果吗Note — If you don’t fancy splashing out on an Adobe license, you can trial their products for 14 days each. That should give you more than enough time to play, check it out.注意—如果您不愿意花钱购买Adobe许可证&#xff0c;则可以分别试…

第十二周编程总结

这个作业属于那个课程C语言程序设计II这个作业要求在哪里https://pintia.cn/problem-sets/1127748174659035136/problems/1127749414029729792我在这个课程的目标是更好的学习函数这个作业在那个具体方面帮助我实现目锻炼了我的编程能力参考文献c语言程序设计26-1 计算最长的字…

可能是全网首个前端源码共读活动,诚邀加入学习

大家好&#xff0c;我是若川。从8月份到现在11月结束了。每周一期&#xff0c;一起读200行左右的源码&#xff0c;撰写辅助文章&#xff0c;截止到现在整整4个月了。由写有《学习源码整体架构系列》20余篇的若川【若川视野公众号号主】倾力组织&#xff0c;召集了各大厂对于源码…

现代游戏中的UX趋势

ux设计中的各种地图游戏UX (GAMES UX) Even though websites and games have matured side-by-side over the past few decades, games have a long and detailed history of user experience. Sure, it was scrappy and fairly rudimentary initially, but the only way you c…

你提交代码前没有校验?巧用gitHooks解决

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。已进行四个月了&#xff0c;很多小伙伴表示收获颇丰。想学源码&#xff0c;极力推荐订阅我写的《学习…

Linux下自动化测试环境的搭建

1.安装Linux虚拟机&#xff0c;详情参考 https://blog.csdn.net/qq_22770715/article/details/78558374 https://www.cnblogs.com/Q277227/p/8176564.html 1.1 需要确定IP &#xff0c;使用 ifconfig 1.2 linux的用户名跟密码&#xff1b; 1.3 确定可以远程ssh登录&…

code craft_以Craft.io为先—关于我们行业的实践职业道路的系列

code craft重点 (Top highlight)For the past two decades, digital product design / UX has been shifting to become a more strategic discipline within organizations. Partially because business leaders have started to pay attention to how design-driven companie…

Nginx+httpd反代实现动静分离

什么是动静分离为了提高网站的响应速度&#xff0c;减轻程序服务器&#xff08;apachephp&#xff0c;nginxphp等&#xff09;的负载&#xff0c;对于静态资源比如图片&#xff0c;js&#xff0c;css&#xff0c;html等静态文件&#xff0c;我们可以在反向代理服务器中设置&…

(建议收藏)前端面试必问的十六条HTTP网络知识体系

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。已进行四个月了&#xff0c;很多小伙伴表示收获颇丰。想学源码&#xff0c;极力推荐订阅我写的《学习…

多边形的时针方向与法线方向

从相反的法线方向观察&#xff0c;顺时针还是逆时针是相反的。 多边形的时针方向与法线方向的关系呈右手法则关系。 GoogleEarth中的面具有时针方向&#xff0c;法线方向为正向&#xff0c;反之为负向 GoogleEarth的垂面在法线方向为亮色&#xff0c;反向为暗色 GoogleEarth的水…

裂墙推荐!再也不用求后端给接口了...

大家好&#xff0c;我是若川。今天咱们来介绍一款强大的云服务平台&#xff01;MemFire Cloud注册即享5GB存储空间、每月100万读额度和每月10万写额度。平台入口&#xff1a;https://memfiredb.com/今天&#xff08;12月10号&#xff09;还有限时的送书活动&#xff01;感兴趣的…

1.今日标签:视频价值一千字

I love the App Store. It looks and works better than ever. But also, I love tricky design challenges. How do you improve something that already works great?我喜欢App Store。 它的外观和工作比以往更好。 但是我也很棘手 设计挑战。 您如何改善已经很好的工作&a…

蚂蚁金服疯了吗?大动作,非裁员,年底全员涨薪又涨假期!!!

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。以下分享一篇水文&#…

书呆子rico_寻找设计和类型书呆子的清道夫

书呆子ricoI studied graphic design at an art school where typography was a core focus. I took 3 levels of typography classes and nearly lost my mind! But even before I studied type, I had a soft spot for signage. It’s one of the themes I enjoy shooting mo…

WebStorm 和 VsCode 的结合体来了!

大家好&#xff0c;我是若川。最近组织了源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。周末分享下简单的文章~每…

设计的概念以及含义_什么是设计概念? 以及为什么您应该始终从一个开始

设计的概念以及含义We work on designs almost every day, and we use different design methods to make the design usable, aesthetically appealing, and likable. But, many times, those well-crafted designs fail to reach a level to become market differentiator or…

netflix 工作原理_Netflix如何在屏幕后面工作?

netflix 工作原理Netflix has reported to have over 182 million subscribers worldwide in the first quarter of 2020 (Of course, these numbers don’t include freeloaders like me, who’s family or friends have been generous enough to share their account and pas…

B/S开发中浏览器的工具利器

B/S系统的前端浏览器性能和标准兼容方面是开发中的一个重要问题&#xff0c;把IE中使用的各种工具整理一下&#xff0c;对于开发中标准、规范检查等起到一个作用 主要是三个主流的浏览器和相关的插件 FireFox Firefox-latest.exe firebug-1.7.3-fx.xpi yslow-3.0.3-fx.xpi 安装…