From 62a140ee1723cec85a7b19725d54e078cdd00493 Mon Sep 17 00:00:00 2001 From: Vladimir Melnikov Date: Sat, 8 Oct 2022 19:48:11 +0300 Subject: [PATCH] serde deserializaion support mdt safi (multicast distribution tree) added Multiple addpath capabilities fixed clippy fixes --- CHANGELOG.md | 16 +- Cargo.toml | 4 +- README.md | 3 + src/afi/evpn.rs | 107 +--- src/afi/flowspec.rs | 227 +++++++- src/afi/ipv4.rs | 45 +- src/afi/ipv6.rs | 51 +- src/afi/mac.rs | 57 +- src/afi/mdt.rs | 217 +++++++ src/afi/mod.rs | 660 +++++++++++++++++----- src/afi/mvpn.rs | 33 +- src/afi/vpls.rs | 35 +- src/bmp/bmputl.rs | 25 +- src/bmp/mod.rs | 74 +-- src/bmp/msginit.rs | 55 +- src/bmp/msgpeer.rs | 58 +- src/bmp/msgrmon.rs | 38 +- src/bmp/msgterm.rs | 34 +- src/bmp/prelude.rs | 2 +- src/error.rs | 20 +- src/lib.rs | 205 ++++--- src/message/attributes/aggregatoras.rs | 50 +- src/message/attributes/aspath.rs | 92 ++- src/message/attributes/atomicaggregate.rs | 26 +- src/message/attributes/attrset.rs | 41 +- src/message/attributes/clusterlist.rs | 18 +- src/message/attributes/community.rs | 145 ++--- src/message/attributes/connector.rs | 80 +++ src/message/attributes/extcommunity.rs | 34 +- src/message/attributes/localpref.rs | 29 +- src/message/attributes/med.rs | 17 +- src/message/attributes/mod.rs | 66 +-- src/message/attributes/multiproto.rs | 23 +- src/message/attributes/nexthop.rs | 37 +- src/message/attributes/origin.rs | 57 +- src/message/attributes/originatorid.rs | 15 +- src/message/attributes/pmsitunnelattr.rs | 90 ++- src/message/attributes/unknown.rs | 48 +- src/message/keepalive.rs | 12 +- src/message/mod.rs | 23 +- src/message/notification.rs | 32 +- src/message/open.rs | 10 +- src/message/update/mod.rs | 77 +-- src/prelude.rs | 9 +- src/util.rs | 7 +- 45 files changed, 1844 insertions(+), 1160 deletions(-) create mode 100644 src/afi/mdt.rs create mode 100644 src/message/attributes/connector.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 4338dd9..a0f43cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,19 @@ -### 0.2.1 (2021-08-01) +### 0.3.0 (2022-10-08) + +#### Features + +* serde deserializaion support +* mdt safi (multicast distribution tree) added #### Fixes -* Multiple addpath capabilities fixed +* clippy fixes + +### 0.2.1 (2021-08-01) + +#### Features + +* multiple AddPath capabilities support ### 0.2.0 (2021-07-25) @@ -12,7 +23,6 @@ * afi::BgpNet support for MAC prefixes * extcommunity varieties extended - ### 0.1.5 (2021-07-19) #### Features diff --git a/Cargo.toml b/Cargo.toml index cb9210e..716f3e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zettabgp" -version = "0.2.1" +version = "0.3.0" authors = ["Vladimir Melnikov "] edition = "2018" license = "MIT OR Apache-2.0" @@ -17,5 +17,5 @@ serialization = ["serde"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = { version="1.0.125", optional = true } +serde = { version="1.0.125", features = ["derive"], optional = true } diff --git a/README.md b/README.md index 5bd0916..49f1ed7 100644 --- a/README.md +++ b/README.md @@ -23,11 +23,13 @@ BMP - BGP Monitoring Protocol version 3. * ipv4 labeled-unicast * ipv4 multicast * ipv4 mvpn + * ipv4 mdt * vpnv4 unicast * vpnv4 multicast * ipv6 unicast * ipv6 labeled-unicast * ipv6 multicast + * ipv6 mdt * vpnv6 unicast * vpnv6 multicast * vpls @@ -47,6 +49,7 @@ BMP - BGP Monitoring Protocol version 3. * Cluster list * Originator ID * Attribute set + * Connector * some PMSI tunnels ## Usage diff --git a/src/afi/evpn.rs b/src/afi/evpn.rs index 3743111..45fc5f9 100644 --- a/src/afi/evpn.rs +++ b/src/afi/evpn.rs @@ -9,9 +9,14 @@ //! This module describes NLRI data structures for evpn https://tools.ietf.org/html/rfc7432 use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; -//EVPN ESI field +///EVPN ESI field #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct EVPNESI { pub v: Vec, } @@ -23,7 +28,7 @@ impl EVPNESI { EVPNESI { v: src.to_vec() } } pub fn is_zero(&self) -> bool { - self.v.iter().find(|x| (**x) != 0).is_none() + !self.v.iter().any(|x| (*x) != 0) } } impl std::fmt::Display for EVPNESI { @@ -40,6 +45,8 @@ impl std::fmt::Display for EVPNESI { } //EVPN Ethernet Auto-Discovery (A-D) route #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpEVPN1 { pub rd: BgpRD, pub esi_type: u8, @@ -84,6 +91,8 @@ impl std::fmt::Display for BgpEVPN1 { //EVPN MAC/IP Advertisement Route #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpEVPN2 { pub rd: BgpRD, pub esi_type: u8, @@ -201,6 +210,8 @@ impl std::fmt::Display for BgpEVPN2 { #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] // EVPN Inclusive Multicast Ethernet Tag route +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpEVPN3 { pub rd: BgpRD, pub ether_tag: u32, @@ -246,8 +257,10 @@ impl std::fmt::Display for BgpEVPN3 { } } +/// EVPN Ethernet Segment Route #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -// EVPN Ethernet Segment Route +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpEVPN4 { pub rd: BgpRD, pub esi_type: u8, @@ -300,6 +313,8 @@ impl std::fmt::Display for BgpEVPN4 { /// EVPN route NLRI #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub enum BgpEVPN { EVPN1(BgpEVPN1), EVPN2(BgpEVPN2), @@ -354,89 +369,3 @@ impl BgpAddrItem for BgpEVPN { unimplemented!(); } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for EVPNESI { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_seq(Some(self.v.len()))?; - for l in self.v.iter() { - state.serialize_element(&l)?; - } - state.end() - } -} - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpEVPN1 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpEVPN1", 5)?; - state.serialize_field("rd", &self.rd)?; - state.serialize_field("esi_type", &self.esi_type)?; - state.serialize_field("esi", &self.esi)?; - state.serialize_field("ether_tag", &self.ether_tag)?; - state.serialize_field("labels", &self.labels)?; - state.end() - } -} - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpEVPN2 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpEVPN2", 7)?; - state.serialize_field("rd", &self.rd)?; - state.serialize_field("esi_type", &self.esi_type)?; - state.serialize_field("esi", &self.esi)?; - state.serialize_field("ether_tag", &self.ether_tag)?; - state.serialize_field("mac", &self.mac)?; - state.serialize_field("ip", &self.ip)?; - state.serialize_field("labels", &self.labels)?; - state.end() - } -} - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpEVPN3 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpEVPN3", 3)?; - state.serialize_field("rd", &self.rd)?; - state.serialize_field("ether_tag", &self.ether_tag)?; - state.serialize_field("ip", &self.ip)?; - state.end() - } -} - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpEVPN4 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpEVPN4", 4)?; - state.serialize_field("rd", &self.rd)?; - state.serialize_field("esi_type", &self.esi_type)?; - state.serialize_field("esi", &self.esi)?; - state.serialize_field("ip", &self.ip)?; - state.end() - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpEVPN { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) - } -} diff --git a/src/afi/flowspec.rs b/src/afi/flowspec.rs index 2f622df..22f0d87 100644 --- a/src/afi/flowspec.rs +++ b/src/afi/flowspec.rs @@ -8,6 +8,8 @@ //! This module describes NLRI data structures for flowspec https://tools.ietf.org/html/rfc5575 use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// FlowSpec NLRI item trait pub trait FSItem { @@ -36,6 +38,8 @@ impl FSItem for BgpAddrV4 { /// FlowSpec NLRI ipv6 unicast #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct FS6 { pub ipv6: BgpAddrV6, pub offset: u8, @@ -75,6 +79,9 @@ impl FSItem for FS6 { /// FlowSpec NLRI vpnv4 unicast #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct FSV4U { pub prefix: WithRd, } @@ -114,6 +121,8 @@ pub trait FSOperItem: Clone + PartialEq + Eq + PartialOrd + Ord { fn decode_from(buf: &[u8]) -> Result<(Self, usize), BgpError>; } #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct FSOperValItem { pub and_bit: bool, pub lt_cmp: bool, @@ -242,7 +251,7 @@ impl FSOperVec { a } fn encode_to(&self, buf: &mut [u8]) -> Result { - if self.items.len() < 1 { + if self.items.is_empty() { return Ok(0); } let mut pos: usize = 0; @@ -265,7 +274,30 @@ impl FSOperVec { Ok((Self { items: v }, pos)) } } +#[cfg(feature = "serialization")] +impl serde::Serialize for FSOperVec { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.items.serialize(serializer) + } +} +#[cfg(feature = "serialization")] +impl<'de, T: FSOperItem + de::Deserialize<'de>> de::Deserialize<'de> for FSOperVec { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + Ok(FSOperVec { + items: Vec::deserialize(deserializer)?, + }) + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct FSOperMaskItem { pub and_bit: bool, pub bit_not: bool, @@ -382,7 +414,7 @@ pub enum BgpFlowSpec> { IcmpCode(FSCmpValOpers), TcpFlags(FSCmpMaskOpers), PacketLength(FSCmpValOpers), - DSCP(FSCmpValOpers), + Dscp(FSCmpValOpers), Fragment(FSCmpMaskOpers), FlowLabel(FSCmpValOpers), } @@ -444,7 +476,7 @@ impl> BgpAddrItem> for BgpFlowSpec { } 11 => { let r = FSOperVec::decode_from(&buf[pos + 1..nlen])?; - Ok((BgpFlowSpec::DSCP(r.0), r.1 + pos + 1)) + Ok((BgpFlowSpec::Dscp(r.0), r.1 + pos + 1)) } 12 => { let r = FSOperVec::decode_from(&buf[pos + 1..nlen])?; @@ -470,7 +502,7 @@ impl> BgpAddrItem> for BgpFlowSpec { BgpFlowSpec::IcmpCode(v) => 2 + v.getbyteslen(), BgpFlowSpec::TcpFlags(v) => 2 + v.getbyteslen(), BgpFlowSpec::PacketLength(v) => 2 + v.getbyteslen(), - BgpFlowSpec::DSCP(v) => 2 + v.getbyteslen(), + BgpFlowSpec::Dscp(v) => 2 + v.getbyteslen(), BgpFlowSpec::Fragment(v) => 2 + v.getbyteslen(), BgpFlowSpec::FlowLabel(v) => 2 + v.getbyteslen(), }; @@ -534,7 +566,7 @@ impl> BgpAddrItem> for BgpFlowSpec { buf[pos] = 10; pos + 1 + v.encode_to(&mut buf[pos + 1..])? } - BgpFlowSpec::DSCP(v) => { + BgpFlowSpec::Dscp(v) => { buf[pos] = 11; pos + 1 + v.encode_to(&mut buf[pos + 1..])? } @@ -552,29 +584,170 @@ impl> BgpAddrItem> for BgpFlowSpec { } #[cfg(feature = "serialization")] -impl serde::Serialize for FSOperValItem { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) +mod ser { + use super::*; + const BFS_N: &str = "BgpFlowSpec"; + const BFS_VARS: [&str; 13] = [ + "PrefixDst", + "PrefixSrc", + "Proto", + "PortAny", + "PortDst", + "PortSrc", + "IcmpType", + "IcmpCode", + "TcpFlags", + "PacketLength", + "DSCP", + "Fragment", + "FlowLabel", + ]; + impl + serde::Serialize> serde::Serialize for BgpFlowSpec { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + BgpFlowSpec::PrefixDst(a) => { + serializer.serialize_newtype_variant(BFS_N, 0, BFS_VARS[0], a) + } + BgpFlowSpec::PrefixSrc(a) => { + serializer.serialize_newtype_variant(BFS_N, 1, BFS_VARS[1], a) + } + BgpFlowSpec::Proto(a) => { + serializer.serialize_newtype_variant(BFS_N, 2, BFS_VARS[2], a) + } + BgpFlowSpec::PortAny(a) => { + serializer.serialize_newtype_variant(BFS_N, 3, BFS_VARS[3], a) + } + BgpFlowSpec::PortDst(a) => { + serializer.serialize_newtype_variant(BFS_N, 4, BFS_VARS[4], a) + } + BgpFlowSpec::PortSrc(a) => { + serializer.serialize_newtype_variant(BFS_N, 5, BFS_VARS[5], a) + } + BgpFlowSpec::IcmpType(a) => { + serializer.serialize_newtype_variant(BFS_N, 6, BFS_VARS[6], a) + } + BgpFlowSpec::IcmpCode(a) => { + serializer.serialize_newtype_variant(BFS_N, 7, BFS_VARS[7], a) + } + BgpFlowSpec::TcpFlags(a) => { + serializer.serialize_newtype_variant(BFS_N, 8, BFS_VARS[8], a) + } + BgpFlowSpec::PacketLength(a) => { + serializer.serialize_newtype_variant(BFS_N, 9, BFS_VARS[9], a) + } + BgpFlowSpec::Dscp(a) => { + serializer.serialize_newtype_variant(BFS_N, 10, BFS_VARS[10], a) + } + BgpFlowSpec::Fragment(a) => { + serializer.serialize_newtype_variant(BFS_N, 11, BFS_VARS[11], a) + } + BgpFlowSpec::FlowLabel(a) => { + serializer.serialize_newtype_variant(BFS_N, 12, BFS_VARS[12], a) + } + } + } } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for FSOperMaskItem { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) + enum BgpFlowSpecVariant { + PrefixDst, + PrefixSrc, + Proto, + PortAny, + PortDst, + PortSrc, + IcmpType, + IcmpCode, + TcpFlags, + PacketLength, + Dscp, + Fragment, + FlowLabel, + } + impl<'de> de::Deserialize<'de> for BgpFlowSpecVariant { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct VariantVisitor; + impl<'de> de::Visitor<'de> for VariantVisitor { + type Value = BgpFlowSpecVariant; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "expecting one of: {:?}", BFS_VARS) + } + fn visit_str( + self, + value: &str, + ) -> Result { + match value { + "PrefixDst" => Ok(BgpFlowSpecVariant::PrefixDst), + "PrefixSrc" => Ok(BgpFlowSpecVariant::PrefixSrc), + "Proto" => Ok(BgpFlowSpecVariant::Proto), + "PortAny" => Ok(BgpFlowSpecVariant::PortAny), + "PortDst" => Ok(BgpFlowSpecVariant::PortDst), + "PortSrc" => Ok(BgpFlowSpecVariant::PortSrc), + "IcmpType" => Ok(BgpFlowSpecVariant::IcmpType), + "IcmpCode" => Ok(BgpFlowSpecVariant::IcmpCode), + "TcpFlags" => Ok(BgpFlowSpecVariant::TcpFlags), + "PacketLength" => Ok(BgpFlowSpecVariant::PacketLength), + "DSCP" => Ok(BgpFlowSpecVariant::Dscp), + "Fragment" => Ok(BgpFlowSpecVariant::Fragment), + "FlowLabel" => Ok(BgpFlowSpecVariant::FlowLabel), + _ => Err(serde::de::Error::unknown_field(value, &BFS_VARS)), + } + } + } + deserializer.deserialize_identifier(VariantVisitor) + } } -} -#[cfg(feature = "serialization")] -impl + std::fmt::Debug> serde::Serialize for BgpFlowSpec { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) + struct BgpFlowSpecVisitor> { + d: std::marker::PhantomData, + } + impl<'de, T: FSItem + de::Deserialize<'de>> de::Visitor<'de> for BgpFlowSpecVisitor { + type Value = BgpFlowSpec; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("enum BgpFlowSpec") + } + fn visit_map(self, mut map: V) -> Result + where + V: serde::de::MapAccess<'de>, + { + if let Some(key) = map.next_key()? { + match key { + BgpFlowSpecVariant::PrefixDst => Ok(BgpFlowSpec::PrefixDst(map.next_value()?)), + BgpFlowSpecVariant::PrefixSrc => Ok(BgpFlowSpec::PrefixSrc(map.next_value()?)), + BgpFlowSpecVariant::Proto => Ok(BgpFlowSpec::Proto(map.next_value()?)), + BgpFlowSpecVariant::PortAny => Ok(BgpFlowSpec::PortAny(map.next_value()?)), + BgpFlowSpecVariant::PortDst => Ok(BgpFlowSpec::PortDst(map.next_value()?)), + BgpFlowSpecVariant::PortSrc => Ok(BgpFlowSpec::PortSrc(map.next_value()?)), + BgpFlowSpecVariant::IcmpType => Ok(BgpFlowSpec::IcmpType(map.next_value()?)), + BgpFlowSpecVariant::IcmpCode => Ok(BgpFlowSpec::IcmpCode(map.next_value()?)), + BgpFlowSpecVariant::TcpFlags => Ok(BgpFlowSpec::TcpFlags(map.next_value()?)), + BgpFlowSpecVariant::PacketLength => { + Ok(BgpFlowSpec::PacketLength(map.next_value()?)) + } + BgpFlowSpecVariant::Dscp => Ok(BgpFlowSpec::Dscp(map.next_value()?)), + BgpFlowSpecVariant::Fragment => Ok(BgpFlowSpec::Fragment(map.next_value()?)), + BgpFlowSpecVariant::FlowLabel => Ok(BgpFlowSpec::FlowLabel(map.next_value()?)), + } + } else { + Err(de::Error::missing_field(BFS_VARS[0])) + } + } + } + impl<'de, T: FSItem + de::Deserialize<'de>> de::Deserialize<'de> for BgpFlowSpec { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_enum( + BFS_N, + &BFS_VARS, + BgpFlowSpecVisitor { + d: std::marker::PhantomData, + }, + ) + } } } diff --git a/src/afi/ipv4.rs b/src/afi/ipv4.rs index 0a84aca..09b131f 100644 --- a/src/afi/ipv4.rs +++ b/src/afi/ipv4.rs @@ -9,16 +9,29 @@ //! This module describes NLRI data structures for ipv4 use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; +use std::default::Default; use std::net::Ipv4Addr; /// ipv4 prefix unicast/multicast NLRI #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpAddrV4 { /// network prefix pub addr: Ipv4Addr, /// prefix length 0..32 pub prefixlen: u8, } +impl Default for BgpAddrV4 { + fn default() -> Self { + BgpAddrV4 { + addr: Ipv4Addr::new(127, 0, 0, 1), + prefixlen: 32, + } + } +} impl BgpAddrV4 { /// Constructs new ipv4 prefix /// ``` @@ -111,6 +124,10 @@ impl BgpAddrV4 { self.in_subnet(&a.range_first()) && self.in_subnet(&a.range_last()) } } + /// Check if given address is multicast + pub fn is_multicast(&self) -> bool { + (self.addr.octets() != [255, 255, 255, 255]) && self.addr.octets()[0] >= 224 + } pub fn from_bits(bits: u8, buf: &[u8]) -> Result<(BgpAddrV4, usize), BgpError> { if bits > 32 { return Err(BgpError::from_string(format!( @@ -118,7 +135,7 @@ impl BgpAddrV4 { bits ))); } - let mut bf = [0 as u8; 4]; + let mut bf = [0_u8; 4]; if bits == 0 { return Ok(( BgpAddrV4 { @@ -142,7 +159,7 @@ impl BgpAddrV4 { if self.prefixlen == 0 { return Ok((0, 0)); } - let mut bf = [0 as u8; 4]; + let mut bf = [0_u8; 4]; bf.clone_from_slice(&self.addr.octets()); let bytes = ((self.prefixlen + 7) / 8) as usize; buf[0..bytes].clone_from_slice(&bf[0..bytes]); @@ -184,6 +201,8 @@ impl std::fmt::Display for BgpAddrV4 { } } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpIPv4RD { pub rd: BgpRD, pub addr: std::net::Ipv4Addr, @@ -227,26 +246,20 @@ impl BgpAddrItem for BgpIPv4RD { } } -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAddrV4 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpAddrV4", 2)?; - state.serialize_field("addr", &self.addr)?; - state.serialize_field("len", &self.prefixlen)?; - state.end() - } -} #[cfg(test)] mod tests { use super::*; #[test] fn test_ipv4_parse() { - assert_eq!("10.0.0.0".parse::(),Ok(BgpAddrV4::new(Ipv4Addr::new(10, 0, 0, 0), 32))); - assert_eq!("10.0.0.0/8".parse::(),Ok(BgpAddrV4::new(Ipv4Addr::new(10, 0, 0, 0), 8))); + assert_eq!( + "10.0.0.0".parse::(), + Ok(BgpAddrV4::new(Ipv4Addr::new(10, 0, 0, 0), 32)) + ); + assert_eq!( + "10.0.0.0/8".parse::(), + Ok(BgpAddrV4::new(Ipv4Addr::new(10, 0, 0, 0), 8)) + ); } #[test] diff --git a/src/afi/ipv6.rs b/src/afi/ipv6.rs index 1dfc276..e7fec7c 100644 --- a/src/afi/ipv6.rs +++ b/src/afi/ipv6.rs @@ -9,16 +9,28 @@ //! This module describes NLRI data structures for ipv6 use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; use std::net::Ipv6Addr; /// ipv6 prefix unicast/multicast NLRI #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpAddrV6 { /// network prefix pub addr: Ipv6Addr, /// prefix length 0..128 pub prefixlen: u8, } +impl Default for BgpAddrV6 { + fn default() -> Self { + BgpAddrV6 { + addr: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), + prefixlen: 128, + } + } +} impl BgpAddrV6 { /// Constructs new ipv6 prefix /// ``` @@ -100,7 +112,6 @@ impl BgpAddrV6 { /// /// assert_eq!(BgpAddrV6::new(Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0x100),112).range_last() , Ipv6Addr::new(0x2a02,0,0,0,0,0,0,0xffff) ); /// ``` - pub fn range_last(&self) -> std::net::Ipv6Addr { if self.prefixlen < 1 { std::net::Ipv6Addr::new( @@ -122,6 +133,10 @@ impl BgpAddrV6 { ) } } + /// Check if given address is multicast + pub fn is_multicast(&self) -> bool { + self.addr.octets()[0] == 255 + } pub fn from_bits(bits: u8, buf: &[u8]) -> Result<(BgpAddrV6, usize), BgpError> { if bits > 128 { return Err(BgpError::from_string(format!( @@ -129,7 +144,7 @@ impl BgpAddrV6 { bits ))); } - let mut bf = [0 as u8; 16]; + let mut bf = [0_u8; 16]; if bits == 0 { return Ok(( BgpAddrV6 { @@ -153,7 +168,7 @@ impl BgpAddrV6 { if self.prefixlen == 0 { return Ok((0, 0)); } - let mut bf = [0 as u8; 16]; + let mut bf = [0_u8; 16]; bf.clone_from_slice(&self.addr.octets()); let bytes = ((self.prefixlen + 7) / 8) as usize; buf[0..bytes].clone_from_slice(&bf[0..bytes]); @@ -196,6 +211,8 @@ impl std::fmt::Display for BgpAddrV6 { } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpIPv6RD { pub rd: BgpRD, pub addr: std::net::Ipv6Addr, @@ -233,26 +250,26 @@ impl BgpAddrItem for BgpIPv6RD { Ok(pos + p2) } } -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAddrV6 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpAddrV6", 2)?; - state.serialize_field("addr", &self.addr)?; - state.serialize_field("len", &self.prefixlen)?; - state.end() - } -} #[cfg(test)] mod tests { use super::*; #[test] fn test_ipv6_parse() { - assert_eq!("2a02::/32".parse::(),Ok(BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), 32))); - assert_eq!("2a02::1".parse::(),Ok(BgpAddrV6::new(Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 1), 128))); + assert_eq!( + "2a02::/32".parse::(), + Ok(BgpAddrV6::new( + Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 0), + 32 + )) + ); + assert_eq!( + "2a02::1".parse::(), + Ok(BgpAddrV6::new( + Ipv6Addr::new(0x2a02, 0, 0, 0, 0, 0, 0, 1), + 128 + )) + ); } #[test] diff --git a/src/afi/mac.rs b/src/afi/mac.rs index 763587f..2a149ac 100644 --- a/src/afi/mac.rs +++ b/src/afi/mac.rs @@ -9,9 +9,14 @@ //! This module describes NLRI data structures for mac address use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// Six-byte ethernet mac address. Used in EVPN. #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct MacAddress { pub mac_address: [u8; 6], } @@ -19,16 +24,18 @@ impl MacAddress { /// Construct new zero mac address. pub fn new() -> MacAddress { MacAddress { - mac_address: [0 as u8; 6], + mac_address: [0_u8; 6], } } /// Construct new mac address from 6 bytes in network order. pub fn from(b: &[u8]) -> MacAddress { - MacAddress { mac_address: [b[5],b[4],b[3],b[2],b[1],b[0]] } + MacAddress { + mac_address: [b[5], b[4], b[3], b[2], b[1], b[0]], + } } /// Construct new mac address from u64. - pub fn from_u64(s:u64) -> MacAddress { - let mut a = [0 as u8; 6]; + pub fn from_u64(s: u64) -> MacAddress { + let mut a = [0_u8; 6]; a[0] = (s & 0xff) as u8; a[1] = ((s >> 8) & 0xff) as u8; a[2] = ((s >> 16) & 0xff) as u8; @@ -39,7 +46,17 @@ impl MacAddress { } /// Pack to u64. pub fn to_u64(&self) -> u64 { - (self.mac_address[5] as u64) << 40 | (self.mac_address[4] as u64) << 32 | (self.mac_address[3] as u64) << 24 | (self.mac_address[2] as u64) << 16 | (self.mac_address[1] as u64) << 8 | (self.mac_address[0] as u64) + (self.mac_address[5] as u64) << 40 + | (self.mac_address[4] as u64) << 32 + | (self.mac_address[3] as u64) << 24 + | (self.mac_address[2] as u64) << 16 + | (self.mac_address[1] as u64) << 8 + | (self.mac_address[0] as u64) + } +} +impl Default for MacAddress { + fn default() -> Self { + Self::new() } } impl std::fmt::Display for MacAddress { @@ -73,13 +90,13 @@ impl std::str::FromStr for MacAddress { type Err = BgpError; fn from_str(s: &str) -> Result { - let mut mac:u64=0; - let mut cnt:usize=0; + let mut mac: u64 = 0; + let mut cnt: usize = 0; for c in s.chars() { - if let Some(d) = c.to_digit(16) { - mac = (mac << 4) | (d as u64); - cnt = cnt + 1; - } + if let Some(d) = c.to_digit(16) { + mac = (mac << 4) | (d as u64); + cnt += 1; + } } if cnt < 1 { return Err(BgpError::static_str("Invalid mac address")); @@ -87,16 +104,6 @@ impl std::str::FromStr for MacAddress { Ok(MacAddress::from_u64(mac)) } } -#[cfg(feature = "serialization")] -impl serde::Serialize for MacAddress { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.to_string().as_str()) - } -} - /// ipv4 prefix unicast/multicast NLRI #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct BgpAddrMac { @@ -110,7 +117,7 @@ impl BgpAddrMac { /// ``` /// use zettabgp::afi::mac::MacAddress; /// use zettabgp::prelude::BgpAddrMac; - /// + /// /// let pfx = BgpAddrMac::new(MacAddress::from_u64(0x121314151600),40); /// ``` pub fn new(address: MacAddress, prefix_len: u8) -> BgpAddrMac { @@ -126,7 +133,7 @@ impl BgpAddrMac { /// ``` /// use zettabgp::afi::mac::MacAddress; /// use zettabgp::prelude::BgpAddrMac; - /// + /// /// assert!(BgpAddrMac::new(MacAddress::from_u64(0x121314151600),40).in_subnet(&MacAddress::from_u64(0x121314151601))) /// ``` pub fn in_subnet(&self, a: &MacAddress) -> bool { @@ -145,7 +152,7 @@ impl BgpAddrMac { /// ``` /// use zettabgp::afi::mac::MacAddress; /// use zettabgp::prelude::BgpAddrMac; - /// + /// /// assert_eq!(BgpAddrMac::new(MacAddress::from_u64(0x1213141516ab),40).range_first() , MacAddress::from_u64(0x121314151600) ); /// ``` pub fn range_first(&self) -> MacAddress { @@ -155,7 +162,7 @@ impl BgpAddrMac { /// ``` /// use zettabgp::afi::mac::MacAddress; /// use zettabgp::prelude::BgpAddrMac; - /// + /// /// assert_eq!(BgpAddrMac::new(MacAddress::from_u64(0x1213141516ab),40).range_last() , MacAddress::from_u64(0x1213141516ff)); /// ``` pub fn range_last(&self) -> MacAddress { diff --git a/src/afi/mdt.rs b/src/afi/mdt.rs new file mode 100644 index 0000000..6455639 --- /dev/null +++ b/src/afi/mdt.rs @@ -0,0 +1,217 @@ +// Copyright 2021-2022 Vladimir Melnikov. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module describes NLRI data structures for mdt (multicast distribution tree) safi for ipv4 and ipv6 + +use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; +use std::default::Default; +use std::net::{Ipv4Addr, Ipv6Addr}; + +/// ipv4 mdt NLRI +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +pub struct BgpMdtV4 { + /// network prefix + pub addr: BgpAddrV4, + /// mdt group + pub group: Ipv4Addr, +} +impl Default for BgpMdtV4 { + fn default() -> Self { + BgpMdtV4 { + addr: BgpAddrV4::default(), + group: Ipv4Addr::new(224, 0, 0, 0), + } + } +} +impl BgpMdtV4 { + /// Constructs new mdtv4 prefix + /// ``` + /// use zettabgp::prelude::{BgpAddrV4,BgpMdtV4}; + /// use std::net::Ipv4Addr; + /// + /// let pfx = BgpMdtV4::new(BgpAddrV4::new(Ipv4Addr::new(192,168,0,0),16),Ipv4Addr::new(224,0,0,0)); + /// ``` + pub fn new(addr: BgpAddrV4, group: Ipv4Addr) -> BgpMdtV4 { + BgpMdtV4 { addr, group } + } +} +impl std::str::FromStr for BgpMdtV4 { + type Err = BgpError; + + fn from_str(s: &str) -> Result { + let addr_grp: Vec<&str> = s.split('@').collect(); + if addr_grp.len() != 2 { + return Err(BgpError::static_str("Invalid MDT")); + }; + Ok(BgpMdtV4 { + addr: addr_grp[0].parse()?, + group: addr_grp[1].parse()?, + }) + } +} +impl BgpItem for BgpMdtV4 { + fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(BgpMdtV4, usize), BgpError> { + if !(32..=128).contains(&bits) { + return Err(BgpError::from_string(format!( + "Invalid BgpMdtV4 FEC length: {:?}", + bits + ))); + } + let mut bf = [0_u8; 4]; + if bits == 32 { + return Ok(( + BgpMdtV4 { + addr: BgpAddrV4 { + addr: decode_addrv4_from(&bf)?, + prefixlen: 0, + }, + group: decode_addrv4_from(buf)?, + }, + 4, + )); + } + let bytes = (((bits - 32) + 7) / 8) as usize; + bf[0..bytes].clone_from_slice(&buf[0..bytes]); + Ok(( + BgpMdtV4 { + addr: BgpAddrV4 { + addr: decode_addrv4_from(&bf)?, + prefixlen: bits-32, + }, + group: decode_addrv4_from(&buf[bytes..])?, + }, + bytes + 4, + )) + } + fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { + let bytes = if self.addr.prefixlen > 0 { + let mut bf = [0_u8; 4]; + bf.clone_from_slice(&self.addr.addr.octets()); + let bytes = ((self.addr.prefixlen + 7) / 8) as usize; + buf[0..bytes].clone_from_slice(&bf[0..bytes]); + bytes + } else { + 0 + }; + buf[bytes..(bytes + 4)].clone_from_slice(&self.group.octets()); + Ok((self.addr.prefixlen + 32, bytes + 4)) + } + fn prefixlen(&self) -> usize { + self.addr.prefixlen as usize + } +} +impl std::fmt::Display for BgpMdtV4 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}@{}", self.addr, self.group) + } +} + +/// ipv6 mdt NLRI +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +pub struct BgpMdtV6 { + /// network prefix + pub addr: BgpAddrV6, + /// mdt group + pub group: Ipv6Addr, +} +impl Default for BgpMdtV6 { + fn default() -> Self { + BgpMdtV6 { + addr: Default::default(), + group: Ipv6Addr::new(0xfe00, 0, 0, 0, 0, 0, 0, 0), + } + } +} +impl BgpMdtV6 { + /// Constructs new mdtv6 prefix + /// ``` + /// use zettabgp::prelude::{BgpAddrV6,BgpMdtV6}; + /// use std::net::Ipv6Addr; + /// + /// let pfx = BgpMdtV6::new(BgpAddrV6::new(Ipv6Addr::new(0,0,0,0,0,0,0,1),128),Ipv6Addr::new(0xfe00,0,0,0,0,0,0,0)); + /// ``` + pub fn new(addr: BgpAddrV6, group: Ipv6Addr) -> BgpMdtV6 { + BgpMdtV6 { addr, group } + } +} +impl std::str::FromStr for BgpMdtV6 { + type Err = BgpError; + + fn from_str(s: &str) -> Result { + let addr_grp: Vec<&str> = s.split('@').collect(); + if addr_grp.len() != 2 { + return Err(BgpError::static_str("Invalid MDT")); + }; + Ok(BgpMdtV6 { + addr: addr_grp[0].parse()?, + group: addr_grp[1].parse()?, + }) + } +} +impl BgpItem for BgpMdtV6 { + fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(BgpMdtV6, usize), BgpError> { + if !(128..=254).contains(&bits) { + return Err(BgpError::from_string(format!( + "Invalid BgpMdtV6 FEC length: {:?}", + bits + ))); + } + let mut bf = [0_u8; 16]; + if bits == 128 { + return Ok(( + BgpMdtV6 { + addr: BgpAddrV6 { + addr: decode_addrv6_from(&bf)?, + prefixlen: 0, + }, + group: decode_addrv6_from(buf)?, + }, + 16, + )); + } + let bytes = (((bits - 128) + 7) / 8) as usize; + bf[0..bytes].clone_from_slice(&buf[0..bytes]); + Ok(( + BgpMdtV6 { + addr: BgpAddrV6 { + addr: decode_addrv6_from(&bf)?, + prefixlen: bits-128, + }, + group: decode_addrv6_from(&buf[bytes..])?, + }, + bytes + 16, + )) + } + fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { + let bytes = if self.addr.prefixlen > 0 { + let mut bf = [0_u8; 16]; + bf.clone_from_slice(&self.addr.addr.octets()); + let bytes = ((self.addr.prefixlen + 7) / 8) as usize; + buf[0..bytes].clone_from_slice(&bf[0..bytes]); + bytes + } else { + 0 + }; + buf[bytes..(bytes + 16)].clone_from_slice(&self.group.octets()); + Ok((self.addr.prefixlen + 128, bytes + 16)) + } + fn prefixlen(&self) -> usize { + self.addr.prefixlen as usize + } +} +impl std::fmt::Display for BgpMdtV6 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}@{}", self.addr, self.group) + } +} diff --git a/src/afi/mod.rs b/src/afi/mod.rs index 0ea698d..387b1fb 100644 --- a/src/afi/mod.rs +++ b/src/afi/mod.rs @@ -12,9 +12,10 @@ use crate::*; #[cfg(feature = "serialization")] use serde::de::{self, Visitor}; #[cfg(feature = "serialization")] -use serde::ser::{SerializeSeq, SerializeStruct}; +use serde::{ser::SerializeStruct, Deserialize, Serialize}; use std::cmp::Ordering; +use std::hash::{Hash, Hasher}; pub mod ipv4; pub use ipv4::*; pub mod ipv6; @@ -29,6 +30,8 @@ pub mod evpn; pub use evpn::*; pub mod flowspec; pub use flowspec::*; +pub mod mdt; +pub use mdt::*; /// NLRI with bits length pub trait BgpItem { @@ -45,6 +48,8 @@ pub trait BgpItemLong { } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub enum BgpAddr { None, V4(std::net::Ipv4Addr), @@ -152,6 +157,8 @@ impl<'de> serde::Deserialize<'de> for BgpNet { /// Represents variance of NLRI collections #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub enum BgpAddrs { None, IPV4U(Vec), @@ -159,11 +166,15 @@ pub enum BgpAddrs { IPV4LU(Vec>), VPNV4U(Vec>>), VPNV4M(Vec>>), + IPV4MDT(Vec>), + IPV4MDTP(Vec>>), IPV6U(Vec), IPV6M(Vec), IPV6LU(Vec>), VPNV6U(Vec>>), VPNV6M(Vec>>), + IPV6MDT(Vec>), + IPV6MDTP(Vec>>), L2VPLS(Vec), MVPN(Vec), EVPN(Vec), @@ -195,16 +206,16 @@ pub fn decode_bgpitems_from>(buf: &[u8]) -> Result<(Vec, usize) v.push(nlri.0); curpos += nlri.1; } - return Ok((v, curpos)); + Ok((v, curpos)) } -pub fn encode_bgpitems_to>(v: &Vec, buf: &mut [u8]) -> Result { +pub fn encode_bgpitems_to>(v: &[T], buf: &mut [u8]) -> Result { let mut curpos = 0; for i in v.iter() { let r = i.set_bits_to(&mut buf[curpos + 1..])?; buf[curpos] = r.0; curpos += r.1 + 1; } - return Ok(curpos); + Ok(curpos) } pub fn decode_bgpaddritems_from>( peermode: BgpTransportMode, @@ -217,10 +228,10 @@ pub fn decode_bgpaddritems_from>( v.push(nlri.0); curpos += nlri.1; } - return Ok((v, curpos)); + Ok((v, curpos)) } pub fn encode_bgpaddritems_to>( - v: &Vec, + v: &[T], peermode: BgpTransportMode, buf: &mut [u8], ) -> Result { @@ -243,10 +254,10 @@ pub fn decode_long_bgpitems_from>( )?); curpos += itemlen + 2; } - return Ok((v, curpos)); + Ok((v, curpos)) } pub fn encode_long_bgpitems_to>( - v: &Vec, + v: &[T], buf: &mut [u8], ) -> Result { let mut curpos = 0; @@ -262,17 +273,17 @@ pub fn decode_pathid_bgpitems_from + Clone + PartialEq + Eq + Part ) -> Result<(Vec>, usize), BgpError> { let mut v = Vec::>::new(); let mut curpos = 0; - while (curpos+4) < buf.len() { + while (curpos + 4) < buf.len() { let pathid = getn_u32(&buf[curpos..]); curpos += 4; let nlri = decode_bgpitem_from(&buf[curpos..])?; v.push(WithPathId::::new(pathid, nlri.0)); curpos += nlri.1; } - return Ok((v, curpos)); + Ok((v, curpos)) } pub fn encode_pathid_bgpitems_to + Clone + PartialEq + Eq + PartialOrd>( - v: &Vec>, + v: &[WithPathId], buf: &mut [u8], ) -> Result { let mut curpos = 0; @@ -283,10 +294,12 @@ pub fn encode_pathid_bgpitems_to + Clone + PartialEq + Eq + Partia buf[curpos] = r.0; curpos += r.1 + 1; } - return Ok(curpos); + Ok(curpos) } /// BGP VPN route distinguisher #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpRD { /// high-order part pub rdh: u32, @@ -381,7 +394,10 @@ impl std::fmt::Display for BgpAddr { } } /// MPLS labels as NLRI component -#[derive(Debug, Clone, Eq, Ord)] +#[derive(Debug, Clone)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct MplsLabels { pub labels: Vec, } @@ -395,37 +411,42 @@ impl MplsLabels { MplsLabels { labels: lbls } } } -/* - labels does not treated as hash part -*/ -impl std::hash::Hash for MplsLabels { - fn hash(&self, _state: &mut H) { - //self.prefix.hash(state) +impl Default for MplsLabels { + fn default() -> Self { + Self::new() + } +} +impl Hash for MplsLabels { + fn hash(&self, _state: &mut H) { + //self.prefix.hash(state) //labels does not produce unique FEC } } -/* - labels does not produce unique FEC -*/ impl PartialOrd for MplsLabels { fn partial_cmp(&self, _other: &Self) -> Option { - None + None //labels does not produce unique FEC + } +} +impl Ord for MplsLabels { + fn cmp(&self, _other: &Self) -> std::cmp::Ordering { + std::cmp::Ordering::Equal //labels does not produce unique FEC } } impl PartialEq for MplsLabels { fn eq(&self, _other: &Self) -> bool { - true + true //labels does not produce unique FEC } } +impl Eq for MplsLabels {} impl std::fmt::Display for MplsLabels { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { //write!(f, "{:?}", self.labels) - let mut first:bool=true; + let mut first: bool = true; for l in self.labels.iter() { if !first { ",".fmt(f)?; } l.fmt(f)?; - first=false; + first = false; } Ok(()) } @@ -458,7 +479,7 @@ impl BgpItem for MplsLabels { Ok((MplsLabels { labels: lbls }, curpos)) } fn set_bits_to(&self, buf: &mut [u8]) -> Result<(u8, usize), BgpError> { - if self.labels.len() == 0 { + if self.labels.is_empty() { return Ok((0, 0)); } let mut curpos: usize = 0; @@ -476,7 +497,7 @@ impl BgpItem for MplsLabels { } } /// Labeled NLRI -#[derive(Debug, Clone, Hash, Eq)] +#[derive(Debug, Clone)] pub struct Labeled> { /// underlying NLRI pub prefix: T, @@ -504,6 +525,12 @@ impl + PartialEq> PartialEq for Labeled { self.prefix.eq(&other.prefix) } } +impl + Eq> Eq for Labeled {} +impl + Hash> Hash for Labeled { + fn hash(&self, state: &mut H) { + self.prefix.hash(state) //labels does not produce unique FEC + } +} impl + PartialOrd> PartialOrd for Labeled { fn partial_cmp(&self, other: &Self) -> Option { self.prefix.partial_cmp(&other.prefix) @@ -516,7 +543,7 @@ impl + Ord> Ord for Labeled { } impl> BgpItem> for Labeled { fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(Labeled, usize), BgpError> { - let l = MplsLabels::extract_bits_from(bits, &buf)?; + let l = MplsLabels::extract_bits_from(bits, buf)?; let p = T::extract_bits_from(bits - ((l.1 * 8) as u8), &buf[l.1..])?; Ok(( Labeled { @@ -537,7 +564,7 @@ impl> BgpItem> for Labeled { } impl + std::fmt::Display> std::fmt::Display for Labeled { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.labels.labels.len() < 1 { + if self.labels.labels.is_empty() { write!(f, "{}", self.prefix) } else { write!(f, " {}", self.labels, self.prefix) @@ -545,17 +572,14 @@ impl + std::fmt::Display> std::fmt::Display for Labeled { } } /// NRI with Route distinguisher -#[derive(Clone, Hash, PartialEq, Eq, Ord)] +#[derive(Clone, Hash, PartialEq, Eq)] pub struct WithRd> { pub prefix: T, pub rd: BgpRD, } impl> WithRd { - pub fn new(rd: BgpRD, inner: T) -> WithRd { - WithRd { - rd: rd, - prefix: inner, - } + pub fn new(rd: BgpRD, prefix: T) -> WithRd { + WithRd { rd, prefix } } } impl + PartialOrd> PartialOrd for WithRd { @@ -570,11 +594,19 @@ impl + PartialOrd> PartialOrd for WithRd { } } } - +impl + Ord> Ord for WithRd { + fn cmp(&self, other: &Self) -> Ordering { + match self.prefix.cmp(&other.prefix) { + Ordering::Less => Ordering::Less, + Ordering::Greater => Ordering::Greater, + Ordering::Equal => self.rd.cmp(&other.rd), + } + } +} impl> BgpItem> for WithRd { fn extract_bits_from(bits: u8, buf: &[u8]) -> Result<(WithRd, usize), BgpError> { if buf.len() < 8 { - return Err(BgpError::static_str("Buffer size too small for RD")); + return Err(BgpError::InsufficientBufferSize); } let r = BgpRD::decode_from(BgpTransportMode::IPv4, &buf[0..8])?; let p = T::extract_bits_from(bits - ((r.1 * 8) as u8), &buf[r.1..])?; @@ -614,23 +646,26 @@ impl + std::fmt::Display> std::fmt::Display for WithRd { } pub type BgpPathId = u32; /// NRI with PathId -#[derive(Clone, PartialEq, Eq, Ord)] +#[derive(Clone)] pub struct WithPathId { pub pathid: BgpPathId, pub nlri: T, } -impl std::hash::Hash for WithPathId { - fn hash(&self, state: &mut H) { +impl PartialEq for WithPathId { + fn eq(&self, other: &Self) -> bool { + self.pathid.eq(&other.pathid) && self.nlri.eq(&other.nlri) + } +} +impl Eq for WithPathId {} +impl Hash for WithPathId { + fn hash(&self, state: &mut H) { self.pathid.hash(state); self.nlri.hash(state); } } impl WithPathId { - pub fn new(pathid: BgpPathId, inner: T) -> WithPathId { - WithPathId { - pathid: pathid, - nlri: inner, - } + pub fn new(pathid: BgpPathId, nlri: T) -> WithPathId { + WithPathId { pathid, nlri } } } impl PartialOrd for WithPathId { @@ -645,7 +680,15 @@ impl PartialOrd for WithPathId { } } } - +impl Ord for WithPathId { + fn cmp(&self, other: &Self) -> Ordering { + match self.nlri.cmp(&other.nlri) { + Ordering::Less => Ordering::Less, + Ordering::Greater => Ordering::Greater, + Ordering::Equal => self.pathid.cmp(&other.pathid), + } + } +} impl std::fmt::Debug for WithPathId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("WithPathId") @@ -654,7 +697,9 @@ impl std::fmt::Debug f .finish() } } -impl std::fmt::Display for WithPathId { +impl std::fmt::Display + for WithPathId +{ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { if self.pathid == 0 { self.nlri.fmt(f) @@ -663,12 +708,51 @@ impl std::fmt::Displ } } } - +impl Default for BgpAddrs { + fn default() -> Self { + Self::new() + } +} impl BgpAddrs { /// creates a new empty BgpAddrs pub fn new() -> BgpAddrs { BgpAddrs::None } + pub fn is_empty(&self) -> bool { + match self { + BgpAddrs::None => true, + BgpAddrs::IPV4U(v) => v.is_empty(), + BgpAddrs::IPV4M(v) => v.is_empty(), + BgpAddrs::IPV4LU(v) => v.is_empty(), + BgpAddrs::VPNV4U(v) => v.is_empty(), + BgpAddrs::VPNV4M(v) => v.is_empty(), + BgpAddrs::IPV6U(v) => v.is_empty(), + BgpAddrs::IPV6M(v) => v.is_empty(), + BgpAddrs::IPV6LU(v) => v.is_empty(), + BgpAddrs::VPNV6U(v) => v.is_empty(), + BgpAddrs::VPNV6M(v) => v.is_empty(), + BgpAddrs::L2VPLS(v) => v.is_empty(), + BgpAddrs::MVPN(v) => v.is_empty(), + BgpAddrs::EVPN(v) => v.is_empty(), + BgpAddrs::FS4U(v) => v.is_empty(), + BgpAddrs::FS6U(v) => v.is_empty(), + BgpAddrs::FSV4U(v) => v.is_empty(), + BgpAddrs::IPV4UP(v) => v.is_empty(), + BgpAddrs::IPV4MP(v) => v.is_empty(), + BgpAddrs::IPV4LUP(v) => v.is_empty(), + BgpAddrs::VPNV4UP(v) => v.is_empty(), + BgpAddrs::VPNV4MP(v) => v.is_empty(), + BgpAddrs::IPV6UP(v) => v.is_empty(), + BgpAddrs::IPV6MP(v) => v.is_empty(), + BgpAddrs::IPV6LUP(v) => v.is_empty(), + BgpAddrs::VPNV6UP(v) => v.is_empty(), + BgpAddrs::VPNV6MP(v) => v.is_empty(), + BgpAddrs::IPV4MDT(v) => v.is_empty(), + BgpAddrs::IPV4MDTP(v) => v.is_empty(), + BgpAddrs::IPV6MDT(v) => v.is_empty(), + BgpAddrs::IPV6MDTP(v) => v.is_empty(), + } + } /// returns collection length pub fn len(&self) -> usize { match self { @@ -699,6 +783,10 @@ impl BgpAddrs { BgpAddrs::IPV6LUP(v) => v.len(), BgpAddrs::VPNV6UP(v) => v.len(), BgpAddrs::VPNV6MP(v) => v.len(), + BgpAddrs::IPV4MDT(v) => v.len(), + BgpAddrs::IPV4MDTP(v) => v.len(), + BgpAddrs::IPV6MDT(v) => v.len(), + BgpAddrs::IPV6MDTP(v) => v.len(), } } /// returns BGP afi+safi codes @@ -731,6 +819,10 @@ impl BgpAddrs { BgpAddrs::IPV6LUP(_) => (2, 4), BgpAddrs::VPNV6UP(_) => (2, 128), BgpAddrs::VPNV6MP(_) => (2, 129), + BgpAddrs::IPV4MDT(_) => (1, 66), + BgpAddrs::IPV4MDTP(_) => (1, 66), + BgpAddrs::IPV6MDT(_) => (2, 66), + BgpAddrs::IPV6MDTP(_) => (2, 66), } } pub fn decode_from( @@ -747,79 +839,86 @@ impl BgpAddrs { //unicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV4UP(r.0), r.1)); + Ok((BgpAddrs::IPV4UP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV4U(r.0), r.1)); + Ok((BgpAddrs::IPV4U(r.0), r.1)) } } 2 => { //multicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV4MP(r.0), r.1)); + Ok((BgpAddrs::IPV4MP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV4M(r.0), r.1)); + Ok((BgpAddrs::IPV4M(r.0), r.1)) } } 4 => { //labeled unicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV4LUP(r.0), r.1)); + Ok((BgpAddrs::IPV4LUP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV4LU(r.0), r.1)); + Ok((BgpAddrs::IPV4LU(r.0), r.1)) } } 5 => { //mvpn v4 - let r = match decode_bgpaddritems_from(BgpTransportMode::IPv4, buf) { - Ok(q) => q, + match decode_bgpaddritems_from(BgpTransportMode::IPv4, buf) { + Ok(r) => Ok((BgpAddrs::MVPN(r.0), r.1)), Err(e) => { eprintln!("MVPN decode error: {:?}\nbuf:{:?}", e, buf); - return Err(e); + Err(e) } - }; - return Ok((BgpAddrs::MVPN(r.0), r.1)); + } + } + 66 => { + //mdt + if peer.check_addpath_receive(afi, safi) { + let r = decode_pathid_bgpitems_from(buf)?; + Ok((BgpAddrs::IPV4MDTP(r.0), r.1)) + } else { + let r = decode_bgpitems_from(buf)?; + Ok((BgpAddrs::IPV4MDT(r.0), r.1)) + } } 128 => { //vpnv4 unicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV4UP(r.0), r.1)); + Ok((BgpAddrs::VPNV4UP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV4U(r.0), r.1)); + Ok((BgpAddrs::VPNV4U(r.0), r.1)) } } 129 => { //vpnv4 multicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV4MP(r.0), r.1)); + Ok((BgpAddrs::VPNV4MP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV4M(r.0), r.1)); + Ok((BgpAddrs::VPNV4M(r.0), r.1)) } } 133 => { //ip4u flowspec let r = decode_bgpaddritems_from(peer.peer_mode, buf)?; - return Ok((BgpAddrs::FS4U(r.0), r.1)); + Ok((BgpAddrs::FS4U(r.0), r.1)) } 134 => { //vpn4u flowspec let r = decode_bgpaddritems_from(peer.peer_mode, buf)?; - return Ok((BgpAddrs::FSV4U(r.0), r.1)); - } - n => { - return Err(BgpError::from_string(format!( - "Unknown safi for ipv4 {:?}", - n - ))) + Ok((BgpAddrs::FSV4U(r.0), r.1)) } + n => Err(BgpError::from_string(format!( + "Unknown safi for ipv4 {:?}", + n + ))), } } 2 => { @@ -829,63 +928,71 @@ impl BgpAddrs { //unicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV6UP(r.0), r.1)); + Ok((BgpAddrs::IPV6UP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV6U(r.0), r.1)); + Ok((BgpAddrs::IPV6U(r.0), r.1)) } } 2 => { //multicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV6MP(r.0), r.1)); + Ok((BgpAddrs::IPV6MP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV6M(r.0), r.1)); + Ok((BgpAddrs::IPV6M(r.0), r.1)) } } 4 => { //labeled unicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV6LUP(r.0), r.1)); + Ok((BgpAddrs::IPV6LUP(r.0), r.1)) + } else { + let r = decode_bgpitems_from(buf)?; + Ok((BgpAddrs::IPV6LU(r.0), r.1)) + } + } + 66 => { + //mdt + if peer.check_addpath_receive(afi, safi) { + let r = decode_pathid_bgpitems_from(buf)?; + Ok((BgpAddrs::IPV6MDTP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::IPV6LU(r.0), r.1)); + Ok((BgpAddrs::IPV6MDT(r.0), r.1)) } } 128 => { //vpnv6 unicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV6UP(r.0), r.1)); + Ok((BgpAddrs::VPNV6UP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV6U(r.0), r.1)); + Ok((BgpAddrs::VPNV6U(r.0), r.1)) } } 129 => { //vpnv6 multicast if peer.check_addpath_receive(afi, safi) { let r = decode_pathid_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV6MP(r.0), r.1)); + Ok((BgpAddrs::VPNV6MP(r.0), r.1)) } else { let r = decode_bgpitems_from(buf)?; - return Ok((BgpAddrs::VPNV6M(r.0), r.1)); + Ok((BgpAddrs::VPNV6M(r.0), r.1)) } } 133 => { //ip6u flowspec let r = decode_bgpaddritems_from(peer.peer_mode, buf)?; - return Ok((BgpAddrs::FS6U(r.0), r.1)); - } - n => { - return Err(BgpError::from_string(format!( - "Unknown safi for ipv6 {:?}", - n - ))) + Ok((BgpAddrs::FS6U(r.0), r.1)) } + n => Err(BgpError::from_string(format!( + "Unknown safi for ipv6 {:?}", + n + ))), } } 25 => { @@ -894,22 +1001,20 @@ impl BgpAddrs { 65 => { //vpls let r = decode_long_bgpitems_from(buf)?; - return Ok((BgpAddrs::L2VPLS(r.0), r.1)); + Ok((BgpAddrs::L2VPLS(r.0), r.1)) } 70 => { //evpn let r = decode_bgpaddritems_from(peer.peer_mode, buf)?; - return Ok((BgpAddrs::EVPN(r.0), r.1)); - } - n => { - return Err(BgpError::from_string(format!( - "Unknown safi for l2 {:?}", - n - ))) + Ok((BgpAddrs::EVPN(r.0), r.1)) } + n => Err(BgpError::from_string(format!( + "Unknown safi for l2 {:?}", + n + ))), } } - n => return Err(BgpError::from_string(format!("Unknown afi {:?}", n))), + n => Err(BgpError::from_string(format!("Unknown afi {:?}", n))), } } pub fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { @@ -941,6 +1046,10 @@ impl BgpAddrs { BgpAddrs::IPV6LUP(v) => encode_pathid_bgpitems_to(v, buf), BgpAddrs::VPNV6UP(v) => encode_pathid_bgpitems_to(v, buf), BgpAddrs::VPNV6MP(v) => encode_pathid_bgpitems_to(v, buf), + BgpAddrs::IPV4MDT(v) => encode_bgpitems_to(v, buf), + BgpAddrs::IPV4MDTP(v) => encode_pathid_bgpitems_to(v, buf), + BgpAddrs::IPV6MDT(v) => encode_bgpitems_to(v, buf), + BgpAddrs::IPV6MDTP(v) => encode_pathid_bgpitems_to(v, buf), } } } @@ -951,77 +1060,316 @@ impl std::fmt::Display for BgpAddrs { } #[cfg(feature = "serialization")] -impl serde::Serialize for MplsLabels { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_seq(Some(self.labels.len()))?; - for l in self.labels.iter() { - state.serialize_element(&l)?; +mod ser { + use super::*; + impl + std::fmt::Debug + serde::Serialize> serde::Serialize for WithRd { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("WithRd", 2)?; + state.serialize_field("rd", &self.rd)?; + state.serialize_field("prefix", &self.prefix)?; + state.end() } - state.end() } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpRD { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("RD", 2)?; - state.serialize_field("rdh", &self.rdh)?; - state.serialize_field("rdl", &self.rdl)?; - state.end() + enum WithRdField { + Rd, + Prefix, + } + const WITHRD_FIELDS: [&str; 2] = ["rd", "prefix"]; + impl<'de> de::Deserialize<'de> for WithRdField { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct FieldVisitor; + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = WithRdField; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("`rd` or `prefix`") + } + fn visit_str(self, value: &str) -> Result { + match value { + "rd" => Ok(WithRdField::Rd), + "prefix" => Ok(WithRdField::Prefix), + _ => Err(serde::de::Error::unknown_field(value, &WITHRD_FIELDS)), + } + } + } + deserializer.deserialize_identifier(FieldVisitor) + } } -} + struct WithRdVisitor { + d: std::marker::PhantomData, + } + impl<'de, T: BgpItem + de::Deserialize<'de>> de::Visitor<'de> for WithRdVisitor { + type Value = WithRd; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct WithRd") + } + fn visit_seq(self, mut seq: V) -> Result + where + V: serde::de::SeqAccess<'de>, + { + let rd = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let prefix = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + Ok(WithRd::new(rd, prefix)) + } -#[cfg(feature = "serialization")] -impl + std::fmt::Debug + serde::Serialize> serde::Serialize for WithRd { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("WithRd", 2)?; - state.serialize_field("rd", &self.rd)?; - state.serialize_field("prefix", &self.prefix)?; - state.end() + fn visit_map(self, mut map: V) -> Result + where + V: serde::de::MapAccess<'de>, + { + let mut rd = None; + let mut prefix = None; + while let Some(key) = map.next_key()? { + match key { + WithRdField::Rd => { + if rd.is_some() { + return Err(de::Error::duplicate_field(WITHRD_FIELDS[0])); + } + rd = Some(map.next_value()?); + } + WithRdField::Prefix => { + if prefix.is_some() { + return Err(de::Error::duplicate_field(WITHRD_FIELDS[1])); + } + prefix = Some(map.next_value()?); + } + } + } + let rd = rd.ok_or_else(|| de::Error::missing_field(WITHRD_FIELDS[0]))?; + let prefix = prefix.ok_or_else(|| de::Error::missing_field(WITHRD_FIELDS[1]))?; + Ok(WithRd::new(rd, prefix)) + } } -} + impl<'de, T: BgpItem + de::Deserialize<'de>> de::Deserialize<'de> for WithRd { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_struct( + "WithRd", + &WITHRD_FIELDS, + WithRdVisitor { + d: std::marker::PhantomData, + }, + ) + } + } + impl + serde::Serialize> serde::Serialize for Labeled { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("Labeled", 2)?; + state.serialize_field("labels", &self.labels)?; + state.serialize_field("prefix", &self.prefix)?; + state.end() + } + } + enum LabeledField { + Labels, + Prefix, + } + const LABELED_FIELDS: [&str; 2] = ["labels", "prefix"]; + impl<'de> de::Deserialize<'de> for LabeledField { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct FieldVisitor; + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = LabeledField; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("`labels` or `prefix`") + } + fn visit_str(self, value: &str) -> Result { + match value { + "labels" => Ok(LabeledField::Labels), + "prefix" => Ok(LabeledField::Prefix), + _ => Err(serde::de::Error::unknown_field(value, &LABELED_FIELDS)), + } + } + } + deserializer.deserialize_identifier(FieldVisitor) + } + } + struct LabeledVisitor { + d: std::marker::PhantomData, + } + impl<'de, T: BgpItem + de::Deserialize<'de>> de::Visitor<'de> for LabeledVisitor { + type Value = Labeled; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct Labeled") + } + fn visit_seq(self, mut seq: V) -> Result + where + V: serde::de::SeqAccess<'de>, + { + let labels = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let prefix = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + Ok(Labeled::new(labels, prefix)) + } -#[cfg(feature = "serialization")] -impl + std::fmt::Debug + serde::Serialize> serde::Serialize for Labeled { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, + fn visit_map(self, mut map: V) -> Result + where + V: serde::de::MapAccess<'de>, + { + let mut labels = None; + let mut prefix = None; + while let Some(key) = map.next_key()? { + match key { + LabeledField::Labels => { + if labels.is_some() { + return Err(de::Error::duplicate_field(LABELED_FIELDS[0])); + } + labels = Some(map.next_value()?); + } + LabeledField::Prefix => { + if prefix.is_some() { + return Err(de::Error::duplicate_field(LABELED_FIELDS[1])); + } + prefix = Some(map.next_value()?); + } + } + } + let labels = labels.ok_or_else(|| de::Error::missing_field(LABELED_FIELDS[0]))?; + let prefix = prefix.ok_or_else(|| de::Error::missing_field(LABELED_FIELDS[1]))?; + Ok(Labeled::new(labels, prefix)) + } + } + impl<'de, T: BgpItem + de::Deserialize<'de>> de::Deserialize<'de> for Labeled { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_struct( + "Labeled", + &LABELED_FIELDS, + LabeledVisitor { + d: std::marker::PhantomData, + }, + ) + } + } + impl + serde::Serialize + Clone + PartialEq + Eq + PartialOrd> serde::Serialize + for WithPathId { - let mut state = serializer.serialize_struct("Labeled", 2)?; - state.serialize_field("labels", &self.labels)?; - state.serialize_field("prefix", &self.prefix)?; - state.end() + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("WithPathId", 2)?; + state.serialize_field("pathid", &self.pathid)?; + state.serialize_field("nlri", &self.nlri)?; + state.end() + } } -} -#[cfg(feature = "serialization")] -impl + serde::Serialize + Clone + PartialEq + Eq + PartialOrd> serde::Serialize for WithPathId { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, + enum WithPathIdField { + Pathid, + Nlri, + } + const WITHPATHID_FIELDS: [&str; 2] = ["pathid", "nlri"]; + impl<'de> de::Deserialize<'de> for WithPathIdField { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct FieldVisitor; + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = WithPathIdField; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("`pathid` or `nlri`") + } + fn visit_str(self, value: &str) -> Result { + match value { + "pathid" => Ok(WithPathIdField::Pathid), + "nlri" => Ok(WithPathIdField::Nlri), + _ => Err(serde::de::Error::unknown_field(value, &WITHPATHID_FIELDS)), + } + } + } + deserializer.deserialize_identifier(FieldVisitor) + } + } + struct WithPathIdVisitor { + d: std::marker::PhantomData, + } + impl<'de, T: Clone + PartialEq + Eq + PartialOrd + de::Deserialize<'de>> de::Visitor<'de> + for WithPathIdVisitor { - let mut state = serializer.serialize_struct("WithPathId", 2)?; - state.serialize_field("pathid", &self.pathid)?; - state.serialize_field("nlri", &self.nlri)?; - state.end() + type Value = WithPathId; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("struct WithRd") + } + fn visit_seq(self, mut seq: V) -> Result + where + V: serde::de::SeqAccess<'de>, + { + let pathid = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let nlri = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + Ok(WithPathId::new(pathid, nlri)) + } + + fn visit_map(self, mut map: V) -> Result + where + V: serde::de::MapAccess<'de>, + { + let mut pathid = None; + let mut nlri = None; + while let Some(key) = map.next_key()? { + match key { + WithPathIdField::Pathid => { + if pathid.is_some() { + return Err(de::Error::duplicate_field(WITHPATHID_FIELDS[0])); + } + pathid = Some(map.next_value()?); + } + WithPathIdField::Nlri => { + if nlri.is_some() { + return Err(de::Error::duplicate_field(WITHPATHID_FIELDS[1])); + } + nlri = Some(map.next_value()?); + } + } + } + let pathid = pathid.ok_or_else(|| de::Error::missing_field(WITHRD_FIELDS[0]))?; + let nlri = nlri.ok_or_else(|| de::Error::missing_field(WITHRD_FIELDS[1]))?; + Ok(WithPathId::new(pathid, nlri)) + } } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAddr { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, + impl<'de, T: Clone + PartialEq + Eq + PartialOrd + de::Deserialize<'de>> de::Deserialize<'de> + for WithPathId { - serializer.serialize_str(format!("{}", self).as_str()) + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_struct( + "WithPathId", + &WITHPATHID_FIELDS, + WithPathIdVisitor { + d: std::marker::PhantomData, + }, + ) + } } } + #[cfg(test)] mod tests { use super::*; diff --git a/src/afi/mvpn.rs b/src/afi/mvpn.rs index bad5d6c..6b5a766 100644 --- a/src/afi/mvpn.rs +++ b/src/afi/mvpn.rs @@ -8,12 +8,15 @@ //! This module describes NLRI data structures for multicast vpn -use crate::*; use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP MVPN type 1 - Intra AS I-PMSI AD /// for example 1:10.255.170.100:1:10.255.170.100 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMVPN1 { pub rd: BgpRD, pub originator: std::net::IpAddr, @@ -55,6 +58,8 @@ impl BgpAddrItem for BgpMVPN1 { /// BGP MVPN type 2 - Inter AS I-PMSI AD /// for example 2:10.255.170.100:1:65000 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMVPN2 { pub rd: BgpRD, pub asn: u32, @@ -87,6 +92,8 @@ impl BgpAddrItem for BgpMVPN2 { /// BGP MVPN type 3 - S-PMSI AD /// for example 3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMVPN3 { pub rd: BgpRD, pub source: std::net::IpAddr, @@ -149,6 +156,8 @@ impl BgpAddrItem for BgpMVPN3 { /// BGP MVPN type 4 - Leaf AD /// for example 4:3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100:10.255.170.98 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMVPN4 { pub spmsi: BgpMVPN3, pub originator: std::net::IpAddr, @@ -189,6 +198,8 @@ impl BgpAddrItem for BgpMVPN4 { /// BGP MVPN type 5 - Source Active AD /// for example 5:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMVPN5 { pub rd: BgpRD, pub source: std::net::IpAddr, @@ -241,6 +252,8 @@ impl BgpAddrItem for BgpMVPN5 { /// for example 6:10.255.170.100:1:65000:32:10.12.53.12:32:224.1.2.3 /// 7:10.255.170.100:1:65000:32:192.168.194.2:32:224.1.2.3 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMVPN67 { pub rd: BgpRD, pub asn: u32, @@ -296,12 +309,14 @@ impl BgpAddrItem for BgpMVPN67 { } // BGP Multicast VPN NLRI #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub enum BgpMVPN { T1(BgpMVPN1), //Intra AS I-PMSI AD 1:10.255.170.100:1:10.255.170.100 T2(BgpMVPN2), //Inter AS I-PMSI AD 2:10.255.170.100:1:65000 - T3(BgpMVPN3), //S-PMSI AD 3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100 - T4(BgpMVPN4), //Leaf AD 4:3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100:10.255.170.98 - T5(BgpMVPN5), //Source Active AD 5:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3 + T3(BgpMVPN3), //S-PMSI AD 3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100 + T4(BgpMVPN4), //Leaf AD 4:3:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3:10.255.170.100:10.255.170.98 + T5(BgpMVPN5), //Source Active AD 5:10.255.170.100:1:32:192.168.194.2:32:224.1.2.3 T6(BgpMVPN67), //Shared Tree Join 6:10.255.170.100:1:65000:32:10.12.53.12:32:224.1.2.3 T7(BgpMVPN67), //Source Tree Join 7:10.255.170.100:1:65000:32:192.168.194.2:32:224.1.2.3 } @@ -392,13 +407,3 @@ impl BgpAddrItem for BgpMVPN { Ok(sz + 2) } } -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpMVPN { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) - } -} - diff --git a/src/afi/vpls.rs b/src/afi/vpls.rs index 005a687..ec77110 100644 --- a/src/afi/vpls.rs +++ b/src/afi/vpls.rs @@ -8,11 +8,14 @@ //! This module describes NLRI data structures for vpls -use crate::*; use crate::afi::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP VPLS NLRI #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpAddrL2 { pub rd: BgpRD, pub site: u16, @@ -39,15 +42,15 @@ impl BgpItemLong for BgpAddrL2 { }) } fn pack_to(&self, buf: &mut [u8]) -> Result { - if buf.len()<15 { + if buf.len() < 15 { return Err(BgpError::insufficient_buffer_size()); } self.rd.encode_rd_to(buf)?; - setn_u16(self.site,&mut buf[8..10]); - setn_u16(self.offset,&mut buf[10..12]); - setn_u16(self.range,&mut buf[12..14]); - let r=self.labels.set_bits_to(&mut buf[14..])?; - Ok(r.1+14) + setn_u16(self.site, &mut buf[8..10]); + setn_u16(self.offset, &mut buf[10..12]); + setn_u16(self.range, &mut buf[12..14]); + let r = self.labels.set_bits_to(&mut buf[14..])?; + Ok(r.1 + 14) } } impl std::fmt::Display for BgpAddrL2 { @@ -60,6 +63,8 @@ impl std::fmt::Display for BgpAddrL2 { } } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpL2 { pub rd: BgpRD, pub site: u16, @@ -110,19 +115,3 @@ impl BgpAddrItem for BgpL2 { Ok(pos + 6) } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAddrL2 { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpAddrL2", 5)?; - state.serialize_field("rd", &self.rd)?; - state.serialize_field("site", &self.site)?; - state.serialize_field("offset", &self.offset)?; - state.serialize_field("range", &self.range)?; - state.serialize_field("labels", &self.labels)?; - state.end() - } -} diff --git a/src/bmp/bmputl.rs b/src/bmp/bmputl.rs index c78e67a..760cec8 100644 --- a/src/bmp/bmputl.rs +++ b/src/bmp/bmputl.rs @@ -29,9 +29,10 @@ pub fn decode_bmp_addr_from(buf: &[u8]) -> Result { && buf[10] == 0 && buf[11] == 0 { - return Ok(std::net::IpAddr::V4(decode_addrv4_from(&buf[12..])?)); + Ok(std::net::IpAddr::V4(decode_addrv4_from(&buf[12..])?)) + } else { + Ok(std::net::IpAddr::V6(decode_addrv6_from(buf)?)) } - return Ok(std::net::IpAddr::V6(decode_addrv6_from(buf)?)); } /// peer header @@ -78,35 +79,35 @@ impl PartialOrd for BmpMessagePeerHeader { match pc { Ordering::Less => return Some(Ordering::Less), Ordering::Greater => return Some(Ordering::Greater), - Ordering::Equal => {}, + Ordering::Equal => {} } }; if let Some(pc) = self.flags.partial_cmp(&other.flags) { match pc { Ordering::Less => return Some(Ordering::Less), Ordering::Greater => return Some(Ordering::Greater), - Ordering::Equal => {}, + Ordering::Equal => {} } }; if let Some(pc) = self.peerdistinguisher.partial_cmp(&other.peerdistinguisher) { match pc { Ordering::Less => return Some(Ordering::Less), Ordering::Greater => return Some(Ordering::Greater), - Ordering::Equal => {}, + Ordering::Equal => {} } }; if let Some(pc) = self.peeraddress.partial_cmp(&other.peeraddress) { match pc { Ordering::Less => return Some(Ordering::Less), Ordering::Greater => return Some(Ordering::Greater), - Ordering::Equal => {}, + Ordering::Equal => {} } }; if let Some(pc) = self.asnum.partial_cmp(&other.asnum) { match pc { Ordering::Less => return Some(Ordering::Less), Ordering::Greater => return Some(Ordering::Greater), - Ordering::Equal => {}, + Ordering::Equal => {} } }; self.routerid.partial_cmp(&other.routerid) @@ -115,23 +116,23 @@ impl PartialOrd for BmpMessagePeerHeader { impl Ord for BmpMessagePeerHeader { fn cmp(&self, other: &Self) -> Ordering { match self.peertype.cmp(&other.peertype) { - Ordering::Equal => {}, + Ordering::Equal => {} x => return x, }; match self.flags.cmp(&other.flags) { - Ordering::Equal => {}, + Ordering::Equal => {} x => return x, }; match self.peerdistinguisher.cmp(&other.peerdistinguisher) { - Ordering::Equal => {}, + Ordering::Equal => {} x => return x, }; match self.peeraddress.cmp(&other.peeraddress) { - Ordering::Equal => {}, + Ordering::Equal => {} x => return x, }; match self.asnum.cmp(&other.asnum) { - Ordering::Equal => {}, + Ordering::Equal => {} x => return x, }; self.routerid.cmp(&other.routerid) diff --git a/src/bmp/mod.rs b/src/bmp/mod.rs index e191953..1cd4aa0 100644 --- a/src/bmp/mod.rs +++ b/src/bmp/mod.rs @@ -8,18 +8,18 @@ //! BGP Monitoring Protocol (BMP) processing - https://tools.ietf.org/html/rfc7854 +mod bmputl; mod msginit; -mod msgterm; mod msgpeer; -mod bmputl; mod msgrmon; +mod msgterm; pub mod prelude; use crate::*; -use msgrmon::BmpMessageRouteMonitoring; use msginit::BmpMessageInitiation; -use msgterm::BmpMessageTermination; use msgpeer::BmpMessagePeerUp; +use msgrmon::BmpMessageRouteMonitoring; +use msgterm::BmpMessageTermination; impl From for BgpError { #[inline] @@ -32,12 +32,12 @@ impl From for BgpError { #[derive(Debug)] pub enum BmpMessage { RouteMonitoring(BmpMessageRouteMonitoring), //0 - StatisticsReport, //1 - PeerDownNotification, //2 - PeerUpNotification(BmpMessagePeerUp), //3 - Initiation(BmpMessageInitiation), //4 - Termination(BmpMessageTermination), //5 - RouteMirroring //6 + StatisticsReport, //1 + PeerDownNotification, //2 + PeerUpNotification(BmpMessagePeerUp), //3 + Initiation(BmpMessageInitiation), //4 + Termination(BmpMessageTermination), //5 + RouteMirroring, //6 } /// BMP message header @@ -46,43 +46,47 @@ pub struct BmpMessageHeader { /// version - always 3 pub version: u8, /// total message length in bytes - pub msglength: usize + pub msglength: usize, } impl BmpMessageHeader { - pub fn decode_from( - buf: &[u8] - ) -> Result<(BmpMessageHeader,usize), BgpError> { - if buf.len()<5 { + pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageHeader, usize), BgpError> { + if buf.len() < 5 { return Err(BgpError::insufficient_buffer_size()); } - if buf[0]!=3 { + if buf[0] != 3 { return Err(BgpError::static_str("BMP packet version != 3")); } - Ok((BmpMessageHeader{ - version: buf[0], - msglength: getn_u32(&buf[1..5]) as usize, - },5)) + Ok(( + BmpMessageHeader { + version: buf[0], + msglength: getn_u32(&buf[1..5]) as usize, + }, + 5, + )) } } impl BmpMessage { - pub fn decode_from( - buf: &[u8] - ) -> Result { - let msgtype=buf[0]; + pub fn decode_from(buf: &[u8]) -> Result { + let msgtype = buf[0]; match msgtype { - 0 => Ok(BmpMessage::RouteMonitoring(BmpMessageRouteMonitoring::decode_from(&buf[1..])?.0)), - 1 => Ok(BmpMessage::StatisticsReport), - 2 => Ok(BmpMessage::PeerDownNotification), - 3 => Ok(BmpMessage::PeerUpNotification(BmpMessagePeerUp::decode_from(&buf[1..])?.0)), - 4 => Ok(BmpMessage::Initiation(BmpMessageInitiation::decode_from(&buf[1..])?.0)), - 5 => Ok(BmpMessage::Termination(BmpMessageTermination::decode_from(&buf[1..])?.0)), - 6 => Ok(BmpMessage::RouteMirroring), - _ => { - Err(BgpError::static_str("Invalid BMP message type")) - } + 0 => Ok(BmpMessage::RouteMonitoring( + BmpMessageRouteMonitoring::decode_from(&buf[1..])?.0, + )), + 1 => Ok(BmpMessage::StatisticsReport), + 2 => Ok(BmpMessage::PeerDownNotification), + 3 => Ok(BmpMessage::PeerUpNotification( + BmpMessagePeerUp::decode_from(&buf[1..])?.0, + )), + 4 => Ok(BmpMessage::Initiation( + BmpMessageInitiation::decode_from(&buf[1..])?.0, + )), + 5 => Ok(BmpMessage::Termination( + BmpMessageTermination::decode_from(&buf[1..])?.0, + )), + 6 => Ok(BmpMessage::RouteMirroring), + _ => Err(BgpError::static_str("Invalid BMP message type")), } } } - diff --git a/src/bmp/msginit.rs b/src/bmp/msginit.rs index 62989da..ebbc2fa 100644 --- a/src/bmp/msginit.rs +++ b/src/bmp/msginit.rs @@ -19,18 +19,22 @@ pub struct BmpInfoVal { } impl BmpInfoVal { - fn decode_from( - buf: &[u8] - ) -> Result<(BmpInfoVal,usize), BgpError> { - if buf.len()<4 { - return Err(BgpError::insufficient_buffer_size()) + fn decode_from(buf: &[u8]) -> Result<(BmpInfoVal, usize), BgpError> { + if buf.len() < 4 { + return Err(BgpError::insufficient_buffer_size()); }; let tp = getn_u16(buf); let ln = getn_u16(&buf[2..4]) as usize; - if ln>(buf.len()-4) { - return Err(BgpError::insufficient_buffer_size()) + if ln > (buf.len() - 4) { + return Err(BgpError::insufficient_buffer_size()); }; - Ok((BmpInfoVal{infotype:tp,info: core::str::from_utf8(&buf[4..4+ln])?.to_string()},ln+4)) + Ok(( + BmpInfoVal { + infotype: tp, + info: core::str::from_utf8(&buf[4..4 + ln])?.to_string(), + }, + ln + 4, + )) } } @@ -42,28 +46,35 @@ pub struct BmpMessageInitiation { /// system description pub sys_descr: Option, /// system name - pub sys_name: Option + pub sys_name: Option, } impl BmpMessageInitiation { pub fn new() -> BmpMessageInitiation { - BmpMessageInitiation{str0:None,sys_descr:None,sys_name:None} + BmpMessageInitiation { + str0: None, + sys_descr: None, + sys_name: None, + } } - pub fn decode_from( - buf: &[u8] - ) -> Result<(BmpMessageInitiation,usize), BgpError> { - let mut pos:usize=0; + pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageInitiation, usize), BgpError> { + let mut pos: usize = 0; let mut ret: BmpMessageInitiation = BmpMessageInitiation::new(); - while pos {ret.str0=Some(c.0.info)}, - 1 => {ret.sys_descr=Some(c.0.info)}, - 2 => {ret.sys_name=Some(c.0.info)}, + 0 => ret.str0 = Some(c.0.info), + 1 => ret.sys_descr = Some(c.0.info), + 2 => ret.sys_name = Some(c.0.info), _ => {} }; - pos+=c.1; - }; - Ok((ret,pos)) + pos += c.1; + } + Ok((ret, pos)) + } +} +impl Default for BmpMessageInitiation { + fn default() -> Self { + Self::new() } } diff --git a/src/bmp/msgpeer.rs b/src/bmp/msgpeer.rs index 6039df7..8baa129 100644 --- a/src/bmp/msgpeer.rs +++ b/src/bmp/msgpeer.rs @@ -6,9 +6,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::*; -use crate::message::*; use crate::bmp::bmputl::*; +use crate::message::*; +use crate::message::open::BgpOpenMessage; +use crate::util::*; +use crate::{BgpError, BgpMessage, BgpSessionParams}; #[derive(Debug)] pub struct BmpMessagePeerUp { @@ -17,40 +19,44 @@ pub struct BmpMessagePeerUp { pub localport: u16, pub remoteport: u16, pub msg1: BgpOpenMessage, - pub msg2: BgpOpenMessage + pub msg2: BgpOpenMessage, } impl BmpMessagePeerUp { - pub fn decode_from( - buf: &[u8] - ) -> Result<(BmpMessagePeerUp,usize), BgpError> { - if buf.len()<62 { - return Err(BgpError::insufficient_buffer_size()); + pub fn decode_from(buf: &[u8]) -> Result<(BmpMessagePeerUp, usize), BgpError> { + if buf.len() < 62 { + return Err(BgpError::InsufficientBufferSize); } let pm = BmpMessagePeerHeader::decode_from(buf)?; - let mut ret=BmpMessagePeerUp{ + let mut ret = BmpMessagePeerUp { peer: pm.0, localaddress: decode_bmp_addr_from(&buf[pm.1..])?, - localport: getn_u16(&buf[pm.1+16..]), - remoteport: getn_u16(&buf[pm.1+18..]), + localport: getn_u16(&buf[pm.1 + 16..]), + remoteport: getn_u16(&buf[pm.1 + 18..]), msg1: BgpOpenMessage::new(), msg2: BgpOpenMessage::new(), }; - let sesspars=BgpSessionParams::new(ret.peer.asnum, 180, ret.peer.peeraddress.into(), ret.peer.routerid, Vec::new()); - let mut pos:usize=pm.1+20; - let msgt=sesspars.decode_message_head(&buf[pos..])?; - pos+=19; - if msgt.0!=BgpMessageType::Open { - return Err(BgpError::static_str("Invalid BGP message type #1")) + let sesspars = BgpSessionParams::new( + ret.peer.asnum, + 180, + ret.peer.peeraddress.into(), + ret.peer.routerid, + Vec::new(), + ); + let mut pos: usize = pm.1 + 20; + let msgt = sesspars.decode_message_head(&buf[pos..])?; + pos += 19; + if msgt.0 != BgpMessageType::Open { + return Err(BgpError::static_str("Invalid BGP message type #1")); } - ret.msg1.decode_from(&sesspars, &buf[pos..pos+msgt.1])?; - pos+=msgt.1; - let msgt=sesspars.decode_message_head(&buf[pos..])?; - pos+=19; - if msgt.0!=BgpMessageType::Open { - return Err(BgpError::static_str("Invalid BGP message type #2")) + ret.msg1.decode_from(&sesspars, &buf[pos..pos + msgt.1])?; + pos += msgt.1; + let msgt = sesspars.decode_message_head(&buf[pos..])?; + pos += 19; + if msgt.0 != BgpMessageType::Open { + return Err(BgpError::static_str("Invalid BGP message type #2")); } - ret.msg2.decode_from(&sesspars, &buf[pos..pos+msgt.1])?; - pos+=msgt.1; - Ok((ret,pos)) + ret.msg2.decode_from(&sesspars, &buf[pos..pos + msgt.1])?; + pos += msgt.1; + Ok((ret, pos)) } } diff --git a/src/bmp/msgrmon.rs b/src/bmp/msgrmon.rs index 85b804d..a812b0d 100644 --- a/src/bmp/msgrmon.rs +++ b/src/bmp/msgrmon.rs @@ -8,10 +8,10 @@ //! BMP route monitoring message -use crate::*; use crate::bmp::bmputl::*; -use crate::message::*; use crate::message::update::BgpUpdateMessage; +use crate::message::*; +use crate::{BgpError, BgpMessage, BgpSessionParams}; /// BMP route monitoring message #[derive(Debug)] @@ -19,27 +19,33 @@ pub struct BmpMessageRouteMonitoring { /// peer header pub peer: BmpMessagePeerHeader, /// incapsulated BGP update message - pub update: BgpUpdateMessage + pub update: BgpUpdateMessage, } impl BmpMessageRouteMonitoring { - pub fn decode_from( - buf: &[u8] - ) -> Result<(BmpMessageRouteMonitoring,usize), BgpError> { - if buf.len()<62 { + pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageRouteMonitoring, usize), BgpError> { + if buf.len() < 62 { return Err(BgpError::insufficient_buffer_size()); } let pm = BmpMessagePeerHeader::decode_from(buf)?; - let mut pos=pm.1; - let sesspars: &BgpSessionParams= &(&pm.0).into(); - let msgt=sesspars.decode_message_head(&buf[pos..])?; - pos+=19; - if msgt.0!=BgpMessageType::Update { - return Err(BgpError::static_str("Invalid BGP message type for BmpMessageRouteMonitoring")) + let mut pos = pm.1; + let sesspars: &BgpSessionParams = &(&pm.0).into(); + let msgt = sesspars.decode_message_head(&buf[pos..])?; + pos += 19; + if msgt.0 != BgpMessageType::Update { + return Err(BgpError::static_str( + "Invalid BGP message type for BmpMessageRouteMonitoring", + )); } let mut upd = BgpUpdateMessage::new(); - upd.decode_from(sesspars, &buf[pos..pos+msgt.1])?; - pos=pos+msgt.1; - Ok((BmpMessageRouteMonitoring{peer:pm.0,update:upd},pos)) + upd.decode_from(sesspars, &buf[pos..pos + msgt.1])?; + pos += msgt.1; + Ok(( + BmpMessageRouteMonitoring { + peer: pm.0, + update: upd, + }, + pos, + )) } } diff --git a/src/bmp/msgterm.rs b/src/bmp/msgterm.rs index 23f9b2d..6767d5b 100644 --- a/src/bmp/msgterm.rs +++ b/src/bmp/msgterm.rs @@ -21,24 +21,30 @@ pub struct BmpMessageTermination { impl BmpMessageTermination { pub fn new() -> BmpMessageTermination { - BmpMessageTermination{str0:None,reason:None} + BmpMessageTermination { + str0: None, + reason: None, + } } - pub fn decode_from( - buf: &[u8] - ) -> Result<(BmpMessageTermination,usize), BgpError> { - let mut pos:usize=0; + pub fn decode_from(buf: &[u8]) -> Result<(BmpMessageTermination, usize), BgpError> { + let mut pos: usize = 0; let mut ret: BmpMessageTermination = BmpMessageTermination::new(); - while pos {ret.str0=Some(core::str::from_utf8(&buf[pos..pos+infolen])?.to_string())}, - 1 => {ret.reason=Some(getn_u16(&buf[pos..]))}, - _ => {} + 0 => ret.str0 = Some(core::str::from_utf8(&buf[pos..pos + infolen])?.to_string()), + 1 => ret.reason = Some(getn_u16(&buf[pos..])), + _ => {} } - pos+=infolen; - }; - Ok((ret,pos)) + pos += infolen; + } + Ok((ret, pos)) + } +} +impl Default for BmpMessageTermination { + fn default() -> Self { + Self::new() } } diff --git a/src/bmp/prelude.rs b/src/bmp/prelude.rs index 1d40a40..001cb69 100644 --- a/src/bmp/prelude.rs +++ b/src/bmp/prelude.rs @@ -16,9 +16,9 @@ //! use zettabgp::bmp::prelude::*; //! ``` -pub use crate::bmp::*; pub use crate::bmp::bmputl::*; pub use crate::bmp::msginit::*; pub use crate::bmp::msgpeer::*; pub use crate::bmp::msgrmon::*; pub use crate::bmp::msgterm::*; +pub use crate::bmp::*; diff --git a/src/error.rs b/src/error.rs index 1963fe4..8167b91 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,8 +17,11 @@ #[derive(Debug)] pub enum BgpError { Static(&'static str), + InsufficientBufferSize, + ProtocolError, + TooManyData, DynStr(std::string::String), - Other(Box) + Other(Box), } impl BgpError { @@ -38,24 +41,30 @@ impl BgpError { BgpError::Other(e) } /// Just says that buffer size is too small. + #[inline] pub fn insufficient_buffer_size() -> BgpError { - BgpError::Static("Insufficient buffer size") + BgpError::InsufficientBufferSize } /// Just says that we have common protocol error. + #[inline] pub fn protocol_error() -> BgpError { - BgpError::Static("Protocol error") + BgpError::ProtocolError } /// Just says that data size is too big to be encoded. + #[inline] pub fn too_many_data() -> BgpError { - BgpError::Static("Too many data") + BgpError::TooManyData } } impl std::fmt::Display for BgpError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { + BgpError::InsufficientBufferSize => write!(f, "BgpError InsufficientBufferSize"), + BgpError::ProtocolError => write!(f, "BgpError ProtocolError"), + BgpError::TooManyData => write!(f, "BgpError TooManyData"), BgpError::Static(s) => write!(f, "BgpError {}", s), BgpError::DynStr(s) => write!(f, "BgpError {}", s), - BgpError::Other(e) => write!(f, "BgpError {}",e) + BgpError::Other(e) => write!(f, "BgpError {}", e), } } } @@ -74,4 +83,3 @@ impl From for BgpError { BgpError::Other(Box::new(error)) } } - diff --git a/src/lib.rs b/src/lib.rs index 1150ae6..510b7ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,14 +114,6 @@ impl From for BgpTransportMode { } } -/// This trait represens NLRI which have sequental chain encoding with opaque length. -pub trait BgpAddrItem { - /// Decode from buffer. Returns entity and consumed buffer length, or error. - fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(T, usize), BgpError>; - /// Encode entity into the buffer. Returns consumed buffer length, or error. - fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result; -} - /// This trait represens BGP protocol message. pub trait BgpMessage { /// Decode from buffer. @@ -130,6 +122,14 @@ pub trait BgpMessage { fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result; } +/// This trait represens NLRI which have sequental chain encoding with opaque length. +pub trait BgpAddrItem { + /// Decode from buffer. Returns entity and consumed buffer length, or error. + fn decode_from(mode: BgpTransportMode, buf: &[u8]) -> Result<(T, usize), BgpError>; + /// Encode entity into the buffer. Returns consumed buffer length, or error. + fn encode_to(&self, mode: BgpTransportMode, buf: &mut [u8]) -> Result; +} + /// BGP capability AddPath. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct BgpCapAddPath { @@ -156,11 +156,13 @@ impl BgpCapAddPath { BgpCapability::SafiIPv4u => (1, 1), BgpCapability::SafiIPv4m => (1, 4), BgpCapability::SafiIPv4mvpn => (1, 5), + BgpCapability::SafiIPv4mdt => (1, 66), BgpCapability::SafiVPNv4u => (1, 128), BgpCapability::SafiVPNv4m => (1, 129), BgpCapability::SafiIPv4lu => (1, 2), BgpCapability::SafiIPv6u => (2, 1), BgpCapability::SafiIPv6lu => (2, 4), + BgpCapability::SafiIPv6mdt => (2, 66), BgpCapability::SafiVPNv6u => (2, 128), BgpCapability::SafiVPNv6m => (2, 129), BgpCapability::SafiVPLS => (25, 65), @@ -170,8 +172,8 @@ impl BgpCapAddPath { Ok(BgpCapAddPath { afi: afisafi.0, safi: afisafi.1, - send: send, - receive: receive, + send, + receive, }) } pub fn encode_to(&self, buf: &mut [u8]) -> Result<(), BgpError> { @@ -214,6 +216,8 @@ pub enum BgpCapability { SafiVPNv4m, /// BGP capability ipv4 labeled unicast. SafiIPv4lu, + /// BGP capability ipv4 mdt. + SafiIPv4mdt, /// BGP capability ipv6 unicast. SafiIPv6u, /// BGP capability ipv6 labeled unicast. @@ -224,6 +228,8 @@ pub enum BgpCapability { SafiVPNv6u, /// BGP capability vpnv6 multicast. SafiVPNv6m, + /// BGP capability ipv6 mdt. + SafiIPv6mdt, /// BGP capability VPLS. SafiVPLS, /// BGP capability EVPN. @@ -248,9 +254,11 @@ impl BgpCapability { BgpCapability::SafiVPNv4fu => 6, BgpCapability::SafiVPNv4m => 6, BgpCapability::SafiIPv4lu => 6, + BgpCapability::SafiIPv4mdt => 6, BgpCapability::SafiIPv6u => 6, BgpCapability::SafiIPv6lu => 6, BgpCapability::SafiIPv6fu => 6, + BgpCapability::SafiIPv6mdt => 6, BgpCapability::SafiVPNv6u => 6, BgpCapability::SafiVPNv6m => 6, BgpCapability::SafiVPLS => 6, @@ -287,6 +295,9 @@ impl BgpCapability { BgpCapability::SafiIPv4lu => { buf.clone_from_slice(&[1, 4, 0, 1, 0, 2]); } + BgpCapability::SafiIPv4mdt => { + buf.clone_from_slice(&[1, 4, 0, 1, 0, 66]); + } BgpCapability::SafiIPv6u => { buf.clone_from_slice(&[1, 4, 0, 2, 0, 1]); } @@ -296,6 +307,9 @@ impl BgpCapability { BgpCapability::SafiIPv6lu => { buf.clone_from_slice(&[1, 4, 0, 2, 0, 4]); } + BgpCapability::SafiIPv6mdt => { + buf.clone_from_slice(&[1, 4, 0, 2, 0, 66]); + } BgpCapability::SafiVPNv6u => { buf.clone_from_slice(&[1, 4, 0, 2, 0, 128]); } @@ -337,7 +351,7 @@ impl BgpCapability { Ok(()) } /// Decode capability code from given buffer. Returns capability and consumed buffer length. - fn from_buffer(buf: &[u8]) -> Result<(BgpCapability, usize), BgpError> { + pub fn from_buffer(buf: &[u8]) -> Result<(BgpCapability, usize), BgpError> { if buf.len() >= 6 && buf[0] == 1 && buf[1] == 4 && buf[2] == 0 { //safi if buf[3] == 1 && buf[4] == 0 { @@ -347,6 +361,7 @@ impl BgpCapability { 2 => Ok((BgpCapability::SafiIPv4lu, 6)), 4 => Ok((BgpCapability::SafiIPv4m, 6)), 5 => Ok((BgpCapability::SafiIPv4mvpn, 6)), + 7 => Ok((BgpCapability::SafiIPv4mdt, 6)), 128 => Ok((BgpCapability::SafiVPNv4u, 6)), 129 => Ok((BgpCapability::SafiVPNv4m, 6)), 133 => Ok((BgpCapability::SafiIPv4fu, 6)), @@ -358,6 +373,7 @@ impl BgpCapability { match buf[5] { 1 => Ok((BgpCapability::SafiIPv6u, 6)), 4 => Ok((BgpCapability::SafiIPv6lu, 6)), + 7 => Ok((BgpCapability::SafiIPv6mdt, 6)), 128 => Ok((BgpCapability::SafiVPNv6u, 6)), 129 => Ok((BgpCapability::SafiVPNv6m, 6)), 133 => Ok((BgpCapability::SafiIPv6fu, 6)), @@ -432,7 +448,7 @@ impl BgpSessionParams { let mut bom = BgpOpenMessage::new(); bom.as_num = self.as_num; bom.router_id = self.router_id; - bom.caps = self.caps.iter().cloned().collect(); + bom.caps = self.caps.clone(); bom.hold_time = self.hold_time; bom } @@ -440,25 +456,19 @@ impl BgpSessionParams { pub fn check_caps(&mut self) { self.has_as32bit = false; for cap in self.caps.iter() { - match cap { - BgpCapability::CapASN32(n) => { - self.has_as32bit = true; - if self.as_num != 0 && self.as_num != 23456 && self.as_num != *n { - eprintln!( - "Warning: Capability 32-bit AS mismatch AS number: {:?}!={:?}", - self.as_num, *n - ); - } - self.as_num = *n; + if let BgpCapability::CapASN32(n) = cap { + self.has_as32bit = true; + if self.as_num != 0 && self.as_num != 23456 && self.as_num != *n { + eprintln!( + "Warning: Capability 32-bit AS mismatch AS number: {:?}!={:?}", + self.as_num, *n + ); } - _ => {} + self.as_num = *n; } } } - fn match_addpath_caps( - vcaps: &Vec, - rcaps: &Vec, - ) -> Vec { + fn match_addpath_caps(vcaps: &[BgpCapAddPath], rcaps: &[BgpCapAddPath]) -> Vec { vcaps .iter() .map(|vq| { @@ -471,23 +481,16 @@ impl BgpSessionParams { .collect() } /// Match capability set - pub fn match_caps(&mut self, rcaps: &Vec) { + pub fn match_caps(&mut self, rcaps: &[BgpCapability]) { self.has_as32bit = false; let nv = self .caps .iter() - .map(|x| match x { + .filter_map(|x| match x { BgpCapability::CapASN32(_) => { if rcaps .iter() - .find(|q| { - if let BgpCapability::CapASN32(_) = q { - true - } else { - false - } - }) - .is_some() + .any(|q| matches!(q, BgpCapability::CapASN32(_))) { Some((*x).clone()) } else { @@ -495,32 +498,24 @@ impl BgpSessionParams { } } BgpCapability::CapAddPath(cap) => { - match rcaps.iter().find(|q| { - if let BgpCapability::CapAddPath(_) = q { - true - } else { - false - } - }) { - None => None, - Some(ocap) => match ocap { - BgpCapability::CapAddPath(icap) => Some(BgpCapability::CapAddPath( - Self::match_addpath_caps(cap, icap), - )), - _ => None, - }, + match rcaps + .iter() + .find(|q| matches!(q, BgpCapability::CapAddPath(_))) + { + Some(BgpCapability::CapAddPath(icap)) => Some(BgpCapability::CapAddPath( + Self::match_addpath_caps(cap, icap), + )), + _ => None, } } _ => { - if rcaps.iter().find(|q| **q == *x).is_some() { + if rcaps.iter().any(|q| *q == *x) { Some((*x).clone()) } else { None } } }) - .filter(|x| x.is_some()) - .map(|x| x.unwrap()) .collect(); self.caps = nv; self.check_caps(); @@ -528,13 +523,10 @@ impl BgpSessionParams { /// Search for specified addpath capability. pub fn find_addpath(&self, afi: u16, safi: u8) -> Option<&BgpCapAddPath> { for cap in self.caps.iter() { - match cap { - BgpCapability::CapAddPath(cap) => { - if let Some(r) = cap.iter().find(|ap| ap.afi == afi && ap.safi == safi) { - return Some(r); - } + if let BgpCapability::CapAddPath(mcap) = cap { + if let Some(r) = mcap.iter().find(|ap| ap.afi == afi && ap.safi == safi) { + return Some(r); } - _ => {} } } None @@ -555,7 +547,40 @@ impl BgpSessionParams { } /// Check for capability pub fn check_capability(&self, cp: &BgpCapability) -> bool { - self.caps.iter().find(|x| *x == cp).is_some() + self.caps.iter().any(|x| x == cp) + } + /// Remove capability + pub fn remove_capability(&mut self, cp: &BgpCapability) { + match cp { + BgpCapability::CapASN32(_) => self + .caps + .retain(|x| !matches!(x, BgpCapability::CapASN32(_))), + BgpCapability::CapAddPath(vc) => { + match self + .caps + .iter_mut() + .find(|x| matches!(x, BgpCapability::CapAddPath(_))) + { + None => return, + Some(ref mut q) => { + if let BgpCapability::CapAddPath(ref mut cvc) = q { + for cp in vc.iter() { + cvc.retain(|x| *x != *cp) + } + }; + }, + }; + self.caps.retain(|x| match x { + BgpCapability::CapAddPath(vc) => !vc.is_empty(), + _ => true, + }) + } + n => self.caps.retain(|x| *x != *n), + } + } + pub fn remove_capability_addpath(&mut self) { + self.caps + .retain(|x| !matches!(x, BgpCapability::CapAddPath(_))); } /// Decode message head from buffer. Returns following message kind and length. pub fn decode_message_head( @@ -580,7 +605,7 @@ impl BgpSessionParams { &mut self, rdsrc: &mut impl std::io::Read, ) -> Result<(message::BgpMessageType, usize), BgpError> { - let mut buf = [0 as u8; 19]; + let mut buf = [0_u8; 19]; rdsrc.read_exact(&mut buf)?; self.decode_message_head(&buf) } @@ -594,7 +619,7 @@ impl BgpSessionParams { if buf.len() < (messagelen + 19) { return Err(BgpError::insufficient_buffer_size()); } - buf[0..16].clone_from_slice(&[255 as u8; 16]); + buf[0..16].clone_from_slice(&[255_u8; 16]); let lng: u16 = (messagelen as u16) + 19; buf[16] = (lng >> 8) as u8; buf[17] = (lng & 0xff) as u8; @@ -612,7 +637,7 @@ impl BgpSessionParams { if buf.len() < (messagelen + 19) { return Err(BgpError::insufficient_buffer_size()); } - buf[0..16].clone_from_slice(&[255 as u8; 16]); + buf[0..16].clone_from_slice(&[255_u8; 16]); let lng: u16 = (messagelen as u16) + 19; buf[16] = (lng >> 8) as u8; buf[17] = (lng & 0xff) as u8; @@ -623,3 +648,55 @@ impl BgpSessionParams { } } } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_capabilities_remove() { + let mut params = BgpSessionParams::new( + 64512, + 180, + BgpTransportMode::IPv4, + std::net::Ipv4Addr::new(1, 1, 1, 1), + vec![ + BgpCapability::SafiIPv4u, + BgpCapability::CapAddPath(vec![ + BgpCapAddPath { + afi: 1, + safi: 1, + send: true, + receive: true, + }, + BgpCapAddPath { + afi: 1, + safi: 2, + send: true, + receive: true, + }, + ]), + ] + .into_iter() + .collect(), + ); + assert_eq!(params.caps.len(), 2); + params.remove_capability(&BgpCapability::SafiIPv4u); + assert_eq!(params.caps.len(), 1); + params.remove_capability(&BgpCapability::SafiIPv4u); + assert_eq!(params.caps.len(), 1); + params.remove_capability(&BgpCapability::CapAddPath(vec![BgpCapAddPath { + afi: 1, + safi: 1, + send: true, + receive: true, + }])); + assert_eq!(params.caps.len(), 1); + params.remove_capability(&BgpCapability::CapAddPath(vec![BgpCapAddPath { + afi: 1, + safi: 2, + send: true, + receive: true, + }])); + assert_eq!(params.caps.len(), 0); + } +} diff --git a/src/message/attributes/aggregatoras.rs b/src/message/attributes/aggregatoras.rs index 08d883b..8b39c55 100644 --- a/src/message/attributes/aggregatoras.rs +++ b/src/message/attributes/aggregatoras.rs @@ -8,13 +8,14 @@ //! BGP "Aggregator AS" path attribute -use crate::*; use crate::message::attributes::*; #[cfg(feature = "serialization")] -use serde::ser::{SerializeStruct}; +use serde::{Deserialize, Serialize}; /// BGP "Aggregator AS" path attribute struct #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpAggregatorAS { /// Autonomous system number pub asn: u32, @@ -22,32 +23,23 @@ pub struct BgpAggregatorAS { pub addr: std::net::Ipv4Addr, } impl BgpAggregatorAS { - pub fn decode_from( - peer: &BgpSessionParams, - buf: &[u8], - ) -> Result { + pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { if peer.has_as32bit { if buf.len() == 8 { Ok(BgpAggregatorAS { - asn: getn_u32(&buf), + asn: getn_u32(buf), addr: decode_addrv4_from(&buf[4..8])?, }) } else { - Err(BgpError::static_str( - "Invalid AggregatorAS 32-bit length", - )) + Err(BgpError::static_str("Invalid AggregatorAS 32-bit length")) } + } else if buf.len() == 6 { + Ok(BgpAggregatorAS { + asn: getn_u16(buf) as u32, + addr: decode_addrv4_from(&buf[2..6])?, + }) } else { - if buf.len() == 6 { - Ok(BgpAggregatorAS { - asn: getn_u16(&buf) as u32, - addr: decode_addrv4_from(&buf[2..6])?, - }) - } else { - Err(BgpError::static_str( - "Invalid AggregatorAS 16-bit length", - )) - } + Err(BgpError::static_str("Invalid AggregatorAS 16-bit length")) } } } @@ -71,23 +63,7 @@ impl BgpAttr for BgpAggregatorAS { flags: 64, } } - fn encode_to( - &self, - peer: &BgpSessionParams, - _buf: &mut [u8], - ) -> Result { + fn encode_to(&self, peer: &BgpSessionParams, _buf: &mut [u8]) -> Result { Ok(if peer.has_as32bit { 4 } else { 2 }) } } -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAggregatorAS { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("AggregatorAS", 2)?; - state.serialize_field("addr", &self.addr)?; - state.serialize_field("asn", &self.asn)?; - state.end() - } -} \ No newline at end of file diff --git a/src/message/attributes/aspath.rs b/src/message/attributes/aspath.rs index d077261..be46061 100644 --- a/src/message/attributes/aspath.rs +++ b/src/message/attributes/aspath.rs @@ -8,24 +8,31 @@ //! BGP "ASpath" path attribute -use crate::*; +use std::cmp::Ordering; +use std::hash::{Hash, Hasher}; use crate::message::attributes::*; #[cfg(feature = "serialization")] -use serde::ser::{SerializeSeq}; +use serde::{Deserialize, Serialize}; /// BGP AS - element of aspath -#[derive(Clone, Copy, Debug, Hash, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpAS { pub value: u32, } /// BGP as-path path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpASpath { pub value: Vec, } impl BgpAS { - pub fn new(v:u32) -> BgpAS { + pub fn new(v: u32) -> BgpAS { BgpAS { value: v } } pub fn tonumb(&self) -> u32 { @@ -46,6 +53,22 @@ impl PartialEq for BgpAS { self.tonumb() == other.tonumb() } } +impl Eq for BgpAS{} +impl PartialOrd for BgpAS { + fn partial_cmp(&self, other: &Self) -> Option { + self.value.partial_cmp(&other.value) + } +} +impl Ord for BgpAS { + fn cmp(&self, other: &Self) -> Ordering { + self.value.cmp(&other.value) + } +} +impl Hash for BgpAS { + fn hash(&self, state: &mut H) { + self.value.hash(state) + } +} impl std::fmt::Display for BgpAS { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { if (self.value & 0xffff) == 0 { @@ -64,10 +87,7 @@ impl BgpASpath { value: sv.into_iter().map(|q| q.into()).collect(), } } - pub fn decode_from( - peer: &BgpSessionParams, - buf: &[u8], - ) -> Result { + pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { if buf.len() < 2 { return Ok(BgpASpath { value: Vec::new() }); } @@ -90,6 +110,11 @@ impl BgpASpath { Ok(BgpASpath { value: v }) } } +impl Default for BgpASpath { + fn default() -> Self { + Self::new() + } +} impl std::fmt::Debug for BgpASpath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("BgpASpath") @@ -109,29 +134,25 @@ impl BgpAttr for BgpASpath { flags: 0x50, } } - fn encode_to( - &self, - peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { + fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { let mut pos: usize; - if self.value.len()<1 { - return Ok(0); - } + if self.value.is_empty() { + return Ok(0); + } if peer.has_as32bit { - if buf.len()<(2+self.value.len()*4) { + if buf.len() < (2 + self.value.len() * 4) { return Err(BgpError::insufficient_buffer_size()); } - buf[0]=2;//as-sequence - buf[1]=self.value.len() as u8; - pos=2; + buf[0] = 2; //as-sequence + buf[1] = self.value.len() as u8; + pos = 2; } else { - if buf.len()<(2+self.value.len()*2) { + if buf.len() < (2 + self.value.len() * 2) { return Err(BgpError::insufficient_buffer_size()); } - buf[0]=2;//as-sequence - buf[1]=self.value.len() as u8; - pos=2; + buf[0] = 2; //as-sequence + buf[1] = self.value.len() as u8; + pos = 2; } for i in &self.value { if peer.has_as32bit { @@ -145,26 +166,3 @@ impl BgpAttr for BgpASpath { Ok(pos) } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAS { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpASpath { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_seq(Some(self.value.len()))?; - for l in self.value.iter() { - state.serialize_element(&l)?; - } - state.end() - } -} diff --git a/src/message/attributes/atomicaggregate.rs b/src/message/attributes/atomicaggregate.rs index 43e6d5e..5813064 100644 --- a/src/message/attributes/atomicaggregate.rs +++ b/src/message/attributes/atomicaggregate.rs @@ -8,11 +8,15 @@ //! BGP "Atomic aggregate" path attribute -use crate::*; use crate::message::attributes::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP Atmic aggregate path attribute #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpAtomicAggregate { pub value: std::net::IpAddr, } @@ -22,7 +26,7 @@ impl BgpAtomicAggregate { buf: &[u8], ) -> Result { Ok(BgpAtomicAggregate { - value: if buf.len() == 0 { + value: if buf.is_empty() { std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)) } else { decode_addr_from(buf)? @@ -39,7 +43,7 @@ impl std::fmt::Debug for BgpAtomicAggregate { } impl std::fmt::Display for BgpAtomicAggregate { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "BgpAtomicAggregate {:?}", self.value) + self.value.fmt(f) } } impl BgpAttr for BgpAtomicAggregate { @@ -49,21 +53,7 @@ impl BgpAttr for BgpAtomicAggregate { flags: 64, } } - fn encode_to( - &self, - _peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { + fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { encode_addr_to(&self.value, buf) } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAtomicAggregate { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.value.to_string().as_str()) - } -} diff --git a/src/message/attributes/attrset.rs b/src/message/attributes/attrset.rs index 95b5d86..5897903 100644 --- a/src/message/attributes/attrset.rs +++ b/src/message/attributes/attrset.rs @@ -10,10 +10,12 @@ use crate::message::attributes::*; #[cfg(feature = "serialization")] -use serde::ser::SerializeStruct; +use serde::{Deserialize, Serialize}; /// BGP attribute set path attribute struct #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpAttrSet { /// Originating autonomous system number pub asn: u32, @@ -21,23 +23,18 @@ pub struct BgpAttrSet { pub attrs: Vec, } impl BgpAttrSet { - pub fn decode_from( - peer: &BgpSessionParams, - buf: &[u8], - ) -> Result { + pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { if !peer.has_as32bit { return Err(BgpError::static_str( "Invalid BgpAttrSet without 32-bit AS support", )); } if buf.len() < 4 { - return Err(BgpError::static_str( - "Invalid BgpAttrSet buffer length", - )); + return Err(BgpError::static_str("Invalid BgpAttrSet buffer length")); } - let mut attrs=Vec::::new(); - let mut curpos=4; - while curpos::new(); + let mut curpos = 4; + while curpos < buf.len() { let flags = buf[curpos]; let tc = buf[curpos + 1]; let attrlen = if (flags & 16) > 0 { @@ -60,8 +57,8 @@ impl BgpAttrSet { curpos += attrlen; } Ok(BgpAttrSet { - asn: getn_u32(&buf), - attrs: attrs, + asn: getn_u32(buf), + attrs, }) } } @@ -85,23 +82,7 @@ impl BgpAttr for BgpAttrSet { flags: 224, } } - fn encode_to( - &self, - _peer: &BgpSessionParams, - _buf: &mut [u8], - ) -> Result { + fn encode_to(&self, _peer: &BgpSessionParams, _buf: &mut [u8]) -> Result { unimplemented!() } } -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAttrSet { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpAttrSet", 2)?; - state.serialize_field("asn", &self.asn)?; - state.serialize_field("attrs", &self.attrs)?; - state.end() - } -} diff --git a/src/message/attributes/clusterlist.rs b/src/message/attributes/clusterlist.rs index ed98a0b..af23936 100644 --- a/src/message/attributes/clusterlist.rs +++ b/src/message/attributes/clusterlist.rs @@ -10,10 +10,13 @@ use crate::message::attributes::*; #[cfg(feature = "serialization")] -use serde::ser::SerializeSeq; +use serde::{Deserialize, Serialize}; /// BGP clustr list path attribute struct #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpClusterList { pub value: Vec, } @@ -59,16 +62,3 @@ impl BgpAttr for BgpClusterList { Ok(pos) } } -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpClusterList { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_seq(Some(self.value.len()))?; - for l in self.value.iter() { - state.serialize_element(&l)?; - } - state.end() - } -} diff --git a/src/message/attributes/community.rs b/src/message/attributes/community.rs index 5810e10..1717d8d 100644 --- a/src/message/attributes/community.rs +++ b/src/message/attributes/community.rs @@ -8,25 +8,32 @@ //! BGP "community list" path attributes -use crate::*; use crate::message::attributes::*; -use std::str::FromStr; #[cfg(feature = "serialization")] -use serde::ser::{SerializeSeq}; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; /// BGP community - element for BgpCommunityList path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpCommunity { pub value: u32, } /// BGP community list path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpCommunityList { pub value: std::collections::BTreeSet, } /// BGP large community - element for BgpLargeCommunityList path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpLargeCommunity { pub ga: u32, pub ldp1: u32, @@ -34,6 +41,9 @@ pub struct BgpLargeCommunity { } /// BGP community list path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpLargeCommunityList { pub value: std::collections::BTreeSet, } @@ -50,13 +60,13 @@ impl BgpLargeCommunity { )), } } - pub fn encode_to(&self,buf: &mut [u8]) -> Result { - if buf.len()<12 { + pub fn encode_to(&self, buf: &mut [u8]) -> Result { + if buf.len() < 12 { return Err(BgpError::insufficient_buffer_size()); } - setn_u32(self.ga,buf); - setn_u32(self.ldp1,&mut buf[4..8]); - setn_u32(self.ldp2,&mut buf[8..12]); + setn_u32(self.ga, buf); + setn_u32(self.ldp1, &mut buf[4..8]); + setn_u32(self.ldp2, &mut buf[8..12]); Ok(12) } } @@ -109,23 +119,22 @@ impl BgpAttr for BgpLargeCommunityList { flags: 224, } } - fn encode_to( - &self, - _peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { + fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { let mut pos: usize = 0; for i in &self.value { - pos+=i.encode_to(&mut buf[pos..])?; + pos += i.encode_to(&mut buf[pos..])?; } Ok(pos) } } +impl Default for BgpLargeCommunityList { + fn default() -> Self { + Self::new() + } +} impl BgpCommunity { pub fn new(v: u32) -> BgpCommunity { - BgpCommunity { - value: v - } + BgpCommunity { value: v } } pub fn from(h: u16, l: u16) -> BgpCommunity { BgpCommunity { @@ -135,21 +144,16 @@ impl BgpCommunity { pub fn decode_from(buf: &[u8]) -> Result { match buf.len() { 4 => Ok(BgpCommunity { - value: getn_u32(&buf), + value: getn_u32(buf), }), - _ => Err(BgpError::static_str( - "Invalid BgpCommunity item length", - )), + _ => Err(BgpError::static_str("Invalid BgpCommunity item length")), } } - fn encode_to( - &self, - buf: &mut [u8], - ) -> Result { - if buf.len()<4 { - return Err(BgpError::insufficient_buffer_size()) + fn encode_to(&self, buf: &mut [u8]) -> Result { + if buf.len() < 4 { + return Err(BgpError::insufficient_buffer_size()); }; - setn_u32(self.value,buf); + setn_u32(self.value, buf); Ok(4) } } @@ -176,11 +180,15 @@ impl FromStr for BgpCommunity { fn from_str(s: &str) -> Result { let parts: Vec<&str> = s.trim().split(':').collect(); if parts.len() < 2 { - Ok(BgpCommunity{value:parts[0].parse()?}) - } else if parts.len()<3 { - Ok(BgpCommunity{value:(parts[0].parse::()? as u32) << 16 | (parts[1].parse::()? as u32)}) + Ok(BgpCommunity { + value: parts[0].parse()?, + }) + } else if parts.len() < 3 { + Ok(BgpCommunity { + value: (parts[0].parse::()? as u32) << 16 | (parts[1].parse::()? as u32), + }) } else { - Ok(BgpCommunity{value:s.parse()?}) + Ok(BgpCommunity { value: s.parse()? }) } } } @@ -194,10 +202,15 @@ impl BgpCommunityList { } pub fn from_vec(v: Vec) -> BgpCommunityList { BgpCommunityList { - value: v.into_iter().collect() + value: v.into_iter().collect(), } } } +impl Default for BgpCommunityList { + fn default() -> Self { + Self::new() + } +} impl BgpCommunityList { pub fn decode_from(buf: &[u8]) -> Result { let mut pos: usize = 0; @@ -225,17 +238,16 @@ impl FromStr for BgpCommunityList { type Err = BgpError; fn from_str(s: &str) -> Result { - let strs:Vec::<&str>=s.split(&[',', ' ', '\t'][..]).collect(); + let strs: Vec<&str> = s.split(&[',', ' ', '\t'][..]).collect(); let mut v = std::collections::BTreeSet::new(); for s in strs.iter() { - if let Ok(c) = s.parse() { - v.insert(c); - } + if let Ok(c) = s.parse() { + v.insert(c); + } } Ok(BgpCommunityList { value: v }) } } - impl BgpAttr for BgpCommunityList { fn attr(&self) -> BgpAttrParams { BgpAttrParams { @@ -243,64 +255,15 @@ impl BgpAttr for BgpCommunityList { flags: 192, } } - fn encode_to( - &self, - _peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { - if buf.len() Result { + if buf.len() < self.value.len() * 4 { return Err(BgpError::insufficient_buffer_size()); } let mut curpos: usize = 0; for c in &self.value { - let lng=c.encode_to(&mut buf[curpos..])?; - curpos+=lng; + let lng = c.encode_to(&mut buf[curpos..])?; + curpos += lng; } Ok(curpos) } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpCommunity { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpCommunityList { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_seq(Some(self.value.len()))?; - for l in self.value.iter() { - state.serialize_element(&l)?; - } - state.end() - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpLargeCommunity { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.to_string().as_str()) - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpLargeCommunityList { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_seq(Some(self.value.len()))?; - for l in self.value.iter() { - state.serialize_element(&l)?; - } - state.end() - } -} \ No newline at end of file diff --git a/src/message/attributes/connector.rs b/src/message/attributes/connector.rs new file mode 100644 index 0000000..716fe99 --- /dev/null +++ b/src/message/attributes/connector.rs @@ -0,0 +1,80 @@ +// Copyright 2021-2022 Vladimir Melnikov. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! BGP "connector" path attribute + +use crate::message::attributes::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; +use std::net::Ipv4Addr; + +/// BGP local preference path attribute +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +pub struct BgpConnector { + pub asn: u32, + pub addr: Ipv4Addr, + pub orig: Ipv4Addr, +} +impl BgpConnector { + pub fn new(asn: u32, addr: Ipv4Addr, orig: Ipv4Addr) -> BgpConnector { + BgpConnector { asn, addr, orig } + } + pub fn decode_from(buf: &[u8]) -> Result { + if buf.len() >= 14 { + if getn_u16(buf) != 1 { + return Err(BgpError::static_str("Unknown Connector type")); + } + Ok(BgpConnector { + asn: getn_u32(&buf[2..6]), + addr: decode_addrv4_from(&buf[6..10])?, + orig: decode_addrv4_from(&buf[10..14])?, + }) + } else { + Err(BgpError::static_str("Invalid Connector length")) + } + } +} +impl std::fmt::Debug for BgpConnector { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BgpConnector") + .field("asn", &self.asn) + .field("addr", &self.addr) + .field("orig", &self.orig) + .finish() + } +} +impl std::fmt::Display for BgpConnector { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "BgpConnector({:?}:{:?} @{:?})", + self.asn, self.addr, self.orig + ) + } +} +impl BgpAttr for BgpConnector { + fn attr(&self) -> BgpAttrParams { + BgpAttrParams { + typecode: 20, + flags: 192, + } + } + fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { + if buf.len() >= 14 { + setn_u16(1, buf); + setn_u32(self.asn, &mut buf[2..6]); + encode_addrv4_to(&self.addr, &mut buf[6..10])?; + encode_addrv4_to(&self.orig, &mut buf[10..14])?; + Ok(14) + } else { + Err(BgpError::static_str("Invalid localpref length")) + } + } +} diff --git a/src/message/attributes/extcommunity.rs b/src/message/attributes/extcommunity.rs index f9014b3..1dfb6fc 100644 --- a/src/message/attributes/extcommunity.rs +++ b/src/message/attributes/extcommunity.rs @@ -10,10 +10,12 @@ use crate::message::attributes::*; #[cfg(feature = "serialization")] -use serde::ser::SerializeSeq; +use serde::{Deserialize, Serialize}; /// BGP extended community - element for BgpExtCommunityList path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpExtCommunity { pub ctype: u8, pub subtype: u8, @@ -155,6 +157,9 @@ impl std::fmt::Display for BgpExtCommunity { /// BGP extended community list path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpExtCommunityList { pub value: std::collections::BTreeSet, } @@ -181,6 +186,11 @@ impl BgpExtCommunityList { Ok(BgpExtCommunityList { value: v }) } } +impl Default for BgpExtCommunityList { + fn default() -> Self { + Self::new() + } +} impl std::fmt::Debug for BgpExtCommunityList { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("BgpExtCommunityList") @@ -209,25 +219,3 @@ impl BgpAttr for BgpExtCommunityList { Ok(pos) } } -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpExtCommunity { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpExtCommunityList { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_seq(Some(self.value.len()))?; - for l in self.value.iter() { - state.serialize_element(&l)?; - } - state.end() - } -} diff --git a/src/message/attributes/localpref.rs b/src/message/attributes/localpref.rs index 0d79e8f..de24ff9 100644 --- a/src/message/attributes/localpref.rs +++ b/src/message/attributes/localpref.rs @@ -8,25 +8,26 @@ //! BGP "local preference" path attribute -use crate::*; use crate::message::attributes::*; - +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP local preference path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpLocalpref { pub value: u32, } impl BgpLocalpref { pub fn new(v: u32) -> BgpLocalpref { - BgpLocalpref { - value: v - } + BgpLocalpref { value: v } } pub fn decode_from(buf: &[u8]) -> Result { if buf.len() >= 4 { Ok(BgpLocalpref { - value: getn_u32(&buf), + value: getn_u32(buf), }) } else { Err(BgpError::static_str("Invalid localpref length")) @@ -52,11 +53,7 @@ impl BgpAttr for BgpLocalpref { flags: 64, } } - fn encode_to( - &self, - _peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { + fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { if buf.len() >= 4 { setn_u32(self.value, buf); Ok(4) @@ -65,13 +62,3 @@ impl BgpAttr for BgpLocalpref { } } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpLocalpref { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_u32(self.value) - } -} diff --git a/src/message/attributes/med.rs b/src/message/attributes/med.rs index eeb9b2e..ec679b8 100644 --- a/src/message/attributes/med.rs +++ b/src/message/attributes/med.rs @@ -9,9 +9,14 @@ //! BGP "multi-exit discriminator" path attribute use crate::message::attributes::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP MED (multi-exit discriminator) path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpMED { pub value: u32, } @@ -22,7 +27,7 @@ impl BgpMED { pub fn decode_from(buf: &[u8]) -> Result { if buf.len() >= 4 { Ok(BgpMED { - value: getn_u32(&buf), + value: getn_u32(buf), }) } else { Err(BgpError::static_str("Invalid MED length")) @@ -57,13 +62,3 @@ impl BgpAttr for BgpMED { } } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpMED { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_u32(self.value) - } -} diff --git a/src/message/attributes/mod.rs b/src/message/attributes/mod.rs index 974445a..cd43c97 100644 --- a/src/message/attributes/mod.rs +++ b/src/message/attributes/mod.rs @@ -14,6 +14,7 @@ pub mod atomicaggregate; pub mod attrset; pub mod clusterlist; pub mod community; +pub mod connector; pub mod extcommunity; pub mod localpref; pub mod med; @@ -24,7 +25,7 @@ pub mod originatorid; pub mod pmsitunnelattr; pub mod unknown; #[cfg(feature = "serialization")] -use serde::ser::SerializeMap; +use serde::{Deserialize, Serialize}; use aggregatoras::BgpAggregatorAS; use aspath::BgpASpath; @@ -32,6 +33,7 @@ use atomicaggregate::BgpAtomicAggregate; use attrset::BgpAttrSet; use clusterlist::BgpClusterList; use community::{BgpCommunityList, BgpLargeCommunityList}; +use connector::BgpConnector; use extcommunity::BgpExtCommunityList; use localpref::BgpLocalpref; use med::BgpMED; @@ -44,22 +46,22 @@ use unknown::BgpAttrUnknown; /// BGP path attribute mandatory parameters - typecode and flags #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpAttrParams { pub typecode: u8, pub flags: u8, } pub trait BgpAttr: std::fmt::Display + std::fmt::Debug { - fn encode_to( - &self, - peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result; + fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result; fn attr(&self) -> BgpAttrParams; } /// BGP path attribute -#[derive(Debug,Hash,PartialOrd,Ord,PartialEq,Eq)] +#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub enum BgpAttrItem { Origin(BgpOrigin), ASPath(BgpASpath), @@ -77,6 +79,7 @@ pub enum BgpAttrItem { LargeCommunityList(BgpLargeCommunityList), PMSITunnel(BgpPMSITunnel), AttrSet(BgpAttrSet), + Connector(BgpConnector), Unknown(BgpAttrUnknown), } @@ -121,10 +124,11 @@ impl BgpAttrItem { 22 => Ok(BgpAttrItem::PMSITunnel(BgpPMSITunnel::decode_from( peer, buf, )?)), + 20 => Ok(BgpAttrItem::Connector(BgpConnector::decode_from(buf)?)), 32 => Ok(BgpAttrItem::LargeCommunityList( BgpLargeCommunityList::decode_from(buf)?, )), - 20 | 21 => + 21 => //deprecated { Ok(BgpAttrItem::Unknown(BgpAttrUnknown::decode_from( @@ -169,26 +173,18 @@ impl BgpAttrItem { let attrlen = attr.encode_to(peer, &mut buf[curpos..])?; if (attrparams.flags & 16) > 0 { if attrlen > 65535 { - return Err(BgpError::static_str( - "Invalid path attribute length", - )); + return Err(BgpError::static_str("Invalid path attribute length")); } setn_u16(attrlen as u16, &mut buf[2..4]); } else { if attrlen > 255 { - return Err(BgpError::static_str( - "Invalid path attribute length", - )); + return Err(BgpError::static_str("Invalid path attribute length")); } buf[2] = attrlen as u8; } Ok(curpos + attrlen) } - pub fn encode_to( - &self, - peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { + pub fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { match self { BgpAttrItem::Origin(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), BgpAttrItem::ASPath(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), @@ -206,38 +202,8 @@ impl BgpAttrItem { BgpAttrItem::LargeCommunityList(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), BgpAttrItem::PMSITunnel(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), BgpAttrItem::AttrSet(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), + BgpAttrItem::Connector(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), BgpAttrItem::Unknown(pa) => BgpAttrItem::encode_bgpattr(pa, peer, buf), } } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAttrItem { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_map(Some(1))?; - match self { - BgpAttrItem::Origin(pa) => state.serialize_entry("Origin",pa)?, - BgpAttrItem::ASPath(pa) => state.serialize_entry("ASPath",pa)?, - BgpAttrItem::NextHop(pa) => state.serialize_entry("NextHop",pa)?, - BgpAttrItem::MED(pa) => state.serialize_entry("MED",pa)?, - BgpAttrItem::LocalPref(pa) => state.serialize_entry("LocalPref",pa)?, - BgpAttrItem::AtomicAggregate(pa) => state.serialize_entry("AtomicAggregate",pa)?, - BgpAttrItem::AggregatorAS(pa) => state.serialize_entry("AggregatorAS",pa)?, - BgpAttrItem::CommunityList(pa) => state.serialize_entry("CommunityList",pa)?, - BgpAttrItem::OriginatorID(pa) => state.serialize_entry("OriginatorID",pa)?, - BgpAttrItem::ClusterList(pa) => state.serialize_entry("ClusterList",pa)?, - //BgpAttrItem::MPUpdates(pa) => state.serialize_entry("MPUpdates",pa), - //BgpAttrItem::MPWithdraws(pa) => state.serialize_entry("MPWithdraws",pa), - BgpAttrItem::ExtCommunityList(pa) => state.serialize_entry("ExtCommunityList",pa)?, - BgpAttrItem::LargeCommunityList(pa) => state.serialize_entry("LargeCommunityList",pa)?, - BgpAttrItem::PMSITunnel(pa) => state.serialize_entry("PMSITunnel",pa)?, - BgpAttrItem::AttrSet(pa) => state.serialize_entry("AttrSet",pa)?, - BgpAttrItem::Unknown(pa) => state.serialize_entry("Unknown",pa)?, - _ => {} - }; - state.end() - } -} diff --git a/src/message/attributes/multiproto.rs b/src/message/attributes/multiproto.rs index fcd8770..28ed744 100644 --- a/src/message/attributes/multiproto.rs +++ b/src/message/attributes/multiproto.rs @@ -8,10 +8,13 @@ //! BGP multiprotocol update and withdraw path attributes, which carries routing information with mp-bgp use crate::prelude::*; -use crate::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP multiprotocol updates #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMPUpdates { /// next hop for this updates pub nexthop: BgpAddr, @@ -62,7 +65,7 @@ impl BgpMPUpdates { } } pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { - let afi = getn_u16(&buf); + let afi = getn_u16(buf); let safi = buf[2]; let mut curpos: usize = 4; let nh: BgpAddr; @@ -71,8 +74,8 @@ impl BgpMPUpdates { 1 => { //ipv4 match safi { - 1 | 2 | 4 | 5 | 133 => { - //unicast|multicast|labeled unicast|mvpn|flow + 1 | 2 | 4 | 5 | 66 | 133 => { + //unicast|multicast|labeled unicast|mvpn|mdt|flow nh = BgpAddr::V4(decode_addrv4_from(&buf[curpos..(curpos + nhlen)])?); curpos += nhlen; } @@ -94,8 +97,8 @@ impl BgpMPUpdates { 2 => { //ipv6 match safi { - 1 | 2 | 4 => { - //unicast|multicast|labeled unicast + 1 | 2 | 4 | 66 => { + //unicast|multicast|labeled unicast|mdt nh = BgpAddr::V6(decode_addrv6_from(&buf[curpos..(curpos + nhlen)])?); curpos += nhlen; } @@ -172,8 +175,8 @@ impl BgpAttr for BgpMPUpdates { let mut curpos: usize = 4; let nhl = match &self.nexthop { BgpAddr::None => 0, - BgpAddr::V4(a) => encode_addrv4_to(&a, &mut buf[curpos..])?, - BgpAddr::V6(a) => encode_addrv6_to(&a, &mut buf[curpos..])?, + BgpAddr::V4(a) => encode_addrv4_to(a, &mut buf[curpos..])?, + BgpAddr::V6(a) => encode_addrv6_to(a, &mut buf[curpos..])?, BgpAddr::V4RD(a) => a.encode_to(peer.peer_mode, &mut buf[curpos..])?, BgpAddr::V6RD(a) => a.encode_to(peer.peer_mode, &mut buf[curpos..])?, _ => return Err(BgpError::static_str("Invalid nexthop kind")), @@ -190,13 +193,15 @@ impl BgpAttr for BgpMPUpdates { /// BGP multiprotocol withdraws #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpMPWithdraws { /// NLRI pub addrs: BgpAddrs, } impl BgpMPWithdraws { pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { - let afi = getn_u16(&buf); + let afi = getn_u16(buf); let safi = buf[2]; let a = BgpAddrs::decode_from(peer, afi, safi, &buf[3..])?; Ok(BgpMPWithdraws { addrs: a.0 }) diff --git a/src/message/attributes/nexthop.rs b/src/message/attributes/nexthop.rs index b1f3a1a..7cc477d 100644 --- a/src/message/attributes/nexthop.rs +++ b/src/message/attributes/nexthop.rs @@ -7,26 +7,25 @@ // except according to those terms. //! BGP nexthop path attribute - -use crate::*; + use crate::message::attributes::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP nexthop #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpNextHop { /// next hop itself pub value: std::net::IpAddr, } impl BgpNextHop { pub fn new(v: std::net::IpAddr) -> BgpNextHop { - BgpNextHop{ - value: v - } + BgpNextHop { value: v } } - pub fn decode_from( - peer: &BgpSessionParams, - buf: &[u8], - ) -> Result { + pub fn decode_from(peer: &BgpSessionParams, buf: &[u8]) -> Result { if peer.peer_mode == BgpTransportMode::IPv6 && buf.len() >= 16 { return Ok(BgpNextHop { value: std::net::IpAddr::V6(decode_addrv6_from(buf)?), @@ -59,17 +58,13 @@ impl BgpAttr for BgpNextHop { flags: 64, } } - fn encode_to( - &self, - peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { - if let std::net::IpAddr::V6(v)=self.value { + fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result { + if let std::net::IpAddr::V6(v) = self.value { if peer.peer_mode == BgpTransportMode::IPv6 && buf.len() >= 16 { return encode_addrv6_to(&v, buf); } }; - if let std::net::IpAddr::V4(v)=self.value { + if let std::net::IpAddr::V4(v) = self.value { if peer.peer_mode == BgpTransportMode::IPv4 && buf.len() >= 4 { return encode_addrv4_to(&v, buf); } @@ -77,13 +72,3 @@ impl BgpAttr for BgpNextHop { Err(BgpError::static_str("Invalid nexthop type")) } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpNextHop { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.value.to_string().as_str()) - } -} diff --git a/src/message/attributes/origin.rs b/src/message/attributes/origin.rs index bd3d1f9..e3c4d8b 100644 --- a/src/message/attributes/origin.rs +++ b/src/message/attributes/origin.rs @@ -8,11 +8,14 @@ //! BGP origin path attribute -use crate::*; use crate::message::attributes::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; /// BGP origin value #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub enum BgpAttrOrigin { Igp, Egp, @@ -30,18 +33,19 @@ impl std::fmt::Display for BgpAttrOrigin { /// BGP origin path attribute #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpOrigin { pub value: BgpAttrOrigin, } impl BgpOrigin { - pub fn new(v:BgpAttrOrigin) -> BgpOrigin { - BgpOrigin{value:v} + pub fn new(v: BgpAttrOrigin) -> BgpOrigin { + BgpOrigin { value: v } } pub fn decode_from(buf: &[u8]) -> Result { - if buf.len() < 1 { - Err(BgpError::static_str( - "Invalid PA len for BgpOrigin", - )) + if buf.is_empty() { + Err(BgpError::InsufficientBufferSize) } else { match buf[0] { 0 => Ok(BgpOrigin { @@ -53,9 +57,7 @@ impl BgpOrigin { 2 => Ok(BgpOrigin { value: BgpAttrOrigin::Incomplete, }), - _ => Err(BgpError::static_str( - "Invalid value for BgpOrigin", - )), + _ => Err(BgpError::static_str("Invalid value for BgpOrigin")), } } } @@ -90,15 +92,9 @@ impl BgpAttr for BgpOrigin { flags: 64, } } - fn encode_to( - &self, - _peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { - if buf.len() < 1 { - Err(BgpError::static_str( - "Invalid PA len for BgpOrigin", - )) + fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { + if buf.is_empty() { + Err(BgpError::InsufficientBufferSize) } else { match self.value { BgpAttrOrigin::Igp => { @@ -117,26 +113,3 @@ impl BgpAttr for BgpOrigin { } } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAttrOrigin { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(match self { - BgpAttrOrigin::Igp => "I", - BgpAttrOrigin::Egp => "E", - _ => "?", - }) - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpOrigin { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.value.to_string().as_str()) - } -} \ No newline at end of file diff --git a/src/message/attributes/originatorid.rs b/src/message/attributes/originatorid.rs index 0823efc..c34be44 100644 --- a/src/message/attributes/originatorid.rs +++ b/src/message/attributes/originatorid.rs @@ -9,10 +9,15 @@ //! BGP originator id path attribute use crate::message::attributes::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; use std::net::IpAddr; /// BGP originator id path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpOriginatorID { pub value: IpAddr, } @@ -73,13 +78,3 @@ impl BgpAttr for BgpOriginatorID { } } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpOriginatorID { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.value.to_string().as_str()) - } -} diff --git a/src/message/attributes/pmsitunnelattr.rs b/src/message/attributes/pmsitunnelattr.rs index ea231c7..73513c6 100644 --- a/src/message/attributes/pmsitunnelattr.rs +++ b/src/message/attributes/pmsitunnelattr.rs @@ -10,8 +10,12 @@ use crate::afi::{BgpItem, MplsLabels}; use crate::message::attributes::*; +#[cfg(feature = "serialization")] +use serde::{Deserialize, Serialize}; #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpPMSITaRSVP { pub ext_tunnel_id: std::net::Ipv4Addr, pub reserved: u16, @@ -22,12 +26,15 @@ impl std::fmt::Display for BgpPMSITaRSVP { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, - "RSVP tunnel:{}:{}:{}:{}", + "RSVP-TE P2MP LSP:{}:{}:{}:{}", self.ext_tunnel_id, self.reserved, self.tunnel_id, self.p2mp_id ) } } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct BgpPMSITaIngressRepl { pub endpoint: std::net::Ipv4Addr, } @@ -36,13 +43,27 @@ impl std::fmt::Display for BgpPMSITaIngressRepl { write!(f, "Ingress replication:{}", self.endpoint) } } - +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] +pub struct BgpPMSITaMLDP { + pub rootnode: std::net::IpAddr, + pub opaque: Vec, +} +impl std::fmt::Display for BgpPMSITaMLDP { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "mLDP P2MP LSP:{}", self.rootnode) + } +} /// PMSI tunnel attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub enum BgpPMSITunnelAttr { None, RSVPTe(BgpPMSITaRSVP), IngressRepl(BgpPMSITaIngressRepl), + MLDP(BgpPMSITaMLDP), } impl std::fmt::Display for BgpPMSITunnelAttr { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -50,18 +71,32 @@ impl std::fmt::Display for BgpPMSITunnelAttr { BgpPMSITunnelAttr::None => "".fmt(f), BgpPMSITunnelAttr::RSVPTe(r) => r.fmt(f), BgpPMSITunnelAttr::IngressRepl(r) => r.fmt(f), + BgpPMSITunnelAttr::MLDP(r) => r.fmt(f), } } } -/// BGP Path attribute for PMSI tunnel +/// BGP Path attribute for PMSI tunnel RFC6514 #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpPMSITunnel { pub flags: u8, pub tunnel_type: u8, pub label: MplsLabels, pub tunnel_attribute: BgpPMSITunnelAttr, } +/* + tunnel_type + + 0 - No tunnel information present + + 1 - RSVP-TE P2MP LSP + + 2 - mLDP P2MP LSP + + 3 - PIM-SSM Tree + + 4 - PIM-SM Tree + + 5 - BIDIR-PIM Tree + + 6 - Ingress Replication + + 7 - mLDP MP2MP LSP +*/ impl BgpPMSITunnel { pub fn decode_from(_peer: &BgpSessionParams, buf: &[u8]) -> Result { if buf.len() < 5 { @@ -95,6 +130,39 @@ impl BgpPMSITunnel { ), }) } + 2 => { + if buf[5] != 6 { + return Err(BgpError::from_string(format!( + "Unknown PMSI tunnel type mLDP p2mp: {}", + buf[5] + ))); + } + if buf.len() < 16 { + return Err(BgpError::from_string(format!( + "PMSI tunnel type mLDP p2mp too short: {}", + buf.len() + ))); + } + if getn_u16(&buf[6..8]) != 1 { + return Err(BgpError::Static("Invalid root node address family")); + } + if buf[8] != 4 { + return Err(BgpError::Static("Invalid root node address length")); + } + let rootnode = decode_addr_from(&buf[9..13])?; + let opaquelen = getn_u16(&buf[13..15]) as usize; + if buf.len() < (15 + opaquelen) { + return Err(BgpError::from_string(format!( + "PMSI tunnel type mLDP p2mp too short: {} < 15+{}", + buf.len(), + opaquelen + ))); + } + BgpPMSITunnelAttr::MLDP(BgpPMSITaMLDP { + rootnode, + opaque: buf[15..(15 + opaquelen)].to_vec(), + }) + } 6 => //Ingress replication { @@ -147,19 +215,3 @@ impl BgpAttr for BgpPMSITunnel { unimplemented!(); } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpPMSITunnel { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(format!("{}", self).as_str()) - /* - let mut state = serializer.serialize_struct("BgpPMSITunnel", 2)?; - state.serialize_field("flags", &self.flags)?; - state.serialize_field("tunnel_type", &self.tunnel_type)?; - state.end() - */ - } -} diff --git a/src/message/attributes/unknown.rs b/src/message/attributes/unknown.rs index dde0d14..994ee16 100644 --- a/src/message/attributes/unknown.rs +++ b/src/message/attributes/unknown.rs @@ -8,13 +8,14 @@ //! BGP unsupported path attributes -use crate::*; use crate::message::attributes::*; #[cfg(feature = "serialization")] -use serde::ser::{SerializeStruct}; +use serde::{Deserialize, Serialize}; /// Unsupported BGP path attribute #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg(feature = "serialization")] +#[derive(Serialize, Deserialize)] pub struct BgpAttrUnknown { /// PA typecode&flags pub params: BgpAttrParams, @@ -22,20 +23,16 @@ pub struct BgpAttrUnknown { pub value: Vec, } impl BgpAttrUnknown { - pub fn new(tc: u8, flg: u8) -> Box { - Box::new(BgpAttrUnknown { + pub fn new(tc: u8, flg: u8) -> BgpAttrUnknown { + BgpAttrUnknown { params: BgpAttrParams { typecode: tc, flags: flg, }, value: Vec::new(), - }) + } } - pub fn decode_from( - tc: u8, - flg: u8, - buf: &[u8], - ) -> Result { + pub fn decode_from(tc: u8, flg: u8, buf: &[u8]) -> Result { let mut ret = BgpAttrUnknown { params: BgpAttrParams { typecode: tc, @@ -72,37 +69,8 @@ impl BgpAttr for BgpAttrUnknown { flags: 64, } } - fn encode_to( - &self, - _peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { + fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { buf[0..self.value.len()].clone_from_slice(self.value.as_slice()); Ok(self.value.len()) } } - -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAttrParams { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpAttrParams", 2)?; - state.serialize_field("typecode", &self.typecode)?; - state.serialize_field("flags", &self.flags)?; - state.end() - } -} -#[cfg(feature = "serialization")] -impl serde::Serialize for BgpAttrUnknown { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut state = serializer.serialize_struct("BgpAttrUnknown", 2)?; - state.serialize_field("params", &self.params)?; - state.serialize_field("value", &self.value)?; - state.end() - } -} \ No newline at end of file diff --git a/src/message/keepalive.rs b/src/message/keepalive.rs index 15c2f2f..8e2c8e4 100644 --- a/src/message/keepalive.rs +++ b/src/message/keepalive.rs @@ -13,18 +13,10 @@ use crate::*; pub struct BgpKeepaliveMessage {} impl BgpMessage for BgpKeepaliveMessage { - fn decode_from( - &mut self, - _peer: &BgpSessionParams, - _buf: &[u8], - ) -> Result<(), BgpError> { + fn decode_from(&mut self, _peer: &BgpSessionParams, _buf: &[u8]) -> Result<(), BgpError> { Ok(()) } - fn encode_to( - &self, - _peer: &BgpSessionParams, - _buf: &mut [u8], - ) -> Result { + fn encode_to(&self, _peer: &BgpSessionParams, _buf: &mut [u8]) -> Result { Ok(0) } } diff --git a/src/message/mod.rs b/src/message/mod.rs index 71ea7b2..266d151 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -8,27 +8,21 @@ //! This module contains BGP messages -use crate::*; use crate::error::*; +use crate::*; +pub mod attributes; +pub mod keepalive; +pub mod notification; pub mod open; +pub use open::*; pub mod update; -pub mod notification; -pub mod keepalive; -pub mod attributes; +pub use update::*; /// trait BgpMessage represents BGP protocol message pub trait BgpMessage { - fn decode_from( - &mut self, - peer: &BgpSessionParams, - buf: &[u8], - ) -> Result<(), BgpError>; - fn encode_to( - &self, - peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result; + fn decode_from(&mut self, peer: &BgpSessionParams, buf: &[u8]) -> Result<(), BgpError>; + fn encode_to(&self, peer: &BgpSessionParams, buf: &mut [u8]) -> Result; } /// Bgp message type: open, update, notification or keepalive. @@ -61,4 +55,3 @@ impl BgpMessageType { } } } - diff --git a/src/message/notification.rs b/src/message/notification.rs index 36d4a5d..2322dc2 100644 --- a/src/message/notification.rs +++ b/src/message/notification.rs @@ -10,11 +10,11 @@ use crate::{BgpError, BgpMessage, BgpSessionParams}; /// BGP notification message pub struct BgpNotificationMessage { -/// error code + /// error code pub error_code: u8, -/// error sub-code + /// error sub-code pub error_subcode: u8, -/// extra data + /// extra data pub data: u16, } impl BgpNotificationMessage { @@ -48,6 +48,7 @@ impl BgpNotificationMessage { 4 => String::from("Unsupported Optional Parameter"), 5 => String::from("Deprecated(5)"), 6 => String::from("Unacceptable Hold Time"), + 7 => String::from("Unsupported capability"), n => String::from(" subcode ") + n.to_string().as_str(), }) .as_str() @@ -127,16 +128,15 @@ impl std::fmt::Display for BgpNotificationMessage { ) } } +impl Default for BgpNotificationMessage { + fn default() -> Self { + Self::new() + } +} impl BgpMessage for BgpNotificationMessage { - fn decode_from( - &mut self, - _peer: &BgpSessionParams, - buf: &[u8], - ) -> Result<(), BgpError> { + fn decode_from(&mut self, _peer: &BgpSessionParams, buf: &[u8]) -> Result<(), BgpError> { if buf.len() < 2 { - return Err(BgpError::static_str( - "Invalid notification message length", - )); + return Err(BgpError::static_str("Invalid notification message length")); } self.error_code = buf[0]; self.error_subcode = buf[1]; @@ -148,15 +148,9 @@ impl BgpMessage for BgpNotificationMessage { } Ok(()) } - fn encode_to( - &self, - _peer: &BgpSessionParams, - buf: &mut [u8], - ) -> Result { + fn encode_to(&self, _peer: &BgpSessionParams, buf: &mut [u8]) -> Result { if buf.len() < 4 { - return Err(BgpError::static_str( - "Invalid notification message length", - )); + return Err(BgpError::static_str("Invalid notification message length")); } buf[0] = self.error_code; buf[1] = self.error_subcode; diff --git a/src/message/open.rs b/src/message/open.rs index 183cd7a..1bb9ddd 100644 --- a/src/message/open.rs +++ b/src/message/open.rs @@ -102,14 +102,18 @@ impl BgpMessage for BgpOpenMessage { Ok(pos) } } - impl BgpOpenMessage { pub fn new() -> BgpOpenMessage { - return BgpOpenMessage { + BgpOpenMessage { as_num: 0, hold_time: 180, router_id: std::net::Ipv4Addr::new(127, 0, 0, 1), caps: Vec::new(), - }; + } + } +} +impl Default for BgpOpenMessage { + fn default() -> Self { + Self::new() } } diff --git a/src/message/update/mod.rs b/src/message/update/mod.rs index 85157c5..3d59f92 100644 --- a/src/message/update/mod.rs +++ b/src/message/update/mod.rs @@ -33,11 +33,8 @@ impl BgpUpdateMessage { /// returns origin attribute. pub fn get_attr_origin(&self) -> Option<&BgpOrigin> { for i in self.attrs.iter() { - match i { - BgpAttrItem::Origin(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::Origin(n) = i { + return Some(n); } } None @@ -45,11 +42,8 @@ impl BgpUpdateMessage { /// returns aspath attribute. pub fn get_attr_aspath(&self) -> Option<&BgpASpath> { for i in self.attrs.iter() { - match i { - BgpAttrItem::ASPath(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::ASPath(n) = i { + return Some(n); } } None @@ -57,11 +51,8 @@ impl BgpUpdateMessage { /// returns community list attribute. pub fn get_attr_communitylist(&self) -> Option<&BgpCommunityList> { for i in self.attrs.iter() { - match i { - BgpAttrItem::CommunityList(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::CommunityList(n) = i { + return Some(n); } } None @@ -69,11 +60,8 @@ impl BgpUpdateMessage { /// returns large community list attribute. pub fn get_attr_largecommunitylist(&self) -> Option<&BgpLargeCommunityList> { for i in self.attrs.iter() { - match i { - BgpAttrItem::LargeCommunityList(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::LargeCommunityList(n) = i { + return Some(n); } } None @@ -81,11 +69,8 @@ impl BgpUpdateMessage { /// returns extended community list attribute. pub fn get_attr_extcommunitylist(&self) -> Option<&BgpExtCommunityList> { for i in self.attrs.iter() { - match i { - BgpAttrItem::ExtCommunityList(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::ExtCommunityList(n) = i { + return Some(n); } } None @@ -93,11 +78,8 @@ impl BgpUpdateMessage { /// returns next hop attribute. pub fn get_attr_nexthop(&self) -> Option<&BgpNextHop> { for i in self.attrs.iter() { - match i { - BgpAttrItem::NextHop(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::NextHop(n) = i { + return Some(n); } } None @@ -105,11 +87,8 @@ impl BgpUpdateMessage { /// returns MPUpdates pub fn get_mpupdates(&self) -> Option<&BgpMPUpdates> { for i in self.attrs.iter() { - match i { - BgpAttrItem::MPUpdates(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::MPUpdates(n) = i { + return Some(n); } } None @@ -117,16 +96,18 @@ impl BgpUpdateMessage { /// returns MPWithdraws pub fn get_mpwithdraws(&self) -> Option<&BgpMPWithdraws> { for i in self.attrs.iter() { - match i { - BgpAttrItem::MPWithdraws(n) => { - return Some(&n); - } - _ => {} + if let BgpAttrItem::MPWithdraws(n) = i { + return Some(n); } } None } } +impl Default for BgpUpdateMessage { + fn default() -> Self { + Self::new() + } +} impl BgpMessage for BgpUpdateMessage { fn decode_from(&mut self, peer: &BgpSessionParams, buf: &[u8]) -> Result<(), BgpError> { let mut curpos: usize = 0; @@ -216,7 +197,7 @@ impl BgpMessage for BgpUpdateMessage { match peer.peer_mode { BgpTransportMode::IPv4 => match self.withdraws { BgpAddrs::IPV4U(ref wdrw) => { - let wlen = encode_bgpitems_to(&wdrw, &mut buf[curpos + 2..])?; + let wlen = encode_bgpitems_to(wdrw, &mut buf[curpos + 2..])?; if wlen > 65535 { return Err(BgpError::too_many_data()); } @@ -224,7 +205,7 @@ impl BgpMessage for BgpUpdateMessage { curpos += 2 + wlen; } BgpAddrs::IPV4UP(ref wdrw) => { - let wlen = encode_pathid_bgpitems_to(&wdrw, &mut buf[curpos + 2..])?; + let wlen = encode_pathid_bgpitems_to(wdrw, &mut buf[curpos + 2..])?; if wlen > 65535 { return Err(BgpError::too_many_data()); } @@ -238,7 +219,7 @@ impl BgpMessage for BgpUpdateMessage { }, BgpTransportMode::IPv6 => match self.withdraws { BgpAddrs::IPV6U(ref wdrw) => { - let wlen = encode_bgpitems_to(&wdrw, &mut buf[curpos + 2..])?; + let wlen = encode_bgpitems_to(wdrw, &mut buf[curpos + 2..])?; if wlen > 65535 { return Err(BgpError::too_many_data()); } @@ -246,7 +227,7 @@ impl BgpMessage for BgpUpdateMessage { curpos += 2 + wlen; } BgpAddrs::IPV6UP(ref wdrw) => { - let wlen = encode_pathid_bgpitems_to(&wdrw, &mut buf[curpos + 2..])?; + let wlen = encode_pathid_bgpitems_to(wdrw, &mut buf[curpos + 2..])?; if wlen > 65535 { return Err(BgpError::too_many_data()); } @@ -274,19 +255,19 @@ impl BgpMessage for BgpUpdateMessage { match peer.peer_mode { BgpTransportMode::IPv4 => match self.updates { BgpAddrs::IPV4U(ref upds) => { - curpos += encode_bgpitems_to(&upds, &mut buf[curpos..])?; + curpos += encode_bgpitems_to(upds, &mut buf[curpos..])?; } BgpAddrs::IPV4UP(ref upds) => { - curpos += encode_pathid_bgpitems_to(&upds, &mut buf[curpos..])?; + curpos += encode_pathid_bgpitems_to(upds, &mut buf[curpos..])?; } _ => {} }, BgpTransportMode::IPv6 => match self.updates { BgpAddrs::IPV6U(ref upds) => { - curpos += encode_bgpitems_to(&upds, &mut buf[curpos..])?; + curpos += encode_bgpitems_to(upds, &mut buf[curpos..])?; } BgpAddrs::IPV6UP(ref upds) => { - curpos += encode_pathid_bgpitems_to(&upds, &mut buf[curpos..])?; + curpos += encode_pathid_bgpitems_to(upds, &mut buf[curpos..])?; } _ => {} }, diff --git a/src/prelude.rs b/src/prelude.rs index 315998e..306f1bc 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -16,7 +16,6 @@ //! use zettabgp::prelude::*; //! ``` - pub use crate::afi::evpn::*; pub use crate::afi::flowspec::*; pub use crate::afi::ipv4::*; @@ -28,12 +27,12 @@ pub use crate::error::*; pub use crate::util::*; pub use crate::*; -pub use crate::BgpMessage; -pub use crate::message::update::*; -pub use crate::message::open::*; -pub use crate::message::notification::*; pub use crate::message::keepalive::*; +pub use crate::message::notification::*; +pub use crate::message::open::*; +pub use crate::message::update::*; pub use crate::message::*; +pub use crate::BgpMessage; pub use crate::message::attributes::aggregatoras::*; pub use crate::message::attributes::aspath::*; diff --git a/src/util.rs b/src/util.rs index 642c4ad..6074bb4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -15,7 +15,7 @@ pub fn decode_addrv4_from(buf: &[u8]) -> Result { if buf.len() < 4 { return Err(BgpError::static_str("Invalid addrv4 length")); } - return Ok(std::net::Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])); + Ok(std::net::Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])) } /// Stores ipv4 address into the buffer. pub fn encode_addrv4_to(addr: &std::net::Ipv4Addr, buf: &mut [u8]) -> Result { @@ -30,7 +30,7 @@ pub fn decode_addrv6_from(buf: &[u8]) -> Result { if buf.len() < 16 { return Err(BgpError::static_str("Invalid addrv6 length")); } - return Ok(std::net::Ipv6Addr::new( + Ok(std::net::Ipv6Addr::new( getn_u16(&buf[0..2]), getn_u16(&buf[2..4]), getn_u16(&buf[4..6]), @@ -39,7 +39,7 @@ pub fn decode_addrv6_from(buf: &[u8]) -> Result { getn_u16(&buf[10..12]), getn_u16(&buf[12..14]), getn_u16(&buf[14..16]), - )); + )) } /// Stores ipv6 address into the buffer. pub fn encode_addrv6_to(addr: &std::net::Ipv6Addr, buf: &mut [u8]) -> Result { @@ -89,4 +89,3 @@ pub fn getn_u64(a: &[u8]) -> u64 { pub fn getn_u128(a: &[u8]) -> u128 { ((getn_u64(a) as u128) << 64) | (getn_u64(&a[8..16]) as u128) } -