diff --git a/src/bgp/message/nlri.rs b/src/bgp/message/nlri.rs index b0d45a96..8daf555f 100644 --- a/src/bgp/message/nlri.rs +++ b/src/bgp/message/nlri.rs @@ -1,3 +1,4 @@ +use crate::bgp::nlri::afisafi::{AfiSafiNlri, Ipv6UnicastNlri}; use crate::bgp::types::{Afi, AfiSafi, NextHop}; use crate::addr::Prefix; @@ -6,7 +7,7 @@ use crate::util::parser::{parse_ipv4addr, parse_ipv6addr, ParseError}; use crate::bgp::message::update::SessionConfig; use crate::flowspec::Component; use crate::typeenum; -use octseq::{Octets, OctetsBuilder, OctetsFrom, Parser}; +use octseq::{Octets, OctetsBuilder, OctetsFrom, OctetsInto, Parser}; use log::debug; use std::fmt; @@ -16,6 +17,8 @@ use std::str::FromStr; #[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; +use crate::bgp::nlri::afisafi::AfiSafi as AfiSafiTrait; +use crate::bgp::nlri::afisafi::IsPrefix; //------------ FixedNlriIter ------------------------------------------------- // diff --git a/src/bgp/message/update.rs b/src/bgp/message/update.rs index 264d7c8e..cfe8f501 100644 --- a/src/bgp/message/update.rs +++ b/src/bgp/message/update.rs @@ -186,18 +186,13 @@ impl UpdateMessage { /// unicast NLRI, they might include ADD-PATH Path IDs or not. /// Once we switch over to the new AfiSafiType enum, we can signal PathId /// presence/absence. - pub fn afi_safis(&self) -> ( - Option, - Option, - Option, - Option, - ) { - ( + pub fn afi_safis(&self) -> [Option; 4] { + [ (!self.withdrawals.is_empty()).then_some(AfiSafi::Ipv4Unicast), (!self.announcements.is_empty()).then_some(AfiSafi::Ipv4Unicast), self.mp_withdrawals().ok().flatten().map(|a| a.afi_safi()), self.mp_announcements().ok().flatten().map(|a| a.afi_safi()), - ) + ] } /// Returns the conventional withdrawals. diff --git a/src/bgp/nlri/afisafi.rs b/src/bgp/nlri/afisafi.rs index a5531cd1..492705f5 100644 --- a/src/bgp/nlri/afisafi.rs +++ b/src/bgp/nlri/afisafi.rs @@ -1,3 +1,4 @@ +use crate::bgp::message::nlri::BasicNlri; use crate::typeenum; // from util::macros #[cfg(feature = "serde")] @@ -368,6 +369,15 @@ impl fmt::Display for Ipv4UnicastNlri { } } +impl From for BasicNlri { + fn from(value: Ipv4UnicastNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + path_id: None + } + } +} + //--- Ipv4Multicast #[derive(Clone, Debug, Hash, PartialEq)] @@ -399,6 +409,15 @@ impl fmt::Display for Ipv4MulticastNlri { } } +impl From for BasicNlri { + fn from(value: Ipv4MulticastNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + path_id: None + } + } +} + //--- Ipv4MplsUnicast #[derive(Clone, Debug, Hash)] @@ -444,6 +463,7 @@ impl fmt::Display for Ipv4MplsUnicastNlri { } } + //--- Ipv4MplsVpnUnicastNlri #[derive(Clone, Debug, Hash)] @@ -578,6 +598,17 @@ impl fmt::Display for Ipv6UnicastNlri { } } + +impl From for BasicNlri { + fn from(value: Ipv6UnicastNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + path_id: None + } + } +} + + //--- Ipv6Multicast #[derive(Clone, Debug, Hash, PartialEq)] @@ -610,6 +641,16 @@ impl fmt::Display for Ipv6MulticastNlri { } +impl From for BasicNlri { + fn from(value: Ipv6MulticastNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + path_id: None + } + } +} + + //--- Ipv6MplsUnicast #[derive(Clone, Debug, Hash)] @@ -724,6 +765,13 @@ impl fmt::Display for Ipv6FlowSpecNlri { } } +impl From> for FlowSpecNlri { + fn from(value: Ipv6FlowSpecNlri) -> Self { + value.0 + } +} + +//--- Addpath stuff impl Ipv6UnicastAddpathNlri { pub fn iter<'a, O, P>(parser: Parser<'a, P>) -> NlriIter<'a, O, P, Self> @@ -735,6 +783,61 @@ impl Ipv6UnicastAddpathNlri { } } + +impl From for BasicNlri { + fn from(value: Ipv6UnicastAddpathNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + // This can't be right. + path_id: Some(crate::bgp::message::nlri::PathId::from_u32(value.path_id().0)) + } + } +} + +impl From for BasicNlri { + fn from(value: Ipv6MulticastAddpathNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + // This can't be right. + path_id: Some(crate::bgp::message::nlri::PathId::from_u32(value.path_id().0)) + } + } +} + +impl From for BasicNlri { + fn from(value: Ipv4UnicastAddpathNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + path_id: Some(crate::bgp::message::nlri::PathId::from_u32(value.path_id().0)) + } + } +} + +impl From for BasicNlri { + fn from(value: Ipv4MulticastAddpathNlri) -> Self { + BasicNlri { + prefix: value.prefix(), + path_id: Some(crate::bgp::message::nlri::PathId::from_u32(value.path_id().0)) + } + } +} + +// TODO: What do we do with the actual PathId, unlike BasicNlri we don't have +// a slot for it. O well, throwing it away for now. +impl From> for FlowSpecNlri { + fn from(value: Ipv4FlowSpecAddpathNlri) -> Self { + value.1.into() + } +} + +impl From> for FlowSpecNlri { + fn from(value: Ipv6FlowSpecAddpathNlri) -> Self { + value.1.into() + } +} + +//------------ Other Nlri types ---------------------------------------------- + impl Ipv4MplsUnicastNlri { pub fn iter<'a, P>(parser: Parser<'a, P>) -> NlriIter<'a, Octs, P, Self> where @@ -745,6 +848,13 @@ impl Ipv4MplsUnicastNlri { } } +impl From> for FlowSpecNlri { + fn from(value: Ipv4FlowSpecNlri) -> Self { + value.0 + } +} + + //------------ L2Vpn ---------------------------------------------------------- //--- L2VpnVpls @@ -856,16 +966,6 @@ where output: std::marker::PhantomData } } - - pub fn map_into_vec>::Output) -> T>(parser: Parser<'a, P>, fmap: F) -> Vec { - NlriIter { - parser, - asp: std::marker::PhantomData::, - output: std::marker::PhantomData:: - } - .map(fmap) - .collect::>() - } } diff --git a/src/bgp/nlri/mod.rs b/src/bgp/nlri/mod.rs index 1671592c..55655f04 100644 --- a/src/bgp/nlri/mod.rs +++ b/src/bgp/nlri/mod.rs @@ -2,7 +2,7 @@ pub mod afisafi; mod common; mod evpn; -mod flowspec; +pub mod flowspec; mod mpls; mod mpls_vpn; mod routetarget; diff --git a/src/bgp/workshop/afisafi_nlri.rs b/src/bgp/workshop/afisafi_nlri.rs index 89721a0c..a0bf1a5e 100644 --- a/src/bgp/workshop/afisafi_nlri.rs +++ b/src/bgp/workshop/afisafi_nlri.rs @@ -26,7 +26,7 @@ pub trait AfiSafiNlri: Clone + Hash + Debug { pub trait HasBasicNlri { fn basic_nlri(&self) -> BasicNlri; fn make_route_with_nlri(nlri: M, pa: &PaMap) - -> RouteWorkshop where M: AfiSafiNlri; + -> RouteWorkshop where M: AfiSafiNlri; } @@ -53,8 +53,8 @@ impl HasBasicNlri for Ipv4UnicastNlri { } fn make_route_with_nlri(nlri: M, pa: &PaMap) - -> RouteWorkshop where M: AfiSafiNlri { - RouteWorkshop::::from_pa_map(nlri, pa.clone()) + -> RouteWorkshop where M: AfiSafiNlri { + RouteWorkshop::::from_pa_map(nlri, pa.clone()) } } @@ -108,8 +108,8 @@ impl HasBasicNlri for Ipv6UnicastNlri { } fn make_route_with_nlri(nlri: M, pa: &PaMap) - -> RouteWorkshop where M: AfiSafiNlri { - RouteWorkshop::::from_pa_map(nlri, pa.clone()) + -> RouteWorkshop where M: AfiSafiNlri { + RouteWorkshop::::from_pa_map(nlri, pa.clone()) } } @@ -155,8 +155,8 @@ impl HasBasicNlri for Ipv4MulticastNlri { } fn make_route_with_nlri(nlri: M, pa: &PaMap) - -> RouteWorkshop where M: AfiSafiNlri { - RouteWorkshop::::from_pa_map(nlri, pa.clone()) + -> RouteWorkshop where M: AfiSafiNlri { + RouteWorkshop::::from_pa_map(nlri, pa.clone()) } } diff --git a/src/bgp/workshop/route.rs b/src/bgp/workshop/route.rs index 266feb45..51ccc2b4 100644 --- a/src/bgp/workshop/route.rs +++ b/src/bgp/workshop/route.rs @@ -1,23 +1,27 @@ use std::fmt::Debug; use std::hash::Hash; -use std::marker::PhantomData; -use octseq::{Octets, OctetsFrom}; +use octseq::{Octets, OctetsFrom, Parser}; use serde::Serialize; use crate::bgp::communities::Community; +use crate::bgp::message::nlri::BasicNlri; +use crate::bgp::message::update::AfiSafi; use crate::bgp::message::update_builder::{ComposeError, MpReachNlriBuilder}; use crate::bgp::message::UpdateMessage; +use crate::bgp::nlri::afisafi::{iter_for_afi_safi, AfiSafiNlri, + AfiSafiParse, Ipv4MulticastNlri, Ipv4UnicastNlri, Ipv6UnicastNlri, + Ipv4MulticastAddpathNlri, Ipv4UnicastAddpathNlri, Ipv6UnicastAddpathNlri, + Ipv6MulticastNlri, Ipv6MulticastAddpathNlri}; use crate::bgp::path_attributes::{FromAttribute, PaMap}; use crate::bgp::{ message::{nlri::Nlri, update_builder::StandardCommunitiesList}, path_attributes::{ ExtendedCommunitiesList, Ipv6ExtendedCommunitiesList, - LargeCommunitiesList, PathAttribute, + LargeCommunitiesList, PathAttribute, }, }; - //------------ TypedRoute ---------------------------------------------------- #[derive(Debug)] @@ -26,7 +30,6 @@ pub enum TypedRoute { Withdraw(Nlri), } - //------------ Route --------------------------------------------------------- #[derive(Debug, Eq, PartialEq, Clone, Hash, Serialize)] @@ -58,7 +61,6 @@ impl Route { } } - //------------ From impls for PathAttribute ---------------------------------- impl From> for PathAttribute { @@ -73,30 +75,28 @@ impl From>> for PathAttribute { } } - //------------ The Workshop -------------------------------------------------- #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize)] -pub struct RouteWorkshop(N, PaMap, PhantomData); +pub struct RouteWorkshop(N, PaMap); -impl RouteWorkshop { +impl RouteWorkshop { pub fn new(nlri: N) -> Self { - Self(nlri, PaMap::empty(), PhantomData) + Self(nlri, PaMap::empty()) } pub fn from_pa_map(nlri: N, pa_map: PaMap) -> Self { - Self(nlri, pa_map, PhantomData) + Self(nlri, pa_map) } - - pub fn from_update_pdu( + + pub fn from_update_pdu( nlri: N, pdu: &UpdateMessage, ) -> Result where for<'a> Vec: OctetsFrom>, { - PaMap::from_update_pdu(pdu) - .map(|r| Self(nlri, r, PhantomData)) + PaMap::from_update_pdu(pdu).map(|r| Self(nlri, r)) } pub fn nlri(&self) -> &N { @@ -189,19 +189,19 @@ impl WorkshopAttribute for Vec { &mut attrs .get::() .map(|c| c.fmap(Community::Extended)) - .unwrap_or_default() + .unwrap_or_default(), ); c.append( &mut attrs .get::() .map(|c| c.fmap(Community::Ipv6Extended)) - .unwrap_or_default() + .unwrap_or_default(), ); c.append( &mut attrs .get::() .map(|c| c.fmap(Community::Large)) - .unwrap_or_default() + .unwrap_or_default(), ); Some(c) @@ -242,17 +242,22 @@ impl WorkshopAttribute for Vec { } } -impl FromAttribute for Vec { } +impl FromAttribute for Vec {} //------------ NlriWorkshop -------------------------------------------------- -impl FromAttribute for crate::bgp::message::nlri::Nlri> { } +impl FromAttribute for crate::bgp::message::nlri::Nlri> {} -impl WorkshopAttribute for crate::bgp::message::nlri::Nlri> { +impl WorkshopAttribute + for crate::bgp::message::nlri::Nlri> +{ fn retrieve(attrs: &PaMap) -> Option where - Self: Sized { - attrs.get::().and_then(|mr| mr.first_nlri()) + Self: Sized, + { + attrs + .get::() + .and_then(|mr| mr.first_nlri()) } fn store( @@ -269,7 +274,7 @@ impl WorkshopAttribute for crate::bgp::message::nlri::Nlri WorkshopAttribute for crate::bgp::types::NextHop { fn retrieve(attrs: &PaMap) -> Option { @@ -297,3 +302,229 @@ impl WorkshopAttribute for crate::bgp::types::NextHop { } } } + + +//------------ The Explosion ------------------------------------------------- + +pub fn into_wrapped_rws_vec< + 'a, + O: Octets, + P: 'a + Octets = O>, + AF: AfiSafiNlri + AfiSafiParse<'a, O, P, Output = AF>, + AFT: Clone + Debug + Hash + From, + T: From>, +>( + parser: Parser<'a, P>, + pa_map: &'a PaMap, +) -> Vec { + iter_for_afi_safi::<'_, _, _, AF>(parser) + .map(|n: AF::Output| { + RouteWorkshop::from_pa_map(AFT::from(n), pa_map.clone()).into() + }) + .collect::>() +} + +fn into_wrapped_rws_iter< + 'a, + O: Octets + 'a, + P: 'a + Octets = O>, + AF: AfiSafiNlri + AfiSafiParse<'a, O, P, Output = AF> + 'a, + AFT: Clone + Debug + Hash + From, + T: From>, +>( + parser: Parser<'a, P>, + pa_map: &'a PaMap, +) -> impl Iterator + 'a { + iter_for_afi_safi::<'_, _, _, AF>(parser) + .map(|n: AF::Output| { + T::from(RouteWorkshop::from_pa_map(AFT::from(n), pa_map.clone())) + }) +} + +pub fn exploded_iter< + 'a, + O: Octets + Clone + Debug + Hash + 'a, + P: 'a + Octets = O>, + T: From> + + From>> + 'a, +>( + parser: Parser<'a, P>, + pa_map: &'a PaMap, +) -> impl Iterator + 'a { + into_wrapped_rws_iter::<'_, _, _, Ipv4UnicastNlri, BasicNlri, T>( + parser, pa_map + ) + .chain( + into_wrapped_rws_vec::<'_, _, _, Ipv6UnicastNlri, BasicNlri, T>( + parser, pa_map + ) + ) + .chain( + into_wrapped_rws_vec::<'_, _, _, Ipv4MulticastNlri, BasicNlri, T>( + parser, pa_map + ) + ) + .chain( + into_wrapped_rws_vec::<'_, _, _, Ipv6MulticastNlri, BasicNlri, T>( + parser, pa_map + ) + ).chain( + into_wrapped_rws_vec::<'_, _, _, + crate::bgp::nlri::afisafi::Ipv4FlowSpecNlri, + crate::bgp::nlri::flowspec::FlowSpecNlri, T>( + parser, pa_map + ) + ).chain( + into_wrapped_rws_vec::<'_, _, _, + crate::bgp::nlri::afisafi::Ipv6FlowSpecNlri, + crate::bgp::nlri::flowspec::FlowSpecNlri, T>( + parser, pa_map + ) + ) +} + +pub fn exploded_add_path_iter< + 'a, + O: Octets + Clone + Debug + Hash + 'a, + P: 'a + Octets = O>, + T: From> + + From>> + 'a, +>( + parser: Parser<'a, P>, + pa_map: &'a PaMap, +) -> impl Iterator + 'a { + into_wrapped_rws_iter::<'_, _, _, Ipv4UnicastAddpathNlri, BasicNlri, T>( + parser, pa_map + ) + .chain( + into_wrapped_rws_vec::<'_, _, _, Ipv6UnicastAddpathNlri, BasicNlri, T>( + parser, pa_map + ) + ) + .chain( + into_wrapped_rws_vec::<'_, _, _, Ipv4MulticastAddpathNlri, BasicNlri, T>( + parser, pa_map + ) + ) + .chain( + into_wrapped_rws_vec::<'_, _, _, Ipv6MulticastAddpathNlri, BasicNlri, T>( + parser, pa_map + ) + ).chain( + into_wrapped_rws_vec::<'_, _, _, + crate::bgp::nlri::afisafi::Ipv4FlowSpecAddpathNlri, + crate::bgp::nlri::flowspec::FlowSpecNlri, T>( + parser, pa_map + ) + ).chain( + into_wrapped_rws_vec::<'_, _, _, + crate::bgp::nlri::afisafi::Ipv6FlowSpecAddpathNlri, + crate::bgp::nlri::flowspec::FlowSpecNlri, T>( + parser, pa_map + ) + ) +} + +pub fn explode_for_afi_safis< + 'a, + O: Octets + Clone + Debug + Hash + 'a, + P: 'a + Octets = O>, + T: From> + + From>>, +>( + afi_safis: impl Iterator, + add_path_cap: bool, + parser: Parser<'a, P>, + pa_map: &'a PaMap, +) -> Vec { + + let mut res = vec![]; + + for afi_safi in afi_safis { + match (afi_safi, add_path_cap) { + (AfiSafi::Ipv4Unicast, false) => { + res.extend( + into_wrapped_rws_iter::<'_, _, _, Ipv4UnicastNlri, BasicNlri, T>( + parser, pa_map + ).collect::>() + ); + } + (AfiSafi::Ipv4Unicast, true) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, Ipv4UnicastAddpathNlri, BasicNlri, T>(parser, pa_map) + ); + } + (AfiSafi::Ipv6Unicast, false) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, Ipv6UnicastNlri, BasicNlri, T>(parser, pa_map) + ); + }, + (AfiSafi::Ipv6Unicast, true) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, Ipv6UnicastAddpathNlri, BasicNlri, T>(parser, pa_map) + ); + }, + (AfiSafi::Ipv4Multicast, false) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, Ipv4MulticastNlri, BasicNlri, T>(parser, pa_map) + ); + }, + (AfiSafi::Ipv4Multicast, true) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, Ipv4MulticastAddpathNlri, BasicNlri, T>(parser, pa_map) + ); + }, + (AfiSafi::Ipv6Multicast, false) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, + Ipv6MulticastNlri, BasicNlri, T>( + parser, pa_map + ) + ); + }, + (AfiSafi::Ipv6Multicast, true) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, + Ipv6MulticastAddpathNlri, BasicNlri, T>( + parser, pa_map + ) + ); + }, + (AfiSafi::Ipv4MplsUnicast, true) => todo!(), + (AfiSafi::Ipv4MplsUnicast, false) => todo!(), + (AfiSafi::Ipv6MplsUnicast, true) => todo!(), + (AfiSafi::Ipv6MplsUnicast, false) => todo!(), + (AfiSafi::Ipv4MplsVpnUnicast, true) => todo!(), + (AfiSafi::Ipv4MplsVpnUnicast, false) => todo!(), + (AfiSafi::Ipv6MplsVpnUnicast, true) => todo!(), + (AfiSafi::Ipv6MplsVpnUnicast, false) => todo!(), + (AfiSafi::Ipv4RouteTarget, true) => todo!(), + (AfiSafi::Ipv4RouteTarget, false) => todo!(), + (AfiSafi::Ipv4FlowSpec, true) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, + crate::bgp::nlri::afisafi::Ipv4FlowSpecNlri, + crate::bgp::nlri::flowspec::FlowSpecNlri, T>( + parser, pa_map + ) + ); + }, + (AfiSafi::Ipv4FlowSpec, false) => todo!(), + (AfiSafi::Ipv6FlowSpec, true) => { + res.extend( + into_wrapped_rws_vec::<'_, _, _, + crate::bgp::nlri::afisafi::Ipv6FlowSpecNlri, + crate::bgp::nlri::flowspec::FlowSpecNlri, T>( + parser, pa_map + ) + ); + }, + (AfiSafi::Ipv6FlowSpec, false) => todo!(), + (AfiSafi::L2VpnVpls, true) => todo!(), + (AfiSafi::L2VpnVpls, false) => todo!(), + (AfiSafi::L2VpnEvpn, true) => todo!(), + (AfiSafi::L2VpnEvpn, false) => todo!(), + }; + } + res +}