| BPF vmtest Tool | |
| =============== | |
| https://gcc.gnu.org/wiki/BPFRunTimeTests | |
| This directory contains a Python script for running BPF programs or shell commands | |
| under a live Linux kernel using QEMU virtual machines. | |
| USAGE | |
| ===== | |
| Before using the tool, you must set the directory where vmtest will look for | |
| kernels and store kernel artifacts. You can do this in two ways: | |
| 1. Set the VMTEST_DIR environment variable | |
| 2. Use the --vmtest-dir flag with each command | |
| Note: This is required to use the tool. | |
| Available Options | |
| ----------------- | |
| usage: main.py [-h] [-v DEBUG|INFO|WARNING|ERROR] [--vmtest-dir DIR] {bpf,vmtest,kernel} ... | |
| BPF vmtest tool | |
| positional arguments: | |
| {bpf,vmtest,kernel} Available commands | |
| bpf BPF program management | |
| vmtest Run VM tests | |
| kernel Kernel management | |
| options: | |
| -h, --help show this help message and exit | |
| -v DEBUG|INFO|WARNING|ERROR, --log-level DEBUG|INFO|WARNING|ERROR | |
| Log level | |
| --vmtest-dir DIR Directory for vmtest artifacts (or set VMTEST_DIR env variable) | |
| COMMANDS | |
| ======== | |
| kernel subcommand | |
| ----------------- | |
| Manage kernel builds for use in virtual machines. You must build a | |
| kernel before using it. | |
| Build a kernel: | |
| python main.py --vmtest-dir="/home/user/.bpf-vmtest-tool" kernel build 6.15 | |
| The tool downloads and builds the specified kernel version from | |
| https://www.kernel.org/pub/linux/kernel and stores the build artifacts in | |
| $VMTEST_DIR/kernels/linux-6.15-x86_64. Specifically, it stores bpftool, | |
| libbpf.a, bzImage-6.15-x86_64, and vmlinux.h, which are used when compiling | |
| BPF programs instead of relying on the host system. | |
| List available kernels: | |
| python main.py --vmtest-dir="/home/user/.bpf-vmtest-tool" kernel list | |
| Remove kernels: | |
| python main.py --vmtest-dir="/home/user/.bpf-vmtest-tool" kernel remove 6.15-x86_64 | |
| Note: If the architecture is omitted, the host architecture is assumed. For | |
| example, 6.15 is treated as 6.15-x86_64 on an x86_64 system. | |
| vmtest subcommand | |
| ----------------- | |
| Run BPF programs and commands inside a QEMU virtual machine with a live kernel. | |
| Options: | |
| -k VERSION, --kernel VERSION | |
| Kernel version to boot in the VM. Must be a kernel previously built using | |
| the "kernel build" subcommand. The kernel version should match the format | |
| used during build (e.g., 6.15-x86_64 or just 6.15 for host architecture). | |
| Required: Yes | |
| -r PATH, --rootfs PATH | |
| Path to a root filesystem directory to mount in the VM. | |
| If not specified, the host's root filesystem (/) is mounted by default. | |
| Required: No | |
| Default: / (host root filesystem) | |
| See "Creating a Custom Rootfs" section below for how to build a rootfs from | |
| a container image. | |
| --bpf-src PATH | |
| BPF C source file to compile and load. Mutually exclusive with --bpf-obj. | |
| --bpf-obj PATH | |
| Pre-compiled BPF object to load. Mutually exclusive with --bpf-src. | |
| -c COMMAND, --command COMMAND | |
| Shell command to run in VM. | |
| At least one of --bpf-src, --bpf-obj, or --command is required. | |
| Examples: | |
| Run a shell command inside a live kernel VM: | |
| python main.py vmtest -k 6.15 -c "uname -a" | |
| Load and run a BPF source file with custom rootfs: | |
| python main.py vmtest -k 6.15 --bpf-src fail.c -r $HOME/rootfs/debian-rootfs | |
| The tool compiles the source file using BPF_CC with BPF_CFLAGS and the | |
| kernel-specific vmlinux.h, then generates a skeleton from the compiled BPF | |
| object using bpftool and compiles it with a generated loader to produce | |
| the final userspace binary. | |
| Load a precompiled BPF object file: | |
| python main.py vmtest -k 6.15 --bpf-obj fail.bpf.o | |
| The tool follows the same steps to generate the final userspace binary, except | |
| it skips the BPF object compilation step. | |
| Creating a Custom Rootfs: | |
| You can build a rootfs from a container image using this script: | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| ROOT="$HOME/rootfs" | |
| IMAGE_NAME="debian-bookworm-rootfs" | |
| CTR_NAME="debian-rootfs-ctr" | |
| cat <<'EOF' | podman build -t "$IMAGE_NAME" - | |
| FROM debian:bookworm | |
| RUN apt-get update && \ | |
| apt-get install -y --no-install-recommends \ | |
| libelf1 \ | |
| qemu-guest-agent \ | |
| && \ | |
| apt-get clean && \ | |
| rm -rf /var/lib/apt/lists/* | |
| EOF | |
| CTR_ID=$(podman create --name "$CTR_NAME" "$IMAGE_NAME") | |
| podman export -o "$ROOT/deb.tar" "$CTR_ID" | |
| tar -xf "$ROOT/deb.tar" -C "$ROOT/debian-rootfs" | |
| podman rm "$CTR_NAME" | |
| echo "Debian rootfs ready at: $ROOT/debian-rootfs" | |
| After running this script, use the rootfs with: | |
| python main.py vmtest -k 6.15 -r $HOME/rootfs/debian-rootfs -c "uname -a" | |
| bpf subcommand | |
| -------------- | |
| Compile BPF source code to bytecode using kernel-specific headers. | |
| Options: | |
| compile | |
| Compile a BPF C source file to a BPF object file. | |
| -k VERSION, --kernel VERSION | |
| Kernel version to use for compilation. The tool will use the vmlinux.h | |
| header from this kernel for the compilation. | |
| Required: Yes | |
| -o OUTPUT, --output OUTPUT | |
| Output path for the compiled BPF object file. | |
| Required: Yes | |
| Example: | |
| python main.py --vmtest-dir="/home/user/.bpf-vmtest-tool" bpf compile \ | |
| invalid-memory-access.c -k 6.15 -o /tmp/invalid-memory-access.bpf.o | |
| The compilation stage can be modified using the BPF_CFLAGS environment variable | |
| (default: -c) | |
| Example : | |
| BPF_CFLAGS="-O2 -E" python main.py --vmtest-dir="/home/user/.bpf-vmtest-tool" \ | |
| bpf compile invalid-memory-access.c -k 6.15 -o /tmp/invalid-memory-access.bpf.o | |
| LIMITATIONS | |
| =========== | |
| - Only x86_64 architecture is currently supported | |
| DEPENDENCIES | |
| ============ | |
| - Python >= 3.9 | |
| - vmtest >= v0.18.0 (https://github.com/danobi/vmtest) | |
| - QEMU | |
| - qemu-guest-agent (on guest filesystem) | |
| For compiling kernels: | |
| - pahole | |
| - See https://docs.kernel.org/process/changes.html#current-minimal-requirements | |
| For compiling and loading BPF programs: | |
| - libbpf | |
| - gcc-bpf-unknown-none (https://gcc.gnu.org/wiki/BPFBackEnd#Where_to_find_GCC_BPF) | |
| BUILD FLAGS | |
| =========== | |
| You can customize compiler settings using environment variables: | |
| - BPF_CC: Compiler for the BPF program (default: bpf-unknown-none-gcc) | |
| - BPF_CFLAGS: Extra flags for BPF program compilation (default: "-O2 -Wall -Werror -c") | |
| - BPF_INCLUDES: Include paths for BPF (default: "-I/usr/local/include -I/usr/include") | |
| - VMTEST_CC: Compiler for the user-space loader (default: gcc) | |
| - VMTEST_CFLAGS: Flags for compiling the loader (default: "-g -Wall -Werror") | |
| - VMTEST_LDFLAGS: Linker flags for the loader (default: "-lelf -lz") | |
| Example usage: | |
| BPF_CFLAGS="-O3 -g" BPF_CC="/bpf-gcc-build/gcc/xgcc" \ | |
| python main.py vmtest -k 6.15 --bpf-src fail.c | |
| DEVELOPMENT | |
| =========== | |
| Development dependencies are specified in pyproject.toml and can be installed | |
| using any suitable Python virtual environment manager. | |
| To run the test suite: | |
| python3 -m pytest |