use crate::{
bgp::{BgpEvent, BgpRoute},
event::{Event, EventOutcome},
types::{AsId, DeviceError, Prefix, PrefixMap, RouterId, StepUpdate},
};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
#[derive(Debug, Eq, Serialize, Deserialize)]
#[serde(bound(deserialize = "P: for<'a> serde::Deserialize<'a>"))]
pub struct ExternalRouter<P: Prefix> {
name: String,
router_id: RouterId,
as_id: AsId,
pub(crate) neighbors: HashSet<RouterId>,
pub(crate) active_routes: P::Map<BgpRoute<P>>,
}
impl<P: Prefix> PartialEq for ExternalRouter<P> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.router_id == other.router_id
&& self.as_id == other.as_id
&& self.neighbors == other.neighbors
&& self.active_routes.eq(&other.active_routes)
}
}
impl<P: Prefix> Clone for ExternalRouter<P> {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
router_id: self.router_id,
as_id: self.as_id,
neighbors: self.neighbors.clone(),
active_routes: self.active_routes.clone(),
}
}
}
impl<P: Prefix> ExternalRouter<P> {
pub(crate) fn new(name: String, router_id: RouterId, as_id: AsId) -> Self {
Self {
name,
router_id,
as_id,
neighbors: HashSet::new(),
active_routes: Default::default(),
}
}
pub(crate) fn handle_event<T>(
&mut self,
_event: Event<P, T>,
) -> Result<EventOutcome<P, T>, DeviceError> {
Ok((StepUpdate::Unchanged, vec![]))
}
pub fn router_id(&self) -> RouterId {
self.router_id
}
pub fn as_id(&self) -> AsId {
self.as_id
}
pub fn name(&self) -> &str {
self.name.as_ref()
}
pub fn advertised_prefixes(&self) -> impl Iterator<Item = &P> {
self.active_routes.keys()
}
pub(crate) fn advertise_prefix<T: Default, I: IntoIterator<Item = u32>>(
&mut self,
prefix: P,
as_path: Vec<AsId>,
med: Option<u32>,
community: I,
) -> (BgpRoute<P>, Vec<Event<P, T>>) {
let route = BgpRoute::new(self.router_id, prefix, as_path, med, community);
let old_route = self.active_routes.insert(prefix, route.clone());
if old_route.as_ref() == Some(&route) {
(route, Vec::new())
} else {
let bgp_event = BgpEvent::Update(route.clone());
let events = self
.neighbors
.iter()
.map(|n| Event::bgp(T::default(), self.router_id, *n, bgp_event.clone()))
.collect();
(route, events)
}
}
pub(crate) fn withdraw_prefix<T: Default>(&mut self, prefix: P) -> Vec<Event<P, T>> {
if self.active_routes.remove(&prefix).is_some() {
self.neighbors
.iter()
.map(|n| Event::bgp(T::default(), self.router_id, *n, BgpEvent::Withdraw(prefix)))
.collect() } else {
Vec::new()
}
}
pub(crate) fn establish_ebgp_session<T: Default>(
&mut self,
router: RouterId,
) -> Result<Vec<Event<P, T>>, DeviceError> {
Ok(if self.neighbors.insert(router) {
self.active_routes
.iter()
.map(|(_, r)| {
Event::bgp(
T::default(),
self.router_id,
router,
BgpEvent::Update(r.clone()),
)
})
.collect()
} else {
Vec::new()
})
}
pub(crate) fn close_ebgp_session(&mut self, router: RouterId) -> Result<(), DeviceError> {
self.neighbors.remove(&router);
Ok(())
}
pub fn advertises_same_routes(&self, other: &Self) -> bool {
self.active_routes.iter().collect::<HashSet<_>>()
== other.active_routes.iter().collect::<HashSet<_>>()
}
pub fn has_active_route(&self, prefix: P) -> bool {
self.active_routes.contains_key(&prefix)
}
pub fn get_advertised_route(&self, prefix: P) -> Option<&BgpRoute<P>> {
self.active_routes.get(&prefix)
}
pub fn get_advertised_routes(&self) -> &P::Map<BgpRoute<P>> {
&self.active_routes
}
pub fn get_bgp_sessions(&self) -> &HashSet<RouterId> {
&self.neighbors
}
#[cfg(test)]
pub fn assert_equal(&self, other: &Self) {
assert_eq!(self.active_routes, other.active_routes);
assert_eq!(self.neighbors, other.neighbors);
}
pub(crate) fn set_name(&mut self, name: String) {
self.name = name;
}
pub(crate) fn set_as_id(&mut self, as_id: AsId) {
self.as_id = as_id;
}
}