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 network v3] fix #6255: snat: update changed bridge IPs in SDN config
Date: Thu, 25 Jun 2026 18:10:19 +0200	[thread overview]
Message-ID: <3ef74118-51a9-4ea3-bb6f-b8c93be35aa6@proxmox.com> (raw)
In-Reply-To: <20260625122420.51674-1-l.sichert@proxmox.com>

gave this another quick spin with an IPv{4,6} simple vnet, lgtm:

Tested-by: Stefan Hanreich <s.hanreich@proxmox.com>
Reviewed-by: Stefan Hanreich <s.hanreich@proxmox.com>


On 6/25/26 2:25 PM, Lukas Sichert wrote:
> When changing the IP address of an SNAT bridge in a Simple or EVPN zone,
> the generated SDN configuration retains the old address. The address is
> currently obtained through 'ip route get', which still reports the
> previous state before 'ifreload' runs.
> 
> Parse the incoming '/etc/network/interfaces' and look up the interface
> used by 'ip route'. If it still has a gateway and a changed IP address,
> update the SNAT address in the generated SDN configuration and log the
> change to the journal.
> 
> Signed-off-by: Lukas Sichert <l.sichert@proxmox.com>
> Link: https://bugzilla.proxmox.com/show_bug.cgi?id=6255
> ---
> 
> Notes:
>     changes from v2 to v3: (thanks @Stefan):
>     - simplified the address lookup by selecting the address and gateway key
>       based on the IP version
>     - add address and gateway check before canonicalzing as canonical_ip
>       creates default ip from undef input
>     - simplified the fallback logic for changed SNAT bridge addresses
>     
>     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
> 
>  src/PVE/Network/SDN/Zones/EvpnPlugin.pm   |  5 ++--
>  src/PVE/Network/SDN/Zones/Plugin.pm       | 32 +++++++++++++++++++++--
>  src/PVE/Network/SDN/Zones/SimplePlugin.pm |  5 ++--
>  3 files changed, 36 insertions(+), 6 deletions(-)
> 
> diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
> index dfbd7e9..37bc9f5 100644
> --- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
> +++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
> @@ -269,8 +269,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 74a3384..5493ec1 100644
> --- a/src/PVE/Network/SDN/Zones/Plugin.pm
> +++ b/src/PVE/Network/SDN/Zones/Plugin.pm
> @@ -9,6 +9,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);
> @@ -306,7 +307,7 @@ sub get_iface_addresses {
>  }
>  
>  sub get_local_route_ip {
> -    my ($targetip) = @_;
> +    my ($targetip, $interfaces_config) = @_;
>  
>      my $ip = undef;
>      my $interface = undef;
> @@ -323,6 +324,33 @@ sub get_local_route_ip {
>  
>          },
>      );
> +    my $ipversion = Net::IP::ip_is_ipv6($targetip) ? 6 : 4;
> +    my $interface_in_config = $interfaces_config->{ifaces}->{$interface};
> +
> +    my $address_key = ($ipversion == 6) ? 'address6' : 'address';
> +    my $gateway_key = ($ipversion == 6) ? 'gateway6' : 'gateway';
> +
> +    # check if ip address and gateway exist in config before normalizing, because
> +    # canonical_ip will return 0.0.0.0, if called with undef
> +    my $ip_address_in_config;
> +    if ($ip_address_in_config = $interface_in_config->{$address_key}) {
> +        $ip_address_in_config = PVE::Network::canonical_ip($ip_address_in_config);
> +    }
> +
> +    my $gateway_in_config;
> +    if ($gateway_in_config = $interface_in_config->{$gateway_key}) {
> +        $gateway_in_config = PVE::Network::canonical_ip($gateway_in_config);
> +    }
> +
> +    # if the device currently used for routing still has a valid description in /network/interfaces/, use it
> +    if ($interface_in_config && $gateway_in_config && $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 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);
>  }
>  
> @@ -368,7 +396,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-25 16:10 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-25 12:24 [PATCH network v3] fix #6255: snat: update changed bridge IPs in SDN config Lukas Sichert
2026-06-25 16:10 ` 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=3ef74118-51a9-4ea3-bb6f-b8c93be35aa6@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