xref: /DragonOS/kernel/crates/rbpf/README.md (revision fae6e9ade46a52976ad5d099643d51cc20876448)
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