From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 3CDDB1FF146 for ; Tue, 23 Jun 2026 14:57:27 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 54FD73479D; Tue, 23 Jun 2026 14:57:06 +0200 (CEST) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH pve-network v3 7/9] sdn: evpn: accept untracked IPv6 NA on EVPN vnet bridges Date: Tue, 23 Jun 2026 14:56:24 +0200 Message-ID: <20260623125626.1195681-8-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260623125626.1195681-1-h.laimer@proxmox.com> References: <20260623125626.1195681-1-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1782219403902 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.086 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: WJOMEDZG74XLHODD2OF3OJE63WTON7TO X-Message-ID-Hash: WJOMEDZG74XLHODD2OF3OJE63WTON7TO X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: In EVPN setups with per-node anycast first-hop gateways, guests may use the shared gateway link-local address as next-hop, while return traffic targets the guest GUA. If an exit node has no neighbor entry for that GUA, it sends an NS. Only the exit-node kernel tracks that NS state. Because ND traffic is seen across EVPN nodes, a non-exit node can receive the guest's NA without a matching local INCOMPLETE entry and can treat it as untracked. Ignoring that NA prevents neighbor learning and can break IPv6 return traffic. Set `accept_untracked_na=2`[1] on EVPN vnet bridges that have IPv6 subnets so valid NA replies are accepted in this distributed gateway topology. Router Advertisements can trigger this, but RA presence is neither a necessary nor a sufficient selector. Keying this to EVPN vnets with IPv6 subnets is therefore more robust, even though it is broader than just looking at whether RAs are enabled. Without this, deployments depend on pre-populated neighbor state (for example guest-initiated traffic/pings first), which is fragile and causes intermittent first-packet IPv6 failures. [1] https://docs.kernel.org/networking/ip-sysctl.html#proc-sys-net-ipv6-variables Signed-off-by: Hannes Laimer --- Notes: v3: - add the missing accept_untracked_na line to the exitnode_local_routing_ipv6 fixture src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 3 +++ .../evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces | 1 + src/test/zones/evpn/exitnode_snat/expected_sdn_interfaces | 1 + src/test/zones/evpn/exitnodenullroute/expected_sdn_interfaces | 1 + src/test/zones/evpn/ipv4ipv6/expected_sdn_interfaces | 1 + src/test/zones/evpn/ipv4ipv6nogateway/expected_sdn_interfaces | 1 + src/test/zones/evpn/ipv6/expected_sdn_interfaces | 1 + src/test/zones/evpn/ipv6underlay/expected_sdn_interfaces | 1 + src/test/zones/evpn/slaac/expected_sdn_interfaces | 1 + 9 files changed, 11 insertions(+) diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm index 9c3304c..d8184eb 100644 --- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm +++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm @@ -302,6 +302,9 @@ sub generate_sdn_config { push @iface_config, "ip-forward on" if $enable_forward_v4; push @iface_config, "ip6-forward on" if $enable_forward_v6; push @iface_config, "arp-accept on" if $ipv4 || $ipv6; + push @iface_config, + "post-up echo 2 > /proc/sys/net/ipv6/conf/$vnetid/accept_untracked_na || true" + if $ipv6; push @iface_config, "vrf $vrf_iface" if $vrf_iface; push(@{ $config->{$vnetid} }, @iface_config) if !$config->{$vnetid}; diff --git a/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces b/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces index b46d4e7..9b268f2 100644 --- a/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces +++ b/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces @@ -9,6 +9,7 @@ iface myvnet mtu 1450 ip6-forward on arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet/accept_untracked_na || true vrf vrf_myzone auto vrf_myzone diff --git a/src/test/zones/evpn/exitnode_snat/expected_sdn_interfaces b/src/test/zones/evpn/exitnode_snat/expected_sdn_interfaces index 0d7d174..3e9b8ad 100644 --- a/src/test/zones/evpn/exitnode_snat/expected_sdn_interfaces +++ b/src/test/zones/evpn/exitnode_snat/expected_sdn_interfaces @@ -28,6 +28,7 @@ iface myvnet2 mtu 1450 ip6-forward on arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet2/accept_untracked_na || true vrf vrf_myzone auto vrf_myzone diff --git a/src/test/zones/evpn/exitnodenullroute/expected_sdn_interfaces b/src/test/zones/evpn/exitnodenullroute/expected_sdn_interfaces index 4bf5ccf..81a3b39 100644 --- a/src/test/zones/evpn/exitnodenullroute/expected_sdn_interfaces +++ b/src/test/zones/evpn/exitnodenullroute/expected_sdn_interfaces @@ -15,6 +15,7 @@ iface myvnet ip-forward on ip6-forward on arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet/accept_untracked_na || true vrf vrf_myzone auto myvnet2 diff --git a/src/test/zones/evpn/ipv4ipv6/expected_sdn_interfaces b/src/test/zones/evpn/ipv4ipv6/expected_sdn_interfaces index 7a5d741..7b1727b 100644 --- a/src/test/zones/evpn/ipv4ipv6/expected_sdn_interfaces +++ b/src/test/zones/evpn/ipv4ipv6/expected_sdn_interfaces @@ -12,6 +12,7 @@ iface myvnet ip-forward on ip6-forward on arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet/accept_untracked_na || true vrf vrf_myzone auto vrf_myzone diff --git a/src/test/zones/evpn/ipv4ipv6nogateway/expected_sdn_interfaces b/src/test/zones/evpn/ipv4ipv6nogateway/expected_sdn_interfaces index 378fa77..4d904be 100644 --- a/src/test/zones/evpn/ipv4ipv6nogateway/expected_sdn_interfaces +++ b/src/test/zones/evpn/ipv4ipv6nogateway/expected_sdn_interfaces @@ -8,6 +8,7 @@ iface myvnet bridge_fd 0 mtu 1450 arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet/accept_untracked_na || true vrf vrf_myzone auto vrf_myzone diff --git a/src/test/zones/evpn/ipv6/expected_sdn_interfaces b/src/test/zones/evpn/ipv6/expected_sdn_interfaces index b2bdbfe..f776122 100644 --- a/src/test/zones/evpn/ipv6/expected_sdn_interfaces +++ b/src/test/zones/evpn/ipv6/expected_sdn_interfaces @@ -10,6 +10,7 @@ iface myvnet mtu 1450 ip6-forward on arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet/accept_untracked_na || true vrf vrf_myzone auto vrf_myzone diff --git a/src/test/zones/evpn/ipv6underlay/expected_sdn_interfaces b/src/test/zones/evpn/ipv6underlay/expected_sdn_interfaces index 3b91f75..ab5988f 100644 --- a/src/test/zones/evpn/ipv6underlay/expected_sdn_interfaces +++ b/src/test/zones/evpn/ipv6underlay/expected_sdn_interfaces @@ -10,6 +10,7 @@ iface myvnet mtu 1450 ip6-forward on arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet/accept_untracked_na || true vrf vrf_myzone auto vrf_myzone diff --git a/src/test/zones/evpn/slaac/expected_sdn_interfaces b/src/test/zones/evpn/slaac/expected_sdn_interfaces index 2e479a3..6853bd4 100644 --- a/src/test/zones/evpn/slaac/expected_sdn_interfaces +++ b/src/test/zones/evpn/slaac/expected_sdn_interfaces @@ -11,6 +11,7 @@ iface myvnet mtu 1450 ip6-forward on arp-accept on + post-up echo 2 > /proc/sys/net/ipv6/conf/myvnet/accept_untracked_na || true vrf vrf_myzone auto vrf_myzone -- 2.47.3