CRUD methods for perlmod that call the helper functions defined earlier. Also add a method that returns the FRR daemons to be enabled and a method that generates FRR configuration after validating it.
Signed-off-by: Gabriel Goller <g.gol...@proxmox.com> Co-authored-by: Stefan Hanreich <s.hanre...@proxmox.com> --- pve-rs/src/sdn/ospf.rs | 173 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-) diff --git a/pve-rs/src/sdn/ospf.rs b/pve-rs/src/sdn/ospf.rs index 4ab1e7e505f0..2c83d638661a 100644 --- a/pve-rs/src/sdn/ospf.rs +++ b/pve-rs/src/sdn/ospf.rs @@ -1,14 +1,16 @@ #[perlmod::package(name = "PVE::RS::SDN::Fabrics::Ospf", lib = "pve_rs")] mod export { - use std::{net::Ipv4Addr, str}; + use std::{collections::HashMap, net::Ipv4Addr, str, sync::Mutex}; - use anyhow::Context; + use anyhow::{Context, Error}; + use perlmod::Value; + use proxmox_frr::serializer::to_raw_config; use proxmox_network_types::{debian::Hostname, ip_address::Ipv4Cidr}; use proxmox_schema::property_string::PropertyString; use proxmox_section_config::typed::{ApiSectionDataEntry, SectionConfigData}; use proxmox_ve_config::sdn::fabric::{ - FabricId, NodeId, SectionType, Validate, + FabricConfig, FabricId, FrrConfigBuilder, NodeId, SectionType, Valid, Validate, ospf::{Area, FabricSection, InterfaceProperties, NodeSection, OspfSectionConfig}, }; use serde::{Deserialize, Serialize}; @@ -214,4 +216,169 @@ mod export { OspfSectionConfig::write_section_config("sdn/fabrics/ospf.cfg", &guard) } } + + #[export(raw_return)] + fn running_config( + #[raw] class: Value, + raw_config: HashMap<String, OspfSectionConfig>, + ) -> Result<perlmod::Value, anyhow::Error> { + // we cannot just construct it from the HashMap via From, since then the order is empty + let section_config = raw_config.into_iter().collect(); + + let return_value = PerlSectionConfig { + section_config: Mutex::new(section_config), + }; + + Ok(perlmod::instantiate_magic!(&class, MAGIC => Box::new( + return_value + ))) + } + + #[export(raw_return)] + fn config(#[raw] class: Value, raw_config: &[u8]) -> Result<perlmod::Value, anyhow::Error> { + let raw_config = std::str::from_utf8(raw_config)?; + + let config = OspfSectionConfig::parse_section_config("ospf.cfg", raw_config)?; + let return_value = PerlSectionConfig { + section_config: Mutex::new(config), + }; + + Ok(perlmod::instantiate_magic!(&class, MAGIC => Box::new( + return_value + ))) + } + + /// Writes the config to a string and returns the configuration and the protocol. + #[export] + fn write( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + ) -> Result<(String, String), Error> { + let full_new_config = this.write()?; + + // We return the protocol here as well, so that in perl we can write to + // the correct config file + Ok((full_new_config, "ospf".to_string())) + } + + #[export] + fn add_fabric( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + params: AddFabric, + ) -> Result<(), Error> { + this.add_fabric(params)?; + + Ok(()) + } + + #[export] + fn add_node( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + params: AddNode, + ) -> Result<(), Error> { + this.add_node(params) + } + + #[export] + fn edit_fabric( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + params: EditFabric, + ) -> Result<(), Error> { + this.edit_fabric(params) + } + + #[export] + fn edit_node( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + params: EditNode, + ) -> Result<(), Error> { + this.edit_node(params) + } + + #[export] + fn delete_fabric( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + params: DeleteFabric, + ) -> Result<(), Error> { + this.delete_fabric(params)?; + + Ok(()) + } + + #[export] + fn delete_node( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + params: DeleteNode, + ) -> Result<(), Error> { + this.delete_node(params)?; + + Ok(()) + } + + #[export] + fn get_inner( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + ) -> HashMap<String, OspfSectionConfig> { + let guard = this.section_config.lock().unwrap(); + guard.clone().into_iter().collect() + } + + #[export] + fn get_fabric( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + fabric: FabricId, + ) -> Result<OspfSectionConfig, Error> { + let guard = this.section_config.lock().unwrap(); + guard + .get(&fabric.to_string()) + .cloned() + .ok_or(anyhow::anyhow!("fabric not found")) + } + + #[export] + fn get_node( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + fabric: FabricId, + node: Hostname, + ) -> Result<OspfSectionConfig, Error> { + let guard = this.section_config.lock().unwrap(); + let nodeid = NodeId::new(fabric, node).to_string(); + guard + .get(&nodeid) + .cloned() + .ok_or(anyhow::anyhow!("node not found")) + } + + #[export] + pub fn enabled_daemons( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + hostname: Hostname, + ) -> Vec<String> { + let config = this.section_config.lock().unwrap(); + + for (_, section) in config.iter() { + if let OspfSectionConfig::Node(node) = section { + if node.node_id == hostname { + return vec!["ospfd".to_string()]; + } + } + } + + Vec::new() + } + + #[export] + pub fn get_frr_raw_config( + #[try_from_ref] this: &PerlSectionConfig<OspfSectionConfig>, + node: Hostname, + ) -> Result<Vec<String>, Error> { + let config = this.section_config.lock().unwrap(); + let ospf_config: Valid<OspfSectionConfig> = OspfSectionConfig::validate(config.clone())?; + + let config = FabricConfig::with_ospf(ospf_config); + let frr_config = FrrConfigBuilder::default() + .add_fabrics(config) + .build(node)?; + + to_raw_config(&frr_config) + } } -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel