M1 progress: engine port compiles except pf.c; AF_DIVERT socket family; ifq framework

- compat layer extended through the full BSD API surface pf_ioctl/pf_lb/
  pf_if/pf_norm/pf_table/pf_ruleset/radix/md5/sha2 need (all compile):
  cpumem/counters model, ifaddr/ifg groups, cred view, endian+in6 names,
  NAT46/64, SipHash24, mbuf_list, frag6 helpers, ip6 forward/checksum,
  tcp options/FSM names, taskqueue & sysctl shims (documented in
  docs/porting-notes.md)
- pfsrc/divert_sock.c: real BSD divert(4) as runtime-registered PF_DIVERT=32
  socket family inside the module (sock_register; NPROTO=AF_MAX=45 -> zero
  core patches); divert_packet/divert6_packet wired for pf.c
- compat/pfk_ifq.c: OpenBSD 8.0 ifq framework with priq back end; hfsc and
  fq_codel aliases pending M5 (recorded in feature matrix as pending)
- design + plan updated for the divert decision (user-requested)
- stage-port.sh: single deterministic rename program for headers and .c
This commit is contained in:
lgcosta committed 2026-11-11 13:35:53 -03:00
1 parent a84b2c91f3
commit 1fcd7b3046
77 files changed
+28002 -1114

No files matched your search

