use crate::models::*;
use bitflags::bitflags;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr};
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TableDumpV2Message {
PeerIndexTable(PeerIndexTable),
RibAfi(RibAfiEntries),
RibGeneric(RibGenericEntries),
}
impl TableDumpV2Message {
pub const fn dump_type(&self) -> TableDumpV2Type {
match self {
TableDumpV2Message::PeerIndexTable(_) => TableDumpV2Type::PeerIndexTable,
TableDumpV2Message::RibAfi(x) => x.rib_type,
TableDumpV2Message::RibGeneric(_) => TableDumpV2Type::RibGeneric,
}
}
}
#[derive(Debug, TryFromPrimitive, IntoPrimitive, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u16)]
pub enum TableDumpV2Type {
PeerIndexTable = 1,
RibIpv4Unicast = 2,
RibIpv4Multicast = 3,
RibIpv6Unicast = 4,
RibIpv6Multicast = 5,
RibGeneric = 6,
GeoPeerTable = 7,
RibIpv4UnicastAddPath = 8,
RibIpv4MulticastAddPath = 9,
RibIpv6UnicastAddPath = 10,
RibIpv6MulticastAddPath = 11,
RibGenericAddPath = 12,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RibAfiEntries {
pub rib_type: TableDumpV2Type,
pub sequence_number: u32,
pub prefix: NetworkPrefix,
pub rib_entries: Vec<RibEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RibGenericEntries {
pub sequence_number: u32,
pub afi: Afi,
pub safi: Safi,
pub nlri: NetworkPrefix,
pub rib_entries: Vec<RibEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RibEntry {
pub peer_index: u16,
pub originated_time: u32,
pub attributes: Attributes,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PeerIndexTable {
pub collector_bgp_id: BgpIdentifier,
pub view_name: String,
pub id_peer_map: HashMap<u16, Peer>,
pub peer_addr_id_map: HashMap<IpAddr, u16>,
}
impl Default for PeerIndexTable {
fn default() -> Self {
PeerIndexTable {
collector_bgp_id: Ipv4Addr::from_str("0.0.0.0").unwrap(),
view_name: "".to_string(),
id_peer_map: HashMap::new(),
peer_addr_id_map: HashMap::new(),
}
}
}
bitflags! {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PeerType: u8 {
const AS_SIZE_32BIT = 0x2;
const ADDRESS_FAMILY_IPV6 = 0x1;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Peer {
pub peer_type: PeerType,
pub peer_bgp_id: BgpIdentifier,
pub peer_address: IpAddr,
pub peer_asn: Asn,
}
impl Peer {
pub fn new(peer_bgp_id: BgpIdentifier, peer_address: IpAddr, peer_asn: Asn) -> Self {
let mut peer_type = PeerType::empty();
if peer_asn.is_four_byte() {
peer_type.insert(PeerType::AS_SIZE_32BIT);
}
if peer_address.is_ipv6() {
peer_type.insert(PeerType::ADDRESS_FAMILY_IPV6);
}
Peer {
peer_type,
peer_bgp_id,
peer_address,
peer_asn,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_peer() -> Peer {
let bgp_id = Ipv4Addr::from_str("1.1.1.1").unwrap();
let peer_address: IpAddr = Ipv4Addr::from_str("2.2.2.2").unwrap().into();
let asn = Asn::new_32bit(65000);
Peer::new(bgp_id, peer_address, asn)
}
#[test]
fn test_peer_new() {
let peer = create_peer();
assert_eq!(peer.peer_type, PeerType::AS_SIZE_32BIT);
assert_eq!(peer.peer_bgp_id, Ipv4Addr::from_str("1.1.1.1").unwrap());
assert_eq!(
peer.peer_address,
IpAddr::V4(Ipv4Addr::from_str("2.2.2.2").unwrap())
);
assert_eq!(peer.peer_asn, Asn::new_32bit(65000));
}
#[test]
fn test_default_peer_index_table() {
let peer_index_table = PeerIndexTable::default();
assert_eq!(
peer_index_table.collector_bgp_id,
Ipv4Addr::from_str("0.0.0.0").unwrap()
);
assert_eq!(peer_index_table.view_name, "".to_string());
assert_eq!(peer_index_table.id_peer_map, HashMap::new());
assert_eq!(peer_index_table.peer_addr_id_map, HashMap::new());
}
#[test]
fn test_peer_type_flags() {
let mut peer_type = PeerType::empty();
assert_eq!(peer_type, PeerType::empty());
peer_type.insert(PeerType::AS_SIZE_32BIT);
assert_eq!(peer_type, PeerType::AS_SIZE_32BIT);
peer_type.insert(PeerType::ADDRESS_FAMILY_IPV6);
assert_eq!(
peer_type,
PeerType::AS_SIZE_32BIT | PeerType::ADDRESS_FAMILY_IPV6
);
peer_type.remove(PeerType::AS_SIZE_32BIT);
assert_eq!(peer_type, PeerType::ADDRESS_FAMILY_IPV6);
peer_type.remove(PeerType::ADDRESS_FAMILY_IPV6);
assert_eq!(peer_type, PeerType::empty());
}
#[test]
fn test_dump_type() {
let peer_index_table = TableDumpV2Message::PeerIndexTable(PeerIndexTable::default());
assert_eq!(
peer_index_table.dump_type(),
TableDumpV2Type::PeerIndexTable
);
let rib_afi = TableDumpV2Message::RibAfi(RibAfiEntries {
rib_type: TableDumpV2Type::RibIpv4Unicast,
sequence_number: 1,
prefix: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
rib_entries: vec![],
});
assert_eq!(rib_afi.dump_type(), TableDumpV2Type::RibIpv4Unicast);
let rib_generic = TableDumpV2Message::RibGeneric(RibGenericEntries {
sequence_number: 1,
afi: Afi::Ipv4,
safi: Safi::Unicast,
nlri: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
rib_entries: vec![],
});
assert_eq!(rib_generic.dump_type(), TableDumpV2Type::RibGeneric);
}
#[test]
#[cfg(feature = "serde")]
fn test_serialization() {
let peer_index_table = TableDumpV2Message::PeerIndexTable(PeerIndexTable::default());
let serialized = serde_json::to_string(&peer_index_table).unwrap();
let deserialized: TableDumpV2Message = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized, peer_index_table);
let rib_entry = RibEntry {
peer_index: 1,
originated_time: 1,
attributes: Attributes::default(),
};
let rib_afi = TableDumpV2Message::RibAfi(RibAfiEntries {
rib_type: TableDumpV2Type::RibIpv4Unicast,
sequence_number: 1,
prefix: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
rib_entries: vec![rib_entry],
});
let serialized = serde_json::to_string(&rib_afi).unwrap();
let deserialized: TableDumpV2Message = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized, rib_afi);
let rib_generic = TableDumpV2Message::RibGeneric(RibGenericEntries {
sequence_number: 1,
afi: Afi::Ipv4,
safi: Safi::Unicast,
nlri: NetworkPrefix::from_str("10.0.0.0/24").unwrap(),
rib_entries: vec![],
});
let serialized = serde_json::to_string(&rib_generic).unwrap();
let deserialized: TableDumpV2Message = serde_json::from_str(&serialized).unwrap();
assert_eq!(deserialized, rib_generic);
}
}