| 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 |