AF_DIVERT family restored & compiling: full socket family (PF_DIVERT=32, sock_register), blocking recv/poll, divert_output-compatible sendmsg reinject, mtag type passthrough; pfk_api decls
This commit is contained in:
1 parent
fe6f767561
commit
ac56534c3b
30 files changed
+2273
-62
No files matched your search
@@ -0,0 +1,101 @@
|
||||
# Architecture guide — one page
|
||||
|
||||
Português: [docs/pt-BR/guide.md](../pt-BR/guide.md).
|
||||
|
||||
## What this port is
|
||||
|
||||
A faithful port of the **OpenBSD 8.0 PF engine** running inside **Linux
|
||||
7.3.4** as one out-of-tree module, `pf.ko`. Nothing is faked: the matching,
|
||||
state, table, normalization and queueing code *is* OpenBSD's, compiled under a
|
||||
compatibility layer; control comes from the real `pfctl` speaking the real
|
||||
OpenBSD ioctl ABI through `/dev/pf`. There is **one global PF instance bound
|
||||
to `init_net`** — exactly like OpenBSD has one kernel; per-netns instances are
|
||||
out of scope.
|
||||
|
||||
Build targets: OpenBSD 8.0 sources (sha256-pinned, `VERSIONS`), Linux 7.3.4
|
||||
(`linux-7.3.4`), `gcc >= 15`, bison. `pfvar.h` v1.548 is shared bit-for-bit
|
||||
between kernel and userland (ioctl encoding per `module/include/pfk.h`).
|
||||
|
||||
## Components
|
||||
|
||||
| Path | Role |
|
||||
|---|---|
|
||||
| `module/pfsrc/` | Ported OpenBSD files: `pf.c` (engine), `pf_ioctl.c` (DIOC* ABI), `pf_norm.c` (scrub/fragments), `pf_table.c`, `pf_ruleset.c`, `pf_if.c`, `pf_lb.c` (pools/NAT ports), `pf_osfp.c`, `pf_syncookies.c`, `ifq.c`/`hfsc.c`/`fq_codel.c` (staged for M5), `if_pflog.c` + `ip_divert.c` (staged references), `divert_sock.c` (divert entry stub), `pfk_mod.c` (load/exit, `/dev/pf`), `pfk_hooks.c` (netfilter data path) |
|
||||
| `module/compat/` | Linux plumbing under the BSD-shaped sources: mbuf-over-`sk_buff` shim (`pfk_mbuf`), kernel glue (malloc/pools/timeouts/locks, `pfk_kern`), interface+address views (`pfk_if`), BSD-semantics IP output/forward (`pfk_ip4`, `pfk_ip6`), socket lookups (`pfk_pcb`), ifq API with priq semantics (`pfk_ifq`), radix/route-table/crypto ports |
|
||||
| `module/include/` | `pfk.h` (master compat header + OpenBSD-style `_IO*` encoding), staged `net/pfvar.h`, `pfk_mbuf.h`, `pfk_net.h`, `pfk_if.h` |
|
||||
| `tools/` | Linux build of OpenBSD 8.0 `pfctl` (single binary), `pdivert` relay, ABI parity harness (`abitest` + `make abi`), offline parse tests (`make test`). Deltas vs upstream: `tools/UPSTREAM.md` |
|
||||
| `scripts/` | `fetch-sources.sh`, `vendorize.sh`, `stage-port.sh` (deterministic staging), `build-kernel.sh`, `build-module.sh`, `vm-*.sh` lab automation |
|
||||
| `tests/vm/` | VM suite gates `01-state.sh … 04-anchors.sh` + `lib.sh`; `tests/confs/` rulesets deployed to the lab |
|
||||
| `patches/kernel/` | Core patch set — currently **empty** (`p1-needs.txt` records why no exports were needed); see [patches.md](patches.md) |
|
||||
|
||||
## Data path (M2, as implemented today)
|
||||
|
||||
OpenBSD runs PF at `IPL_NET` in process-ish context; our compat locks are
|
||||
sleepable, so the hook **never calls `pf_test()` in softirq**. Packets are
|
||||
stolen onto an ordered workqueue (`pfk_netisr`) and the verdict is applied by
|
||||
re-injection, tagged per direction via `skb->mark` so the survivor is not
|
||||
re-queued by our own hook.
|
||||
|
||||
```
|
||||
Linux 7.3.4, module pf.ko
|
||||
NIC ──► netfilter (softirq — enqueue only)
|
||||
PRE_ROUTING PF_IN ─┐ ┌─ LOCAL_OUT PF_OUT
|
||||
POST_ROUTING PF_OUT ─┤ NF_STOLEN ├─ (runs AFTER conntrack)
|
||||
LOCAL_IN/FORWARD: pass-through ┘ POST_ROUTING: NF_IP_PRI_LAST-1
|
||||
│ (skb ref + kmalloc pfk_pkt;
|
||||
│ alloc failure ⇒ NF_ACCEPT = fail-open)
|
||||
▼
|
||||
pfk_netisr workqueue (process context)
|
||||
│
|
||||
pfk_m_wrap_skb(skb)──► struct mbuf shim
|
||||
│
|
||||
pf_test(af, dir, ifp, &m) ◄── the real OpenBSD 8.0 engine:
|
||||
│ scrub/normalize → state lookup
|
||||
│ → rules/anchors/tables/quick
|
||||
│ → state insert → verdict
|
||||
▼
|
||||
pass ──► mark |= PFK_DONE_IN/OUT ──► reinject: PF_IN: netif_rx() (survivor
|
||||
of reassembly allowed through)
|
||||
PF_OUT: skb_dst()->output()
|
||||
block/drop ──► kfree_skb() (+ PF's own return-rst/ICMP generation)
|
||||
fragment-buffered ──► our reference dropped; pf keeps the survivor (m == NULL)
|
||||
```
|
||||
|
||||
Control plane: `/dev/pf` (miscdev, mode 0600, write gated on `CAP_NET_ADMIN`)
|
||||
→ `pfk_ioctl_io()` copies the parameter struct sized from the OpenBSD `_IOR/
|
||||
_IOW` encoding, dispatches into the ported `pfioctl()` (`pf_ioctl.c`) — the
|
||||
full DIOC* ABI as upstream. `pfctl -e/-f/-s/-t` are that same OpenBSD binary,
|
||||
rebuilt.
|
||||
|
||||
## Queues, divert, pflog — today's observable behavior
|
||||
|
||||
- **Queues**: `pfctl` parses `queue`/`queue on` (8.0 syntax); kernel-side the
|
||||
ifq API is implemented by `compat/pfk_ifq.c` with **priq semantics only**;
|
||||
the `pfq` classful qdisc and the HFSC/FQ-CoDel back ends land in **M5**.
|
||||
`ifq.c`/`hfsc.c`/`fq_codel.c` are staged and compile-ready but are not in
|
||||
the module object list yet.
|
||||
- **Divert**: `divert-to`/`divert` tag evaluate to PF's `PF_DIVERT` verdict;
|
||||
`divert_packet()` (`pfsrc/divert_sock.c`) currently **drops the packet with
|
||||
a rate-limited kernel log** because the AF_DIVERT socket family is not yet
|
||||
instantiated. The `pdivert` relay (userspace) exists and expects
|
||||
`socket(PF_DIVERT=32, SOCK_RAW, IPPROTO_DIVERT=254)`.
|
||||
- **pflog**: `pflog_packet()` returns success but **logs nothing** (one-time
|
||||
`pr_warn "packet not logged"`); `if_pflog.c` is staged, netlink back end is
|
||||
M4/M5.
|
||||
|
||||
## Milestones (see feature-matrix.md for per-feature status)
|
||||
|
||||
| Milestone | Scope | Status (2026-11-11) |
|
||||
|---|---|---|
|
||||
| M0 | repo, scripts, kernel build, VM boots 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 | **in progress** — data path implemented, gates 01–04 not all green yet |
|
||||
| M3 | NAT (nat/rdr/binat), scrub e2e, pflog | pending |
|
||||
| M4 | route-to/dup-to/fail-to, divert e2e | pending |
|
||||
| M5 | queues: ifq back ends (hfsc/fq_codel) + `pfq` qdisc | pending |
|
||||
| M6 | docs complete, patchset tidy, full suite green, tagged releases | in progress (this doc set) |
|
||||
|
||||
## Next reads
|
||||
|
||||
[build.md](build.md) → [vm-lab.md](vm-lab.md) → [pf-guide.md](pf-guide.md) →
|
||||
[feature-matrix.md](feature-matrix.md) → [caveats.md](caveats.md).
|
||||
Reference in new issue
Block a user