使用Rust编写eBPF程序
参考Aya项目 ,使用Rust编写eBPF程序,最吸引人的地方在于,只需要一种语言就可以完成用户态程序和内核态程序的编写,体验比较好。
1. 开发环境设置
本文使用的开发环境是Fedora Server 39 ,内核版本是6.5.6-300 ,CPU架构是aarch64。
[root@localhost clash]# uname -a
Linux localhost 6.5.6-300.fc39.aarch64 #1 SMP PREEMPT_DYNAMIC Fri Oct  6 19:36:57 UTC 2023 aarch64 GNU/Linux
[root@localhost clash]# more /etc/os-release 
NAME="Fedora Linux"
VERSION="39 (Server Edition)"
ID=fedora
VERSION_ID=39
VERSION_CODENAME=""
PLATFORM_ID="platform:f39"
PRETTY_NAME="Fedora Linux 39 (Server Edition)"
ANSI_COLOR="0;38;2;60;110;180"
LOGO=fedora-logo-icon
CPE_NAME="cpe:/o:fedoraproject:fedora:39"
HOME_URL="https://fedoraproject.org/"
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f39/system-administrators-guide/"
SUPPORT_URL="https://ask.fedoraproject.org/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Fedora"
REDHAT_BUGZILLA_PRODUCT_VERSION=39
REDHAT_SUPPORT_PRODUCT="Fedora"
REDHAT_SUPPORT_PRODUCT_VERSION=39
SUPPORT_END=2024-05-14
VARIANT="Server Edition"
VARIANT_ID=server
[root@localhost clash]# 
1.1 OS依赖安装
dnf install llvm llvm-devel
error: No suitable version of LLVM was found system-wide or pointed
              to by LLVM_SYS_160_PREFIX.
       
              Consider using `llvmenv` to compile an appropriate copy of LLVM, and
              refer to the llvm-sys documentation for more information.
       
              llvm-sys: https://crates.io/crates/llvm-sys
              llvmenv: https://crates.io/crates/llvmenv
   --> /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/llvm-sys-160.1.4/src/lib.rs:490:1
    |
490 | / std::compile_error!(concat!(
491 | |     "No suitable version of LLVM was found system-wide or pointed
492 | |        to by LLVM_SYS_",
493 | |     env!("CARGO_PKG_VERSION_MAJOR"),
...   |
500 | |        llvmenv: https://crates.io/crates/llvmenv"
501 | | ));
    | |__^
error: could not compile `llvm-sys` (lib) due to previous error
warning: build failed, waiting for other jobs to finish...
error: failed to compile `bpf-linker v0.9.10`, intermediate artifacts can be found at `/tmp/cargo-installTRuP1E`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.
[root@localhost ~]#
1.2 Rust依赖安装
rustup install stable
rustup toolchain install nightly --component rust-src
# arm64架构
cargo install --no-default-features bpf-linker
cargo install cargo-generate
2. 创建eBPF项目
这一步使用cargo以及对应的模板生成项目脚手架。
[root@localhost ~]# cd workspace/
[root@localhost workspace]# pwd
/root/workspace
[root@localhost workspace]# 
[root@localhost workspace]# cargo generate --name xdp-hello -d program_type=xdp https://github.com/aya-rs/aya-template
⚠️   Favorite `https://github.com/aya-rs/aya-template` not found in config, using it as a git repository: https://github.com/aya-rs/aya-template
🔧   program_type: "xdp" (variable provided via CLI)
🔧   Destination: /root/workspace/xdp-hello ...
🔧   project-name: xdp-hello ...
🔧   Generating template ...
🔧   Moving generated files into: `/root/workspace/xdp-hello`...
🔧   Initializing a fresh Git repository
✨   Done! New project created /root/workspace/xdp-hello
[root@localhost workspace]# cd xdp-hello/
[root@localhost xdp-hello]# tree .
.
├── Cargo.toml
├── README.md
├── xdp-hello
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── xdp-hello-common
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── xdp-hello-ebpf
│   ├── Cargo.toml
│   ├── rust-toolchain.toml
│   └── src
│       └── main.rs
└── xtask
    ├── Cargo.toml
    └── src
        ├── build_ebpf.rs
        ├── main.rs
        └── run.rs
9 directories, 13 files
[root@localhost xdp-hello]#
3. 编译运行
这个自动生成的项目可以直接编译运行,但是默认绑定的是eth0网卡,如果网卡不一样需要修改下代码或者在运行时指定网卡名。
3.1 编译
[root@localhost xdp-hello]# cargo xtask run -- -h
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
// 省略编译细节
// 省略编译细节
   Compiling xdp-hello v0.1.0 (/root/workspace/xdp-hello/xdp-hello)
    Finished dev [unoptimized + debuginfo] target(s) in 12.37s
Usage: xdp-hello [OPTIONS]
Options:
  -i, --iface <IFACE>  [default: eth0]
  -h, --help           Print help
[root@localhost xdp-hello]#
3.2 运行
方法一:修改
xdp-hello/src/main.rs文件中的eth0为自己的网卡名称,执行RUST_LOG=info cargo xtask run。方法二:使用
RUST_LOG=info cargo xtask run -- -i ens160运行。
运行后会看到很多日志,表示这个xdp-hello这个eBPF程序已经正常被加载到内核,并且被接收网络包的事件触发。
[root@localhost xdp-hello]# RUST_LOG=info cargo xtask run
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/xtask run`
    Finished dev [optimized] target(s) in 0.04s
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
[2024-01-02T08:00:55Z INFO  xdp_hello] Waiting for Ctrl-C...
[2024-01-02T08:00:55Z INFO  xdp_hello] received a packet
[2024-01-02T08:00:55Z INFO  xdp_hello] received a packet
[2024-01-02T08:00:55Z INFO  xdp_hello] received a packet
[2024-01-02T08:00:55Z INFO  xdp_hello] received a packet
[2024-01-02T08:00:55Z INFO  xdp_hello] received a packet
4. 总结
看了Learning eBPF这本书,了解到aya这个项目,之前也学习过一段时间Rust,顺手试了下,上手体检还是非常好的。
对于开发生产级别的eBPF程序,个人还是比较推荐使用C语言和libbpf库或者Rust语言和aya库这种组合。一是单一编程语言可以实现,二是有CORE支持,可以兼顾编程体验和“一次编译到处运行”的效果。
BCC框架作为比较早期的eBPF框架,为了解决一次编译到处运行的问题,需要在运行环境安装一大堆依赖包,相当于是使用的时候才编译,长期来看这种方案不适合推广。
Last modified: 17 August 2025