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:
1 parent
a84b2c91f3
commit
1fcd7b3046
77 files changed
+28002
-1114
No files matched your search
+3
-1
@@ -40,7 +40,7 @@ deb_cmd() { deb "bash -s" <<<"$1"; }
|
||||
# Run a shell script inside a lab VM (nested ssh from deb with the lab key).
|
||||
# Guest host keys change every lab rebuild -> pin-noise disabled for this hop.
|
||||
VMSSH_OPTS="-o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o LogLevel=ERROR"
|
||||
vm_cmd() { local ip=$1; deb "ssh -i $LAB_KEY_DEB $VMSSH_OPTS root@$ip 'bash -s'" <<<"$2"; }
|
||||
vm_cmd() { local ip=$1; deb "ssh -i $LAB_KEY_DEB $VMSSH_OPTS root@$ip 'sh -s'" <<<"$2"; }
|
||||
|
||||
# --- template rendering: replace @KEY@ tokens from environment + extra K=V ---
|
||||
RENDER_KEYS=(
|
||||
@@ -164,6 +164,7 @@ runcmd_extra() {
|
||||
cat > /etc/local.d/pflab.start <<'EOS'
|
||||
#!/bin/sh
|
||||
sysctl -q -p /etc/sysctl.d/00-pflab.conf 2>/dev/null
|
||||
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > "$f" 2>/dev/null; done
|
||||
IF=$(ip route show default 2>/dev/null | awk '{print $5; exit}')
|
||||
[ -n "$IF" ] || exit 0
|
||||
iptables -t nat -A POSTROUTING -o "$IF" -j MASQUERADE
|
||||
@@ -222,6 +223,7 @@ packages_fixup() { # safety net if cloud-init ran before pf0 had transit up
|
||||
for a in $VMS; do
|
||||
ip=$(vm_ip "$a")
|
||||
vm_cmd "$ip" 'command -v iperf3 >/dev/null 2>&1 && command -v iptables >/dev/null 2>&1 || {
|
||||
grep -q nameserver /etc/resolv.conf 2>/dev/null || echo nameserver 192.168.122.1 >> /etc/resolv.conf
|
||||
. /etc/os-release
|
||||
grep -qE "^[^#]*/community" /etc/apk/repositories || echo "${HOME}/v${VERSION_ID}/community" >> /etc/apk/repositories
|
||||
apk update -q >/dev/null 2>&1
|
||||
|
||||
+120
-89
@@ -1,112 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
# Deterministic staging of OpenBSD 8.0 sources into module/ ports.
|
||||
# Deterministic staging of OpenBSD 8.0 sources into the module/ port.
|
||||
#
|
||||
# Every transformation is logged in docs/porting-notes.md ("porting log").
|
||||
# Re-running refreshes pristine copies while PRESERVING our port edits is
|
||||
# NOT done here — ported files are committed and edited in-tree thereafter;
|
||||
# this script is used (a) first-time staging, (b) `--diff <file>` to compare
|
||||
# our ported copy against pristine upstream for rebase forensics.
|
||||
# Ported files are committed and edited in-tree afterwards; this script is
|
||||
# used (a) for first-time staging, (b) with `--diff <file>` to compare our
|
||||
# ported copy against the pristine upstream file (rebase forensics).
|
||||
set -euo pipefail
|
||||
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
U="$REPO/_vendor/upstream"
|
||||
M="$REPO/module"
|
||||
LOG="$REPO/docs/porting-notes.md"
|
||||
|
||||
# --- shared rename program -------------------------------------------------
|
||||
# BSD type/macro names that collide with Linux uapi or with the kernel's own
|
||||
# macros are renamed to our pf_* equivalents. Applied to the staged headers
|
||||
# and to every ported .c file.
|
||||
pf_sed() {
|
||||
sed -i -E \
|
||||
-e 's/\bstruct ip6_hdr\b/struct pf_ip6_hdr/g' \
|
||||
-e 's/\bstruct ip\b/struct pf_ip/g' \
|
||||
-e 's/\bstruct tcphdr\b/struct pf_tcphdr/g' \
|
||||
-e 's/\bstruct udphdr\b/struct pf_udphdr/g' \
|
||||
-e 's/\bstruct icmp\b/struct pf_icmp/g' \
|
||||
-e 's/\bstruct icmp6_hdr\b/struct pf_icmp6/g' \
|
||||
-e 's/\bstruct mld_hdr\b/struct pf_mld_hdr/g' \
|
||||
-e 's/\bstruct nd_neighbor_solicit\b/struct pf_nd_neighbor_solicit/g' \
|
||||
-e 's/\bstruct rtentry\b/struct pf_rtentry/g' \
|
||||
-e 's/\bstruct ifnet\b/struct pfk_ifnet/g' \
|
||||
-e 's/\bIFF_([A-Z0-9_]+)/PFIFF_\1/g' \
|
||||
-e 's/\bIP_OPTIONS\b/PF_IP_OPTIONS/g' \
|
||||
-e 's/\bIP_RECORD_ROUTE\b/PF_IP_RECORD_ROUTE/g' \
|
||||
-e 's/\bIP_TIMESTAMP\b/PF_IP_TIMESTAMP/g' \
|
||||
-e 's/ip6_fragment[(]/pfk_ip6_fragment(/g' \
|
||||
-e 's/in6_proto_cksum_out[(]/pfk_in6_proto_cksum_out(/g' \
|
||||
-e 's/ip6_forward[(]/pfk_ip6_forward(/g' \
|
||||
-e 's/ifp->if_output[(]/pfk_if_output(/g' \
|
||||
-e 's/pfk_if_output[(]ifp, m, sin6tosa[(]dst[)]/pfk_if_output(ifp, m, (struct sockaddr *)sin6tosa(dst)/g' \
|
||||
-e 's/pfk_if_output[(]ifp, m, sintosa[(]dst[)]/pfk_if_output(ifp, m, (struct sockaddr *)sintosa(dst)/g' \
|
||||
-e 's/^([ \t]*)[^;]*\.(sa|sin|sin6|six|sun)[0-9]*_len[[:space:]]*=[^;]*;/\1;/' \
|
||||
-e 's/struct radix_node \[2\], u_int8_t\);/struct radix_node *, u_int8_t);/' \
|
||||
-e '/^#define[[:space:]]+isupper\(c\)/d' \
|
||||
-e '/^#define[[:space:]]+islower\(c\)/d' \
|
||||
-e '/^#define[[:space:]]+isalpha\(c\)/d' \
|
||||
-e 's/\btcp_mssdflt\b/pfk_tcp_mssdflt/g' \
|
||||
-e 's/([a-z0-9_]+)->p_ucred->cr_ruid/pfk_pruid(\1)/g' \
|
||||
-e 's/([a-z0-9_]+)->p_ucred->cr_uid/pfk_pruid(\1)/g' \
|
||||
-e 's/([a-z0-9_]+)->p_p->ps_pid/pfk_ppid(\1)/g' \
|
||||
-e 's/^([a-zA-Z_][a-zA-Z0-9_ \t\*]*\b[a-zA-Z_][a-zA-Z0-9_]*)\(\);/\1(void);/' \
|
||||
"$@"
|
||||
}
|
||||
|
||||
stage_hdrs() {
|
||||
mkdir -p "$M/include/net" "$M/include/compat/net" "$M/include/compat/sys" "$M/include/compat/crypto"
|
||||
cp -f "$U/sys/net/pfvar.h" "$M/include/net/pfvar.h"
|
||||
cp -f "$U/sys/net/pfvar_priv.h" "$M/include/net/pfvar_priv.h"
|
||||
cp -f "$U/sys/net/if_pflog.h" "$M/include/compat/net/if_pflog.h"
|
||||
cp -f "$U/sys/net/radix.h" "$M/include/compat/net/radix.h"
|
||||
cp -f "$U/sys/net/rtable.h" "$M/include/compat/net/rtable.h"
|
||||
cp -f "$U/sys/net/ifq.h" "$M/include/compat/net/ifq.h"
|
||||
cp -f "$U/sys/net/toeplitz.h" "$M/include/compat/net/toeplitz.h"
|
||||
cp -f "$U/sys/sys/queue.h" "$M/include/compat/sys/queue.h"
|
||||
cp -f "$U/sys/sys/tree.h" "$M/include/compat/sys/tree.h"
|
||||
# NOTE: radix.h / siphash.h / toeplitz.h are NOT copied verbatim — our
|
||||
# cleaned PFLINUX versions live in module/include/compat/{net,crypto}/
|
||||
# (BSD syntax like __bounded / _BYTE_ORDER does not compile in-kernel).
|
||||
mkdir -p "$M/include/net" "$M/include/compat/net" \
|
||||
"$M/include/compat/sys" "$M/include/compat/crypto"
|
||||
cp -f "$U/sys/net/pfvar.h" "$M/include/net/pfvar.h"
|
||||
cp -f "$U/sys/net/pfvar_priv.h" "$M/include/net/pfvar_priv.h"
|
||||
pf_sed "$M/include/net/pfvar.h" "$M/include/net/pfvar_priv.h"
|
||||
|
||||
cp -f "$U/sys/sys/queue.h" "$M/include/compat/sys/queue.h"
|
||||
cp -f "$U/sys/sys/tree.h" "$M/include/compat/sys/tree.h"
|
||||
# GCC requires the attribute AFTER the storage class when 'inline'
|
||||
# follows (OpenBSD writes '__unused static inline').
|
||||
sed -i 's/^__unused static inline/static inline/' \
|
||||
"$M/include/compat/sys/tree.h"
|
||||
|
||||
# NOTE: radix.h / rtable.h / ifq.h / toeplitz.h / siphash.h are NOT
|
||||
# copied verbatim — our cleaned PFLINUX versions live in
|
||||
# module/include/compat/{net,crypto}/ (BSD syntax such as __bounded
|
||||
# or _BYTE_ORDER does not compile in-kernel). Never overwrite them.
|
||||
}
|
||||
|
||||
stage_c() { # relpath upstream -> module/compat|pf
|
||||
local up="$1" dst="$2"
|
||||
cp -f "$up" "$dst"
|
||||
}
|
||||
|
||||
# port_c <upstream-sys-rel> <module-rel> : first-time staging of an OpenBSD
|
||||
# .c file with deterministic transformations (all logged to PORT notes):
|
||||
# 1. all original #include lines -> single '#include <pfk.h>' (+ keep
|
||||
# none: pfvar is pulled by pfk.h chain when needed via -I)
|
||||
# 2. BSD wire struct renames (avoid Linux-uapi collisions):
|
||||
# ip6_hdr→pf_ip6_hdr, struct ip→pf_ip, tcphdr→pf_tcphdr,
|
||||
# udphdr→pf_udphdr, struct icmp→pf_icmp, icmp6_hdr→icmp6hdr
|
||||
# 3. BSD IFF_* flag names -> PFIFF_* (Linux owns IFF_*)
|
||||
# 4. sa_len/sin_len/six_len assignment statements commented out
|
||||
# 5. '#if NPFLOG > 0'-style option headers were never included (dropped)
|
||||
# port_c <upstream-sys-rel> <module-rel>
|
||||
# 1. every '#include' line is removed and replaced by pfk.h + the pfvar
|
||||
# headers; all '#ifdef _KERNEL' guards stay intact (the module is built
|
||||
# with -D_KERNEL=1, so the kernel branches are compiled).
|
||||
# 2. the shared rename program is applied.
|
||||
port_c() {
|
||||
local up="$U/sys/$1" dst="$M/$2"
|
||||
[ -f "$up" ] || { echo "no upstream $1" >&2; return 1; }
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
if [ -f "$dst" ]; then echo "EXISTS: $2 (not re-staged; use --diff)"; return 0; fi
|
||||
{
|
||||
printf '/* PFLINUX port of OpenBSD 8.0 %s — see docs/porting-notes.md */\n' "$1"
|
||||
printf '#include <pfk.h>\n'
|
||||
# keep everything after the last original #include (body)
|
||||
awk 'BEGIN{last=0} /^#include/{last=NR} END{print last}' "$up" |
|
||||
{ read n; tail -n +$((n+1)) "$up"; }
|
||||
} > "$dst.part"
|
||||
sed -i -E \
|
||||
-e 's/\bstruct ip6_hdr\b/struct pf_ip6_hdr/g' \
|
||||
-e 's/\bstruct ip\b/struct pf_ip/g' \
|
||||
-e 's/\bstruct tcphdr\b/struct pf_tcphdr/g' \
|
||||
-e 's/\bstruct udphdr\b/struct pf_udphdr/g' \
|
||||
-e 's/\bstruct icmp\b/struct pf_icmp/g' \
|
||||
-e 's/\bstruct icmp6_hdr\b/struct icmp6hdr/g' \
|
||||
-e 's/\bIFF_([A-Z0-9_]+)/PFIFF_\1/g' \
|
||||
-e 's/\bIP_OPTIONS\b/PF_IP_OPTIONS/g' \
|
||||
-e 's/\bIP_RECORD_ROUTE\b/PF_IP_RECORD_ROUTE/g' \
|
||||
-e 's/\bIP_TIMESTAMP\b/PF_IP_TIMESTAMP/g' \
|
||||
-e 's/->sa_len[[:space:]]*=[^;]*;/\/* PFLINUX sa_len: *\/;/g' \
|
||||
-e 's/([a-z0-9_]*(sa|sin|six|sun)_len)[[:space:]]*=[^;]*;/\/* PFLINUX \1 *\/;/g' \
|
||||
"$dst.part"
|
||||
mv "$dst.part" "$dst"
|
||||
log "port_c $1 -> $2 (includes→pfk.h; struct renames; sa_len nulled)"
|
||||
local up="$U/sys/$1" dst="$M/$2"
|
||||
[ -f "$up" ] || { echo "no upstream $1" >&2; return 1; }
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
if [ -f "$dst" ]; then
|
||||
echo "EXISTS: $2 (not re-staged; use --diff)"
|
||||
return 0
|
||||
fi
|
||||
{
|
||||
printf '/* PFLINUX port of OpenBSD 8.0 %s — see docs/porting-notes.md */\n' "$1"
|
||||
printf '#include <pfk.h>\n'
|
||||
printf '#include <net/pfvar.h>\n'
|
||||
printf '#include <net/pfvar_priv.h>\n\n'
|
||||
sed -E '/^[[:space:]]*#include/d' "$up"
|
||||
} > "$dst.part"
|
||||
pf_sed "$dst.part"
|
||||
mv "$dst.part" "$dst"
|
||||
log "port_c $1 -> $2 (includes dropped -> pfk.h; -D_KERNEL mode; renames)"
|
||||
}
|
||||
|
||||
PORTED_LIST='net/pf.c net/pf_ioctl.c net/pf_norm.c net/pf_if.c net/pf_lb.c
|
||||
net/pf_ruleset.c net/pf_table.c net/pf_osfp.c net/pf_syncookies.c
|
||||
net/ifq.c net/hfsc.c net/fq_codel.c net/if_pflog.c netinet/ip_divert.c
|
||||
crypto/md5.c crypto/sha2.c'
|
||||
# NOTE: radix.c/rtable.c (ported by hand in T10 against our cleaned
|
||||
# compat/net/radix.h) and siphash/toeplitz (own PFLINUX impls) are
|
||||
# deliberately NOT in the auto-port list.
|
||||
# radix.c/rtable.c (hand-ported against our cleaned compat/net/radix.h) and
|
||||
# siphash/toeplitz (own PFLinux implementations) are deliberately NOT in the
|
||||
# automatic list.
|
||||
|
||||
log() { mkdir -p "$(dirname "$LOG")"; printf '\n%s\n```sh\n%s\n```\n' "## $(date -Is) staging" "$*" >> "$LOG"; }
|
||||
log() {
|
||||
mkdir -p "$(dirname "$LOG")"
|
||||
printf '\n## %s staging\n\n```sh\n%s\n```\n' "$(date -Is)" "$*" >> "$LOG"
|
||||
}
|
||||
|
||||
cmd="${1:-stage}"
|
||||
case "$cmd" in
|
||||
stage)
|
||||
log "stage: headers + skeletons"
|
||||
stage_hdrs
|
||||
echo "headers staged: $(find "$M/include/net" "$M/include/compat" -type f | wc -l)"
|
||||
;;
|
||||
port)
|
||||
shift
|
||||
for f in ${*:-$PORTED_LIST}; do
|
||||
case "$f" in
|
||||
net/pf.c|net/pf_ioctl.c|net/pf_norm.c|net/pf_if.c|net/pf_lb.c|\
|
||||
net/pf_ruleset.c|net/pf_table.c|net/pf_osfp.c|net/pf_syncookies.c|\
|
||||
net/ifq.c|net/hfsc.c|net/fq_codel.c|net/if_pflog.c)
|
||||
port_c "$f" "pfsrc/${f##*/}";;
|
||||
netinet/ip_divert.c)
|
||||
port_c "$f" "pfsrc/ip_divert.c";;
|
||||
crypto/md5.c|crypto/sha2.c)
|
||||
port_c "$f" "compat/${f##*/}";;
|
||||
esac
|
||||
done
|
||||
;;
|
||||
--diff)
|
||||
[ -f "$U/$2" ] || { echo "no pristine $2"; exit 1; }
|
||||
diff -u "$U/$2" "$M/$2" | head -80
|
||||
;;
|
||||
*) echo "usage: stage-port.sh [stage|--diff relpath]"; exit 1;;
|
||||
stage)
|
||||
log "stage: headers"
|
||||
stage_hdrs
|
||||
echo "headers staged: $(find "$M/include/net" "$M/include/compat" -type f | wc -l)"
|
||||
;;
|
||||
port)
|
||||
shift
|
||||
for f in ${*:-$PORTED_LIST}; do
|
||||
case "$f" in
|
||||
net/pf.c|net/pf_ioctl.c|net/pf_norm.c|net/pf_if.c|net/pf_lb.c|\
|
||||
net/pf_ruleset.c|net/pf_table.c|net/pf_osfp.c|net/pf_syncookies.c|\
|
||||
net/ifq.c|net/hfsc.c|net/fq_codel.c|net/if_pflog.c)
|
||||
port_c "$f" "pfsrc/${f##*/}" ;;
|
||||
net/radix.c|net/rtable.c)
|
||||
port_c "$f" "compat/${f##*/}" ;;
|
||||
netinet/ip_divert.c)
|
||||
port_c "$f" "pfsrc/ip_divert.c" ;;
|
||||
crypto/md5.c|crypto/sha2.c)
|
||||
port_c "$f" "compat/${f##*/}" ;;
|
||||
esac
|
||||
done
|
||||
;;
|
||||
--diff)
|
||||
[ -f "$U/$2" ] || { echo "no pristine $2"; exit 1; }
|
||||
diff -u "$U/$2" "$M/$2" | head -80
|
||||
;;
|
||||
*)
|
||||
echo "usage: stage-port.sh [stage|port [files...]|--diff relpath]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -28,7 +28,6 @@ done
|
||||
|
||||
lab_env
|
||||
command -v rsync >/dev/null || die "rsync missing on laptop"
|
||||
command -v genisoimage >/dev/null 2>&1 || true # iso is built on deb, not here
|
||||
|
||||
host_prereqs
|
||||
ensure_networks
|
||||
@@ -55,7 +54,9 @@ if [ -n "$PF0_KERNEL" ]; then
|
||||
rsync -a -e "ssh ${SSH_OPTS[*]}" "$PF0_INITRD" "$DEB_USER@$DEB:$BOOT_DIR/initrd"
|
||||
IPATH="$BOOT_DIR/initrd"
|
||||
fi
|
||||
PF0_KB=" <kernel>$KPATH</kernel>"$'\n'" <initrd>$IPATH</initrd>"$'\n'" <cmdline>root=/dev/vda2 ro console=ttyS0,115200n8</cmdline>"
|
||||
# with an initrd, Alpine's initramfs needs its module list on the cmdline;
|
||||
# the no-initrd (built-in drivers, T6) case keeps the plain contract cmdline
|
||||
PF0_KB=" <kernel>$KPATH</kernel>"$'\n'" <initrd>$IPATH</initrd>"$'\n'" <cmdline>root=/dev/vda2 ro console=ttyS0,115200n8 modules=sd-mod,usb-storage,ext4,ena,gve</cmdline>"
|
||||
fi
|
||||
log "pf0 direct kernel boot override: $KPATH"
|
||||
fi
|
||||
@@ -72,6 +73,6 @@ deb_ssh_config
|
||||
laptop_ssh_config
|
||||
|
||||
log "validate: ssh pf0 'ip -br a'"
|
||||
ssh "${SSH_OPTS[@]}" pf0 'ip -br a' || warn "ssh pf0 failed — check $LAPTOP_SSH_FRAG"
|
||||
ssh "${SSH_OPTS[@]}" pf0 'ip -br a' || die "ssh pf0 failed — check $LAPTOP_SSH_FRAG"
|
||||
log "LAB UP: aliases on laptop: ssh pf0|cli|srv|gw2 (ProxyJump $DEB_USER@$DEB)"
|
||||
deb "virsh list" || true
|
||||
@@ -13,16 +13,17 @@ lab_env
|
||||
|
||||
cd "$REPO"
|
||||
FILES=()
|
||||
add() { # add <path...> — files only; dirs expanded
|
||||
add() { # add <path...> — files only; dirs expanded; warns on explicit misses
|
||||
local p
|
||||
for p in "$@"; do
|
||||
if [ -d "$p" ]; then add "$p"/*
|
||||
elif [ -f "$p" ]; then FILES+=("$p")
|
||||
elif [ "$EXPLICIT" = 1 ]; then warn "skip missing: $p"
|
||||
fi
|
||||
done
|
||||
}
|
||||
if [ $# -gt 0 ]; then
|
||||
add "$@"
|
||||
EXPLICIT=0
|
||||
if [ $# -gt 0 ]; then EXPLICIT=1; add "$@"
|
||||
else
|
||||
shopt -s nullglob
|
||||
add out/linux-*-bzImage out/bzImage out/*.ko module/*.ko tools/out/*
|
||||
|
||||
Reference in new issue
Block a user