bgpkit_parser/encoder/
updates_encoder.rs

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