use crate::{
event::{Event, EventOutcome},
ospf::{global::GlobalOspfProcess, IgpTarget, OspfProcess},
types::{
DeviceError, IntoIpv4Prefix, Ipv4Prefix, Prefix, PrefixMap, RouterId, StepUpdate, ASN,
},
};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
mod bgp_process;
mod sr_process;
pub use bgp_process::BgpProcess;
pub use sr_process::{SrProcess, StaticRoute};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(bound(deserialize = "P: for<'a> Deserialize<'a>, Ospf: for<'a> Deserialize<'a>"))]
pub struct Router<P: Prefix, Ospf = GlobalOspfProcess> {
name: String,
router_id: RouterId,
asn: ASN,
pub ospf: Ospf,
pub sr: SrProcess<P>,
pub bgp: BgpProcess<P>,
pub(crate) do_load_balancing: bool,
}
impl<P: Prefix, Ospf> IntoIpv4Prefix for Router<P, Ospf> {
type T = Router<Ipv4Prefix, Ospf>;
fn into_ipv4_prefix(self) -> Self::T {
Router {
name: self.name,
router_id: self.router_id,
asn: self.asn,
ospf: self.ospf,
sr: self.sr.into_ipv4_prefix(),
bgp: self.bgp.into_ipv4_prefix(),
do_load_balancing: self.do_load_balancing,
}
}
}
impl<P: Prefix, Ospf: Clone> Clone for Router<P, Ospf> {
fn clone(&self) -> Self {
Router {
name: self.name.clone(),
router_id: self.router_id,
asn: self.asn,
ospf: self.ospf.clone(),
sr: self.sr.clone(),
bgp: self.bgp.clone(),
do_load_balancing: self.do_load_balancing,
}
}
}
impl<P: Prefix, Ospf> Router<P, Ospf> {
pub fn router_id(&self) -> RouterId {
self.router_id
}
pub fn name(&self) -> &str {
self.name.as_ref()
}
pub(crate) fn set_name(&mut self, name: String) {
self.name = name;
}
pub fn asn(&self) -> ASN {
self.asn
}
pub(crate) fn set_asn(&mut self, asn: ASN) -> ASN {
let old_asn = self.asn;
self.asn = asn;
self.bgp.set_asn(asn);
old_asn
}
pub fn get_load_balancing(&self) -> bool {
self.do_load_balancing
}
pub(crate) fn set_load_balancing(&mut self, mut do_load_balancing: bool) -> bool {
std::mem::swap(&mut self.do_load_balancing, &mut do_load_balancing);
do_load_balancing
}
}
impl<P: Prefix, Ospf: OspfProcess> Router<P, Ospf> {
pub(crate) fn new(name: String, router_id: RouterId, asn: ASN) -> Router<P, Ospf> {
Router {
name,
router_id,
asn,
ospf: Ospf::new(router_id),
sr: SrProcess::new(),
bgp: BgpProcess::new(router_id, asn),
do_load_balancing: false,
}
}
pub unsafe fn trigger_event<T: Default>(
&mut self,
event: Event<P, T>,
) -> Result<EventOutcome<P, T>, DeviceError> {
self.handle_event(event)
}
pub(crate) fn handle_event<T: Default>(
&mut self,
event: Event<P, T>,
) -> Result<EventOutcome<P, T>, DeviceError> {
match event {
Event::Bgp { src, dst, e, .. } if dst == self.router_id => {
let prefix = e.prefix();
let old = self.get_next_hop(prefix);
let events = self.bgp.handle_event(src, e)?;
let new = self.get_next_hop(prefix);
Ok((StepUpdate::new(prefix, old, new), events))
}
Event::Ospf {
src, dst, area, e, ..
} if dst == self.router_id => {
let (changed, mut ospf_events) = self.ospf.handle_event(src, area, e)?;
if changed {
self.bgp.update_igp(&self.ospf);
let mut bgp_events = self.bgp.update_tables(false)?;
ospf_events.append(&mut bgp_events);
Ok((StepUpdate::Multiple, ospf_events))
} else {
Ok((StepUpdate::Unchanged, ospf_events))
}
}
Event::Bgp { dst, .. } | Event::Ospf { dst, .. } => {
Err(DeviceError::WrongRouter(self.router_id, dst))
}
}
}
pub(crate) fn is_waiting_for_timeout(&self) -> bool {
self.ospf.is_waiting_for_timeout()
}
pub(crate) fn trigger_timeout<T: Default>(&mut self) -> Result<Vec<Event<P, T>>, DeviceError> {
self.update_ospf(|ospf| ospf.trigger_timeout())
}
pub fn get_fib(&self) -> P::Map<Vec<RouterId>> {
let prefixes: Vec<_> = self
.sr
.get_table()
.keys()
.chain(self.bgp.rib.keys())
.unique()
.copied()
.collect();
let mut result: P::Map<Vec<RouterId>> = Default::default();
for prefix in prefixes {
result.insert(prefix, self.get_next_hop(prefix));
}
result
}
pub fn get_next_hop(&self, prefix: P) -> Vec<RouterId> {
let sr_target = self.sr.get_table().get_lpm(&prefix);
let bgp_rib = self.bgp.get_route(prefix);
let target = match (sr_target, bgp_rib) {
(Some((sr_p, sr_target)), Some(route)) if route.route.prefix.contains(sr_p) => {
IgpTarget::from(*sr_target)
}
(Some((_, target)), None) => IgpTarget::from(*target),
(_, Some(route)) => IgpTarget::Ospf(route.route.next_hop),
(None, None) => IgpTarget::Drop,
};
let nhs = self.ospf.get(target);
if self.do_load_balancing || nhs.is_empty() {
nhs.to_vec()
} else {
vec![nhs[0]]
}
}
pub(crate) fn update_ospf<F, T: Default>(
&mut self,
f: F,
) -> Result<Vec<Event<P, T>>, DeviceError>
where
F: FnOnce(&mut Ospf) -> Result<(bool, Vec<Event<P, T>>), DeviceError>,
{
let (recompute_bgp, mut ospf_events) = f(&mut self.ospf)?;
if recompute_bgp {
self.bgp.update_igp(&self.ospf);
let mut bgp_events = self.bgp.update_tables(false)?;
ospf_events.append(&mut bgp_events);
}
Ok(ospf_events)
}
pub(crate) fn swap_ospf<Ospf2: OspfProcess>(self) -> (Router<P, Ospf2>, Ospf) {
(
Router {
name: self.name,
router_id: self.router_id,
asn: self.asn,
ospf: Ospf2::new(self.router_id),
sr: self.sr,
bgp: self.bgp,
do_load_balancing: self.do_load_balancing,
},
self.ospf,
)
}
}