bgpkit_parser/parser/mrt/messages/table_dump_v2/
geo_peer_table.rs1use crate::error::ParserError;
4use crate::models::*;
5use crate::parser::ReadUtils;
6use bytes::{Buf, BufMut, Bytes, BytesMut};
7use std::net::IpAddr;
8
9pub fn parse_geo_peer_table(data: &mut Bytes) -> Result<GeoPeerTable, ParserError> {
49 let collector_bgp_id = data.read_ipv4_address()?;
51
52 let view_name_len = data.get_u16() as usize;
54 let view_name = data.read_n_bytes_to_string(view_name_len)?;
55
56 let collector_latitude = data.get_f32();
58 let collector_longitude = data.get_f32();
59
60 let mut geo_table = GeoPeerTable::new(
61 collector_bgp_id,
62 view_name,
63 collector_latitude,
64 collector_longitude,
65 );
66
67 let peer_count = data.get_u16();
69
70 for _ in 0..peer_count {
72 let peer_type_raw = data.get_u8();
74 let peer_type = PeerType::from_bits_retain(peer_type_raw);
75
76 let peer_bgp_id = data.read_ipv4_address()?;
78
79 let peer_ip: IpAddr = if peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6) {
81 data.read_ipv6_address()?.into()
82 } else {
83 data.read_ipv4_address()?.into()
84 };
85
86 let peer_asn = if peer_type.contains(PeerType::AS_SIZE_32BIT) {
88 Asn::new_32bit(data.get_u32())
89 } else {
90 Asn::new_16bit(data.get_u16())
91 };
92
93 let peer = Peer {
95 peer_type,
96 peer_bgp_id,
97 peer_ip,
98 peer_asn,
99 };
100
101 let peer_latitude = data.get_f32();
103 let peer_longitude = data.get_f32();
104
105 let geo_peer = GeoPeer::new(peer, peer_latitude, peer_longitude);
106 geo_table.add_geo_peer(geo_peer);
107 }
108
109 Ok(geo_table)
110}
111
112impl GeoPeerTable {
113 pub fn encode(&self) -> Bytes {
136 let mut buf = BytesMut::new();
137
138 buf.put_u32(self.collector_bgp_id.into());
140
141 let view_name_bytes = self.view_name.as_bytes();
143 buf.put_u16(view_name_bytes.len() as u16);
144 buf.extend(view_name_bytes);
145
146 buf.put_f32(self.collector_latitude);
148 buf.put_f32(self.collector_longitude);
149
150 buf.put_u16(self.geo_peers.len() as u16);
152
153 for geo_peer in &self.geo_peers {
155 buf.put_u8(geo_peer.peer.peer_type.bits());
157
158 buf.put_u32(geo_peer.peer.peer_bgp_id.into());
160
161 match geo_peer.peer.peer_ip {
163 std::net::IpAddr::V4(ipv4) => {
164 buf.put_u32(ipv4.into());
165 }
166 std::net::IpAddr::V6(ipv6) => {
167 buf.extend_from_slice(&ipv6.octets());
168 }
169 }
170
171 if geo_peer
173 .peer
174 .peer_type
175 .contains(crate::models::PeerType::AS_SIZE_32BIT)
176 {
177 buf.put_u32(u32::from(geo_peer.peer.peer_asn));
178 } else {
179 buf.put_u16(u16::from(geo_peer.peer.peer_asn));
180 }
181
182 buf.put_f32(geo_peer.peer_latitude);
184 buf.put_f32(geo_peer.peer_longitude);
185 }
186
187 buf.freeze()
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194 use bytes::BufMut;
195 use bytes::BytesMut;
196 use std::net::{Ipv4Addr, Ipv6Addr};
197 use std::str::FromStr;
198
199 #[test]
200 fn test_parse_geo_peer_table() {
201 let mut data = BytesMut::new();
202
203 data.put_u32(0x0A000001); let view_name = "test-view";
208 data.put_u16(view_name.len() as u16);
209 data.extend_from_slice(view_name.as_bytes());
210
211 data.put_f32(51.5074);
213 data.put_f32(-0.1278);
214
215 data.put_u16(2);
217
218 data.put_u8(0x00); data.put_u32(0x01010101); data.put_u32(0x02020202); data.put_u16(65001); data.put_f32(40.7128); data.put_f32(-74.0060); data.put_u8(0x03); data.put_u32(0x03030303); data.extend_from_slice(&[
231 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 0x00, 0x01,
233 ]);
234 data.put_u32(65002); data.put_f32(f32::NAN); data.put_f32(f32::NAN); let mut bytes = data.freeze();
239 let result = parse_geo_peer_table(&mut bytes).unwrap();
240
241 assert_eq!(
243 result.collector_bgp_id,
244 Ipv4Addr::from_str("10.0.0.1").unwrap()
245 );
246 assert_eq!(result.view_name, "test-view");
247 assert_eq!(result.collector_latitude, 51.5074);
248 assert_eq!(result.collector_longitude, -0.1278);
249
250 assert_eq!(result.geo_peers.len(), 2);
252
253 let peer1 = &result.geo_peers[0];
255 assert_eq!(
256 peer1.peer.peer_bgp_id,
257 Ipv4Addr::from_str("1.1.1.1").unwrap()
258 );
259 assert_eq!(
260 peer1.peer.peer_ip,
261 IpAddr::V4(Ipv4Addr::from_str("2.2.2.2").unwrap())
262 );
263 assert_eq!(peer1.peer.peer_asn, Asn::new_16bit(65001));
264 assert!(!peer1.peer.peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6));
265 assert!(!peer1.peer.peer_type.contains(PeerType::AS_SIZE_32BIT));
266 assert_eq!(peer1.peer_latitude, 40.7128);
267 assert_eq!(peer1.peer_longitude, -74.0060);
268
269 let peer2 = &result.geo_peers[1];
271 assert_eq!(
272 peer2.peer.peer_bgp_id,
273 Ipv4Addr::from_str("3.3.3.3").unwrap()
274 );
275 assert_eq!(
276 peer2.peer.peer_ip,
277 IpAddr::V6(Ipv6Addr::from_str("2001:db8::1").unwrap())
278 );
279 assert_eq!(peer2.peer.peer_asn, Asn::new_32bit(65002));
280 assert!(peer2.peer.peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6));
281 assert!(peer2.peer.peer_type.contains(PeerType::AS_SIZE_32BIT));
282 assert!(peer2.peer_latitude.is_nan());
283 assert!(peer2.peer_longitude.is_nan());
284 }
285
286 #[test]
287 fn test_parse_geo_peer_table_private_collector() {
288 let mut data = BytesMut::new();
289
290 data.put_u32(0x0A000001); let view_name = "private-view";
295 data.put_u16(view_name.len() as u16);
296 data.extend_from_slice(view_name.as_bytes());
297
298 data.put_f32(f32::NAN);
300 data.put_f32(f32::NAN);
301
302 data.put_u16(0);
304
305 let mut bytes = data.freeze();
306 let result = parse_geo_peer_table(&mut bytes).unwrap();
307
308 assert!(result.collector_latitude.is_nan());
309 assert!(result.collector_longitude.is_nan());
310 assert_eq!(result.geo_peers.len(), 0);
311 }
312
313 #[test]
314 fn test_geo_peer_table_round_trip() {
315 let collector_bgp_id = Ipv4Addr::from_str("192.168.1.1").unwrap();
316 let mut original_table = GeoPeerTable::new(
317 collector_bgp_id,
318 "round-trip-test".to_string(),
319 37.7749, -122.4194, );
322
323 let peer1 = Peer::new(
325 Ipv4Addr::from_str("203.0.113.1").unwrap(),
326 Ipv4Addr::from_str("203.0.113.2").unwrap().into(),
327 Asn::new_16bit(64512),
328 );
329 let geo_peer1 = GeoPeer::new(peer1, 35.6762, 139.6503); original_table.add_geo_peer(geo_peer1);
331
332 let peer2 = Peer::new(
333 Ipv4Addr::from_str("198.51.100.1").unwrap(),
334 std::net::Ipv6Addr::from_str("2001:db8:85a3::8a2e:370:7334")
335 .unwrap()
336 .into(),
337 Asn::new_32bit(4200000000),
338 );
339 let geo_peer2 = GeoPeer::new(peer2, -33.8688, 151.2093); original_table.add_geo_peer(geo_peer2);
341
342 let encoded = original_table.encode();
344 let mut encoded_bytes = encoded;
345 let parsed_table = parse_geo_peer_table(&mut encoded_bytes).unwrap();
346
347 assert_eq!(
349 parsed_table.collector_bgp_id,
350 original_table.collector_bgp_id
351 );
352 assert_eq!(parsed_table.view_name, original_table.view_name);
353 assert_eq!(
354 parsed_table.collector_latitude,
355 original_table.collector_latitude
356 );
357 assert_eq!(
358 parsed_table.collector_longitude,
359 original_table.collector_longitude
360 );
361 assert_eq!(parsed_table.geo_peers.len(), original_table.geo_peers.len());
362
363 let parsed_peer1 = &parsed_table.geo_peers[0];
365 let original_peer1 = &original_table.geo_peers[0];
366 assert_eq!(
367 parsed_peer1.peer.peer_bgp_id,
368 original_peer1.peer.peer_bgp_id
369 );
370 assert_eq!(parsed_peer1.peer.peer_ip, original_peer1.peer.peer_ip);
371 assert_eq!(parsed_peer1.peer.peer_asn, original_peer1.peer.peer_asn);
372 assert_eq!(parsed_peer1.peer.peer_type, original_peer1.peer.peer_type);
373 assert_eq!(parsed_peer1.peer_latitude, original_peer1.peer_latitude);
374 assert_eq!(parsed_peer1.peer_longitude, original_peer1.peer_longitude);
375
376 let parsed_peer2 = &parsed_table.geo_peers[1];
378 let original_peer2 = &original_table.geo_peers[1];
379 assert_eq!(
380 parsed_peer2.peer.peer_bgp_id,
381 original_peer2.peer.peer_bgp_id
382 );
383 assert_eq!(parsed_peer2.peer.peer_ip, original_peer2.peer.peer_ip);
384 assert_eq!(parsed_peer2.peer.peer_asn, original_peer2.peer.peer_asn);
385 assert_eq!(parsed_peer2.peer.peer_type, original_peer2.peer.peer_type);
386 assert_eq!(parsed_peer2.peer_latitude, original_peer2.peer_latitude);
387 assert_eq!(parsed_peer2.peer_longitude, original_peer2.peer_longitude);
388
389 assert_eq!(parsed_table, original_table);
391 }
392
393 #[test]
394 fn test_geo_peer_table_encoding() {
395 let collector_bgp_id = Ipv4Addr::from_str("10.0.0.1").unwrap();
396 let mut geo_table = GeoPeerTable::new(
397 collector_bgp_id,
398 "test-view".to_string(),
399 51.5074, -0.1278, );
402
403 let peer1 = Peer::new(
405 Ipv4Addr::from_str("1.1.1.1").unwrap(),
406 Ipv4Addr::from_str("2.2.2.2").unwrap().into(),
407 Asn::new_16bit(65001),
408 );
409 let geo_peer1 = GeoPeer::new(peer1, 40.7128, -74.0060); geo_table.add_geo_peer(geo_peer1);
411
412 let peer2 = Peer::new(
414 Ipv4Addr::from_str("3.3.3.3").unwrap(),
415 std::net::Ipv6Addr::from_str("2001:db8::1").unwrap().into(),
416 Asn::new_32bit(65002),
417 );
418 let geo_peer2 = GeoPeer::new(peer2, f32::NAN, f32::NAN); geo_table.add_geo_peer(geo_peer2);
420
421 let encoded = geo_table.encode();
423
424 let mut expected = BytesMut::new();
426
427 expected.put_u32(0x0A000001); let view_name = "test-view";
432 expected.put_u16(view_name.len() as u16);
433 expected.extend_from_slice(view_name.as_bytes());
434
435 expected.put_f32(51.5074);
437 expected.put_f32(-0.1278);
438
439 expected.put_u16(2);
441
442 expected.put_u8(0x00); expected.put_u32(0x01010101); expected.put_u32(0x02020202); expected.put_u16(65001); expected.put_f32(40.7128); expected.put_f32(-74.0060); expected.put_u8(0x03); expected.put_u32(0x03030303); expected.extend_from_slice(&[
454 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455 0x00, 0x01,
456 ]); expected.put_u32(65002); expected.put_f32(f32::NAN); expected.put_f32(f32::NAN); let expected_bytes = expected.freeze();
462
463 assert_eq!(encoded.len(), expected_bytes.len());
465 assert_eq!(encoded, expected_bytes);
466 }
467}