public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: Re: [PATCH networking v2] fix #6255: SNAT: fix incorrect IP collection for sdn config
Date: Mon, 22 Jun 2026 14:53:50 +0200	[thread overview]
Message-ID: <87cf364d-2253-4d47-b6f0-29120f12fceb@proxmox.com> (raw)
In-Reply-To: <20260327153959.87687-1-l.sichert@proxmox.com>

functionality-wise looks fine, some annotations to the code inline

On 3/27/26 4:39 PM, Lukas Sichert wrote:
> 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.
> 
> Determine the IP version (IPv4 or IPv6) of the address used with 'ip
> route'. Then parse the incoming /etc/network/interfaces file and look up
> the interface currently used by 'ip route'. If the interface is still
> present and has a gateway and ip address with the correct version, but
> the ip address has changed, update the ip address in the SDN
> configuration accordingly and log the change to the journal.
> 
> Signed-off-by: Lukas Sichert <l.sichert@proxmox.com>
> ---
> 
> Notes:
>     changes from v1 to v2: (thanks @Gabriel, @Stefan)
>     -add handling for IPV6 addresses
>     -remove warnings for missing ip/gateway, as they might trigger
>       in some legitimate scenarios
>     -add canonical formatting for IPv4 and IPV6
>     -execute make tidy
>     -small restructuring of if clauses for earlier exit
>     -fix typos
>     
>     concerning the ignoring of live routing tables:
>     
>     The function only determines the currently used interface (via 'ip
>     route') and its ip address and returns these two. The gateway configured
>     in /etc/network/interfaces is only used to verify that the interface is
>     still a valid candidate after an 'ifreload -a'. As it cannot switch
>     interfaces relative what to 'ip route' reports it should not be able
>     influence gateway selection.
>     
>     If I am missing a more obscure way or an edge case where gateway
>     selection could still be affected, please let me know.
>     
>     Also I have thought about adding "... does not match with its actual ip
>     address reported by ip route ...", but after this would be displayed
>     'ifreload -a' gets executed and 'ip route' changes.
> 
>  src/PVE/Network/SDN/Zones/EvpnPlugin.pm   |  5 ++--
>  src/PVE/Network/SDN/Zones/Plugin.pm       | 30 +++++++++++++++++++++--
>  src/PVE/Network/SDN/Zones/SimplePlugin.pm |  5 ++--
>  3 files changed, 34 insertions(+), 6 deletions(-)
> 
> diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
> index 8e7ddfd..91b8a7e 100644
> --- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
> +++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
> @@ -252,8 +252,9 @@ sub generate_sdn_config {
>          if ($subnet->{snat}) {
>  
>              #find outgoing interface
> -            my ($outip, $outiface) =
> -                PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip);
> +            my ($outip, $outiface) = 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..1d18acc 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,7 +280,7 @@ sub del_bridge_fdb {
>  #helper
>  
>  sub get_local_route_ip {
> -    my ($targetip) = @_;
> +    my ($targetip, $interfaces_config) = @_;
>  
>      my $ip = undef;
>      my $interface = undef;
> @@ -296,6 +297,31 @@ sub get_local_route_ip {
>  
>          },
>      );
> +    my $ipversion = Net::IP::ip_is_ipv6($targetip) ? 6 : 4;
> +    my $interface_in_config = $interfaces_config->{ifaces}->{$interface};
> +    my $ip_address_in_config = undef;
> +    my $gateway_in_config = undef;
> +
> +    if ($ipversion == 6) {
> +        $ip_address_in_config = PVE::Network::canonical_ip($interface_in_config->{address6});
> +        $gateway_in_config = PVE::Network::canonical_ip($interface_in_config->{gateway6});
> +    } else {
> +        $ip_address_in_config = PVE::Network::canonical_ip($interface_in_config->{address});
> +        $gateway_in_config = PVE::Network::canonical_ip($interface_in_config->{gateway});
> +    }

nit: potentially the following is a bit nicer?

my $address_key = ($ipversion == 6) ? 'address6' : 'address';
my $ip_address_in_config =
PVE::Network::canonical_ip($interface_in_config->{$address_key});


> +    # 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 eq $ip) {
> +            return ($ip_address_in_config, $interface);
> +        } else {
> +            syslog(
> +                "warning",
> +                "ip address $ip_address_in_config of interface $interface in /etc/network/interfaces does not match with its ip address reported by ip route: $ip, switching to $ip_address_in_config for SNAT",
> +            );
> +            return ($ip_address_in_config, $interface);
> +        }
> +    }
>      return ($ip, $interface);

nit: could be shortened

if (
  $interface_in_config
  && $gateway_in_config
  && $ip_address_in_config ne $ip
) {
  syslog(..)
  return ($ip_address_in_config, $interface);
}

return ($ip, $interface);

>  }
>  
> @@ -323,7 +349,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..ac772e7 100644
> --- a/src/PVE/Network/SDN/Zones/SimplePlugin.pm
> +++ b/src/PVE/Network/SDN/Zones/SimplePlugin.pm
> @@ -112,8 +112,9 @@ sub generate_sdn_config {
>          push @iface_config, "up ip route add $cidr dev $vnetid" if $mask == 32 && $ipversion == 4;
>          if ($subnet->{snat}) {
>              #find outgoing interface
> -            my ($outip, $outiface) =
> -                PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip);
> +            my ($outip, $outiface) = PVE::Network::SDN::Zones::Plugin::get_local_route_ip(
> +                $checkrouteip, $interfaces_config,
> +            );
>              if ($outip && $outiface) {
>                  #use snat, faster than masquerade
>                  push @iface_config,





      reply	other threads:[~2026-06-22 12:54 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-27 15:39 [PATCH networking v2] fix #6255: SNAT: fix incorrect IP collection for sdn config Lukas Sichert
2026-06-22 12:53 ` Stefan Hanreich [this message]

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=87cf364d-2253-4d47-b6f0-29120f12fceb@proxmox.com \
    --to=s.hanreich@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
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal