This commit is contained in:
@ -23,6 +23,7 @@ use nom::number::complete::{be_u16, be_u8};
|
||||
use nom::Err::Failure;
|
||||
use nom::IResult;
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
/// BGPOpenOptionType represents the option types in the Open message.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
|
||||
@ -34,9 +35,9 @@ impl BGPOpenOptionType {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for BGPOpenOptionType {
|
||||
fn into(self) -> u8 {
|
||||
self.0
|
||||
impl From<BGPOpenOptionType> for u8 {
|
||||
fn from(val: BGPOpenOptionType) -> Self {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,14 +96,12 @@ impl WritablePacket for OpenOption {
|
||||
}
|
||||
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
|
||||
match &self.oval {
|
||||
OpenOptions::Capabilities(c) => {
|
||||
return Ok(2 + c.wire_len(ctx)?);
|
||||
}
|
||||
OpenOptions::Capabilities(c) => Ok(2 + c.wire_len(ctx)?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OpenOption {
|
||||
impl Display for OpenOption {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "OpenOption: {}", self.oval)
|
||||
}
|
||||
@ -113,11 +112,11 @@ pub enum OpenOptions {
|
||||
Capabilities(OpenOptionCapabilities),
|
||||
}
|
||||
|
||||
impl fmt::Display for OpenOptions {
|
||||
impl Display for OpenOptions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
return match &self {
|
||||
match &self {
|
||||
OpenOptions::Capabilities(c) => write!(f, "Capabilities: {}", c),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,7 +136,7 @@ impl ReadablePacket for OpenOptionCapabilities {
|
||||
be_u8,
|
||||
nom::multi::many0(|i| BGPCapability::from_wire(ctx, i)),
|
||||
)(buf)?;
|
||||
return IResult::Ok((buf, OpenOptionCapabilities { caps }));
|
||||
IResult::Ok((buf, OpenOptionCapabilities { caps }))
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +160,7 @@ impl WritablePacket for OpenOptionCapabilities {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OpenOptionCapabilities {
|
||||
impl Display for OpenOptionCapabilities {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Capabilities: [")?;
|
||||
for cap in &self.caps {
|
||||
@ -181,9 +180,9 @@ impl BGPCapabilityType {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for BGPCapabilityType {
|
||||
fn into(self) -> u8 {
|
||||
return self.0;
|
||||
impl From<BGPCapabilityType> for u8 {
|
||||
fn from(val: BGPCapabilityType) -> Self {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,17 +305,17 @@ impl WritablePacket for BGPCapability {
|
||||
}
|
||||
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
|
||||
// BGPCapabilityType(u8) + cap_len(u8) + val
|
||||
return match &self.val {
|
||||
match &self.val {
|
||||
BGPCapabilityValue::FourByteASN(v) => Ok(2 + v.wire_len(ctx)?),
|
||||
BGPCapabilityValue::Multiprotocol(v) => Ok(2 + v.wire_len(ctx)?),
|
||||
BGPCapabilityValue::RouteRefresh(v) => Ok(2 + v.wire_len(ctx)?),
|
||||
BGPCapabilityValue::GracefulRestart(v) => Ok(2 + v.wire_len(ctx)?),
|
||||
BGPCapabilityValue::UnknownCapability(v) => Ok(2 + v.wire_len(ctx)?),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BGPCapability {
|
||||
impl Display for BGPCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
std::fmt::Display::fmt(&self.val, f)
|
||||
}
|
||||
@ -331,7 +330,7 @@ pub enum BGPCapabilityValue {
|
||||
UnknownCapability(UnknownCapability),
|
||||
}
|
||||
|
||||
impl fmt::Display for BGPCapabilityValue {
|
||||
impl Display for BGPCapabilityValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self {
|
||||
BGPCapabilityValue::FourByteASN(v) => std::fmt::Display::fmt(v, f),
|
||||
@ -379,7 +378,7 @@ impl WritablePacket for UnknownCapability {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for UnknownCapability {
|
||||
impl Display for UnknownCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "UnknownCapability type: {}", self.cap_code)
|
||||
}
|
||||
@ -403,7 +402,7 @@ impl ReadablePacket for FourByteASNCapability {
|
||||
buf: &'a [u8],
|
||||
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
|
||||
let (buf, asn) = nom::combinator::complete(nom::number::complete::be_u32)(buf)?;
|
||||
return IResult::Ok((buf, FourByteASNCapability::new(asn)));
|
||||
IResult::Ok((buf, FourByteASNCapability::new(asn)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,7 +417,7 @@ impl WritablePacket for FourByteASNCapability {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FourByteASNCapability {
|
||||
impl Display for FourByteASNCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "FourByteASN: asn: {}", self.asn)
|
||||
}
|
||||
@ -445,17 +444,12 @@ impl ReadablePacket for MultiprotocolCapability {
|
||||
ctx: &ParserContext,
|
||||
buf: &'a [u8],
|
||||
) -> IResult<&'a [u8], MultiprotocolCapability, BGPParserError<&'a [u8]>> {
|
||||
let (buf, (afi_raw, _, safi_raw)) = nom::combinator::complete(nom::sequence::tuple((
|
||||
let (buf, (afi, _, safi)) = nom::combinator::complete(nom::sequence::tuple((
|
||||
|i| AddressFamilyIdentifier::from_wire(ctx, i),
|
||||
nom::bytes::complete::take(1u8),
|
||||
|i| SubsequentAddressFamilyIdentifier::from_wire(ctx, i),
|
||||
)))(buf)?;
|
||||
|
||||
let afi = AddressFamilyIdentifier::try_from(afi_raw)
|
||||
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
|
||||
let safi = SubsequentAddressFamilyIdentifier::try_from(safi_raw)
|
||||
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
|
||||
|
||||
IResult::Ok((buf, MultiprotocolCapability::new(afi, safi)))
|
||||
}
|
||||
}
|
||||
@ -473,7 +467,7 @@ impl WritablePacket for MultiprotocolCapability {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MultiprotocolCapability {
|
||||
impl Display for MultiprotocolCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "MultiprotocolCapbility: [ {} {} ]", self.afi, self.safi,)
|
||||
}
|
||||
@ -501,7 +495,7 @@ impl ReadablePacket for RouteRefreshCapability {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RouteRefreshCapability {
|
||||
impl Display for RouteRefreshCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "RouteRefreshCapability")
|
||||
}
|
||||
@ -548,7 +542,7 @@ impl WritablePacket for GracefulRestartPayload {
|
||||
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
|
||||
let afi: u16 = self.afi.into();
|
||||
let mut res = vec![0u8; 2];
|
||||
byteorder::NetworkEndian::write_u16(res.as_mut(), afi.into());
|
||||
byteorder::NetworkEndian::write_u16(res.as_mut(), afi);
|
||||
res.push(self.safi.into());
|
||||
res.push(if self.af_flags { 0x80 } else { 0 });
|
||||
Ok(res)
|
||||
@ -558,7 +552,7 @@ impl WritablePacket for GracefulRestartPayload {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GracefulRestartPayload {
|
||||
impl Display for GracefulRestartPayload {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
@ -604,7 +598,7 @@ impl WritablePacket for GracefulRestartCapability {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GracefulRestartCapability {
|
||||
impl Display for GracefulRestartCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "GracefulRestartCapability: [")?;
|
||||
for value in &self.payloads {
|
||||
@ -630,14 +624,13 @@ impl WritablePacket for ExtendedNextHopEncodingCapability {
|
||||
Ok(self
|
||||
.afi_safi_nhafi
|
||||
.iter()
|
||||
.map(|e| {
|
||||
.flat_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())
|
||||
.chain(vec![0x00, Into::<u8>::into(e.1)])
|
||||
.chain(Into::<Vec<u8>>::into(e.2))
|
||||
.collect::<Vec<u8>>()
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<u8>>())
|
||||
}
|
||||
|
||||
@ -672,7 +665,7 @@ impl ReadablePacket for ExtendedNextHopEncodingCapability {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExtendedNextHopEncodingCapability {
|
||||
impl Display for ExtendedNextHopEncodingCapability {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ExtendednextHopEncodingCapability [")?;
|
||||
for entry in &self.afi_safi_nhafi {
|
||||
@ -698,7 +691,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_four_byte_asn_capability() {
|
||||
let bytes: &[u8] = &[0x41, 0x04, 0x00, 0x00, 0x00, 0x2a];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let (buf, result) = BGPCapability::from_wire(ctx, bytes).unwrap();
|
||||
assert_eq!(
|
||||
result,
|
||||
@ -716,7 +711,9 @@ mod tests {
|
||||
0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02,
|
||||
0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00, 0x2a,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let (_buf, result) =
|
||||
nom::multi::many0(|buf: &'a [u8]| OpenOption::from_wire(ctx, buf))(option_bytes)
|
||||
.unwrap();
|
||||
@ -728,7 +725,9 @@ mod tests {
|
||||
#[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 ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let (_, cap) = ExtendedNextHopEncodingCapability::from_wire(ctx, &bytes).unwrap();
|
||||
|
||||
let expected_str =
|
||||
|
||||
@ -27,11 +27,11 @@ pub enum AddressFamilyIdentifier {
|
||||
Ipv6,
|
||||
}
|
||||
|
||||
impl Into<u16> for AddressFamilyIdentifier {
|
||||
fn into(self) -> u16 {
|
||||
match self {
|
||||
Self::Ipv4 => 1,
|
||||
Self::Ipv6 => 2,
|
||||
impl From<AddressFamilyIdentifier> for u16 {
|
||||
fn from(val: AddressFamilyIdentifier) -> Self {
|
||||
match val {
|
||||
AddressFamilyIdentifier::Ipv4 => 1,
|
||||
AddressFamilyIdentifier::Ipv6 => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,28 +50,28 @@ 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(),
|
||||
impl From<AddressFamilyIdentifier> for Vec<u8> {
|
||||
fn from(val: AddressFamilyIdentifier) -> Self {
|
||||
match val {
|
||||
AddressFamilyIdentifier::Ipv4 => 1_u16.to_be_bytes().to_vec(),
|
||||
AddressFamilyIdentifier::Ipv6 => 2_u16.to_be_bytes().to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience functions to convert AddressFamilyIdentifier into those used by netlink.
|
||||
impl Into<netlink_packet_route::AddressFamily> for AddressFamilyIdentifier {
|
||||
fn into(self) -> netlink_packet_route::AddressFamily {
|
||||
match self {
|
||||
impl From<AddressFamilyIdentifier> for netlink_packet_route::AddressFamily {
|
||||
fn from(val: AddressFamilyIdentifier) -> Self {
|
||||
match val {
|
||||
AddressFamilyIdentifier::Ipv4 => netlink_packet_route::AddressFamily::Inet,
|
||||
AddressFamilyIdentifier::Ipv6 => netlink_packet_route::AddressFamily::Inet6,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<rtnetlink::IpVersion> for AddressFamilyIdentifier {
|
||||
fn into(self) -> rtnetlink::IpVersion {
|
||||
match self {
|
||||
impl From<AddressFamilyIdentifier> for rtnetlink::IpVersion {
|
||||
fn from(val: AddressFamilyIdentifier) -> Self {
|
||||
match val {
|
||||
AddressFamilyIdentifier::Ipv4 => rtnetlink::IpVersion::V4,
|
||||
AddressFamilyIdentifier::Ipv6 => rtnetlink::IpVersion::V6,
|
||||
}
|
||||
@ -113,14 +113,14 @@ pub enum SubsequentAddressFamilyIdentifier {
|
||||
MulticastMplsVpn,
|
||||
}
|
||||
|
||||
impl Into<u8> for SubsequentAddressFamilyIdentifier {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
Self::Unicast => 1,
|
||||
Self::Multicast => 2,
|
||||
Self::NlriWithMpls => 4,
|
||||
Self::MplsLabeledVPN => 128,
|
||||
Self::MulticastMplsVpn => 129,
|
||||
impl From<SubsequentAddressFamilyIdentifier> for u8 {
|
||||
fn from(val: SubsequentAddressFamilyIdentifier) -> Self {
|
||||
match val {
|
||||
SubsequentAddressFamilyIdentifier::Unicast => 1,
|
||||
SubsequentAddressFamilyIdentifier::Multicast => 2,
|
||||
SubsequentAddressFamilyIdentifier::NlriWithMpls => 4,
|
||||
SubsequentAddressFamilyIdentifier::MplsLabeledVPN => 128,
|
||||
SubsequentAddressFamilyIdentifier::MulticastMplsVpn => 129,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,9 +45,9 @@ impl BGPMessageType {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for BGPMessageType {
|
||||
fn into(self) -> u8 {
|
||||
self.0
|
||||
impl From<BGPMessageType> for u8 {
|
||||
fn from(val: BGPMessageType) -> Self {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
impl From<u8> for BGPMessageType {
|
||||
@ -264,7 +264,7 @@ impl Decoder for Codec {
|
||||
let len: u16 = byteorder::BigEndian::read_u16(&buf[16..18]);
|
||||
if buf.len() < len.into() {
|
||||
// Not enough data to read this frame.
|
||||
return Ok(None);
|
||||
Ok(None)
|
||||
} else if buf.len() == len as usize {
|
||||
// Exactly one message here, parse and clear buf.
|
||||
let parse_result = BGPMessage::from_wire(&self.ctx, buf.as_ref());
|
||||
@ -306,7 +306,7 @@ impl WritablePacket for BGPMessage {
|
||||
{
|
||||
let mut tmp: [u8; 2] = [0u8; 2];
|
||||
NetworkEndian::write_u16(&mut tmp, self.wire_len(ctx)?);
|
||||
buf.extend_from_slice(&mut tmp);
|
||||
buf.extend_from_slice(&tmp);
|
||||
}
|
||||
// Type
|
||||
buf.push(self.msg_type.into());
|
||||
@ -428,9 +428,9 @@ impl WritablePacket for OpenMessage {
|
||||
for opt in &self.options {
|
||||
count += (*opt).to_wire(ctx)?.len();
|
||||
}
|
||||
Ok(count
|
||||
count
|
||||
.try_into()
|
||||
.map_err(|_| "overflow in wire_len in OpenMessage")?)
|
||||
.map_err(|_| "overflow in wire_len in OpenMessage")
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,12 +485,12 @@ impl ReadablePacket for UpdateMessage {
|
||||
impl WritablePacket for UpdateMessage {
|
||||
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
let mut tmp: &mut [u8] = &mut [0u8; 2];
|
||||
let tmp: &mut [u8] = &mut [0u8; 2];
|
||||
let mut wd_len: u16 = 0;
|
||||
for wd in &self.withdrawn_nlri {
|
||||
wd_len += wd.wire_len(ctx)?;
|
||||
}
|
||||
NetworkEndian::write_u16(&mut tmp, wd_len);
|
||||
NetworkEndian::write_u16(tmp, wd_len);
|
||||
buf.append(&mut tmp.to_vec());
|
||||
for wd in &self.withdrawn_nlri {
|
||||
buf.extend(wd.to_wire(ctx)?);
|
||||
@ -499,7 +499,7 @@ impl WritablePacket for UpdateMessage {
|
||||
for pattr in &self.path_attributes {
|
||||
pattr_len += pattr.wire_len(ctx)?;
|
||||
}
|
||||
NetworkEndian::write_u16(&mut tmp, pattr_len);
|
||||
NetworkEndian::write_u16(tmp, pattr_len);
|
||||
buf.extend(tmp.to_vec());
|
||||
for pattr in &self.path_attributes {
|
||||
buf.extend(pattr.to_wire(ctx)?);
|
||||
@ -566,7 +566,9 @@ mod tests {
|
||||
0x02, 0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00,
|
||||
0x2a,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv4);
|
||||
let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap();
|
||||
assert_eq!(buf.len(), 0);
|
||||
|
||||
@ -585,7 +587,9 @@ mod tests {
|
||||
0x18, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02,
|
||||
0x02, 0x80, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x22, 0x36,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv4);
|
||||
let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap();
|
||||
assert_eq!(buf.len(), 0);
|
||||
|
||||
@ -609,14 +613,16 @@ mod tests {
|
||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xcb, 0x01, 0x4e,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv4);
|
||||
let (buf, result) = BGPMessage::from_wire(ctx, update_msg_bytes).unwrap();
|
||||
assert_eq!(buf.len(), 0);
|
||||
|
||||
let want_str = "UpdateMessage [ withdrawn: announced: 203.1.78.0/24 path attributes: OriginPathAttribute::INCOMPLETEAS Path: { Segment [ Type: AS_SEGMENT 39540 57118 29691 1299 4739 ]] }NextHop: 185.95.219.36Communities: [ 1299:35000, 29691:4000, 29691:4021, 39540:4000, 39540:4010, 57118:2000, 57118:2010, ] LargeCommunities: [ 57118:20:0, 57118:20:10, ] ]";
|
||||
assert_eq!(format!("{}", result), want_str);
|
||||
|
||||
let reencoded = result.to_wire(&ctx).unwrap();
|
||||
let reencoded = result.to_wire(ctx).unwrap();
|
||||
assert_eq!(&reencoded, update_msg_bytes);
|
||||
}
|
||||
|
||||
@ -664,7 +670,7 @@ mod tests {
|
||||
for b in &buf {
|
||||
print!("0x{:02x}, ", b);
|
||||
}
|
||||
assert_eq!(buf.as_ref(), update_msg_bytes.as_ref());
|
||||
assert_eq!(buf.as_ref(), update_msg_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -72,11 +72,9 @@ impl ReadablePacket for NLRI {
|
||||
let (buf, prefix) = take(octet_len)(buf)?;
|
||||
|
||||
match ctx.nlri_mode {
|
||||
None => {
|
||||
return Err(Failure(BGPParserError::CustomText(
|
||||
"nlri_mode not set in the context for NLRI::from_wire".to_string(),
|
||||
)));
|
||||
}
|
||||
None => Err(Failure(BGPParserError::CustomText(
|
||||
"nlri_mode not set in the context for NLRI::from_wire".to_string(),
|
||||
))),
|
||||
Some(afi) => Ok((
|
||||
buf,
|
||||
NLRI {
|
||||
@ -115,8 +113,7 @@ impl<'de> Deserialize<'de> for NLRI {
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Self::try_from(String::deserialize(deserializer)?.as_str())
|
||||
.map_err(|e| de::Error::custom(e))
|
||||
Self::try_from(String::deserialize(deserializer)?.as_str()).map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,7 +204,7 @@ impl TryInto<IpAddr> for NLRI {
|
||||
impl TryFrom<&str> for NLRI {
|
||||
type Error = eyre::ErrReport;
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
let parts: Vec<&str> = value.split("/").collect();
|
||||
let parts: Vec<&str> = value.split('/').collect();
|
||||
if parts.len() != 2 {
|
||||
bail!("Expected ip_addr/prefixlen but got: {}", value);
|
||||
}
|
||||
@ -217,11 +214,11 @@ impl TryFrom<&str> for NLRI {
|
||||
let mut octets: Vec<u8>;
|
||||
let afi: AddressFamilyIdentifier;
|
||||
|
||||
if parts[0].contains(":") {
|
||||
if parts[0].contains(':') {
|
||||
afi = AddressFamilyIdentifier::Ipv6;
|
||||
let addr: Ipv6Addr = Ipv6Addr::from_str(parts[0]).map_err(|e| eyre!(e))?;
|
||||
octets = addr.octets().to_vec();
|
||||
} else if parts[0].contains(".") {
|
||||
} else if parts[0].contains('.') {
|
||||
afi = AddressFamilyIdentifier::Ipv4;
|
||||
let addr: Ipv4Addr = Ipv4Addr::from_str(parts[0]).map_err(|e| eyre!(e))?;
|
||||
octets = addr.octets().to_vec();
|
||||
@ -237,7 +234,7 @@ impl TryFrom<&str> for NLRI {
|
||||
let num_bytes = (prefixlen / 8) + 1;
|
||||
let mask = u8::MAX << (8 - (prefixlen % 8));
|
||||
octets.truncate(num_bytes.into());
|
||||
if octets.len() > 0 {
|
||||
if !octets.is_empty() {
|
||||
let last_pos = octets.len() - 1;
|
||||
octets[last_pos] &= mask;
|
||||
}
|
||||
@ -282,7 +279,7 @@ mod tests {
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use super::NLRI;
|
||||
use crate::constants::AddressFamilyIdentifier::{self, Ipv4, Ipv6};
|
||||
use crate::constants::AddressFamilyIdentifier::{Ipv4, Ipv6};
|
||||
use crate::traits::ParserContext;
|
||||
use crate::traits::ReadablePacket;
|
||||
use crate::traits::WritablePacket;
|
||||
@ -290,7 +287,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_basic_nlri_v6() {
|
||||
let nlri_bytes: &[u8] = &[0x20, 0x20, 0x01, 0xdb, 0x8];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap();
|
||||
assert_eq!(nlri_res.1.afi, Ipv6);
|
||||
assert_eq!(nlri_res.1.prefixlen, 32);
|
||||
@ -305,7 +304,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_basic_nlri_v4() {
|
||||
let nlri_bytes: &[u8] = &[0x18, 192, 168, 1];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv4);
|
||||
let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap();
|
||||
assert_eq!(nlri_res.1.afi, Ipv4);
|
||||
assert_eq!(nlri_res.1.prefixlen, 24);
|
||||
|
||||
@ -472,10 +472,10 @@ impl ReadablePacket for NextHopPathAttribute {
|
||||
|
||||
impl WritablePacket for NextHopPathAttribute {
|
||||
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
|
||||
return Ok(self.0.octets().to_vec());
|
||||
Ok(self.0.octets().to_vec())
|
||||
}
|
||||
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
|
||||
return Ok(4);
|
||||
Ok(4)
|
||||
}
|
||||
}
|
||||
|
||||
@ -584,7 +584,7 @@ impl ReadablePacket for AggregatorPathAttribute {
|
||||
ctx: &ParserContext,
|
||||
buf: &'a [u8],
|
||||
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
|
||||
if !ctx.four_octet_asn.is_some() {
|
||||
if ctx.four_octet_asn.is_none() {
|
||||
return Err(Failure(BGPParserError::CustomText(
|
||||
"Non four byte ASN not supported (AggregatorPathAttribute from_wire)".to_string(),
|
||||
)));
|
||||
@ -604,7 +604,8 @@ impl ReadablePacket for AggregatorPathAttribute {
|
||||
|
||||
impl WritablePacket for AggregatorPathAttribute {
|
||||
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
|
||||
if !ctx.four_octet_asn.is_some() {
|
||||
if ctx.four_octet_asn.is_none() {
|
||||
// TODO: This should be gracefully handled, not panic!
|
||||
panic!("Non four byte ASN not supported (AggregatorPathAttribute from_wire)");
|
||||
}
|
||||
let mut buf: Vec<u8> = vec![0u8; 4];
|
||||
@ -613,7 +614,8 @@ impl WritablePacket for AggregatorPathAttribute {
|
||||
Ok(buf)
|
||||
}
|
||||
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
|
||||
if !ctx.four_octet_asn.is_some() {
|
||||
if ctx.four_octet_asn.is_none() {
|
||||
// TODO: This should be gracefully handled, not panic!
|
||||
panic!("Non four byte ASN not supported (AggregatorPathAttribute from_wire)");
|
||||
}
|
||||
Ok(8)
|
||||
@ -733,7 +735,7 @@ impl WritablePacket for ExtendedCommunitiesPathAttribute {
|
||||
if !self.value.len() == 7 {
|
||||
return Err("ExtendedCommunitiesPathAttribute value length != 7");
|
||||
}
|
||||
Ok(vec![vec![self.t_high], self.value.to_owned()].concat())
|
||||
Ok([vec![self.t_high], self.value.to_owned()].concat())
|
||||
}
|
||||
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
|
||||
Ok(8)
|
||||
@ -847,7 +849,7 @@ impl MPReachNLRIPathAttribute {
|
||||
// https://datatracker.ietf.org/doc/html/rfc2545 describes what the nexthop
|
||||
// field can contain. Returns a tuple of (global_nh, linklocal_nh)
|
||||
pub fn nexthop_to_v6(self) -> Option<(Ipv6Addr, Option<Ipv6Addr>)> {
|
||||
return match self.nexthop.len() {
|
||||
match self.nexthop.len() {
|
||||
16 => {
|
||||
let nh_bytes: [u8; 16] = self.nexthop.try_into().unwrap();
|
||||
Some((Ipv6Addr::from(nh_bytes), None))
|
||||
@ -861,7 +863,7 @@ impl MPReachNLRIPathAttribute {
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1010,7 +1012,9 @@ mod tests {
|
||||
0x02, 0x04, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x20, 0x1a,
|
||||
0x00, 0x00, 0x78, 0xfc,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result = &ASPathAttribute::from_wire(ctx, as_path_bytes).unwrap();
|
||||
|
||||
let expected_aspath: Vec<u32> = vec![39540, 57118, 8218, 30972];
|
||||
@ -1029,7 +1033,9 @@ mod tests {
|
||||
0x02, 0x04, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x20, 0x1a,
|
||||
0x00, 0x00, 0x78, 0xfc, 0x01, 0x02, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result = &ASPathAttribute::from_wire(ctx, as_path_bytes).unwrap();
|
||||
|
||||
let expected_aspath: Vec<u32> = vec![39540, 57118, 8218, 30972];
|
||||
@ -1048,7 +1054,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_next_hop_path_attribute() {
|
||||
let nh_bytes: &[u8] = &[192, 168, 1, 1];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result = NextHopPathAttribute::from_wire(ctx, nh_bytes).unwrap();
|
||||
|
||||
assert_eq!(result.1 .0, "192.168.1.1".parse::<Ipv4Addr>().unwrap());
|
||||
@ -1060,7 +1068,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_multi_exit_discriminator_path_attribute() {
|
||||
let med_bytes: &[u8] = &[0xca, 0x00, 0x00, 0xbe];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result = MultiExitDiscPathAttribute::from_wire(ctx, med_bytes).unwrap();
|
||||
|
||||
assert_eq!(result.1 .0, 3388997822);
|
||||
@ -1072,7 +1082,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_local_pref_path_attribute() {
|
||||
let local_pref_bytes: &[u8] = &[0xca, 0x00, 0x00, 0xbe];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result = LocalPrefPathAttribute::from_wire(ctx, local_pref_bytes).unwrap();
|
||||
|
||||
assert_eq!(result.1 .0, 3388997822);
|
||||
@ -1090,7 +1102,9 @@ mod tests {
|
||||
0xff, 0xf1, 0x73, 0xfb, 0x0f, 0xa0, 0x73, 0xfb, 0x0f, 0xc8, 0x9a, 0x74, 0x0f, 0xa0,
|
||||
0x9a, 0x74, 0x0f, 0xb4, 0xdf, 0x1e, 0x07, 0xd0, 0xdf, 0x1e, 0x07, 0xe4,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result = CommunitiesPathAttribute::from_wire(ctx, communities_bytes).unwrap();
|
||||
let expected_communities: Vec<(u16, u16)> = vec![
|
||||
(0, 0x32bd),
|
||||
@ -1127,7 +1141,9 @@ mod tests {
|
||||
0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14,
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result = LargeCommunitiesPathAttribute::from_wire(ctx, large_community_bytes).unwrap();
|
||||
assert_eq!(result.1.values.len(), 2);
|
||||
assert_eq!(result.1.values[0].global_admin, 57118);
|
||||
@ -1154,7 +1170,9 @@ mod tests {
|
||||
0x20, 0x20, 0x01, 0x0d, 0xb8, // NLRI 1
|
||||
0x10, 0xfe, 0x80, // NLRI 2
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result: (&[u8], MPReachNLRIPathAttribute) =
|
||||
MPReachNLRIPathAttribute::from_wire(ctx, mp_reach_bytes).unwrap();
|
||||
assert_eq!(result.1.afi, Ipv6);
|
||||
@ -1184,7 +1202,9 @@ mod tests {
|
||||
0x20, 0x20, 0x01, 0x0d, 0xb8, // NLRI 1
|
||||
0x10, 0xfe, 0x80, // NLRI 2
|
||||
];
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let result: (&[u8], MPUnreachNLRIPathAttribute) =
|
||||
MPUnreachNLRIPathAttribute::from_wire(ctx, mp_unreach_bytes).unwrap();
|
||||
assert_eq!(result.1.afi, Ipv6);
|
||||
@ -1201,7 +1221,7 @@ mod tests {
|
||||
|
||||
// Tests the high level dispatching of the path attribute parser
|
||||
#[test]
|
||||
fn test_path_attribute_parsing<'a>() {
|
||||
fn test_path_attribute_parsing() {
|
||||
let path_attr_bytes: &[u8] = &[
|
||||
0x40, 0x01, 0x01, 0x00, 0x50, 0x02, 0x00, 0x1a, 0x02, 0x06, 0x00, 0x00, 0x9a, 0x74,
|
||||
0x00, 0x00, 0x62, 0x03, 0x00, 0x00, 0x0b, 0x62, 0x00, 0x00, 0x19, 0x35, 0x00, 0x00,
|
||||
@ -1212,10 +1232,14 @@ mod tests {
|
||||
0x9a, 0x74, 0x0f, 0xbe,
|
||||
];
|
||||
|
||||
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6);
|
||||
let ctx = &ParserContext::default()
|
||||
.four_octet_asn(true)
|
||||
.nlri_mode(Ipv6);
|
||||
let (buf, res): (_, Vec<PathAttribute>) =
|
||||
nom::multi::many0(|buf: &'a [u8]| PathAttribute::from_wire(ctx, buf))(path_attr_bytes)
|
||||
.unwrap();
|
||||
nom::multi::many0(|buf: &'static [u8]| PathAttribute::from_wire(ctx, buf))(
|
||||
path_attr_bytes,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(buf.len(), 0);
|
||||
let expected_str = "[OriginPathAttribute(IGP), \
|
||||
ASPathAttribute(ASPathAttribute { segments: \
|
||||
|
||||
@ -21,7 +21,7 @@ use nom::IResult;
|
||||
|
||||
// ParserContext contains information pertinent to configurations which affect
|
||||
// how message parsing is to be handled.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub struct ParserContext {
|
||||
// Whether the peer is RFC6793 compliant.
|
||||
pub four_octet_asn: Option<bool>,
|
||||
@ -30,13 +30,6 @@ pub struct ParserContext {
|
||||
}
|
||||
|
||||
impl ParserContext {
|
||||
pub fn new() -> ParserContext {
|
||||
ParserContext {
|
||||
four_octet_asn: None,
|
||||
nlri_mode: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn four_octet_asn(mut self, v: bool) -> Self {
|
||||
self.four_octet_asn = Some(v);
|
||||
self
|
||||
|
||||
Reference in New Issue
Block a user