* [PATCH network v2 0/4] sdn: evpn: IPv6 underlay support
@ 2026-05-15 11:06 Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 1/4] sdn: evpn: prepare " Hannes Laimer
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Hannes Laimer @ 2026-05-15 11:06 UTC (permalink / raw)
To: pve-devel
After we bumped frr this will work now, so rebased it and sent it again. Adds
IPv6 underlay support for EVPN: IPv6-capable underlays can be selected and IPv6
peers configured. On a dual-stack underlay the EVPN session picks IPv6.
I mostly tested this on top of the bgp-fabric series[2], but it does not depend
on the changes in the that series.
v2:
- dropped two patches that have already been applied
- rebased on top of current master
[v1] https://lore.proxmox.com/pve-devel/20260122135151.292794-1-h.laimer@proxmox.com/
[2] https://lore.proxmox.com/pve-devel/20260515102500.216264-1-h.laimer@proxmox.com/
pve-network:
Hannes Laimer (4):
sdn: evpn: prepare IPv6 underlay support
sdn: evpn: keep router-id valid on IPv6 underlay
sdn: stabilize peer IP ordering when generating sdn config
sdn: evpn: add tests covering ipv6 underlays
src/PVE/Network/SDN/Controllers/EvpnPlugin.pm | 68 ++++++++++++---
src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 18 ++--
src/PVE/Network/SDN/Zones/VxlanPlugin.pm | 2 +-
.../expected_controller_config | 63 ++++++++++++++
.../expected_sdn_interfaces | 58 +++++++++++++
.../exitnode_local_routing_ipv6/interfaces | 7 ++
.../exitnode_local_routing_ipv6/sdn_config | 27 ++++++
.../expected_controller_config | 85 +++++++++++++++++++
.../expected_sdn_interfaces | 64 ++++++++++++++
.../evpn/openfabric_fabric_ipv6/interfaces | 6 ++
.../evpn/openfabric_fabric_ipv6/sdn_config | 83 ++++++++++++++++++
.../expected_controller_config | 74 ++++++++++++++++
.../expected_sdn_interfaces | 58 +++++++++++++
.../openfabric_fabric_ipv6_only/interfaces | 6 ++
.../openfabric_fabric_ipv6_only/sdn_config | 79 +++++++++++++++++
15 files changed, 679 insertions(+), 19 deletions(-)
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/expected_controller_config
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/interfaces
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/sdn_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/expected_controller_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/expected_sdn_interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/sdn_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_controller_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_sdn_interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/sdn_config
Summary over all repositories:
15 files changed, 679 insertions(+), 19 deletions(-)
--
Generated by murpp 0.11.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH pve-network v2 1/4] sdn: evpn: prepare IPv6 underlay support
2026-05-15 11:06 [PATCH network v2 0/4] sdn: evpn: IPv6 underlay support Hannes Laimer
@ 2026-05-15 11:06 ` Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 2/4] sdn: evpn: keep router-id valid on IPv6 underlay Hannes Laimer
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Hannes Laimer @ 2026-05-15 11:06 UTC (permalink / raw)
To: pve-devel
Allow IPv6-capable underlays to be selected and IPv6 peers to be
configured. On a dual-stack underlay (every node carries both an IPv4
and IPv6 address) the EVPN session picks IPv6.
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
src/PVE/Network/SDN/Controllers/EvpnPlugin.pm | 66 ++++++++++++++++---
src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 16 +++--
2 files changed, 67 insertions(+), 15 deletions(-)
diff --git a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index 8953418..0246788 100644
--- a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -137,22 +137,30 @@ sub generate_frr_config {
return;
}
- if (!$current_node->{ip}) {
+ my $addr_key = fabric_addr_key($nodes);
+ if (!$addr_key) {
log_warn(
- "Node $local_node requires an IP in the fabric $fabric->{id} to configure the EVPN controller"
+ "Fabric $fabric->{id} has no consistent address family for all nodes (need all v6 or all v4)"
+ );
+ return;
+ }
+
+ if (!$current_node->{$addr_key}) {
+ log_warn(
+ "Node $local_node requires a $addr_key address in the fabric $fabric->{id} to configure the EVPN controller"
);
return;
}
for my $node_id (sort keys %$nodes) {
my $node = $nodes->{$node_id};
- push @peers, $node->{ip} if $node->{ip};
+ push @peers, $node->{$addr_key};
}
$loopback = "dummy_$fabric->{id}";
- $ifaceip = $current_node->{ip};
- $routerid = $current_node->{ip};
+ $ifaceip = $current_node->{$addr_key};
+ $routerid = $current_node->{$addr_key};
if ($fabric->{protocol} eq 'bgp' && $bgp_mode eq 'external') {
if (!$current_node->{asn}) {
@@ -357,21 +365,29 @@ sub generate_zone_frr_config {
return;
}
- if (!$current_node->{ip}) {
+ my $addr_key = fabric_addr_key($nodes);
+ if (!$addr_key) {
+ log_warn(
+ "Fabric $fabric->{id} has no consistent address family for all nodes (need all v6 or all v4)"
+ );
+ return;
+ }
+
+ if (!$current_node->{$addr_key}) {
log_warn(
- "Node $local_node requires an IP in the fabric $fabric->{id} to configure the EVPN controller"
+ "Node $local_node requires a $addr_key address in the fabric $fabric->{id} to configure the EVPN controller"
);
return;
}
for my $node (values %$nodes) {
- push @peers, $node->{ip} if $node->{ip};
+ push @peers, $node->{$addr_key};
}
$loopback = "dummy_$fabric->{id}";
- $ifaceip = $current_node->{ip};
- $routerid = $current_node->{ip};
+ $ifaceip = $current_node->{$addr_key};
+ $routerid = $current_node->{$addr_key};
} elsif ($controller->{peers}) {
@peers = PVE::Tools::split_list($controller->{'peers'}) if $controller->{'peers'};
@@ -673,6 +689,18 @@ sub on_update_hook {
die "must have exactly one of peers / fabric defined"
if ($controller->{peers} && $controller->{fabric})
|| !($controller->{peers} || $controller->{fabric});
+ if ($controller->{peers}) {
+ my @peers = PVE::Tools::split_list($controller->{peers});
+ my $family;
+
+ foreach my $peer (@peers) {
+ my $peer_family = Net::IP::ip_is_ipv6($peer) ? 6 : 4;
+ if (defined($family) && $family != $peer_family) {
+ die "peers must contain only IPv4 or only IPv6 addresses\n";
+ }
+ $family = $peer_family;
+ }
+ }
}
}
@@ -704,4 +732,22 @@ sub find_isis_controller {
return $res;
}
+# Returns 'ip6' if every node carries an ip6, 'ip' if every node carries an ip
+# (preferring v6 when both are present), or undef if the fabric has no
+# consistent address family across nodes.
+sub fabric_addr_key {
+ my ($nodes) = @_;
+
+ 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};
+ }
+
+ return 'ip6' if $all_v6;
+ return 'ip' if $all_v4;
+ return undef;
+}
+
1;
diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 5df7e5f..a78b646 100644
--- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -188,17 +188,23 @@ sub generate_sdn_config {
my $current_node = eval { $config->get_node($controller->{fabric}, $local_node) };
die "could not configure EVPN zone $plugin_config->{id}: $@" if $@;
- die "Node $local_node requires an IP in the fabric $fabric->{id} to configure the EVPN zone"
- if !$current_node->{ip};
+ my $addr_key = PVE::Network::SDN::Controllers::EvpnPlugin::fabric_addr_key($nodes);
+ die
+ "Fabric $fabric->{id} has no consistent address family for all nodes (need all v6 or all v4)"
+ if !$addr_key;
+
+ die
+ "Node $local_node requires a $addr_key address in the fabric $fabric->{id} to configure the EVPN zone"
+ if !$current_node->{$addr_key};
for my $node (values %$nodes) {
- push @peers, $node->{ip} if $node->{ip};
+ push @peers, $node->{$addr_key};
}
$loopback = "dummy_$fabric->{id}";
- $ifaceip = $current_node->{ip};
- $routerid = $current_node->{ip};
+ $ifaceip = $current_node->{$addr_key};
+ $routerid = $current_node->{$addr_key};
} else {
die "neither fabric nor peers configured for EVPN controller $controller->{id}";
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH pve-network v2 2/4] sdn: evpn: keep router-id valid on IPv6 underlay
2026-05-15 11:06 [PATCH network v2 0/4] sdn: evpn: IPv6 underlay support Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 1/4] sdn: evpn: prepare " Hannes Laimer
@ 2026-05-15 11:06 ` Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 3/4] sdn: stabilize peer IP ordering when generating sdn config Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 4/4] sdn: evpn: add tests covering ipv6 underlays Hannes Laimer
3 siblings, 0 replies; 5+ messages in thread
From: Hannes Laimer @ 2026-05-15 11:06 UTC (permalink / raw)
To: pve-devel
BGP router-ids are 32-bit values, so use get_router_id() instead of the
address directly, cause that would only work for IPv4 underlays.
And remove dead code in the EVPN zone plugin, we don't need the
router-id there anywhere.
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
src/PVE/Network/SDN/Controllers/EvpnPlugin.pm | 4 ++--
src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 2 --
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index 0246788..6568459 100644
--- a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -160,7 +160,7 @@ sub generate_frr_config {
$loopback = "dummy_$fabric->{id}";
$ifaceip = $current_node->{$addr_key};
- $routerid = $current_node->{$addr_key};
+ $routerid = PVE::Network::SDN::Controllers::Plugin::get_router_id($ifaceip, $loopback);
if ($fabric->{protocol} eq 'bgp' && $bgp_mode eq 'external') {
if (!$current_node->{asn}) {
@@ -387,7 +387,7 @@ sub generate_zone_frr_config {
$loopback = "dummy_$fabric->{id}";
$ifaceip = $current_node->{$addr_key};
- $routerid = $current_node->{$addr_key};
+ $routerid = PVE::Network::SDN::Controllers::Plugin::get_router_id($ifaceip, $loopback);
} elsif ($controller->{peers}) {
@peers = PVE::Tools::split_list($controller->{'peers'}) if $controller->{'peers'};
diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
index a78b646..0be304a 100644
--- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -157,7 +157,6 @@ sub generate_sdn_config {
my $loopback = undef;
my $ifaceip = undef;
my $iface = undef;
- my $routerid = undef;
if ($controller->{peers}) {
@peers = PVE::Tools::split_list($controller->{'peers'});
@@ -204,7 +203,6 @@ sub generate_sdn_config {
$loopback = "dummy_$fabric->{id}";
$ifaceip = $current_node->{$addr_key};
- $routerid = $current_node->{$addr_key};
} else {
die "neither fabric nor peers configured for EVPN controller $controller->{id}";
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH pve-network v2 3/4] sdn: stabilize peer IP ordering when generating sdn config
2026-05-15 11:06 [PATCH network v2 0/4] sdn: evpn: IPv6 underlay support Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 1/4] sdn: evpn: prepare " Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 2/4] sdn: evpn: keep router-id valid on IPv6 underlay Hannes Laimer
@ 2026-05-15 11:06 ` Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 4/4] sdn: evpn: add tests covering ipv6 underlays Hannes Laimer
3 siblings, 0 replies; 5+ messages in thread
From: Hannes Laimer @ 2026-05-15 11:06 UTC (permalink / raw)
To: pve-devel
Sort peer iteration so the generated config is stable across runs.
Without this, hash iteration order leaks into the output and multi-peer
tests fail randomly.
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
src/PVE/Network/SDN/Controllers/EvpnPlugin.pm | 4 ++--
src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 4 ++--
src/PVE/Network/SDN/Zones/VxlanPlugin.pm | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index 6568459..f23cb8b 100644
--- a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -380,8 +380,8 @@ sub generate_zone_frr_config {
return;
}
- for my $node (values %$nodes) {
- push @peers, $node->{$addr_key};
+ for my $node_id (sort keys %$nodes) {
+ push @peers, $nodes->{$node_id}->{$addr_key};
}
$loopback = "dummy_$fabric->{id}";
diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 0be304a..9b06d66 100644
--- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -196,8 +196,8 @@ sub generate_sdn_config {
"Node $local_node requires a $addr_key address in the fabric $fabric->{id} to configure the EVPN zone"
if !$current_node->{$addr_key};
- for my $node (values %$nodes) {
- push @peers, $node->{$addr_key};
+ for my $node_id (sort keys %$nodes) {
+ push @peers, $nodes->{$node_id}->{$addr_key};
}
$loopback = "dummy_$fabric->{id}";
diff --git a/src/PVE/Network/SDN/Zones/VxlanPlugin.pm b/src/PVE/Network/SDN/Zones/VxlanPlugin.pm
index 1db610f..a408261 100644
--- a/src/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -127,7 +127,7 @@ sub generate_sdn_config {
my @iface_config = ();
push @iface_config, "vxlan-id $tag";
- for my $address (@peers) {
+ for my $address (sort @peers) {
next if $address eq $ifaceip;
push @iface_config, "vxlan_remoteip $address";
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH pve-network v2 4/4] sdn: evpn: add tests covering ipv6 underlays
2026-05-15 11:06 [PATCH network v2 0/4] sdn: evpn: IPv6 underlay support Hannes Laimer
` (2 preceding siblings ...)
2026-05-15 11:06 ` [PATCH pve-network v2 3/4] sdn: stabilize peer IP ordering when generating sdn config Hannes Laimer
@ 2026-05-15 11:06 ` Hannes Laimer
3 siblings, 0 replies; 5+ messages in thread
From: Hannes Laimer @ 2026-05-15 11:06 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
.../expected_controller_config | 63 ++++++++++++++
.../expected_sdn_interfaces | 58 +++++++++++++
.../exitnode_local_routing_ipv6/interfaces | 7 ++
.../exitnode_local_routing_ipv6/sdn_config | 27 ++++++
.../expected_controller_config | 85 +++++++++++++++++++
.../expected_sdn_interfaces | 64 ++++++++++++++
.../evpn/openfabric_fabric_ipv6/interfaces | 6 ++
.../evpn/openfabric_fabric_ipv6/sdn_config | 83 ++++++++++++++++++
.../expected_controller_config | 74 ++++++++++++++++
.../expected_sdn_interfaces | 58 +++++++++++++
.../openfabric_fabric_ipv6_only/interfaces | 6 ++
.../openfabric_fabric_ipv6_only/sdn_config | 79 +++++++++++++++++
12 files changed, 610 insertions(+)
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/expected_controller_config
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/interfaces
create mode 100644 src/test/zones/evpn/exitnode_local_routing_ipv6/sdn_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/expected_controller_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/expected_sdn_interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6/sdn_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_controller_config
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_sdn_interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/interfaces
create mode 100644 src/test/zones/evpn/openfabric_fabric_ipv6_only/sdn_config
diff --git a/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_controller_config b/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_controller_config
new file mode 100644
index 0000000..382660f
--- /dev/null
+++ b/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_controller_config
@@ -0,0 +1,63 @@
+frr version 10.6.1
+frr defaults datacenter
+hostname localhost
+log syslog informational
+service integrated-vtysh-config
+!
+vrf vrf_myzone
+ vni 1000
+exit-vrf
+!
+router bgp 65000
+ bgp router-id 192.168.0.1
+ no bgp hard-administrative-reset
+ no bgp default ipv4-unicast
+ coalesce-time 1000
+ no bgp graceful-restart notification
+ neighbor VTEP peer-group
+ neighbor VTEP remote-as 65000
+ neighbor VTEP bfd
+ neighbor 192.168.0.2 peer-group VTEP
+ neighbor 192.168.0.3 peer-group VTEP
+ !
+ address-family l2vpn evpn
+ neighbor VTEP activate
+ neighbor VTEP route-map MAP_VTEP_IN in
+ neighbor VTEP route-map MAP_VTEP_OUT out
+ advertise-all-vni
+ exit-address-family
+exit
+!
+router bgp 65000 vrf vrf_myzone
+ bgp router-id 192.168.0.1
+ no bgp hard-administrative-reset
+ no bgp graceful-restart notification
+ !
+ address-family l2vpn evpn
+ default-originate ipv4
+ default-originate ipv6
+ exit-address-family
+exit
+!
+ip prefix-list only_default seq 1 permit 0.0.0.0/0
+!
+ipv6 prefix-list only_default_v6 seq 1 permit ::/0
+!
+route-map MAP_VTEP_IN deny 1
+ match ip address prefix-list only_default
+exit
+!
+route-map MAP_VTEP_IN deny 2
+ match ipv6 address prefix-list only_default_v6
+exit
+!
+route-map MAP_VTEP_IN permit 3
+exit
+!
+route-map MAP_VTEP_OUT permit 1
+exit
+!
+ipv6 route 2a08:2142:302:3::/64 fe80::2 xvrf_myzone
+!
+line vty
+!
diff --git a/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces b/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces
new file mode 100644
index 0000000..b46d4e7
--- /dev/null
+++ b/src/test/zones/evpn/exitnode_local_routing_ipv6/expected_sdn_interfaces
@@ -0,0 +1,58 @@
+#version:1
+
+auto myvnet
+iface myvnet
+ address 2a08:2142:302:3::1/64
+ bridge_ports vxlan_myvnet
+ bridge_stp off
+ bridge_fd 0
+ mtu 1450
+ ip6-forward on
+ arp-accept on
+ vrf vrf_myzone
+
+auto vrf_myzone
+iface vrf_myzone
+ vrf-table auto
+ post-up ip route del vrf vrf_myzone unreachable default metric 4278198272
+
+auto vrfbr_myzone
+iface vrfbr_myzone
+ bridge-ports vrfvx_myzone
+ bridge_stp off
+ bridge_fd 0
+ mtu 1450
+ vrf vrf_myzone
+
+auto vrfvx_myzone
+iface vrfvx_myzone
+ vxlan-id 1000
+ vxlan-local-tunnelip 192.168.0.1
+ bridge-learning off
+ bridge-arp-nd-suppress on
+ mtu 1450
+
+auto vxlan_myvnet
+iface vxlan_myvnet
+ vxlan-id 100
+ vxlan-local-tunnelip 192.168.0.1
+ bridge-learning off
+ bridge-arp-nd-suppress on
+ mtu 1450
+
+auto xvrf_myzone
+iface xvrf_myzone
+ link-type veth
+ address 10.255.255.1/30
+ address fe80::1/126
+ veth-peer-name xvrfp_myzone
+ mtu 1500
+
+auto xvrfp_myzone
+iface xvrfp_myzone
+ link-type veth
+ address 10.255.255.2/30
+ address fe80::2/126
+ veth-peer-name xvrf_myzone
+ vrf vrf_myzone
+ mtu 1500
diff --git a/src/test/zones/evpn/exitnode_local_routing_ipv6/interfaces b/src/test/zones/evpn/exitnode_local_routing_ipv6/interfaces
new file mode 100644
index 0000000..66bb826
--- /dev/null
+++ b/src/test/zones/evpn/exitnode_local_routing_ipv6/interfaces
@@ -0,0 +1,7 @@
+auto vmbr0
+iface vmbr0 inet static
+ address 192.168.0.1/24
+ gateway 192.168.0.254
+ bridge-ports eth0
+ bridge-stp off
+ bridge-fd 0
diff --git a/src/test/zones/evpn/exitnode_local_routing_ipv6/sdn_config b/src/test/zones/evpn/exitnode_local_routing_ipv6/sdn_config
new file mode 100644
index 0000000..499b13a
--- /dev/null
+++ b/src/test/zones/evpn/exitnode_local_routing_ipv6/sdn_config
@@ -0,0 +1,27 @@
+{
+ version => 1,
+ vnets => {
+ ids => {
+ myvnet => { tag => "100", type => "vnet", zone => "myzone" },
+ },
+ },
+
+ zones => {
+ ids => { myzone => { ipam => "pve", type => "evpn", controller => "evpnctl", 'vrf-vxlan' => 1000, exitnodes => { 'localhost' => 1 }, 'exitnodes-local-routing' => 1 },
+ },
+ },
+ controllers => {
+ ids => { evpnctl => { type => "evpn", 'peers' => '192.168.0.1,192.168.0.2,192.168.0.3', asn => "65000" } },
+ },
+
+ subnets => {
+ ids => { 'myzone-2a08:2142:302:3::-64' => {
+ 'type' => 'subnet',
+ 'vnet' => 'myvnet',
+ 'gateway' => '2a08:2142:302:3::1',
+ },
+ }
+ }
+}
+
+
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6/expected_controller_config b/src/test/zones/evpn/openfabric_fabric_ipv6/expected_controller_config
new file mode 100644
index 0000000..fc6ebeb
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6/expected_controller_config
@@ -0,0 +1,85 @@
+frr version 10.6.1
+frr defaults datacenter
+hostname localhost
+log syslog informational
+service integrated-vtysh-config
+!
+vrf vrf_evpn
+ vni 100
+exit-vrf
+!
+router bgp 65000
+ bgp router-id 17.29.105.96
+ no bgp hard-administrative-reset
+ no bgp default ipv4-unicast
+ coalesce-time 1000
+ no bgp graceful-restart notification
+ neighbor VTEP peer-group
+ neighbor VTEP remote-as 65000
+ neighbor VTEP bfd
+ neighbor VTEP update-source dummy_test
+ neighbor fd00::2 peer-group VTEP
+ neighbor fd00::3 peer-group VTEP
+ !
+ address-family l2vpn evpn
+ neighbor VTEP activate
+ neighbor VTEP route-map MAP_VTEP_IN in
+ neighbor VTEP route-map MAP_VTEP_OUT out
+ advertise-all-vni
+ exit-address-family
+exit
+!
+router bgp 65000 vrf vrf_evpn
+ bgp router-id 17.29.105.96
+ no bgp hard-administrative-reset
+ no bgp graceful-restart notification
+exit
+!
+router openfabric test
+ net 49.0001.1720.2000.3001.00
+exit
+!
+interface dummy_test
+ ip router openfabric test
+ ipv6 router openfabric test
+ openfabric passive
+exit
+!
+interface ens20
+ ip router openfabric test
+ ipv6 router openfabric test
+ openfabric hello-interval 1
+exit
+!
+interface ens21
+ ip router openfabric test
+ ipv6 router openfabric test
+ openfabric hello-interval 1
+exit
+!
+ipv6 access-list pve_openfabric_test_ip6s permit fd00::/64
+!
+access-list pve_openfabric_test_ips permit 172.20.3.0/24
+!
+route-map MAP_VTEP_IN permit 1
+exit
+!
+route-map MAP_VTEP_OUT permit 1
+exit
+!
+route-map pve_openfabric permit 100
+ match ip address pve_openfabric_test_ips
+ set src 172.20.3.1
+exit
+!
+route-map pve_openfabric6 permit 110
+ match ipv6 address pve_openfabric_test_ip6s
+ set src fd00::1
+exit
+!
+ip protocol openfabric route-map pve_openfabric
+!
+ipv6 protocol openfabric route-map pve_openfabric6
+!
+line vty
+!
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6/expected_sdn_interfaces b/src/test/zones/evpn/openfabric_fabric_ipv6/expected_sdn_interfaces
new file mode 100644
index 0000000..d017713
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6/expected_sdn_interfaces
@@ -0,0 +1,64 @@
+#version:1
+
+auto vnet0
+iface vnet0
+ address 10.123.123.1/24
+ hwaddress BC:24:11:3B:39:34
+ bridge_ports vxlan_vnet0
+ bridge_stp off
+ bridge_fd 0
+ mtu 1450
+ ip-forward on
+ arp-accept on
+ vrf vrf_evpn
+
+auto vrf_evpn
+iface vrf_evpn
+ vrf-table auto
+ post-up ip route add vrf vrf_evpn unreachable default metric 4278198272
+
+auto vrfbr_evpn
+iface vrfbr_evpn
+ bridge-ports vrfvx_evpn
+ bridge_stp off
+ bridge_fd 0
+ mtu 1450
+ vrf vrf_evpn
+
+auto vrfvx_evpn
+iface vrfvx_evpn
+ vxlan-id 100
+ vxlan-local-tunnelip fd00::1
+ bridge-learning off
+ bridge-arp-nd-suppress on
+ mtu 1450
+
+auto vxlan_vnet0
+iface vxlan_vnet0
+ vxlan-id 123456
+ vxlan-local-tunnelip fd00::1
+ bridge-learning off
+ bridge-arp-nd-suppress on
+ 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 ens20
+iface ens20 inet static
+ address 172.20.3.1/32
+ ip-forward 1
+
+auto ens21
+iface ens21 inet static
+ address 172.20.3.1/32
+ ip-forward 1
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6/interfaces b/src/test/zones/evpn/openfabric_fabric_ipv6/interfaces
new file mode 100644
index 0000000..1b4384b
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6/interfaces
@@ -0,0 +1,6 @@
+auto vmbr0
+iface vmbr0 inet static
+ address 172.20.3.1/32
+ bridge-ports eth0
+ bridge-stp off
+ bridge-fd 0
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6/sdn_config b/src/test/zones/evpn/openfabric_fabric_ipv6/sdn_config
new file mode 100644
index 0000000..6fe01cc
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6/sdn_config
@@ -0,0 +1,83 @@
+{
+ 'zones' => {
+ 'ids' => {
+ 'evpn' => {
+ 'type' => 'evpn',
+ 'ipam' => 'pve',
+ 'mac' => 'BC:24:11:3B:39:34',
+ 'controller' => 'ctrl',
+ 'vrf-vxlan' => 100
+ }
+ }
+ },
+ 'vnets' => {
+ 'ids' => {
+ 'vnet0' => {
+ 'zone' => 'evpn',
+ 'type' => 'vnet',
+ 'tag' => 123456
+ }
+ }
+ },
+ 'version' => 1,
+ 'subnets' => {
+ 'ids' => {
+ 'evpn-10.123.123.0-24' => {
+ 'vnet' => 'vnet0',
+ 'type' => 'subnet',
+ 'gateway' => '10.123.123.1'
+ }
+ }
+ },
+ 'controllers' => {
+ 'ids' => {
+ 'ctrl' => {
+ 'fabric' => 'test',
+ 'asn' => 65000,
+ 'type' => 'evpn'
+ }
+ }
+ },
+ 'fabrics' => {
+ 'ids' => {
+ 'test' => {
+ 'type' => 'openfabric_fabric',
+ 'id' => 'test',
+ 'hello_interval' => 1,
+ 'ip_prefix' => '172.20.3.0/24',
+ 'ip6_prefix' => 'fd00::/64',
+ },
+ 'test_localhost' => {
+ 'interfaces' => [
+ 'name=ens20',
+ 'name=ens21'
+ ],
+ 'id' => 'test_localhost',
+ 'type' => 'openfabric_node',
+ 'ip' => '172.20.3.1',
+ 'ip6' => 'fd00::1',
+ },
+ 'test_pathfinder' => {
+ 'id' => 'test_pathfinder',
+ 'interfaces' => [
+ 'name=ens20',
+ 'name=ens21'
+ ],
+ 'ip' => '172.20.3.2',
+ 'ip6' => 'fd00::2',
+ 'type' => 'openfabric_node',
+ },
+ 'test_raider' => {
+ 'ip' => '172.20.3.3',
+ 'ip6' => 'fd00::3',
+ 'type' => 'openfabric_node',
+ 'interfaces' => [
+ 'name=ens21',
+ 'name=ens20'
+ ],
+ 'id' => 'test_raider',
+ }
+ }
+ }
+ };
+
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_controller_config b/src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_controller_config
new file mode 100644
index 0000000..f3f633a
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_controller_config
@@ -0,0 +1,74 @@
+frr version 10.6.1
+frr defaults datacenter
+hostname localhost
+log syslog informational
+service integrated-vtysh-config
+!
+vrf vrf_evpn
+ vni 100
+exit-vrf
+!
+router bgp 65000
+ bgp router-id 17.29.105.96
+ no bgp hard-administrative-reset
+ no bgp default ipv4-unicast
+ coalesce-time 1000
+ no bgp graceful-restart notification
+ neighbor VTEP peer-group
+ neighbor VTEP remote-as 65000
+ neighbor VTEP bfd
+ neighbor VTEP update-source dummy_test
+ neighbor fd00::2 peer-group VTEP
+ neighbor fd00::3 peer-group VTEP
+ !
+ address-family l2vpn evpn
+ neighbor VTEP activate
+ neighbor VTEP route-map MAP_VTEP_IN in
+ neighbor VTEP route-map MAP_VTEP_OUT out
+ advertise-all-vni
+ exit-address-family
+exit
+!
+router bgp 65000 vrf vrf_evpn
+ bgp router-id 17.29.105.96
+ no bgp hard-administrative-reset
+ no bgp graceful-restart notification
+exit
+!
+router openfabric test
+ net 49.0001.0000.0000.0001.00
+exit
+!
+interface dummy_test
+ ipv6 router openfabric test
+ openfabric passive
+exit
+!
+interface ens20
+ ipv6 router openfabric test
+ openfabric hello-interval 1
+exit
+!
+interface ens21
+ ipv6 router openfabric test
+ openfabric hello-interval 1
+exit
+!
+ipv6 access-list pve_openfabric_test_ip6s permit fd00::/64
+!
+route-map MAP_VTEP_IN permit 1
+exit
+!
+route-map MAP_VTEP_OUT permit 1
+exit
+!
+route-map pve_openfabric6 permit 100
+ match ipv6 address pve_openfabric_test_ip6s
+ set src fd00::1
+exit
+!
+!
+ipv6 protocol openfabric route-map pve_openfabric6
+!
+line vty
+!
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_sdn_interfaces b/src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_sdn_interfaces
new file mode 100644
index 0000000..51507d7
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6_only/expected_sdn_interfaces
@@ -0,0 +1,58 @@
+#version:1
+
+auto vnet0
+iface vnet0
+ address 10.123.123.1/24
+ hwaddress BC:24:11:3B:39:34
+ bridge_ports vxlan_vnet0
+ bridge_stp off
+ bridge_fd 0
+ mtu 1450
+ ip-forward on
+ arp-accept on
+ vrf vrf_evpn
+
+auto vrf_evpn
+iface vrf_evpn
+ vrf-table auto
+ post-up ip route add vrf vrf_evpn unreachable default metric 4278198272
+
+auto vrfbr_evpn
+iface vrfbr_evpn
+ bridge-ports vrfvx_evpn
+ bridge_stp off
+ bridge_fd 0
+ mtu 1450
+ vrf vrf_evpn
+
+auto vrfvx_evpn
+iface vrfvx_evpn
+ vxlan-id 100
+ vxlan-local-tunnelip fd00::1
+ bridge-learning off
+ bridge-arp-nd-suppress on
+ mtu 1450
+
+auto vxlan_vnet0
+iface vxlan_vnet0
+ vxlan-id 123456
+ vxlan-local-tunnelip fd00::1
+ bridge-learning off
+ bridge-arp-nd-suppress on
+ mtu 1450
+
+auto dummy_test
+iface dummy_test inet6 static
+ address fd00::1/128
+ link-type dummy
+ ip-forward 1
+
+auto ens20
+iface ens20 inet6 static
+ address fd00::1/128
+ ip-forward 1
+
+auto ens21
+iface ens21 inet6 static
+ address fd00::1/128
+ ip-forward 1
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6_only/interfaces b/src/test/zones/evpn/openfabric_fabric_ipv6_only/interfaces
new file mode 100644
index 0000000..1b4384b
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6_only/interfaces
@@ -0,0 +1,6 @@
+auto vmbr0
+iface vmbr0 inet static
+ address 172.20.3.1/32
+ bridge-ports eth0
+ bridge-stp off
+ bridge-fd 0
diff --git a/src/test/zones/evpn/openfabric_fabric_ipv6_only/sdn_config b/src/test/zones/evpn/openfabric_fabric_ipv6_only/sdn_config
new file mode 100644
index 0000000..5dc2163
--- /dev/null
+++ b/src/test/zones/evpn/openfabric_fabric_ipv6_only/sdn_config
@@ -0,0 +1,79 @@
+{
+ 'zones' => {
+ 'ids' => {
+ 'evpn' => {
+ 'type' => 'evpn',
+ 'ipam' => 'pve',
+ 'mac' => 'BC:24:11:3B:39:34',
+ 'controller' => 'ctrl',
+ 'vrf-vxlan' => 100
+ }
+ }
+ },
+ 'vnets' => {
+ 'ids' => {
+ 'vnet0' => {
+ 'zone' => 'evpn',
+ 'type' => 'vnet',
+ 'tag' => 123456
+ }
+ }
+ },
+ 'version' => 1,
+ 'subnets' => {
+ 'ids' => {
+ 'evpn-10.123.123.0-24' => {
+ 'vnet' => 'vnet0',
+ 'type' => 'subnet',
+ 'gateway' => '10.123.123.1'
+ }
+ }
+ },
+ 'controllers' => {
+ 'ids' => {
+ 'ctrl' => {
+ 'fabric' => 'test',
+ 'asn' => 65000,
+ 'type' => 'evpn'
+ }
+ }
+ },
+ 'fabrics' => {
+ 'ids' => {
+ 'test' => {
+ 'type' => 'openfabric_fabric',
+ 'id' => 'test',
+ 'hello_interval' => 1,
+ 'ip6_prefix' => 'fd00::/64',
+ },
+ 'test_localhost' => {
+ 'interfaces' => [
+ 'name=ens20',
+ 'name=ens21'
+ ],
+ 'id' => 'test_localhost',
+ 'type' => 'openfabric_node',
+ 'ip6' => 'fd00::1',
+ },
+ 'test_pathfinder' => {
+ 'id' => 'test_pathfinder',
+ 'interfaces' => [
+ 'name=ens20',
+ 'name=ens21'
+ ],
+ 'ip6' => 'fd00::2',
+ 'type' => 'openfabric_node',
+ },
+ 'test_raider' => {
+ 'ip6' => 'fd00::3',
+ 'type' => 'openfabric_node',
+ 'interfaces' => [
+ 'name=ens21',
+ 'name=ens20'
+ ],
+ 'id' => 'test_raider',
+ }
+ }
+ }
+ };
+
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-15 11:07 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-15 11:06 [PATCH network v2 0/4] sdn: evpn: IPv6 underlay support Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 1/4] sdn: evpn: prepare " Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 2/4] sdn: evpn: keep router-id valid on IPv6 underlay Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 3/4] sdn: stabilize peer IP ordering when generating sdn config Hannes Laimer
2026-05-15 11:06 ` [PATCH pve-network v2 4/4] sdn: evpn: add tests covering ipv6 underlays Hannes Laimer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox