From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 091E71FF13C for ; Thu, 30 Apr 2026 16:30:04 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id BE0A6B549; Thu, 30 Apr 2026 16:30:02 +0200 (CEST) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH proxmox-perl-rs v2 03/11] pve-rs: sdn: add IPv6 RA builder binding Date: Thu, 30 Apr 2026 16:29:45 +0200 Message-ID: <20260430142953.315412-4-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260430142953.315412-1-h.laimer@proxmox.com> References: <20260430142953.315412-1-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1777559296771 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.920 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_MAILER 2 Automated Mailer Tag Left in Email SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: O2CTRJG73P7XCORXVL2VC3GMXW6IXZXP X-Message-ID-Hash: O2CTRJG73P7XCORXVL2VC3GMXW6IXZXP X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Expose the typed FRR pipeline for IPv6 Router Advertisements to perl, so the EVPN controller plugin can fold a vnet's RA settings and its subnets' per-prefix overrides into the FRR config it assembles. Signed-off-by: Hannes Laimer --- pve-rs/Makefile | 1 + pve-rs/src/bindings/sdn/ipv6_ra.rs | 50 ++++++++++++++++++++++++++++++ pve-rs/src/bindings/sdn/mod.rs | 1 + 3 files changed, 52 insertions(+) create mode 100644 pve-rs/src/bindings/sdn/ipv6_ra.rs diff --git a/pve-rs/Makefile b/pve-rs/Makefile index 25642cd..f18852d 100644 --- a/pve-rs/Makefile +++ b/pve-rs/Makefile @@ -32,6 +32,7 @@ PERLMOD_PACKAGES := \ PVE::RS::ResourceScheduling::Static \ PVE::RS::ResourceScheduling::Dynamic \ PVE::RS::SDN::Fabrics \ + PVE::RS::SDN::IPv6RA \ PVE::RS::SDN::PrefixLists \ PVE::RS::SDN::RouteMaps \ PVE::RS::SDN \ diff --git a/pve-rs/src/bindings/sdn/ipv6_ra.rs b/pve-rs/src/bindings/sdn/ipv6_ra.rs new file mode 100644 index 0000000..7338bf9 --- /dev/null +++ b/pve-rs/src/bindings/sdn/ipv6_ra.rs @@ -0,0 +1,50 @@ +#[perlmod::package(name = "PVE::RS::SDN::IPv6RA", lib = "pve_rs")] +pub mod pve_rs_sdn_ipv6_ra { + //! The `PVE::RS::SDN::IPv6RA` package. + //! + //! Builds the per-vnet IPv6 Router Advertisement / Neighbor Discovery configuration + //! the FRR template renders. Per-RA settings (M / O flags, RDNSS list, optional + //! timing knobs) live on the vnet running config. Per-prefix settings + //! (autonomous, on-link, lifetimes) live on the subnet running config. The perl side + //! passes both as raw running-config hashes, this module converts them into the typed + //! pipeline and returns the rendered `NdInterface`. + + use std::collections::BTreeMap; + + use anyhow::{Context, Error}; + + use proxmox_frr::ser::nd::NdInterface; + use proxmox_ve_config::sdn::{ + config::{SubnetConfig, SubnetRunningConfig, VnetConfig, VnetRunningConfig}, + nd::frr::build_nd_interface, + SubnetName, VnetName, + }; + + /// Build the [`NdInterface`] for one vnet. + /// + /// Returns `None` when the vnet has no `ipv6-ra` master toggle set, or when there + /// are no IPv6 subnets to advertise. + /// + /// `subnets` is the running-config slice for the subnets belonging to this vnet, in + /// the same shape the perl side already has them. The map is iterated in key order + /// so the emitted prefix list is stable. + #[export] + pub fn build_interface( + vnet_name: VnetName, + vnet: VnetRunningConfig, + subnets: BTreeMap, + ) -> Result, Error> { + let mut vnet_config = VnetConfig::new(vnet_name, None); + vnet_config.set_ipv6_ra(vnet.ipv6_ra_config()); + + let mut subnet_configs: Vec = Vec::with_capacity(subnets.len()); + for (id, running) in subnets { + let name: SubnetName = id + .parse() + .with_context(|| format!("invalid subnet id: {id}"))?; + subnet_configs.push(SubnetConfig::try_from_running_config(name, running)?); + } + + Ok(build_nd_interface(&vnet_config, subnet_configs.iter())) + } +} diff --git a/pve-rs/src/bindings/sdn/mod.rs b/pve-rs/src/bindings/sdn/mod.rs index c6361c3..d77099e 100644 --- a/pve-rs/src/bindings/sdn/mod.rs +++ b/pve-rs/src/bindings/sdn/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod fabrics; +pub(crate) mod ipv6_ra; pub(crate) mod prefix_lists; pub(crate) mod route_maps; -- 2.47.3