From: Lukas Sichert <l.sichert@proxmox.com>
To: pve-devel@lists.proxmox.com
Cc: Lukas Sichert <l.sichert@proxmox.com>
Subject: [PATCH network] fix #6255: SNAT: fix incorrect IP collection for sdn config
Date: Mon, 9 Mar 2026 10:13:45 +0100 [thread overview]
Message-ID: <20260309091346.20049-1-l.sichert@proxmox.com> (raw)
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 <l.sichert@proxmox.com>
---
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
next reply other threads:[~2026-03-09 9:14 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-09 9:13 Lukas Sichert [this message]
2026-03-10 9:09 ` Gabriel Goller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260309091346.20049-1-l.sichert@proxmox.com \
--to=l.sichert@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox