all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Gabriel Goller <g.goller@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH proxmox-ve-rs v2 1/2] frr: make room for deserialization structs
Date: Fri, 22 Aug 2025 11:00:33 +0200	[thread overview]
Message-ID: <20250822090102.102949-2-g.goller@proxmox.com> (raw)
In-Reply-To: <20250822090102.102949-1-g.goller@proxmox.com>

Move all the serialization structs to a new subfolder `ser`. This makes
place for the deserialization structs which will land in a new folder
`de`. The deserialization structs will be used to parse the output of
`vtysh` commands, so that we can show statistics of various sdn objects.
Also update all the callsites to use the new subfolder.

Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
---
 proxmox-frr/src/lib.rs                  | 242 +-----------------------
 proxmox-frr/src/ser/mod.rs              | 241 +++++++++++++++++++++++
 proxmox-frr/src/{ => ser}/openfabric.rs |   4 +-
 proxmox-frr/src/{ => ser}/ospf.rs       |   2 +-
 proxmox-frr/src/{ => ser}/route_map.rs  |   0
 proxmox-frr/src/{ => ser}/serializer.rs |   2 +-
 proxmox-ve-config/src/sdn/fabric/frr.rs | 170 +++++++++--------
 proxmox-ve-config/src/sdn/frr.rs        |   2 +-
 proxmox-ve-config/tests/fabric/main.rs  |   2 +-
 9 files changed, 340 insertions(+), 325 deletions(-)
 create mode 100644 proxmox-frr/src/ser/mod.rs
 rename proxmox-frr/src/{ => ser}/openfabric.rs (97%)
 rename proxmox-frr/src/{ => ser}/ospf.rs (99%)
 rename proxmox-frr/src/{ => ser}/route_map.rs (100%)
 rename proxmox-frr/src/{ => ser}/serializer.rs (99%)

