Examples
Relevant source files
- examples/
- examples/load_elf.rs
- examples/allowed_memory.rs
- examples/rbpf_plugin.rs
- examples/date.rs
- examples/disassemble.rs
- examples/to_json.rs
- Cargo.toml
| Example | Requires | Shows |
|---|---|---|
disassemble | std | disassembler::disassemble on a hand-written program |
to_json | — | disassembler::to_insn_vec + json crate: dump an ELF program as JSON |
load_elf | std | Load the .classifier section of load_elf__block_a_port.o with the elf crate, run it on a TCP packet in EbpfVmFixedMbuff (offsets 0x40, 0x50), register bpf_trace_printf |
date | std | EbpfVmNoData, a custom helper (Unix time in seconds at index 1), interpreter vs. x86_64 JIT |
allowed_memory | — | A map-lookup style helper returning a pointer to a static, plus register_allowed_memory. The eBPF object is built from the Aya project in examples/allowed-memory/. |
rbpf_plugin | — | Plugin for bpf_conformance . Reads the program from stdin, takes memory as hex in the first argument, and accepts --jit, --cranelift and --program |
cargo run --example disassemble
cargo run --example load_elf
cargo run --example allowed_memory
cargo build --all-features --release --example rbpf_pluginLoading programs from ELF
load_elf.rs explains why programs built for the kernel can need patching before rbpf runs them. The C source load_elf__block_a_port.c was compiled with:
clang -O2 -emit-llvm -c load_elf__block_a_port.c -o - | \
llc -march=bpf -filetype=obj -o load_elf__block_a_port.oThe kernel rewrites __sk_buff accesses. rbpf does not. The three 4-byte loads of the packet pointers (opcode 0x61) are therefore patched to 8-byte loads (0x79), and the data and data_end offsets moved to 0x40/0x50 so the 64-bit pointers do not overlap.
let file = ElfBytes::<AnyEndian>::minimal_parse(slice).expect("Fail to parse ELF file");
let hdr = file.section_header_by_name(".classifier").unwrap().unwrap();
let prog = file.section_data(&hdr).unwrap().0;
let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
vm.register_helper(rbpf::helpers::BPF_TRACE_PRINTK_IDX, rbpf::helpers::bpf_trace_printf).unwrap();
let res = vm.execute_program(packet).unwrap();Map-style helpers and allowed memory
const BPF_MAP_LOOKUP_ELEM_IDX: u32 = 1;
static MAP_VALUE: Value = Value { result: 1 };
fn bpf_lookup_elem(_map: u64, key_addr: u64, _flags: u64, _u4: u64, _u5: u64) -> u64 {
let key: Key = unsafe { *(key_addr as *const Key) };
if key.protocol == 1 { return core::ptr::addr_of!(MAP_VALUE) as u64; }
0
}
let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
vm.register_helper(BPF_MAP_LOOKUP_ELEM_IDX, bpf_lookup_elem).unwrap();
let start = core::ptr::addr_of!(MAP_VALUE) as u64;
vm.register_allowed_memory(start..start + core::mem::size_of::<Value>() as u64);
assert_eq!(vm.execute_program().unwrap(), 1);Without the register_allowed_memory call, the interpreter rejects the program’s read through the returned pointer as an out-of-bounds load.
AArch64 embedding
There is no example binary for the AArch64 compiler. The reference embedding is the Linux test harness in tests/aarch64_jit.rs (the native::Image type) together with the AxiomOS controller harness in tests/aarch64/managed.rs. See AArch64 JIT and Testing and CI.