The manual is the from-zero path on Debian 13 (trixie): packages, the 7.3.4 kernel tree, pf.ko, the userland, the libvirt lab, the gate suite, the stress test and running PF on the host itself. Every command in it was executed on the lab's Debian 13.7 host, including the toolchain report and the kernel.org checksum. Trixie ships gcc 14 and no gcc-15; the kernel and pf.ko build with gcc 14 unpatched, so the manual documents that instead of the gcc >= 15 the generic install guide asks for.
PF on Linux
Port of the OpenBSD PF (packet filter) to Linux 7.3.4 as an
out-of-tree kernel module — the real PF engine (pf.c, pf_norm.c,
pf_table.c, pf_lb.c, hfsc.c, … ported from OpenBSD 8.0 sources) driven by
the real OpenBSD pfctl over the /dev/pf ioctl ABI.
Status: the filter core, stateful filtering, tables, anchors, NAT
(nat-to/rdr-to/binat-to), forced routing (route-to/dup-to/reply-to),
pools, divert, pflog and the OpenBSD 8.0 queues (HFSC) are verified
in a real libvirt lab — 15/15 gates green. What is still pending is stated
per feature in docs/en/feature-matrix.md.
Screencasts (EN + PT, narrated): docs/en/screencast.md.
Design: docs/superpowers/specs/2026-11-11-pf-linux-port-design.md
· plan: docs/superpowers/plans/2026-11-11-pf-linux-port.md.
Milestones
| Milestone | Scope | Status |
|---|---|---|
| M0 | repo, scripts, kernel build, VM boots the custom kernel | done |
| M1 | compat layer, pf.ko loads, /dev/pf, pfctl -f / -s info |
done |
| M2 | filter core: rules/states/tables/anchors, VM gates 01–04 | done — gates 01/02/03/04 green |
| M3 | NAT (nat-to/rdr-to/binat-to), scrub |
done — gates 05/06/07/09 (incl. 2 MB integrity through a redirect, min-ttl/max-mss measured) |
| M4 | route-to/dup-to/reply-to, pools, divert e2e, pflog | done — divert (11), pflog (12), route-to/dup-to (08), pools (10), reply-to (13) verified |
| M5 | queues: HFSC back end in the data path | done (mechanical) — gate 15: queues load, hfsc attaches, pfctl -s queue -v reports class stats, a 2 MB queued flow is counted by the class. bandwidth = HFSC linkshare (guarantee, not cap; 8.0 has no upperlimit syntax) |
| M6 | docs complete, patchset tidy, full suite green, tagged release | done — docs EN+PT-BR, 15/15 suite green, tagged (v1.0.0) |
What you get
| Area | Feature |
|---|---|
| Filtering | rules, anchors, quick, match/block(drop/return/return-rst)/pass, keep state, syncookies |
| State/Tables | stateful firewall engine, pfr tables (radix + hash, pfctl -t) |
| NAT | nat-to (port pools, sticky-port, static-port), rdr-to, binat-to |
| Scrub | fragment reassembly, overlap drop, min-ttl/max-mss/df/no-df, set reassemble |
| QoS (ALTQ successor) | queue/queue on with OpenBSD 8.0 ifq schedulers: HFSC verified in the data path (gate 15), priq default, FQ-CoDel compiled; pfctl -s queue -v works |
| Divert | divert-to / divert tag + pdivert relay over an in-module PF_DIVERT socket family (verified: packet to userspace and back) |
| Route | route-to/dup-to/reply-to + pools (round-robin, source-hash) verified (fail-to no longer exists in OpenBSD 8.0) |
| Logging | pflogd via /dev/pflog (DLT_PFLOG pcap, OpenBSD record layout) — verified |
| Control | /dev/pf (0600), OpenBSD 8.0 ioctl ABI, Linux build of pfctl (single binary) |
Not in scope: pfsync/CARP failover, IPsec/pfkey, ftp-proxy, per-netns PF
instances, classic-ALTQ-only schedulers (cbq/wfq/red — removed upstream before
OpenBSD 8.0).
Screencasts
Seven narrated screencasts per language (English and Portuguese), 1080p30 with burned-in subtitles, the lab's network diagram drawn over the terminal, and a continuous film that crossfades the phases together. Every video is a real shell session against the Alpine VMs — commands typed key by key, the kernel answering live — with a MiniMax female voice narrating:
./scripts/screencast/build-all.sh # -> out/screencast/{en,pt}/*.mp4
Details, per-phase breakdown and the YouTube description text:
docs/en/screencast.md ·
docs/pt-BR/screencast.md
Quick start
Full recipe: docs/en/install.md. Short version
(commands are read from the scripts):
./scripts/fetch-sources.sh # OpenBSD 8.0 sources (C3SL mirror, sha256-pinned)
./scripts/vendorize.sh # stage the pristine files we port
./scripts/build-kernel.sh # kernel 7.3.4: bzImage + modules_prepare (export patch: none needed)
./scripts/build-module.sh # -> module/pf.ko
make -C tools # -> tools/out/{pfctl,pdivert,pflogd,abitest}
sudo insmod module/pf.ko # /dev/pf (0600) + netfilter hooks
sudo pfctl -f /etc/pf.conf && sudo pfctl -e
Every feature listed above is exercised by the lab suite before you need it;
docs/en/feature-matrix.md says which gate proves
what, and docs/en/pf-guide.md lists the deviations you
should know before putting PF on a path that matters.
VM validation lab (Alpine on libvirt): docs/en/vm-lab.md.
Documentação em português: README.pt-BR.md e
docs/pt-BR/.
Layout
module/— kernel sources: ported PF engine (module/pfsrc) + Linux compat layer (module/compat)tools/— pfctl (static Linux build), pdivert relay, pflogd, ABI harness (make -C tools abi)patches/kernel/— Linux core patch set (currently empty; evidence inp1-needs.txt, seedocs/en/patches.md)scripts/— fetch/build/patch/VM automation, plusscripts/screencast/for the videostests/vm/— VM suite: 15 gates (tests/vm/NN-*.sh) +lib.shdocs/en/+docs/pt-BR/— full bilingual documentationdocs/superpowers/— design spec + implementation plan
License
Ported OpenBSD code retains its original ISC license and copyright notices. New Linux-side code: ISC.