diff --git a/proxmox-frr/src/lib.rs b/proxmox-frr/src/lib.rs
index 86101182fafd..35b62cb39c91 100644
--- a/proxmox-frr/src/lib.rs
+++ b/proxmox-frr/src/lib.rs
@@ -1,241 +1 @@
-pub mod openfabric;
-pub mod ospf;
-pub mod route_map;
-pub mod serializer;
-
-use std::collections::{BTreeMap, BTreeSet};
-use std::fmt::Display;
-use std::str::FromStr;
-
-use crate::route_map::{AccessList, ProtocolRouteMap, RouteMap};
-
-use thiserror::Error;
-
-/// Generic FRR router.
-///
-/// This generic FRR router contains all the protocols that we implement.
-/// In FRR this is e.g.:
-/// ```text
-/// router openfabric test
-/// !....
-/// ! or
-/// router ospf
-/// !....
-/// ```
-#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub enum Router {
-    Openfabric(openfabric::OpenfabricRouter),
-    Ospf(ospf::OspfRouter),
-}
-
-impl From<openfabric::OpenfabricRouter> for Router {
-    fn from(value: openfabric::OpenfabricRouter) -> Self {
-        Router::Openfabric(value)
-    }
-}
-
-/// Generic FRR routername.
-///
-/// The variants represent different protocols. Some have `router <protocol> <name>`, others have
-/// `router <protocol> <process-id>`, some only have `router <protocol>`.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub enum RouterName {
-    Openfabric(openfabric::OpenfabricRouterName),
-    Ospf(ospf::OspfRouterName),
-}
-
-impl From<openfabric::OpenfabricRouterName> for RouterName {
-    fn from(value: openfabric::OpenfabricRouterName) -> Self {
-        Self::Openfabric(value)
-    }
-}
-
-impl Display for RouterName {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Openfabric(r) => r.fmt(f),
-            Self::Ospf(r) => r.fmt(f),
-        }
-    }
-}
-
-/// The interface name is the same on ospf and openfabric, but it is an enum so that we can have
-/// two different entries in the btreemap. This allows us to have an interface in a ospf and
-/// openfabric fabric.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub enum InterfaceName {
-    Openfabric(CommonInterfaceName),
-    Ospf(CommonInterfaceName),
-}
-
-impl Display for InterfaceName {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            InterfaceName::Openfabric(frr_word) => frr_word.fmt(f),
-            InterfaceName::Ospf(frr_word) => frr_word.fmt(f),
-        }
-    }
-}
-
-/// Generic FRR Interface.
-///
-/// In FRR config it looks like this:
-/// ```text
-/// interface <name>
-/// ! ...
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Interface {
-    Openfabric(openfabric::OpenfabricInterface),
-    Ospf(ospf::OspfInterface),
-}
-
-impl From<openfabric::OpenfabricInterface> for Interface {
-    fn from(value: openfabric::OpenfabricInterface) -> Self {
-        Self::Openfabric(value)
-    }
-}
-
-impl From<ospf::OspfInterface> for Interface {
-    fn from(value: ospf::OspfInterface) -> Self {
-        Self::Ospf(value)
-    }
-}
-
-#[derive(Error, Debug)]
-pub enum FrrWordError {
-    #[error("word is empty")]
-    IsEmpty,
-    #[error("word contains invalid character")]
-    InvalidCharacter,
-}
-
-/// A simple FRR Word.
-///
-/// Every string argument or value in FRR is an FrrWord. FrrWords must only contain ascii
-/// characters and must not have a whitespace.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct FrrWord(String);
-
-impl FrrWord {
-    pub fn new<T: AsRef<str> + Into<String>>(name: T) -> Result<Self, FrrWordError> {
-        if name.as_ref().is_empty() {
-            return Err(FrrWordError::IsEmpty);
-        }
-
-        if name
-            .as_ref()
-            .as_bytes()
-            .iter()
-            .any(|c| !c.is_ascii() || c.is_ascii_whitespace())
-        {
-            eprintln!("invalid char in: \"{}\"", name.as_ref());
-            return Err(FrrWordError::InvalidCharacter);
-        }
-
-        Ok(Self(name.into()))
-    }
-}
-
-impl FromStr for FrrWord {
-    type Err = FrrWordError;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        Self::new(s)
-    }
-}
-
-impl Display for FrrWord {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
-impl AsRef<str> for FrrWord {
-    fn as_ref(&self) -> &str {
-        &self.0
-    }
-}
-
-#[derive(Error, Debug)]
-pub enum CommonInterfaceNameError {
-    #[error("interface name too long")]
-    TooLong,
-}
-
-/// Name of a interface, which is common between all protocols.
-///
-/// FRR itself doesn't enforce any limits, but the kernel does. Linux only allows interface names
-/// to be a maximum of 16 bytes. This is enforced by this struct.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct CommonInterfaceName(String);
-
-impl TryFrom<&str> for CommonInterfaceName {
-    type Error = CommonInterfaceNameError;
-
-    fn try_from(value: &str) -> Result<Self, Self::Error> {
-        Self::new(value)
-    }
-}
-
-impl TryFrom<String> for CommonInterfaceName {
-    type Error = CommonInterfaceNameError;
-
-    fn try_from(value: String) -> Result<Self, Self::Error> {
-        Self::new(value)
-    }
-}
-
-impl CommonInterfaceName {
-    pub fn new<T: AsRef<str> + Into<String>>(s: T) -> Result<Self, CommonInterfaceNameError> {
-        if s.as_ref().len() <= 15 {
-            Ok(Self(s.into()))
-        } else {
-            Err(CommonInterfaceNameError::TooLong)
-        }
-    }
-}
-
-impl Display for CommonInterfaceName {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
-/// Main FRR config.
-///
-/// Contains the two main frr building blocks: routers and interfaces. It also holds other
-/// top-level FRR options, such as access-lists, router-maps and protocol-routemaps. This struct
-/// gets generated using the `FrrConfigBuilder` in `proxmox-ve-config`.
-#[derive(Clone, Debug, PartialEq, Eq, Default)]
-pub struct FrrConfig {
-    pub router: BTreeMap<RouterName, Router>,
-    pub interfaces: BTreeMap<InterfaceName, Interface>,
-    pub access_lists: Vec<AccessList>,
-    pub routemaps: Vec<RouteMap>,
-    pub protocol_routemaps: BTreeSet<ProtocolRouteMap>,
-}
-
-impl FrrConfig {
-    pub fn new() -> Self {
-        Self::default()
-    }
-
-    pub fn router(&self) -> impl Iterator<Item = (&RouterName, &Router)> + '_ {
-        self.router.iter()
-    }
-
-    pub fn interfaces(&self) -> impl Iterator<Item = (&InterfaceName, &Interface)> + '_ {
-        self.interfaces.iter()
-    }
-
-    pub fn access_lists(&self) -> impl Iterator<Item = &AccessList> + '_ {
-        self.access_lists.iter()
-    }
-    pub fn routemaps(&self) -> impl Iterator<Item = &RouteMap> + '_ {
-        self.routemaps.iter()
-    }
-
-    pub fn protocol_routemaps(&self) -> impl Iterator<Item = &ProtocolRouteMap> + '_ {
-        self.protocol_routemaps.iter()
-    }
-}
+pub mod ser;
diff --git a/proxmox-frr/src/ser/mod.rs b/proxmox-frr/src/ser/mod.rs
new file mode 100644
index 000000000000..a90397b59a9b
--- /dev/null
+++ b/proxmox-frr/src/ser/mod.rs
@@ -0,0 +1,241 @@
+pub mod openfabric;
+pub mod ospf;
+pub mod route_map;
+pub mod serializer;
+
+use std::collections::{BTreeMap, BTreeSet};
+use std::fmt::Display;
+use std::str::FromStr;
+
+use crate::ser::route_map::{AccessList, ProtocolRouteMap, RouteMap};
+
+use thiserror::Error;
+
+/// Generic FRR router.
+///
+/// This generic FRR router contains all the protocols that we implement.
+/// In FRR this is e.g.:
+/// ```text
+/// router openfabric test
+/// !....
+/// ! or
+/// router ospf
+/// !....
+/// ```
+#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum Router {
+    Openfabric(openfabric::OpenfabricRouter),
+    Ospf(ospf::OspfRouter),
+}
+
+impl From<openfabric::OpenfabricRouter> for Router {
+    fn from(value: openfabric::OpenfabricRouter) -> Self {
+        Router::Openfabric(value)
+    }
+}
+
+/// Generic FRR routername.
+///
+/// The variants represent different protocols. Some have `router <protocol> <name>`, others have
+/// `router <protocol> <process-id>`, some only have `router <protocol>`.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum RouterName {
+    Openfabric(openfabric::OpenfabricRouterName),
+    Ospf(ospf::OspfRouterName),
+}
+
+impl From<openfabric::OpenfabricRouterName> for RouterName {
+    fn from(value: openfabric::OpenfabricRouterName) -> Self {
+        Self::Openfabric(value)
+    }
+}
+
+impl Display for RouterName {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Openfabric(r) => r.fmt(f),
+            Self::Ospf(r) => r.fmt(f),
+        }
+    }
+}
+
+/// The interface name is the same on ospf and openfabric, but it is an enum so that we can have
+/// two different entries in the btreemap. This allows us to have an interface in a ospf and
+/// openfabric fabric.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum InterfaceName {
+    Openfabric(CommonInterfaceName),
+    Ospf(CommonInterfaceName),
+}
+
+impl Display for InterfaceName {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            InterfaceName::Openfabric(frr_word) => frr_word.fmt(f),
+            InterfaceName::Ospf(frr_word) => frr_word.fmt(f),
+        }
+    }
+}
+
+/// Generic FRR Interface.
+///
+/// In FRR config it looks like this:
+/// ```text
+/// interface <name>
+/// ! ...
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum Interface {
+    Openfabric(openfabric::OpenfabricInterface),
+    Ospf(ospf::OspfInterface),
+}
+
+impl From<openfabric::OpenfabricInterface> for Interface {
+    fn from(value: openfabric::OpenfabricInterface) -> Self {
+        Self::Openfabric(value)
+    }
+}
+
+impl From<ospf::OspfInterface> for Interface {
+    fn from(value: ospf::OspfInterface) -> Self {
+        Self::Ospf(value)
+    }
+}
+
+#[derive(Error, Debug)]
+pub enum FrrWordError {
+    #[error("word is empty")]
+    IsEmpty,
+    #[error("word contains invalid character")]
+    InvalidCharacter,
+}
+
+/// A simple FRR Word.
+///
+/// Every string argument or value in FRR is an FrrWord. FrrWords must only contain ascii
+/// characters and must not have a whitespace.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct FrrWord(String);
+
+impl FrrWord {
+    pub fn new<T: AsRef<str> + Into<String>>(name: T) -> Result<Self, FrrWordError> {
+        if name.as_ref().is_empty() {
+            return Err(FrrWordError::IsEmpty);
+        }
+
+        if name
+            .as_ref()
+            .as_bytes()
+            .iter()
+            .any(|c| !c.is_ascii() || c.is_ascii_whitespace())
+        {
+            eprintln!("invalid char in: \"{}\"", name.as_ref());
+            return Err(FrrWordError::InvalidCharacter);
+        }
+
+        Ok(Self(name.into()))
+    }
+}
+
+impl FromStr for FrrWord {
+    type Err = FrrWordError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        Self::new(s)
+    }
+}
+
+impl Display for FrrWord {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl AsRef<str> for FrrWord {
+    fn as_ref(&self) -> &str {
+        &self.0
+    }
+}
+
+#[derive(Error, Debug)]
+pub enum CommonInterfaceNameError {
+    #[error("interface name too long")]
+    TooLong,
+}
+
+/// Name of a interface, which is common between all protocols.
+///
+/// FRR itself doesn't enforce any limits, but the kernel does. Linux only allows interface names
+/// to be a maximum of 16 bytes. This is enforced by this struct.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct CommonInterfaceName(String);
+
+impl TryFrom<&str> for CommonInterfaceName {
+    type Error = CommonInterfaceNameError;
+
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        Self::new(value)
+    }
+}
+
+impl TryFrom<String> for CommonInterfaceName {
+    type Error = CommonInterfaceNameError;
+
+    fn try_from(value: String) -> Result<Self, Self::Error> {
+        Self::new(value)
+    }
+}
+
+impl CommonInterfaceName {
+    pub fn new<T: AsRef<str> + Into<String>>(s: T) -> Result<Self, CommonInterfaceNameError> {
+        if s.as_ref().len() <= 15 {
+            Ok(Self(s.into()))
+        } else {
+            Err(CommonInterfaceNameError::TooLong)
+        }
+    }
+}
+
+impl Display for CommonInterfaceName {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+/// Main FRR config.
+///
+/// Contains the two main frr building blocks: routers and interfaces. It also holds other
+/// top-level FRR options, such as access-lists, router-maps and protocol-routemaps. This struct
+/// gets generated using the `FrrConfigBuilder` in `proxmox-ve-config`.
+#[derive(Clone, Debug, PartialEq, Eq, Default)]
+pub struct FrrConfig {
+    pub router: BTreeMap<RouterName, Router>,
+    pub interfaces: BTreeMap<InterfaceName, Interface>,
+    pub access_lists: Vec<AccessList>,
+    pub routemaps: Vec<RouteMap>,
+    pub protocol_routemaps: BTreeSet<ProtocolRouteMap>,
+}
+
+impl FrrConfig {
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    pub fn router(&self) -> impl Iterator<Item = (&RouterName, &Router)> + '_ {
+        self.router.iter()
+    }
+
+    pub fn interfaces(&self) -> impl Iterator<Item = (&InterfaceName, &Interface)> + '_ {
+        self.interfaces.iter()
+    }
+
+    pub fn access_lists(&self) -> impl Iterator<Item = &AccessList> + '_ {
+        self.access_lists.iter()
+    }
+    pub fn routemaps(&self) -> impl Iterator<Item = &RouteMap> + '_ {
+        self.routemaps.iter()
+    }
+
+    pub fn protocol_routemaps(&self) -> impl Iterator<Item = &ProtocolRouteMap> + '_ {
+        self.protocol_routemaps.iter()
+    }
+}
diff --git a/proxmox-frr/src/openfabric.rs b/proxmox-frr/src/ser/openfabric.rs
similarity index 97%
rename from proxmox-frr/src/openfabric.rs
rename to proxmox-frr/src/ser/openfabric.rs
index 6e2a7200ab37..0f0c65062d36 100644
--- a/proxmox-frr/src/openfabric.rs
+++ b/proxmox-frr/src/ser/openfabric.rs
@@ -5,8 +5,8 @@ use proxmox_sdn_types::net::Net;
 
 use thiserror::Error;
 
