Add capability from rfc8950.
Just the basic parser, still needs to be integrated into the rest of the code for the OPEN message parsing, and then the rest of the MP Reach/Unreach NLRI parsing needs to be added.
This commit is contained in:
@ -201,7 +201,7 @@ pub mod BGPCapabilityTypeValues {
|
|||||||
pub const ROUTE_REFRESH_BGP4: BGPCapabilityType = BGPCapabilityType(2);
|
pub const ROUTE_REFRESH_BGP4: BGPCapabilityType = BGPCapabilityType(2);
|
||||||
/// Outbound Route Filtering Capability [RFC5291]
|
/// Outbound Route Filtering Capability [RFC5291]
|
||||||
pub const OUTBOUND_ROUTE_FILTERING: BGPCapabilityType = BGPCapabilityType(3);
|
pub const OUTBOUND_ROUTE_FILTERING: BGPCapabilityType = BGPCapabilityType(3);
|
||||||
/// Extended Next Hop Encoding [RFC5549]
|
/// Extended Next Hop Encoding [RFC8950]
|
||||||
pub const EXTENDED_NEXT_HOP: BGPCapabilityType = BGPCapabilityType(5);
|
pub const EXTENDED_NEXT_HOP: BGPCapabilityType = BGPCapabilityType(5);
|
||||||
/// BGP Extended Message [RFC8654]
|
/// BGP Extended Message [RFC8654]
|
||||||
pub const EXTENDED_MESSAGE: BGPCapabilityType = BGPCapabilityType(6);
|
pub const EXTENDED_MESSAGE: BGPCapabilityType = BGPCapabilityType(6);
|
||||||
@ -248,6 +248,7 @@ impl ReadablePacket for BGPCapability {
|
|||||||
})(buf)?;
|
})(buf)?;
|
||||||
(buf, BGPCapabilityValue::Multiprotocol(cap))
|
(buf, BGPCapabilityValue::Multiprotocol(cap))
|
||||||
}
|
}
|
||||||
|
// TODO: Add extended next hop.
|
||||||
BGPCapabilityTypeValues::ROUTE_REFRESH_BGP4 => {
|
BGPCapabilityTypeValues::ROUTE_REFRESH_BGP4 => {
|
||||||
let (buf, _) = be_u8(buf)?;
|
let (buf, _) = be_u8(buf)?;
|
||||||
let (buf, cap) = nom::multi::length_value(be_u8, |i| {
|
let (buf, cap) = nom::multi::length_value(be_u8, |i| {
|
||||||
@ -616,12 +617,81 @@ impl fmt::Display for GracefulRestartCapability {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RFC8950 - Advertising IPv4 NLRI with IPv6 next hop.
|
||||||
|
// GracefulRestartPayload represents the contents of the graceful restart cap.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExtendedNextHopEncodingCapability {
|
||||||
|
pub afi_safi_nhafi: Vec<(
|
||||||
|
AddressFamilyIdentifier,
|
||||||
|
SubsequentAddressFamilyIdentifier,
|
||||||
|
AddressFamilyIdentifier,
|
||||||
|
)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WritablePacket for ExtendedNextHopEncodingCapability {
|
||||||
|
fn to_wire(&self, _ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
|
||||||
|
Ok(self
|
||||||
|
.afi_safi_nhafi
|
||||||
|
.iter()
|
||||||
|
.map(|e| {
|
||||||
|
Into::<Vec<u8>>::into(e.0)
|
||||||
|
.into_iter()
|
||||||
|
.chain(vec![0x00, Into::<u8>::into(e.1)].into_iter())
|
||||||
|
.chain(Into::<Vec<u8>>::into(e.2).into_iter())
|
||||||
|
.collect::<Vec<u8>>()
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<u8>>())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wire_len(&self, _ctx: &ParserContext) -> Result<u16, &'static str> {
|
||||||
|
Ok((self.afi_safi_nhafi.len() * 6) as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadablePacket for ExtendedNextHopEncodingCapability {
|
||||||
|
fn from_wire<'a>(
|
||||||
|
ctx: &ParserContext,
|
||||||
|
buf: &'a [u8],
|
||||||
|
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let (buf, tuples) = nom::combinator::complete(nom::multi::many0(nom::sequence::tuple((
|
||||||
|
|i| AddressFamilyIdentifier::from_wire(ctx, i),
|
||||||
|
|i| {
|
||||||
|
let (buf, _) = be_u8(i)?; // Eat the 0 byte.
|
||||||
|
SubsequentAddressFamilyIdentifier::from_wire(ctx, buf)
|
||||||
|
},
|
||||||
|
|i| AddressFamilyIdentifier::from_wire(ctx, i),
|
||||||
|
))))(buf)?;
|
||||||
|
|
||||||
|
IResult::Ok((
|
||||||
|
buf,
|
||||||
|
Self {
|
||||||
|
afi_safi_nhafi: tuples,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ExtendedNextHopEncodingCapability {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "ExtendednextHopEncodingCapability [")?;
|
||||||
|
for entry in &self.afi_safi_nhafi {
|
||||||
|
write!(f, "afi: {}, safi: {}, nhafi: {}", entry.0, entry.1, entry.2)?;
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::BGPCapability;
|
use super::BGPCapability;
|
||||||
use super::BGPCapabilityTypeValues;
|
use super::BGPCapabilityTypeValues;
|
||||||
use super::BGPCapabilityValue;
|
use super::BGPCapabilityValue;
|
||||||
|
use super::ExtendedNextHopEncodingCapability;
|
||||||
use super::FourByteASNCapability;
|
use super::FourByteASNCapability;
|
||||||
use super::OpenOption;
|
use super::OpenOption;
|
||||||
use crate::bgp_packet::constants::AddressFamilyIdentifier::Ipv6;
|
use crate::bgp_packet::constants::AddressFamilyIdentifier::Ipv6;
|
||||||
@ -657,4 +727,15 @@ mod tests {
|
|||||||
let expected_str = "[OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(1), val: Multiprotocol(MultiprotocolCapability { afi: Ipv4, safi: Unicast }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(128), val: UnknownCapability(UnknownCapability { cap_code: 128, payload: [] }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(2), val: RouteRefresh(RouteRefreshCapability) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(70), val: UnknownCapability(UnknownCapability { cap_code: 70, payload: [] }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(65), val: FourByteASN(FourByteASNCapability { asn: 42 }) }] }) }]";
|
let expected_str = "[OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(1), val: Multiprotocol(MultiprotocolCapability { afi: Ipv4, safi: Unicast }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(128), val: UnknownCapability(UnknownCapability { cap_code: 128, payload: [] }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(2), val: RouteRefresh(RouteRefreshCapability) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(70), val: UnknownCapability(UnknownCapability { cap_code: 70, payload: [] }) }] }) }, OpenOption { option_type: BGPOpenOptionType(2), oval: Capabilities(OpenOptionCapabilities { caps: [BGPCapability { cap_type: BGPCapabilityType(65), val: FourByteASN(FourByteASNCapability { asn: 42 }) }] }) }]";
|
||||||
assert_eq!(format!("{:?}", result), expected_str);
|
assert_eq!(format!("{:?}", result), expected_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extended_next_hop_encoding_capability() {
|
||||||
|
let bytes: Vec<u8> = vec![0x00, 0x01, 0x00, 0x01, 0x00, 0x02];
|
||||||
|
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||||
|
let (_, cap) = ExtendedNextHopEncodingCapability::from_wire(ctx, &bytes).unwrap();
|
||||||
|
|
||||||
|
let expected_str =
|
||||||
|
"ExtendednextHopEncodingCapability [afi: Ipv4, safi: Unicast, nhafi: Ipv6]";
|
||||||
|
assert_eq!(expected_str, cap.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,15 @@ impl TryFrom<u16> for AddressFamilyIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<Vec<u8>> for AddressFamilyIdentifier {
|
||||||
|
fn into(self) -> Vec<u8> {
|
||||||
|
match self {
|
||||||
|
Self::Ipv4 => 1_u16.to_be_bytes().to_vec(),
|
||||||
|
Self::Ipv6 => 2_u16.to_be_bytes().to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This parser for AFI makes it easier to write the other message parsers.
|
/// This parser for AFI makes it easier to write the other message parsers.
|
||||||
impl ReadablePacket for AddressFamilyIdentifier {
|
impl ReadablePacket for AddressFamilyIdentifier {
|
||||||
fn from_wire<'a>(
|
fn from_wire<'a>(
|
||||||
@ -80,6 +89,9 @@ impl fmt::Display for AddressFamilyIdentifier {
|
|||||||
pub enum SubsequentAddressFamilyIdentifier {
|
pub enum SubsequentAddressFamilyIdentifier {
|
||||||
Unicast,
|
Unicast,
|
||||||
Multicast,
|
Multicast,
|
||||||
|
NlriWithMpls,
|
||||||
|
MplsLabeledVPN,
|
||||||
|
MulticastMplsVpn,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u8> for SubsequentAddressFamilyIdentifier {
|
impl Into<u8> for SubsequentAddressFamilyIdentifier {
|
||||||
@ -87,6 +99,9 @@ impl Into<u8> for SubsequentAddressFamilyIdentifier {
|
|||||||
match self {
|
match self {
|
||||||
Self::Unicast => 1,
|
Self::Unicast => 1,
|
||||||
Self::Multicast => 2,
|
Self::Multicast => 2,
|
||||||
|
Self::NlriWithMpls => 4,
|
||||||
|
Self::MplsLabeledVPN => 128,
|
||||||
|
Self::MulticastMplsVpn => 129,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,6 +112,9 @@ impl TryFrom<u8> for SubsequentAddressFamilyIdentifier {
|
|||||||
match i {
|
match i {
|
||||||
1 => Ok(Self::Unicast),
|
1 => Ok(Self::Unicast),
|
||||||
2 => Ok(Self::Multicast),
|
2 => Ok(Self::Multicast),
|
||||||
|
4 => Ok(Self::NlriWithMpls),
|
||||||
|
128 => Ok(Self::MplsLabeledVPN),
|
||||||
|
129 => Ok(Self::MulticastMplsVpn),
|
||||||
_ => Err(std::io::Error::new(
|
_ => Err(std::io::Error::new(
|
||||||
ErrorKind::InvalidInput,
|
ErrorKind::InvalidInput,
|
||||||
format!("Unknown SAFI value: {} ", i),
|
format!("Unknown SAFI value: {} ", i),
|
||||||
@ -125,6 +143,9 @@ impl fmt::Display for SubsequentAddressFamilyIdentifier {
|
|||||||
match self {
|
match self {
|
||||||
Self::Unicast => write!(f, "Unicast"),
|
Self::Unicast => write!(f, "Unicast"),
|
||||||
Self::Multicast => write!(f, "Multicast"),
|
Self::Multicast => write!(f, "Multicast"),
|
||||||
|
Self::NlriWithMpls => write!(f, "NlriWithMpls"),
|
||||||
|
Self::MulticastMplsVpn => write!(f, "MulticastMplsVpn"),
|
||||||
|
Self::MplsLabeledVPN => write!(f, "MplsLabeledVpn"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use bgpd::route_client::netlink::NetlinkConnector;
|
use bgpd::route_client::netlink::NetlinkConnector;
|
||||||
use bgpd::route_client::southbound_interface::DummyVerifier;
|
|
||||||
use bgpd::route_client::southbound_interface::SouthboundInterface;
|
use bgpd::route_client::southbound_interface::SouthboundInterface;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|||||||
@ -1276,6 +1276,7 @@ where
|
|||||||
for attr in &u.path_attributes {
|
for attr in &u.path_attributes {
|
||||||
match attr {
|
match attr {
|
||||||
PathAttribute::MPReachNLRIPathAttribute(nlri) => {
|
PathAttribute::MPReachNLRIPathAttribute(nlri) => {
|
||||||
|
// TODO: Determine which AFI/SAFI this update corresponds to.
|
||||||
let nexthop_res = nlri.clone().nexthop_to_v6();
|
let nexthop_res = nlri.clone().nexthop_to_v6();
|
||||||
// TODO: How do we pick whether to use the global or LLNH?
|
// TODO: How do we pick whether to use the global or LLNH?
|
||||||
if let Some((global, _llnh_opt)) = nexthop_res {
|
if let Some((global, _llnh_opt)) = nexthop_res {
|
||||||
@ -1287,6 +1288,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PathAttribute::MPUnreachNLRIPathAttribute(nlri) => {
|
PathAttribute::MPUnreachNLRIPathAttribute(nlri) => {
|
||||||
|
// TODO: Determine which AFI/SAFI this update corresponds to.
|
||||||
self.process_withdrawals(nlri.nlris.clone())?;
|
self.process_withdrawals(nlri.nlris.clone())?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
Reference in New Issue
Block a user