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
