all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH proxmox-ve-rs v5 2/9] frr: add IPv6 router advertisement support
Date: Thu, 29 Oct 2026 16:41:41 +0100	[thread overview]
Message-ID: <20261029154148.2882594-3-h.laimer@proxmox.com> (raw)
In-Reply-To: <20261029154148.2882594-1-h.laimer@proxmox.com>

The generated FRR config can now carry IPv6 Router Advertisement
settings per interface, along with the prefixes to announce. Each of
these interfaces gets a block of ipv6 nd commands that turns its
advertisements on. Settings left unset are not rendered, so FRR keeps
its defaults for them.

Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---

Notes:
    v5:
     - the ND block is rendered ahead of the node-local config, so local overrides win
    
    v3:
     - keep prefix lifetimes on no-autoconfig prefixes (were dropped)
     - emit ra-interval before ra-lifetime
     - single prefix line instead of duplicated autoconfig branches

 .../templates/frr.conf.jinja                  |  1 +
 .../templates/nd_interfaces.jinja             | 28 ++++++++++
 proxmox-frr/src/ser/mod.rs                    |  6 ++
 proxmox-frr/src/ser/nd.rs                     | 56 +++++++++++++++++++
 proxmox-frr/src/ser/serializer.rs             |  6 +-
 5 files changed, 96 insertions(+), 1 deletion(-)
 create mode 100644 proxmox-frr-templates/templates/nd_interfaces.jinja
 create mode 100644 proxmox-frr/src/ser/nd.rs

diff --git a/proxmox-frr-templates/templates/frr.conf.jinja b/proxmox-frr-templates/templates/frr.conf.jinja
index 1f98489e09fb..8d96648e5e02 100644
--- a/proxmox-frr-templates/templates/frr.conf.jinja
+++ b/proxmox-frr-templates/templates/frr.conf.jinja
@@ -1,6 +1,7 @@
 {% include "bgpd.jinja" %}
 {% include "isisd.jinja" %}
 {% include "prefix_lists.jinja" %}
+{% include "nd_interfaces.jinja" %}
 {% for line in custom_frr_config %}
 {{ line }}
 {% endfor %}
diff --git a/proxmox-frr-templates/templates/nd_interfaces.jinja b/proxmox-frr-templates/templates/nd_interfaces.jinja
new file mode 100644
index 000000000000..dd047a93a6af
--- /dev/null
+++ b/proxmox-frr-templates/templates/nd_interfaces.jinja
@@ -0,0 +1,28 @@
+{% for name, iface in nd_interfaces|items %}
+!
+interface {{ name }}
+ no ipv6 nd suppress-ra
+{% if iface.managed_config_flag %}
+ ipv6 nd managed-config-flag
+{% endif %}
+{% if iface.other_config_flag %}
+ ipv6 nd other-config-flag
+{% endif %}
+{% if iface.interval is not none %}
+ ipv6 nd ra-interval {{ iface.interval }}
+{% endif %}
+{% if iface.router_lifetime is not none %}
+ ipv6 nd ra-lifetime {{ iface.router_lifetime }}
+{% endif %}
+{% if iface.mtu is not none %}
+ ipv6 nd mtu {{ iface.mtu }}
+{% endif %}
+{% for rdnss in iface.rdnss %}
+ ipv6 nd rdnss {{ rdnss }}
+{% endfor %}
+{% for prefix in iface.prefixes %}
+ ipv6 nd prefix {{ prefix.cidr }} {{ prefix.valid }} {{ prefix.preferred }}{% if not prefix.autonomous %} no-autoconfig{% endif %}{% if not prefix.on_link %} off-link{% endif %}
+
+{% endfor %}
+exit
+{% endfor %}
diff --git a/proxmox-frr/src/ser/mod.rs b/proxmox-frr/src/ser/mod.rs
index b651121b4a82..a65ee46270b5 100644
--- a/proxmox-frr/src/ser/mod.rs
+++ b/proxmox-frr/src/ser/mod.rs
@@ -1,5 +1,6 @@
 pub mod bgp;
 pub mod isis;
+pub mod nd;
 pub mod openfabric;
 pub mod ospf;
 pub mod route_map;
@@ -234,6 +235,11 @@ pub struct FrrConfig {
     #[serde(default)]
     pub prefix_lists: BTreeMap<PrefixListName, Vec<PrefixListRule>>,
 
+    /// `interface <name> / ipv6 nd ...` blocks emitted for subnets with Router
+    /// Advertisements enabled. Presence of an entry implies `no ipv6 nd suppress-ra`.
+    #[serde(default)]
+    pub nd_interfaces: BTreeMap<InterfaceName, nd::NdInterface>,
+
     #[serde(default)]
     pub custom_frr_config: Vec<String>,
 }
