Add types to generate the IS-IS frr configuration. These are very similar to the OpenFabric configuration, but we want to keep them separate because they will diverge in the future.
Signed-off-by: Gabriel Goller <g.gol...@proxmox.com> --- proxmox-frr/src/isis.rs | 90 +++++++++++++++++++++++++++++++++++ proxmox-frr/src/lib.rs | 13 +++++ proxmox-frr/src/route_map.rs | 2 + proxmox-frr/src/serializer.rs | 37 ++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 proxmox-frr/src/isis.rs diff --git a/proxmox-frr/src/isis.rs b/proxmox-frr/src/isis.rs new file mode 100644 index 000000000000..a407c900ae58 --- /dev/null +++ b/proxmox-frr/src/isis.rs @@ -0,0 +1,90 @@ +use std::fmt::Debug; +use std::fmt::Display; + +use proxmox_sdn_types::net::Net; + +use thiserror::Error; + +use crate::FrrWord; +use crate::FrrWordError; + +/// The name of a IS-IS router. Is an FrrWord. +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct IsisRouterName(FrrWord); + +impl From<FrrWord> for IsisRouterName { + fn from(value: FrrWord) -> Self { + Self(value) + } +} + +impl IsisRouterName { + pub fn new(name: FrrWord) -> Self { + Self(name) + } +} + +impl Display for IsisRouterName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "isis {}", self.0) + } +} + +/// All the properties a IS-IS router can hold. +/// +/// These can serialized with a " " space prefix as they are in the `router isis` block. +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct IsisRouter { + /// The NET address + pub net: Net, +} + +impl IsisRouter { + pub fn new(net: Net) -> Self { + Self { net } + } + + pub fn net(&self) -> &Net { + &self.net + } +} + +/// The IS-IS interface properties. +/// +/// This struct holds all the IS-IS interface properties. The most important one here is the +/// fabric_id, which ties the interface to a fabric. When serialized these properties all get +/// prefixed with a space (" ") as they are inside the interface block. They serialize roughly to: +/// +/// ```text +/// interface ens20 +/// ip router isis <fabric_id> +/// ipv6 router isis <fabric_id> +/// isis hello-interval <value> +/// isis hello-multiplier <value> +/// isis csnp-interval <value> +/// isis passive <value> +/// ``` +/// +/// The is_ipv4 and is_ipv6 properties decide if we need to add `ip router isis`, `ipv6 +/// router isis`, or both. An interface can only be part of a single fabric. +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct IsisInterface { + // Note: an interface can only be a part of a single fabric (so no vec needed here) + pub fabric_id: IsisRouterName, + pub passive: Option<bool>, + // Note: openfabric is very similar to isis, so we can use the same properties here + pub hello_interval: Option<proxmox_sdn_types::openfabric::HelloInterval>, + pub csnp_interval: Option<proxmox_sdn_types::openfabric::CsnpInterval>, + pub hello_multiplier: Option<proxmox_sdn_types::openfabric::HelloMultiplier>, + pub point_to_point: bool, + pub is_ipv4: bool, + pub is_ipv6: bool, +} + +#[derive(Error, Debug)] +pub enum IsisInterfaceError { + #[error("Unknown error converting to IsisInterface")] + UnknownError, + #[error("Error parsing frr word")] + FrrWordParse(#[from] FrrWordError), +} diff --git a/proxmox-frr/src/lib.rs b/proxmox-frr/src/lib.rs index 86101182fafd..daf592e0ad7f 100644 --- a/proxmox-frr/src/lib.rs +++ b/proxmox-frr/src/lib.rs @@ -1,3 +1,4 @@ +pub mod isis; pub mod openfabric; pub mod ospf; pub mod route_map; @@ -25,6 +26,7 @@ use thiserror::Error; #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum Router { Openfabric(openfabric::OpenfabricRouter), + Isis(isis::IsisRouter), Ospf(ospf::OspfRouter), } @@ -41,6 +43,7 @@ impl From<openfabric::OpenfabricRouter> for Router { #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum RouterName { Openfabric(openfabric::OpenfabricRouterName), + Isis(isis::IsisRouterName), Ospf(ospf::OspfRouterName), } @@ -54,6 +57,7 @@ impl Display for RouterName { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Openfabric(r) => r.fmt(f), + Self::Isis(r) => r.fmt(f), Self::Ospf(r) => r.fmt(f), } } @@ -65,6 +69,7 @@ impl Display for RouterName { #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum InterfaceName { Openfabric(CommonInterfaceName), + Isis(CommonInterfaceName), Ospf(CommonInterfaceName), } @@ -72,6 +77,7 @@ 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::Isis(frr_word) => frr_word.fmt(f), InterfaceName::Ospf(frr_word) => frr_word.fmt(f), } } @@ -86,6 +92,7 @@ impl Display for InterfaceName { #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Interface { Openfabric(openfabric::OpenfabricInterface), + Isis(isis::IsisInterface), Ospf(ospf::OspfInterface), } @@ -95,6 +102,12 @@ impl From<openfabric::OpenfabricInterface> for Interface { } } +impl From<isis::IsisInterface> for Interface { + fn from(value: isis::IsisInterface) -> Self { + Self::Isis(value) + } +} + impl From<ospf::OspfInterface> for Interface { fn from(value: ospf::OspfInterface) -> Self { Self::Ospf(value) diff --git a/proxmox-frr/src/route_map.rs b/proxmox-frr/src/route_map.rs index 0918a3cead14..4e163a912425 100644 --- a/proxmox-frr/src/route_map.rs +++ b/proxmox-frr/src/route_map.rs @@ -201,6 +201,7 @@ pub struct RouteMap { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ProtocolType { Openfabric, + Isis, Ospf, } @@ -208,6 +209,7 @@ impl Display for ProtocolType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ProtocolType::Openfabric => write!(f, "openfabric"), + ProtocolType::Isis => write!(f, "isis"), ProtocolType::Ospf => write!(f, "ospf"), } } diff --git a/proxmox-frr/src/serializer.rs b/proxmox-frr/src/serializer.rs index f8a3c7238d94..794c43db8888 100644 --- a/proxmox-frr/src/serializer.rs +++ b/proxmox-frr/src/serializer.rs @@ -1,6 +1,7 @@ use std::fmt::{self, Write}; use crate::{ + isis::{IsisInterface, IsisRouter}, openfabric::{OpenfabricInterface, OpenfabricRouter}, ospf::{OspfInterface, OspfRouter}, route_map::{AccessList, AccessListName, ProtocolRouteMap, RouteMap}, @@ -84,6 +85,7 @@ impl FrrSerializer for Interface { fn serialize(&self, f: &mut FrrConfigBlob<'_>) -> fmt::Result { match self { Interface::Openfabric(openfabric_interface) => openfabric_interface.serialize(f)?, + Interface::Isis(isis_interface) => isis_interface.serialize(f)?, Interface::Ospf(ospf_interface) => ospf_interface.serialize(f)?, } Ok(()) @@ -114,6 +116,33 @@ impl FrrSerializer for OpenfabricInterface { } } +impl FrrSerializer for IsisInterface { + fn serialize(&self, f: &mut FrrConfigBlob<'_>) -> fmt::Result { + if self.is_ipv6 { + writeln!(f, " ipv6 router {}", self.fabric_id)?; + } + if self.is_ipv4 { + writeln!(f, " ip router {}", self.fabric_id)?; + } + if self.passive == Some(true) { + writeln!(f, " isis passive")?; + } + if let Some(interval) = self.hello_interval { + writeln!(f, " isis hello-interval {interval}",)?; + } + if let Some(multiplier) = self.hello_multiplier { + writeln!(f, " isis hello-multiplier {multiplier}",)?; + } + if let Some(interval) = self.csnp_interval { + writeln!(f, " isis csnp-interval {interval}",)?; + } + if self.point_to_point { + writeln!(f, " isis network point-to-point")?; + } + Ok(()) + } +} + impl FrrSerializer for OspfInterface { fn serialize(&self, f: &mut FrrConfigBlob<'_>) -> fmt::Result { writeln!(f, " ip ospf {}", self.area)?; @@ -131,6 +160,7 @@ impl FrrSerializer for Router { fn serialize(&self, f: &mut FrrConfigBlob<'_>) -> fmt::Result { match self { Router::Openfabric(open_fabric_router) => open_fabric_router.serialize(f), + Router::Isis(isis_router) => isis_router.serialize(f), Router::Ospf(ospf_router) => ospf_router.serialize(f), } } @@ -143,6 +173,13 @@ impl FrrSerializer for OpenfabricRouter { } } +impl FrrSerializer for IsisRouter { + fn serialize(&self, f: &mut FrrConfigBlob<'_>) -> fmt::Result { + writeln!(f, " net {}", self.net())?; + Ok(()) + } +} + impl FrrSerializer for OspfRouter { fn serialize(&self, f: &mut FrrConfigBlob<'_>) -> fmt::Result { writeln!(f, " ospf router-id {}", self.router_id())?; -- 2.47.2 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel