bgpkit_parser/parser/mrt/messages/table_dump_v2/
peer_index_table.rs1use crate::encoder::sink::put_u16_len_slice;
2use crate::error::{check_max, EncodingError};
3use crate::models::{Afi, AsnLength, Peer, PeerIndexTable, PeerType};
4use crate::parser::ReadUtils;
5use crate::ParserError;
6use bytes::{BufMut, Bytes, BytesMut};
7use std::collections::HashMap;
8use std::net::{IpAddr, Ipv4Addr};
9
10pub fn parse_peer_index_table(data: &mut Bytes) -> Result<PeerIndexTable, ParserError> {
23 let collector_bgp_id = Ipv4Addr::from(data.read_u32()?);
24 let view_name_length = data.read_u16()?;
26 let view_name =
27 String::from_utf8(data.read_n_bytes(view_name_length as usize)?).unwrap_or("".to_string());
28
29 let peer_count = data.read_u16()?;
30 let mut peers = vec![];
31 for _index in 0..peer_count {
32 let peer_type = PeerType::from_bits_retain(data.read_u8()?);
33 let afi = match peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6) {
34 true => Afi::Ipv6,
35 false => Afi::Ipv4,
36 };
37 let asn_len = match peer_type.contains(PeerType::AS_SIZE_32BIT) {
38 true => AsnLength::Bits32,
39 false => AsnLength::Bits16,
40 };
41
42 let peer_bgp_id = Ipv4Addr::from(data.read_u32()?);
43 let peer_ip: IpAddr = data.read_address(&afi)?;
44 let peer_asn = data.read_asn(asn_len)?;
45 peers.push(Peer {
46 peer_type,
47 peer_bgp_id,
48 peer_ip,
49 peer_asn,
50 })
51 }
52
53 let mut id_peer_map = HashMap::new();
54 let mut peer_ip_id_map = HashMap::new();
55
56 for (id, p) in peers.into_iter().enumerate() {
57 id_peer_map.insert(id as u16, p);
58 peer_ip_id_map.insert(p.peer_ip, id as u16);
59 }
60
61 Ok(PeerIndexTable {
62 collector_bgp_id,
63 view_name,
64 id_peer_map,
65 peer_ip_id_map,
66 })
67}
68
69impl PeerIndexTable {
70 pub fn add_peer(&mut self, peer: Peer) -> Result<u16, EncodingError> {
77 match self.peer_ip_id_map.get(&peer.peer_ip) {
78 Some(id) => Ok(*id),
79 None => {
80 let next_id = self.peer_ip_id_map.len();
81 check_max("PeerIndexTable peer count", next_id + 1, u16::MAX as usize)?;
82 let peer_id = next_id as u16;
83 self.peer_ip_id_map.insert(peer.peer_ip, peer_id);
84 self.id_peer_map.insert(peer_id, peer);
85 Ok(peer_id)
86 }
87 }
88 }
89
90 pub fn get_peer_by_id(&self, peer_id: &u16) -> Option<&Peer> {
100 self.id_peer_map.get(peer_id)
101 }
102
103 pub fn get_peer_id_by_addr(&self, peer_ip: &IpAddr) -> Option<u16> {
125 self.peer_ip_id_map.get(peer_ip).copied()
126 }
127
128 pub fn encode(&self) -> Result<Bytes, EncodingError> {
151 let mut buf = BytesMut::new();
152
153 buf.put_u32(self.collector_bgp_id.into());
155
156 put_u16_len_slice(
158 &mut buf,
159 "PeerIndexTable view name length",
160 self.view_name.as_bytes(),
161 )?;
162
163 let peer_count = self.id_peer_map.len();
165 check_max("PeerIndexTable peer count", peer_count, u16::MAX as usize)?;
166 buf.put_u16(peer_count as u16);
167
168 let mut peer_ids: Vec<_> = self.id_peer_map.keys().collect();
170 peer_ids.sort();
171 for id in peer_ids {
172 let peer = self.id_peer_map.get(id).unwrap();
173 buf.put_u8(peer.peer_type.bits());
175
176 buf.put_u32(peer.peer_bgp_id.into());
178
179 match peer.peer_ip {
181 IpAddr::V4(ipv4) => {
182 buf.put_slice(&ipv4.octets());
183 }
184 IpAddr::V6(ipv6) => {
185 buf.put_slice(&ipv6.octets());
186 }
187 };
188
189 match peer.peer_type.contains(PeerType::AS_SIZE_32BIT) {
191 true => buf.put_u32(peer.peer_asn.to_u32()),
192 false => buf.put_u16(peer.peer_asn.to_u32() as u16),
193 };
194 }
195
196 Ok(buf.freeze())
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use crate::models::Asn;
205 use std::str::FromStr;
206
207 #[test]
208 fn test_peer_index_table_encode() {
209 let mut index_table = PeerIndexTable {
210 collector_bgp_id: Ipv4Addr::from(1234),
211 view_name: String::from("example"),
212 id_peer_map: HashMap::new(),
213 peer_ip_id_map: Default::default(),
214 };
215
216 index_table
217 .add_peer(Peer::new(
218 Ipv4Addr::from(1234),
219 IpAddr::from_str("192.168.1.1").unwrap(),
220 Asn::new_32bit(1234),
221 ))
222 .unwrap();
223 index_table
224 .add_peer(Peer::new(
225 Ipv4Addr::from(12345),
226 IpAddr::from_str("192.168.1.2").unwrap(),
227 Asn::new_32bit(12345),
228 ))
229 .unwrap();
230
231 let encoded = index_table.encode().unwrap();
232 let parsed_index_table = parse_peer_index_table(&mut encoded.clone()).unwrap();
233 assert_eq!(index_table, parsed_index_table);
234 }
235
236 #[test]
237 fn test_get_peer_by_id() {
238 let mut index_table = PeerIndexTable {
239 collector_bgp_id: Ipv4Addr::from(1234),
240 view_name: String::from("example"),
241 id_peer_map: HashMap::new(),
242 peer_ip_id_map: Default::default(),
243 };
244
245 let peer1 = Peer::new(
246 Ipv4Addr::from(1234),
247 IpAddr::from_str("10.0.0.1").unwrap(),
248 Asn::new_32bit(1234),
249 );
250 let peer2 = Peer::new(
251 Ipv4Addr::from(12345),
252 IpAddr::from_str("10.0.0.2").unwrap(),
253 Asn::new_32bit(12345),
254 );
255
256 let peer1_id = index_table.add_peer(peer1).unwrap();
257 let peer2_id = index_table.add_peer(peer2).unwrap();
258
259 assert_eq!(
260 index_table.get_peer_by_id(&peer1_id),
261 Some(&Peer::new(
262 Ipv4Addr::from(1234),
263 IpAddr::from_str("10.0.0.1").unwrap(),
264 Asn::new_32bit(1234),
265 ))
266 );
267 assert_eq!(
268 index_table.get_peer_by_id(&peer2_id),
269 Some(&Peer::new(
270 Ipv4Addr::from(12345),
271 IpAddr::from_str("10.0.0.2").unwrap(),
272 Asn::new_32bit(12345),
273 ))
274 );
275 }
276
277 #[test]
278 fn test_add_peer_rejects_overflow_without_corruption() {
279 let mut index_table = PeerIndexTable::default();
280
281 for i in 0..(u16::MAX as u32) {
283 let ip = IpAddr::from(Ipv4Addr::from(i + 1));
284 index_table
285 .add_peer(Peer::new(Ipv4Addr::from(1), ip, Asn::new_32bit(i)))
286 .unwrap();
287 }
288 assert_eq!(index_table.id_peer_map.len(), u16::MAX as usize);
289
290 let overflow_ip = IpAddr::from(Ipv4Addr::from(u16::MAX as u32 + 1));
292 let overflow_peer = Peer::new(Ipv4Addr::from(1), overflow_ip, Asn::new_32bit(65536));
293 let err = index_table.add_peer(overflow_peer).unwrap_err();
294 assert_eq!(
295 err,
296 EncodingError::ValueTooLarge {
297 field: "PeerIndexTable peer count",
298 actual: u16::MAX as usize + 1,
299 max: u16::MAX as usize
300 }
301 );
302
303 assert_eq!(index_table.id_peer_map.len(), u16::MAX as usize);
305 assert_eq!(index_table.get_peer_id_by_addr(&overflow_ip), None);
306
307 let existing_ip = IpAddr::from(Ipv4Addr::from(1u32));
309 let existing = Peer::new(Ipv4Addr::from(1), existing_ip, Asn::new_32bit(0));
310 assert_eq!(index_table.add_peer(existing).unwrap(), 0);
311
312 index_table.encode().unwrap();
314 }
315}