On Wed, Jul 02, 2025 at 04:50:14PM +0200, Gabriel Goller wrote: > From: Stefan Hanreich <s.hanre...@proxmox.com> > > This module exposes the functionality provided proxmox-ve-config for > the SDN fabrics to perl. We add initial support for reading and > writing the section config stored in /etc/pve/sdn/fabrics.cfg as well > as the running configuration, stored in /etc/pve/sdn/.running-config. > It also provides a helper method for calculating the digest of the > configuration. > > Co-authored-by: Gabriel Goller <g.gol...@proxmox.com> > Signed-off-by: Stefan Hanreich <s.hanre...@proxmox.com> > --- > pve-rs/Cargo.toml | 3 +- > pve-rs/Makefile | 1 + > pve-rs/debian/control | 1 + > pve-rs/src/bindings/mod.rs | 3 + > pve-rs/src/bindings/sdn/fabrics.rs | 95 ++++++++++++++++++++++++++++++ > pve-rs/src/bindings/sdn/mod.rs | 1 + > 6 files changed, 103 insertions(+), 1 deletion(-) > create mode 100644 pve-rs/src/bindings/sdn/fabrics.rs > create mode 100644 pve-rs/src/bindings/sdn/mod.rs > > diff --git a/pve-rs/Cargo.toml b/pve-rs/Cargo.toml > index c7f11a395ce7..19c7431206e9 100644 > --- a/pve-rs/Cargo.toml > +++ b/pve-rs/Cargo.toml > @@ -39,9 +39,10 @@ proxmox-log = "1" > proxmox-notify = { version = "1", features = ["pve-context"] } > proxmox-openid = "1" > proxmox-resource-scheduling = "1" > +proxmox-section-config = "3" > proxmox-shared-cache = "1" > proxmox-subscription = "1" > proxmox-sys = "1" > proxmox-tfa = { version = "6", features = ["api"] } > proxmox-time = "2" > -proxmox-ve-config = { version = "0.3" } > +proxmox-ve-config = { version = "0.3", features = [ "frr" ] } > diff --git a/pve-rs/Makefile b/pve-rs/Makefile > index afe792adc9f0..21561b2a292a 100644 > --- a/pve-rs/Makefile > +++ b/pve-rs/Makefile > @@ -29,6 +29,7 @@ PERLMOD_PACKAGES := \ > PVE::RS::Firewall::SDN \ > PVE::RS::OpenId \ > PVE::RS::ResourceScheduling::Static \ > + PVE::RS::SDN::Fabrics \ > PVE::RS::TFA > > PERLMOD_PACKAGE_FILES := $(addsuffix .pm,$(subst ::,/,$(PERLMOD_PACKAGES))) > diff --git a/pve-rs/debian/control b/pve-rs/debian/control > index 9e424ec255b0..7ebab20f055d 100644 > --- a/pve-rs/debian/control > +++ b/pve-rs/debian/control > @@ -33,6 +33,7 @@ Build-Depends: cargo:native <!nocheck>, > librust-proxmox-tfa-6+default-dev, > librust-proxmox-time-2+default-dev, > librust-proxmox-ve-config-dev (>= 0.2.1-~~), > + librust-proxmox-ve-config+frr-dev (>= 0.2.2-~~), > librust-serde-1+default-dev, > librust-serde-bytes-0.11+default-dev, > librust-serde-json-1+default-dev, > diff --git a/pve-rs/src/bindings/mod.rs b/pve-rs/src/bindings/mod.rs > index e4fb4db09482..7730de370473 100644 > --- a/pve-rs/src/bindings/mod.rs > +++ b/pve-rs/src/bindings/mod.rs > @@ -11,6 +11,9 @@ pub use openid::pve_rs_open_id; > > pub mod firewall; > > +mod sdn; > +pub use sdn::fabrics::pve_rs_sdn_fabrics; > + > #[allow(unused_imports)] > pub use crate::common::bindings::*; > > diff --git a/pve-rs/src/bindings/sdn/fabrics.rs > b/pve-rs/src/bindings/sdn/fabrics.rs > new file mode 100644 > index 000000000000..fac5602c0241 > --- /dev/null > +++ b/pve-rs/src/bindings/sdn/fabrics.rs > @@ -0,0 +1,95 @@ > +#[perlmod::package(name = "PVE::RS::SDN::Fabrics", lib = "pve_rs")] > +pub mod pve_rs_sdn_fabrics { > + //! The `PVE::RS::SDN::Fabrics` package. > + //! > + //! This provides the configuration for the SDN fabrics, as well as > helper methods for reading > + //! / writing the configuration, as well as for generating ifupdown2 and > FRR configuration. > + > + use std::collections::BTreeMap; > + use std::ops::Deref; > + use std::sync::Mutex; > + > + use anyhow::Error; > + use openssl::hash::{hash, MessageDigest}; > + use serde::{Deserialize, Serialize}; > + > + use perlmod::Value; > + use proxmox_section_config::typed::SectionConfigData; > + use proxmox_ve_config::common::valid::Validatable; > + > + use proxmox_ve_config::sdn::fabric::{section_config::Section, > FabricConfig}; > + > + /// A SDN Fabric config instance. > + #[derive(Serialize, Deserialize)] > + pub struct PerlFabricConfig { > + /// The fabric config instance > + pub fabric_config: Mutex<FabricConfig>, > + } > + > + perlmod::declare_magic!(Box<PerlFabricConfig> : &PerlFabricConfig as > "PVE::RS::SDN::Fabrics::Config"); > + > + /// Parse the raw configuration from `/etc/pve/sdn/fabrics.cfg`.
↑ Class method Takes the class ↓ > + #[export] > + fn config(#[raw] class: Value, raw_config: &[u8]) -> > Result<perlmod::Value, Error> { > + let raw_config = std::str::from_utf8(raw_config)?; > + let config = FabricConfig::parse_section_config(raw_config)?; > + > + Ok( > + perlmod::instantiate_magic!(&class, MAGIC => > Box::new(PerlFabricConfig { > + fabric_config: Mutex::new(config.into_inner()), > + })), > + ) > + } > + > + /// Parse the configuration from `/etc/pve/sdn/.running_config`. ↑ Class method Takes the class ↓ > + #[export] > + fn running_config( > + #[raw] class: Value, > + fabrics: BTreeMap<String, Section>, > + ) -> Result<perlmod::Value, Error> { > + let fabrics = SectionConfigData::from_iter(fabrics); > + let config = FabricConfig::from_section_config(fabrics)?; > + > + Ok( > + perlmod::instantiate_magic!(&class, MAGIC => > Box::new(PerlFabricConfig { > + fabric_config: Mutex::new(config.into_inner()), > + })), > + ) > + } > + > + /// Class method: Convert the configuration into the section config > sections. ↑ Method Takes self/this ↓ > + /// > + /// Used for writing the running configuration. > + #[export] > + fn to_sections( > + #[try_from_ref] this: &PerlFabricConfig, > + ) -> Result<BTreeMap<String, Section>, Error> { > + let config = this > + .fabric_config > + .lock() > + .unwrap() > + .clone() > + .into_valid()? > + .into_section_config(); > + > + Ok(BTreeMap::from_iter(config.clone())) > + } > + > + /// Class method: Convert the configuration into the section config > string. ↑ Method Takes self/this ↓ > + /// > + /// Used for writing `/etc/pve/sdn/fabrics.cfg` > + #[export] > + fn to_raw(#[try_from_ref] this: &PerlFabricConfig) -> Result<String, > Error> { > + this.fabric_config.lock().unwrap().write_section_config() > + } > + > + /// Class method: Generate a digest for the whole configuration ↑ Method Takes self/this ↓ > + #[export] > + fn digest(#[try_from_ref] this: &PerlFabricConfig) -> Result<String, > Error> { > + let config = this.fabric_config.lock().unwrap(); > + let data = serde_json::to_vec(config.deref())?; > + let hash = hash(MessageDigest::sha256(), &data)?; > + > + Ok(hex::encode(hash)) > + } > +} > diff --git a/pve-rs/src/bindings/sdn/mod.rs b/pve-rs/src/bindings/sdn/mod.rs > new file mode 100644 > index 000000000000..0ec7009cc788 > --- /dev/null > +++ b/pve-rs/src/bindings/sdn/mod.rs > @@ -0,0 +1 @@ > +pub(crate) mod fabrics; > -- > 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel