bgpkit_parser/models/bgp/
capabilities.rsuse num_enum::{FromPrimitive, IntoPrimitive};
#[allow(non_camel_case_types)]
#[derive(Debug, FromPrimitive, IntoPrimitive, PartialEq, Eq, Hash, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum BgpCapabilityType {
MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4 = 1,
ROUTE_REFRESH_CAPABILITY_FOR_BGP_4 = 2,
OUTBOUND_ROUTE_FILTERING_CAPABILITY = 3,
EXTENDED_NEXT_HOP_ENCODING = 5,
BGP_EXTENDED_MESSAGE = 6,
BGPSEC_CAPABILITY = 7,
MULTIPLE_LABELS_CAPABILITY = 8,
BGP_ROLE = 9,
GRACEFUL_RESTART_CAPABILITY = 64,
SUPPORT_FOR_4_OCTET_AS_NUMBER_CAPABILITY = 65,
SUPPORT_FOR_DYNAMIC_CAPABILITY = 67,
MULTISESSION_BGP_CAPABILITY = 68,
ADD_PATH_CAPABILITY = 69,
ENHANCED_ROUTE_REFRESH_CAPABILITY = 70,
LONG_LIVED_GRACEFUL_RESTART_CAPABILITY = 71,
ROUTING_POLICY_DISTRIBUTION = 72,
FQDN_CAPABILITY = 73,
#[num_enum(catch_all)]
Unknown(u8),
}
impl BgpCapabilityType {
pub const fn is_deprecated(&self) -> bool {
matches!(
self,
BgpCapabilityType::Unknown(4 | 66 | 128 | 129 | 130 | 131 | 184 | 185)
)
}
pub const fn is_reserved(&self) -> bool {
matches!(self, BgpCapabilityType::Unknown(0 | 255))
}
pub const fn is_reserved_for_experimental_use(&self) -> bool {
matches!(self, BgpCapabilityType::Unknown(239..=254))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parsing_capability() {
assert!(BgpCapabilityType::from(0).is_reserved());
assert!(BgpCapabilityType::from(255).is_reserved());
for code in [4, 66, 128, 129, 130, 131, 184, 185] {
assert!(BgpCapabilityType::from(code).is_deprecated());
}
let unassigned_ranges = [10..=63, 74..=127, 132..=183, 186..=238];
for code in <[_; 4]>::into_iter(unassigned_ranges).flatten() {
let ty = BgpCapabilityType::from(code);
assert_eq!(ty, BgpCapabilityType::Unknown(code));
assert!(!ty.is_deprecated() && !ty.is_reserved());
}
assert_eq!(
BgpCapabilityType::from(1),
BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4
);
assert_eq!(
BgpCapabilityType::from(2),
BgpCapabilityType::ROUTE_REFRESH_CAPABILITY_FOR_BGP_4
);
assert_eq!(
BgpCapabilityType::from(3),
BgpCapabilityType::OUTBOUND_ROUTE_FILTERING_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(5),
BgpCapabilityType::EXTENDED_NEXT_HOP_ENCODING
);
assert_eq!(
BgpCapabilityType::from(6),
BgpCapabilityType::BGP_EXTENDED_MESSAGE
);
assert_eq!(
BgpCapabilityType::from(7),
BgpCapabilityType::BGPSEC_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(8),
BgpCapabilityType::MULTIPLE_LABELS_CAPABILITY
);
assert_eq!(BgpCapabilityType::from(9), BgpCapabilityType::BGP_ROLE);
assert_eq!(
BgpCapabilityType::from(64),
BgpCapabilityType::GRACEFUL_RESTART_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(65),
BgpCapabilityType::SUPPORT_FOR_4_OCTET_AS_NUMBER_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(67),
BgpCapabilityType::SUPPORT_FOR_DYNAMIC_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(68),
BgpCapabilityType::MULTISESSION_BGP_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(69),
BgpCapabilityType::ADD_PATH_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(70),
BgpCapabilityType::ENHANCED_ROUTE_REFRESH_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(71),
BgpCapabilityType::LONG_LIVED_GRACEFUL_RESTART_CAPABILITY
);
assert_eq!(
BgpCapabilityType::from(72),
BgpCapabilityType::ROUTING_POLICY_DISTRIBUTION
);
assert_eq!(
BgpCapabilityType::from(73),
BgpCapabilityType::FQDN_CAPABILITY
);
}
#[test]
fn test_reserved_for_experimental() {
let experimental_ranges = [239..=254];
for code in <[_; 1]>::into_iter(experimental_ranges).flatten() {
let ty = BgpCapabilityType::from(code);
assert_eq!(ty, BgpCapabilityType::Unknown(code));
assert!(ty.is_reserved_for_experimental_use());
}
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
let ty = BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4;
let serialized = serde_json::to_string(&ty).unwrap();
let deserialized: BgpCapabilityType = serde_json::from_str(&serialized).unwrap();
assert_eq!(ty, deserialized);
}
}