From 7e46f8fdc25df21fa73ff138474ef4dcb66e8427 Mon Sep 17 00:00:00 2001 From: Adolfo Delorenzo Date: Fri, 15 May 2026 08:55:41 -0600 Subject: [PATCH] fix(kernel): enable nftables address-family handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Third KubeSolo crash from the QEMU validation loop: nft add table ip kubesolo-masq: exit status 1 Error: Could not process rule: Operation not supported That's EOPNOTSUPP from netlink. nf_tables core is loaded (the binary even runs cleanly now after the previous dual-glibc fix), but no address families are registered with it — so any `nft add table ip ...`, `add table inet ...`, etc. is rejected. In modern Linux (5.x / 6.x) the nftables address families are gated by separate BOOL Kconfigs: CONFIG_NF_TABLES_IPV4 "ip" family CONFIG_NF_TABLES_IPV6 "ip6" family CONFIG_NF_TABLES_INET "inet" family (both) CONFIG_NF_TABLES_NETDEV "netdev" family These are bool (not tristate) — they must be built into the kernel; no module to load at runtime. Our shared kernel-container.fragment had CONFIG_NF_TABLES=m (the core) but none of the family Kconfigs, and the arm64 defconfig leaves them off. Fix: enable all four families as =y in kernel-container.fragment. Also pin the NFT expression modules KubeSolo v1.1.4+'s masquerade ruleset depends on (NFT_NAT, NFT_MASQ, NFT_CT, NFT_REDIR, NFT_REJECT, NFT_REJECT_INET, NFT_COMPAT, NFT_FIB + FIB_IPV4/6) as =m — they're already in modules-arm64.list / modules.list and get modprobed at boot, this just makes sure olddefconfig doesn't strip them when applied on top of a minimal defconfig. NF_NAT_MASQUERADE pinned =y because NFT_MASQ select-depends on it; on some kernels it would get auto-selected, on others it gets dropped by olddefconfig if not pinned. This change requires a kernel rebuild — the configs are bool / module defs, not runtime knobs. On the Odroid: rm -rf build/cache/kernel-arm64-generic sudo make kernel-arm64 # ~30-60 min from scratch sudo make rootfs-arm64 disk-image-arm64 x86 needs the same treatment when we cut v0.3.1. Co-Authored-By: Claude Opus 4.7 (1M context) --- build/config/kernel-container.fragment | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/build/config/kernel-container.fragment b/build/config/kernel-container.fragment index 62830a1..9a03999 100644 --- a/build/config/kernel-container.fragment +++ b/build/config/kernel-container.fragment @@ -53,6 +53,34 @@ CONFIG_NF_TABLES=m CONFIG_VETH=m CONFIG_VXLAN=m +# nftables address-family handlers. These are BOOL Kconfigs (not tristate) +# so they have to be built into the kernel — there's no module to modprobe +# at runtime. Without them, `nft add table ip ...` returns EOPNOTSUPP and +# KubeSolo v1.1.4+'s pod-masquerade setup fails at boot. +CONFIG_NF_TABLES_IPV4=y +CONFIG_NF_TABLES_IPV6=y +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y + +# nftables expression modules used by KubeSolo's masquerade ruleset and +# kube-proxy's nft-compat path. Listed in modules.list / modules-arm64.list +# so init loads them at boot. +CONFIG_NFT_NAT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_CT=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_REJECT_INET=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_FIB=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NFT_FIB_IPV6=m + +# IPv4 NAT bits NFT_MASQ depends on. Auto-selected on most kernels but we +# pin them explicitly so olddefconfig doesn't strip them when the fragment +# is applied on top of a minimal defconfig. +CONFIG_NF_NAT_MASQUERADE=y + # Security: AppArmor + Audit CONFIG_AUDIT=y CONFIG_AUDITSYSCALL=y