lgcosta 928322edf7 feat(debian13): add host prep script and implementation manual
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.
2026-11-12 20:11:09 -03:00

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 in p1-needs.txt, see docs/en/patches.md)
  • scripts/ — fetch/build/patch/VM automation, plus scripts/screencast/ for the videos
  • tests/vm/ — VM suite: 15 gates (tests/vm/NN-*.sh) + lib.sh
  • docs/en/ + docs/pt-BR/ — full bilingual documentation
  • docs/superpowers/ — design spec + implementation plan

License

Ported OpenBSD code retains its original ISC license and copyright notices. New Linux-side code: ISC.

S
Description
Mirror of github.com/lgcosta/pf-linux-port
Readme ISC
82 MiB
0 Stars 1 Watchers 0 Forks
Languages
C 80.8%
Yacc 8.5%
Shell 6.1%
Python 3.6%
Makefile 0.5%
Other 0.5%