From: Hannes Laimer <h.laimer@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH pve-network v3 5/9] sdn: evpn: add IPv6 RA / SLAAC support
Date: Tue, 23 Jun 2026 14:56:22 +0200 [thread overview]
Message-ID: <20260623125626.1195681-6-h.laimer@proxmox.com> (raw)
In-Reply-To: <20260623125626.1195681-1-h.laimer@proxmox.com>
Configure IPv6 Router Advertisements on EVPN vnets so guests can
autoconfigure addresses via SLAAC and pick up DNS / DHCP hints.
The configuration is split between the VNet and the subnet, matching
the protocol's per-RA / per-prefix layers. Defaults are picked so
the typical SLAAC case needs no per-subnet configuration.
The API rejects each option where it does not apply: the RA toggle
outside EVPN zones, per-prefix overrides on IPv4 subnets, and
explicitly enabling the autonomous flag on non-/64 prefixes.
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
Notes:
v3:
- accept valid IPv6 subnets again, non-/64 and SNAT no longer rejected
- reject autonomous only when explicitly set on a non-/64
- validate preferred not above valid, cap both at u32 max
- name the offending field in validation errors
- gate RA via a supports_ipv6_ra predicate, breaks the load cycle
- reject a router lifetime below the RA interval
- read subnets once from the running snapshot, no pending leak
- eval guard RA generation, gate it on zone node membership
- register ipv6-ra-rdnss in encode_value
src/PVE/Network/SDN.pm | 1 +
src/PVE/Network/SDN/Controllers.pm | 21 ++++-
src/PVE/Network/SDN/Controllers/EvpnPlugin.pm | 22 ++++-
src/PVE/Network/SDN/Controllers/Plugin.pm | 2 +-
src/PVE/Network/SDN/SubnetPlugin.pm | 68 +++++++++++++++
src/PVE/Network/SDN/VnetPlugin.pm | 85 +++++++++++++++++++
src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 14 ++-
src/PVE/Network/SDN/Zones/Plugin.pm | 6 ++
.../evpn/slaac/expected_controller_config | 53 ++++++++++++
.../zones/evpn/slaac/expected_sdn_interfaces | 43 ++++++++++
src/test/zones/evpn/slaac/interfaces | 7 ++
src/test/zones/evpn/slaac/sdn_config | 41 +++++++++
12 files changed, 354 insertions(+), 9 deletions(-)
create mode 100644 src/test/zones/evpn/slaac/expected_controller_config
create mode 100644 src/test/zones/evpn/slaac/expected_sdn_interfaces
create mode 100644 src/test/zones/evpn/slaac/interfaces
create mode 100644 src/test/zones/evpn/slaac/sdn_config
diff --git a/src/PVE/Network/SDN.pm b/src/PVE/Network/SDN.pm
index 33a3cf3..8f30fe7 100644
--- a/src/PVE/Network/SDN.pm
+++ b/src/PVE/Network/SDN.pm
@@ -516,6 +516,7 @@ sub encode_value {
|| $key eq 'allowed_ips'
|| $key eq 'secondary-controllers'
|| $key eq 'redistribute'
+ || $key eq 'ipv6-ra-rdnss'
) {
if (ref($value) eq 'HASH') {
return join(',', sort keys(%$value));
diff --git a/src/PVE/Network/SDN/Controllers.pm b/src/PVE/Network/SDN/Controllers.pm
index 4336b86..5a4cb93 100644
--- a/src/PVE/Network/SDN/Controllers.pm
+++ b/src/PVE/Network/SDN/Controllers.pm
@@ -8,6 +8,7 @@ use JSON;
use PVE::Tools qw(extract_param dir_glob_regex run_command);
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::Zones;
@@ -153,6 +154,18 @@ sub generate_frr_config {
}
}
+ # Bucket subnets by vnet once, from the same config snapshot the rest of the FRR
+ # config is generated from: the committed running config on apply, the compiled
+ # pending config for the dry-run diff. This keeps frr.conf consistent with the
+ # generated /etc/network/interfaces.d/sdn.
+ my $subnets_by_vnet = {};
+ my $subnet_cfg = $sdn_config->{subnets} // { ids => {} };
+ for my $subnetid (sort keys %{ $subnet_cfg->{ids} }) {
+ my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($subnet_cfg, $subnetid);
+ next if !$subnet->{vnet};
+ $subnets_by_vnet->{ $subnet->{vnet} }->{$subnetid} = $subnet;
+ }
+
foreach my $id (sort keys %{ $vnet_cfg->{ids} }) {
my $plugin_config = $vnet_cfg->{ids}->{$id};
my $zoneid = $plugin_config->{zone};
@@ -169,7 +182,13 @@ sub generate_frr_config {
my $controller_plugin =
PVE::Network::SDN::Controllers::Plugin->lookup($controller->{type});
$controller_plugin->generate_vnet_frr_config(
- $plugin_config, $controller, $zone, $zoneid, $id, $frr_config,
+ $plugin_config,
+ $controller,
+ $zone,
+ $zoneid,
+ $id,
+ $frr_config,
+ $subnets_by_vnet->{$id} // {},
);
if (!$zone->{'rt-import'}) {
diff --git a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index 4220cb6..b9dcb9f 100644
--- a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -11,6 +11,7 @@ use PVE::RESTEnvironment qw(log_warn);
use PVE::Network::SDN::Controllers::Plugin;
use PVE::Network::SDN::Zones::Plugin;
use PVE::Network::SDN::Fabrics;
+use PVE::RS::SDN::IPv6RA;
use Net::IP;
use base('PVE::Network::SDN::Controllers::Plugin');
@@ -584,19 +585,34 @@ sub generate_zone_frr_config {
}
sub generate_vnet_frr_config {
- my ($class, $plugin_config, $controller, $zone, $zoneid, $vnetid, $config) = @_;
+ my ($class, $plugin_config, $controller, $zone, $zoneid, $vnetid, $config, $subnets) = @_;
+
+ $subnets //= {};
+
+ my $local_node = PVE::INotify::nodename();
+
+ # Only emit ND/RA config on nodes that are part of the zone, mirroring the node
+ # filtering of the bridge generation in the zones plugin.
+ my $is_zone_member = !defined($zone->{nodes}) || $zone->{nodes}->{$local_node};
+
+ if ($plugin_config->{'ipv6-ra'} && $is_zone_member) {
+ my $nd_iface =
+ eval { PVE::RS::SDN::IPv6RA::build_interface($vnetid, $plugin_config, $subnets); };
+ if (my $err = $@) {
+ log_warn("vnet $vnetid: could not generate IPv6 RA configuration: $err");
+ }
+ $config->{frr}->{nd_interfaces}->{$vnetid} = $nd_iface if $nd_iface;
+ }
my $exitnodes = $zone->{'exitnodes'};
my $exitnodes_local_routing = $zone->{'exitnodes-local-routing'};
return if !$exitnodes_local_routing;
- my $local_node = PVE::INotify::nodename();
my $is_gateway = $exitnodes->{$local_node};
return if !$is_gateway;
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
$config->{frr}->{ip_routes} //= [];
foreach my $subnetid (sort keys %{$subnets}) {
my $subnet = $subnets->{$subnetid};
diff --git a/src/PVE/Network/SDN/Controllers/Plugin.pm b/src/PVE/Network/SDN/Controllers/Plugin.pm
index 6da3eec..45870ee 100644
--- a/src/PVE/Network/SDN/Controllers/Plugin.pm
+++ b/src/PVE/Network/SDN/Controllers/Plugin.pm
@@ -93,7 +93,7 @@ sub generate_zone_frr_config {
}
sub generate_vnet_frr_config {
- my ($class, $plugin_config, $controller, $zoneid, $vnetid, $config) = @_;
+ my ($class, $plugin_config, $controller, $zone, $zoneid, $vnetid, $config, $subnets) = @_;
}
diff --git a/src/PVE/Network/SDN/SubnetPlugin.pm b/src/PVE/Network/SDN/SubnetPlugin.pm
index e2a0e50..078fed7 100644
--- a/src/PVE/Network/SDN/SubnetPlugin.pm
+++ b/src/PVE/Network/SDN/SubnetPlugin.pm
@@ -177,6 +177,39 @@ sub properties {
description => 'IP address for the DNS server',
optional => 1,
},
+ # Per-prefix Router Advertisement overrides. Only meaningful for IPv6 subnets
+ # whose vnet has `ipv6-ra` enabled, silently ignored otherwise.
+ 'nd-prefix-autonomous' => {
+ type => 'boolean',
+ description =>
+ "Set the autonomous (A) flag for this prefix in RAs, enabling SLAAC for"
+ . " hosts on this subnet. SLAAC requires a /64 prefix, so this defaults to"
+ . " enabled on /64 subnets and disabled (and not enablable) otherwise.",
+ optional => 1,
+ },
+ 'nd-prefix-on-link' => {
+ type => 'boolean',
+ description =>
+ "Set the on-link (L) flag for this prefix in RAs (default: on-link).",
+ optional => 1,
+ default => 1,
+ },
+ 'nd-prefix-valid-lifetime' => {
+ type => 'integer',
+ description => "Valid lifetime for this prefix in RAs, in seconds.",
+ minimum => 0,
+ maximum => 4294967295,
+ default => 2592000,
+ optional => 1,
+ },
+ 'nd-prefix-preferred-lifetime' => {
+ type => 'integer',
+ description => "Preferred lifetime for this prefix in RAs, in seconds.",
+ minimum => 0,
+ maximum => 4294967295,
+ default => 604800,
+ optional => 1,
+ },
};
}
@@ -189,6 +222,10 @@ sub options {
dnszoneprefix => { optional => 1 },
'dhcp-range' => { optional => 1 },
'dhcp-dns-server' => { optional => 1 },
+ 'nd-prefix-autonomous' => { optional => 1 },
+ 'nd-prefix-on-link' => { optional => 1 },
+ 'nd-prefix-valid-lifetime' => { optional => 1 },
+ 'nd-prefix-preferred-lifetime' => { optional => 1 },
};
}
@@ -206,6 +243,37 @@ sub on_update_hook {
my $dns = $zone->{dns};
my $dnszone = $zone->{dnszone};
my $reversedns = $zone->{reversedns};
+ my $is_ipv6 = PVE::JSONSchema::pve_verify_cidrv6($cidr, 1);
+
+ # Per-prefix RA overrides only apply on IPv6 subnets. Reject explicit overrides on
+ # IPv4 subnets so the user notices their config has no effect.
+ if (!$is_ipv6) {
+ for my $opt (
+ qw(nd-prefix-autonomous nd-prefix-on-link nd-prefix-valid-lifetime nd-prefix-preferred-lifetime)
+ ) {
+ raise_param_exc({ $opt => "only valid on IPv6 subnets" })
+ if defined($subnet->{$opt});
+ }
+ }
+
+ # SLAAC requires a /64 prefix (RFC 4862), so the autonomous flag defaults to enabled
+ # only on /64 subnets. Explicitly enabling it elsewhere can never work, reject it.
+ if ($is_ipv6 && $mask != 64 && $subnet->{'nd-prefix-autonomous'}) {
+ raise_param_exc(
+ { 'nd-prefix-autonomous' => "autonomous (SLAAC) flag requires a /64 prefix" });
+ }
+
+ # The preferred lifetime must not exceed the valid lifetime (RFC 4861), FRR rejects
+ # such prefix lines at config load. Mixed explicit/default cases are clamped when the
+ # FRR config is built.
+ my $nd_valid = $subnet->{'nd-prefix-valid-lifetime'};
+ my $nd_preferred = $subnet->{'nd-prefix-preferred-lifetime'};
+ if (defined($nd_valid) && defined($nd_preferred) && $nd_preferred > $nd_valid) {
+ raise_param_exc({
+ 'nd-prefix-preferred-lifetime' =>
+ "preferred lifetime must not be greater than the valid lifetime ($nd_valid)",
+ });
+ }
my $mac = undef;
diff --git a/src/PVE/Network/SDN/VnetPlugin.pm b/src/PVE/Network/SDN/VnetPlugin.pm
index e041575..2479d7c 100644
--- a/src/PVE/Network/SDN/VnetPlugin.pm
+++ b/src/PVE/Network/SDN/VnetPlugin.pm
@@ -83,6 +83,57 @@ sub properties {
"If true, sets the isolated property for all interfaces on the bridge of this VNet.",
optional => 1,
},
+ # IPv6 Router Advertisement settings (EVPN zones only). The master toggle gates
+ # the rest. Per-prefix flags live on the subnet (nd-prefix-*).
+ 'ipv6-ra' => {
+ type => 'boolean',
+ description =>
+ "Emit IPv6 Router Advertisements on this VNet's bridge. Requires the VNet to belong"
+ . " to an EVPN zone with at least one IPv6 subnet.",
+ optional => 1,
+ },
+ 'ipv6-ra-managed' => {
+ type => 'boolean',
+ description => "Set the managed-address (M) flag in emitted RAs.",
+ optional => 1,
+ },
+ 'ipv6-ra-other' => {
+ type => 'boolean',
+ description => "Set the other-configuration (O) flag in emitted RAs.",
+ optional => 1,
+ },
+ 'ipv6-ra-rdnss' => {
+ type => 'array',
+ description => "RDNSS (Recursive DNS Server) addresses advertised in RAs.",
+ optional => 1,
+ items => {
+ type => 'string',
+ format => 'ipv6',
+ },
+ },
+ 'ipv6-ra-router-lifetime' => {
+ type => 'integer',
+ description =>
+ "Router lifetime advertised in RAs (seconds). 0 tells hosts not to use this"
+ . " router as a default gateway.",
+ optional => 1,
+ minimum => 0,
+ maximum => 9000,
+ },
+ 'ipv6-ra-interval' => {
+ type => 'integer',
+ description => "Maximum interval between unsolicited RAs (seconds).",
+ optional => 1,
+ minimum => 4,
+ maximum => 1800,
+ },
+ 'ipv6-ra-mtu' => {
+ type => 'integer',
+ description => "MTU advertised in RAs.",
+ optional => 1,
+ minimum => 1280,
+ maximum => 65535,
+ },
};
}
@@ -93,6 +144,13 @@ sub options {
alias => { optional => 1 },
vlanaware => { optional => 1 },
'isolate-ports' => { optional => 1 },
+ 'ipv6-ra' => { optional => 1 },
+ 'ipv6-ra-managed' => { optional => 1 },
+ 'ipv6-ra-other' => { optional => 1 },
+ 'ipv6-ra-rdnss' => { optional => 1 },
+ 'ipv6-ra-router-lifetime' => { optional => 1 },
+ 'ipv6-ra-interval' => { optional => 1 },
+ 'ipv6-ra-mtu' => { optional => 1 },
};
}
@@ -117,6 +175,33 @@ sub on_update_hook {
raise_param_exc({ vlanaware => "vlanaware vnet is not compatible with subnets" })
if $subnets;
}
+
+ # RA settings are only consumed by zones whose plugin emits RAs (currently EVPN).
+ # Reject them elsewhere so the user notices their config has no effect. Loaded at
+ # runtime to avoid a compile-time module cycle (Zones -> Vnets -> VnetPlugin).
+ if (my @ra_opts = sort grep { /^ipv6-ra/ } keys %$vnet) {
+ require PVE::Network::SDN::Zones;
+ require PVE::Network::SDN::Zones::Plugin;
+
+ my $zone_cfg = PVE::Network::SDN::Zones::config();
+ my $zone = $zone_cfg->{ids}->{ $vnet->{zone} };
+ my $zone_plugin =
+ $zone ? eval { PVE::Network::SDN::Zones::Plugin->lookup($zone->{type}) } : undef;
+
+ raise_param_exc({ $ra_opts[0] => "IPv6 RA options are only supported on EVPN zones" })
+ if !$zone_plugin || !$zone_plugin->supports_ipv6_ra();
+ }
+
+ # RFC 4861: a non-zero router lifetime must be at least the maximum RA interval
+ # (FRR default: 600s), FRR rejects the lifetime at config load otherwise.
+ my $ra_lifetime = $vnet->{'ipv6-ra-router-lifetime'};
+ my $ra_interval = $vnet->{'ipv6-ra-interval'} // 600;
+ if (defined($ra_lifetime) && $ra_lifetime != 0 && $ra_lifetime < $ra_interval) {
+ raise_param_exc({
+ 'ipv6-ra-router-lifetime' =>
+ "router lifetime must be 0 or at least the RA interval ($ra_interval seconds)",
+ });
+ }
}
1;
diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
index dfbd7e9..d8bfa80 100644
--- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -266,12 +266,14 @@ sub generate_sdn_config {
$enable_forward_v4 = 1 if $gateway;
}
- if ($subnet->{snat}) {
+ if ($subnet->{snat} && $is_evpn_gateway) {
- #find outgoing interface
+ #find outgoing interface, but don't fail the whole vnet on a node that
+ #cannot route the check address (e.g. no IPv6 connectivity)
my ($outip, $outiface) =
- PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip);
- if ($outip && $outiface && $is_evpn_gateway) {
+ eval { PVE::Network::SDN::Zones::Plugin::get_local_route_ip($checkrouteip) };
+ warn "vnet $vnetid: not generating SNAT rules for $cidr: $@" if $@;
+ if ($outip && $outiface) {
#use snat, faster than masquerade
push @iface_config,
"post-up $iptables -t nat -A POSTROUTING -s '$cidr' -o $outiface -j SNAT --to-source $outip";
@@ -431,5 +433,9 @@ sub vnet_update_hook {
}
}
+sub supports_ipv6_ra {
+ return 1;
+}
+
1;
diff --git a/src/PVE/Network/SDN/Zones/Plugin.pm b/src/PVE/Network/SDN/Zones/Plugin.pm
index 74a3384..a0adfe9 100644
--- a/src/PVE/Network/SDN/Zones/Plugin.pm
+++ b/src/PVE/Network/SDN/Zones/Plugin.pm
@@ -163,6 +163,12 @@ sub vnet_update_hook {
# do nothing by default
}
+# Whether vnets in this zone type can emit IPv6 Router Advertisements (ipv6-ra* vnet
+# options). Zone plugins that generate RA configuration override this.
+sub supports_ipv6_ra {
+ return 0;
+}
+
#helpers
sub parse_tag_number_or_range {
my ($str, $max, $tag) = @_;
diff --git a/src/test/zones/evpn/slaac/expected_controller_config b/src/test/zones/evpn/slaac/expected_controller_config
new file mode 100644
index 0000000..7d59591
--- /dev/null
+++ b/src/test/zones/evpn/slaac/expected_controller_config
@@ -0,0 +1,53 @@
+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
+exit
+!
+route-map MAP_VTEP_IN permit 1
+exit
+!
+route-map MAP_VTEP_OUT permit 1
+exit
+!
+interface myvnet
+ no ipv6 nd suppress-ra
+ ipv6 nd managed-config-flag
+ ipv6 nd other-config-flag
+ ipv6 nd rdnss 2a08:2142:302:3::53
+ ipv6 nd prefix 2a08:2142:302:3::/64 7200 3600
+ ipv6 nd prefix fd00:1::/64 2592000 604800 no-autoconfig
+exit
+!
+line vty
+!
diff --git a/src/test/zones/evpn/slaac/expected_sdn_interfaces b/src/test/zones/evpn/slaac/expected_sdn_interfaces
new file mode 100644
index 0000000..2e479a3
--- /dev/null
+++ b/src/test/zones/evpn/slaac/expected_sdn_interfaces
@@ -0,0 +1,43 @@
+#version:1
+
+auto myvnet
+iface myvnet
+ address 2a08:2142:302:3::1/64
+ address fd00:1::1/64
+ hwaddress A2:1D:CB:1A:C0:8B
+ 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 add 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
diff --git a/src/test/zones/evpn/slaac/interfaces b/src/test/zones/evpn/slaac/interfaces
new file mode 100644
index 0000000..66bb826
--- /dev/null
+++ b/src/test/zones/evpn/slaac/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/slaac/sdn_config b/src/test/zones/evpn/slaac/sdn_config
new file mode 100644
index 0000000..e6294e3
--- /dev/null
+++ b/src/test/zones/evpn/slaac/sdn_config
@@ -0,0 +1,41 @@
+{
+ version => 1,
+ vnets => {
+ ids => {
+ myvnet => {
+ tag => "100",
+ type => "vnet",
+ zone => "myzone",
+ 'ipv6-ra' => 1,
+ 'ipv6-ra-managed' => 1,
+ 'ipv6-ra-other' => 1,
+ 'ipv6-ra-rdnss' => ['2a08:2142:302:3::53'],
+ },
+ },
+ },
+
+ zones => {
+ ids => { myzone => { ipam => "pve", type => "evpn", controller => "evpnctl", 'vrf-vxlan' => 1000, 'mac' => 'A2:1D:CB:1A:C0:8B' } },
+ },
+ 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',
+ 'nd-prefix-valid-lifetime' => 7200,
+ 'nd-prefix-preferred-lifetime' => 3600,
+ },
+ 'myzone-fd00:1::-64' => {
+ 'type' => 'subnet',
+ 'vnet' => 'myvnet',
+ 'gateway' => 'fd00:1::1',
+ 'nd-prefix-autonomous' => 0,
+ },
+ }
+ }
+}
--
2.47.3
next prev parent reply other threads:[~2026-06-23 12:58 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-23 12:56 [PATCH docs/manager/network/proxmox{-perl-rs,-ve-rs} v3 0/9] add IPv6 RA / SLAAC support to EVPN zones Hannes Laimer
2026-06-23 12:56 ` [PATCH proxmox-perl-rs v3 1/9] pve-rs: sdn: add IPv6 RA builder binding Hannes Laimer
2026-06-23 12:56 ` [PATCH proxmox-ve-rs v3 2/9] frr: add IPv6 router advertisement support Hannes Laimer
2026-06-23 12:56 ` [PATCH proxmox-ve-rs v3 3/9] ve-config: add per-vnet IPv6 RA configuration Hannes Laimer
2026-06-23 12:56 ` [PATCH pve-manager v3 4/9] ui: sdn: add IPv6 RA / SLAAC support Hannes Laimer
2026-06-23 12:56 ` Hannes Laimer [this message]
2026-06-23 12:56 ` [PATCH pve-network v3 6/9] sdn: evpn: derive IP version from CIDR for gateway-less subnets Hannes Laimer
2026-06-23 12:56 ` [PATCH pve-network v3 7/9] sdn: evpn: accept untracked IPv6 NA on EVPN vnet bridges Hannes Laimer
2026-06-23 12:56 ` [PATCH pve-network v3 8/9] api: vnet: include zone-type in vnet list Hannes Laimer
2026-06-23 12:56 ` [PATCH pve-docs v3 9/9] sdn: add IPv6 RA / SLAAC section 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=20260623125626.1195681-6-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