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 B87E31FF136 for ; Mon, 09 Mar 2026 10:14:40 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 36F101D39A; Mon, 9 Mar 2026 10:14:32 +0100 (CET) From: Lukas Sichert To: pve-devel@lists.proxmox.com Subject: [PATCH network] fix #6255: SNAT: fix incorrect IP collection for sdn config Date: Mon, 9 Mar 2026 10:13:45 +0100 Message-ID: <20260309091346.20049-1-l.sichert@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1773047603157 X-SPAM-LEVEL: Spam detection results: 2 AWL -1.199 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 POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes RCVD_IN_MSPIKE_H2 0.001 Average reputation (+2) RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.408 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.819 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.903 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLACK 3 Contains an URL listed in the URIBL blacklist [plugin.pm] Message-ID-Hash: SNNJ44HPJVAQA5XXQEQX7224A3PEIHBP X-Message-ID-Hash: SNNJ44HPJVAQA5XXQEQX7224A3PEIHBP X-MailFrom: l.sichert@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 CC: Lukas Sichert X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On a host with a SimpleZone or EVPN and SNAT configured, when changing the ip address of the bridge that handles the SNAT, the changes are not reflected in /etc/network/interfaces.d/sdn. This happens because the ip address is resolved via 'ip route get 8.8.8.8'. By the time this command is executed, no ifreload has been executed yet, so ip route still contains the old ip address. To use the updated ip address, parse the incoming /network/interfaces file and look up the interface currently used. If the interface is still present and has a gateway configured, but its ip address has changed, update the ip address in the SDN configuration accordingly and log the change to the journal. If the interface or the gateway cannot be found, log this condition to the journal and fall back to the IP address returned by ip route. Here only print the warning for the missing gateway if the device does not have a ip address configured. Signed-off-by: Lukas Sichert --- Notes: This is not a very beautiful nor robust fix to the problem. But without bigger changes for SNAT Stefan and me could not think of a better solution. I have thought about automatically switching to a interface with gateway, if the address reported by ip route cannot be found in /network/interfaces. This would look something like my $ifaces = $interfaces_config->{ifaces}; for my $ifname (sort keys %{$ifaces // {}}) { my $ifgateway = $ifaces->{$ifname}->{gateway}; my $ifaddress = $ifaces->{$ifname}->{address}; if ( $ifgateway && $ifaddress ) { syslog("warning", "using interface $interface with ip address $ifaddress and gateway for SNAT" ); syslog("info", "if you want to use the live kernel routing table for SNAT, delete all gateways from the interfaces file and reapply SDN" ); return ($ifaddress, $ifname); } } But as this would prevent custom runtime routing configurations from being applied for resolving peer addresses in VxLan and EVPN I decided to exclude it. Also I am not very happy about the long warning, but I feel like the Information provided there should not be omitted. If anybody has any opinions or suggestions regarding this, please tell me. Thanks src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 2 +- src/PVE/Network/SDN/Zones/Plugin.pm | 25 ++++++++++++++++++++--- src/PVE/Network/SDN/Zones/SimplePlugin.pm | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm index 8e7ddfd..f69bc48 100644 --- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm +++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm @@ -253,7 +253,7 @@ sub generate_sdn_config { #find outgoing interface my ($outip, $outiface) = - PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip); + PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip, $interfaces_config); if ($outip && $outiface && $is_evpn_gateway) { #use snat, faster than masquerade push @iface_config, diff --git a/src/PVE/Network/SDN/Zones/Plugin.pm b/src/PVE/Network/SDN/Zones/Plugin.pm index 826ebdf..b021899 100644 --- a/src/PVE/Network/SDN/Zones/Plugin.pm +++ b/src/PVE/Network/SDN/Zones/Plugin.pm @@ -8,6 +8,7 @@ use PVE::IPRoute2; use PVE::JSONSchema; use PVE::Cluster; use PVE::Network; +use PVE::SafeSyslog; use PVE::JSONSchema qw(get_standard_option); use base qw(PVE::SectionConfig); @@ -279,9 +280,9 @@ sub del_bridge_fdb { #helper sub get_local_route_ip { - my ($targetip) = @_; + my ($targetip, $interfaces_config) = @_; - my $ip = undef; + my $ip = undef; my $interface = undef; run_command( @@ -296,6 +297,24 @@ sub get_local_route_ip { }, ); + my $interface_in_config = $interfaces_config->{ifaces}->{$interface}; + my $ip_address_in_config = $interface_in_config->{address}; + my $gateway_in_config = $interface_in_config->{gateway}; + +# if the device currently used for routing still has a valid description in /network/interfaces/, use it + if ($interface_in_config && $gateway_in_config) { + if ($ip_address_in_config ne $ip) { + syslog( "warning", +"ip address $ip_address_in_config of interface $interface in /etc/network/interfaces does not match with it ip address reported by ip route: $ip, switching to $ip_address_in_config for SNAT" + ); + } + return ($ip_address_in_config, $interface); + } + + if (!$interface_in_config) { + syslog( "warning", "current SNAT networking interface $interface is not listed in /etc/network/interfaces anymore"); + } elsif (!$gateway_in_config && $ip_address_in_config) { + syslog( "warning", "currently used networking interface $interface does not have a gateway configured in /etc/network/interfaces"); } return ($ip, $interface); } @@ -323,7 +342,7 @@ sub find_local_ip_interface_peers { #if peer is remote, find source with ip route foreach my $address (@{$peers}) { - my ($ip, $interface) = get_local_route_ip($address); + my ($ip, $interface) = get_local_route_ip($address, $network_config); return ($ip, $interface); } } diff --git a/src/PVE/Network/SDN/Zones/SimplePlugin.pm b/src/PVE/Network/SDN/Zones/SimplePlugin.pm index f5cd18e..11c031a 100644 --- a/src/PVE/Network/SDN/Zones/SimplePlugin.pm +++ b/src/PVE/Network/SDN/Zones/SimplePlugin.pm @@ -113,7 +113,7 @@ sub generate_sdn_config { if ($subnet->{snat}) { #find outgoing interface my ($outip, $outiface) = - PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip); + PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip, $interfaces_config); if ($outip && $outiface) { #use snat, faster than masquerade push @iface_config, -- 2.47.3