Python-BPF is an LLVM IR generator for eBPF programs written in Python. It uses llvmlite to generate LLVM IR and then compiles to LLVM object files. These object files can be loaded into the kernel for execution. Python-BPF performs compilation without relying on BCC.
Note: This project is under active development and not ready for production use.
- Generate eBPF programs directly from Python.
- Compile to LLVM object files for kernel execution.
- Built with
llvmlite
for IR generation. - Supports maps, helpers, and global definitions for BPF.
- Companion project: pylibbpf, which provides the bindings required for object loading and execution.
Dependencies:
clang
- Python ≥ 3.8
Install via pip:
pip install pythonbpf pylibbpf
import time
from pythonbpf import bpf, map, section, bpfglobal, BPF
from pythonbpf.helper import pid
from pythonbpf.maps import HashMap
from pylibbpf import *
from ctypes import c_void_p, c_int64, c_uint64, c_int32
import matplotlib.pyplot as plt
# This program attaches an eBPF tracepoint to sys_enter_clone,
# counts per-PID clone syscalls, stores them in a hash map,
# and then plots the distribution as a histogram using matplotlib.
# It provides a quick view of process creation activity over 10 seconds.
@bpf
@map
def hist() -> HashMap:
return HashMap(key=c_int32, value=c_uint64, max_entries=4096)
@bpf
@section("tracepoint/syscalls/sys_enter_clone")
def hello(ctx: c_void_p) -> c_int64:
process_id = pid()
one = 1
prev = hist().lookup(process_id)
if prev:
previous_value = prev + 1
print(f"count: {previous_value} with {process_id}")
hist().update(process_id, previous_value)
return c_int64(0)
else:
hist().update(process_id, one)
return c_int64(0)
@bpf
@bpfglobal
def LICENSE() -> str:
return "GPL"
b = BPF()
b.load_and_attach()
hist = BpfMap(b, hist)
print("Recording")
time.sleep(10)
counts = list(hist.values())
plt.hist(counts, bins=20)
plt.xlabel("Clone calls per PID")
plt.ylabel("Frequency")
plt.title("Syscall clone counts")
plt.show()
Python-BPF provides a complete pipeline to write, compile, and load eBPF programs in Python:
-
Python Source Code
- Users write BPF programs in Python using decorators like
@bpf
,@map
,@section
, and@bpfglobal
. - Maps (hash maps), helpers (e.g.,
ktime
,deref
), and tracepoints are defined using Python constructs, preserving a syntax close to standard Python.
- Users write BPF programs in Python using decorators like
-
AST Generation
- The Python
ast
module parses the source code into an Abstract Syntax Tree (AST). - Decorators and type annotations are captured to determine BPF maps, tracepoints, and global variables.
- The Python
-
LLVM IR Emission
- The AST is transformed into LLVM Intermediate Representation (IR) using
llvmlite
. - IR captures BPF maps, control flow, assignments, and calls to helper functions.
- Debug information is emitted for easier inspection.
- The AST is transformed into LLVM Intermediate Representation (IR) using
-
LLVM Object File Compilation
- The LLVM IR (
.ll
) is compiled into a BPF target object file (.o
) usingllc -march=bpf -O2
. - This produces a kernel-loadable ELF object file containing the BPF bytecode.
- The LLVM IR (
-
libbpf Integration (via pylibbpf)
- The compiled object file can be loaded into the kernel using
pylibbpf
. - Maps, tracepoints, and program sections are initialized, and helper functions are resolved.
- Programs are attached to kernel hooks (e.g., syscalls) for execution.
- The compiled object file can be loaded into the kernel using
-
Execution in Kernel
- The kernel executes the loaded eBPF program.
- Hash maps, helpers, and global variables behave as defined in the Python source.
- Output can be read via BPF maps, helper functions, or trace printing.
This architecture eliminates the need for embedding C code in Python, allowing full Python tooling support while generating true BPF object files ready for kernel execution.
-
Create a virtual environment and activate it:
python3 -m venv .venv source .venv/bin/activate
-
Install dependencies:
make install
Then, run any example in
examples
-
Verify an object file with the kernel verifier:
./tools/check.sh check execve2.o
-
Run an object file using
bpftool
:./tools/check.sh run execve2.o
-
Explore LLVM IR output from clang in
examples/c-form
by runningmake
.