use crate::bgp::parse_bgp_message;
use crate::models::capabilities::BgpCapabilityType;
use crate::models::*;
use crate::parser::bmp::error::ParserBmpError;
use crate::parser::bmp::messages::BmpPeerType;
use crate::parser::ReadUtils;
use bytes::{Buf, Bytes};
use log::warn;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::net::IpAddr;
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
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, TryFromPrimitive, IntoPrimitive, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u16)]
pub enum PeerUpTlvType {
String = 0,
SysDescr = 1,
SysName = 2,
VrTableName = 3,
AdminLabel = 4,
}
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PeerUpNotificationTlv {
pub info_type: PeerUpTlvType,
pub info_len: u16,
pub info_value: String,
}
pub fn parse_peer_up_notification(
data: &mut Bytes,
afi: &Afi,
asn_len: &AsnLength,
peer_type: Option<&BmpPeerType>,
) -> Result<PeerUpNotification, ParserBmpError> {
let local_addr: IpAddr = match afi {
Afi::Ipv4 => {
data.has_n_remaining(12)?;
data.advance(12);
let ip = data.read_ipv4_address()?;
ip.into()
}
Afi::Ipv6 => data.read_ipv6_address()?.into(),
Afi::LinkState => {
data.has_n_remaining(12)?;
data.advance(12);
std::net::Ipv4Addr::new(0, 0, 0, 0).into()
}
};
let local_port = data.read_u16()?;
let remote_port = data.read_u16()?;
data.has_n_remaining(19)?; let bgp1_length = u16::from_be_bytes([data[16], data[17]]) as usize;
data.has_n_remaining(bgp1_length)?;
let mut bgp1_data = data.split_to(bgp1_length);
let sent_open = parse_bgp_message(&mut bgp1_data, false, asn_len)?;
data.has_n_remaining(19)?; let bgp2_length = u16::from_be_bytes([data[16], data[17]]) as usize;
data.has_n_remaining(bgp2_length)?;
let mut bgp2_data = data.split_to(bgp2_length);
let received_open = parse_bgp_message(&mut bgp2_data, false, asn_len)?;
if let Some(BmpPeerType::LocalRib) = peer_type {
if let BgpMessage::Open(ref open_msg) = &sent_open {
let has_multiprotocol_capability = open_msg.opt_params.iter().any(|param| {
if let ParamValue::Capacities(caps) = ¶m.param_value {
caps.iter()
.any(|cap| cap.ty == BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4)
} else {
false
}
});
if !has_multiprotocol_capability {
warn!("RFC 9069: Local RIB peer up notification should include multiprotocol capabilities in fabricated OPEN messages (parsing Peer Up Notification)");
}
}
}
let mut tlvs = vec![];
let mut has_vr_table_name = false;
while data.remaining() >= 4 {
let info_type = PeerUpTlvType::try_from(data.read_u16()?)?;
let info_len = data.read_u16()?;
let info_value = data.read_n_bytes_to_string(info_len as usize)?;
if let Some(BmpPeerType::LocalRib) = peer_type {
if info_type == PeerUpTlvType::VrTableName {
has_vr_table_name = true;
if info_value.is_empty() || info_value.len() > 255 {
warn!(
"RFC 9069: VrTableName TLV length must be 1-255 bytes, found {} bytes (parsing Peer Up Notification)",
info_value.len()
);
}
}
}
tlvs.push(PeerUpNotificationTlv {
info_type,
info_len,
info_value,
})
}
if let Some(BmpPeerType::LocalRib) = peer_type {
if !has_vr_table_name {
warn!("RFC 9069: Local RIB peer up notification should include VrTableName TLV (parsing Peer Up Notification)");
}
}
Ok(PeerUpNotification {
local_addr,
local_port,
remote_port,
sent_open,
received_open,
tlvs,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::capabilities::{BgpCapabilityType, MultiprotocolExtensionsCapability};
use bytes::BytesMut;
use std::cell::RefCell;
use std::net::{IpAddr, Ipv4Addr};
use std::sync::{Arc, Mutex, Once};
thread_local! {
static WARNING_CAPTURE: RefCell<Option<Arc<Mutex<Vec<String>>>>> = const { RefCell::new(None) };
}
struct WarningCaptureGuard {
warnings: Arc<Mutex<Vec<String>>>,
}
impl WarningCaptureGuard {
fn warnings(&self) -> &Arc<Mutex<Vec<String>>> {
&self.warnings
}
}
impl Drop for WarningCaptureGuard {
fn drop(&mut self) {
clear_warning_logger();
}
}
#[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,
bgp_identifier: Ipv4Addr::new(0, 0, 0, 0),
extended_length: false,
opt_params: vec![],
});
let bgp_open_message_bytes = bgp_open_message.encode(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, None);
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, PeerUpTlvType::SysDescr);
assert_eq!(tlv.info_len, 2);
assert_eq!(tlv.info_value, "\u{0}\u{3}");
}
Err(_) => {
panic!("parse_peer_up_notification should return Ok");
}
}
}
fn setup_warning_logger() -> WarningCaptureGuard {
use log::{Level, Record};
static LOGGER_INIT: Once = Once::new();
struct TestLogger;
impl log::Log for TestLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= Level::Warn
}
fn log(&self, record: &Record) {
if record.level() <= Level::Warn {
WARNING_CAPTURE.with(|capture| {
if let Some(warnings) = capture.borrow().as_ref() {
match warnings.lock() {
Ok(mut warnings) => warnings.push(record.args().to_string()),
Err(poisoned) => {
poisoned.into_inner().push(record.args().to_string());
}
}
}
});
}
}
fn flush(&self) {}
}
LOGGER_INIT.call_once(|| {
log::set_boxed_logger(Box::new(TestLogger)).unwrap();
log::set_max_level(log::LevelFilter::Warn);
});
let warnings = Arc::new(Mutex::new(Vec::new()));
WARNING_CAPTURE.with(|capture| {
*capture.borrow_mut() = Some(warnings.clone());
});
WarningCaptureGuard { warnings }
}
fn clear_warning_logger() {
WARNING_CAPTURE.with(|capture| {
*capture.borrow_mut() = None;
});
}
#[test]
fn test_parse_peer_up_notification_no_warnings() {
let warnings = setup_warning_logger();
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp1 = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_16bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![],
});
let bgp1_bytes = bgp1.encode(AsnLength::Bits32);
let bgp2 = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_16bit(65002),
hold_time: 90,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 2),
extended_length: false,
opt_params: vec![],
});
let bgp2_bytes = bgp2.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp1_bytes);
data.extend_from_slice(&bgp2_bytes);
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x08, ]);
data.extend_from_slice(b"TestNode");
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
assert!(result.is_ok(), "Parsing should succeed without warnings");
let peer_notification = result.unwrap();
assert_eq!(
peer_notification.local_addr,
IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))
);
assert_eq!(peer_notification.local_port, 179);
assert_eq!(peer_notification.remote_port, 179);
if let crate::models::BgpMessage::Open(ref open1) = &peer_notification.sent_open {
assert_eq!(open1.asn, crate::models::Asn::new_16bit(65001));
} else {
panic!("sent_open should be an OPEN message");
}
if let crate::models::BgpMessage::Open(ref open2) = &peer_notification.received_open {
assert_eq!(open2.asn, crate::models::Asn::new_16bit(65002));
} else {
panic!("received_open should be an OPEN message");
}
assert_eq!(peer_notification.tlvs.len(), 1);
assert_eq!(peer_notification.tlvs[0].info_type, PeerUpTlvType::String);
assert_eq!(peer_notification.tlvs[0].info_value, "TestNode");
let captured_warnings = warnings.warnings().lock().unwrap();
assert!(
captured_warnings.is_empty(),
"Test should not produce warnings, but got: {:?}",
*captured_warnings
);
}
#[test]
fn test_parse_peer_up_insufficient_data_first_bgp() {
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]);
data.extend_from_slice(&[
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x40, 0x01, ]);
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
assert!(
result.is_err(),
"Should fail with insufficient data for first BGP message"
);
}
#[test]
fn test_parse_peer_up_insufficient_data_second_bgp() {
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 = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: Default::default(),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(0, 0, 0, 0),
extended_length: false,
opt_params: vec![],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&[
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x30, ]);
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
assert!(
result.is_err(),
"Should fail with insufficient data for second BGP message"
);
}
#[test]
fn test_parse_peer_up_excess_data_in_tlvs() {
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 = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: Default::default(),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(0, 0, 0, 0),
extended_length: false,
opt_params: vec![],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&[0x00, 0x00]); data.extend_from_slice(&[0x00, 0x04]); data.extend_from_slice(b"Test");
data.extend_from_slice(&[0x00, 0x00]); data.extend_from_slice(&[0x00, 0x06]); data.extend_from_slice(b"Router");
data.extend_from_slice(&[0x00, 0x01, 0x02]);
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
assert!(result.is_ok(), "Should handle excess data gracefully");
let peer_notification = result.unwrap();
assert_eq!(peer_notification.tlvs.len(), 2); assert_eq!(peer_notification.tlvs[0].info_type, PeerUpTlvType::String);
assert_eq!(peer_notification.tlvs[0].info_value, "Test");
assert_eq!(peer_notification.tlvs[1].info_type, PeerUpTlvType::String);
assert_eq!(peer_notification.tlvs[1].info_value, "Router");
}
#[test]
fn test_local_rib_without_multiprotocol_capability() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_32bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![], });
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let peer_type = BmpPeerType::LocalRib;
let result =
parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
assert!(result.is_ok(), "Parsing should succeed");
}
#[test]
fn test_local_rib_with_multiprotocol_capability() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_32bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![OptParam {
param_type: 2, param_len: 6,
param_value: ParamValue::Capacities(vec![Capability {
ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
value: CapabilityValue::MultiprotocolExtensions(
MultiprotocolExtensionsCapability {
afi: Afi::Ipv4,
safi: Safi::Unicast,
},
),
}]),
}],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let peer_type = BmpPeerType::LocalRib;
let result =
parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
assert!(result.is_ok(), "Parsing should succeed");
}
#[test]
fn test_local_rib_without_vr_table_name_tlv() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_32bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![OptParam {
param_type: 2, param_len: 6,
param_value: ParamValue::Capacities(vec![Capability {
ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
value: CapabilityValue::MultiprotocolExtensions(
MultiprotocolExtensionsCapability {
afi: Afi::Ipv4,
safi: Safi::Unicast,
},
),
}]),
}],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&[0x00, 0x00]); data.extend_from_slice(&[0x00, 0x04]); data.extend_from_slice(b"Test");
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let peer_type = BmpPeerType::LocalRib;
let result =
parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
assert!(result.is_ok(), "Parsing should succeed");
}
#[test]
fn test_local_rib_with_valid_vr_table_name_tlv() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_32bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![OptParam {
param_type: 2, param_len: 6,
param_value: ParamValue::Capacities(vec![Capability {
ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
value: CapabilityValue::MultiprotocolExtensions(
MultiprotocolExtensionsCapability {
afi: Afi::Ipv4,
safi: Safi::Unicast,
},
),
}]),
}],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x00, 0x08]); data.extend_from_slice(b"LocalRIB");
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let peer_type = BmpPeerType::LocalRib;
let result =
parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
assert!(result.is_ok(), "Parsing should succeed");
let peer_notification = result.unwrap();
assert_eq!(peer_notification.tlvs.len(), 1);
assert_eq!(
peer_notification.tlvs[0].info_type,
PeerUpTlvType::VrTableName
);
assert_eq!(peer_notification.tlvs[0].info_value, "LocalRIB");
}
#[test]
fn test_local_rib_with_empty_vr_table_name() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_32bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![OptParam {
param_type: 2, param_len: 6,
param_value: ParamValue::Capacities(vec![Capability {
ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
value: CapabilityValue::MultiprotocolExtensions(
MultiprotocolExtensionsCapability {
afi: Afi::Ipv4,
safi: Safi::Unicast,
},
),
}]),
}],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x00, 0x00]);
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let peer_type = BmpPeerType::LocalRib;
let result =
parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
assert!(result.is_ok(), "Parsing should succeed");
}
#[test]
fn test_local_rib_with_oversized_vr_table_name() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_32bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![OptParam {
param_type: 2, param_len: 6,
param_value: ParamValue::Capacities(vec![Capability {
ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
value: CapabilityValue::MultiprotocolExtensions(
MultiprotocolExtensionsCapability {
afi: Afi::Ipv4,
safi: Safi::Unicast,
},
),
}]),
}],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
let oversized_name = "A".repeat(256);
data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x01, 0x00]); data.extend_from_slice(oversized_name.as_bytes());
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let peer_type = BmpPeerType::LocalRib;
let result =
parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
assert!(result.is_ok(), "Parsing should succeed");
}
#[test]
fn test_non_local_rib_no_validation() {
let mut data = BytesMut::new();
data.extend_from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: crate::models::Asn::new_32bit(65001),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
extended_length: false,
opt_params: vec![],
});
let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
data.extend_from_slice(&bgp_bytes);
data.extend_from_slice(&bgp_bytes);
let afi = Afi::Ipv4;
let asn_len = AsnLength::Bits32;
let peer_type = BmpPeerType::Global;
let result =
parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
assert!(result.is_ok(), "Parsing should succeed");
}
}