From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: Gabriel Goller <g.goller@proxmox.com>
Cc: pve-devel@lists.proxmox.com
Subject: Re: [pve-devel] [PATCH proxmox-perl-rs v2 4/4] fabrics: add function to get all neighbors of the fabric
Date: Mon, 25 Aug 2025 10:28:20 +0200 [thread overview]
Message-ID: <qxosl7ui5ddtkmdyphgngn7kba6asel2fywe7eowuylv5rqeex@phffxok5y2vh> (raw)
In-Reply-To: <20250822090102.102949-7-g.goller@proxmox.com>
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 <g.goller@proxmox.com>
> ---
> 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<Vec<RouteStatus>> for RoutesParsed {
> type Error = anyhow::Error;
>
> @@ -739,6 +764,90 @@ pub mod pve_rs_sdn_fabrics {
> }
> }
>
> + impl TryInto<Vec<NeighborStatus>> for NeighborsParsed {
> + type Error = anyhow::Error;
> +
> + fn try_into(self) -> Result<Vec<NeighborStatus>, 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<NeighborStatus> = 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<HashMap<FabricId, Status>> 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<Vec<status::NeighborStatus>, 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
next prev parent reply other threads:[~2025-08-25 8:28 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-22 9:00 [pve-devel] [PATCH manager/network/proxmox{-ve-rs, -perl-rs} v2 00/12] Add fabric status view Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH proxmox-ve-rs v2 1/2] frr: make room for deserialization structs Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH proxmox-ve-rs v2 2/2] frr: add deserialization types for openfabric and ospf Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH proxmox-perl-rs v2 1/4] pve: fabrics: update proxmox-frr import path Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH proxmox-perl-rs v2 2/4] fabrics: add function to get status of fabric Gabriel Goller
2025-08-25 8:11 ` Wolfgang Bumiller
2025-08-25 8:25 ` Wolfgang Bumiller
2025-08-25 11:39 ` Gabriel Goller
2025-08-25 14:37 ` Wolfgang Bumiller
2025-08-25 15:33 ` Gabriel Goller
2025-08-26 7:55 ` Wolfgang Bumiller
2025-08-26 8:29 ` Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH proxmox-perl-rs v2 3/4] fabrics: add function to get all routes distributed by the fabrics Gabriel Goller
2025-08-25 8:22 ` Wolfgang Bumiller
2025-08-25 11:40 ` Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH proxmox-perl-rs v2 4/4] fabrics: add function to get all neighbors of the fabric Gabriel Goller
2025-08-25 8:28 ` Wolfgang Bumiller [this message]
2025-08-25 11:41 ` Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH pve-network v2 1/3] fabrics: add fabrics status to SDN::status function Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH pve-network v2 2/3] fabrics: add api endpoint to return fabrics routes Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH pve-network v2 3/3] fabrics: add api endpoint to return fabric neighbors Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH pve-manager v2 1/3] pvestatd: add fabrics status to pvestatd Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH pve-manager v2 2/3] fabrics: add resource view for fabrics Gabriel Goller
2025-08-22 9:00 ` [pve-devel] [PATCH pve-manager v2 3/3] permissions: differentiate between zone and fabric paths Gabriel Goller
2025-08-26 9:52 ` [pve-devel] [PATCH manager/network/proxmox{-ve-rs, -perl-rs} v2 00/12] Add fabric status view Gabriel Goller
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=qxosl7ui5ddtkmdyphgngn7kba6asel2fywe7eowuylv5rqeex@phffxok5y2vh \
--to=w.bumiller@proxmox.com \
--cc=g.goller@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox