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
next prev 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