Skip to content

Latest commit

 

History

History
183 lines (95 loc) · 8.68 KB

File metadata and controls

183 lines (95 loc) · 8.68 KB

eBPF 是啥能干啥

简单说明


eBPF (扩展的伯克利数据包过滤器)是一项强大的 Linux 内核技术,允许在内核空间运行用户定义的程序,而无需修改内核源代码或加载内核模块. 它源自 BPF(Berkeley Packet Filter),但大大扩展了其功能.

主要用途:

  • 网络: 数据包过滤、流量控制、负载均衡

  • 安全: 系统调用监控、入侵检测

  • 性能分析: 跟踪内核和应用程序行为

  • 观测性: 收集各种系统和应用指标

优势:

  • 高性能: 直接在内核中执行,开销小

  • 安全: eBPF 程序在执行前经过验证

  • 灵活: 可以动态加载和更新程序

eBPF 技术正在迅速发展,被广泛应用于云原生、网络、安全等领域,相信众多的编程爱好者也会对 eBPF 技术产生浓厚的兴趣并且尝试使用它,但是在第一步搭建开发环境时可能会遇到一些困难,止步不前了. 的确是这样, eBPF 的开发环境搭建起来并不是那么容易,不同的 Linux 发行版、内核版本、工具链等都会对 eBPF 的开发环境产生影响,因此需要一些技巧和经验.

主要基于 eunomia-bpf 的 bpf-developer-tutorial 作为主要参考资料,实践和整理. 例子主要基于 eunomia-bpf 的工具进行编译和运行,这里只是将它的例子中的用户态的逻辑转换成 go 语言的程序.

ebpf 简介和相关资料


ebpf 工具链


Go 生态圈中的 ebpf 库

  • cilium/ebpf - 这是一个广泛使用的 Go eBPF 库,提供了加载和运行 eBPF 程序的功能.

  • iovisor/gobpf - 另一个流行的 eBPF 库, Go bindings for BCC for creating eBPF programs.

  • libbpfgo:libbpfgo 是一个用于 Linux eBPF 项目的 Go 库. 它是围绕 libbpf 项目构建的一个薄层 Go 包装器.

  • dropbox/goebpf: Dropbox 开发的 Go eBPF 库,专注于简单性和可用性.

eBPF CO-RE: Compile Once – Run Everywhere


eBPF CO-RE (Compile Once – Run Everywhere) 是 eBPF 技术的一个重要进展,旨在解决 eBPF 程序的可移植性问题. CO-RE 允许开发者编写一次 eBPF 程序,然后在不同的 Linux 内核版本上运行,而无需重新编译.

CO-RE 的主要包括以下特性:

  • BTF (BPF Type Format): 提供了内核数据结构的详细类型信息.

  • 重定位: 允许在运行时动态调整 eBPF 程序中的内存访问.

  • 内核符号和类型信息: 通过 BTF 提供,使 eBPF 程序能够适应不同的内核版本.

传统 eBPF vs CO-RE eBPF

传统 eBPF 的限制

  • 可移植性差: 需要为每个目标内核版本重新编译.

  • 依赖内核头文件: 编译时需要完整的内核头文件.

  • 版本特定: eBPF 程序往往只能在特定的内核版本上运行.

CO-RE eBPF 的优势

  • 提高可移植性: 一次编译,到处运行.

  • 减少依赖: 不再需要完整的内核头文件.

  • 适应性强: 能够适应不同的内核版本和配置.

  • 简化部署: 无需为每个目标系统维护多个版本的 eBPF 程序.

最佳实践


  • 使用最新的 libbpf: 确保使用最新版本的 libbpf,以获得最新的 CO-RE 支持.

  • 利用 BTF 信息: 在编译时使用-g 选项保留调试信息.

  • 使用 BPF skeleton: 利用 bpftool gen skeleton 生成 skeleton 头文件,简化 eBPF 程序的加载和管理.

  • 避免硬编码偏移: 使用 BPF helpers 和 CO-RE 重定位来访问内核结构,而不是硬编码偏移.

  • 测试多个内核版本: 在不同版本的内核上测试你的程序,确保 CO-RE 正常工作.

