eBPF开发者教程:通过示例逐步学习eBPF
这是一个基于CO-RE(Compile Once, Run Everywhere)的eBPF开发教程。它提供了从入门到高级的eBPF开发实践,包括基本概念、代码示例和实际应用。与BCC不同,我们使用libbpf
、Cilium
、libbpf-rs
和eunomia-bpf等框架进行开发,示例代码涵盖了C
、Go
和Rust
等语言。
本教程不涉及复杂的概念和场景介绍,主要目的是通过非常简短的示例(从20行代码开始)帮助eBPF应用开发者快速掌握eBPF的开发方法和技巧。教程内容可以在目录中找到,每个目录都是一个独立的eBPF工具示例。
教程重点关注可观测性、网络、安全等领域的eBPF示例。
中文版在这里
目录
入门示例
本节包含简单的eBPF程序示例和介绍。主要使用eunomia-bpf
框架来简化开发,并介绍eBPF的基本用法和开发流程。
- 第0课-介绍 介绍eBPF的基本概念和常用的开发工具
- 第1课-helloworld 使用eBPF开发最简单的"Hello World"程序,并介绍eBPF的基本框架和开发流程
- 第2课-kprobe-unlink 使用eBPF中的kprobe捕获unlink系统调用
- 第3课-fentry-unlink 使用eBPF中的fentry捕获unlink系统调用
- 第4课-opensnoop 使用eBPF捕获进程打开文件的系统调用,并使用全局变量在eBPF中过滤进程PID
- 第5课-uprobe-bashreadline 使用eBPF中的uprobe捕获bash中的readline函数调用
- 第6课-sigsnoop 捕获进程发送信号的系统调用集合,并使用哈希映射存储状态
- 第7课-execsnoop 捕获进程执行时间并通过perf事件数组输出到用户空间
- 第8课-exitsnoop 捕获进程退出事件并使用环形缓冲区输出到用户空间
- 第9课-runqlat 捕获进程调度延迟并以直方图格式记录
- 第10课-hardirqs 使用hardirqs或softirqs捕获中断事件
高级文档和示例
我们开始基于libbpf
构建完整的eBPF项目,并将它们与各种应用场景结合起来进行实际使用。
- 第11课-bootstrap 使用libbpf-bootstrap编写原生libbpf用户空间代码,并建立完整的libbpf项目
- 第12课-profile 使用eBPF进行性能分析
- 第13课-tcpconnlat 记录TCP连接延迟,并使用libbpf在用户空间处理数据
- 第14课-tcpstates 记录TCP连接状态和TCP RTT
- 第15课-javagc 使用usdt捕获用户级别的Java GC事件持续时间
- 第16课-memleak 检测内存泄漏
- 第17课-biopattern 捕获磁盘IO模式
- 第18课-进一步阅读 进一步阅读:论文列表、项目、博客等
- 第19课-lsm-connect 使用LSM进行安全检测和防御
- 第20课-tc 使用eBPF进行tc流量控制
- 第21课-xdp 使用eBPF进行XDP数据包处理
深入主题
本节涵盖与eBPF相关的高级主题,包括在Android上使用eBPF程序、可能的攻击和防御方法以及复杂的跟踪。结合eBPF的用户模式和内核模式可以带来强大的功能(以及安全风险)。
Android:
网络与跟踪:
安全:
- 使用eBPF修改系统调用参数
- eBPF的安全路径:挑战与创新
- 使用eBPF隐藏进程或文件信息
- 使用bpf_send_signal发送信号终止进程
- 使用eBPF添加sudo用户
- 使用eBPF替换任何程序读取或写入的文本
- BPF生命周期:在用户模式应用程序退出后继续以分离模式运行eBPF程序
其他:
持续更新中...
为什么写这个教程?
在学习eBPF的过程中,我们受到了bcc python开发者教程的启发和帮助。然而,从当前的角度来看,使用libbpf来开发eBPF应用程序是一个相对更好的选择。然而,似乎很少有教程专注于基于libbpf和BPF CO-RE的eBPF开发,并通过示例和工具进行介绍。因此,我们发起了这个项目,采用与bcc python开发者教程类似的组织方法,但使用CO-RE的libbpf进行开发。
本项目主要基于libbpf-bootstrap和eunomia-bpf框架,并使用eunomia-bpf帮助简化一些用户空间libbpf eBPF代码的开发,让开发者可以专注于内核空间eBPF代码开发。
- 我们还提供了一个小工具GPTtrace,它使用ChatGPT通过自然语言描述自动编写eBPF程序并跟踪Linux系统。这个工具允许您以交互方式学习eBPF程序:GPTtrace
- 如果您在eBPF学习过程中遇到任何问题或在实践中遇到bug,请随时在本仓库的issue或讨论区提出。我们将尽力帮助您!
GitHub模板:轻松构建eBPF项目和开发环境,一键编译并运行eBPF程序
在启动一个新的eBPF项目时,您是否对如何设置环境和选择编程语言感到困惑?别担心,我们为您准备了一系列GitHub模板,帮助您快速启动一个全新的eBPF项目。只需点击GitHub上的Use this template
按钮即可开始。
- https://github.com/eunomia-bpf/libbpf-starter-template <SOURCE_TEXT>
$ git clone https://github.com/eunomia-bpf/bpf-developer-tutorial.git
$ cd bpf-developer-tutorial
$ git submodule update --init --recursive # 同步子模块
$ cd src/24-hide
$ make
为什么我们需要基于libbpf和BPF CO-RE的教程?
在历史上,当谈到开发BPF应用程序时,人们可以选择BCC框架来在实现各种Tracepoints的BPF程序时将BPF程序加载到内核中。BCC提供了一个内置的Clang编译器,可以在运行时编译BPF代码,并将其定制为符合特定主机内核的程序。这是在不断变化的内核内部环境中开发可维护BPF应用程序的唯一途径。在文章《BPF的可移植性和CO-RE》中详细介绍了BPF的可移植性和CO-RE的引入,解释了为什么BCC曾是唯一可行的选择,以及为什么现在libbpf被认为是一个更好的选择。去年,Libbpf在功能和复杂性方面得到了显著改善,消除了与BCC的许多差异(特别是对于Tracepoints应用程序),并增加了许多BCC不支持的新功能(例如全局变量和BPF骨架)。
诚然,BCC尽力简化了BPF开发者的工作,但有时在提供便利的同时也增加了问题定位和修复的难度。用户必须记住它的命名约定和为Tracepoints自动生成的结构,并且必须依赖于重写此代码来读取内核数据和访问kprobe参数。使用BPF地图时,有必要编写与内核实际操作不完全匹配的半面向对象的C代码。此外,BCC在用户空间中编写了大量样板代码,手动配置最琐碎的部分。
如上所述,BCC依赖于运行时编译并嵌入了大型LLVM/Clang库,这在理想的使用场景中与BCC之间产生了某些差距:
- 编译时的高资源利用率(内存和CPU),可能会在繁忙的服务器中干扰主要进程。
- 它依赖于内核头文件包,并且需要在每个目标主机上安装。即便如此,如果某些内核内容未通过公共头文件公开,仍然需要将类型定义复制并粘贴到BPF代码中以实现目的。
- 即使是最小的编译时错误也只能在运行时检测到,然后重新编译并重启用户空间应用程序。这极大地影响了开发的迭代时间(并增加了挫败感……)。
Libbpf + BPF CO-RE(一次编译 - 到处运行)采取了一种不同的方法,将BPF程序视为普通用户空间程序:它们只需要编译成可以部署在目标主机上的小型二进制文件,无需修改。libbpf充当BPF程序的加载器,负责配置工作(重定位、加载和验证BPF程序,创建BPF地图,附加到BPF钩子等),开发者只需关注BPF程序的正确性和性能。这种方法最大限度地减少了开销,消除了依赖关系,并改善了整体开发者体验。
在API和代码约定方面,libbpf遵循“最小惊讶”的理念,大多数事情都需要明确说明:没有隐含的头文件,也没有代码重写。大多数单调的步骤可以通过简单的C代码和适当的辅助宏来消除。此外,用户编写的内容是需要执行的内容,BPF应用程序的结构是一对一的,最终由内核验证并执行。
参考资料: BCC到Libbpf转换指南(翻译) - 深入探讨eBPF
eunomia-bpf
eunomia-bpf 是一个开源的eBPF动态加载运行时和开发工具包,旨在简化eBPF程序的开发、构建、分发和执行。它基于libbpf CO-RE轻量级开发框架。
通过eunomia-bpf,你可以:
- 在编写eBPF程序或工具时,仅编写libbpf内核模式代码,自动检索内核模式导出信息。
- 使用Wasm开发eBPF用户模式程序,控制整个eBPF程序的加载和执行,并在WASM虚拟机中处理相关数据。
- eunomia-bpf可以将预编译的eBPF程序打包成通用的JSON或WASM模块,跨架构和内核版本分发,实现动态加载和执行,无需重新编译。
eunomia-bpf由编译工具链和运行时库组成。与传统框架如BCC和原生libbpf相比,它极大地简化了eBPF程序的开发过程,在大多数情况下,仅需编写内核模式代码即可轻松构建、打包和发布完整的eBPF应用程序。同时,内核模式eBPF代码保证了与主流开发框架的兼容性,如libbpf、libbpfgo、libbpf-rs等。当需要编写用户模式代码时,可以借助Webassembly使用多种语言。与bpftrace等脚本工具相比,eunomia-bpf保持了类似的便利性,同时不限于追踪场景,还可以用于网络和安全等其他领域。
- eunomia-bpf项目GitHub地址: https://github.com/eunomia-bpf/eunomia-bpf
- gitee镜像: https://gitee.com/anolis/eunomia
让ChatGPT帮助我们
本教程使用ChatGPT学习如何编写eBPF程序。同时,我们尝试教ChatGPT如何编写eBPF程序。一般步骤如下:
- 教它eBPF编程的基本知识。
- 向它展示一些案例:hello world,eBPF程序的基本结构,如何使用eBPF程序进行追踪,并让它开始编写教程。
- 手动调整教程并纠正代码和文档中的错误。
- 将修改后的代码反馈给ChatGPT以便进一步学习。
- 尝试让ChatGPT自动生成eBPF程序及相应的教程文档!例如:
完整的对话日志可以在此找到:ChatGPT.md
我们还构建了一个命令行工具的演示。通过本教程的训练,它可以使用自然语言描述自动编写eBPF程序并追踪Linux系统: https://github.com/eunomia-bpf/GPTtrace
</SOURCE_TEXT>