use crate::{
formatter::NetworkFormatter,
ospf::{IgpTarget, OspfImpl},
types::{IntoIpv4Prefix, Ipv4Prefix, Prefix, PrefixMap, RouterId},
};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SrProcess<P: Prefix> {
pub(crate) static_routes: P::Map<StaticRoute>,
}
impl<P: Prefix> IntoIpv4Prefix for SrProcess<P> {
type T = SrProcess<Ipv4Prefix>;
fn into_ipv4_prefix(self) -> Self::T {
SrProcess {
static_routes: self
.static_routes
.into_iter()
.map(|(p, sr)| (p.into_ipv4_prefix(), sr))
.collect(),
}
}
}
impl<P: Prefix> SrProcess<P> {
pub(super) fn new() -> Self {
Self {
static_routes: Default::default(),
}
}
pub(crate) fn set(&mut self, prefix: P, route: Option<StaticRoute>) -> Option<StaticRoute> {
if let Some(route) = route {
self.static_routes.insert(prefix, route)
} else {
self.static_routes.remove(&prefix)
}
}
pub fn get(&self, prefix: P) -> Option<StaticRoute> {
self.static_routes.get_lpm(&prefix).map(|(_, sr)| *sr)
}
pub fn get_exact(&self, prefix: P) -> Option<StaticRoute> {
self.static_routes.get_lpm(&prefix).map(|(_, sr)| *sr)
}
pub fn get_table(&self) -> &P::Map<StaticRoute> {
&self.static_routes
}
}
impl<'n, P: Prefix, Q, Ospf: OspfImpl> NetworkFormatter<'n, P, Q, Ospf> for SrProcess<P> {
fn fmt(&self, net: &'n crate::network::Network<P, Q, Ospf>) -> String {
self.static_routes
.iter()
.map(|(p, sr)| format!("{p} -> {}", sr.fmt(net)))
.join("\n")
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, Copy, Serialize, Deserialize)]
pub enum StaticRoute {
Direct(RouterId),
Indirect(RouterId),
Drop,
}
impl From<StaticRoute> for IgpTarget {
fn from(value: StaticRoute) -> Self {
match value {
StaticRoute::Direct(r) => IgpTarget::Neighbor(r),
StaticRoute::Indirect(r) => IgpTarget::Ospf(r),
StaticRoute::Drop => IgpTarget::Drop,
}
}
}
impl StaticRoute {
pub fn router(&self) -> Option<RouterId> {
match self {
StaticRoute::Direct(r) | StaticRoute::Indirect(r) => Some(*r),
StaticRoute::Drop => None,
}
}
}