From ed3be3156b00ec21f240ef5213b74d19b1715023 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Wed, 4 Nov 2026 15:05:23 +0100 Subject: [PATCH] feat(network): VLAN 11 link radius0 on the nodes, Cilium VLAN bypass VLAN 11 "(11) RADIUS" carries the FreeRADIUS proxy traffic to the UDM RADIUS, which accepts clients from its own networks only. - Talos k8s-{1,2,3}: VLANConfig radius0 (VLAN 11 on uplink), link only, no addresses, IPv6 disabled (VLAN 11 sends RAs). - Cilium bpf.vlanBypass [30, 11]: radius0 is address-less like ens19, so its tagged frames meet the VLAN filter on uplink (#592). Co-Authored-By: Claude Opus 5.5 --- kubernetes/infrastructure/cilium/helmrelease.yaml | 15 ++++++++------- kubernetes/talos/patches/k8s-1.yaml | 15 +++++++++++++++ kubernetes/talos/patches/k8s-2.yaml | 10 ++++++++++ kubernetes/talos/patches/k8s-3.yaml | 10 ++++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/kubernetes/infrastructure/cilium/helmrelease.yaml b/kubernetes/infrastructure/cilium/helmrelease.yaml index d39508c7..273a1dd1 100644 --- a/kubernetes/infrastructure/cilium/helmrelease.yaml +++ b/kubernetes/infrastructure/cilium/helmrelease.yaml @@ -95,19 +95,20 @@ spec: # VLAN-tagged frames, accounted as "VLAN traffic disallowed by VLAN # filter" in cilium_drop_count_total. # - # Only VLAN 30 (v30iot) needs listing. Cilium attaches to devices that - # carry an address, so it sees mgmt0's frames already untagged by the - # 8021q layer — nothing for a VLAN filter to match. ens19 is deliberately - # address-less, so its frames only meet the filter on the shared parent, - # still tagged. Adding 40 would change nothing and would touch the - # datapath carrying etcd and the API. + # Only the address-less macvlan parents need listing: VLAN 30 (ens19, + # v30iot) and VLAN 11 (radius0, freeradius-udm). Cilium attaches to + # devices that carry an address, so it sees mgmt0's frames already + # untagged by the 8021q layer — nothing for a VLAN filter to match. + # ens19 and radius0 are deliberately address-less, so their frames only + # meet the filter on the shared parent, still tagged. Adding 40 would + # change nothing and would touch the datapath carrying etcd and the API. # # The symptom when this is wrong is not a DHCP timeout: a tc-layer drop # reaches an AF_PACKET sender as ENOBUFS, so the CNI dhcp plugin reports # "no buffer space available" (#592). # # Same three-copy problem as policyMapMax above. Takes an agent restart. - vlanBypass: [30] + vlanBypass: [30, 11] # Let pods reach the cluster's own LoadBalancer external IPs; Cilium # redirects the socket directly to the backend pod instead of sending # traffic out to the VIP and back (which fails with L2 announcements). diff --git a/kubernetes/talos/patches/k8s-1.yaml b/kubernetes/talos/patches/k8s-1.yaml index 3f7aa0de..f7b92ce1 100644 --- a/kubernetes/talos/patches/k8s-1.yaml +++ b/kubernetes/talos/patches/k8s-1.yaml @@ -8,6 +8,10 @@ machine: # 10.2.30.0/24 route makes node replies bypass the UDM and breaks every # DNATed flow. net.ipv6.conf.ens19.disable_ipv6: "1" + # radius0 (VLAN 11) is LINK ONLY as well: the macvlan parent for the + # FreeRADIUS attachment. VLAN 11 announces RAs; the node must not + # autoconfigure from them. + net.ipv6.conf.radius0.disable_ipv6: "1" # These two sit on the untagged fallback network, where nothing may run. # Left enabled they autoconfigure a ULA and an IPv6 default route from its # RAs, which ties with mgmt0's and costs the cluster IPv6 egress. @@ -168,6 +172,17 @@ vlanID: 30 parent: uplink up: true --- +# VLAN 11, UniFi "(11) RADIUS": link only, no addresses, no DHCP. Macvlan +# parent of the freeradius-udm attachment +# (kubernetes/apps/authentik/freeradius-network-attachment.yaml), which names +# it as `master`; renaming this link means editing that too. +apiVersion: v1alpha1 +kind: VLANConfig +name: radius0 +vlanID: 11 +parent: uplink +up: true +--- # Pod network, VLAN 48. Node-to-node only: the VXLAN overlay rides it once the # kubelet node IP moves here, and nothing on it is routed off the switch. # diff --git a/kubernetes/talos/patches/k8s-2.yaml b/kubernetes/talos/patches/k8s-2.yaml index 32b16c79..99f0a7f6 100644 --- a/kubernetes/talos/patches/k8s-2.yaml +++ b/kubernetes/talos/patches/k8s-2.yaml @@ -7,6 +7,8 @@ machine: # macvlan parent for the v30iot pod attachments; host addresses on that L2 # make node replies bypass the UDM and break every UDM-DNATed flow. net.ipv6.conf.ens19.disable_ipv6: "1" + # radius0 (VLAN 11): link only — see k8s-1.yaml. + net.ipv6.conf.radius0.disable_ipv6: "1" # Same for the physical ports on the untagged fallback network: left # enabled they take an IPv6 default route from its RAs and cost the # cluster IPv6 egress. @@ -115,6 +117,14 @@ vlanID: 30 parent: uplink up: true --- +# VLAN 11, "(11) RADIUS": link only, no host addressing — see k8s-1.yaml. +apiVersion: v1alpha1 +kind: VLANConfig +name: radius0 +vlanID: 11 +parent: uplink +up: true +--- # Pod network, VLAN 48. Node-to-node only, statically addressed, no gateway # and no DHCP — see k8s-1.yaml. apiVersion: v1alpha1 diff --git a/kubernetes/talos/patches/k8s-3.yaml b/kubernetes/talos/patches/k8s-3.yaml index 20012676..67d9384f 100644 --- a/kubernetes/talos/patches/k8s-3.yaml +++ b/kubernetes/talos/patches/k8s-3.yaml @@ -4,6 +4,8 @@ machine: sysctls: # v30iot NIC carries no host addressing — see k8s-1.yaml. net.ipv6.conf.ens19.disable_ipv6: "1" + # radius0 (VLAN 11): link only — see k8s-1.yaml. + net.ipv6.conf.radius0.disable_ipv6: "1" # Same for the physical ports on the untagged fallback network — see # k8s-1.yaml. net.ipv6.conf.uplink.disable_ipv6: "1" @@ -102,6 +104,14 @@ vlanID: 30 parent: uplink up: true --- +# VLAN 11, "(11) RADIUS": link only, no host addressing — see k8s-1.yaml. +apiVersion: v1alpha1 +kind: VLANConfig +name: radius0 +vlanID: 11 +parent: uplink +up: true +--- # Pod network, VLAN 48. Node-to-node only, statically addressed, no gateway # and no DHCP — see k8s-1.yaml. apiVersion: v1alpha1 -- 2.54.0