use crate::bgp::parse_bgp_message;
use crate::models::*;
use crate::parser::bmp::error::ParserBmpError;
use crate::parser::ReadUtils;
use bytes::{Buf, Bytes};
use std::net::IpAddr;
#[derive(Debug)]
pub struct PeerUpNotification {
pub local_addr: IpAddr,
pub local_port: u16,
pub remote_port: u16,
pub sent_open: BgpMessage,
pub received_open: BgpMessage,
pub tlvs: Vec<PeerUpNotificationTlv>,
}
#[derive(Debug)]
pub struct PeerUpNotificationTlv {
pub info_type: u16,
pub info_len: u16,
pub info_value: String,
}
pub fn parse_peer_up_notification(
data: &mut Bytes,
afi: &Afi,
asn_len: &AsnLength,
) -> Result<PeerUpNotification, ParserBmpError> {
let local_addr: IpAddr = match afi {
Afi::Ipv4 => {
data.advance(12);
let ip = data.read_ipv4_address()?;
ip.into()
}
Afi::Ipv6 => data.read_ipv6_address()?.into(),
};
let local_port = data.read_u16()?;
let remote_port = data.read_u16()?;
let sent_open = parse_bgp_message(data, false, asn_len)?;
let received_open = parse_bgp_message(data, false, asn_len)?;
let mut tlvs = vec![];
while data.remaining() >= 4 {
let info_type = data.read_u16()?;
let info_len = data.read_u16()?;
let info_value = data.read_n_bytes_to_string(info_len as usize)?;
tlvs.push(PeerUpNotificationTlv {
info_type,
info_len,
info_value,
})
}
Ok(PeerUpNotification {
local_addr,
local_port,
remote_port,
sent_open,
received_open,
tlvs,
})
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::BytesMut;
use std::net::{IpAddr, Ipv4Addr};
#[test]
fn test_parse_peer_up_notification() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01,
0x01, 0x01,
]);
data.extend_from_slice(&[0x1F, 0x40]); data.extend_from_slice(&[0x23, 0x28]); let bgp_open_message = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 0,
asn: Default::default(),
hold_time: 0,
sender_ip: Ipv4Addr::new(0, 0, 0, 0),
extended_length: false,
opt_params: vec![],
});
let bgp_open_message_bytes = bgp_open_message.encode(false, AsnLength::Bits32);
data.extend_from_slice(&bgp_open_message_bytes);
data.extend_from_slice(&bgp_open_message_bytes);
data.extend_from_slice(&[0x00, 0x01]); data.extend_from_slice(&[0x00, 0x02]); data.extend_from_slice(&[0x00, 0x03]); let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len);
match result {
Ok(peer_notification) => {
assert_eq!(
peer_notification.local_addr,
IpAddr::V4(std::net::Ipv4Addr::new(10, 1, 1, 1))
);
assert_eq!(peer_notification.local_port, 8000);
assert_eq!(peer_notification.remote_port, 9000);
let tlv = peer_notification.tlvs.first().unwrap();
assert_eq!(tlv.info_type, 1);
assert_eq!(tlv.info_len, 2);
assert_eq!(tlv.info_value, "\u{0}\u{3}");
}
Err(_) => {
assert!(false, "parse_peer_up_notification should return Ok");
}
}
}
}