pub mod attributes;
pub mod capabilities;
pub mod community;
pub mod elem;
pub mod error;
pub mod flowspec;
pub mod linkstate;
pub mod role;
pub mod tunnel_encap;
pub use attributes::*;
pub use community::*;
pub use elem::*;
pub use error::*;
pub use flowspec::*;
pub use linkstate::*;
pub use role::*;
pub use tunnel_encap::*;
use crate::models::network::*;
use capabilities::{
AddPathCapability, BgpCapabilityType, BgpExtendedMessageCapability, BgpRoleCapability,
ExtendedNextHopCapability, FourOctetAsCapability, GracefulRestartCapability,
MultiprotocolExtensionsCapability, RouteRefreshCapability,
};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::net::Ipv4Addr;
pub type BgpIdentifier = Ipv4Addr;
#[allow(non_camel_case_types)]
#[derive(Debug, TryFromPrimitive, IntoPrimitive, Copy, Clone, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum BgpMessageType {
OPEN = 1,
UPDATE = 2,
NOTIFICATION = 3,
KEEPALIVE = 4,
ROUTE_REFRESH = 5,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum BgpMessage {
Open(BgpOpenMessage),
Update(BgpUpdateMessage),
Notification(BgpNotificationMessage),
KeepAlive,
RouteRefresh(BgpRouteRefreshMessage),
}
impl BgpMessage {
pub const fn msg_type(&self) -> BgpMessageType {
match self {
BgpMessage::Open(_) => BgpMessageType::OPEN,
BgpMessage::Update(_) => BgpMessageType::UPDATE,
BgpMessage::Notification(_) => BgpMessageType::NOTIFICATION,
BgpMessage::KeepAlive => BgpMessageType::KEEPALIVE,
BgpMessage::RouteRefresh(_) => BgpMessageType::ROUTE_REFRESH,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BgpRouteRefreshMessage {
pub afi: u16,
pub subtype: u8,
pub safi: u8,
pub data: Vec<u8>,
}
impl BgpRouteRefreshMessage {
pub fn afi(&self) -> Option<Afi> {
Afi::try_from(self.afi).ok()
}
pub fn safi(&self) -> Option<Safi> {
Safi::try_from(self.safi).ok()
}
pub fn validation_warnings(&self) -> Vec<crate::error::BgpValidationWarning> {
use crate::error::BgpValidationWarning;
let mut warnings = Vec::new();
match self.subtype {
0 => {}
1 | 2 => {
if !self.data.is_empty() {
warnings.push(BgpValidationWarning::InvalidRouteRefreshLength {
subtype: self.subtype,
length: 4 + self.data.len(),
});
}
}
subtype => {
warnings.push(BgpValidationWarning::UnknownRouteRefreshSubtype { subtype });
}
}
warnings
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BgpOpenMessage {
pub version: u8,
pub asn: Asn,
pub hold_time: u16,
pub bgp_identifier: BgpIdentifier,
pub extended_length: bool,
pub opt_params: Vec<OptParam>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OptParam {
pub param_type: u8,
pub param_value: ParamValue,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ParamValue {
Raw(Vec<u8>),
Capacities(Vec<Capability>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Capability {
pub ty: BgpCapabilityType,
pub value: CapabilityValue,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CapabilityValue {
Raw(Vec<u8>),
MultiprotocolExtensions(MultiprotocolExtensionsCapability),
RouteRefresh(RouteRefreshCapability),
ExtendedNextHop(ExtendedNextHopCapability),
GracefulRestart(GracefulRestartCapability),
FourOctetAs(FourOctetAsCapability),
AddPath(AddPathCapability),
BgpRole(BgpRoleCapability),
BgpExtendedMessage(BgpExtendedMessageCapability),
}
#[derive(Debug, Clone, PartialEq, Default, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BgpUpdateMessage {
pub withdrawn_prefixes: Vec<NetworkPrefix>,
pub attributes: Attributes,
pub announced_prefixes: Vec<NetworkPrefix>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BgpNotificationMessage {
pub error: BgpError,
pub data: Vec<u8>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::BgpValidationWarning;
fn route_refresh(subtype: u8, data: Vec<u8>) -> BgpRouteRefreshMessage {
BgpRouteRefreshMessage {
afi: 1,
subtype,
safi: 1,
data,
}
}
#[test]
fn test_route_refresh_validation_warnings() {
assert!(route_refresh(0, vec![]).validation_warnings().is_empty());
assert!(route_refresh(0, vec![0x01])
.validation_warnings()
.is_empty());
assert!(route_refresh(1, vec![]).validation_warnings().is_empty());
assert!(route_refresh(2, vec![]).validation_warnings().is_empty());
assert_eq!(
route_refresh(2, vec![0xDE, 0xAD, 0xBE]).validation_warnings(),
vec![BgpValidationWarning::InvalidRouteRefreshLength {
subtype: 2,
length: 7
}]
);
assert_eq!(
route_refresh(3, vec![]).validation_warnings(),
vec![BgpValidationWarning::UnknownRouteRefreshSubtype { subtype: 3 }]
);
}
#[test]
fn test_message_type() {
let open = BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: Asn::new_32bit(1),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 0, 2, 1),
extended_length: false,
opt_params: vec![],
});
assert_eq!(open.msg_type(), BgpMessageType::OPEN);
let update = BgpMessage::Update(BgpUpdateMessage::default());
assert_eq!(update.msg_type(), BgpMessageType::UPDATE);
let notification = BgpMessage::Notification(BgpNotificationMessage {
error: BgpError::Unknown(0, 0),
data: vec![],
});
assert_eq!(notification.msg_type(), BgpMessageType::NOTIFICATION);
let keepalive = BgpMessage::KeepAlive;
assert_eq!(keepalive.msg_type(), BgpMessageType::KEEPALIVE);
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
let open = BgpMessage::Open(BgpOpenMessage {
version: 4,
asn: Asn::new_32bit(1),
hold_time: 180,
bgp_identifier: Ipv4Addr::new(192, 0, 2, 1),
extended_length: false,
opt_params: vec![],
});
let serialized = serde_json::to_string(&open).unwrap();
let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
assert_eq!(open, deserialized);
let update = BgpMessage::Update(BgpUpdateMessage::default());
let serialized = serde_json::to_string(&update).unwrap();
let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
assert_eq!(update, deserialized);
let notification = BgpMessage::Notification(BgpNotificationMessage {
error: BgpError::Unknown(0, 0),
data: vec![],
});
let serialized = serde_json::to_string(¬ification).unwrap();
let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
assert_eq!(notification, deserialized);
let keepalive = BgpMessage::KeepAlive;
let serialized = serde_json::to_string(&keepalive).unwrap();
let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
assert_eq!(keepalive, deserialized);
}
}