-use crate::FrrWord;
-use crate::FrrWordError;
+use crate::ser::FrrWord;
+use crate::ser::FrrWordError;
 
 /// The name of a OpenFabric router. Is an FrrWord.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
diff --git a/proxmox-frr/src/ospf.rs b/proxmox-frr/src/ser/ospf.rs
similarity index 99%
rename from proxmox-frr/src/ospf.rs
rename to proxmox-frr/src/ser/ospf.rs
index d0e098e099d2..67e39a45b8de 100644
--- a/proxmox-frr/src/ospf.rs
+++ b/proxmox-frr/src/ser/ospf.rs
@@ -4,7 +4,7 @@ use std::net::Ipv4Addr;
 
 use thiserror::Error;
 
-use crate::{FrrWord, FrrWordError};
+use crate::ser::{FrrWord, FrrWordError};
 
 /// The name of the ospf frr router.
 ///
diff --git a/proxmox-frr/src/route_map.rs b/proxmox-frr/src/ser/route_map.rs
similarity index 100%
rename from proxmox-frr/src/route_map.rs
rename to proxmox-frr/src/ser/route_map.rs
diff --git a/proxmox-frr/src/serializer.rs b/proxmox-frr/src/ser/serializer.rs
similarity index 99%
rename from proxmox-frr/src/serializer.rs
rename to proxmox-frr/src/ser/serializer.rs
index f8a3c7238d94..3a681e2f0d7a 100644
--- a/proxmox-frr/src/serializer.rs
+++ b/proxmox-frr/src/ser/serializer.rs
@@ -1,6 +1,6 @@
 use std::fmt::{self, Write};
 
