bgpkit_parser/parser/mrt/messages/table_dump_v2/
geo_peer_table.rs1use crate::encoder::sink::put_u16_len_slice;
4use crate::error::{check_max, EncodingError, ParserError};
5use crate::models::*;
6use crate::parser::ReadUtils;
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8use std::net::IpAddr;
9
10pub fn parse_geo_peer_table(data: &mut Bytes) -> Result<GeoPeerTable, ParserError> {
50 let collector_bgp_id = data.read_ipv4_address()?;
52
53 let view_name_len = data.read_u16()? as usize;
55 let view_name = data.read_n_bytes_to_string(view_name_len)?;
56
57 data.has_n_remaining(4)?;
59 let collector_latitude = data.get_f32();
60 data.has_n_remaining(4)?;
61 let collector_longitude = data.get_f32();
62
63 let mut geo_table = GeoPeerTable::new(
64 collector_bgp_id,
65 view_name,
66 collector_latitude,
67 collector_longitude,
68 );
69
70 let peer_count = data.read_u16()?;
72
73 for _ in 0..peer_count {
75 let peer_type_raw = data.read_u8()?;
77 let peer_type = PeerType::from_bits_retain(peer_type_raw);
78
79 let peer_bgp_id = data.read_ipv4_address()?;
81
82 let peer_ip: IpAddr = if peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6) {
84 data.read_ipv6_address()?.into()
85 } else {
86 data.read_ipv4_address()?.into()
87 };
88
89 let peer_asn = if peer_type.contains(PeerType::AS_SIZE_32BIT) {
91 Asn::new_32bit(data.read_u32()?)
92 } else {
93 Asn::new_16bit(data.read_u16()?)
94 };
95
96 let peer = Peer {
98 peer_type,
99 peer_bgp_id,
100 peer_ip,
101 peer_asn,
102 };
103
104 data.has_n_remaining(4)?;
106 let peer_latitude = data.get_f32();
107 data.has_n_remaining(4)?;
108 let peer_longitude = data.get_f32();
109
110 let geo_peer = GeoPeer::new(peer, peer_latitude, peer_longitude);
111 geo_table.add_geo_peer(geo_peer);
112 }
113
114 Ok(geo_table)
115}
116
117impl GeoPeerTable {
118 pub fn encode(&self) -> Result<Bytes, EncodingError> {
141 let mut buf = BytesMut::new();
142
143 buf.put_u32(self.collector_bgp_id.into());
145
146 put_u16_len_slice(
148 &mut buf,
149 "GeoPeerTable view name length",
150 self.view_name.as_bytes(),
151 )?;
152
153 buf.put_f32(self.collector_latitude);
155 buf.put_f32(self.collector_longitude);
156
157 check_max(
159 "GeoPeerTable peer count",
160 self.geo_peers.len(),
161 u16::MAX as usize,
162 )?;
163 buf.put_u16(self.geo_peers.len() as u16);
164
165 for geo_peer in &self.geo_peers {
167 buf.put_u8(geo_peer.peer.peer_type.bits());
169
170 buf.put_u32(geo_peer.peer.peer_bgp_id.into());
172
173 match geo_peer.peer.peer_ip {
175 std::net::IpAddr::V4(ipv4) => {
176 buf.put_u32(ipv4.into());
177 }
178 std::net::IpAddr::V6(ipv6) => {
179 buf.extend_from_slice(&ipv6.octets());
180 }
181 }
182
183 if geo_peer
185 .peer
186 .peer_type
187 .contains(crate::models::PeerType::AS_SIZE_32BIT)
188 {
189 buf.put_u32(u32::from(geo_peer.peer.peer_asn));
190 } else {
191 buf.put_u16(u16::from(geo_peer.peer.peer_asn));
192 }
193
194 buf.put_f32(geo_peer.peer_latitude);
196 buf.put_f32(geo_peer.peer_longitude);
197 }
198
199 Ok(buf.freeze())
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use bytes::BufMut;
207 use bytes::BytesMut;
208 use std::net::{Ipv4Addr, Ipv6Addr};
209 use std::str::FromStr;
210
211 #[test]
212 fn test_parse_geo_peer_table() {
213 let mut data = BytesMut::new();
214
215 data.put_u32(0x0A000001); let view_name = "test-view";
220 data.put_u16(view_name.len() as u16);
221 data.extend_from_slice(view_name.as_bytes());
222
223 data.put_f32(51.5074);
225 data.put_f32(-0.1278);
226
227 data.put_u16(2);
229
230 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(&[
243 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x01,
245 ]);
246 data.put_u32(65002); data.put_f32(f32::NAN); data.put_f32(f32::NAN); let mut bytes = data.freeze();
251 let result = parse_geo_peer_table(&mut bytes).unwrap();
252
253 assert_eq!(
255 result.collector_bgp_id,
256 Ipv4Addr::from_str("10.0.0.1").unwrap()
257 );
258 assert_eq!(result.view_name, "test-view");
259 assert_eq!(result.collector_latitude, 51.5074);
260 assert_eq!(result.collector_longitude, -0.1278);
261
262 assert_eq!(result.geo_peers.len(), 2);
264
265 let peer1 = &result.geo_peers[0];
267 assert_eq!(
268 peer1.peer.peer_bgp_id,
269 Ipv4Addr::from_str("1.1.1.1").unwrap()
270 );
271 assert_eq!(
272 peer1.peer.peer_ip,
273 IpAddr::V4(Ipv4Addr::from_str("2.2.2.2").unwrap())
274 );
275 assert_eq!(peer1.peer.peer_asn, Asn::new_16bit(65001));
276 assert!(!peer1.peer.peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6));
277 assert!(!peer1.peer.peer_type.contains(PeerType::AS_SIZE_32BIT));
278 assert_eq!(peer1.peer_latitude, 40.7128);
279 assert_eq!(peer1.peer_longitude, -74.0060);
280
281 let peer2 = &result.geo_peers[1];
283 assert_eq!(
284 peer2.peer.peer_bgp_id,
285 Ipv4Addr::from_str("3.3.3.3").unwrap()
286 );
287 assert_eq!(
288 peer2.peer.peer_ip,
289 IpAddr::V6(Ipv6Addr::from_str("2001:db8::1").unwrap())
290 );
291 assert_eq!(peer2.peer.peer_asn, Asn::new_32bit(65002));
292 assert!(peer2.peer.peer_type.contains(PeerType::ADDRESS_FAMILY_IPV6));
293 assert!(peer2.peer.peer_type.contains(PeerType::AS_SIZE_32BIT));
294 assert!(peer2.peer_latitude.is_nan());
295 assert!(peer2.peer_longitude.is_nan());
296 }
297
298 #[test]
299 fn test_parse_geo_peer_table_private_collector() {
300 let mut data = BytesMut::new();
301
302 data.put_u32(0x0A000001); let view_name = "private-view";
307 data.put_u16(view_name.len() as u16);
308 data.extend_from_slice(view_name.as_bytes());
309
310 data.put_f32(f32::NAN);
312 data.put_f32(f32::NAN);
313
314 data.put_u16(0);
316
317 let mut bytes = data.freeze();
318 let result = parse_geo_peer_table(&mut bytes).unwrap();
319
320 assert!(result.collector_latitude.is_nan());
321 assert!(result.collector_longitude.is_nan());
322 assert_eq!(result.geo_peers.len(), 0);
323 }
324
325 #[test]
326 fn test_geo_peer_table_round_trip() {
327 let collector_bgp_id = Ipv4Addr::from_str("192.168.1.1").unwrap();
328 let mut original_table = GeoPeerTable::new(
329 collector_bgp_id,
330 "round-trip-test".to_string(),
331 37.7749, -122.4194, );
334
335 let peer1 = Peer::new(
337 Ipv4Addr::from_str("203.0.113.1").unwrap(),
338 Ipv4Addr::from_str("203.0.113.2").unwrap().into(),
339 Asn::new_16bit(64512),
340 );
341 let geo_peer1 = GeoPeer::new(peer1, 35.6762, 139.6503); original_table.add_geo_peer(geo_peer1);
343
344 let peer2 = Peer::new(
345 Ipv4Addr::from_str("198.51.100.1").unwrap(),
346 std::net::Ipv6Addr::from_str("2001:db8:85a3::8a2e:370:7334")
347 .unwrap()
348 .into(),
349 Asn::new_32bit(4200000000),
350 );
351 let geo_peer2 = GeoPeer::new(peer2, -33.8688, 151.2093); original_table.add_geo_peer(geo_peer2);
353
354 let encoded = original_table.encode().unwrap();
356 let mut encoded_bytes = encoded;
357 let parsed_table = parse_geo_peer_table(&mut encoded_bytes).unwrap();
358
359 assert_eq!(
361 parsed_table.collector_bgp_id,
362 original_table.collector_bgp_id
363 );
364 assert_eq!(parsed_table.view_name, original_table.view_name);
365 assert_eq!(
366 parsed_table.collector_latitude,
367 original_table.collector_latitude
368 );
369 assert_eq!(
370 parsed_table.collector_longitude,
371 original_table.collector_longitude
372 );
373 assert_eq!(parsed_table.geo_peers.len(), original_table.geo_peers.len());
374
375 let parsed_peer1 = &parsed_table.geo_peers[0];
377 let original_peer1 = &original_table.geo_peers[0];
378 assert_eq!(
379 parsed_peer1.peer.peer_bgp_id,
380 original_peer1.peer.peer_bgp_id
381 );
382 assert_eq!(parsed_peer1.peer.peer_ip, original_peer1.peer.peer_ip);
383 assert_eq!(parsed_peer1.peer.peer_asn, original_peer1.peer.peer_asn);
384 assert_eq!(parsed_peer1.peer.peer_type, original_peer1.peer.peer_type);
385 assert_eq!(parsed_peer1.peer_latitude, original_peer1.peer_latitude);
386 assert_eq!(parsed_peer1.peer_longitude, original_peer1.peer_longitude);
387
388 let parsed_peer2 = &parsed_table.geo_peers[1];
390 let original_peer2 = &original_table.geo_peers[1];
391 assert_eq!(
392 parsed_peer2.peer.peer_bgp_id,
393 original_peer2.peer.peer_bgp_id
394 );
395 assert_eq!(parsed_peer2.peer.peer_ip, original_peer2.peer.peer_ip);
396 assert_eq!(parsed_peer2.peer.peer_asn, original_peer2.peer.peer_asn);
397 assert_eq!(parsed_peer2.peer.peer_type, original_peer2.peer.peer_type);
398 assert_eq!(parsed_peer2.peer_latitude, original_peer2.peer_latitude);
399 assert_eq!(parsed_peer2.peer_longitude, original_peer2.peer_longitude);
400
401 assert_eq!(parsed_table, original_table);
403 }
404
405 #[test]
406 fn test_geo_peer_table_encoding() {
407 let collector_bgp_id = Ipv4Addr::from_str("10.0.0.1").unwrap();
408 let mut geo_table = GeoPeerTable::new(
409 collector_bgp_id,
410 "test-view".to_string(),
411 51.5074, -0.1278, );
414
415 let peer1 = Peer::new(
417 Ipv4Addr::from_str("1.1.1.1").unwrap(),
418 Ipv4Addr::from_str("2.2.2.2").unwrap().into(),
419 Asn::new_16bit(65001),
420 );
421 let geo_peer1 = GeoPeer::new(peer1, 40.7128, -74.0060); geo_table.add_geo_peer(geo_peer1);
423
424 let peer2 = Peer::new(
426 Ipv4Addr::from_str("3.3.3.3").unwrap(),
427 std::net::Ipv6Addr::from_str("2001:db8::1").unwrap().into(),
428 Asn::new_32bit(65002),
429 );
430 let geo_peer2 = GeoPeer::new(peer2, f32::NAN, f32::NAN); geo_table.add_geo_peer(geo_peer2);
432
433 let encoded = geo_table.encode().unwrap();
435
436 let mut expected = BytesMut::new();
438
439 expected.put_u32(0x0A000001); let view_name = "test-view";
444 expected.put_u16(view_name.len() as u16);
445 expected.extend_from_slice(view_name.as_bytes());
446
447 expected.put_f32(51.5074);
449 expected.put_f32(-0.1278);
450
451 expected.put_u16(2);
453
454 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(&[
466 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x01,
468 ]); expected.put_u32(65002); expected.put_f32(f32::NAN); expected.put_f32(f32::NAN); let expected_bytes = expected.freeze();
474
475 assert_eq!(encoded.len(), expected_bytes.len());
477 assert_eq!(encoded, expected_bytes);
478 }
479}