use std::{fmt::Display, net::Ipv4Addr};
use ipnet::Ipv4Net;
use thiserror::Error;
use crate::{
config::ConfigModifier,
network::Network,
ospf::OspfImpl,
types::{NetworkError, NonOverlappingPrefix, Prefix, RouterId, ASN},
};
mod cisco_frr;
pub mod cisco_frr_generators;
mod default;
pub use cisco_frr::CiscoFrrCfgGen;
pub use default::DefaultAddressor;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LinkId(RouterId, RouterId);
impl LinkId {
pub fn new(a: RouterId, b: RouterId) -> Self {
if a.index() < b.index() {
Self(a, b)
} else {
Self(b, a)
}
}
}
impl From<(RouterId, RouterId)> for LinkId {
fn from(x: (RouterId, RouterId)) -> Self {
Self::new(x.0, x.1)
}
}
pub trait CfgGen<P: Prefix, Q, Ospf: OspfImpl, A> {
fn generate_config(
&mut self,
net: &Network<P, Q, Ospf>,
addressor: &mut A,
) -> Result<String, ExportError>;
fn generate_command(
&mut self,
net: &Network<P, Q, Ospf>,
addressor: &mut A,
cmd: ConfigModifier<P>,
) -> Result<String, ExportError>;
}
pub trait Addressor<P: Prefix> {
fn as_network(&mut self, asn: ASN) -> Result<Ipv4Net, ExportError>;
fn try_get_router_address(&self, router: RouterId) -> Option<Ipv4Addr> {
self.try_get_router(router).map(|r| r.1)
}
fn router_address(&mut self, router: RouterId) -> Result<Ipv4Addr, ExportError> {
Ok(self.router(router)?.1)
}
fn try_get_router_address_full(
&self,
router: RouterId,
) -> Option<Result<Ipv4Net, ExportError>> {
self.try_get_router(router)
.map(|(net, ip)| Ok(Ipv4Net::new(ip, net.prefix_len())?))
}
fn router_address_full(&mut self, router: RouterId) -> Result<Ipv4Net, ExportError> {
let (net, ip) = self.router(router)?;
Ok(Ipv4Net::new(ip, net.prefix_len())?)
}
fn try_get_router_network(&self, router: RouterId) -> Option<Ipv4Net> {
self.try_get_router(router).map(|r| r.0)
}
fn router_network(&mut self, router: RouterId) -> Result<Ipv4Net, ExportError> {
Ok(self.router(router)?.0)
}
fn try_get_router(&self, router: RouterId) -> Option<(Ipv4Net, Ipv4Addr)>;
fn router(&mut self, router: RouterId) -> Result<(Ipv4Net, Ipv4Addr), ExportError>;
fn register_pec(&mut self, pec: P, prefixes: Vec<Ipv4Net>)
where
P: NonOverlappingPrefix;
fn get_pecs(&self) -> &P::Map<Vec<Ipv4Net>>;
fn prefix(&mut self, prefix: P) -> Result<MaybePec<Ipv4Net>, ExportError>;
fn prefix_address(&mut self, prefix: P) -> Result<MaybePec<Ipv4Net>, ExportError> {
fn get_net(net: Ipv4Net) -> Result<Ipv4Net, ExportError> {
Ok(Ipv4Net::new(
net.hosts().next().ok_or(ExportError::NotEnoughAddresses)?,
net.prefix_len(),
)
.unwrap())
}
Ok(match self.prefix(prefix)? {
MaybePec::Single(net) => MaybePec::Single(get_net(net)?),
MaybePec::Pec(p, nets) => MaybePec::Pec(
p,
nets.into_iter()
.map(get_net)
.collect::<Result<_, ExportError>>()?,
),
})
}
fn try_get_iface_address(
&self,
router: RouterId,
neighbor: RouterId,
) -> Option<Result<Ipv4Addr, ExportError>> {
self.try_get_iface(router, neighbor)
.map(|r| r.map(|iface| iface.0))
}
fn iface_address(
&mut self,
router: RouterId,
neighbor: RouterId,
) -> Result<Ipv4Addr, ExportError> {
Ok(self.iface(router, neighbor)?.0)
}
fn try_get_iface_address_full(
&self,
router: RouterId,
neighbor: RouterId,
) -> Option<Result<Ipv4Net, ExportError>> {
self.try_get_iface(router, neighbor)
.map(|r| r.and_then(|(ip, net, _)| Ok(Ipv4Net::new(ip, net.prefix_len())?)))
}
fn iface_address_full(
&mut self,
router: RouterId,
neighbor: RouterId,
) -> Result<Ipv4Net, ExportError> {
let (ip, net, _) = self.iface(router, neighbor)?;
Ok(Ipv4Net::new(ip, net.prefix_len())?)
}
fn try_get_iface_index(
&self,
router: RouterId,
neighbor: RouterId,
) -> Option<Result<usize, ExportError>> {
self.try_get_iface(router, neighbor)
.map(|r| r.map(|iface| iface.2))
}
fn iface_index(&mut self, router: RouterId, neighbor: RouterId) -> Result<usize, ExportError> {
Ok(self.iface(router, neighbor)?.2)
}
fn try_get_iface_network(
&self,
a: RouterId,
b: RouterId,
) -> Option<Result<Ipv4Net, ExportError>> {
self.try_get_iface(a, b).map(|r| r.map(|iface| iface.1))
}
fn iface_network(&mut self, a: RouterId, b: RouterId) -> Result<Ipv4Net, ExportError> {
Ok(self.iface(a, b)?.1)
}
fn try_get_iface(
&self,
router: RouterId,
neighbor: RouterId,
) -> Option<Result<(Ipv4Addr, Ipv4Net, usize), ExportError>>;
fn iface(
&mut self,
router: RouterId,
neighbor: RouterId,
) -> Result<(Ipv4Addr, Ipv4Net, usize), ExportError>;
fn list_ifaces(&self, router: RouterId) -> Vec<(RouterId, Ipv4Addr, Ipv4Net, usize)>;
fn list_links(&self) -> Vec<((RouterId, usize), (RouterId, usize))>;
fn find_address(&self, address: impl Into<Ipv4Net>) -> Result<RouterId, ExportError>;
fn find_next_hop(
&self,
router: RouterId,
address: impl Into<Ipv4Net>,
) -> Result<RouterId, ExportError>;
fn find_neighbor(&self, router: RouterId, iface_idx: usize) -> Result<RouterId, ExportError>;
}
#[derive(Debug, Error)]
pub enum ExportError {
#[error("Invalid Netmask: {0}")]
InvalidNetmask(#[from] ipnet::PrefixLenError),
#[error("IP address could not be assigned! ran out of addresses.")]
NotEnoughAddresses,
#[error("Router {0:?} has not enough interfaces!")]
NotEnoughInterfaces(RouterId),
#[error("Router {0:?} has not enough loopback interfaces!")]
NotEnoughLoopbacks(RouterId),
#[error("Cannot create config for internal router {0:?}. Reason: {1}")]
InternalCfgGenError(RouterId, String),
#[error("Cannot create config for external router {0:?}. Reason: {1}")]
ExternalCfgGenError(RouterId, String),
#[error("Router {0:?} and {1:?} are not connected!")]
RouterNotConnectedTo(RouterId, RouterId),
#[error("No router with ID {0:?} does exist.")]
InvalidRouterId(RouterId),
#[error("Cannot withdraw a route that is not yet advertised!")]
WithdrawUnadvertisedRoute,
#[error("Config modifier does not cause any change in the given router.")]
ModifierDoesNotAffectRouter,
#[error("IP Address {0} could not be associated with any router!")]
AddressNotFound(Ipv4Net),
#[error("Interface {1} of router {0:?} does not exist!")]
InterfaceNotFound(RouterId, String),
#[error("The two routers {0:?} and {1:?} are not connected via an interface!")]
RoutersNotConnected(RouterId, RouterId),
#[error("The network {0} or the prefix lies within a reserved IP range.")]
PrefixWithinReservedIpRange(Ipv4Net),
#[error("Did not expect a prefix equivalence class of {0}!")]
UnexpectedPec(Ipv4Net),
#[error("{0}")]
NotSupported(&'static str),
}
impl From<NetworkError> for ExportError {
fn from(value: NetworkError) -> Self {
match value {
NetworkError::DeviceNotFound(r) => Self::InvalidRouterId(r),
e => panic!("Unexpected network error when generating configuration! {e}"),
}
}
}
fn ip_err<T>(option: Option<T>) -> Result<T, ExportError> {
option.ok_or(ExportError::NotEnoughAddresses)
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MaybePec<T> {
Single(T),
Pec(Ipv4Net, Vec<T>),
}
impl<T> MaybePec<T> {
pub fn first(&self) -> &T {
match self {
MaybePec::Single(v) => v,
MaybePec::Pec(_, vs) => vs.first().unwrap(),
}
}
pub fn to_vec(self) -> Vec<T> {
match self {
MaybePec::Single(v) => vec![v],
MaybePec::Pec(_, v) => v,
}
}
#[track_caller]
pub fn unwrap_single(self) -> T {
match self {
MaybePec::Single(x) => x,
MaybePec::Pec(p, _) => {
panic!("called `MaybePec::unwrap_single()` on a `MaybePec::Pec({p})` value.")
}
}
}
pub fn single(self) -> Option<T> {
match self {
MaybePec::Single(t) => Some(t),
MaybePec::Pec(_, _) => None,
}
}
pub fn single_or(self) -> Result<T, ExportError> {
match self {
MaybePec::Single(t) => Ok(t),
MaybePec::Pec(p, _) => Err(ExportError::UnexpectedPec(p)),
}
}
pub fn single_or_err<E>(self, err: E) -> Result<T, E> {
match self {
MaybePec::Single(t) => Ok(t),
MaybePec::Pec(_, _) => Err(err),
}
}
pub fn single_or_else<E, F: FnOnce(Vec<T>) -> E>(self, err: F) -> Result<T, E> {
match self {
MaybePec::Single(t) => Ok(t),
MaybePec::Pec(_, v) => Err(err(v)),
}
}
pub fn map<R, F: FnMut(T) -> R>(self, mut f: F) -> MaybePec<R> {
match self {
MaybePec::Single(v) => MaybePec::Single(f(v)),
MaybePec::Pec(p, vs) => MaybePec::Pec(p, vs.into_iter().map(f).collect()),
}
}
pub fn iter(&self) -> MaybePecIter<'_, T> {
self.into_iter()
}
#[cfg(feature = "rand")]
pub fn sample_random_n<R: rand::Rng>(&self, rng: &mut R, n: usize) -> Vec<&T>
where
T: Ord,
{
use rand::prelude::IteratorRandom;
match self {
MaybePec::Single(v) => vec![v],
MaybePec::Pec(_, vs) if vs.len() <= n => vs.iter().collect(),
MaybePec::Pec(_, vs) => {
let mut vs: Vec<&T> = vs.iter().collect();
vs.sort();
let mut samples = vs[1..(vs.len() - 1)]
.iter()
.copied()
.choose_multiple(rng, n - 2);
samples.insert(0, vs[0]);
samples.push(vs.pop().unwrap());
samples
}
}
}
pub fn sample_uniform_n(&self, n: usize) -> Vec<&T>
where
T: Ord,
{
match self {
MaybePec::Single(v) => vec![v],
MaybePec::Pec(_, vs) if vs.len() <= n => vs.iter().collect(),
MaybePec::Pec(_, vs) => {
assert!(n >= 2);
let mut vs: Vec<&T> = vs.iter().collect();
vs.sort();
if n > 2 {
let n_steps = n - 1;
let step_size = vs.len() / n_steps;
let last = vs.pop();
vs.into_iter()
.step_by(step_size)
.take(n_steps)
.chain(last)
.collect()
} else {
vec![vs.first().unwrap(), vs.last().unwrap()]
}
}
}
}
}
impl<T> IntoIterator for MaybePec<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.to_vec().into_iter()
}
}
impl<T: Display> Display for MaybePec<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MaybePec::Single(x) => x.fmt(f),
MaybePec::Pec(p, v) => write!(f, "{} ({} prefixes)", p, v.len()),
}
}
}
#[derive(Debug, Clone)]
pub struct MaybePecIter<'a, T> {
x: &'a MaybePec<T>,
idx: usize,
}
impl<'a, T> Iterator for MaybePecIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self.x {
MaybePec::Single(x) if self.idx == 0 => {
self.idx = 1;
Some(x)
}
MaybePec::Single(_) => None,
MaybePec::Pec(_, xs) => {
let elem = xs.get(self.idx);
self.idx += 1;
elem
}
}
}
}
impl<'a, T> IntoIterator for &'a MaybePec<T> {
type Item = &'a T;
type IntoIter = MaybePecIter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
MaybePecIter { x: self, idx: 0 }
}
}