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 2/2] sdn: vxlan: enforce single address family in peers list
Date: Fri, 16 Jan 2026 12:08:42 +0100	[thread overview]
Message-ID: <20260116110843.89615-3-h.laimer@proxmox.com> (raw)
In-Reply-To: <20260116110843.89615-1-h.laimer@proxmox.com>

We want the underlay to either be IPv4 or IPv6. A dual-stack underlay
adds ambiguity and extra complexity in source selection and validation
without a real use-case.

This includes tests for fabrics, we prefer IPv6 if the fabric offers
both.

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
 src/PVE/Network/SDN/Zones/VxlanPlugin.pm      | 42 +++++++++++++--
 .../vxlan/fabric_ipv4/expected_sdn_interfaces | 26 +++++++++
 src/test/zones/vxlan/fabric_ipv4/interfaces   |  5 ++
 src/test/zones/vxlan/fabric_ipv4/sdn_config   | 50 +++++++++++++++++
 .../vxlan/fabric_ipv6/expected_sdn_interfaces | 32 +++++++++++
 src/test/zones/vxlan/fabric_ipv6/interfaces   |  5 ++
 src/test/zones/vxlan/fabric_ipv6/sdn_config   | 54 +++++++++++++++++++
 7 files changed, 210 insertions(+), 4 deletions(-)
 create mode 100644 src/test/zones/vxlan/fabric_ipv4/expected_sdn_interfaces
 create mode 100644 src/test/zones/vxlan/fabric_ipv4/interfaces
 create mode 100644 src/test/zones/vxlan/fabric_ipv4/sdn_config
 create mode 100644 src/test/zones/vxlan/fabric_ipv6/expected_sdn_interfaces
 create mode 100644 src/test/zones/vxlan/fabric_ipv6/interfaces
 create mode 100644 src/test/zones/vxlan/fabric_ipv6/sdn_config

diff --git a/src/PVE/Network/SDN/Zones/VxlanPlugin.pm b/src/PVE/Network/SDN/Zones/VxlanPlugin.pm
index 1db610f..ac006b5 100644
--- a/src/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 use PVE::Network::SDN::Zones::Plugin;
 use PVE::Tools qw($IPV4RE);
+use Net::IP qw(ip_is_ipv6);
 use PVE::INotify;
 use PVE::Network::SDN::Controllers::EvpnPlugin;
 use PVE::Exception qw(raise raise_param_exc);
@@ -104,15 +105,35 @@ sub generate_sdn_config {
         my $current_node = eval { $config->get_node($plugin_config->{fabric}, $local_node) };
         die "could not configure VXLAN zone $plugin_config->{id}: $@" if $@;
 
+        my $all_v6 = 1;
+        my $all_v4 = 1;
+        for my $node (values %$nodes) {
+            $all_v6 = 0 if !$node->{ip6};
+            $all_v4 = 0 if !$node->{ip};
+        }
+
+        # the following checks are not strictly necesarry cause we we shouldn't
+        # even get here if there are nodes on the fabric that don't have an
+        # address on any of the prefixes defined for the fabric
+        my $addr_key;
+        if ($all_v6) {
+            $addr_key = 'ip6';
+        } elsif ($all_v4) {
+            $addr_key = 'ip';
+        } else {
+            die
+                "Fabric $fabric->{id} has no consistent address family for all nodes (need all v6 or all v4)";
+        }
+
         die
-            "Node $local_node requires an IP in the fabric $fabric->{id} to configure the VXLAN zone $plugin_config->{id}"
-            if !$current_node->{ip};
+            "Node $local_node requires a $addr_key address in fabric $fabric->{id} to configure VXLAN zone $plugin_config->{id}"
+            if !$current_node->{$addr_key};
 
         for my $node (values %$nodes) {
-            push @peers, $node->{ip} if $node->{ip};
+            push @peers, $node->{$addr_key} if $node->{$addr_key};
         }
 
-        $ifaceip = $current_node->{ip};
+        $ifaceip = $current_node->{$addr_key};
     } else {
         die "neither peers nor fabric configured for VXLAN zone $plugin_config->{id}";
     }
@@ -163,6 +184,19 @@ sub on_update_hook {
             fabric => "must have exactly one of peers / fabric defined",
         });
     }