注意事项

  • CO-RE 并不能解决所有的兼容性问题. 某些内核 API 的变化可能仍然需要代码适配.

  • 确保目标系统的内核支持并启用了 BTF.

  • 某些非常底层或特定于版本的功能可能仍然需要传统的 eBPF 开发方

eunomia-bpf


开发、构建和分发 eBPF 一直以来都是一个高门槛的工作,使用 BCCbpftrace 等工具开发效率高、可移植性好,但是分发部署时需要安装 LLVM、Clang 等编译环境,每次运行的时候执行本地或远程编译过程,资源消耗较大,而且不容易安装相关的依赖;使用原生的 CO-RE libbpf 时又需要编写不少用户态加载代码来帮助 eBPF 程序正确加载和从内核中获取上报的信息,同时对于 eBPF 程序的分发、管理也没有很好地解决方案.

eunomia-bpf 是一个开源的 eBPF 动态加载运行时和开发工具链,是为了简化 eBPF 程序的开发、构建、分发、运行而设计的,基于 libbpf 的 CO-RE 轻量级开发框架.

使用 eunomia-bpf ,可以:

  • 在编写 eBPF 程序或工具时只编写内核态代码,自动获取内核态导出信息,并作为模块动态加载;

  • 使用 WASM 进行用户态交互程序的开发,在 WASM 虚拟机内部控制整个 eBPF 程序的加载和执行,以及处理相关数据;

  • eunomia-bpf 可以将预编译的 eBPF 程序打包为通用的 JSON 或 WASM 模块,跨架构和内核版本进行分发,无需重新编译即可动态加载运行.

eunomia-bpf 由一个编译工具链和一个运行时库组成, 对比传统的 BCC、原生 libbpf 等框架,大幅简化了 eBPF 程序的开发流程,在大多数时候只需编写内核态代码,即可轻松构建、打包、发布完整的 eBPF 应用,同时内核态 eBPF 代码保证和主流的 libbpf,libbpfgo,libbpf-rs 等开发框架的 100% 兼容性. 需要编写用户态代码的时候,也可以借助 Webassembly 实现通过多种语言进行用户态开发. 和 bpftrace 等脚本工具相比, eunomia-bpf 保留了类似的便捷性, 同时不仅局限于 trace 方面, 可以用于更多的场景, 如网络、安全等等.

前面的一些例子都是抄eunomia-bpfbpf-developer-tutorial, 有时间会尝试补充一些相关的学习资料.

也许会使用cilium/ebpf库来实现其中的一些例子.

culium/ebpf

Cilium/eBPF 是一个用 Go 语言编写的库,提供了一套用于处理 eBPF 程序的 API. 它允许开发者以一种安全、高效的方式在 Go 程序中加载、管理和与 eBPF 程序交互.

主要特性包括:

  1. eBPF 程序加载:支持加载预编译的 eBPF 对象文件.

  2. 映射管理:提供了创建、访问和管理 eBPF 映射的功能.

  3. 程序附加:支持将 eBPF 程序附加到各种内核钩子点.

  4. BTF (BPF Type Format) 支持:增强了跨内核版本的兼容性.

  5. CO-RE (Compile Once – Run Everywhere) 支持:允许编写一次代码,在不同内核版本上运行.

  6. 错误处理:提供详细的错误信息,便于调试.

  7. 安全性:实现了多种安全检查,以防止不安全的操作.

主要应用场景包括:

  • 网络监控和过滤

  • 系统调用跟踪

  • 性能分析

  • 安全策略实施

  • 自定义网络协议实现

注意事项

  • 使用 Cilium/eBPF 需要较新的 Linux 内核版本(推荐 5.4+).

  • 某些功能可能需要特定的内核配置选项.

  • 开发 eBPF 程序通常需要 root 权限.

Cilium/eBPF 为 Go 开发者提供了一个强大的工具,用于利用 eBPF 技术进行系统级编程和网络编程. 它简化了 eBPF 程序的开发和管理过程,同时保持了高性能和灵活性.