-use crate::{
+use crate::ser::{
     openfabric::{OpenfabricInterface, OpenfabricRouter},
     ospf::{OspfInterface, OspfRouter},
     route_map::{AccessList, AccessListName, ProtocolRouteMap, RouteMap},
diff --git a/proxmox-ve-config/src/sdn/fabric/frr.rs b/proxmox-ve-config/src/sdn/fabric/frr.rs
index 486f7dc51dcb..10025b3544b9 100644
--- a/proxmox-ve-config/src/sdn/fabric/frr.rs
+++ b/proxmox-ve-config/src/sdn/fabric/frr.rs
@@ -1,12 +1,7 @@
 use std::net::{IpAddr, Ipv4Addr};
 use tracing;
 
-use proxmox_frr::ospf::{self, NetworkType};
-use proxmox_frr::route_map::{
-    AccessAction, AccessList, AccessListName, AccessListRule, ProtocolRouteMap, ProtocolType,
-    RouteMap, RouteMapMatch, RouteMapMatchInner, RouteMapName, RouteMapSet,
-};
-use proxmox_frr::{FrrConfig, FrrWord, Interface, InterfaceName, Router, RouterName};
+use proxmox_frr::ser::{self};
 use proxmox_network_types::ip_address::Cidr;
 use proxmox_sdn_types::net::Net;
 
@@ -26,7 +21,7 @@ use crate::sdn::fabric::{FabricConfig, FabricEntry};
 pub fn build_fabric(
     current_node: NodeId,
     config: Valid<FabricConfig>,
-    frr_config: &mut FrrConfig,
+    frr_config: &mut ser::FrrConfig,
 ) -> Result<(), anyhow::Error> {
     let mut routemap_seq = 100;
     let mut current_router_id: Option<Ipv4Addr> = None;
@@ -93,27 +88,31 @@ pub fn build_fabric(
                 }
 
                 if let Some(ipv4cidr) = fabric.ip_prefix() {
-                    let rule = AccessListRule {
-                        action: AccessAction::Permit,
+                    let rule = ser::route_map::AccessListRule {
+                        action: ser::route_map::AccessAction::Permit,
                         network: Cidr::from(ipv4cidr),
                         seq: None,
                     };
-                    let access_list_name =
-                        AccessListName::new(format!("pve_openfabric_{}_ips", fabric_id));
-                    frr_config.access_lists.push(AccessList {
+                    let access_list_name = ser::route_map::AccessListName::new(format!(
+                        "pve_openfabric_{}_ips",
+                        fabric_id
+                    ));
+                    frr_config.access_lists.push(ser::route_map::AccessList {
                         name: access_list_name,
                         rules: vec![rule],
                     });
                 }
                 if let Some(ipv6cidr) = fabric.ip6_prefix() {
-                    let rule = AccessListRule {
-                        action: AccessAction::Permit,
+                    let rule = ser::route_map::AccessListRule {
+                        action: ser::route_map::AccessAction::Permit,
                         network: Cidr::from(ipv6cidr),
                         seq: None,
                     };
-                    let access_list_name =
-                        AccessListName::new(format!("pve_openfabric_{}_ip6s", fabric_id));
-                    frr_config.access_lists.push(AccessList {
+                    let access_list_name = ser::route_map::AccessListName::new(format!(
+                        "pve_openfabric_{}_ip6s",
+                        fabric_id
+                    ));
+                    frr_config.access_lists.push(ser::route_map::AccessList {
                         name: access_list_name,
                         rules: vec![rule],
                     });
@@ -128,10 +127,12 @@ pub fn build_fabric(
                     ));
                     routemap_seq += 10;
 
-                    let protocol_routemap = ProtocolRouteMap {
+                    let protocol_routemap = ser::route_map::ProtocolRouteMap {
                         is_ipv6: false,
-                        protocol: ProtocolType::Openfabric,
-                        routemap_name: RouteMapName::new("pve_openfabric".to_owned()),
+                        protocol: ser::route_map::ProtocolType::Openfabric,
+                        routemap_name: ser::route_map::RouteMapName::new(
+                            "pve_openfabric".to_owned(),
+                        ),
                     };
 
                     frr_config.protocol_routemaps.insert(protocol_routemap);
@@ -145,10 +146,12 @@ pub fn build_fabric(
                     ));
                     routemap_seq += 10;
 
-                    let protocol_routemap = ProtocolRouteMap {
+                    let protocol_routemap = ser::route_map::ProtocolRouteMap {
                         is_ipv6: true,
-                        protocol: ProtocolType::Openfabric,
-                        routemap_name: RouteMapName::new("pve_openfabric6".to_owned()),
+                        protocol: ser::route_map::ProtocolType::Openfabric,
+                        routemap_name: ser::route_map::RouteMapName::new(
+                            "pve_openfabric6".to_owned(),
+                        ),
                     };
 
                     frr_config.protocol_routemaps.insert(protocol_routemap);
@@ -164,8 +167,8 @@ pub fn build_fabric(
 
                 let fabric = ospf_entry.fabric_section();
 
-                let frr_word_area = FrrWord::new(fabric.properties().area.to_string())?;
-                let frr_area = ospf::Area::new(frr_word_area)?;
+                let frr_word_area = ser::FrrWord::new(fabric.properties().area.to_string())?;
+                let frr_area = ser::ospf::Area::new(frr_word_area)?;
                 let (router_name, router_item) = build_ospf_router(*router_id)?;
                 frr_config.router.insert(router_name, router_item);
 
@@ -196,17 +199,18 @@ pub fn build_fabric(
                     }
                 }
 
-                let access_list_name = AccessListName::new(format!("pve_ospf_{}_ips", fabric_id));
+                let access_list_name =
+                    ser::route_map::AccessListName::new(format!("pve_ospf_{}_ips", fabric_id));
 
-                let rule = AccessListRule {
-                    action: AccessAction::Permit,
+                let rule = ser::route_map::AccessListRule {
+                    action: ser::route_map::AccessAction::Permit,
                     network: Cidr::from(
                         fabric.ip_prefix().expect("fabric must have a ipv4 prefix"),
                     ),
                     seq: None,
                 };
 
-                frr_config.access_lists.push(AccessList {
+                frr_config.access_lists.push(ser::route_map::AccessList {
                     name: access_list_name,
                     rules: vec![rule],
                 });
@@ -220,10 +224,10 @@ pub fn build_fabric(
                 routemap_seq += 10;
                 frr_config.routemaps.push(routemap);
 
-                let protocol_routemap = ProtocolRouteMap {
+                let protocol_routemap = ser::route_map::ProtocolRouteMap {
                     is_ipv6: false,
-                    protocol: ProtocolType::Ospf,
-                    routemap_name: RouteMapName::new("pve_ospf".to_owned()),
+                    protocol: ser::route_map::ProtocolType::Ospf,
+                    routemap_name: ser::route_map::RouteMapName::new("pve_ospf".to_owned()),
                 };
 
                 frr_config.protocol_routemaps.insert(protocol_routemap);
@@ -234,10 +238,10 @@ pub fn build_fabric(
 }
 
 /// Helper that builds a OSPF router with a the router_id.
-fn build_ospf_router(router_id: Ipv4Addr) -> Result<(RouterName, Router), anyhow::Error> {
-    let ospf_router = proxmox_frr::ospf::OspfRouter { router_id };
-    let router_item = Router::Ospf(ospf_router);
-    let router_name = RouterName::Ospf(proxmox_frr::ospf::OspfRouterName);
+fn build_ospf_router(router_id: Ipv4Addr) -> Result<(ser::RouterName, ser::Router), anyhow::Error> {
+    let ospf_router = ser::ospf::OspfRouter { router_id };
+    let router_item = ser::Router::Ospf(ospf_router);
+    let router_name = ser::RouterName::Ospf(ser::ospf::OspfRouterName);
     Ok((router_name, router_item))
 }
 
@@ -245,45 +249,45 @@ fn build_ospf_router(router_id: Ipv4Addr) -> Result<(RouterName, Router), anyhow
 fn build_openfabric_router(
     fabric_id: &FabricId,
     net: Net,
-) -> Result<(RouterName, Router), anyhow::Error> {
-    let ofr = proxmox_frr::openfabric::OpenfabricRouter { net };
-    let router_item = Router::Openfabric(ofr);
-    let frr_word_id = FrrWord::new(fabric_id.to_string())?;
-    let router_name = RouterName::Openfabric(frr_word_id.into());
+) -> Result<(ser::RouterName, ser::Router), anyhow::Error> {
+    let ofr = ser::openfabric::OpenfabricRouter { net };
+    let router_item = ser::Router::Openfabric(ofr);
+    let frr_word_id = ser::FrrWord::new(fabric_id.to_string())?;
+    let router_name = ser::RouterName::Openfabric(frr_word_id.into());
     Ok((router_name, router_item))
 }
 
 /// Helper that builds a OSPF interface from an [`ospf::Area`] and the [`OspfInterfaceProperties`].
 fn build_ospf_interface(
-    area: ospf::Area,
+    area: ser::ospf::Area,
     interface: &OspfInterfaceProperties,
-) -> Result<(Interface, InterfaceName), anyhow::Error> {
-    let frr_interface = proxmox_frr::ospf::OspfInterface {
+) -> Result<(ser::Interface, ser::InterfaceName), anyhow::Error> {
+    let frr_interface = ser::ospf::OspfInterface {
         area,
         // Interfaces are always none-passive
         passive: None,
         network_type: if interface.ip.is_some() {
             None
         } else {
-            Some(NetworkType::PointToPoint)
+            Some(ser::ospf::NetworkType::PointToPoint)
         },
     };
 
-    let interface_name = InterfaceName::Ospf(interface.name.as_str().try_into()?);
+    let interface_name = ser::InterfaceName::Ospf(interface.name.as_str().try_into()?);
     Ok((frr_interface.into(), interface_name))
 }
 
 /// Helper that builds the OSPF dummy interface using the [`FabricId`] and the [`ospf::Area`].
 fn build_ospf_dummy_interface(
     fabric_id: &FabricId,
-    area: ospf::Area,
-) -> Result<(Interface, InterfaceName), anyhow::Error> {
-    let frr_interface = proxmox_frr::ospf::OspfInterface {
+    area: ser::ospf::Area,
+) -> Result<(ser::Interface, ser::InterfaceName), anyhow::Error> {
+    let frr_interface = ser::ospf::OspfInterface {
         area,
         passive: Some(true),
         network_type: None,
     };
-    let interface_name = InterfaceName::Openfabric(format!("dummy_{}", fabric_id).try_into()?);
+    let interface_name = ser::InterfaceName::Openfabric(format!("dummy_{}", fabric_id).try_into()?);
     Ok((frr_interface.into(), interface_name))
 }
 
@@ -297,9 +301,9 @@ fn build_openfabric_interface(
     fabric_config: &OpenfabricProperties,
     is_ipv4: bool,
     is_ipv6: bool,
-) -> Result<(Interface, InterfaceName), anyhow::Error> {
-    let frr_word = FrrWord::new(fabric_id.to_string())?;
-    let mut frr_interface = proxmox_frr::openfabric::OpenfabricInterface {
+) -> Result<(ser::Interface, ser::InterfaceName), anyhow::Error> {
+    let frr_word = ser::FrrWord::new(fabric_id.to_string())?;
+    let mut frr_interface = ser::openfabric::OpenfabricInterface {
         fabric_id: frr_word.into(),
         // Every interface is not passive by default
         passive: None,
@@ -315,7 +319,7 @@ fn build_openfabric_interface(
     if frr_interface.hello_interval.is_none() {
         frr_interface.hello_interval = fabric_config.hello_interval;
     }
-    let interface_name = InterfaceName::Openfabric(interface.name.as_str().try_into()?);
+    let interface_name = ser::InterfaceName::Openfabric(interface.name.as_str().try_into()?);
     Ok((frr_interface.into(), interface_name))
 }
 
@@ -324,9 +328,9 @@ fn build_openfabric_dummy_interface(
     fabric_id: &FabricId,
     is_ipv4: bool,
     is_ipv6: bool,
-) -> Result<(Interface, InterfaceName), anyhow::Error> {
-    let frr_word = FrrWord::new(fabric_id.to_string())?;
-    let frr_interface = proxmox_frr::openfabric::OpenfabricInterface {
+) -> Result<(ser::Interface, ser::InterfaceName), anyhow::Error> {
+    let frr_word = ser::FrrWord::new(fabric_id.to_string())?;
+    let frr_interface = ser::openfabric::OpenfabricInterface {
         fabric_id: frr_word.into(),
         hello_interval: None,
         passive: Some(true),
@@ -335,29 +339,37 @@ fn build_openfabric_dummy_interface(
         is_ipv4,
         is_ipv6,
     };
-    let interface_name = InterfaceName::Openfabric(format!("dummy_{}", fabric_id).try_into()?);
+    let interface_name = ser::InterfaceName::Openfabric(format!("dummy_{}", fabric_id).try_into()?);
     Ok((frr_interface.into(), interface_name))
 }
 
 /// Helper that builds a RouteMap for the OpenFabric protocol.
-fn build_openfabric_routemap(fabric_id: &FabricId, router_ip: IpAddr, seq: u32) -> RouteMap {
+fn build_openfabric_routemap(
+    fabric_id: &FabricId,
+    router_ip: IpAddr,
+    seq: u32,
+) -> ser::route_map::RouteMap {
     let routemap_name = match router_ip {
-        IpAddr::V4(_) => RouteMapName::new("pve_openfabric".to_owned()),
-        IpAddr::V6(_) => RouteMapName::new("pve_openfabric6".to_owned()),
+        IpAddr::V4(_) => ser::route_map::RouteMapName::new("pve_openfabric".to_owned()),
+        IpAddr::V6(_) => ser::route_map::RouteMapName::new("pve_openfabric6".to_owned()),
     };
-    RouteMap {
+    ser::route_map::RouteMap {
         name: routemap_name.clone(),
         seq,
-        action: AccessAction::Permit,
+        action: ser::route_map::AccessAction::Permit,
         matches: vec![match router_ip {
-            IpAddr::V4(_) => RouteMapMatch::V4(RouteMapMatchInner::IpAddress(AccessListName::new(
-                format!("pve_openfabric_{fabric_id}_ips"),
-            ))),
-            IpAddr::V6(_) => RouteMapMatch::V6(RouteMapMatchInner::IpAddress(AccessListName::new(
-                format!("pve_openfabric_{fabric_id}_ip6s"),
-            ))),
+            IpAddr::V4(_) => {
+                ser::route_map::RouteMapMatch::V4(ser::route_map::RouteMapMatchInner::IpAddress(
+                    ser::route_map::AccessListName::new(format!("pve_openfabric_{fabric_id}_ips")),
+                ))
+            }
+            IpAddr::V6(_) => {
+                ser::route_map::RouteMapMatch::V6(ser::route_map::RouteMapMatchInner::IpAddress(
+                    ser::route_map::AccessListName::new(format!("pve_openfabric_{fabric_id}_ip6s")),
+                ))
+            }
         }],
-        sets: vec![RouteMapSet::IpSrc(router_ip)],
+        sets: vec![ser::route_map::RouteMapSet::IpSrc(router_ip)],
     }
 }
 
@@ -366,17 +378,19 @@ fn build_ospf_dummy_routemap(
     fabric_id: &FabricId,
     router_ip: Ipv4Addr,
     seq: u32,
-) -> Result<RouteMap, anyhow::Error> {
-    let routemap_name = RouteMapName::new("pve_ospf".to_owned());
+) -> Result<ser::route_map::RouteMap, anyhow::Error> {
+    let routemap_name = ser::route_map::RouteMapName::new("pve_ospf".to_owned());
     // create route-map
-    let routemap = RouteMap {
+    let routemap = ser::route_map::RouteMap {
         name: routemap_name.clone(),
         seq,
-        action: AccessAction::Permit,
-        matches: vec![RouteMapMatch::V4(RouteMapMatchInner::IpAddress(
-            AccessListName::new(format!("pve_ospf_{fabric_id}_ips")),
-        ))],
-        sets: vec![RouteMapSet::IpSrc(IpAddr::from(router_ip))],
+        action: ser::route_map::AccessAction::Permit,
+        matches: vec![ser::route_map::RouteMapMatch::V4(
+            ser::route_map::RouteMapMatchInner::IpAddress(ser::route_map::AccessListName::new(
+                format!("pve_ospf_{fabric_id}_ips"),
+            )),
+        )],
+        sets: vec![ser::route_map::RouteMapSet::IpSrc(IpAddr::from(router_ip))],
     };
 
     Ok(routemap)
diff --git a/proxmox-ve-config/src/sdn/frr.rs b/proxmox-ve-config/src/sdn/frr.rs
index f7929c1f6c16..5d4e4b2ebdbd 100644
--- a/proxmox-ve-config/src/sdn/frr.rs
+++ b/proxmox-ve-config/src/sdn/frr.rs
@@ -1,6 +1,6 @@
 use std::collections::{BTreeMap, BTreeSet};
 
-use proxmox_frr::FrrConfig;
+use proxmox_frr::ser::FrrConfig;
 
 use crate::common::valid::Valid;
 use crate::sdn::fabric::{section_config::node::NodeId, FabricConfig};
diff --git a/proxmox-ve-config/tests/fabric/main.rs b/proxmox-ve-config/tests/fabric/main.rs
index 47bbbeb77886..09629d406449 100644
--- a/proxmox-ve-config/tests/fabric/main.rs
+++ b/proxmox-ve-config/tests/fabric/main.rs
@@ -1,5 +1,5 @@
 #![cfg(feature = "frr")]
-use proxmox_frr::serializer::dump;
+use proxmox_frr::ser::serializer::dump;
 use proxmox_ve_config::sdn::{
     fabric::{section_config::node::NodeId, FabricConfig},
     frr::FrrConfigBuilder,
-- 
2.47.2



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


  reply	other threads:[~2025-08-22  9:02 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 ` Gabriel Goller [this message]
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
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=20250822090102.102949-2-g.goller@proxmox.com \
    --to=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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal