使用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: 27 October 2024