|
| 1 | +# Ported kernel BPF selftests |
| 2 | + |
| 3 | +Programs here are ports of tests from the Linux kernel tree, under |
| 4 | +`tools/testing/selftests/bpf/progs/`. Each file names its upstream original in a |
| 5 | +header comment. |
| 6 | + |
| 7 | +They are ordinary cases as far as the framework is concerned: discovered |
| 8 | +automatically, and checked at all three levels (IR, `llc`, kernel verifier). The |
| 9 | +point of this directory is breadth of **program type** — between them these |
| 10 | +cover `tracepoint`, `raw_tp`, `tp_btf`, `xdp`, `cgroup/getsockopt`, `netfilter` |
| 11 | +and `kprobe.multi`, most of which nothing else in the suite exercises. |
| 12 | + |
| 13 | +## What a port does and does not prove |
| 14 | + |
| 15 | +A kernel selftest is two halves: the BPF program in `progs/`, and a userspace |
| 16 | +driver in `prog_tests/` that loads it through a skeleton, triggers it, and |
| 17 | +asserts on the result. **Only the BPF half is ported here**, because the |
| 18 | +framework compiles and verifies programs but never runs them. |
| 19 | + |
| 20 | +So these check that PythonBPF emits a loadable, verifiable object for a given |
| 21 | +program type and feature mix. They do not check that the program *behaves* the |
| 22 | +way the kernel's version does. Treat a passing test here as a compiler |
| 23 | +assertion, not a semantic one. |
| 24 | + |
| 25 | +## `WORKAROUND(globals)` |
| 26 | + |
| 27 | +The selftest corpus overwhelmingly reports results through global variables: the |
| 28 | +program writes a global, and the driver reads it back. PythonBPF has no global |
| 29 | +variable support yet, so those become one-entry `HashMap`s keyed by index. |
| 30 | + |
| 31 | +Every such substitution is tagged `WORKAROUND(globals)` in a comment: |
| 32 | + |
| 33 | +```bash |
| 34 | +grep -rn "WORKAROUND(globals)" tests/passing_tests/selftests/ |
| 35 | +``` |
| 36 | + |
| 37 | +This is deliberate scaffolding, not the intended shape. When real globals land, |
| 38 | +these should be rewritten to use them — the tag is there to make that sweep |
| 39 | +mechanical. Note that a map substitution also changes what a future userspace |
| 40 | +driver would read, so it is not purely cosmetic. |
| 41 | + |
| 42 | +## Adding another |
| 43 | + |
| 44 | +Check it against what the compiler actually supports before starting — no loops, |
| 45 | +no BPF-to-BPF calls, no kfuncs, no atomics, no `__builtin_*`, one opaque context |
| 46 | +argument, and only `HashMap` / `PerfEventArray` / `RingBuffer`. A program that |
| 47 | +needs more than one level of struct field access (`ctx->regs.ip`) is also out of |
| 48 | +reach today. |
| 49 | + |
| 50 | +Anything importing from `vmlinux` goes in `vmlinux/` so it is skipped rather |
| 51 | +than failed on machines without a generated `vmlinux.py`. |
0 commit comments