@@ -124,11 +124,11 @@
- [ ] Step 1: implement + port `pf_route/pf_route6` glue; compile.
- [ ] Step 2: tests `09-routeto.sh` (tcpdump counts wan vs wan2: rr alternation exact, hash-source deterministic per src; loop-guard: pf0->pf0 route-to with gw=pf0 must not livelock: bounded pkts then block `block loop drop`? use upstream `pf_route` loop detection → drop; assert), `10-dup-fail.sh`; commit.
### Task 15: divert
**Files:** `module/pf/pf_divert_nl.c` (kernel: `netlink_kernel_create(NETLINK_USERSOCK, proto=31? use NETLINK_USERSOCK group id per divert port)`, table port→socket, `divert-to` path: copy skb → nl msg `{cookie, divport, af, ip hdr+payload}`; reinjection path on user `send`: parse → route per original semantics `ip_divert.c` reference (divert-to: re-route to original dst via gw if needed; plain divert tag: re-enter `netif_receive_skb`/local_xmit per 8.0 `pf_send` behavior; drop-after-timeout via per-packet timer default 5s? match upstream: no accept → packet never delivered (copy consumed? original held until accept/timeout then free — mirror OpenBSD: keep, timeout drop).
**Interfaces:** `pdivert -p 10000` + rule `pass in divert-to 127.0.0.1 10000`? upstream model: `divert-to` sends to divert socket at **host:port**; ours: netlink port id; document mapping in `docs/en/divert.md`; stats `DIOCBUSYSTATS` unchanged.
- [ ] Step 1: implement + tool link already from T8.
- [ ] Step 2: test `11-divert.sh`: pdivert on pf0 flips a byte of ping payload → cli receives modified echo-replies; kill pdivert → traffic stops (timeout) not leaks; commit.
### Task 15: divert — AF_DIVERT socket family (design §4.4, user-requested)
**Files:** `module/pfsrc/divert_sock.c` (kernel-internal PF_DIVERT=32 family via `sock_register`, zero core patches), `tools/pdivert/` (BSD divert(8) workflow over the socket), tests reuse upstream `regress/sys/net/pf_divert` semantics (Perl client adapted to our socket).
**Interfaces:** `divert_packet/divert6_packet(mbuf, dir, port)` consumed by pf.c (already wired); userspace ABI: `socket(PF_DIVERT=32, SOCK_RAW, IPPROTO_DIVERT=254)`, `bind(sin_port=divert_port)`, `recvmsg` → raw IP packet + cmsgs (IFINDEX/DIR/TYPE/DST), `sendmsg` → re-inject (divert-to ⇒ local `netif_rx`; tag-divert ⇒ re-route).
- [ ] Step 1: kernel self-test (module_param `divert_selftest`): inject synthetic packet → socket recv → send → observed re-injection; no netfilter re-entry loop.
- [ ] Step 2: test `11-divert.sh`: pdivert on pf0 flips a byte of ping payload → cli receives modified echo-replies; kill pdivert → traffic stops (no leak); `divert-to 10.0.99.9 10000` cross-host variant; commit.
### Task 16: ifq + pfq queueing
**Files:** `module/ifq/ifq.c ifq.h hfsc.c fq_codel.c` ported (skb-backed via pfk_mbuf), `module/pfq/pfq_qdisc.c` (classful qdisc `pfq`: root=ifq attach; ops: enqueue→`ifq_enqueue(ifq_for_class)`, dequeue loop; classid = queue index from pf rule queue tag), `module/pf/pf_ifq_bridge.c` (DIOCADDQUEUE/GETQUEUES/GETQUEUE/QSTATS + `pf_test` queue assignment + `set queue` default-class + ifq per-iface registry via `pfq_q_enter`), scripts `pf-qdisc.sh` auto-attach on `queue on` detection at DIOCADDQUEUE.
@@ -139,16 +139,22 @@ priority bits). `DIOCADDQUEUE/DIOCGETQUEUES/DIOCGETQUEUE/DIOCGETQSTATS` (the rea
fq_codel** with rate gates (§7); class visibility via `tc -s qdisc show` is a
stretch goal, counters via `pfctl` are the gate.
### 4.4 divert
- In-pf action `divert-to host:port` / tag `divert port`: packet copied to
userspace divert channel; **channel = kernel netlink** (`NETLINK_USERSOCK` proto)
because Linux has no `AF_DIVERT` (in-tree reference logic ported from
`sys/netinet/ip_divert.c`; userland `pdivert` tool implements `divert(8)`-style
rewrite-loop over the netlink channel; wire format documented; `DIOCBUSYSTATS`
etc. unchanged). Diverted flow re-enters via the channel write →
`__dev_queue_xmit`/`netif_receive_skb` following ip_divert `divert_output`
semantics (re-route via gw neighbor for `divert-to`).
- Test parity anchored by upstream `regress/sys/net/pf_divert` semantics.
### 4.4 divert — real AF_DIVERT in the kernel (no netlink substitute)
OpenBSD's `divert(4)` socket family is ported as a **runtime-registered
socket family inside pf.ko**: Linux 7.3 registers protocol families with
`sock_register()` and `NPROTO = AF_MAX = 45`, so BSD's `PF_DIVERT = 32`
(the unused legacy PF_IUCV slot) fits with **zero core changes**. Implemented
in `module/pfsrc/divert_sock.c`: `socket(PF_DIVERT, SOCK_RAW, IPPROTO_DIVERT)`
+ `bind(port)` + `recvmsg/sendmsg`, packet metadata via cmsg (ifindex, dir,
divert type, original dst). `divert_packet()/divert6_packet()` (called by the
ported pf.c) queue to the bound socket; `sendmsg` re-injects with OpenBSD
semantics: `PF_DIVERT_TO` → local delivery (`netif_rx` on the recorded
interface), plain `divert` tag → re-route (`dst->output`), mirroring
`ip_divert.c:divert_output()`. The BSD `divert(8)` workflow (upstream
`regress/sys/net/pf_divert`) drives this socket unchanged; our shipped
`pdivert` is a thin Linux port. Wire format documented in
`docs/en/divert-wireformat.md`. pflog keeps its netlink multicast channel
(slot PFLOG_PROTO=1 on `NETLINK_USERSOCK`).
### 4.5 route-to / dup-to / fail-to
`pf_route6`/`pf_route` port: pool selection via `pf_lb.c` (as-is), next-hop