I have done the following
Steps to reproduce
- Build the kernel from
main as kernel/Makefile does (KSOURCE is linux-6.18.5): cp kernel/config-arm64 .config && make ARCH=arm64 olddefconfig && make ARCH=arm64 Image.
- Boot it and try the legacy tables:
container run --rm --kernel ./Image --cap-add NET_ADMIN alpine:3.20 sh -c \
'apk add -q iptables iptables-legacy; iptables-legacy -t nat -L -n; iptables-legacy -t mangle -L -n'
Current behavior
iptables v1.8.10 (legacy): can't initialize iptables table `nat': Table does not exist (do you need to insmod?)
iptables v1.8.10 (legacy): can't initialize iptables table `mangle': Table does not exist (do you need to insmod?)
iptables-nft works on the same kernel, and both work on the default 6.12.28 kernel.
Cause: the file was generated on 6.1.68 and still carries CONFIG_IP_NF_IPTABLES=y, CONFIG_IP_NF_NAT=y, CONFIG_IP_NF_MANGLE=y, CONFIG_IP_NF_FILTER=y. Newer kernels gate the legacy tables behind CONFIG_NETFILTER_XTABLES_LEGACY (net/netfilter/Kconfig, a bare bool that defaults off); CONFIG_IP_NF_IPTABLES_LEGACY and CONFIG_IP6_NF_IPTABLES_LEGACY depend on it, and IP_NF_NAT, IP_NF_MANGLE and IP_NF_FILTER depend on IP_NF_IPTABLES_LEGACY. The file predates those symbols, so on 6.18.5 olddefconfig leaves them unset and the legacy filter, nat and mangle tables silently drop out while the =y lines stay in the file:
$ make ARCH=arm64 olddefconfig; grep -E "XTABLES_LEGACY|IP_NF_IPTABLES" .config
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP6_NF_IPTABLES=y
# CONFIG_NETFILTER_XTABLES_LEGACY is not set
Effect on Kubernetes node images: apple/container#2120 already shows the two iptables backends are not interchangeable in kindest/node (there node prep calls iptables-nft and fails because the default kernel has no nf_tables). An nft-only kernel inverts it: kind's entrypoint selects the node's backend by counting existing rules and sends a 0-0 tie to legacy, so /usr/sbin/iptables inside the node answers "Table does not exist" and the container k8s node-prep rules cannot apply. kube-proxy itself keeps working because its image carries its own wrapper and picks nft (checked on a Cilium cluster on this kernel: ClusterIP and DNS answer); node-level tools that shell out to iptables-legacy are what break.
Expected behavior
Either the legacy tables the file still lists come back (CONFIG_NETFILTER_XTABLES_LEGACY=y, CONFIG_IP_NF_IPTABLES_LEGACY=y, CONFIG_IP6_NF_IPTABLES_LEGACY=y, which makes the existing IP_NF_* lines take effect again), or the kernel is documented as nft-only and the stale IP_NF_NAT/IP_NF_MANGLE/IP_NF_FILTER lines are removed so the file matches what it builds. Happy to send the PR for whichever you prefer.
Environment
- OS: macOS 26.2 (25C56), Apple silicon
- Xcode / Swift: not involved (kernel build in an ubuntu:24.04 container with gcc 13.3; the Kconfig defaults are toolchain-independent, but I have not run the in-tree
kernel/image path)
- Container: container CLI version 1.0.0 (build: release, commit: ee848e3)
- containerization:
kernel/config-arm64 at main (sha256 dedb03de...), linux-6.18.5
Relevant log output
Found while measuring the config change proposed in #912.
Code of Conduct
I have done the following
Steps to reproduce
mainaskernel/Makefiledoes (KSOURCEis linux-6.18.5):cp kernel/config-arm64 .config && make ARCH=arm64 olddefconfig && make ARCH=arm64 Image.container run --rm --kernel ./Image --cap-add NET_ADMIN alpine:3.20 sh -c \ 'apk add -q iptables iptables-legacy; iptables-legacy -t nat -L -n; iptables-legacy -t mangle -L -n'Current behavior
iptables-nftworks on the same kernel, and both work on the default 6.12.28 kernel.Cause: the file was generated on 6.1.68 and still carries
CONFIG_IP_NF_IPTABLES=y,CONFIG_IP_NF_NAT=y,CONFIG_IP_NF_MANGLE=y,CONFIG_IP_NF_FILTER=y. Newer kernels gate the legacy tables behindCONFIG_NETFILTER_XTABLES_LEGACY(net/netfilter/Kconfig, a bare bool that defaults off);CONFIG_IP_NF_IPTABLES_LEGACYandCONFIG_IP6_NF_IPTABLES_LEGACYdepend on it, andIP_NF_NAT,IP_NF_MANGLEandIP_NF_FILTERdepend onIP_NF_IPTABLES_LEGACY. The file predates those symbols, so on 6.18.5olddefconfigleaves them unset and the legacy filter, nat and mangle tables silently drop out while the=ylines stay in the file:Effect on Kubernetes node images: apple/container#2120 already shows the two iptables backends are not interchangeable in kindest/node (there node prep calls
iptables-nftand fails because the default kernel has no nf_tables). An nft-only kernel inverts it: kind's entrypoint selects the node's backend by counting existing rules and sends a 0-0 tie to legacy, so/usr/sbin/iptablesinside the node answers "Table does not exist" and thecontainer k8snode-prep rules cannot apply. kube-proxy itself keeps working because its image carries its own wrapper and picks nft (checked on a Cilium cluster on this kernel: ClusterIP and DNS answer); node-level tools that shell out toiptables-legacyare what break.Expected behavior
Either the legacy tables the file still lists come back (
CONFIG_NETFILTER_XTABLES_LEGACY=y,CONFIG_IP_NF_IPTABLES_LEGACY=y,CONFIG_IP6_NF_IPTABLES_LEGACY=y, which makes the existingIP_NF_*lines take effect again), or the kernel is documented as nft-only and the staleIP_NF_NAT/IP_NF_MANGLE/IP_NF_FILTERlines are removed so the file matches what it builds. Happy to send the PR for whichever you prefer.Environment
kernel/imagepath)kernel/config-arm64atmain(sha256 dedb03de...), linux-6.18.5Relevant log output
Found while measuring the config change proposed in #912.
Code of Conduct