all lists on 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal