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).unwrap();
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).unwrap();
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).unwrap();
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).unwrap();
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).unwrap();
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).unwrap();
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_value: ParamValue::Capacities(vec![Capability {
579 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
580 value: CapabilityValue::MultiprotocolExtensions(
581 MultiprotocolExtensionsCapability {
582 afi: Afi::Ipv4,
583 safi: Safi::Unicast,
584 },
585 ),
586 }]),
587 }],
588 });
589 let bgp_bytes = bgp_open.encode(AsnLength::Bits32).unwrap();
590 data.extend_from_slice(&bgp_bytes);
591 data.extend_from_slice(&bgp_bytes);
592
593 let afi = Afi::Ipv4;
594 let asn_len = AsnLength::Bits32;
595 let peer_type = BmpPeerType::LocalRib;
596
597 let result =
598 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
599
600 assert!(result.is_ok(), "Parsing should succeed");
601 }
603
604 #[test]
605 fn test_local_rib_without_vr_table_name_tlv() {
606 let mut data = BytesMut::new();
609
610 data.extend_from_slice(&[
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
613 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
617
618 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
620 version: 4,
621 asn: crate::models::Asn::new_32bit(65001),
622 hold_time: 180,
623 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
624 extended_length: false,
625 opt_params: vec![OptParam {
626 param_type: 2, param_value: ParamValue::Capacities(vec![Capability {
628 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
629 value: CapabilityValue::MultiprotocolExtensions(
630 MultiprotocolExtensionsCapability {
631 afi: Afi::Ipv4,
632 safi: Safi::Unicast,
633 },
634 ),
635 }]),
636 }],
637 });
638 let bgp_bytes = bgp_open.encode(AsnLength::Bits32).unwrap();
639 data.extend_from_slice(&bgp_bytes);
640 data.extend_from_slice(&bgp_bytes);
641
642 data.extend_from_slice(&[0x00, 0x00]); data.extend_from_slice(&[0x00, 0x04]); data.extend_from_slice(b"Test");
646
647 let afi = Afi::Ipv4;
648 let asn_len = AsnLength::Bits32;
649 let peer_type = BmpPeerType::LocalRib;
650
651 let result =
652 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
653
654 assert!(result.is_ok(), "Parsing should succeed");
655 }
657
658 #[test]
659 fn test_local_rib_with_valid_vr_table_name_tlv() {
660 let mut data = BytesMut::new();
663
664 data.extend_from_slice(&[
666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
667 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
671
672 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
674 version: 4,
675 asn: crate::models::Asn::new_32bit(65001),
676 hold_time: 180,
677 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
678 extended_length: false,
679 opt_params: vec![OptParam {
680 param_type: 2, param_value: ParamValue::Capacities(vec![Capability {
682 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
683 value: CapabilityValue::MultiprotocolExtensions(
684 MultiprotocolExtensionsCapability {
685 afi: Afi::Ipv4,
686 safi: Safi::Unicast,
687 },
688 ),
689 }]),
690 }],
691 });
692 let bgp_bytes = bgp_open.encode(AsnLength::Bits32).unwrap();
693 data.extend_from_slice(&bgp_bytes);
694 data.extend_from_slice(&bgp_bytes);
695
696 data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x00, 0x08]); data.extend_from_slice(b"LocalRIB");
700
701 let afi = Afi::Ipv4;
702 let asn_len = AsnLength::Bits32;
703 let peer_type = BmpPeerType::LocalRib;
704
705 let result =
706 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
707
708 assert!(result.is_ok(), "Parsing should succeed");
709
710 let peer_notification = result.unwrap();
711 assert_eq!(peer_notification.tlvs.len(), 1);
712 assert_eq!(
713 peer_notification.tlvs[0].info_type,
714 PeerUpTlvType::VrTableName
715 );
716 assert_eq!(peer_notification.tlvs[0].info_value, "LocalRIB");
717 }
719
720 #[test]
721 fn test_local_rib_with_empty_vr_table_name() {
722 let mut data = BytesMut::new();
725
726 data.extend_from_slice(&[
728 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
729 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
733
734 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
736 version: 4,
737 asn: crate::models::Asn::new_32bit(65001),
738 hold_time: 180,
739 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
740 extended_length: false,
741 opt_params: vec![OptParam {
742 param_type: 2, param_value: ParamValue::Capacities(vec![Capability {
744 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
745 value: CapabilityValue::MultiprotocolExtensions(
746 MultiprotocolExtensionsCapability {
747 afi: Afi::Ipv4,
748 safi: Safi::Unicast,
749 },
750 ),
751 }]),
752 }],
753 });
754 let bgp_bytes = bgp_open.encode(AsnLength::Bits32).unwrap();
755 data.extend_from_slice(&bgp_bytes);
756 data.extend_from_slice(&bgp_bytes);
757
758 data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x00, 0x00]); let afi = Afi::Ipv4;
763 let asn_len = AsnLength::Bits32;
764 let peer_type = BmpPeerType::LocalRib;
765
766 let result =
767 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
768
769 assert!(result.is_ok(), "Parsing should succeed");
770 }
772
773 #[test]
774 fn test_local_rib_with_oversized_vr_table_name() {
775 let mut data = BytesMut::new();
778
779 data.extend_from_slice(&[
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
782 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
786
787 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
789 version: 4,
790 asn: crate::models::Asn::new_32bit(65001),
791 hold_time: 180,
792 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
793 extended_length: false,
794 opt_params: vec![OptParam {
795 param_type: 2, param_value: ParamValue::Capacities(vec![Capability {
797 ty: BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4,
798 value: CapabilityValue::MultiprotocolExtensions(
799 MultiprotocolExtensionsCapability {
800 afi: Afi::Ipv4,
801 safi: Safi::Unicast,
802 },
803 ),
804 }]),
805 }],
806 });
807 let bgp_bytes = bgp_open.encode(AsnLength::Bits32).unwrap();
808 data.extend_from_slice(&bgp_bytes);
809 data.extend_from_slice(&bgp_bytes);
810
811 let oversized_name = "A".repeat(256);
813 data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(&[0x01, 0x00]); data.extend_from_slice(oversized_name.as_bytes());
816
817 let afi = Afi::Ipv4;
818 let asn_len = AsnLength::Bits32;
819 let peer_type = BmpPeerType::LocalRib;
820
821 let result =
822 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
823
824 assert!(result.is_ok(), "Parsing should succeed");
825 }
827
828 #[test]
829 fn test_parse_peer_up_unknown_tlv() {
830 let mut data = BytesMut::new();
831
832 data.extend_from_slice(&[
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
835 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
839
840 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
842 version: 4,
843 asn: crate::models::Asn::new_32bit(65001),
844 hold_time: 180,
845 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
846 extended_length: false,
847 opt_params: vec![],
848 });
849 let bgp_bytes = bgp_open.encode(AsnLength::Bits32).unwrap();
850 data.extend_from_slice(&bgp_bytes);
851 data.extend_from_slice(&bgp_bytes);
852
853 data.extend_from_slice(&[0x00, 0x00]); data.extend_from_slice(&[0x00, 0x04]); data.extend_from_slice(b"Test");
857
858 data.extend_from_slice(&[0x00, 0xFF]); data.extend_from_slice(&[0x00, 0x03]); data.extend_from_slice(b"Foo");
861
862 let afi = Afi::Ipv4;
863 let asn_len = AsnLength::Bits32;
864 let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, None);
865
866 assert!(
867 result.is_ok(),
868 "Should parse unknown TLV types without error"
869 );
870 let peer_notification = result.unwrap();
871 assert_eq!(peer_notification.tlvs.len(), 2);
872 assert_eq!(peer_notification.tlvs[0].info_type, PeerUpTlvType::String);
873 assert_eq!(peer_notification.tlvs[0].info_value, "Test");
874 assert_eq!(
875 peer_notification.tlvs[1].info_type,
876 PeerUpTlvType::Unknown(255)
877 );
878 assert_eq!(peer_notification.tlvs[1].info_value, "Foo");
879 }
880
881 #[test]
882 fn test_non_local_rib_no_validation() {
883 let mut data = BytesMut::new();
885
886 data.extend_from_slice(&[
888 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
889 0x01, 0x01, 0x00, 0xB3, 0x00, 0xB3, ]);
893
894 let bgp_open = crate::models::BgpMessage::Open(BgpOpenMessage {
896 version: 4,
897 asn: crate::models::Asn::new_32bit(65001),
898 hold_time: 180,
899 bgp_identifier: Ipv4Addr::new(192, 168, 1, 1),
900 extended_length: false,
901 opt_params: vec![],
902 });
903 let bgp_bytes = bgp_open.encode(AsnLength::Bits32).unwrap();
904 data.extend_from_slice(&bgp_bytes);
905 data.extend_from_slice(&bgp_bytes);
906
907 let afi = Afi::Ipv4;
908 let asn_len = AsnLength::Bits32;
909 let peer_type = BmpPeerType::Global; let result =
912 parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len, Some(&peer_type));
913
914 assert!(result.is_ok(), "Parsing should succeed");
915 }
917}