Skip to main content

bgpkit_parser/encoder/
updates_encoder.rs

1use std::net::IpAddr;
2use std::str::FromStr;
3
4use crate::error::EncodingError;
5use crate::models::{
6    Asn, Bgp4MpEnum, Bgp4MpMessage, Bgp4MpType, BgpMessage, BgpUpdateMessage, CommonHeader,
7    EntryType, MrtMessage,
8};
9use crate::utils::convert_timestamp;
10use crate::BgpElem;
11use bytes::{Bytes, BytesMut};
12
13#[derive(Debug, Default)]
14pub struct MrtUpdatesEncoder {
15    cached_elems: Vec<BgpElem>,
16}
17
18impl MrtUpdatesEncoder {
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    pub fn reset(&mut self) {
24        self.cached_elems.clear();
25    }
26
27    pub fn process_elem(&mut self, elem: &BgpElem) {
28        self.cached_elems.push(elem.clone());
29    }
30
31    pub fn export_bytes(&mut self) -> Result<Bytes, EncodingError> {
32        let mut bytes = BytesMut::new();
33
34        for elem in &self.cached_elems {
35            let msg = BgpUpdateMessage::from(elem);
36            let peer_asn = Asn::new_32bit(elem.peer_asn.to_u32());
37            let local_asn = Asn::new_32bit(0);
38            let local_ip = match elem.peer_ip {
39                IpAddr::V4(_) => IpAddr::from_str("0.0.0.0").unwrap(),
40                IpAddr::V6(_) => IpAddr::from_str("::").unwrap(),
41            };
42            let msg_type = Bgp4MpType::MessageAs4;
43
44            let bgp4mp_msg = Bgp4MpMessage {
45                msg_type,
46                peer_asn,
47                local_asn,
48                interface_index: 0,
49                peer_ip: elem.peer_ip,
50                local_ip,
51                bgp_message: BgpMessage::Update(msg),
52            };
53
54            let mrt_message = MrtMessage::Bgp4Mp(Bgp4MpEnum::Message(bgp4mp_msg));
55
56            let (seconds, microseconds) = convert_timestamp(elem.timestamp);
57
58            let subtype = Bgp4MpType::MessageAs4 as u16;
59            let data_bytes = mrt_message.encode(subtype)?;
60            let header_bytes = CommonHeader {
61                timestamp: seconds,
62                microsecond_timestamp: Some(microseconds),
63                entry_type: EntryType::BGP4MP_ET,
64                entry_subtype: subtype,
65                length: data_bytes.len() as u32,
66            }
67            .encode();
68            bytes.extend(header_bytes);
69            bytes.extend(data_bytes);
70        }
71
72        self.reset();
73
74        Ok(bytes.freeze())
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    use crate::models::NetworkPrefix;
82    use crate::parse_mrt_record;
83    use bytes::Buf;
84    use std::io::Cursor;
85
86    #[test]
87    fn test_encoding_updates() {
88        let mut encoder = MrtUpdatesEncoder::new();
89        let mut elem = BgpElem {
90            peer_ip: IpAddr::V4("10.0.0.1".parse().unwrap()),
91            peer_asn: Asn::from(65000),
92            ..Default::default()
93        };
94        elem.prefix.prefix = "10.250.0.0/24".parse().unwrap();
95        encoder.process_elem(&elem);
96        elem.prefix.prefix = "10.251.0.0/24".parse().unwrap();
97        encoder.process_elem(&elem);
98        let bytes = encoder.export_bytes().unwrap();
99
100        let mut cursor = Cursor::new(bytes.clone());
101        while cursor.has_remaining() {
102            let _parsed = parse_mrt_record(&mut cursor).unwrap();
103        }
104    }
105
106    #[test]
107    fn test_encoding_updates_v6() {
108        let mut encoder = MrtUpdatesEncoder::new();
109
110        let mut elem = BgpElem {
111            peer_ip: IpAddr::V6("::1".parse().unwrap()),
112            peer_asn: Asn::from(65000),
113            ..Default::default()
114        };
115        // ipv6 prefix
116        elem.prefix = NetworkPrefix::from_str("2001:db8::/32").unwrap();
117        encoder.process_elem(&elem);
118        let bytes = encoder.export_bytes().unwrap();
119        let mut cursor = Cursor::new(bytes.clone());
120        while cursor.has_remaining() {
121            let _parsed = parse_mrt_record(&mut cursor).unwrap();
122        }
123    }
124}