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_index = self.index_table.add_peer(peer);
52 let path_id = elem.prefix.path_id;
53 let prefix = elem.prefix.prefix;
54
55 let entries_map = self.per_prefix_entries_map.entry(prefix).or_default();
56 let entry = RibEntry {
57 peer_index,
58 path_id,
59 originated_time: elem.timestamp as u32,
60 attributes: Attributes::from(elem),
61 };
62 entries_map.insert(peer_index, entry);
63 }
64
65 pub fn export_bytes(&mut self) -> Bytes {
74 let mut bytes = BytesMut::new();
75
76 let mrt_message = MrtMessage::TableDumpV2Message(TableDumpV2Message::PeerIndexTable(
78 self.index_table.clone(),
79 ));
80 let (seconds, _microseconds) = convert_timestamp(self.timestamp);
81 let subtype = TableDumpV2Type::PeerIndexTable as u16;
82 let data_bytes = mrt_message.encode(subtype);
83 let header = CommonHeader {
84 timestamp: seconds,
85 microsecond_timestamp: None,
86 entry_type: EntryType::TABLE_DUMP_V2,
87 entry_subtype: subtype,
88 length: data_bytes.len() as u32,
89 };
90 let header_bytes = header.encode();
91 bytes.extend(header_bytes);
92 bytes.extend(data_bytes);
93
94 for (entry_count, (prefix, entries_map)) in self.per_prefix_entries_map.iter().enumerate() {
96 let rib_type = match prefix.addr().is_ipv6() {
97 true => TableDumpV2Type::RibIpv6Unicast,
98 false => TableDumpV2Type::RibIpv4Unicast,
99 };
100
101 let mut prefix_rib_entry = RibAfiEntries {
102 rib_type,
103 sequence_number: entry_count as u32,
104 prefix: NetworkPrefix::new(*prefix, None),
105 rib_entries: vec![],
106 };
107 for entry in entries_map.values() {
108 prefix_rib_entry.rib_entries.push(entry.clone());
109 }
110
111 let mrt_message =
112 MrtMessage::TableDumpV2Message(TableDumpV2Message::RibAfi(prefix_rib_entry));
113
114 let (seconds, _microseconds) = convert_timestamp(self.timestamp);
115 let subtype = rib_type as u16;
116 let data_bytes = mrt_message.encode(subtype);
117 let header_bytes = CommonHeader {
118 timestamp: seconds,
119 microsecond_timestamp: None,
120 entry_type: EntryType::TABLE_DUMP_V2,
121 entry_subtype: subtype,
122 length: data_bytes.len() as u32,
123 }
124 .encode();
125 bytes.extend(header_bytes);
126 bytes.extend(data_bytes);
127 }
128
129 self.reset();
130
131 bytes.freeze()
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use crate::models::Asn;
139 use crate::parse_mrt_record;
140 use bytes::Buf;
141 use std::io::Cursor;
142
143 #[test]
144 fn test_encoding_rib() {
145 let mut encoder = MrtRibEncoder::new();
146 let mut elem = BgpElem {
147 peer_ip: IpAddr::V4("10.0.0.1".parse().unwrap()),
148 peer_asn: Asn::from(65000),
149 ..Default::default()
150 };
151 elem.prefix.prefix = "10.250.0.0/24".parse().unwrap();
152 encoder.process_elem(&elem);
153 elem.prefix.prefix = "10.251.0.0/24".parse().unwrap();
154 encoder.process_elem(&elem);
155 let bytes = encoder.export_bytes();
156
157 let mut cursor = Cursor::new(bytes.clone());
158 while cursor.has_remaining() {
159 let _parsed = parse_mrt_record(&mut cursor).unwrap();
160 }
161
162 let mut encoder = MrtRibEncoder::new();
164 let mut elem = BgpElem {
165 peer_ip: IpAddr::V6("::1".parse().unwrap()),
166 peer_asn: Asn::from(65000),
167 ..Default::default()
168 };
169 elem.prefix.prefix = "2001:db8::/32".parse().unwrap();
171 encoder.process_elem(&elem);
172 let bytes = encoder.export_bytes();
173
174 let mut cursor = Cursor::new(bytes.clone());
175 while cursor.has_remaining() {
176 let _parsed = parse_mrt_record(&mut cursor).unwrap();
177 }
178 }
179}