bgpkit_parser/encoder/
updates_encoder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::net::IpAddr;
use std::str::FromStr;

use crate::models::{
    Asn, Bgp4MpEnum, Bgp4MpMessage, Bgp4MpType, BgpMessage, BgpUpdateMessage, CommonHeader,
    EntryType, MrtMessage,
};
use crate::utils::convert_timestamp;
use crate::BgpElem;
use bytes::{Bytes, BytesMut};

#[derive(Debug, Default)]
pub struct MrtUpdatesEncoder {
    cached_elems: Vec<BgpElem>,
}

impl MrtUpdatesEncoder {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn reset(&mut self) {
        self.cached_elems.clear();
    }

    pub fn process_elem(&mut self, elem: &BgpElem) {
        self.cached_elems.push(elem.clone());
    }

    pub fn export_bytes(&mut self) -> Bytes {
        let mut bytes = BytesMut::new();

        for elem in &self.cached_elems {
            let msg = BgpUpdateMessage::from(elem);
            let peer_asn = Asn::new_32bit(elem.peer_asn.to_u32());
            let local_asn = Asn::new_32bit(0);
            let local_ip = match elem.peer_ip {
                IpAddr::V4(_) => IpAddr::from_str("0.0.0.0").unwrap(),
                IpAddr::V6(_) => IpAddr::from_str("::").unwrap(),
            };
            let msg_type = Bgp4MpType::MessageAs4;

            let bgp4mp_msg = Bgp4MpMessage {
                msg_type,
                peer_asn,
                local_asn,
                interface_index: 0,
                peer_ip: elem.peer_ip,
                local_ip,
                bgp_message: BgpMessage::Update(msg),
            };

            let mrt_message = MrtMessage::Bgp4Mp(Bgp4MpEnum::Message(bgp4mp_msg));

            let (seconds, microseconds) = convert_timestamp(elem.timestamp);

            let subtype = Bgp4MpType::MessageAs4 as u16;
            let data_bytes = mrt_message.encode(subtype);
            let header_bytes = CommonHeader {
                timestamp: seconds,
                microsecond_timestamp: Some(microseconds),
                entry_type: EntryType::BGP4MP_ET,
                entry_subtype: subtype,
                length: data_bytes.len() as u32,
            }
            .encode();
            bytes.extend(header_bytes);
            bytes.extend(data_bytes);
        }

        self.reset();

        bytes.freeze()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::models::NetworkPrefix;
    use crate::parse_mrt_record;
    use bytes::Buf;
    use std::io::Cursor;

    #[test]
    fn test_encoding_updates() {
        let mut encoder = MrtUpdatesEncoder::new();
        let mut elem = BgpElem {
            peer_ip: IpAddr::V4("10.0.0.1".parse().unwrap()),
            peer_asn: Asn::from(65000),
            ..Default::default()
        };
        elem.prefix.prefix = "10.250.0.0/24".parse().unwrap();
        encoder.process_elem(&elem);
        elem.prefix.prefix = "10.251.0.0/24".parse().unwrap();
        encoder.process_elem(&elem);
        let bytes = encoder.export_bytes();

        let mut cursor = Cursor::new(bytes.clone());
        while cursor.has_remaining() {
            let _parsed = parse_mrt_record(&mut cursor).unwrap();
        }
    }

    #[test]
    fn test_encoding_updates_v6() {
        let mut encoder = MrtUpdatesEncoder::new();

        let mut elem = BgpElem {
            peer_ip: IpAddr::V6("::1".parse().unwrap()),
            peer_asn: Asn::from(65000),
            ..Default::default()
        };
        // ipv6 prefix
        elem.prefix = NetworkPrefix::from_str("2001:db8::/32").unwrap();
        encoder.process_elem(&elem);
        let bytes = encoder.export_bytes();
        let mut cursor = Cursor::new(bytes.clone());
        while cursor.has_remaining() {
            let _parsed = parse_mrt_record(&mut cursor).unwrap();
        }
    }
}