|
| 1 | +# `bpf*-unknown-none` |
| 2 | + |
| 3 | +**Tier: 3** |
| 4 | + |
| 5 | +* `bpfeb-unknown-none` (big endian) |
| 6 | +* `bpfel-unknown-none` (little endian) |
| 7 | + |
| 8 | +Targets for the [eBPF virtual machine][ebpf]. |
| 9 | + |
| 10 | +## Target maintainers |
| 11 | + |
| 12 | +- [@dave-tucker](https://github.com/dave-tucker) |
| 13 | +- [@vadorovsky](https://github.com/vadorovsky) |
| 14 | + |
| 15 | +## Requirements |
| 16 | + |
| 17 | +BPF targets require a Rust toolchain with `rust-src` component and |
| 18 | +[bpf-linker][bpf-linker]. |
| 19 | + |
| 20 | +They don't support std and alloc and are meant for `no_std` environment. |
| 21 | + |
| 22 | +`extern "C"` uses the [BPF ABI calling convention][bpf-abi]. |
| 23 | + |
| 24 | +Produced binaries use the ELF format. |
| 25 | + |
| 26 | +## Building the target |
| 27 | + |
| 28 | +You can build Rust with support for BPF targets by adding them to the `target` |
| 29 | +list in `config.toml`: |
| 30 | + |
| 31 | +```toml |
| 32 | +[build] |
| 33 | +target = ["bpfeb-unknown-none", "bpfel-unknown-none"] |
| 34 | +``` |
| 35 | + |
| 36 | +## Building Rust programs |
| 37 | + |
| 38 | +Rust does not yet ship pre-compiled artifacts for this target. To compile for |
| 39 | +this target, you will either need to build Rust with the target enabled (see |
| 40 | +"Building the target" above), or build your own copy of `core` by using |
| 41 | +`build-std` or similar. |
| 42 | + |
| 43 | +Building the BPF target requires specifying it explicitly. Users can either |
| 44 | +add them to the `target` list in `config.toml`: |
| 45 | + |
| 46 | +```toml |
| 47 | +[build] |
| 48 | +target = ["bpfel-unknown-none"] |
| 49 | +``` |
| 50 | + |
| 51 | +Or specify it directly in the `cargo build` invocation: |
| 52 | + |
| 53 | +```console |
| 54 | +cargo +nightly build -Z build-std=core --target bpfel-unknown-none |
| 55 | +``` |
| 56 | + |
| 57 | +## Testing |
| 58 | + |
| 59 | +eBPF bytecode need to be executed on an eBPF virtual machine, like the one |
| 60 | +provided by the Linux kernel or one of user-space implementations like |
| 61 | +[rbpf][rbpf]. None of them supports running Rust testsuite. |
| 62 | + |
| 63 | +Currently the best way of unit testing the code used in BPF programs is |
| 64 | +extracting it to a separate crate, which can be built and ran on a host target, |
| 65 | +and using it as a dependency. |
| 66 | + |
| 67 | +## Cross-compilation toolchains |
| 68 | + |
| 69 | +Technically speaking, every build for BPF target is a cross build and is |
| 70 | +performed on a host target (e.g. `x86_64-unknown-linux-*`) for the BPF target |
| 71 | +(e.g. `bpfel-unknown-none`). The resulting BPF bytecode can be executed on a |
| 72 | +virtual machine, which can run on different host architectures (x86_64, aarch64, |
| 73 | +riscv64 etc.). The BPF bytecode format stays the same regardless of the host |
| 74 | +architecture hosting the virtual machine. When building BPF code, compiler does |
| 75 | +not care about the architecture hosting the VM. |
| 76 | + |
| 77 | +That said, in the context of BPF VM in the Linux kernel and BPF programs |
| 78 | +interacting with kernel types, the architecture which hosts the VM affects |
| 79 | +these types. For example, `char` in C translates to different Rust types |
| 80 | +on different architectures (`i8` on x86_64, `u8` on aarch64). Therefore, kernel |
| 81 | +types are different across architectures. Solving that problem is still not a |
| 82 | +concern of the Rust compiler itself. On the other hand, [Aya][aya] (the library |
| 83 | +for writing BPF programs and the main consumer of BPF targets in Rust) handles |
| 84 | +the C type differences by providing the [`aya-ebpf-cty`][aya-ebpf-cty] library, |
| 85 | +with type aliases similar to those provided by `core:ffi`. aya-ebpf-cty allows |
| 86 | +to specify the VM host target through the `CARGO_CFG_BPF_TARGET_ARCH` |
| 87 | +environment variable (e.g. `CARGO_CFG_BPF_TARGET_ARCH=aarch64`). |
| 88 | + |
| 89 | +## C code |
| 90 | + |
| 91 | +It's possible to link a Rust BPF project to bitcode or object files which are |
| 92 | +built from C code with [clang][clang]. It can be done using `rustc-link-lib` |
| 93 | +instruction in `build.rs`. Example: |
| 94 | + |
| 95 | +```rust |
| 96 | +let out_dir = std::env::var("OUT_DIR").unwrap(); |
| 97 | +let c_module = "my_module.bpf.c" |
| 98 | +let s = Command::new("clang") |
| 99 | + .arg("-I") |
| 100 | + .arg("src/") |
| 101 | + .arg("-O2") |
| 102 | + .arg("-emit-llvm") |
| 103 | + .arg("-target") |
| 104 | + .arg("bpf") |
| 105 | + .arg("-c") |
| 106 | + .arg("-g") |
| 107 | + .arg(c_module) |
| 108 | + .arg("-o") |
| 109 | + .arg(format!("{out_dir}/my_module.bpf.o")) |
| 110 | + .status() |
| 111 | + .unwrap(); |
| 112 | +assert!(s.success()); |
| 113 | +println!("cargo:rustc-link-search=native={out_dir}"); |
| 114 | +println!("cargo:rustc-link-lib=link-arg={out_dir}/my_module.bpf.o"); |
| 115 | +``` |
| 116 | + |
| 117 | +[ebpf]: https://ebpf.io/ |
| 118 | +[bpf-linker]: https://github.com/aya-rs/bpf-linker |
| 119 | +[bpf-abi]: https://www.kernel.org/doc/html/v6.13-rc5/bpf/standardization/abi.html |
| 120 | +[rbpf]: https://github.com/qmonnet/rbpf |
| 121 | +[aya]: https://aya-rs.dev |
| 122 | +[aya-ebpf-cty]: https://github.com/aya-rs/aya/tree/main/ebpf/aya-ebpf-cty |
| 123 | +[clang]: https://clang.llvm.org/ |
0 commit comments