Skip to content

Commit

Permalink
Merge pull request #163 from bgpkit/bugfix/162
Browse files Browse the repository at this point in the history
Better BMP support
  • Loading branch information
digizeph authored Apr 5, 2024
2 parents af03064 + 46e9580 commit 51f8540
Show file tree
Hide file tree
Showing 13 changed files with 306 additions and 68 deletions.
6 changes: 2 additions & 4 deletions src/encoder/rib_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ mod tests {

let mut cursor = Cursor::new(bytes.clone());
while cursor.has_remaining() {
let parsed = parse_mrt_record(&mut cursor).unwrap();
dbg!(&parsed);
let _parsed = parse_mrt_record(&mut cursor).unwrap();
}

// v6
Expand All @@ -168,8 +167,7 @@ mod tests {

let mut cursor = Cursor::new(bytes.clone());
while cursor.has_remaining() {
let parsed = parse_mrt_record(&mut cursor).unwrap();
dbg!(&parsed);
let _parsed = parse_mrt_record(&mut cursor).unwrap();
}
}
}
6 changes: 2 additions & 4 deletions src/encoder/updates_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ mod tests {

let mut cursor = Cursor::new(bytes.clone());
while cursor.has_remaining() {
let parsed = parse_mrt_record(&mut cursor).unwrap();
dbg!(&parsed);
let _parsed = parse_mrt_record(&mut cursor).unwrap();
}
}

