public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH pve-network 1/2] sdn: vxlan: make local underlay selection work for IPv6 peers
Date: Fri, 16 Jan 2026 12:08:41 +0100	[thread overview]
Message-ID: <20260116110843.89615-2-h.laimer@proxmox.com> (raw)
In-Reply-To: <20260116110843.89615-1-h.laimer@proxmox.com>

IPv6 peers couldn't be matched to local underlay addresses, so nodes
would not skip their own peer IP. We need this for VXLAN IPv6 support.

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
 src/PVE/Network/SDN/Zones/Plugin.pm           | 72 +++++++++++++++++--
 .../zones/vxlan/ipv6/expected_sdn_interfaces  | 15 ++++
 src/test/zones/vxlan/ipv6/interfaces          |  7 ++
 src/test/zones/vxlan/ipv6/sdn_config          | 17 +++++
 4 files changed, 104 insertions(+), 7 deletions(-)
 create mode 100644 src/test/zones/vxlan/ipv6/expected_sdn_interfaces
 create mode 100644 src/test/zones/vxlan/ipv6/interfaces
 create mode 100644 src/test/zones/vxlan/ipv6/sdn_config

diff --git a/src/PVE/Network/SDN/Zones/Plugin.pm b/src/PVE/Network/SDN/Zones/Plugin.pm
index 826ebdf..bfa96f7 100644
--- a/src/PVE/Network/SDN/Zones/Plugin.pm
+++ b/src/PVE/Network/SDN/Zones/Plugin.pm
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 
 use PVE::Tools qw(run_command);
+use Net::IP qw(ip_is_ipv6);
 use PVE::IPRoute2;
 use PVE::JSONSchema;
 use PVE::Cluster;
@@ -278,14 +279,54 @@ sub del_bridge_fdb {
 
 #helper
 
+sub _normalize_ip {
+    my ($ip) = @_;
+
+    return undef if !defined($ip);
+    $ip =~ s!/.*$!!;
+    return $ip;
+}
+
+sub _get_iface_addresses {
+    my ($iface_cfg) = @_;
+
+    return () if !$iface_cfg;
+
+    my @addrs;
+    for my $key (qw(address address6)) {
+        my $val = $iface_cfg->{$key};
+        next if !defined($val);
+        if (ref($val) eq 'ARRAY') {
+            push @addrs, @$val;
+        } else {
+            push @addrs, $val;
+        }
+    }
+
+    return @addrs;
+}
+
+sub _address_matches_family {
+    my ($address, $family) = @_;
+
+    my $ip = _normalize_ip($address);
+    return 0 if !defined($ip);
+
+    return ip_is_ipv6($ip) ? $family == 6 : $family == 4;
+}
+
 sub get_local_route_ip {
     my ($targetip) = @_;
 
     my $ip = undef;
     my $interface = undef;
 
+    my @cmd = ('/sbin/ip');
+    push @cmd, '-6' if ip_is_ipv6($targetip);
+    push @cmd, 'route', 'get', $targetip;
+
     run_command(
-        ['/sbin/ip', 'route', 'get', $targetip],
+        \@cmd,
         outfunc => sub {
             if ($_[0] =~ m/src ($PVE::Tools::IPRE)/) {
                 $ip = $1;
@@ -307,16 +348,33 @@ sub find_local_ip_interface_peers {
 
     #if iface is defined, return ip if exist (if not,try to find it on other ifaces)
     if ($iface) {
-        my $ip = $ifaces->{$iface}->{address};
-        return ($ip, $iface) if $ip;
+        my @iface_addrs = _get_iface_addresses($ifaces->{$iface});
+        if (!@{$peers} && @iface_addrs) {
+            my $ip = _normalize_ip($iface_addrs[0]);
+            return ($ip, $iface) if $ip;
+        }
+        foreach my $address (@{$peers}) {
+            my $family = ip_is_ipv6($address) ? 6 : 4;
+            foreach my $iface_addr (@iface_addrs) {
+                next if !_address_matches_family($iface_addr, $family);
+                my $ip = _normalize_ip($iface_addr);
+                return ($ip, $iface) if $ip;
+            }
+        }
     }
 
     #is a local ip member of peers list ?
     foreach my $address (@{$peers}) {
-        while (my $interface = each %$ifaces) {
-            my $ip = $ifaces->{$interface}->{address};
-            if ($ip && $ip eq $address) {
-                return ($ip, $interface);
+        my $family = ip_is_ipv6($address) ? 6 : 4;
+        my $peer_ip = _normalize_ip($address);
+        next if !defined($peer_ip);
+        foreach my $interface (keys %$ifaces) {
+            foreach my $iface_addr (_get_iface_addresses($ifaces->{$interface})) {
+                next if !_address_matches_family($iface_addr, $family);
+                my $ip = _normalize_ip($iface_addr);
+                if ($ip && $ip eq $peer_ip) {
+                    return ($ip, $interface);
+                }
             }
         }
     }
diff --git a/src/test/zones/vxlan/ipv6/expected_sdn_interfaces b/src/test/zones/vxlan/ipv6/expected_sdn_interfaces
new file mode 100644
index 0000000..032ab99
--- /dev/null
+++ b/src/test/zones/vxlan/ipv6/expected_sdn_interfaces
@@ -0,0 +1,15 @@
+#version:1
+
+auto myvnet
+iface myvnet
+	bridge_ports vxlan_myvnet
+	bridge_stp off
+	bridge_fd 0
+	mtu 1450
+
+auto vxlan_myvnet
+iface vxlan_myvnet
+	vxlan-id 100
+	vxlan_remoteip 2a08:2200:100:1::11
+	vxlan_remoteip 2a08:2200:100:1::12
+	mtu 1450
diff --git a/src/test/zones/vxlan/ipv6/interfaces b/src/test/zones/vxlan/ipv6/interfaces
new file mode 100644
index 0000000..602179b
--- /dev/null
+++ b/src/test/zones/vxlan/ipv6/interfaces
@@ -0,0 +1,7 @@
+auto vmbr0
+iface vmbr0 inet static
+	address 2a08:2200:100:1::10/64
+	gateway 2a08:2200:100:1::1
+        bridge-ports eth0
+        bridge-stp off
+        bridge-fd 0
diff --git a/src/test/zones/vxlan/ipv6/sdn_config b/src/test/zones/vxlan/ipv6/sdn_config
new file mode 100644
index 0000000..484be23
--- /dev/null
+++ b/src/test/zones/vxlan/ipv6/sdn_config
@@ -0,0 +1,17 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { tag => 100, type => "vnet", zone => "myzone" },
+                      },
+             },
+  zones   => {
+               ids => {
+                        myzone => {
+                                    ipam => "pve",
+                                    type => "vxlan",
+                                    peers => "2a08:2200:100:1::10,2a08:2200:100:1::11,2a08:2200:100:1::12",
+                                  },
+                      },
+             },
+}
-- 
2.47.3



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


  reply	other threads:[~2026-01-16 11:09 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-16 11:08 [pve-devel] [PATCH docs/network 0/3] SDN VXLAN IPv6 underlay support Hannes Laimer
2026-01-16 11:08 ` Hannes Laimer [this message]
2026-01-16 11:08 ` [pve-devel] [PATCH pve-network 2/2] sdn: vxlan: enforce single address family in peers list Hannes Laimer
2026-01-16 11:08 ` [pve-devel] [PATCH pve-docs 1/1] sdn: vxlan: add short section about underlay address family Hannes Laimer

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=20260116110843.89615-2-h.laimer@proxmox.com \
    --to=h.laimer@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