1use crate::models::*;
3use bitflags::bitflags;
4use num_enum::{IntoPrimitive, TryFromPrimitive};
5use std::collections::HashMap;
6use std::net::{IpAddr, Ipv4Addr};
7use std::str::FromStr;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum TableDumpV2Message {
13 PeerIndexTable(PeerIndexTable),
14 RibAfi(RibAfiEntries),
15 RibGeneric(RibGenericEntries),
17 GeoPeerTable(GeoPeerTable),
19}
20
21impl TableDumpV2Message {
22 pub const fn dump_type(&self) -> TableDumpV2Type {
23 match self {
24 TableDumpV2Message::PeerIndexTable(_) => TableDumpV2Type::PeerIndexTable,
25 TableDumpV2Message::RibAfi(x) => x.rib_type,
26 TableDumpV2Message::RibGeneric(_) => TableDumpV2Type::RibGeneric,
27 TableDumpV2Message::GeoPeerTable(_) => TableDumpV2Type::GeoPeerTable,
28 }
29 }
30}
31
32#[derive(Debug, TryFromPrimitive, IntoPrimitive, Copy, Clone, PartialEq, Eq, Hash)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37#[repr(u16)]
38pub enum TableDumpV2Type {
39 PeerIndexTable = 1,
40 RibIpv4Unicast = 2,
41 RibIpv4Multicast = 3,
42 RibIpv6Unicast = 4,
43 RibIpv6Multicast = 5,
44 RibGeneric = 6,
45 GeoPeerTable = 7,
46 RibIpv4UnicastAddPath = 8,
47 RibIpv4MulticastAddPath = 9,
48 RibIpv6UnicastAddPath = 10,
49 RibIpv6MulticastAddPath = 11,
50 RibGenericAddPath = 12,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
82#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
83pub struct RibAfiEntries {
84 pub rib_type: TableDumpV2Type,
85 pub sequence_number: u32,
86 pub prefix: NetworkPrefix,
87 pub rib_entries: Vec<RibEntry>,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq)]
112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
113pub struct RibGenericEntries {
114 pub sequence_number: u32,
115 pub afi: Afi,
116 pub safi: Safi,
117 pub nlri: NetworkPrefix,
118 pub rib_entries: Vec<RibEntry>,
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub struct RibEntry {
147 pub peer_index: u16,
148 pub originated_time: u32,
149 pub path_id: Option<u32>,
150 pub attributes: Attributes,
151}
152
153#[derive(Debug, Clone, PartialEq, Eq)]
165#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
166pub struct PeerIndexTable {
167 pub collector_bgp_id: BgpIdentifier,
168 pub view_name: String,
169 pub id_peer_map: HashMap<u16, Peer>,
170 pub peer_ip_id_map: HashMap<IpAddr, u16>,
171}
172
173impl Default for PeerIndexTable {
174 fn default() -> Self {
175 PeerIndexTable {
176 collector_bgp_id: Ipv4Addr::from_str("0.0.0.0").unwrap(),
177 view_name: "".to_string(),
178 id_peer_map: HashMap::new(),
179 peer_ip_id_map: HashMap::new(),
180 }
181 }
182}
183
184bitflags! {
185 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
186 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
187 pub struct PeerType: u8 {
188 const AS_SIZE_32BIT = 0x2;
189 const ADDRESS_FAMILY_IPV6 = 0x1;
190 }
191}
192
193#[derive(Debug, Clone, Copy)]
195#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
196pub struct GeoPeer {
197 pub peer: Peer,
198 pub peer_latitude: f32,
199 pub peer_longitude: f32,
200}
201
202impl PartialEq for GeoPeer {
203 fn eq(&self, other: &Self) -> bool {
204 self.peer == other.peer
205 && self.peer_latitude.to_bits() == other.peer_latitude.to_bits()
206 && self.peer_longitude.to_bits() == other.peer_longitude.to_bits()
207 }
208}
209
210impl Eq for GeoPeer {}
211
212impl GeoPeer {
213 pub fn new(peer: Peer, latitude: f32, longitude: f32) -> Self {
214 Self {
215 peer,
216 peer_latitude: latitude,
217 peer_longitude: longitude,
218 }
219 }
220}
221
222#[derive(Debug, Clone)]
224#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
225pub struct GeoPeerTable {
226 pub collector_bgp_id: BgpIdentifier,
227 pub view_name: String,
228 pub collector_latitude: f32,
229 pub collector_longitude: f32,
230 pub geo_peers: Vec<GeoPeer>,
231}
232
233impl PartialEq for GeoPeerTable {
234 fn eq(&self, other: &Self) -> bool {
235 self.collector_bgp_id == other.collector_bgp_id
236 && self.view_name == other.view_name
237 && self.collector_latitude.to_bits() == other.collector_latitude.to_bits()
238 && self.collector_longitude.to_bits() == other.collector_longitude.to_bits()
239 && self.geo_peers == other.geo_peers
240 }
241}
242
243impl Eq for GeoPeerTable {}
244
245impl GeoPeerTable {
246 pub fn new(
247 collector_bgp_id: BgpIdentifier,
248 view_name: String,
249 collector_latitude: f32,
250 collector_longitude: f32,
251 ) -> Self {
252 Self {
253 collector_bgp_id,
254 view_name,
255 collector_latitude,
256 collector_longitude,
257 geo_peers: Vec::new(),
258 }
259 }
260
261 pub fn add_geo_peer(&mut self, geo_peer: GeoPeer) {
262 self.geo_peers.push(geo_peer);
263 }
264}
265
266#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
269pub struct Peer {
270 pub peer_type: PeerType,
271 pub peer_bgp_id: BgpIdentifier,
272 pub peer_ip: IpAddr,
273 pub peer_asn: Asn,
274}
275
276impl Peer {
277 pub fn new(peer_bgp_id: BgpIdentifier, peer_ip: IpAddr, peer_asn: Asn) -> Self {
278 let mut peer_type = PeerType::empty();
279
280 if peer_asn.is_four_byte() {
281 peer_type.insert(PeerType::AS_SIZE_32BIT);
282 }
283
284 if peer_ip.is_ipv6() {
285 peer_type.insert(PeerType::ADDRESS_FAMILY_IPV6);
286 }
287
288 Peer {
289 peer_type,
290 peer_bgp_id,
291 peer_ip,
292 peer_asn,
293 }
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300
301 fn create_peer() -> Peer {
303 let bgp_id = Ipv4Addr::from_str("1.1.1.1").unwrap();
304 let peer_ip: IpAddr = Ipv4Addr::from_str("2.2.2.2").unwrap().into();
305 let asn = Asn::new_32bit(65000);
307 Peer::new(bgp_id, peer_ip, asn)
308 }
309
310 #[test]
311 fn test_peer_new() {
312 let peer = create_peer();
313 assert_eq!(peer.peer_type, PeerType::AS_SIZE_32BIT);
314 assert_eq!(peer.peer_bgp_id, Ipv4Addr::from_str("1.1.1.1").unwrap());
315 assert_eq!(
316 peer.peer_ip,
317 IpAddr::V4(Ipv4Addr::from_str("2.2.2.2").unwrap())
318 );
319 assert_eq!(peer.peer_asn, Asn::new_32bit(65000));
320 }
321
322 #[test]
323 fn test_peer_new_variations() {
324 let peer_ipv4_16bit = Peer::new(
326 Ipv4Addr::from_str("10.0.0.1").unwrap(),
327 IpAddr::V4(Ipv4Addr::from_str("10.0.0.2").unwrap()),
328 Asn::new_16bit(65001),
329 );
330 assert_eq!(peer_ipv4_16bit.peer_type, PeerType::empty());
331
332 let peer_ipv6_16bit = Peer::new(
334 Ipv4Addr::from_str("10.0.0.1").unwrap(),
335 IpAddr::V6(std::net::Ipv6Addr::from_str("2001:db8::1").unwrap()),
336 Asn::new_16bit(65002),
337 );
338 assert_eq!(peer_ipv6_16bit.peer_type, PeerType::ADDRESS_FAMILY_IPV6);
339
340 let peer_ipv6_32bit = Peer::new(
342 Ipv4Addr::from_str("10.0.0.1").unwrap(),
343 IpAddr::V6(std::net::Ipv6Addr::from_str("2001:db8::2").unwrap()),
344 Asn::new_32bit(65003),
345 );
346 assert_eq!(
347 peer_ipv6_32bit.peer_type,
348 PeerType::AS_SIZE_32BIT | PeerType::ADDRESS_FAMILY_IPV6
349 );
350 }
351
352 #[test]
353 fn test_default_peer_index_table() {
354 let peer_index_table = PeerIndexTable::default();
355 assert_eq!(
356 peer_index_table.collector_bgp_id,
357 Ipv4Addr::from_str("0.0.0.0").unwrap()
358 );
359 assert_eq!(peer_index_table.view_name, "".to_string());
360 assert_eq!(peer_index_table.id_peer_map, HashMap::new());
361 assert_eq!(peer_index_table.peer_ip_id_map, HashMap::new());
362 }
363
364 #[test]
365 fn test_peer_type_flags() {
366 let mut peer_type = PeerType::empty();
367 assert_eq!(peer_type, PeerType::empty());
368
369 peer_type.insert(PeerType::AS_SIZE_32BIT);
370 assert_eq!(peer_type, PeerType::AS_SIZE_32BIT);
371
372 peer_type.insert(PeerType::ADDRESS_FAMILY_IPV6);
373 assert_eq!(
374 peer_type,
375 PeerType::AS_SIZE_32BIT | PeerType::ADDRESS_FAMILY_IPV6
376 );
377
378 peer_type.remove(PeerType::AS_SIZE_32BIT);
379 assert_eq!(peer_type, PeerType::ADDRESS_FAMILY_IPV6);
380
381 peer_type.remove(PeerType::ADDRESS_FAMILY_IPV6);
382 assert_eq!(peer_type, PeerType::empty());
383 }
384
385 #[test]
386 fn test_dump_type() {
387 let peer_index_table = TableDumpV2Message::PeerIndexTable(PeerIndexTable::default());
388 assert_eq!(
389 peer_index_table.dump_type(),
390 TableDumpV2Type::PeerIndexTable
391 );
392
393 let rib_afi = TableDumpV2Message::RibAfi(RibAfiEntries {
394 rib_type: TableDumpV2Type::RibIpv4Unicast,
395 sequence_number: 1,
396 prefix: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
397 rib_entries: vec![],
398 });
399 assert_eq!(rib_afi.dump_type(), TableDumpV2Type::RibIpv4Unicast);
400
401 let rib_generic = TableDumpV2Message::RibGeneric(RibGenericEntries {
402 sequence_number: 1,
403 afi: Afi::Ipv4,
404 safi: Safi::Unicast,
405 nlri: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
406 rib_entries: vec![],
407 });
408 assert_eq!(rib_generic.dump_type(), TableDumpV2Type::RibGeneric);
409 }
410
411 #[test]
412 #[cfg(feature = "serde")]
413 fn test_serialization() {
414 let peer_index_table = TableDumpV2Message::PeerIndexTable(PeerIndexTable::default());
415 let serialized = serde_json::to_string(&peer_index_table).unwrap();
416 let deserialized: TableDumpV2Message = serde_json::from_str(&serialized).unwrap();
417 assert_eq!(deserialized, peer_index_table);
418
419 let rib_entry = RibEntry {
420 peer_index: 1,
421 originated_time: 1,
422 path_id: None,
423 attributes: Attributes::default(),
424 };
425 let rib_afi = TableDumpV2Message::RibAfi(RibAfiEntries {
426 rib_type: TableDumpV2Type::RibIpv4Unicast,
427 sequence_number: 1,
428 prefix: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
429 rib_entries: vec![rib_entry],
430 });
431 let serialized = serde_json::to_string(&rib_afi).unwrap();
432 let deserialized: TableDumpV2Message = serde_json::from_str(&serialized).unwrap();
433 assert_eq!(deserialized, rib_afi);
434
435 let rib_generic = TableDumpV2Message::RibGeneric(RibGenericEntries {
436 sequence_number: 1,
437 afi: Afi::Ipv4,
438 safi: Safi::Unicast,
439 nlri: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
440 rib_entries: vec![],
441 });
442 let serialized = serde_json::to_string(&rib_generic).unwrap();
443 let deserialized: TableDumpV2Message = serde_json::from_str(&serialized).unwrap();
444 assert_eq!(deserialized, rib_generic);
445 }
446
447 #[test]
448 fn test_geo_peer() {
449 let peer = create_peer();
450 let geo_peer = GeoPeer::new(peer, 40.7128, -74.0060);
451
452 assert_eq!(geo_peer.peer, peer);
453 assert_eq!(geo_peer.peer_latitude, 40.7128);
454 assert_eq!(geo_peer.peer_longitude, -74.0060);
455
456 let private_geo_peer = GeoPeer::new(peer, f32::NAN, f32::NAN);
458 assert!(private_geo_peer.peer_latitude.is_nan());
459 assert!(private_geo_peer.peer_longitude.is_nan());
460 }
461
462 #[test]
463 fn test_geo_peer_table() {
464 let collector_bgp_id = Ipv4Addr::from_str("10.0.0.1").unwrap();
465 let mut geo_table = GeoPeerTable::new(
466 collector_bgp_id,
467 "test-view".to_string(),
468 51.5074, -0.1278, );
471
472 assert!(!geo_table.collector_latitude.is_nan());
473 assert!(!geo_table.collector_longitude.is_nan());
474 assert_eq!(geo_table.collector_latitude, 51.5074);
475 assert_eq!(geo_table.collector_longitude, -0.1278);
476
477 let peer1 = create_peer();
479 let geo_peer1 = GeoPeer::new(peer1, 40.7128, -74.0060); geo_table.add_geo_peer(geo_peer1);
481
482 let peer2 = Peer::new(
484 Ipv4Addr::from_str("2.2.2.2").unwrap(),
485 Ipv4Addr::from_str("3.3.3.3").unwrap().into(),
486 Asn::new_32bit(65001),
487 );
488 let geo_peer2 = GeoPeer::new(peer2, f32::NAN, f32::NAN);
489 geo_table.add_geo_peer(geo_peer2);
490
491 assert_eq!(geo_table.geo_peers.len(), 2);
492
493 assert!(!geo_table.geo_peers[0].peer_latitude.is_nan());
495 assert!(!geo_table.geo_peers[0].peer_longitude.is_nan());
496 assert!(geo_table.geo_peers[1].peer_latitude.is_nan());
497 assert!(geo_table.geo_peers[1].peer_longitude.is_nan());
498
499 let private_geo_table = GeoPeerTable::new(
501 collector_bgp_id,
502 "private-view".to_string(),
503 f32::NAN,
504 f32::NAN,
505 );
506 assert!(private_geo_table.collector_latitude.is_nan());
507 assert!(private_geo_table.collector_longitude.is_nan());
508 }
509}