bgpkit_parser/parser/bmp/messages/
peer_up_notification.rs

1use crate::bgp::parse_bgp_message;
2use crate::models::*;
3use crate::parser::bmp::error::ParserBmpError;
4use crate::parser::ReadUtils;
5use bytes::{Buf, Bytes};
6use num_enum::{IntoPrimitive, TryFromPrimitive};
7use std::net::IpAddr;
8
9#[derive(Debug, PartialEq, Clone)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct PeerUpNotification {
12    pub local_addr: IpAddr,
13    pub local_port: u16,
14    pub remote_port: u16,
15    pub sent_open: BgpMessage,
16    pub received_open: BgpMessage,
17    pub tlvs: Vec<PeerUpNotificationTlv>,
18}
19
20///Type-Length-Value Type
21///
22/// https://www.iana.org/assignments/bmp-parameters/bmp-parameters.xhtml#initiation-peer-up-tlvs
23#[derive(Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Clone, Copy)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[repr(u16)]
26pub enum PeerUpTlvType {
27    String = 0,
28    SysDescr = 1,
29    SysName = 2,
30    VrTableName = 3,
31    AdminLabel = 4,
32}
33
34#[derive(Debug, PartialEq, Clone)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub struct PeerUpNotificationTlv {
37    pub info_type: PeerUpTlvType,
38    pub info_len: u16,
39    pub info_value: String,
40}
41
42pub fn parse_peer_up_notification(
43    data: &mut Bytes,
44    afi: &Afi,
45    asn_len: &AsnLength,
46) -> Result<PeerUpNotification, ParserBmpError> {
47    let local_addr: IpAddr = match afi {
48        Afi::Ipv4 => {
49            data.advance(12);
50            let ip = data.read_ipv4_address()?;
51            ip.into()
52        }
53        Afi::Ipv6 => data.read_ipv6_address()?.into(),
54    };
55
56    let local_port = data.read_u16()?;
57    let remote_port = data.read_u16()?;
58
59    let sent_open = parse_bgp_message(data, false, asn_len)?;
60    let received_open = parse_bgp_message(data, false, asn_len)?;
61    // let received_open = parse_bgp_open_message(data)?;
62    let mut tlvs = vec![];
63    while data.remaining() >= 4 {
64        let info_type = PeerUpTlvType::try_from(data.read_u16()?)?;
65        let info_len = data.read_u16()?;
66        let info_value = data.read_n_bytes_to_string(info_len as usize)?;
67        tlvs.push(PeerUpNotificationTlv {
68            info_type,
69            info_len,
70            info_value,
71        })
72    }
73    Ok(PeerUpNotification {
74        local_addr,
75        local_port,
76        remote_port,
77        sent_open,
78        received_open,
79        tlvs,
80    })
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use bytes::BytesMut;
87    use std::net::{IpAddr, Ipv4Addr};
88
89    #[test]
90    fn test_parse_peer_up_notification() {
91        let mut data = BytesMut::new();
92        // Assuming setup for test where local address is "10.1.1.1" IPv4
93        // local port is 8000, remote port is 9000. Adjust accordingly.
94        data.extend_from_slice(&[
95            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01,
96            0x01, 0x01,
97        ]);
98        data.extend_from_slice(&[0x1F, 0x40]); // 8000 in network byte order
99        data.extend_from_slice(&[0x23, 0x28]); // 9000 in network byte order
100
101        let bgp_open_message = crate::models::BgpMessage::Open(BgpOpenMessage {
102            version: 0,
103            asn: Default::default(),
104            hold_time: 0,
105            sender_ip: Ipv4Addr::new(0, 0, 0, 0),
106            extended_length: false,
107            opt_params: vec![],
108        });
109        let bgp_open_message_bytes = bgp_open_message.encode(false, AsnLength::Bits32);
110        data.extend_from_slice(&bgp_open_message_bytes);
111        data.extend_from_slice(&bgp_open_message_bytes);
112
113        // add tlv
114        data.extend_from_slice(&[0x00, 0x01]); // info_type
115        data.extend_from_slice(&[0x00, 0x02]); // info_len
116        data.extend_from_slice(&[0x00, 0x03]); // info_value
117
118        let afi = Afi::Ipv4;
119        let asn_len = AsnLength::Bits32;
120
121        let result = parse_peer_up_notification(&mut data.freeze(), &afi, &asn_len);
122
123        match result {
124            Ok(peer_notification) => {
125                assert_eq!(
126                    peer_notification.local_addr,
127                    IpAddr::V4(std::net::Ipv4Addr::new(10, 1, 1, 1))
128                );
129                assert_eq!(peer_notification.local_port, 8000);
130                assert_eq!(peer_notification.remote_port, 9000);
131
132                // Continue to check other values from peer_notification like sent_open, received_open, tlvs
133                let tlv = peer_notification.tlvs.first().unwrap();
134                assert_eq!(tlv.info_type, PeerUpTlvType::SysDescr);
135                assert_eq!(tlv.info_len, 2);
136                assert_eq!(tlv.info_value, "\u{0}\u{3}");
137            }
138            Err(_) => {
139                panic!("parse_peer_up_notification should return Ok");
140            }
141        }
142    }
143}