use crate::parser::bmp::error::ParserBmpError;
use crate::parser::ReadUtils;
use bgp_models::network::{Afi, AsnLength};
use num_traits::FromPrimitive;
use std::io::{Cursor, Seek, SeekFrom};
use std::net::IpAddr;
#[derive(Debug, Primitive)]
pub enum BmpMsgType {
RouteMonitoring = 0,
StatisticsReport = 1,
PeerDownNotification = 2,
PeerUpNotification = 3,
InitiationMessage = 4,
TerminationMessage = 5,
RouteMirroringMessage = 6,
}
#[derive(Debug)]
pub struct BmpCommonHeader {
pub version: u8,
pub msg_len: u32,
pub msg_type: BmpMsgType,
}
pub fn parse_bmp_common_header(
reader: &mut Cursor<&[u8]>,
) -> Result<BmpCommonHeader, ParserBmpError> {
let version = reader.read_8b()?;
if version != 3 {
return Err(ParserBmpError::CorruptedBmpMessage);
}
let msg_len = reader.read_32b()?;
let msg_type = BmpMsgType::from_u8(reader.read_8b()?).unwrap();
Ok(BmpCommonHeader {
version,
msg_len,
msg_type,
})
}
#[derive(Debug)]
pub struct BmpPerPeerHeader {
pub peer_type: PeerType,
pub peer_flags: u8,
pub peer_distinguisher: u64,
pub peer_ip: IpAddr,
pub peer_asn: u32,
pub peer_bgp_id: u32,
pub timestamp: f64,
pub afi: Afi,
pub asn_len: AsnLength,
}
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Primitive)]
pub enum PeerType {
GlobalInstancePeer = 0,
RDInstancePeer = 1,
LocalInstancePeer = 2,
}
pub fn parse_per_peer_header(
reader: &mut Cursor<&[u8]>,
) -> Result<BmpPerPeerHeader, ParserBmpError> {
let peer_type = PeerType::from_u8(reader.read_8b()?).unwrap();
let peer_flags = reader.read_8b()?;
let peer_distinguisher = reader.read_64b()?;
let (is_router_ipv6, is_2byte_asn) = (peer_flags & 0x80 > 0, peer_flags & 0x20 > 0);
let afi = match is_router_ipv6 {
true => Afi::Ipv6,
false => Afi::Ipv4,
};
let asn_len = match is_2byte_asn {
true => AsnLength::Bits16,
false => AsnLength::Bits32,
};
let peer_ip: IpAddr = if is_router_ipv6 {
reader.read_ipv6_address()?.into()
} else {
reader.seek(SeekFrom::Current(12))?;
let ip = reader.read_ipv4_address()?;
ip.into()
};
let peer_asn: u32 = if is_2byte_asn {
reader.seek(SeekFrom::Current(2))?;
reader.read_16b()? as u32
} else {
reader.read_32b()?
};
let peer_bgp_id = reader.read_32b()?;
let t_sec = reader.read_32b()?;
let t_usec = reader.read_32b()?;
let timestamp = t_sec as f64 + (t_usec as f64) / 1_000_000.0;
Ok(BmpPerPeerHeader {
peer_type,
peer_flags,
peer_distinguisher,
peer_ip,
peer_asn,
peer_bgp_id,
timestamp,
afi,
asn_len,
})
}