#ebpf #linux

oxidebpf

一个用于管理eBPF程序的纯Rust库

11个版本

0.2.7 2022年9月9日
0.2.6 2022年9月8日
0.2.5 2022年8月3日
0.2.4 2022年5月2日
0.1.3 2022年1月20日

Unix APIs 中排名第 278

Download history 39/week @ 2024-03-30 12/week @ 2024-04-06

每月下载量 354
tbm 中使用

BSD-3-Clause 许可协议

225KB
5K SLoC

oxidebpf

oxidebpf 是一个用于管理eBPF程序的宽松许可Rust库。

动机

oxidebpf 的动机是创建一个宽松许可的Rust库,用于管理尽可能多环境中运行的长运行eBPF程序。为此,需要打破一些预先设定的模式,即如何开发和部署eBPF应用程序。我们希望能够轻松部署一个在尽可能多的发行版上工作的eBPF解决方案;而不强迫用户必须具备工具链。用户通常只希望有一个产品来完成事情 - 而不需要大量额外的设置或维护。这个库帮助我们实现了这一目标 - 并且我们正在公开分享它。

最初这个库满足了我们的当前eBPF需求,所以它不是一个完整的eBPF实现。我们非常欢迎贡献,并且随着时间的推移,我们将逐渐增加功能列表。

目标

我们希望 oxidebpf 能够满足以下目标。

  • 宽松许可,无GPL依赖。
  • 支持自定义CO-RE eBPF
  • 在Linux 4.4+上运行eBPF程序
  • 纯Rust编写,或者尽可能接近纯Rust。
  • 最小依赖,只引入实现所需功能的最小依赖集合。

要求

提供了一套Linux环境用于构建和测试,依赖项列在其 bootstrap.sh 脚本中。通常,你可能需要

$ sudo apt-get install build-essential clang llvm libclang-dev linux-tools-oem \
  linux-tools-(kernel version)-generic

此外,您还需要安装货运软件。推荐使用cargo-with软件包进行调试和测试。它允许您在测试期间通过运行以下命令来跟踪BPF调用:cargo with "strace -vfe bpf" -- test

入门指南

以下是一些快速入门步骤。

  1. 如果您想使用perfmaps,请在您的Cargo.toml中添加oxidebpf,同时也要添加crossbeam-channel
  2. 使用ProgramBlueprint来加载您的编译后的eBPF对象文件,其中包含映射和程序。
  3. 为每个要加载的程序创建一个Program,并设置选项。
  4. 使用您的程序创建一个ProgramVersion。您可以创建多个ProgramVersion,代表不同的程序集。例如,针对不同内核版本设计的程序。
  5. 创建一个ProgramGroup
  6. 将您的ProgramVersionsProgramBlueprint提供给ProgramGroup,并告诉它开始加载。它将按顺序尝试加载每个ProgramVersion,直到在当前内核上成功加载。如果无法加载任何程序版本,它将返回一个错误,该错误由每个ProgramVersion的底层错误组成。
let program = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
    .join("test")
    .join(format!("test_program_{}", std::env::consts::ARCH));
let program_blueprint =
    ProgramBlueprint::new(&std::fs::read(program).expect("Could not open file"), None)
        .expect("Could not open test object file");
let mut program_group = ProgramGroup::new();
let (tx, rx) = crossbeam_channel::bounded(1024);

program_group.load(
    program_blueprint,
    vec![ProgramVersion::new(vec![
        Program::new(
            "test_program_map_update",
            vec!["do_mount"],
        )
        .syscall(true),
        Program::new("test_program", vec!["do_mount"]).syscall(true),
    ])],
    || (tx, PerfBufferSize::Total(4096))),
).expect("Could not load programs");

// read from rx any events from a perfmap in the loaded program version

注意:这期望在您的项目的test子目录中存在一个test_program_[arch]二进制文件,其中[arch]是您的系统的架构。

构建

项目包含几个Vagrantfile,用于构建和测试库。

$ cd vagrant/ubuntu_20.04
$ vagrant up
$ vagrant ssh
$ cd oxidebpf
$ cargo build

如果您想本地构建,请检查bootstrap.sh文件,以找到与您的系统最相似的Vagrantfile。此文件将包含用于分发版的构建和测试依赖项。

测试

  1. test/目录中运行docker-compose run -rm test-builder以构建BPF测试应用程序。有关RHEL构建的附加选项,请参阅test/README.md
  2. 使用cargo test运行测试。要跟踪发生的BPF系统调用,请使用带有cargo with "strace -fe bpf" -- test(取决于cargo-with,默认由vagrant bootstrap包含)的测试运行测试。

注意:某些测试可能需要root权限才能通过。其他测试需要单线程上下文才能通过。为了测试一致性,请尝试运行:sudo -E /path/to/your/.cargo/bin/cargo test -- --test-threads=1。为了方便,您可以将其别名为alias scargo="sudo -E $HOME/.cargo/bin/cargo",并使用scargo test --test-threads=1运行测试。

功能

指标

oxidebpf 拥有一个(默认禁用)的功能,称为 metrics。启用后,它将使用 metrics crate 来传播与 ebpf maps 相关的内部指标。以下是 metricsoxidebpf 目前报告的内容

  • perfmap.unread_size_pct:表示 perfmap 缓冲区中有多少尚未读取的直方图。这将在轮询 perf map 文件描述符后立即发出,但在读取之前。这仅在 epoll 期间唤醒的 perfmap 中发出,如果一个 perfmap 永远得不到数据,则不会通过此指标报告。报告地图名称和 cpu 作为标签。还会为该指标发出一个 describe_histogram!,以告知报告者这是一个百分比单位。这可以用来设置直方图桶。

  • perfmap.buffer_size_kb:表示为 perfmap 缓冲区的数据部分分配多少内存(以 KB 为单位)。请注意,始终为元数据分配一个额外的页面。这将在创建地图之前立即发出。地图名称作为标签报告。

  • perfmap.num_buffers:表示为 perfmap 分配多少缓冲区。这也是 oxidebpf 检测到的在线 cpu 数量。这将在创建 perf map 之前立即发出。地图名称作为标签报告。

  • perfmap.channel.full:表示尝试通过为 perfmap 提供的用户通道发送丢弃的消息,但失败次数(因为通道已满)。地图名称作为标签报告。

在此阶段,添加或删除指标不会被考虑为破坏性更改,但随着我们稳定最有用的指标,我们可能会重新考虑此决定。

依赖项

~6–16MB
~179K SLoC