Writing eBPF Programs with Rust Aya Framework
This article can be found at: https://www.ebpf.top/post/ebpf_rust_aya
1. Introduction
A significant change in Linux Kernel version 6.1 is the introduction of support for the Rust programming language. Rust is a system programming language that offers robust compile-time guarantees and precise control over memory lifetimes. Integrating Rust language into kernel development will bring additional safety measures to the early stages of kernel development. eBPF is a technology in the kernel that enables running user-defined programs based on events, with a validator mechanism ensuring the security of eBPF programs running in the kernel.
Rust and eBPF share a common goal of ensuring kernel safety, albeit with different focuses.
Although writing eBPF programs in Rust often involves unsafe memory reads and writes in the kernel, leveraging Rust and Aya can indeed provide a fast and efficient development experience. This includes automatically generating the entire program framework (eBPF program and corresponding user-space code), parameter validation, error handling, unified build and management processes, and more.
Aya is an eBPF library focused on operability and developer experience, built entirely on Rust, using only the libc package for system calls. The official repository of Aya can be found at https://github.com/aya-rs/aya/, with the current version being v0.1.11, and the project is still in its early stages. Developing eBPF programs based on the Aya library offers the following conveniences:
- Management, building, and testing of projects using Rust’s Cargo tool.
- Support for directly generating CO-RE bindings with Rust and kernel files.
- Easy code sharing between user tool code (Rust) and eBPF code running in the kernel.
- No dependencies on LLVM, libbpf, bcc, and the like.
This article focuses on the process of writing eBPF programs and generating user-space programs using Aya, without delving into detailed explanations of generating Rust code.
2. Setting Up Rust Development Environment
2.1 Create a VM Virtual Machine
To write eBPF programs with Rust, we first need to set up a Rust development environment locally. Here, I will use the multipass tool to quickly create an environment with Ubuntu 22.04 LTS.
|
|
The default disk size is 5G, which can easily fill up, so here I’ve set the disk size to 20G. Adjust this according to your needs.
For existing multipass instances that need adjustment, the multipass version must be greater than 1.10, and the instance to be adjusted must be in a stopped state. Refer to Modifying an Instance for details on how to adjust instances, such as using
multipass set local.rust-aya.cpus=4
ormultipass set local.rust-aya.memory=8G
to adjust CPU and memory sizes.
2.2 Install Rust Development Environment
Typically, the Rust development environment is managed using the rustup tool. We can quickly install this tool with the following command:
|
|
In most cases, we choose the default options for installation. The installation process involves downloading a script to install the rustup tool, as well as the latest stable version of Rust. If the installation is successful, you should see the following message at the end:
|
|
Once rustup is installed, we can use it to install Rust stable (which is likely already installed by default) and nightly. Note that using Aya currently requires Rust Nightly.
Rust has 3 release channels:
- Nightly
- Beta
- Stable
While most Rust developers primarily use the stable channel, developers wishing to experiment with new features may use nightly or beta versions. For more details, refer to Appendix G: How Rust is Developed and “Nightly Rust”
|
|
After installing nightly
, we can use rustup toolchain list
to check the development toolchain in the local environment.
2.3 Install Dependencies for bpf-linker
and bpftool
To use Aya, we also need to install the dependencies such as bpf-linker
, which relies on LLVM/Clang and other tools. Therefore, we need to install them beforehand:
|
|
Finally, to generate bindings for kernel data structures, we must install bpftool
. You can install it from the distribution version or build it from the source code. Here, I choose the distribution version installation (based on Ubuntu 22.04). For source code installation, you can refer to the bpftool repository documentation:
|
|
This completes the installation of the entire environment and dependencies required for developing with Aya.
3. Aya Guide to Create eBPF Programs
3.1 Creating a Project Using the Guide
Aya provides a set of template guides for creating programs corresponding to eBPF types, and the guide creation depends on cargo-generate
, so we need to install it before running the guide program:
|
|
During the installation of
cargo-generate
, I encountered the following errors, mainly due to issues with the openssl library. If you encounter similar problems, you can refer to cargo-generate Installation Guide and Rust OpenSSL documentation. If everything goes smoothly, you can ignore this notice.
1 2 3 4 5 6 7
... warning: build failed, waiting for other jobs to finish... error: failed to compile `cargo-generate v0.16.0`, intermediate artifacts can be found at `/tmp/cargo-install8NrREg ... $ sudo apt install openssl pkg-config libssl-dev gcc m4 ca-certificates make perl -y # Reinstall it
After installing the dependencies, we can use the guide to create an eBPF project. Here, we take the XDP type program as an example:
$ cargo generate https://github.com/aya-rs/aya-template
Here, we enter the project name myapp
, and choose the eBPF program type as xdp
. After completing the related settings, the guide will automatically create a Rust project named myapp, which includes a simple XDP type eBPF program and its corresponding user-space program. The overall structure of the myapp directory is as follows:
|
|
The generated eBPF program is located in the myapp-ebpf/src directory, with the file name main.rs. The complete content of the file is as follows:
|
|
3.2 Compile eBPF Program
Firstly, let’s compile the corresponding eBPF program using the cargo tool:
|
|
After the compilation is completed, the program is saved in the target directory:
|
|
Thus, the compilation of the eBPF program has been completed. Next, we need to proceed with compiling the user-space code.
3.3 Run User-space Program
We can directly run the user-space program using the cargo command:
|
|
Setting the log level environment variable with
RUST_LOG=info
is necessary. By default, the log level is set to warn, but the code generated by the wizard prints logs at the info level. Specifying it during runtime is crucial to avoid missing log messages during program execution.
The cargo xtask run
command compiles the user-space code and runs it directly. However, during execution, we encountered an error unknown network interface eth0
. This happened because the default program specified to load the XDP program onto the eth0 network interface, which was not present in our VM setup. Here, we explicitly specified to use the lo interface for testing, and running it again yields the following result:
|
|
This time, the user-space program is running correctly, and the corresponding eBPF program is loaded into the kernel.
|
|
We initiate a ping packet validation on the lo interface:
We can observe that when running the ping -c 1 127.0.0.1
command in another terminal window, the corresponding log received a packet
is printed in the log of the user-space myapp program simultaneously.
Thus, we have completed the validation of the simplest XDP program based on Aya. If you plan to advance further to print packet logs or to filter specific packets, you can refer to the corresponding chapters in Aya Book.
4. Conclusion
Through the usage of Aya throughout the process, we have found that developing eBPF programs with Aya indeed brings us many conveniences. The wizard helps set up the basic framework of the entire project and manages tasks like compilation and loading, making it particularly beginner-friendly. The default generated user-space code and eBPF code achieve a certain level of code reuse, especially making logging more convenient. At the same time, the project’s current documentation is not fully comprehensive yet, with documents on program types like Probe/Tracepoint/XDP still being improved. If you are interested, you are also welcome to contribute to the related development. More information can be found in Aya: Your Trusty eBPF Companion.
Moreover, it is anticipated that the libbpf-bootstrap project can implement Aya’s wizard-style creation of eBPF program codes soon, providing a fast onboarding experience for writing eBPF-related programs.
References
- Author: DavidDi
- Link: https://www.ebpf.top/en/post/ebpf_rust_aya/
- License: This work is under a Attribution-NonCommercial-NoDerivs 4.0 International. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.
- Last Modified Time: 2024-02-07 00:20:33.080924629 +0800 CST