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.read_u16()? as usize;
54 let view_name = data.read_n_bytes_to_string(view_name_len)?;
55
56 data.has_n_remaining(4)?;
58 let collector_latitude = data.get_f32();
59 data.has_n_remaining(4)?;
60 let collector_longitude = data.get_f32();
61
62 let mut geo_table = GeoPeerTable::new(
63 collector_bgp_id,
64 view_name,
65 collector_latitude,
66 collector_longitude,
67 );
68
69 let peer_count = data.read_u16()?;
71
72 for _ in 0..peer_count {
74 let peer_type_raw = data.read_u8()?;
76 let peer_type = PeerType::from_bits_retain(peer_type_raw);
77
78 let peer_bgp_id = data.read_ipv4_address()?;
80
81 let peer_ip: IpAddr = if peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6) {
83 data.read_ipv6_address()?.into()
84 } else {
85 data.read_ipv4_address()?.into()
86 };
87
88 let peer_asn = if peer_type.contains(PeerType::AS_SIZE_32BIT) {
90 Asn::new_32bit(data.read_u32()?)
91 } else {
92 Asn::new_16bit(data.read_u16()?)
93 };
94
95 let peer = Peer {
97 peer_type,
98 peer_bgp_id,
99 peer_ip,
100 peer_asn,
101 };
102
103 data.has_n_remaining(4)?;
105 let peer_latitude = data.get_f32();
106 data.has_n_remaining(4)?;
107 let peer_longitude = data.get_f32();
108
109 let geo_peer = GeoPeer::new(peer, peer_latitude, peer_longitude);
110 geo_table.add_geo_peer(geo_peer);
111 }
112
113 Ok(geo_table)
114}
115
116impl GeoPeerTable {
117 pub fn encode(&self) -> Bytes {
140 let mut buf = BytesMut::new();
141
142 buf.put_u32(self.collector_bgp_id.into());
144
145 let view_name_bytes = self.view_name.as_bytes();
147 buf.put_u16(view_name_bytes.len() as u16);
148 buf.extend(view_name_bytes);
149
150 buf.put_f32(self.collector_latitude);
152 buf.put_f32(self.collector_longitude);
153
154 buf.put_u16(self.geo_peers.len() as u16);
156
157 for geo_peer in &self.geo_peers {
159 buf.put_u8(geo_peer.peer.peer_type.bits());
161
162 buf.put_u32(geo_peer.peer.peer_bgp_id.into());
164
165 match geo_peer.peer.peer_ip {
167 std::net::IpAddr::V4(ipv4) => {
168 buf.put_u32(ipv4.into());
169 }
170 std::net::IpAddr::V6(ipv6) => {
171 buf.extend_from_slice(&ipv6.octets());
172 }
173 }
174
175 if geo_peer
177 .peer
178 .peer_type
179 .contains(crate::models::PeerType::AS_SIZE_32BIT)
180 {
181 buf.put_u32(u32::from(geo_peer.peer.peer_asn));
182 } else {
183 buf.put_u16(u16::from(geo_peer.peer.peer_asn));
184 }
185
186 buf.put_f32(geo_peer.peer_latitude);
188 buf.put_f32(geo_peer.peer_longitude);
189 }
190
191 buf.freeze()
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198 use bytes::BufMut;
199 use bytes::BytesMut;
200 use std::net::{Ipv4Addr, Ipv6Addr};
201 use std::str::FromStr;
202
203 #[test]
204 fn test_parse_geo_peer_table() {
205 let mut data = BytesMut::new();
206
207 data.put_u32(0x0A000001); let view_name = "test-view";
212 data.put_u16(view_name.len() as u16);
213 data.extend_from_slice(view_name.as_bytes());
214
215 data.put_f32(51.5074);
217 data.put_f32(-0.1278);
218
219 data.put_u16(2);
221
222 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(&[
235 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x01,
237 ]);
238 data.put_u32(65002); data.put_f32(f32::NAN); data.put_f32(f32::NAN); let mut bytes = data.freeze();
243 let result = parse_geo_peer_table(&mut bytes).unwrap();
244
245 assert_eq!(
247 result.collector_bgp_id,
248 Ipv4Addr::from_str("10.0.0.1").unwrap()
249 );
250 assert_eq!(result.view_name, "test-view");
251 assert_eq!(result.collector_latitude, 51.5074);
252 assert_eq!(result.collector_longitude, -0.1278);
253
254 assert_eq!(result.geo_peers.len(), 2);
256
257 let peer1 = &result.geo_peers[0];
259 assert_eq!(
260 peer1.peer.peer_bgp_id,
261 Ipv4Addr::from_str("1.1.1.1").unwrap()
262 );
263 assert_eq!(
264 peer1.peer.peer_ip,
265 IpAddr::V4(Ipv4Addr::from_str("2.2.2.2").unwrap())
266 );
267 assert_eq!(peer1.peer.peer_asn, Asn::new_16bit(65001));
268 assert!(!peer1.peer.peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6));
269 assert!(!peer1.peer.peer_type.contains(PeerType::AS_SIZE_32BIT));
270 assert_eq!(peer1.peer_latitude, 40.7128);
271 assert_eq!(peer1.peer_longitude, -74.0060);
272
273 let peer2 = &result.geo_peers[1];
275 assert_eq!(
276 peer2.peer.peer_bgp_id,
277 Ipv4Addr::from_str("3.3.3.3").unwrap()
278 );
279 assert_eq!(
280 peer2.peer.peer_ip,
281 IpAddr::V6(Ipv6Addr::from_str("2001:db8::1").unwrap())
282 );
283 assert_eq!(peer2.peer.peer_asn, Asn::new_32bit(65002));
284 assert!(peer2.peer.peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6));
285 assert!(peer2.peer.peer_type.contains(PeerType::AS_SIZE_32BIT));
286 assert!(peer2.peer_latitude.is_nan());
287 assert!(peer2.peer_longitude.is_nan());
288 }
289
290 #[test]
291 fn test_parse_geo_peer_table_private_collector() {
292 let mut data = BytesMut::new();
293
294 data.put_u32(0x0A000001); let view_name = "private-view";
299 data.put_u16(view_name.len() as u16);
300 data.extend_from_slice(view_name.as_bytes());
301
302 data.put_f32(f32::NAN);
304 data.put_f32(f32::NAN);
305
306 data.put_u16(0);
308
309 let mut bytes = data.freeze();
310 let result = parse_geo_peer_table(&mut bytes).unwrap();
311
312 assert!(result.collector_latitude.is_nan());
313 assert!(result.collector_longitude.is_nan());
314 assert_eq!(result.geo_peers.len(), 0);
315 }
316
317 #[test]
318 fn test_geo_peer_table_round_trip() {
319 let collector_bgp_id = Ipv4Addr::from_str("192.168.1.1").unwrap();
320 let mut original_table = GeoPeerTable::new(
321 collector_bgp_id,
322 "round-trip-test".to_string(),
323 37.7749, -122.4194, );
326
327 let peer1 = Peer::new(
329 Ipv4Addr::from_str("203.0.113.1").unwrap(),
330 Ipv4Addr::from_str("203.0.113.2").unwrap().into(),
331 Asn::new_16bit(64512),
332 );
333 let geo_peer1 = GeoPeer::new(peer1, 35.6762, 139.6503); original_table.add_geo_peer(geo_peer1);
335
336 let peer2 = Peer::new(
337 Ipv4Addr::from_str("198.51.100.1").unwrap(),
338 std::net::Ipv6Addr::from_str("2001:db8:85a3::8a2e:370:7334")
339 .unwrap()
340 .into(),
341 Asn::new_32bit(4200000000),
342 );
343 let geo_peer2 = GeoPeer::new(peer2, -33.8688, 151.2093); original_table.add_geo_peer(geo_peer2);
345
346 let encoded = original_table.encode();
348 let mut encoded_bytes = encoded;
349 let parsed_table = parse_geo_peer_table(&mut encoded_bytes).unwrap();
350
351 assert_eq!(
353 parsed_table.collector_bgp_id,
354 original_table.collector_bgp_id
355 );
356 assert_eq!(parsed_table.view_name, original_table.view_name);
357 assert_eq!(
358 parsed_table.collector_latitude,
359 original_table.collector_latitude
360 );
361 assert_eq!(
362 parsed_table.collector_longitude,
363 original_table.collector_longitude
364 );
365 assert_eq!(parsed_table.geo_peers.len(), original_table.geo_peers.len());
366
367 let parsed_peer1 = &parsed_table.geo_peers[0];
369 let original_peer1 = &original_table.geo_peers[0];
370 assert_eq!(
371 parsed_peer1.peer.peer_bgp_id,
372 original_peer1.peer.peer_bgp_id
373 );
374 assert_eq!(parsed_peer1.peer.peer_ip, original_peer1.peer.peer_ip);
375 assert_eq!(parsed_peer1.peer.peer_asn, original_peer1.peer.peer_asn);
376 assert_eq!(parsed_peer1.peer.peer_type, original_peer1.peer.peer_type);
377 assert_eq!(parsed_peer1.peer_latitude, original_peer1.peer_latitude);
378 assert_eq!(parsed_peer1.peer_longitude, original_peer1.peer_longitude);
379
380 let parsed_peer2 = &parsed_table.geo_peers[1];
382 let original_peer2 = &original_table.geo_peers[1];
383 assert_eq!(
384 parsed_peer2.peer.peer_bgp_id,
385 original_peer2.peer.peer_bgp_id
386 );
387 assert_eq!(parsed_peer2.peer.peer_ip, original_peer2.peer.peer_ip);
388 assert_eq!(parsed_peer2.peer.peer_asn, original_peer2.peer.peer_asn);
389 assert_eq!(parsed_peer2.peer.peer_type, original_peer2.peer.peer_type);
390 assert_eq!(parsed_peer2.peer_latitude, original_peer2.peer_latitude);
391 assert_eq!(parsed_peer2.peer_longitude, original_peer2.peer_longitude);
392
393 assert_eq!(parsed_table, original_table);
395 }
396
397 #[test]
398 fn test_geo_peer_table_encoding() {
399 let collector_bgp_id = Ipv4Addr::from_str("10.0.0.1").unwrap();
400 let mut geo_table = GeoPeerTable::new(
401 collector_bgp_id,
402 "test-view".to_string(),
403 51.5074, -0.1278, );
406
407 let peer1 = Peer::new(
409 Ipv4Addr::from_str("1.1.1.1").unwrap(),
410 Ipv4Addr::from_str("2.2.2.2").unwrap().into(),
411 Asn::new_16bit(65001),
412 );
413 let geo_peer1 = GeoPeer::new(peer1, 40.7128, -74.0060); geo_table.add_geo_peer(geo_peer1);
415
416 let peer2 = Peer::new(
418 Ipv4Addr::from_str("3.3.3.3").unwrap(),
419 std::net::Ipv6Addr::from_str("2001:db8::1").unwrap().into(),
420 Asn::new_32bit(65002),
421 );
422 let geo_peer2 = GeoPeer::new(peer2, f32::NAN, f32::NAN); geo_table.add_geo_peer(geo_peer2);
424
425 let encoded = geo_table.encode();
427
428 let mut expected = BytesMut::new();
430
431 expected.put_u32(0x0A000001); let view_name = "test-view";
436 expected.put_u16(view_name.len() as u16);
437 expected.extend_from_slice(view_name.as_bytes());
438
439 expected.put_f32(51.5074);
441 expected.put_f32(-0.1278);
442
443 expected.put_u16(2);
445
446 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(&[
458 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459 0x00, 0x01,
460 ]); expected.put_u32(65002); expected.put_f32(f32::NAN); expected.put_f32(f32::NAN); let expected_bytes = expected.freeze();
466
467 assert_eq!(encoded.len(), expected_bytes.len());
469 assert_eq!(encoded, expected_bytes);
470 }
471}