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 <[email protected]>
---
 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
[email protected]
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to