bgpkit_parser/encoder/
rib_encoder.rs1use crate::models::{
8 Attributes, BgpElem, CommonHeader, EntryType, MrtMessage, NetworkPrefix, Peer, PeerIndexTable,
9 RibAfiEntries, RibEntry, TableDumpV2Message, TableDumpV2Type,
10};
11use crate::utils::convert_timestamp;
12use bytes::{Bytes, BytesMut};
13use ipnet::IpNet;
14use std::collections::HashMap;
15use std::net::{IpAddr, Ipv4Addr};
16
17#[derive(Default)]
18pub struct MrtRibEncoder {
19 index_table: PeerIndexTable,
20
21 per_prefix_entries_map: HashMap<IpNet, HashMap<u16, RibEntry>>,
22
23 timestamp: f64,
24}
25
26impl MrtRibEncoder {
27 pub fn new() -> Self {
28 Self::default()
29 }
30
31 pub fn reset(&mut self) {
32 self.index_table = PeerIndexTable::default();
33 self.per_prefix_entries_map = HashMap::default();
34 self.timestamp = 0.0;
35 }
36
37 pub fn process_elem(&mut self, elem: &BgpElem) {
43 if self.timestamp == 0.0 {
44 self.timestamp = elem.timestamp;
45 }
46 let bgp_identifier = match elem.peer_ip {
47 IpAddr::V4(ip) => ip,
48 IpAddr::V6(_ip) => Ipv4Addr::from(0),
49 };
50 let peer = Peer::new(bgp_identifier, elem.peer_ip, elem.peer_asn);
51 let peer_id = self.index_table.add_peer(peer);
52 let prefix = elem.prefix.prefix;
53
54 let entries_map = self.per_prefix_entries_map.entry(prefix).or_default();
55 let entry = RibEntry {
56 peer_index: peer_id,
57 originated_time: elem.timestamp as u32,
58 attributes: Attributes::from(elem),
59 };
60 entries_map.insert(peer_id, entry);
61 }
62
63 pub fn export_bytes(&mut self) -> Bytes {
72 let mut bytes = BytesMut::new();
73
74 let mrt_message = MrtMessage::TableDumpV2Message(TableDumpV2Message::PeerIndexTable(
76 self.index_table.clone(),
77 ));
78 let (seconds, _microseconds) = convert_timestamp(self.timestamp);
79 let subtype = TableDumpV2Type::PeerIndexTable as u16;
80 let data_bytes = mrt_message.encode(subtype);
81 let header = CommonHeader {
82 timestamp: seconds,
83 microsecond_timestamp: None,
84 entry_type: EntryType::TABLE_DUMP_V2,
85 entry_subtype: subtype,
86 length: data_bytes.len() as u32,
87 };
88 let header_bytes = header.encode();
89 bytes.extend(header_bytes);
90 bytes.extend(data_bytes);
91
92 for (entry_count, (prefix, entries_map)) in self.per_prefix_entries_map.iter().enumerate() {
94 let rib_type = match prefix.addr().is_ipv6() {
95 true => TableDumpV2Type::RibIpv6Unicast,
96 false => TableDumpV2Type::RibIpv4Unicast,
97 };
98
99 let mut prefix_rib_entry = RibAfiEntries {
100 rib_type,
101 sequence_number: entry_count as u32,
102 prefix: NetworkPrefix::new(*prefix, 0),
103 rib_entries: vec![],
104 };
105 for entry in entries_map.values() {
106 prefix_rib_entry.rib_entries.push(entry.clone());
107 }
108
109 let mrt_message =
110 MrtMessage::TableDumpV2Message(TableDumpV2Message::RibAfi(prefix_rib_entry));
111
112 let (seconds, _microseconds) = convert_timestamp(self.timestamp);
113 let subtype = rib_type as u16;
114 let data_bytes = mrt_message.encode(subtype);
115 let header_bytes = CommonHeader {
116 timestamp: seconds,
117 microsecond_timestamp: None,
118 entry_type: EntryType::TABLE_DUMP_V2,
119 entry_subtype: subtype,
120 length: data_bytes.len() as u32,
121 }
122 .encode();
123 bytes.extend(header_bytes);
124 bytes.extend(data_bytes);
125 }
126
127 self.reset();
128
129 bytes.freeze()
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::models::Asn;
137 use crate::parse_mrt_record;
138 use bytes::Buf;
139 use std::io::Cursor;
140
141 #[test]
142 fn test_encoding_rib() {
143 let mut encoder = MrtRibEncoder::new();
144 let mut elem = BgpElem {
145 peer_ip: IpAddr::V4("10.0.0.1".parse().unwrap()),
146 peer_asn: Asn::from(65000),
147 ..Default::default()
148 };
149 elem.prefix.prefix = "10.250.0.0/24".parse().unwrap();
150 encoder.process_elem(&elem);
151 elem.prefix.prefix = "10.251.0.0/24".parse().unwrap();
152 encoder.process_elem(&elem);
153 let bytes = encoder.export_bytes();
154
155 let mut cursor = Cursor::new(bytes.clone());
156 while cursor.has_remaining() {
157 let _parsed = parse_mrt_record(&mut cursor).unwrap();
158 }
159
160 let mut encoder = MrtRibEncoder::new();
162 let mut elem = BgpElem {
163 peer_ip: IpAddr::V6("::1".parse().unwrap()),
164 peer_asn: Asn::from(65000),
165 ..Default::default()
166 };
167 elem.prefix.prefix = "2001:db8::/32".parse().unwrap();
169 encoder.process_elem(&elem);
170 let bytes = encoder.export_bytes();
171
172 let mut cursor = Cursor::new(bytes.clone());
173 while cursor.has_remaining() {
174 let _parsed = parse_mrt_record(&mut cursor).unwrap();
175 }
176 }
177}