Expand All @@ -113,8 +112,7 @@ mod tests {
let bytes = encoder.export_bytes();
let mut cursor = Cursor::new(bytes.clone());
while cursor.has_remaining() {
let parsed = parse_mrt_record(&mut cursor).unwrap();
dbg!(&parsed);
let _parsed = parse_mrt_record(&mut cursor).unwrap();
}
}
}
1 change: 0 additions & 1 deletion src/models/bgp/attributes/aspath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,6 @@ mod tests {
fn test_get_collector() {
let aspath = AsPath::from_sequence([1, 2, 3, 5]);
let collector = aspath.get_collector_opt();
dbg!(&collector);
assert_eq!(collector.unwrap(), 1);

let aspath = AsPath::from_segments(vec![AsPathSegment::set([7])]);
Expand Down
62 changes: 55 additions & 7 deletions src/parser/bmp/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::bmp::messages::headers::BmpPeerType;
use crate::bmp::messages::initiation_message::InitiationTlvType;
use crate::bmp::messages::peer_down_notification::PeerDownReason;
use crate::bmp::messages::peer_up_notification::PeerUpTlvType;
use crate::bmp::messages::route_mirroring::RouteMirroringInfo;
use crate::bmp::messages::termination_message::TerminationTlvType;
use crate::bmp::messages::termination_message::{TerminationReason, TerminationTlvType};
use crate::bmp::messages::BmpMsgType;
use crate::ParserError;
use num_enum::TryFromPrimitiveError;
Expand All @@ -12,6 +14,8 @@ use std::fmt::{Display, Formatter};
pub enum ParserBmpError {
InvalidOpenBmpHeader,
UnsupportedOpenBmpMessage,
UnknownTlvType,
UnknownTlvValue,
CorruptedBmpMessage,
TruncatedBmpMessage,
}
Expand All @@ -31,6 +35,12 @@ impl Display for ParserBmpError {
ParserBmpError::TruncatedBmpMessage => {
write!(f, "Truncated BMP message")
}
ParserBmpError::UnknownTlvType => {
write!(f, "Unknown TLV type")
}
ParserBmpError::UnknownTlvValue => {
write!(f, "Unknown TLV value")
}
}
}
}
Expand Down Expand Up @@ -58,13 +68,19 @@ impl From<TryFromPrimitiveError<BmpMsgType>> for ParserBmpError {

impl From<TryFromPrimitiveError<BmpPeerType>> for ParserBmpError {
fn from(_: TryFromPrimitiveError<BmpPeerType>) -> Self {
ParserBmpError::InvalidOpenBmpHeader
ParserBmpError::CorruptedBmpMessage
}
}

impl From<TryFromPrimitiveError<InitiationTlvType>> for ParserBmpError {
fn from(_: TryFromPrimitiveError<InitiationTlvType>) -> Self {
ParserBmpError::CorruptedBmpMessage
ParserBmpError::UnknownTlvType
}
}

impl From<TryFromPrimitiveError<PeerUpTlvType>> for ParserBmpError {
fn from(_: TryFromPrimitiveError<PeerUpTlvType>) -> Self {
ParserBmpError::UnknownTlvType
}
}

Expand All @@ -76,7 +92,19 @@ impl From<TryFromPrimitiveError<RouteMirroringInfo>> for ParserBmpError {

impl From<TryFromPrimitiveError<TerminationTlvType>> for ParserBmpError {
fn from(_: TryFromPrimitiveError<TerminationTlvType>) -> Self {
ParserBmpError::CorruptedBmpMessage
ParserBmpError::UnknownTlvType
}
}

impl From<TryFromPrimitiveError<TerminationReason>> for ParserBmpError {
fn from(_: TryFromPrimitiveError<TerminationReason>) -> Self {
ParserBmpError::UnknownTlvValue
}
}

impl From<TryFromPrimitiveError<PeerDownReason>> for ParserBmpError {
fn from(_: TryFromPrimitiveError<PeerDownReason>) -> Self {
ParserBmpError::UnknownTlvValue
}
}

Expand All @@ -102,6 +130,14 @@ mod tests {
ParserBmpError::TruncatedBmpMessage.to_string(),
"Truncated BMP message"
);
assert_eq!(
ParserBmpError::UnknownTlvType.to_string(),
"Unknown TLV type"
);
assert_eq!(
ParserBmpError::UnknownTlvValue.to_string(),
"Unknown TLV value"
);
}

#[test]
Expand All @@ -120,19 +156,31 @@ mod tests {
);
assert_eq!(
ParserBmpError::from(TryFromPrimitiveError::<BmpPeerType>::new(0)),
ParserBmpError::InvalidOpenBmpHeader
ParserBmpError::CorruptedBmpMessage
);
assert_eq!(
ParserBmpError::from(TryFromPrimitiveError::<InitiationTlvType>::new(0)),
ParserBmpError::CorruptedBmpMessage
ParserBmpError::UnknownTlvType
);
assert_eq!(
ParserBmpError::from(TryFromPrimitiveError::<RouteMirroringInfo>::new(0)),
ParserBmpError::CorruptedBmpMessage
);
assert_eq!(
ParserBmpError::from(TryFromPrimitiveError::<TerminationTlvType>::new(0)),
ParserBmpError::CorruptedBmpMessage
ParserBmpError::UnknownTlvType
);
assert_eq!(
ParserBmpError::from(TryFromPrimitiveError::<PeerUpTlvType>::new(0)),
ParserBmpError::UnknownTlvType
);
assert_eq!(
ParserBmpError::from(TryFromPrimitiveError::<TerminationReason>::new(0)),
ParserBmpError::UnknownTlvValue
);
assert_eq!(
ParserBmpError::from(TryFromPrimitiveError::<PeerDownReason>::new(0)),
ParserBmpError::UnknownTlvValue
);
}
}
4 changes: 2 additions & 2 deletions src/parser/bmp/messages/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub fn parse_bmp_common_header(data: &mut Bytes) -> Result<BmpCommonHeader, Pars
/// | Timestamp (microseconds) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
#[derive(Debug)]
#[derive(Debug, Clone, PartialEq)]
pub struct BmpPerPeerHeader {
pub peer_type: BmpPeerType,
pub peer_flags: PerPeerFlags,
Expand Down Expand Up @@ -124,7 +124,7 @@ impl BmpPerPeerHeader {
///
/// - RFC7854: https://datatracker.ietf.org/doc/html/rfc7854#section-4.2
/// - RFC9069: https://datatracker.ietf.org/doc/html/rfc9069
#[derive(Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq, Hash)]
#[derive(Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq, Hash, Clone)]
#[repr(u8)]
pub enum BmpPeerType {
Global = 0,
Expand Down
6 changes: 4 additions & 2 deletions src/parser/bmp/messages/initiation_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bytes::{Buf, Bytes};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::convert::TryFrom;

#[derive(Debug)]
#[derive(Debug, Clone, PartialEq)]
pub struct InitiationMessage {
pub tlvs: Vec<InitiationTlv>,
}
Expand All @@ -18,13 +18,15 @@ pub struct InitiationTlv {

///Type-Length-Value Type
///
/// For more, see: https://datatracker.ietf.org/doc/html/rfc1213
/// https://www.iana.org/assignments/bmp-parameters/bmp-parameters.xhtml#initiation-peer-up-tlvs
#[derive(Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Clone, Copy)]
#[repr(u16)]
pub enum InitiationTlvType {
String = 0,
SysDescr = 1,
SysName = 2,
VrTableName = 3,
AdminLabel = 4,
}

/// Parse BMP initiation message
Expand Down
83 changes: 68 additions & 15 deletions src/parser/bmp/messages/peer_down_notification.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
use crate::parser::bmp::error::ParserBmpError;
use crate::parser::ReadUtils;
use bytes::{Buf, Bytes};
use num_enum::{IntoPrimitive, TryFromPrimitive};

#[derive(Debug)]
#[derive(Debug, PartialEq, Clone)]
pub struct PeerDownNotification {
pub reason: u8,
pub reason: PeerDownReason,
pub data: Option<Vec<u8>>,
}

#[derive(Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Clone, Copy)]
#[repr(u8)]
pub enum PeerDownReason {
Reserved = 0,
LocalSystemClosedNotificationPduFollows = 1,
LocalSystemClosedFsmEvenFollows = 2,
RemoteSystemClosedNotificationPduFollows = 3,
RemoteSystemsClosedNoData,
PeerDeConfigured = 5,
LocalSystemClosedTlvDataFollows = 6,
}

pub fn parse_peer_down_notification(
data: &mut Bytes,
) -> Result<PeerDownNotification, ParserBmpError> {
let reason = data.read_u8()?;
let reason = PeerDownReason::try_from(data.read_u8()?)?;
let bytes_left = data.remaining();
let data: Option<Vec<u8>> = match reason {
1 => {
PeerDownReason::Reserved => match bytes_left {
0 => None,
_ => Some(data.read_n_bytes(bytes_left)?),
},
PeerDownReason::LocalSystemClosedNotificationPduFollows => {
/*
The local system closed the session. Following the
Reason is a BGP PDU containing a BGP NOTIFICATION message that
would have been sent to the peer.
*/
Some(data.read_n_bytes(bytes_left)?)
}
2 => {
PeerDownReason::LocalSystemClosedFsmEvenFollows => {
/*
The local system closed the session. No notification
message was sent. Following the reason code is a 2-byte field
Expand All @@ -33,15 +50,15 @@ pub fn parse_peer_down_notification(
*/
Some(data.read_n_bytes(bytes_left)?)
}
3 => {
PeerDownReason::RemoteSystemClosedNotificationPduFollows => {
/*
The remote system closed the session with a notification
message. Following the Reason is a BGP PDU containing the BGP
NOTIFICATION message as received from the peer.
*/
Some(data.read_n_bytes(bytes_left)?)
}
4 => {
PeerDownReason::RemoteSystemsClosedNoData => {
/*
The remote system closed the session without a
notification message. This includes any unexpected termination of
Expand All @@ -50,7 +67,7 @@ pub fn parse_peer_down_notification(
*/
None
}
5 => {
PeerDownReason::PeerDeConfigured => {
/*
Information for this peer will no longer be sent to the
monitoring station for configuration reasons. This does not,
Expand All @@ -60,7 +77,14 @@ pub fn parse_peer_down_notification(
*/
None
}
_ => return Err(ParserBmpError::CorruptedBmpMessage),
PeerDownReason::LocalSystemClosedTlvDataFollows => {
/*
https://www.rfc-editor.org/rfc/rfc9069.html#name-peer-down-notification
The Peer Down notification MUST use reason code 6. Following the reason
is data in TLV format. The following Peer Down Information TLV type is defined:
*/
Some(data.read_n_bytes(bytes_left)?)
}
};
Ok(PeerDownNotification { reason, data })
}
Expand All @@ -80,7 +104,10 @@ mod tests {
let result = parse_peer_down_notification(&mut data);
assert!(result.is_ok());
let peer_down_notification = result.unwrap();
assert_eq!(peer_down_notification.reason, 1);
assert_eq!(
peer_down_notification.reason,
PeerDownReason::LocalSystemClosedNotificationPduFollows
);
assert_eq!(peer_down_notification.data.unwrap(), vec![0u8; 10]);

// Test with reason `2`
Expand All @@ -91,7 +118,10 @@ mod tests {
let result = parse_peer_down_notification(&mut data);
assert!(result.is_ok());
let peer_down_notification = result.unwrap();
assert_eq!(peer_down_notification.reason, 2);
assert_eq!(
peer_down_notification.reason,
PeerDownReason::LocalSystemClosedFsmEvenFollows
);
assert_eq!(peer_down_notification.data.unwrap(), vec![0u8; 10]);

// Test with reason `3`
Expand All @@ -102,7 +132,10 @@ mod tests {
let result = parse_peer_down_notification(&mut data);
assert!(result.is_ok());
let peer_down_notification = result.unwrap();
assert_eq!(peer_down_notification.reason, 3);
assert_eq!(
peer_down_notification.reason,
PeerDownReason::RemoteSystemClosedNotificationPduFollows
);
assert_eq!(peer_down_notification.data.unwrap(), vec![0u8; 10]);

// Test with reason `4`
Expand All @@ -112,7 +145,10 @@ mod tests {
let result = parse_peer_down_notification(&mut data);
assert!(result.is_ok());
let peer_down_notification = result.unwrap();
assert_eq!(peer_down_notification.reason, 4);
assert_eq!(
peer_down_notification.reason,
PeerDownReason::RemoteSystemsClosedNoData
);
assert!(peer_down_notification.data.is_none());

// Test with reason `5`
Expand All @@ -122,12 +158,29 @@ mod tests {
let result = parse_peer_down_notification(&mut data);
assert!(result.is_ok());
let peer_down_notification = result.unwrap();
assert_eq!(peer_down_notification.reason, 5);
assert_eq!(
peer_down_notification.reason,
PeerDownReason::PeerDeConfigured
);
assert!(peer_down_notification.data.is_none());

// Test with invalid reason
// Test with reason `5`
let mut data = bytes::BytesMut::new();
data.put_u8(6);
data.put_slice(&[0u8; 10]);
let mut data = data.freeze();
let result = parse_peer_down_notification(&mut data);
assert!(result.is_ok());
let peer_down_notification = result.unwrap();
assert_eq!(
peer_down_notification.reason,
PeerDownReason::LocalSystemClosedTlvDataFollows
);
assert_eq!(peer_down_notification.data.unwrap(), vec![0u8; 10]);

// Test with invalid reason
let mut data = bytes::BytesMut::new();
data.put_u8(7);
let mut data = data.freeze();
let result = parse_peer_down_notification(&mut data);
assert!(result.is_err());
Expand Down
Loading

0 comments on commit 51f8540

Please sign in to comment.