1use crate::bgp::parse_bgp_message;
2use crate::models::capabilities::BgpCapabilityType;
3use crate::models::*;
4use crate::parser::bmp::error::ParserBmpError;
5use crate::parser::bmp::messages::BmpPeerType;
6use crate::parser::ReadUtils;
7use bytes::{Buf, Bytes};
8use log::warn;
9use num_enum::{FromPrimitive, IntoPrimitive};
10use std::net::IpAddr;
11
12#[derive(Debug, PartialEq, Clone)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct PeerUpNotification {
15 pub local_addr: IpAddr,
16 pub local_port: u16,
17 pub remote_port: u16,
18 pub sent_open: BgpMessage,
19 pub received_open: BgpMessage,
20 pub tlvs: Vec<PeerUpNotificationTlv>,
21}
22
23#[derive(Debug, FromPrimitive, IntoPrimitive, PartialEq, Clone, Copy)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33#[repr(u16)]
34pub enum PeerUpTlvType {
35 String = 0,
36 SysDescr = 1,
38 SysName = 2,
40 VrTableName = 3,
41 AdminLabel = 4,
42 #[num_enum(catch_all)]
43 Unknown(u16) = 65535,
44}
45
46#[derive(Debug, PartialEq, Clone)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct PeerUpNotificationTlv {
49 pub info_type: PeerUpTlvType,
50 pub info_len: u16,
51 pub info_value: String,
52}
53
54pub fn parse_peer_up_notification(
55 data: &mut Bytes,
56 afi: &Afi,
57 asn_len: &AsnLength,
58 peer_type: Option<&BmpPeerType>,
59) -> Result<PeerUpNotification, ParserBmpError> {
60 let local_addr: IpAddr = match afi {
61 Afi::Ipv4 => {
62 data.has_n_remaining(12)?;
63 data.advance(12);
64 let ip = data.read_ipv4_address()?;
65 ip.into()
66 }
67 Afi::Ipv6 => data.read_ipv6_address()?.into(),
68 Afi::LinkState => {
69 data.has_n_remaining(12)?;
72 data.advance(12);
73 std::net::Ipv4Addr::new(0, 0, 0, 0).into()
74 }
75 };
76
77 let local_port = data.read_u16()?;
78 let remote_port = data.read_u16()?;
79
80 data.has_n_remaining(19)?; let bgp1_length = u16::from_be_bytes([data[16], data[17]]) as usize;
83 data.has_n_remaining(bgp1_length)?;
84 let mut bgp1_data = data.split_to(bgp1_length);
85 let sent_open = parse_bgp_message(&mut bgp1_data, false, asn_len)?;
86
87 data.has_n_remaining(19)?; let bgp2_length = u16::from_be_bytes([data[16], data[17]]) as usize;
90 data.has_n_remaining(bgp2_length)?;
91 let mut bgp2_data = data.split_to(bgp2_length);
92 let received_open = parse_bgp_message(&mut bgp2_data, false, asn_len)?;
93
94 if let Some(BmpPeerType::LocalRib) = peer_type {
96 if let BgpMessage::Open(ref open_msg) = &sent_open {
98 let has_multiprotocol_capability = open_msg.opt_params.iter().any(|param| {
99 if let ParamValue::Capacities(caps) = ¶m.param_value {
100 caps.iter()
101 .any(|cap| cap.ty == BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4)
102 } else {
103 false
104 }
105 });
106 if !has_multiprotocol_capability {
107 warn!("RFC 9069: Local RIB peer up notification should include multiprotocol capabilities in fabricated OPEN messages (parsing Peer Up Notification)");
108 }
109 }
110 }
111
112 let mut tlvs = vec![];
113 let mut has_vr_table_name = false;
114
115 while data.remaining() >= 4 {
116 let info_type = PeerUpTlvType::from(data.read_u16()?);
117 let info_len = data.read_u16()?;
118 let info_value = data.read_n_bytes_to_string(info_len as usize)?;
119
120 if let Some(BmpPeerType::LocalRib) = peer_type {
122 if info_type == PeerUpTlvType::VrTableName {
123 has_vr_table_name = true;
124 if info_value.is_empty() || info_value.len() > 255 {
126 warn!(
127 "RFC 9069: VrTableName TLV length must be 1-255 bytes, found {} bytes (parsing Peer Up Notification)",
128 info_value.len()
129 );
130 }
131 }
132 }
133
134 tlvs.push(PeerUpNotificationTlv {
135 info_type,
136 info_len,
137 info_value,
138 })
139 }
140
141 if let Some(BmpPeerType::LocalRib) = peer_type {
143 if !has_vr_table_name {
144 warn!("RFC 9069: Local RIB peer up notification should include VrTableName TLV (parsing Peer Up Notification)");
145 }
146 }
147 Ok(PeerUpNotification {
148 local_addr,
149 local_port,
150 remote_port,
151 sent_open,
152 received_open,
153 tlvs,
154 })
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use crate::models::capabilities::{BgpCapabilityType, MultiprotocolExtensionsCapability};
161 use bytes::BytesMut;
162 use std::cell::RefCell;
163 use std::net::{IpAddr, Ipv4Addr};
164 use std::sync::{Arc, Mutex, Once};
165
166 thread_local! {
167 static WARNING_CAPTURE: RefCell<Option<Arc<Mutex<Vec<String>>>>> = const { RefCell::new(None) };
168 }
169
170 struct WarningCaptureGuard {
171 warnings: Arc<Mutex<Vec<String>>>,
172 }
173
174 impl WarningCaptureGuard {
175 fn warnings(&self) -> &Arc<Mutex<Vec<String>>> {
176 &self.warnings
177 }
178 }
179
180 impl Drop for WarningCaptureGuard {
181 fn drop(&mut self) {
182 clear_warning_logger();
183 }
184 }
185
186 #[test]
187 fn test_parse_peer_up_notification() {
188 let mut data = BytesMut::new();
189 data.extend_from_slice(&[
192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01,
193 0x01, 0x01,
194 ]);
195 data.extend_from_slice(&[0x1F, 0x40]); data.extend_from_slice(&[0x23, 0x28]); let bgp_open_message = crate::models::BgpMessage::Open(BgpOpenMessage {
199 version: 0,
200 asn: Default::default(),
201 hold_time: 0,
202 bgp_identifier: Ipv4Addr::new(0, 0, 0, 0),
203 extended_length: false,
204 opt_params: vec![],
205 });
206 let bgp_open_message_bytes = bgp_open_message.encode(AsnLength::Bits32);
207 data.extend_from_slice(&bgp_open_message_bytes);
208 data.extend_from_slice(&bgp_open_message_bytes);
209
210 data.extend_from_slice(&[0x00, 0x01]); data.extend_from_slice(&[0x00, 0x02]); data.extend_from_slice(&[0x00, 0x03]); let afi = Afi::Ipv4;
216 let asn_len = AsnLength::Bits32;
217
218 let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
219
220 match result {
221 Ok(peer_notification) => {
222 assert_eq!(
223 peer_notification.local_addr,
224 IpAddr::V4(std::net::Ipv4Addr::new(10, 1, 1, 1))
225 );
226 assert_eq!(peer_notification.local_port, 8000);
227 assert_eq!(peer_notification.remote_port, 9000);
228
229 let tlv = peer_notification.tlvs.first().unwrap();
231 assert_eq!(tlv.info_type, PeerUpTlvType::SysDescr);
232 assert_eq!(tlv.info_len, 2);
233 assert_eq!(tlv.info_value, "\u{0}\u{3}");
234 }
235 Err(_) => {
236 panic!("parse_peer_up_notification should return Ok");
237 }
238 }
239 }
240
241 fn setup_warning_logger() -> WarningCaptureGuard {
243 use log::{Level, Record};
244
245 static LOGGER_INIT: Once = Once::new();
246
247 struct TestLogger;
248
249 impl log::Log for TestLogger {
250 fn enabled(&self, metadata: &log::Metadata) -> bool {
251 metadata.level() <= Level::Warn
252 }
253
254 fn log(&self, record: &Record) {
255 if record.level() <= Level::Warn {
256 WARNING_CAPTURE.with(|capture| {
257 if let Some(warnings) = capture.borrow().as_ref() {
258 match warnings.lock() {
259 Ok(mut warnings) => warnings.push(record.args().to_string()),
260 Err(poisoned) => {
261 poisoned.into_inner().push(record.args().to_string());
262 }
263 }
264 }
265 });
266 }
267 }
268
269 fn flush(&self) {}
270 }
271
272 LOGGER_INIT.call_once(|| {
273 log::set_boxed_logger(Box::new(TestLogger)).unwrap();
274 log::set_max_level(log::LevelFilter::Warn);
275 });
276
277 let warnings = Arc::new(Mutex::new(Vec::new()));
278 WARNING_CAPTURE.with(|capture| {
279 *capture.borrow_mut() = Some(warnings.clone());
280 });
281 WarningCaptureGuard { warnings }
282 }
283
284 fn clear_warning_logger() {
285 WARNING_CAPTURE.with(|capture| {
286 *capture.borrow_mut() = None;
287 });
288 }
289
290 #[test]
296 fn test_parse_peer_up_notification_no_warnings() {
297 let warnings = setup_warning_logger();
298
299 let mut data = BytesMut::new();
304
305 data.extend_from_slice(&[
307 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
308 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
312
313 let bgp1 = crate::models::BgpMessage::Open(BgpOpenMessage {
318 version: 4,
319 asn: crate::models::Asn::new_16bit(65001),
320 hold_time: 180,
321 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
322 extended_length: false,
323 opt_params: vec![],
324 });
325 let bgp1_bytes = bgp1.encode(AsnLength::Bits32);
326
327 let bgp2 = crate::models::BgpMessage::Open(BgpOpenMessage {
329 version: 4,
330 asn: crate::models::Asn::new_16bit(65002),
331 hold_time: 90,
332 bgp_identifier: Ipv4Addr::new(192, 168, 1, 2),
333 extended_length: false,
334 opt_params: vec![],
335 });
336 let bgp2_bytes = bgp2.encode(AsnLength::Bits32);
337
338 data.extend_from_slice(&bgp1_bytes);
340 data.extend_from_slice(&bgp2_bytes);
341
342 data.extend_from_slice(&[
344 0x00, 0x00, 0x00, 0x08, ]);
347 data.extend_from_slice(b"TestNode");
348
349 let afi = Afi::Ipv4;
350 let asn_len = AsnLength::Bits32;
351
352 let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
353
354 assert!(result.is_ok(), "Parsing should succeed without warnings");
356
357 let peer_notification = result.unwrap();
358 assert_eq!(
359 peer_notification.local_addr,
360 IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))
361 );
362 assert_eq!(peer_notification.local_port, 179);
363 assert_eq!(peer_notification.remote_port, 179);
364
365 if let crate::models::BgpMessage::Open(ref open1) = &peer_notification.sent_open {
367 assert_eq!(open1.asn, crate::models::Asn::new_16bit(65001));
368 } else {
369 panic!("sent_open should be an OPEN message");
370 }
371
372 if let crate::models::BgpMessage::Open(ref open2) = &peer_notification.received_open {
373 assert_eq!(open2.asn, crate::models::Asn::new_16bit(65002));
374 } else {
375 panic!("received_open should be an OPEN message");
376 }
377
378 assert_eq!(peer_notification.tlvs.len(), 1);
380 assert_eq!(peer_notification.tlvs[0].info_type, PeerUpTlvType::String);
381 assert_eq!(peer_notification.tlvs[0].info_value, "TestNode");
382
383 let captured_warnings = warnings.warnings().lock().unwrap();
385 assert!(
386 captured_warnings.is_empty(),
387 "Test should not produce warnings, but got: {:?}",
388 *captured_warnings
389 );
390 }
391
392 #[test]
393 fn test_parse_peer_up_insufficient_data_first_bgp() {
394 let mut data = BytesMut::new();
395
396 data.extend_from_slice(&[
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01,
399 0x01, 0x01,
400 ]);
401 data.extend_from_slice(&[0x1F, 0x40]); data.extend_from_slice(&[0x23, 0x28]); data.extend_from_slice(&[
406 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
408 0x40, 0x01, ]);
411 let afi = Afi::Ipv4;
414 let asn_len = AsnLength::Bits32;
415 let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
416
417 assert!(
418 result.is_err(),
419 "Should fail with insufficient data for first BGP message"
420 );
421 }
422
423 #[test]
424 fn test_parse_peer_up_insufficient_data_second_bgp() {
425 let mut data = BytesMut::new();
426
427 data.extend_from_slice(&[
429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01,
430 0x01, 0x01,
431 ]);
432 data.extend_from_slice(&[0x1F, 0x40]); data.extend_from_slice(&[0x23, 0x28]); let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
437 version: 4,
438 asn: Default::default(),
439 hold_time: 180,
440 bgp_identifier: Ipv4Addr::new(0, 0, 0, 0),
441 extended_length: false,
442 opt_params: vec![],
443 });
444 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
445 data.extend_from_slice(&bgp_bytes);
446
447 data.extend_from_slice(&[
449 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
451 0x30, ]);
454
455 let afi = Afi::Ipv4;
456 let asn_len = AsnLength::Bits32;
457 let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
458
459 assert!(
460 result.is_err(),
461 "Should fail with insufficient data for second BGP message"
462 );
463 }
464
465 #[test]
466 fn test_parse_peer_up_excess_data_in_tlvs() {
467 let mut data = BytesMut::new();
468
469 data.extend_from_slice(&[
471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01,
472 0x01, 0x01,
473 ]);
474 data.extend_from_slice(&[0x1F, 0x40]); data.extend_from_slice(&[0x23, 0x28]); let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
479 version: 4,
480 asn: Default::default(),
481 hold_time: 180,
482 bgp_identifier: Ipv4Addr::new(0, 0, 0, 0),
483 extended_length: false,
484 opt_params: vec![],
485 });
486 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
487 data.extend_from_slice(&bgp_bytes);
488 data.extend_from_slice(&bgp_bytes);
489
490 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;
503 let asn_len = AsnLength::Bits32;
504 let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
505
506 assert!(result.is_ok(), "Should handle excess data gracefully");
508
509 let peer_notification = result.unwrap();
510 assert_eq!(peer_notification.tlvs.len(), 2); assert_eq!(peer_notification.tlvs[0].info_type, PeerUpTlvType::String);
512 assert_eq!(peer_notification.tlvs[0].info_value, "Test");
513 assert_eq!(peer_notification.tlvs[1].info_type, PeerUpTlvType::String);
514 assert_eq!(peer_notification.tlvs[1].info_value, "Router");
515 }
516
517 #[test]
518 fn test_local_rib_without_multiprotocol_capability() {
519 let mut data = BytesMut::new();
522
523 data.extend_from_slice(&[
525 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
526 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
530
531 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
533 version: 4,
534 asn: crate::models::Asn::new_32bit(65001),
535 hold_time: 180,
536 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
537 extended_length: false,
538 opt_params: vec![], });
540 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
541 data.extend_from_slice(&bgp_bytes);
542 data.extend_from_slice(&bgp_bytes);
543
544 let afi = Afi::Ipv4;
545 let asn_len = AsnLength::Bits32;
546 let peer_type = BmpPeerType::LocalRib;
547
548 let result =
549 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
550
551 assert!(result.is_ok(), "Parsing should succeed");
552 }
554
555 #[test]
556 fn test_local_rib_with_multiprotocol_capability() {
557 let mut data = BytesMut::new();
560
561 data.extend_from_slice(&[
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
564 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
568
569 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
571 version: 4,
572 asn: crate::models::Asn::new_32bit(65001),
573 hold_time: 180,
574 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
575 extended_length: false,
576 opt_params: vec![OptParam {
577 param_type: 2, param_len: 6,
579 param_value: ParamValue::Capacities(vec![Capability {
580 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
581 value: CapabilityValue::MultiprotocolExtensions(
582 MultiprotocolExtensionsCapability {
583 afi: Afi::Ipv4,
584 safi: Safi::Unicast,
585 },
586 ),
587 }]),
588 }],
589 });
590 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
591 data.extend_from_slice(&bgp_bytes);
592 data.extend_from_slice(&bgp_bytes);
593
594 let afi = Afi::Ipv4;
595 let asn_len = AsnLength::Bits32;
596 let peer_type = BmpPeerType::LocalRib;
597
598 let result =
599 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
600
601 assert!(result.is_ok(), "Parsing should succeed");
602 }
604
605 #[test]
606 fn test_local_rib_without_vr_table_name_tlv() {
607 let mut data = BytesMut::new();
610
611 data.extend_from_slice(&[
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
614 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
618
619 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
621 version: 4,
622 asn: crate::models::Asn::new_32bit(65001),
623 hold_time: 180,
624 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
625 extended_length: false,
626 opt_params: vec![OptParam {
627 param_type: 2, param_len: 6,
629 param_value: ParamValue::Capacities(vec![Capability {
630 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
631 value: CapabilityValue::MultiprotocolExtensions(
632 MultiprotocolExtensionsCapability {
633 afi: Afi::Ipv4,
634 safi: Safi::Unicast,
635 },
636 ),
637 }]),
638 }],
639 });
640 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
641 data.extend_from_slice(&bgp_bytes);
642 data.extend_from_slice(&bgp_bytes);
643
644 data.extend_from_slice(&[0x00, 0x00]); data.extend_from_slice(&[0x00, 0x04]); data.extend_from_slice(b"Test");
648
649 let afi = Afi::Ipv4;
650 let asn_len = AsnLength::Bits32;
651 let peer_type = BmpPeerType::LocalRib;
652
653 let result =
654 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
655
656 assert!(result.is_ok(), "Parsing should succeed");
657 }
659
660 #[test]
661 fn test_local_rib_with_valid_vr_table_name_tlv() {
662 let mut data = BytesMut::new();
665
666 data.extend_from_slice(&[
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
669 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
673
674 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
676 version: 4,
677 asn: crate::models::Asn::new_32bit(65001),
678 hold_time: 180,
679 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
680 extended_length: false,
681 opt_params: vec![OptParam {
682 param_type: 2, param_len: 6,
684 param_value: ParamValue::Capacities(vec![Capability {
685 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
686 value: CapabilityValue::MultiprotocolExtensions(
687 MultiprotocolExtensionsCapability {
688 afi: Afi::Ipv4,
689 safi: Safi::Unicast,
690 },
691 ),
692 }]),
693 }],
694 });
695 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
696 data.extend_from_slice(&bgp_bytes);
697 data.extend_from_slice(&bgp_bytes);
698
699 data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x00, 0x08]); data.extend_from_slice(b"LocalRIB");
703
704 let afi = Afi::Ipv4;
705 let asn_len = AsnLength::Bits32;
706 let peer_type = BmpPeerType::LocalRib;
707
708 let result =
709 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
710
711 assert!(result.is_ok(), "Parsing should succeed");
712
713 let peer_notification = result.unwrap();
714 assert_eq!(peer_notification.tlvs.len(), 1);
715 assert_eq!(
716 peer_notification.tlvs[0].info_type,
717 PeerUpTlvType::VrTableName
718 );
719 assert_eq!(peer_notification.tlvs[0].info_value, "LocalRIB");
720 }
722
723 #[test]
724 fn test_local_rib_with_empty_vr_table_name() {
725 let mut data = BytesMut::new();
728
729 data.extend_from_slice(&[
731 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
732 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
736
737 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
739 version: 4,
740 asn: crate::models::Asn::new_32bit(65001),
741 hold_time: 180,
742 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
743 extended_length: false,
744 opt_params: vec![OptParam {
745 param_type: 2, param_len: 6,
747 param_value: ParamValue::Capacities(vec![Capability {
748 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
749 value: CapabilityValue::MultiprotocolExtensions(
750 MultiprotocolExtensionsCapability {
751 afi: Afi::Ipv4,
752 safi: Safi::Unicast,
753 },
754 ),
755 }]),
756 }],
757 });
758 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
759 data.extend_from_slice(&bgp_bytes);
760 data.extend_from_slice(&bgp_bytes);
761
762 data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x00, 0x00]); let afi = Afi::Ipv4;
767 let asn_len = AsnLength::Bits32;
768 let peer_type = BmpPeerType::LocalRib;
769
770 let result =
771 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
772
773 assert!(result.is_ok(), "Parsing should succeed");
774 }
776
777 #[test]
778 fn test_local_rib_with_oversized_vr_table_name() {
779 let mut data = BytesMut::new();
782
783 data.extend_from_slice(&[
785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
786 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
790
791 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
793 version: 4,
794 asn: crate::models::Asn::new_32bit(65001),
795 hold_time: 180,
796 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
797 extended_length: false,
798 opt_params: vec![OptParam {
799 param_type: 2, param_len: 6,
801 param_value: ParamValue::Capacities(vec![Capability {
802 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
803 value: CapabilityValue::MultiprotocolExtensions(
804 MultiprotocolExtensionsCapability {
805 afi: Afi::Ipv4,
806 safi: Safi::Unicast,
807 },
808 ),
809 }]),
810 }],
811 });
812 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
813 data.extend_from_slice(&bgp_bytes);
814 data.extend_from_slice(&bgp_bytes);
815
816 let oversized_name = "A".repeat(256);
818 data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x01, 0x00]); data.extend_from_slice(oversized_name.as_bytes());
821
822 let afi = Afi::Ipv4;
823 let asn_len = AsnLength::Bits32;
824 let peer_type = BmpPeerType::LocalRib;
825
826 let result =
827 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
828
829 assert!(result.is_ok(), "Parsing should succeed");
830 }
832
833 #[test]
834 fn test_parse_peer_up_unknown_tlv() {
835 let mut data = BytesMut::new();
836
837 data.extend_from_slice(&[
839 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
840 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
844
845 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
847 version: 4,
848 asn: crate::models::Asn::new_32bit(65001),
849 hold_time: 180,
850 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
851 extended_length: false,
852 opt_params: vec![],
853 });
854 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
855 data.extend_from_slice(&bgp_bytes);
856 data.extend_from_slice(&bgp_bytes);
857
858 data.extend_from_slice(&[0x00, 0x00]); data.extend_from_slice(&[0x00, 0x04]); data.extend_from_slice(b"Test");
862
863 data.extend_from_slice(&[0x00, 0xFF]); data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(b"Foo");
866
867 let afi = Afi::Ipv4;
868 let asn_len = AsnLength::Bits32;
869 let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
870
871 assert!(
872 result.is_ok(),
873 "Should parse unknown TLV types without error"
874 );
875 let peer_notification = result.unwrap();
876 assert_eq!(peer_notification.tlvs.len(), 2);
877 assert_eq!(peer_notification.tlvs[0].info_type, PeerUpTlvType::String);
878 assert_eq!(peer_notification.tlvs[0].info_value, "Test");
879 assert_eq!(
880 peer_notification.tlvs[1].info_type,
881 PeerUpTlvType::Unknown(255)
882 );
883 assert_eq!(peer_notification.tlvs[1].info_value, "Foo");
884 }
885
886 #[test]
887 fn test_non_local_rib_no_validation() {
888 let mut data = BytesMut::new();
890
891 data.extend_from_slice(&[
893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
894 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
898
899 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
901 version: 4,
902 asn: crate::models::Asn::new_32bit(65001),
903 hold_time: 180,
904 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
905 extended_length: false,
906 opt_params: vec![],
907 });
908 let bgp_bytes = bgp_open.encode(AsnLength::Bits32);
909 data.extend_from_slice(&bgp_bytes);
910 data.extend_from_slice(&bgp_bytes);
911
912 let afi = Afi::Ipv4;
913 let asn_len = AsnLength::Bits32;
914 let peer_type = BmpPeerType::Global; let result =
917 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
918
919 assert!(result.is_ok(), "Parsing should succeed");
920 }
922}