From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 47F7A1FF187 for ; Mon, 25 Aug 2025 10:28:21 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 93882C225; Mon, 25 Aug 2025 10:28:24 +0200 (CEST) Date: Mon, 25 Aug 2025 10:28:20 +0200 From: Wolfgang Bumiller To: Gabriel Goller Message-ID: References: <20250822090102.102949-1-g.goller@proxmox.com> <20250822090102.102949-7-g.goller@proxmox.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20250822090102.102949-7-g.goller@proxmox.com> X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1756110496822 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.074 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 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] [PATCH proxmox-perl-rs v2 4/4] fabrics: add function to get all neighbors of the fabric X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Cc: pve-devel@lists.proxmox.com Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" On Fri, Aug 22, 2025 at 11:00:38AM +0200, Gabriel Goller wrote: > In order to also display the neighbors of a specific node in the > FabricContentView resource window get the Neighbors of the all the > fabrics. Query frr (vtysh) to get the neighbors of both openefabric and > ospf, parse it and then compile a array containing all neighbors and > the fabric it relates to. > > Signed-off-by: Gabriel Goller > --- > pve-rs/src/bindings/sdn/fabrics.rs | 152 +++++++++++++++++++++++++++++ > 1 file changed, 152 insertions(+) > > diff --git a/pve-rs/src/bindings/sdn/fabrics.rs b/pve-rs/src/bindings/sdn/fabrics.rs > index f1addd4364d2..c033a4072685 100644 > --- a/pve-rs/src/bindings/sdn/fabrics.rs > +++ b/pve-rs/src/bindings/sdn/fabrics.rs > @@ -594,6 +594,18 @@ pub mod pve_rs_sdn_fabrics { > section_config::{fabric::FabricId, node::Node as ConfigNode}, > }; > > + /// The status of a neighbor. > + /// > + /// Contains the neighbor, the fabric and protocol it belongs to and the some status > + /// information. > + #[derive(Debug, Serialize)] > + pub struct NeighborStatus { > + neighbor: String, > + status: String, > + fabric_id: FabricId, > + protocol: Protocol, > + } > + > /// The status of a route. > /// > /// Contains the route, the fabric and protocol it belongs to and some extra nexthop > @@ -651,6 +663,19 @@ pub mod pve_rs_sdn_fabrics { > pub ospf: de::Routes, > } > > + /// Parsed neighbors for all protocols > + /// > + /// These are the neighbors parsed from the json output of: > + /// `vtysh -c 'show openfabric neighbor json'` and > + /// `vtysh -c 'show ip ospf neighbor json'`. > + #[derive(Debug, Serialize)] > + pub struct NeighborsParsed { > + /// The openfabric neighbors in FRR > + pub openfabric: de::openfabric::Neighbors, > + /// The ospf neighbors in FRR > + pub ospf: de::ospf::Neighbors, > + } > + > impl TryInto> for RoutesParsed { > type Error = anyhow::Error; > > @@ -739,6 +764,90 @@ pub mod pve_rs_sdn_fabrics { > } > } > > + impl TryInto> for NeighborsParsed { > + type Error = anyhow::Error; > + > + fn try_into(self) -> Result, Self::Error> { > + let hostname = proxmox_sys::nodename(); > + > + // get all nodes > + let raw_config = std::fs::read_to_string("/etc/pve/sdn/fabrics.cfg")?; ^ Same as the other patches. > + let config = FabricConfig::parse_section_config(&raw_config)?; > + > + let mut stats: Vec = Vec::new(); > + > + for (nodeid, node) in config.values().flat_map(|entry| { > + entry > + .nodes() > + .map(|(id, node)| (id.to_string(), node.clone())) ^ ... I'm sensing pattern here. Would it make sense to add a `FabricConfig::all_nodes(&self) -> impl Iterator<...>` ? > + }) { > + if nodeid != hostname { > + continue; > + } > + let fabric_id = node.id().fabric_id().clone(); ^ unnecessary clone > + > + match node { > + ConfigNode::Openfabric(_) => { > + for area in &self.openfabric.areas { > + if area.area == fabric_id.as_str() { > + for circuit in &area.circuits { > + if let (Some(adj), Some(state)) = > + (&circuit.adj, &circuit.state) > + { > + stats.push(NeighborStatus { > + neighbor: adj.clone(), > + status: state.clone(), > + protocol: Protocol::Openfabric, > + fabric_id: fabric_id.clone(), > + }); > + } > + } > + } > + } > + } > + ConfigNode::Ospf(node) => { > + let interface_names: HashSet<&str> = node > + .properties() > + .interfaces() > + .map(|i| i.name().as_str()) > + .collect(); > + > + for (neighbor_key, neighbor_list) in &self.ospf.neighbors { > + let mut has_matching_neighbor = false; > + for neighbor in neighbor_list { > + match neighbor.interface_name.split_once(":") { > + Some((interface_name, _)) => { > + if interface_names.contains(interface_name) { > + has_matching_neighbor = true; > + break; > + } > + } > + _ => { > + continue; > + } > + } > + } > + if has_matching_neighbor { > + let status = neighbor_list > + .first() > + .map(|n| n.neighbor_state.clone()) > + .unwrap_or_default(); > + stats.push(NeighborStatus { > + neighbor: neighbor_key.clone(), > + status, > + protocol: Protocol::Ospf, > + fabric_id: fabric_id.clone(), > + }); > + } > + } > + } > + } > + } > + > + Ok(stats) > + } > + } > + > impl TryInto> for RoutesParsed { > type Error = anyhow::Error; > > @@ -873,6 +982,49 @@ pub mod pve_rs_sdn_fabrics { > route_status.try_into() > } > > + /// Get all the neighbors of all the fabrics on this node. > + /// > + /// Go through all fabrics that exist on this node. Then get the neighbors of them all and > + /// concat them into a single array. > + #[export] > + fn neighbors() -> Result, Error> { > + let openfabric_neighbors_string = String::from_utf8( > + Command::new("sh") > + .args(["-c", "vtysh -c 'show openfabric neighbor json'"]) > + .output()? > + .stdout, > + )?; > + > + let ospf_neighbors_string = String::from_utf8( > + Command::new("sh") > + .args(["-c", "vtysh -c 'show ip ospf neighbor json'"]) > + .output()? > + .stdout, > + )?; > + > + let openfabric_neighbors: proxmox_frr::de::openfabric::Neighbors = > + if openfabric_neighbors_string.is_empty() { > + proxmox_frr::de::openfabric::Neighbors::default() > + } else { > + serde_json::from_str(&openfabric_neighbors_string) > + .with_context(|| "error parsing openfabric neighbors")? > + }; > + > + let ospf_neighbors: proxmox_frr::de::ospf::Neighbors = if ospf_neighbors_string.is_empty() { > + proxmox_frr::de::ospf::Neighbors::default() > + } else { > + serde_json::from_str(&ospf_neighbors_string) > + .with_context(|| "error parsing ospf neighbors")? > + }; > + > + let neighbor_status = status::NeighborsParsed { > + openfabric: openfabric_neighbors, > + ospf: ospf_neighbors, > + }; > + > + neighbor_status.try_into() > + } > + > /// Return the status of all fabrics on this node. > /// > /// Go through all fabrics in the config, then filter out the ones that exist on this node. > -- > 2.47.2 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel