1*fae6e9adSlinfeng# rbpf 2*fae6e9adSlinfeng 3*fae6e9adSlinfeng<picture> 4*fae6e9adSlinfeng <source media="(prefers-color-scheme: dark)" srcset="misc/rbpf_256_border.png"> 5*fae6e9adSlinfeng <img src="misc/rbpf_256.png"> 6*fae6e9adSlinfeng</picture> 7*fae6e9adSlinfeng 8*fae6e9adSlinfengRust (user-space) virtual machine for eBPF 9*fae6e9adSlinfeng 10*fae6e9adSlinfeng[![Build Status](https://github.com/qmonnet/rbpf/actions/workflows/test.yaml/badge.svg)](https://github.com/qmonnet/rbpf/actions/workflows/test.yaml) 11*fae6e9adSlinfeng[![Build status](https://ci.appveyor.com/api/projects/status/ia74coeuhxtrcvsk/branch/main?svg=true)](https://ci.appveyor.com/project/qmonnet/rbpf/branch/main) 12*fae6e9adSlinfeng[![Coverage Status](https://coveralls.io/repos/github/qmonnet/rbpf/badge.svg?branch=main)](https://coveralls.io/github/qmonnet/rbpf?branch=main) 13*fae6e9adSlinfeng[![Crates.io](https://img.shields.io/crates/v/rbpf.svg)](https://crates.io/crates/rbpf) 14*fae6e9adSlinfeng 15*fae6e9adSlinfeng* [Description](#description) 16*fae6e9adSlinfeng* [Link to the crate](#link-to-the-crate) 17*fae6e9adSlinfeng* [API](#api) 18*fae6e9adSlinfeng* [Example uses](#example-uses) 19*fae6e9adSlinfeng* [Building eBPF programs](#building-ebpf-programs) 20*fae6e9adSlinfeng* [Build Features](#build-features) 21*fae6e9adSlinfeng* [Feedback welcome!](#feedback-welcome) 22*fae6e9adSlinfeng* [Questions / Answers](#questions--answers) 23*fae6e9adSlinfeng* [Caveats](#caveats) 24*fae6e9adSlinfeng* [_To do_ list](#to-do-list) 25*fae6e9adSlinfeng* [License](#license) 26*fae6e9adSlinfeng* [Inspired by](#inspired-by) 27*fae6e9adSlinfeng* [Other resources](#other-resources) 28*fae6e9adSlinfeng 29*fae6e9adSlinfeng## Description 30*fae6e9adSlinfeng 31*fae6e9adSlinfengThis crate contains a virtual machine for eBPF program execution. BPF, as in 32*fae6e9adSlinfeng_Berkeley Packet Filter_, is an assembly-like language initially developed for 33*fae6e9adSlinfengBSD systems, in order to filter packets in the kernel with tools such as 34*fae6e9adSlinfengtcpdump so as to avoid useless copies to user-space. It was ported to Linux, 35*fae6e9adSlinfengwhere it evolved into eBPF (_extended_ BPF), a faster version with more 36*fae6e9adSlinfengfeatures. While BPF programs are originally intended to run in the kernel, the 37*fae6e9adSlinfengvirtual machine of this crate enables running it in user-space applications; 38*fae6e9adSlinfengit contains an interpreter, an x86_64 JIT-compiler for eBPF programs, as well as 39*fae6e9adSlinfenga disassembler. 40*fae6e9adSlinfeng 41*fae6e9adSlinfengIt is based on Rich Lane's [uBPF software](https://github.com/iovisor/ubpf/), 42*fae6e9adSlinfengwhich does nearly the same, but is written in C. 43*fae6e9adSlinfeng 44*fae6e9adSlinfengThe crate is supposed to compile and run on Linux, MacOS X, and Windows, 45*fae6e9adSlinfengalthough the JIT-compiler does not work with Windows at this time. 46*fae6e9adSlinfeng 47*fae6e9adSlinfeng## Link to the crate 48*fae6e9adSlinfeng 49*fae6e9adSlinfengThis crate is available from [crates.io](https://crates.io/crates/rbpf), so it 50*fae6e9adSlinfengshould work out of the box by adding it as a dependency in your `Cargo.toml` 51*fae6e9adSlinfengfile: 52*fae6e9adSlinfeng 53*fae6e9adSlinfeng```toml 54*fae6e9adSlinfeng[dependencies] 55*fae6e9adSlinfengrbpf = "0.2.0" 56*fae6e9adSlinfeng``` 57*fae6e9adSlinfeng 58*fae6e9adSlinfengYou can also use the development version from this GitHub repository. This 59*fae6e9adSlinfengshould be as simple as putting this inside your `Cargo.toml`: 60*fae6e9adSlinfeng 61*fae6e9adSlinfeng```toml 62*fae6e9adSlinfeng[dependencies] 63*fae6e9adSlinfengrbpf = { git = "https://github.com/qmonnet/rbpf" } 64*fae6e9adSlinfeng``` 65*fae6e9adSlinfeng 66*fae6e9adSlinfengOf course, if you prefer, you can clone it locally, possibly hack the crate, 67*fae6e9adSlinfengand then indicate the path of your local version in `Cargo.toml`: 68*fae6e9adSlinfeng 69*fae6e9adSlinfeng```toml 70*fae6e9adSlinfeng[dependencies] 71*fae6e9adSlinfengrbpf = { path = "path/to/rbpf" } 72*fae6e9adSlinfeng``` 73*fae6e9adSlinfeng 74*fae6e9adSlinfengThen indicate in your source code that you want to use the crate: 75*fae6e9adSlinfeng 76*fae6e9adSlinfeng```rust,ignore 77*fae6e9adSlinfengextern crate rbpf; 78*fae6e9adSlinfeng``` 79*fae6e9adSlinfeng 80*fae6e9adSlinfeng## API 81*fae6e9adSlinfeng 82*fae6e9adSlinfengThe API is pretty well documented inside the source code. You should also be 83*fae6e9adSlinfengable to access [an online version of the documentation from 84*fae6e9adSlinfenghere](https://docs.rs/rbpf/), automatically generated from the 85*fae6e9adSlinfeng[crates.io](https://crates.io/crates/rbpf) version (may not be up-to-date with 86*fae6e9adSlinfengthe main branch). [Examples](../../tree/main/examples) and [unit 87*fae6e9adSlinfengtests](../../tree/main/tests) should also prove helpful. Here is a summary of 88*fae6e9adSlinfenghow to use the crate. 89*fae6e9adSlinfeng 90*fae6e9adSlinfengHere are the steps to follow to run an eBPF program with rbpf: 91*fae6e9adSlinfeng 92*fae6e9adSlinfeng1. Create a virtual machine. There are several kinds of machines, we will come 93*fae6e9adSlinfeng back on this later. When creating the VM, pass the eBPF program as an 94*fae6e9adSlinfeng argument to the constructor. 95*fae6e9adSlinfeng2. If you want to use some helper functions, register them into the virtual 96*fae6e9adSlinfeng machine. 97*fae6e9adSlinfeng3. If you want a JIT-compiled program, compile it. 98*fae6e9adSlinfeng4. Execute your program: either run the interpreter or call the JIT-compiled 99*fae6e9adSlinfeng function. 100*fae6e9adSlinfeng 101*fae6e9adSlinfengeBPF has been initially designed to filter packets (now it has some other hooks 102*fae6e9adSlinfengin the Linux kernel, such as kprobes, but this is not covered by rbpf). As a 103*fae6e9adSlinfengconsequence, most of the load and store instructions of the program are 104*fae6e9adSlinfengperformed on a memory area representing the packet data. However, in the Linux 105*fae6e9adSlinfengkernel, the eBPF program does not immediately access this data area: initially, 106*fae6e9adSlinfengit has access to a C `struct sk_buff` instead, which is a buffer containing 107*fae6e9adSlinfengmetadata about the packet—including memory addresses of the beginning and of 108*fae6e9adSlinfengthe end of the packet data area. So the program first loads those pointers from 109*fae6e9adSlinfengthe `sk_buff`, and then can access the packet data. 110*fae6e9adSlinfeng 111*fae6e9adSlinfengThis behavior can be replicated with rbpf, but it is not mandatory. For this 112*fae6e9adSlinfengreason, we have several structs representing different kinds of virtual 113*fae6e9adSlinfengmachines: 114*fae6e9adSlinfeng 115*fae6e9adSlinfeng* `struct EbpfVmMbuffer` mimics the kernel. When the program is run, the 116*fae6e9adSlinfeng address provided to its first eBPF register will be the address of a metadata 117*fae6e9adSlinfeng buffer provided by the user, and that is expected to contain pointers to the 118*fae6e9adSlinfeng start and the end of the packet data memory area. 119*fae6e9adSlinfeng 120*fae6e9adSlinfeng* `struct EbpfVmFixedMbuff` has one purpose: enabling the execution of programs 121*fae6e9adSlinfeng created to be compatible with the kernel, while saving the effort to manually 122*fae6e9adSlinfeng handle the metadata buffer for the user. In fact, this struct has a static 123*fae6e9adSlinfeng internal buffer that is passed to the program. The user has to indicate the 124*fae6e9adSlinfeng offset values at which the eBPF program expects to find the start and the end 125*fae6e9adSlinfeng of packet data in the buffer. On calling the function that runs the program 126*fae6e9adSlinfeng (JITted or not), the struct automatically updates the addresses in this 127*fae6e9adSlinfeng static buffer, at the appointed offsets, for the start and the end of the 128*fae6e9adSlinfeng packet data the program is called upon. 129*fae6e9adSlinfeng 130*fae6e9adSlinfeng* `struct EbpfVmRaw` is for programs that want to run directly on packet data. 131*fae6e9adSlinfeng No metadata buffer is involved, the eBPF program directly receives the 132*fae6e9adSlinfeng address of the packet data in its first register. This is the behavior of 133*fae6e9adSlinfeng uBPF. 134*fae6e9adSlinfeng 135*fae6e9adSlinfeng* `struct EbpfVmNoData` does not take any data. The eBPF program takes no 136*fae6e9adSlinfeng argument whatsoever and its return value is deterministic. Not so sure there 137*fae6e9adSlinfeng is a valid use case for that, but if nothing else, this is very useful for 138*fae6e9adSlinfeng unit tests. 139*fae6e9adSlinfeng 140*fae6e9adSlinfengAll these structs implement the same public functions: 141*fae6e9adSlinfeng 142*fae6e9adSlinfeng```rust,ignore 143*fae6e9adSlinfeng// called with EbpfVmMbuff:: prefix 144*fae6e9adSlinfengpub fn new(prog: &'a [u8]) -> Result<EbpfVmMbuff<'a>, Error> 145*fae6e9adSlinfeng 146*fae6e9adSlinfeng// called with EbpfVmFixedMbuff:: prefix 147*fae6e9adSlinfengpub fn new(prog: &'a [u8], 148*fae6e9adSlinfeng data_offset: usize, 149*fae6e9adSlinfeng data_end_offset: usize) -> Result<EbpfVmFixedMbuff<'a>, Error> 150*fae6e9adSlinfeng 151*fae6e9adSlinfeng// called with EbpfVmRaw:: prefix 152*fae6e9adSlinfengpub fn new(prog: &'a [u8]) -> Result<EbpfVmRaw<'a>, Error> 153*fae6e9adSlinfeng 154*fae6e9adSlinfeng// called with EbpfVmNoData:: prefix 155*fae6e9adSlinfengpub fn new(prog: &'a [u8]) -> Result<EbpfVmNoData<'a>, Error> 156*fae6e9adSlinfeng``` 157*fae6e9adSlinfeng 158*fae6e9adSlinfengThis is used to create a new instance of a VM. The return type is dependent of 159*fae6e9adSlinfengthe struct from which the function is called. For instance, 160*fae6e9adSlinfeng`rbpf::EbpfVmRaw::new(Some(my_program))` would return an instance of `struct 161*fae6e9adSlinfengrbpf::EbpfVmRaw` (wrapped in a `Result`). When a program is loaded, it is 162*fae6e9adSlinfengchecked with a very simple verifier (nothing close to the one for Linux 163*fae6e9adSlinfengkernel). Users are also able to replace it with a custom verifier. 164*fae6e9adSlinfeng 165*fae6e9adSlinfengFor `struct EbpfVmFixedMbuff`, two additional arguments must be passed to the 166*fae6e9adSlinfengconstructor: `data_offset` and `data_end_offset`. They are the offset (byte 167*fae6e9adSlinfengnumber) at which the pointers to the beginning and to the end, respectively, of 168*fae6e9adSlinfengthe memory area of packet data are to be stored in the internal metadata buffer 169*fae6e9adSlinfengeach time the program is executed. Other structs do not use this mechanism and 170*fae6e9adSlinfengdo not need those offsets. 171*fae6e9adSlinfeng 172*fae6e9adSlinfeng```rust,ignore 173*fae6e9adSlinfeng// for struct EbpfVmMbuff, struct EbpfVmRaw and struct EbpfVmRawData 174*fae6e9adSlinfengpub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> 175*fae6e9adSlinfeng 176*fae6e9adSlinfeng// for struct EbpfVmFixedMbuff 177*fae6e9adSlinfengpub fn set_program(&mut self, prog: &'a [u8], 178*fae6e9adSlinfeng data_offset: usize, 179*fae6e9adSlinfeng data_end_offset: usize) -> Result<(), Error> 180*fae6e9adSlinfeng``` 181*fae6e9adSlinfeng 182*fae6e9adSlinfengYou can use for example `my_vm.set_program(my_program);` to change the loaded 183*fae6e9adSlinfengprogram after the VM instance creation. This program is checked with the 184*fae6e9adSlinfengverifier attached to the VM. The verifying function of the VM can be changed at 185*fae6e9adSlinfengany moment. 186*fae6e9adSlinfeng 187*fae6e9adSlinfeng```rust,ignore 188*fae6e9adSlinfengpub type Verifier = fn(prog: &[u8]) -> Result<(), Error>; 189*fae6e9adSlinfeng 190*fae6e9adSlinfengpub fn set_verifier(&mut self, 191*fae6e9adSlinfeng verifier: Verifier) -> Result<(), Error> 192*fae6e9adSlinfeng``` 193*fae6e9adSlinfeng 194*fae6e9adSlinfengNote that if a program has already been loaded into the VM, setting a new 195*fae6e9adSlinfengverifier also immediately runs it on the loaded program. However, the verifier 196*fae6e9adSlinfengis not run if no program has been loaded (if `None` was passed to the `new()` 197*fae6e9adSlinfengmethod when creating the VM). 198*fae6e9adSlinfeng 199*fae6e9adSlinfeng```rust,ignore 200*fae6e9adSlinfengpub type Helper = fn (u64, u64, u64, u64, u64) -> u64; 201*fae6e9adSlinfeng 202*fae6e9adSlinfengpub fn register_helper(&mut self, 203*fae6e9adSlinfeng key: u32, 204*fae6e9adSlinfeng function: Helper) -> Result<(), Error> 205*fae6e9adSlinfeng``` 206*fae6e9adSlinfeng 207*fae6e9adSlinfengThis function is used to register a helper function. The VM stores its 208*fae6e9adSlinfengregisters in a hashmap, so the key can be any `u32` value you want. It may be 209*fae6e9adSlinfenguseful for programs that should be compatible with the Linux kernel and 210*fae6e9adSlinfengtherefore must use specific helper numbers. 211*fae6e9adSlinfeng 212*fae6e9adSlinfeng```rust,ignore 213*fae6e9adSlinfeng// for struct EbpfVmMbuff 214*fae6e9adSlinfengpub fn execute_program(&self, 215*fae6e9adSlinfeng mem: &'a mut [u8], 216*fae6e9adSlinfeng mbuff: &'a mut [u8]) -> Result<(u64), Error> 217*fae6e9adSlinfeng 218*fae6e9adSlinfeng// for struct EbpfVmFixedMbuff and struct EbpfVmRaw 219*fae6e9adSlinfengpub fn execute_program(&self, 220*fae6e9adSlinfeng mem: &'a mut [u8]) -> Result<(u64), Error> 221*fae6e9adSlinfeng 222*fae6e9adSlinfeng// for struct EbpfVmNoData 223*fae6e9adSlinfengpub fn execute_program(&self) -> Result<(u64), Error> 224*fae6e9adSlinfeng``` 225*fae6e9adSlinfeng 226*fae6e9adSlinfengInterprets the loaded program. The function takes a reference to the packet 227*fae6e9adSlinfengdata and the metadata buffer, or only to the packet data, or nothing at all, 228*fae6e9adSlinfengdepending on the kind of the VM used. The value returned is the result of the 229*fae6e9adSlinfengeBPF program. 230*fae6e9adSlinfeng 231*fae6e9adSlinfeng```rust,ignore 232*fae6e9adSlinfengpub fn jit_compile(&mut self) -> Result<(), Error> 233*fae6e9adSlinfeng``` 234*fae6e9adSlinfeng 235*fae6e9adSlinfengJIT-compile the loaded program, for x86_64 architecture. If the program is to 236*fae6e9adSlinfenguse helper functions, they must be registered into the VM before this function 237*fae6e9adSlinfengis called. The generated assembly function is internally stored in the VM. 238*fae6e9adSlinfeng 239*fae6e9adSlinfeng```rust,ignore 240*fae6e9adSlinfeng// for struct EbpfVmMbuff 241*fae6e9adSlinfengpub unsafe fn execute_program_jit(&self, mem: &'a mut [u8], 242*fae6e9adSlinfeng mbuff: &'a mut [u8]) -> Result<(u64), Error> 243*fae6e9adSlinfeng 244*fae6e9adSlinfeng// for struct EbpfVmFixedMbuff and struct EbpfVmRaw 245*fae6e9adSlinfengpub unsafe fn execute_program_jit(&self, mem: &'a mut [u8]) -> Result<(u64), Error> 246*fae6e9adSlinfeng 247*fae6e9adSlinfeng// for struct EbpfVmNoData 248*fae6e9adSlinfengpub unsafe fn execute_program_jit(&self) -> Result<(u64), Error> 249*fae6e9adSlinfeng``` 250*fae6e9adSlinfeng 251*fae6e9adSlinfengCalls the JIT-compiled program. The arguments to provide are the same as for 252*fae6e9adSlinfeng`execute_program()`, again depending on the kind of VM that is used. The result of 253*fae6e9adSlinfengthe JIT-compiled program should be the same as with the interpreter, but it 254*fae6e9adSlinfengshould run faster. Note that if errors occur during the program execution, the 255*fae6e9adSlinfengJIT-compiled version does not handle it as well as the interpreter, and the 256*fae6e9adSlinfengprogram may crash. For this reason, the functions are marked as `unsafe`. 257*fae6e9adSlinfeng 258*fae6e9adSlinfeng## Example uses 259*fae6e9adSlinfeng 260*fae6e9adSlinfeng### Simple example 261*fae6e9adSlinfeng 262*fae6e9adSlinfengThis comes from the unit test `test_vm_add`. 263*fae6e9adSlinfeng 264*fae6e9adSlinfeng```rust 265*fae6e9adSlinfengextern crate rbpf; 266*fae6e9adSlinfeng 267*fae6e9adSlinfengfn main() { 268*fae6e9adSlinfeng 269*fae6e9adSlinfeng // This is the eBPF program, in the form of bytecode instructions. 270*fae6e9adSlinfeng let prog = &[ 271*fae6e9adSlinfeng 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov32 r0, 0 272*fae6e9adSlinfeng 0xb4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov32 r1, 2 273*fae6e9adSlinfeng 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // add32 r0, 1 274*fae6e9adSlinfeng 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // add32 r0, r1 275*fae6e9adSlinfeng 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit 276*fae6e9adSlinfeng ]; 277*fae6e9adSlinfeng 278*fae6e9adSlinfeng // Instantiate a struct EbpfVmNoData. This is an eBPF VM for programs that 279*fae6e9adSlinfeng // takes no packet data in argument. 280*fae6e9adSlinfeng // The eBPF program is passed to the constructor. 281*fae6e9adSlinfeng let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap(); 282*fae6e9adSlinfeng 283*fae6e9adSlinfeng // Execute (interpret) the program. No argument required for this VM. 284*fae6e9adSlinfeng assert_eq!(vm.execute_program().unwrap(), 0x3); 285*fae6e9adSlinfeng} 286*fae6e9adSlinfeng``` 287*fae6e9adSlinfeng 288*fae6e9adSlinfeng### With JIT, on packet data 289*fae6e9adSlinfeng 290*fae6e9adSlinfengThis comes from the unit test `test_jit_ldxh`. 291*fae6e9adSlinfeng 292*fae6e9adSlinfeng```rust 293*fae6e9adSlinfengextern crate rbpf; 294*fae6e9adSlinfeng 295*fae6e9adSlinfengfn main() { 296*fae6e9adSlinfeng let prog = &[ 297*fae6e9adSlinfeng 0x71, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxh r0, [r1+2] 298*fae6e9adSlinfeng 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // exit 299*fae6e9adSlinfeng ]; 300*fae6e9adSlinfeng 301*fae6e9adSlinfeng // Let's use some data. 302*fae6e9adSlinfeng let mem = &mut [ 303*fae6e9adSlinfeng 0xaa, 0xbb, 0x11, 0xcc, 0xdd 304*fae6e9adSlinfeng ]; 305*fae6e9adSlinfeng 306*fae6e9adSlinfeng // This is an eBPF VM for programs reading from a given memory area (it 307*fae6e9adSlinfeng // directly reads from packet data) 308*fae6e9adSlinfeng let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap(); 309*fae6e9adSlinfeng 310*fae6e9adSlinfeng #[cfg(any(windows, not(feature = "std")))] { 311*fae6e9adSlinfeng assert_eq!(vm.execute_program(mem).unwrap(), 0x11); 312*fae6e9adSlinfeng } 313*fae6e9adSlinfeng #[cfg(all(not(windows), feature = "std"))] { 314*fae6e9adSlinfeng // This time we JIT-compile the program. 315*fae6e9adSlinfeng vm.jit_compile().unwrap(); 316*fae6e9adSlinfeng 317*fae6e9adSlinfeng // Then we execute it. For this kind of VM, a reference to the packet 318*fae6e9adSlinfeng // data must be passed to the function that executes the program. 319*fae6e9adSlinfeng unsafe { assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11); } 320*fae6e9adSlinfeng } 321*fae6e9adSlinfeng} 322*fae6e9adSlinfeng``` 323*fae6e9adSlinfeng### Using a metadata buffer 324*fae6e9adSlinfeng 325*fae6e9adSlinfengThis comes from the unit test `test_jit_mbuff` and derives from the unit test 326*fae6e9adSlinfeng`test_jit_ldxh`. 327*fae6e9adSlinfeng 328*fae6e9adSlinfeng```rust 329*fae6e9adSlinfengextern crate rbpf; 330*fae6e9adSlinfeng 331*fae6e9adSlinfengfn main() { 332*fae6e9adSlinfeng let prog = &[ 333*fae6e9adSlinfeng // Load mem from mbuff at offset 8 into R1 334*fae6e9adSlinfeng 0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 335*fae6e9adSlinfeng // ldhx r1[2], r0 336*fae6e9adSlinfeng 0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 337*fae6e9adSlinfeng 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 338*fae6e9adSlinfeng ]; 339*fae6e9adSlinfeng let mem = &mut [ 340*fae6e9adSlinfeng 0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd 341*fae6e9adSlinfeng ]; 342*fae6e9adSlinfeng 343*fae6e9adSlinfeng // Just for the example we create our metadata buffer from scratch, and 344*fae6e9adSlinfeng // we store the pointers to packet data start and end in it. 345*fae6e9adSlinfeng let mut mbuff = &mut [0u8; 32]; 346*fae6e9adSlinfeng unsafe { 347*fae6e9adSlinfeng let mut data = mbuff.as_ptr().offset(8) as *mut u64; 348*fae6e9adSlinfeng let mut data_end = mbuff.as_ptr().offset(24) as *mut u64; 349*fae6e9adSlinfeng *data = mem.as_ptr() as u64; 350*fae6e9adSlinfeng *data_end = mem.as_ptr() as u64 + mem.len() as u64; 351*fae6e9adSlinfeng } 352*fae6e9adSlinfeng 353*fae6e9adSlinfeng // This eBPF VM is for program that use a metadata buffer. 354*fae6e9adSlinfeng let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap(); 355*fae6e9adSlinfeng 356*fae6e9adSlinfeng #[cfg(any(windows, not(feature = "std")))] { 357*fae6e9adSlinfeng assert_eq!(vm.execute_program(mem, mbuff).unwrap(), 0x2211); 358*fae6e9adSlinfeng } 359*fae6e9adSlinfeng #[cfg(all(not(windows), feature = "std"))] { 360*fae6e9adSlinfeng // Here again we JIT-compile the program. 361*fae6e9adSlinfeng vm.jit_compile().unwrap(); 362*fae6e9adSlinfeng 363*fae6e9adSlinfeng // Here we must provide both a reference to the packet data, and to the 364*fae6e9adSlinfeng // metadata buffer we use. 365*fae6e9adSlinfeng unsafe { 366*fae6e9adSlinfeng assert_eq!(vm.execute_program_jit(mem, mbuff).unwrap(), 0x2211); 367*fae6e9adSlinfeng } 368*fae6e9adSlinfeng } 369*fae6e9adSlinfeng} 370*fae6e9adSlinfeng``` 371*fae6e9adSlinfeng 372*fae6e9adSlinfeng### Loading code from an object file; and using a virtual metadata buffer 373*fae6e9adSlinfeng 374*fae6e9adSlinfengThis comes from unit test `test_vm_block_port`. 375*fae6e9adSlinfeng 376*fae6e9adSlinfengThis example requires the following additional crates, you may have to add them 377*fae6e9adSlinfengto your `Cargo.toml` file. 378*fae6e9adSlinfeng 379*fae6e9adSlinfeng```toml 380*fae6e9adSlinfeng[dependencies] 381*fae6e9adSlinfengrbpf = "0.2.0" 382*fae6e9adSlinfengelf = "0.0.10" 383*fae6e9adSlinfeng``` 384*fae6e9adSlinfeng 385*fae6e9adSlinfengIt also uses a kind of VM that uses an internal buffer used to simulate the 386*fae6e9adSlinfeng`sk_buff` used by eBPF programs in the kernel, without having to manually 387*fae6e9adSlinfengcreate a new buffer for each packet. It may be useful for programs compiled for 388*fae6e9adSlinfengthe kernel and that assumes the data they receive is a `sk_buff` pointing to 389*fae6e9adSlinfengthe packet data start and end addresses. So here we just provide the offsets at 390*fae6e9adSlinfengwhich the eBPF program expects to find those pointers, and the VM handles the 391*fae6e9adSlinfengbuffer update so that we only have to provide a reference to the packet data 392*fae6e9adSlinfengfor each run of the program. 393*fae6e9adSlinfeng 394*fae6e9adSlinfeng```rust 395*fae6e9adSlinfengextern crate elf; 396*fae6e9adSlinfenguse std::path::PathBuf; 397*fae6e9adSlinfeng 398*fae6e9adSlinfengextern crate rbpf; 399*fae6e9adSlinfenguse rbpf::helpers; 400*fae6e9adSlinfeng 401*fae6e9adSlinfengfn main() { 402*fae6e9adSlinfeng // Load a program from an ELF file, e.g. compiled from C to eBPF with 403*fae6e9adSlinfeng // clang/LLVM. Some minor modification to the bytecode may be required. 404*fae6e9adSlinfeng let filename = "examples/load_elf__block_a_port.elf"; 405*fae6e9adSlinfeng 406*fae6e9adSlinfeng let path = PathBuf::from(filename); 407*fae6e9adSlinfeng let file = match elf::File::open_path(&path) { 408*fae6e9adSlinfeng Ok(f) => f, 409*fae6e9adSlinfeng Err(e) => panic!("Error: {:?}", e), 410*fae6e9adSlinfeng }; 411*fae6e9adSlinfeng 412*fae6e9adSlinfeng // Here we assume the eBPF program is in the ELF section called 413*fae6e9adSlinfeng // ".classifier". 414*fae6e9adSlinfeng let text_scn = match file.get_section(".classifier") { 415*fae6e9adSlinfeng Some(s) => s, 416*fae6e9adSlinfeng None => panic!("Failed to look up .classifier section"), 417*fae6e9adSlinfeng }; 418*fae6e9adSlinfeng 419*fae6e9adSlinfeng let prog = &text_scn.data; 420*fae6e9adSlinfeng 421*fae6e9adSlinfeng // This is our data: a real packet, starting with Ethernet header 422*fae6e9adSlinfeng let packet = &mut [ 423*fae6e9adSlinfeng 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 424*fae6e9adSlinfeng 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 425*fae6e9adSlinfeng 0x08, 0x00, // ethertype 426*fae6e9adSlinfeng 0x45, 0x00, 0x00, 0x3b, // start ip_hdr 427*fae6e9adSlinfeng 0xa6, 0xab, 0x40, 0x00, 428*fae6e9adSlinfeng 0x40, 0x06, 0x96, 0x0f, 429*fae6e9adSlinfeng 0x7f, 0x00, 0x00, 0x01, 430*fae6e9adSlinfeng 0x7f, 0x00, 0x00, 0x01, 431*fae6e9adSlinfeng 0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr 432*fae6e9adSlinfeng 0xd1, 0xe5, 0xc4, 0x9d, 433*fae6e9adSlinfeng 0xd4, 0x30, 0xb5, 0xd2, 434*fae6e9adSlinfeng 0x80, 0x18, 0x01, 0x56, 435*fae6e9adSlinfeng 0xfe, 0x2f, 0x00, 0x00, 436*fae6e9adSlinfeng 0x01, 0x01, 0x08, 0x0a, // start data 437*fae6e9adSlinfeng 0x00, 0x23, 0x75, 0x89, 438*fae6e9adSlinfeng 0x00, 0x23, 0x63, 0x2d, 439*fae6e9adSlinfeng 0x71, 0x64, 0x66, 0x73, 440*fae6e9adSlinfeng 0x64, 0x66, 0x0a 441*fae6e9adSlinfeng ]; 442*fae6e9adSlinfeng 443*fae6e9adSlinfeng // This is an eBPF VM for programs using a virtual metadata buffer, similar 444*fae6e9adSlinfeng // to the sk_buff that eBPF programs use with tc and in Linux kernel. 445*fae6e9adSlinfeng // We must provide the offsets at which the pointers to packet data start 446*fae6e9adSlinfeng // and end must be stored: these are the offsets at which the program will 447*fae6e9adSlinfeng // load the packet data from the metadata buffer. 448*fae6e9adSlinfeng let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap(); 449*fae6e9adSlinfeng 450*fae6e9adSlinfeng // We register a helper function, that can be called by the program, into 451*fae6e9adSlinfeng // the VM. The `bpf_trace_printf` is only available when we have access to 452*fae6e9adSlinfeng // the standard library. 453*fae6e9adSlinfeng #[cfg(feature = "std")] { 454*fae6e9adSlinfeng vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, 455*fae6e9adSlinfeng helpers::bpf_trace_printf).unwrap(); 456*fae6e9adSlinfeng } 457*fae6e9adSlinfeng 458*fae6e9adSlinfeng // This kind of VM takes a reference to the packet data, but does not need 459*fae6e9adSlinfeng // any reference to the metadata buffer: a fixed buffer is handled 460*fae6e9adSlinfeng // internally by the VM. 461*fae6e9adSlinfeng let res = vm.execute_program(packet).unwrap(); 462*fae6e9adSlinfeng println!("Program returned: {:?} ({:#x})", res, res); 463*fae6e9adSlinfeng} 464*fae6e9adSlinfeng``` 465*fae6e9adSlinfeng 466*fae6e9adSlinfeng## Building eBPF programs 467*fae6e9adSlinfeng 468*fae6e9adSlinfengBesides passing the raw hexadecimal codes for building eBPF programs, two other 469*fae6e9adSlinfengmethods are available. 470*fae6e9adSlinfeng 471*fae6e9adSlinfeng### Assembler 472*fae6e9adSlinfeng 473*fae6e9adSlinfengThe first method consists in using the assembler provided by the crate. 474*fae6e9adSlinfeng 475*fae6e9adSlinfeng```rust 476*fae6e9adSlinfengextern crate rbpf; 477*fae6e9adSlinfenguse rbpf::assembler::assemble; 478*fae6e9adSlinfeng 479*fae6e9adSlinfenglet prog = assemble("add64 r1, 0x605 480*fae6e9adSlinfeng mov64 r2, 0x32 481*fae6e9adSlinfeng mov64 r1, r0 482*fae6e9adSlinfeng be16 r0 483*fae6e9adSlinfeng neg64 r2 484*fae6e9adSlinfeng exit").unwrap(); 485*fae6e9adSlinfeng 486*fae6e9adSlinfeng#[cfg(feature = "std")] { 487*fae6e9adSlinfeng println!("{:?}", prog); 488*fae6e9adSlinfeng} 489*fae6e9adSlinfeng``` 490*fae6e9adSlinfeng 491*fae6e9adSlinfengThe above snippet will produce: 492*fae6e9adSlinfeng 493*fae6e9adSlinfeng```rust,ignore 494*fae6e9adSlinfengOk([0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, 495*fae6e9adSlinfeng 0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 496*fae6e9adSlinfeng 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 497*fae6e9adSlinfeng 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 498*fae6e9adSlinfeng 0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 499*fae6e9adSlinfeng 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) 500*fae6e9adSlinfeng``` 501*fae6e9adSlinfeng 502*fae6e9adSlinfengConversely, a disassembler is also available to dump instruction names from 503*fae6e9adSlinfengbytecode in a human-friendly format. 504*fae6e9adSlinfeng 505*fae6e9adSlinfeng```rust 506*fae6e9adSlinfengextern crate rbpf; 507*fae6e9adSlinfenguse rbpf::disassembler::disassemble; 508*fae6e9adSlinfeng 509*fae6e9adSlinfenglet prog = &[ 510*fae6e9adSlinfeng 0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, 511*fae6e9adSlinfeng 0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 512*fae6e9adSlinfeng 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 513*fae6e9adSlinfeng 0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 514*fae6e9adSlinfeng 0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 515*fae6e9adSlinfeng 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 516*fae6e9adSlinfeng]; 517*fae6e9adSlinfeng 518*fae6e9adSlinfengdisassemble(prog); 519*fae6e9adSlinfeng``` 520*fae6e9adSlinfeng 521*fae6e9adSlinfengThis will produce the following output: 522*fae6e9adSlinfeng 523*fae6e9adSlinfeng```txt 524*fae6e9adSlinfengadd64 r1, 0x605 525*fae6e9adSlinfengmov64 r2, 0x32 526*fae6e9adSlinfengmov64 r1, r0 527*fae6e9adSlinfengbe16 r0 528*fae6e9adSlinfengneg64 r2 529*fae6e9adSlinfengexit 530*fae6e9adSlinfeng``` 531*fae6e9adSlinfeng 532*fae6e9adSlinfengPlease refer to [source code](src/assembler.rs) and [tests](tests/assembler.rs) 533*fae6e9adSlinfengfor the syntax and the list of instruction names. 534*fae6e9adSlinfeng 535*fae6e9adSlinfeng### Building API 536*fae6e9adSlinfeng 537*fae6e9adSlinfengThe other way to build programs is to chain commands from the instruction 538*fae6e9adSlinfengbuilder API. It looks less like assembly, maybe more like high-level functions. 539*fae6e9adSlinfengWhat's sure is that the result is more verbose, but if you prefer to build 540*fae6e9adSlinfengprograms this way, it works just as well. If we take again the same sample as 541*fae6e9adSlinfengabove, it would be constructed as follows. 542*fae6e9adSlinfeng 543*fae6e9adSlinfeng```rust 544*fae6e9adSlinfengextern crate rbpf; 545*fae6e9adSlinfenguse rbpf::insn_builder::*; 546*fae6e9adSlinfeng 547*fae6e9adSlinfenglet mut program = BpfCode::new(); 548*fae6e9adSlinfengprogram.add(Source::Imm, Arch::X64).set_dst(1).set_imm(0x605).push() 549*fae6e9adSlinfeng .mov(Source::Imm, Arch::X64).set_dst(2).set_imm(0x32).push() 550*fae6e9adSlinfeng .mov(Source::Reg, Arch::X64).set_src(0).set_dst(1).push() 551*fae6e9adSlinfeng .swap_bytes(Endian::Big).set_dst(0).set_imm(0x10).push() 552*fae6e9adSlinfeng .negate(Arch::X64).set_dst(2).push() 553*fae6e9adSlinfeng .exit().push(); 554*fae6e9adSlinfeng``` 555*fae6e9adSlinfeng 556*fae6e9adSlinfengAgain, please refer to [the source and related tests](src/insn_builder.rs) to 557*fae6e9adSlinfengget more information and examples on how to use it. 558*fae6e9adSlinfeng 559*fae6e9adSlinfeng## Build features 560*fae6e9adSlinfeng 561*fae6e9adSlinfeng### `no_std` 562*fae6e9adSlinfeng 563*fae6e9adSlinfengThe `rbpf` crate has a Cargo feature named "std" that is enabled by default. To 564*fae6e9adSlinfenguse `rbpf` in `no_std` environments this feature needs to be disabled. To do 565*fae6e9adSlinfengthis, you need to modify your dependency on `rbpf` in Cargo.toml to disable the 566*fae6e9adSlinfengenabled-by-default features. 567*fae6e9adSlinfeng 568*fae6e9adSlinfeng```toml 569*fae6e9adSlinfeng[dependencies] 570*fae6e9adSlinfengrbpf = { version = "1.0", default-features = false } 571*fae6e9adSlinfeng``` 572*fae6e9adSlinfeng 573*fae6e9adSlinfengNote that when using this crate in `no_std` environments, the `jit` module 574*fae6e9adSlinfengisn't available. This is because it depends on functions provided by `libc` 575*fae6e9adSlinfeng(`libc::posix_memalign()`, `libc::mprotect()`) which aren't available on 576*fae6e9adSlinfeng`no_std`. 577*fae6e9adSlinfeng 578*fae6e9adSlinfengThe `assembler` module is available, albeit with reduced debugging features. It 579*fae6e9adSlinfengdepends on the `combine` crate providing parser combinators. Under `no_std` 580*fae6e9adSlinfengthis crate only provides simple parsers which generate less descriptive error 581*fae6e9adSlinfengmessages. 582*fae6e9adSlinfeng 583*fae6e9adSlinfeng## Feedback welcome! 584*fae6e9adSlinfeng 585*fae6e9adSlinfengThis is the author's first try at writing Rust code. He learned a lot in the 586*fae6e9adSlinfengprocess, but there remains a feeling that this crate has a kind of C-ish style 587*fae6e9adSlinfengin some places instead of the Rusty look the author would like it to have. So 588*fae6e9adSlinfengfeedback (or PRs) are welcome, including about ways you might see to take 589*fae6e9adSlinfengbetter advantage of Rust features. 590*fae6e9adSlinfeng 591*fae6e9adSlinfengNote that the project expects new commits to be covered by the 592*fae6e9adSlinfeng[Developer's Certificate of Origin](https://wiki.linuxfoundation.org/dco). 593*fae6e9adSlinfengWhen contributing Pull Requests, please sign off your commits accordingly. 594*fae6e9adSlinfeng 595*fae6e9adSlinfeng## Questions / Answers 596*fae6e9adSlinfeng 597*fae6e9adSlinfeng### Why implementing an eBPF virtual machine in Rust? 598*fae6e9adSlinfeng 599*fae6e9adSlinfengAs of this writing, there is no particular use case for this crate at the best 600*fae6e9adSlinfengof the author's knowledge. The author happens to work with BPF on Linux and to 601*fae6e9adSlinfengknow how uBPF works, and he wanted to learn and experiment with Rust—no more 602*fae6e9adSlinfengthan that. 603*fae6e9adSlinfeng 604*fae6e9adSlinfeng### What are the differences with uBPF? 605*fae6e9adSlinfeng 606*fae6e9adSlinfengOther than the language, obviously? Well, there are some differences: 607*fae6e9adSlinfeng 608*fae6e9adSlinfeng* Some constants, such as the maximum length for programs or the length for the 609*fae6e9adSlinfeng stack, differs between uBPF and rbpf. The latter uses the same values as the 610*fae6e9adSlinfeng Linux kernel, while uBPF has its own values. 611*fae6e9adSlinfeng 612*fae6e9adSlinfeng* When an error occurs while a program is run by uBPF, the function running the 613*fae6e9adSlinfeng program silently returns the maximum value as an error code, while rbpf 614*fae6e9adSlinfeng returns Rust type `Error`. 615*fae6e9adSlinfeng 616*fae6e9adSlinfeng* The registration of helper functions, that can be called from within an eBPF 617*fae6e9adSlinfeng program, is not handled in the same way. 618*fae6e9adSlinfeng 619*fae6e9adSlinfeng* The distinct structs permitting to run program either on packet data, or with 620*fae6e9adSlinfeng a metadata buffer (simulated or not) is a specificity of rbpf. 621*fae6e9adSlinfeng 622*fae6e9adSlinfeng* As for performance: theoretically the JITted programs are expected to run at 623*fae6e9adSlinfeng the same speed, while the C interpreter of uBPF should go slightly faster 624*fae6e9adSlinfeng than rbpf. But this has not been asserted yet. Benchmarking both programs 625*fae6e9adSlinfeng would be an interesting thing to do. 626*fae6e9adSlinfeng 627*fae6e9adSlinfeng### Can I use it with the “classic” BPF (a.k.a cBPF) version? 628*fae6e9adSlinfeng 629*fae6e9adSlinfengNo. This crate only works with extended BPF (eBPF) programs. For cBPF programs, 630*fae6e9adSlinfengsuch as used by tcpdump (as of this writing) for example, you may be interested 631*fae6e9adSlinfengin the [bpfjit crate](https://crates.io/crates/bpfjit) written by Alexander 632*fae6e9adSlinfengPolakov instead. 633*fae6e9adSlinfeng 634*fae6e9adSlinfeng### What functionalities are implemented? 635*fae6e9adSlinfeng 636*fae6e9adSlinfengRunning and JIT-compiling eBPF programs work. There is also a mechanism to 637*fae6e9adSlinfengregister user-defined helper functions. The eBPF implementation of the Linux 638*fae6e9adSlinfengkernel comes with [some additional 639*fae6e9adSlinfengfeatures](https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md): 640*fae6e9adSlinfenga high number of helpers, several kinds of maps, tail calls. 641*fae6e9adSlinfeng 642*fae6e9adSlinfeng* Additional helpers should be easy to add, but very few of the existing Linux 643*fae6e9adSlinfeng helpers have been replicated in rbpf so far. 644*fae6e9adSlinfeng 645*fae6e9adSlinfeng* Tail calls (“long jumps” from an eBPF program into another) are not 646*fae6e9adSlinfeng implemented. This is probably not trivial to design and implement. 647*fae6e9adSlinfeng 648*fae6e9adSlinfeng* The interaction with maps is done through the use of specific helpers, so 649*fae6e9adSlinfeng this should not be difficult to add. The maps themselves can reuse the maps 650*fae6e9adSlinfeng in the kernel (if on Linux), to communicate with in-kernel eBPF programs for 651*fae6e9adSlinfeng instance; or they can be handled in user space. Rust has arrays and hashmaps, 652*fae6e9adSlinfeng so their implementation should be pretty straightforward (and may be added to 653*fae6e9adSlinfeng rbpf in the future). 654*fae6e9adSlinfeng 655*fae6e9adSlinfeng### What about program validation? 656*fae6e9adSlinfeng 657*fae6e9adSlinfengThe ”verifier” of this crate is very short and has nothing to do with the 658*fae6e9adSlinfengkernel verifier, which means that it accepts programs that may not be safe. On 659*fae6e9adSlinfengthe other hand, you probably do not run this in a kernel here, so it will not 660*fae6e9adSlinfengcrash your system. Implementing a verifier similar to the one in the kernel is 661*fae6e9adSlinfengnot trivial, and we cannot “copy” it since it is under GPL license. 662*fae6e9adSlinfeng 663*fae6e9adSlinfeng### What about safety then? 664*fae6e9adSlinfeng 665*fae6e9adSlinfengRust has a strong emphasis on safety. Yet to have the eBPF VM work, some 666*fae6e9adSlinfeng`unsafe` blocks of code are used. The VM, taken as an eBPF interpreter, can 667*fae6e9adSlinfengreturn an error but should not crash. Please file an issue otherwise. 668*fae6e9adSlinfeng 669*fae6e9adSlinfengAs for the JIT-compiler, it is a different story, since runtime memory checks 670*fae6e9adSlinfengare more complicated to implement in assembly. It _will_ crash if your 671*fae6e9adSlinfengJIT-compiled program tries to perform unauthorized memory accesses. Usually, it 672*fae6e9adSlinfengcould be a good idea to test your program with the interpreter first. 673*fae6e9adSlinfeng 674*fae6e9adSlinfengOh, and if your program has infinite loops, even with the interpreter, you're 675*fae6e9adSlinfengon your own. 676*fae6e9adSlinfeng 677*fae6e9adSlinfeng## Caveats 678*fae6e9adSlinfeng 679*fae6e9adSlinfeng* This crate is **under development** and the API may be subject to change. 680*fae6e9adSlinfeng 681*fae6e9adSlinfeng* The JIT compiler produces an unsafe program: memory access are not tested at 682*fae6e9adSlinfeng runtime (yet). Use with caution. 683*fae6e9adSlinfeng 684*fae6e9adSlinfeng* A small number of eBPF instructions have not been implemented yet. This 685*fae6e9adSlinfeng should not be a problem for the majority of eBPF programs. 686*fae6e9adSlinfeng 687*fae6e9adSlinfeng* Beware of turnips. Turnips are disgusting. 688*fae6e9adSlinfeng 689*fae6e9adSlinfeng## _To do_ list 690*fae6e9adSlinfeng 691*fae6e9adSlinfeng* Implement some traits (`Clone`, `Drop`, `Debug` are good candidates). 692*fae6e9adSlinfeng* Provide built-in support for user-space array and hash BPF maps. 693*fae6e9adSlinfeng* Improve safety of JIT-compiled programs with runtime memory checks. 694*fae6e9adSlinfeng* Add helpers (some of those supported in the kernel, such as checksum update, 695*fae6e9adSlinfeng could be helpful). 696*fae6e9adSlinfeng* Improve verifier. Could we find a way to directly support programs compiled 697*fae6e9adSlinfeng with clang? 698*fae6e9adSlinfeng* Maybe one day, tail calls? 699*fae6e9adSlinfeng* JIT-compilers for other architectures? 700*fae6e9adSlinfeng* … 701*fae6e9adSlinfeng 702*fae6e9adSlinfeng## License 703*fae6e9adSlinfeng 704*fae6e9adSlinfengFollowing the effort of the Rust language project itself in order to ease 705*fae6e9adSlinfengintegration with other projects, the rbpf crate is distributed under the terms 706*fae6e9adSlinfengof both the MIT license and the Apache License (Version 2.0). 707*fae6e9adSlinfeng 708*fae6e9adSlinfengSee 709*fae6e9adSlinfeng[LICENSE-APACHE](https://github.com/qmonnet/rbpf/blob/main/LICENSE-APACHE) 710*fae6e9adSlinfengand [LICENSE-MIT](https://github.com/qmonnet/rbpf/blob/main/LICENSE-MIT) for 711*fae6e9adSlinfengdetails. 712*fae6e9adSlinfeng 713*fae6e9adSlinfeng## Version 714*fae6e9adSlinfeng[The last commit](https://github.com/qmonnet/rbpf/commit/fe7021b07b08a43b836743a77796d07ce1f4902e) 715*fae6e9adSlinfeng 716*fae6e9adSlinfeng 717*fae6e9adSlinfeng## Inspired by 718*fae6e9adSlinfeng 719*fae6e9adSlinfeng* [uBPF](https://github.com/iovisor/ubpf), a C user-space implementation of an 720*fae6e9adSlinfeng eBPF virtual machine, with a JIT-compiler and disassembler (and also 721*fae6e9adSlinfeng including the assembler from the human-readable form of the instructions, 722*fae6e9adSlinfeng such as in `mov r0, 0x1337`), by Rich Lane for Big Switch Networks (2015) 723*fae6e9adSlinfeng 724*fae6e9adSlinfeng* [_Building a simple JIT in 725*fae6e9adSlinfeng Rust_](https://www.sophiajt.com/building-a-simple-jit-in-rust), 726*fae6e9adSlinfeng by Sophia Turner (2015) 727*fae6e9adSlinfeng 728*fae6e9adSlinfeng* [bpfjit](https://github.com/polachok/bpfjit) (also [on 729*fae6e9adSlinfeng crates.io](https://crates.io/crates/bpfjit)), a Rust crate exporting the cBPF 730*fae6e9adSlinfeng JIT compiler from FreeBSD 10 tree to Rust, by Alexander Polakov (2016) 731*fae6e9adSlinfeng 732*fae6e9adSlinfeng## Other resources 733*fae6e9adSlinfeng 734*fae6e9adSlinfeng* Cilium project documentation about BPF: [_BPF and XDP Reference 735*fae6e9adSlinfeng Guide_](http://docs.cilium.io/en/latest/bpf/) 736*fae6e9adSlinfeng 737*fae6e9adSlinfeng* [Kernel documentation about BPF](https://docs.kernel.org/bpf/) 738*fae6e9adSlinfeng 739*fae6e9adSlinfeng* [_Dive into BPF: a list of reading 740*fae6e9adSlinfeng material_](https://qmonnet.github.io/whirl-offload/2016/09/01/dive-into-bpf), 741*fae6e9adSlinfeng a blog article listing documentation for BPF and related technologies (2016) 742*fae6e9adSlinfeng 743*fae6e9adSlinfeng* [The Rust programming language](https://www.rust-lang.org) 744