+
+    if ($zone->{peers}) {
+        my @peers = PVE::Tools::split_list($zone->{peers});
+        my $family;
+
+        foreach my $peer (@peers) {
+            my $peer_family = ip_is_ipv6($peer) ? 6 : 4;
+            if (defined($family) && $family != $peer_family) {
+                raise_param_exc({ peers => "must contain only IPv4 or only IPv6 addresses" });
+            }
+            $family = $peer_family;
+        }
+    }
 }
 
 sub vnet_update_hook {
diff --git a/src/test/zones/vxlan/fabric_ipv4/expected_sdn_interfaces b/src/test/zones/vxlan/fabric_ipv4/expected_sdn_interfaces
new file mode 100644
index 0000000..3423104
--- /dev/null
+++ b/src/test/zones/vxlan/fabric_ipv4/expected_sdn_interfaces
@@ -0,0 +1,26 @@
+#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 172.20.3.2
+	vxlan_remoteip 172.20.3.3
+	mtu 1450
+
+auto dummy_test
+iface dummy_test inet static
+	address 172.20.3.1/32
+	link-type dummy
+	ip-forward 1
+
+auto ens18
+iface ens18 inet static
+	address 172.20.3.1/32
+	ip-forward 1
diff --git a/src/test/zones/vxlan/fabric_ipv4/interfaces b/src/test/zones/vxlan/fabric_ipv4/interfaces
new file mode 100644
index 0000000..68b6a88
--- /dev/null
+++ b/src/test/zones/vxlan/fabric_ipv4/interfaces
@@ -0,0 +1,5 @@
+auto vmbr0
+iface vmbr0 inet manual
+        bridge-ports eth0
+        bridge-stp off
+        bridge-fd 0
diff --git a/src/test/zones/vxlan/fabric_ipv4/sdn_config b/src/test/zones/vxlan/fabric_ipv4/sdn_config
new file mode 100644
index 0000000..eaaf3a9
--- /dev/null
+++ b/src/test/zones/vxlan/fabric_ipv4/sdn_config
@@ -0,0 +1,50 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { tag => 100, type => "vnet", zone => "myzone" },
+                      },
+             },
+  zones   => {
+               ids => {
+                        myzone => {
+                                    ipam => "pve",
+                                    type => "vxlan",
+                                    fabric => "test",
+                                  },
+                      },
+             },
+  fabrics => {
+               ids => {
+                        test => {
+                                  type => 'openfabric_fabric',
+                                  id => 'test',
+                                  ip_prefix => '172.20.3.0/24',
+                                },
+                        test_localhost => {
+                                       id => 'test_localhost',
+                                       type => 'openfabric_node',
+                                       interfaces => [
+                                         'name=ens18',
+                                       ],
+                                       ip => '172.20.3.1',
+                                     },
+                        test_node2 => {
+                                   id => 'test_node2',
+                                   type => 'openfabric_node',
+                                   interfaces => [
+                                     'name=ens18',
+                                   ],
+                                   ip => '172.20.3.2',
+                                 },
+                        test_node3 => {
+                                   id => 'test_node3',
+                                   type => 'openfabric_node',
+                                   interfaces => [
+                                     'name=ens18',
+                                   ],
+                                   ip => '172.20.3.3',
+                                 },
+                      },
+             },
+}
diff --git a/src/test/zones/vxlan/fabric_ipv6/expected_sdn_interfaces b/src/test/zones/vxlan/fabric_ipv6/expected_sdn_interfaces
new file mode 100644
index 0000000..7351fc9
--- /dev/null
+++ b/src/test/zones/vxlan/fabric_ipv6/expected_sdn_interfaces
@@ -0,0 +1,32 @@
+#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 fd00::2
+	vxlan_remoteip fd00::3
+	mtu 1450
+
+auto dummy_test
+iface dummy_test inet static
+	address 172.20.3.1/32
+	link-type dummy
+	ip-forward 1
+
+auto dummy_test
+iface dummy_test inet6 static
+	address fd00::1/128
+	link-type dummy
+	ip-forward 1
+
+auto ens18
+iface ens18 inet static
+	address 172.20.3.1/32
+	ip-forward 1
diff --git a/src/test/zones/vxlan/fabric_ipv6/interfaces b/src/test/zones/vxlan/fabric_ipv6/interfaces
new file mode 100644
index 0000000..68b6a88
--- /dev/null
+++ b/src/test/zones/vxlan/fabric_ipv6/interfaces
@@ -0,0 +1,5 @@
+auto vmbr0
+iface vmbr0 inet manual
+        bridge-ports eth0
+        bridge-stp off
+        bridge-fd 0
diff --git a/src/test/zones/vxlan/fabric_ipv6/sdn_config b/src/test/zones/vxlan/fabric_ipv6/sdn_config
new file mode 100644
index 0000000..f463a88
--- /dev/null
+++ b/src/test/zones/vxlan/fabric_ipv6/sdn_config
@@ -0,0 +1,54 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { tag => 100, type => "vnet", zone => "myzone" },
+                      },
+             },
+  zones   => {
+               ids => {
+                        myzone => {
+                                    ipam => "pve",
+                                    type => "vxlan",
+                                    fabric => "test",
+                                  },
+                      },
+             },
+  fabrics => {
+               ids => {
+                        test => {
+                                  type => 'openfabric_fabric',
+                                  id => 'test',
+                                  ip_prefix => '172.20.3.0/24',
+                                  ip6_prefix => 'fd00::/64',
+                                },
+                        test_localhost => {
+                                       id => 'test_localhost',
+                                       type => 'openfabric_node',
+                                       interfaces => [
+                                         'name=ens18',
+                                       ],
+                                       ip => '172.20.3.1',
+                                       ip6 => 'fd00::1',
+                                     },
+                        test_node2 => {
+                                   id => 'test_node2',
+                                   type => 'openfabric_node',
+                                   interfaces => [
+                                     'name=ens18',
+                                   ],
+                                   ip => '172.20.3.2',
+                                   ip6 => 'fd00::2',
+                                 },
+                        test_node3 => {
+                                   id => 'test_node3',
+                                   type => 'openfabric_node',
+                                   interfaces => [
+                                     'name=ens18',
+                                   ],
+                                   ip => '172.20.3.3',
+                                   ip6 => 'fd00::3',
+                                 },
+                      },
+             },
+}
-- 
2.47.3



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


  parent reply	other threads:[~2026-01-16 11:08 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 ` [pve-devel] [PATCH pve-network 1/2] sdn: vxlan: make local underlay selection work for IPv6 peers Hannes Laimer
2026-01-16 11:08 ` Hannes Laimer [this message]
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-3-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