diff --git a/proxmox-frr/src/ser/nd.rs b/proxmox-frr/src/ser/nd.rs
new file mode 100644
index 000000000000..4eef037511da
--- /dev/null
+++ b/proxmox-frr/src/ser/nd.rs
@@ -0,0 +1,56 @@
+use std::net::Ipv6Addr;
+
+use proxmox_network_types::ip_address::Ipv6Cidr;
+use serde::{Deserialize, Serialize};
+
+fn default_true() -> bool {
+    true
+}
+
+/// A prefix advertised in Router Advertisements on an interface.
+///
+/// Both lifetimes are emitted in seconds whether or not the prefix is autonomous. The
+/// preferred lifetime must not exceed the valid one, FRR rejects the prefix otherwise.
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
+pub struct NdPrefix {
+    pub cidr: Ipv6Cidr,
+    #[serde(
+        default = "default_true",
+        deserialize_with = "proxmox_serde::perl::deserialize_bool"
+    )]
+    pub autonomous: bool,
+    #[serde(
+        default = "default_true",
+        deserialize_with = "proxmox_serde::perl::deserialize_bool"
+    )]
+    pub on_link: bool,
+    #[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")]
+    pub valid: u32,
+    #[serde(deserialize_with = "proxmox_serde::perl::deserialize_u32")]
+    pub preferred: u32,
+}
+
+/// Router Advertisement configuration of an interface, one `ipv6 nd` command per field.
+///
+/// An entry for an interface turns its RAs on, the generated config emits
+/// `no ipv6 nd suppress-ra` for it.
+#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct NdInterface {
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
+    pub managed_config_flag: bool,
+    #[serde(default, deserialize_with = "proxmox_serde::perl::deserialize_bool")]
+    pub other_config_flag: bool,
+    #[serde(default)]
+    pub rdnss: Vec<Ipv6Addr>,
+    /// `None` leaves the router lifetime to FRR, three times the RA interval. A value above
+    /// 0 has to be at least the interval, which is why the template renders the interval
+    /// first, FRR checks the lifetime against the interval it has at that point.
+    #[serde(default)]
+    pub router_lifetime: Option<u32>,
+    #[serde(default)]
+    pub interval: Option<u32>,
+    #[serde(default)]
+    pub mtu: Option<u32>,
+    #[serde(default)]
+    pub prefixes: Vec<NdPrefix>,
+}
diff --git a/proxmox-frr/src/ser/serializer.rs b/proxmox-frr/src/ser/serializer.rs
index 2ac85d8cf6c5..5b5d5a5081ab 100644
--- a/proxmox-frr/src/ser/serializer.rs
+++ b/proxmox-frr/src/ser/serializer.rs
@@ -5,7 +5,7 @@ use crate::ser::FrrConfig;
 use proxmox_sortable_macro::sortable;
 
 #[sortable]
-pub static TEMPLATES: [(&str, &str); 12] = sorted!([
+pub static TEMPLATES: [(&str, &str); 13] = sorted!([
     (
         "fabricd.jinja",
         include_str!("/usr/share/proxmox-frr/templates/fabricd.jinja"),
@@ -50,6 +50,10 @@ pub static TEMPLATES: [(&str, &str); 12] = sorted!([
         "protocol_routemaps.jinja",
         include_str!("/usr/share/proxmox-frr/templates/protocol_routemaps.jinja"),
     ),
+    (
+        "nd_interfaces.jinja",
+        include_str!("/usr/share/proxmox-frr/templates/nd_interfaces.jinja"),
+    ),
     (
         "frr.conf.jinja",
         include_str!("/usr/share/proxmox-frr/templates/frr.conf.jinja"),
-- 
2.47.3





  parent reply	other threads:[~2026-10-29 15:42 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-29 15:41 [PATCH docs/manager/network/proxmox{-perl-rs,-ve-rs} v5 0/9] add IPv6 RA / SLAAC support to EVPN zones Hannes Laimer
2026-10-29 15:41 ` [PATCH proxmox-perl-rs v5 1/9] pve-rs: sdn: add IPv6 RA builder binding Hannes Laimer
2026-10-29 15:41 ` Hannes Laimer [this message]
2026-10-29 15:41 ` [PATCH proxmox-ve-rs v5 3/9] ve-config: sdn: add IPv6 router advertisement settings Hannes Laimer
2026-10-29 15:41 ` [PATCH pve-manager v5 4/9] ui: sdn: add IPv6 RA / SLAAC support Hannes Laimer
2026-11-02 13:53   ` Lukas Sichert
2026-10-29 15:41 ` [PATCH pve-network v5 5/9] sdn: evpn: derive IP version from CIDR for gateway-less subnets Hannes Laimer
2026-10-29 15:41 ` [PATCH pve-network v5 6/9] sdn: evpn: accept untracked IPv6 neighbor advertisements Hannes Laimer
2026-10-29 15:41 ` [PATCH pve-network v5 7/9] sdn: evpn: add IPv6 RA / SLAAC support Hannes Laimer
2026-10-29 15:41 ` [PATCH pve-network v5 8/9] api: vnets: include the zone type in the vnet list Hannes Laimer
2026-10-29 15:41 ` [PATCH pve-docs v5 9/9] sdn: add IPv6 RA / SLAAC section Hannes Laimer
2026-10-30 15:07 ` [PATCH docs/manager/network/proxmox{-perl-rs,-ve-rs} v5 0/9] add IPv6 RA / SLAAC support to EVPN zones Lukas Sichert
2026-10-30 16:30   ` Lukas Sichert
2026-11-02 14:25 ` Lukas Sichert

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=20261029154148.2882594-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 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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal