A no_std Rust eBPF foundation library for kernel or kernel-like environments.
It mainly provides three kinds of capabilities:
- Rust bindings for the Linux eBPF UAPI
- Unified abstractions for common BPF maps and helpers
- Basic support for program preprocessing, perf events, and raw tracepoints
This crate is better suited as a building block for an eBPF runtime or host-side implementation than as a standalone userspace loader.
kbpf-basic pulls together the parts of an eBPF runtime that are closely related to execution and are otherwise easy to reimplement repeatedly:
linux_bpf: Linux BPF constants, enums, and struct bindingsmap: map metadata parsing, map creation, and common map operationshelper: host-side entry points for common BPF helpersprog: program metadata and verifier log information parsingperf: perf event structures and buffer supportraw_tracepoint: raw tracepoint attach argument parsingEBPFPreProcessor: map fd / map value relocation before program loading
The current codebase implements or exposes the following:
- Supported map types
ARRAYPERCPU_ARRAYPERF_EVENT_ARRAYHASHPERCPU_HASHLRU_HASHLRU_PERCPU_HASHQUEUESTACKRINGBUF
- Common map operations
lookupupdatedeleteget_next_keylookup_and_deletefor_each- queue/stack
push/pop/peek
- Helper and runtime support
bpf_trace_printk-style outputbpf_perf_event_outputbpf_probe_readbpf_ktime_get_ns- ring buffer helper
- raw tracepoint argument parsing
- perf event mmap/ring page support
This crate does not perform all kernel-specific work by itself. The host environment is expected to implement two key traits:
KernelAuxiliaryOps- Handles map fd/pointer resolution, user-kernel memory copy, time, output, page allocation, and virtual mapping
PerCpuVariantsOps- Handles per-CPU data creation and CPU count discovery
If these traits are not properly wired into your host, many APIs will still compile but will fail at runtime.
A typical integration flow looks like this:
- Implement
KernelAuxiliaryOpsandPerCpuVariantsOpsin your host environment. - Build map metadata from
BpfMapMetaorbpf_attr. - Create a
UnifiedMapwithbpf_map_create. - Run
EBPFPreProcessorbefore loading the program to relocate map references. - Initialize the helper dispatch table with
init_helper_functions. - Parse program metadata, perf arguments, or raw tracepoint arguments as needed.
The following example only shows how the pieces fit together. It is not a complete runnable implementation:
use kbpf_basic::{
EBPFPreProcessor, KernelAuxiliaryOps,
map::{BpfMapMeta, PerCpuVariantsOps, bpf_map_create},
};
struct KernelOps;
struct PerCpuOps;
impl KernelAuxiliaryOps for KernelOps { /* host-side implementation */ }
impl PerCpuVariantsOps for PerCpuOps { /* per-cpu implementation */ }
fn setup(map_meta: BpfMapMeta, insns: Vec<u8>) {
let _map = bpf_map_create::<KernelOps, PerCpuOps>(map_meta, None).unwrap();
let _relocated = EBPFPreProcessor::preprocess::<KernelOps>(insns).unwrap();
}- This is a
no_stdcrate. - The code uses
#![feature(c_variadic)], so it currently requires nightly Rust. - The repository passes a basic
cargo check.
This crate is a good fit if you are:
- building an eBPF subsystem inside your own kernel
- integrating eBPF into a unikernel, exokernel, or teaching kernel
- implementing Linux-like eBPF runtime behavior in a non-Linux environment
If your goal is to load and manage eBPF programs directly from Linux userspace, you will usually still need a loader, verifier, object parsing, and attach flow around this crate. Covering the full userspace experience is not its goal.