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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.