#![deny(missing_docs)]
pub mod open;
pub use crate::open::*;
pub mod notification;
pub use crate::notification::*;
pub mod update;
pub use crate::update::*;
mod util;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::convert::TryFrom;
use std::fmt::{Debug, Display, Formatter};
use std::io::{Error, ErrorKind, Read, Write};
const BGP_MIN_MESSAGE_SIZE: usize = 19;
const BGP_MAX_MESSAGE_SIZE: usize = 4096;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(u16)]
pub enum AFI {
IPV4 = 0x01,
IPV6 = 0x02,
L2VPN = 0x19,
BGPLS = 0x4004,
}
impl AFI {
fn empty_buffer(&self) -> Vec<u8> {
match self {
AFI::IPV4 => vec![0u8; 4],
AFI::IPV6 => vec![0u8; 16],
_ => unimplemented!(),
}
}
}
impl TryFrom<u16> for AFI {
type Error = Error;
fn try_from(v: u16) -> Result<Self, Self::Error> {
match v {
0x01 => Ok(AFI::IPV4),
0x02 => Ok(AFI::IPV6),
0x19 => Ok(AFI::L2VPN),
0x4004 => Ok(AFI::BGPLS),
_ => Err(Error::new(
ErrorKind::Other,
format!("Not a supported AFI: '{}'", v),
)),
}
}
}
impl Display for AFI {
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
use AFI::*;
let s = match self {
IPV4 => "IPv4",
IPV6 => "IPv6",
L2VPN => "L2VPN",
BGPLS => "BGPLS",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(u8)]
pub enum SAFI {
Unicast = 1,
Multicast = 2,
Mpls = 4,
MulticastVpn = 5,
Vpls = 65,
Evpn = 70,
BgpLs = 71,
BgpLsVpn = 72,
Rtc = 132,
MplsVpn = 128,
Flowspec = 133,
FlowspecVPN = 134,
}
impl TryFrom<u8> for SAFI {
type Error = Error;
fn try_from(v: u8) -> Result<Self, Self::Error> {
match v {
1 => Ok(SAFI::Unicast),
2 => Ok(SAFI::Multicast),
4 => Ok(SAFI::Mpls),
5 => Ok(SAFI::MulticastVpn),
65 => Ok(SAFI::Vpls),
70 => Ok(SAFI::Evpn),
71 => Ok(SAFI::BgpLs),
72 => Ok(SAFI::BgpLsVpn),
128 => Ok(SAFI::MplsVpn),
132 => Ok(SAFI::Rtc),
133 => Ok(SAFI::Flowspec),
134 => Ok(SAFI::FlowspecVPN),
_ => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Not a supported SAFI: '{}'", v),
)),
}
}
}
impl Display for SAFI {
fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
use SAFI::*;
let s = match self {
Unicast => "Unicast",
Multicast => "Multicast",
Mpls => "MPLS",
MulticastVpn => "Multicast VPN",
Vpls => "VPLS",
Evpn => "EVPN",
BgpLs => "BGPLS",
BgpLsVpn => "BGPLSVPN",
Rtc => "RTC",
MplsVpn => "MPLS VPN",
Flowspec => "Flowspec",
FlowspecVPN => "Flowspec VPN",
};
write!(f, "{}", s)
}
}
#[derive(Clone, Debug)]
pub struct Header {
pub marker: [u8; 16],
pub length: u16,
pub record_type: u8,
}
impl Header {
pub fn parse(stream: &mut impl Read) -> Result<Header, Error> {
let mut marker = [0u8; 16];
stream.read_exact(&mut marker)?;
let length = stream.read_u16::<BigEndian>()?;
let record_type = stream.read_u8()?;
Ok(Header {
marker,
length,
record_type,
})
}
pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
buf.write_all(&self.marker)?;
buf.write_u16::<BigEndian>(self.length)?;
buf.write_u8(self.record_type)
}
}
#[derive(Clone, Debug)]
pub enum Message {
Open(Open),
Update(Update),
Notification(Notification),
KeepAlive,
RouteRefresh(RouteRefresh),
}
impl Message {
fn encode_noheader(&self, buf: &mut impl Write) -> Result<(), Error> {
match self {
Message::Open(open) => open.encode(buf),
Message::Update(update) => update.encode(buf),
Message::Notification(notification) => notification.encode(buf),
Message::KeepAlive => Ok(()),
Message::RouteRefresh(refresh) => refresh.encode(buf),
}
}
pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
let mut message_buf: Vec<u8> = Vec::with_capacity(BGP_MIN_MESSAGE_SIZE); self.encode_noheader(&mut message_buf)?;
let message_length = message_buf.len();
if (message_length + BGP_MIN_MESSAGE_SIZE) > BGP_MAX_MESSAGE_SIZE {
return Err(Error::new(
ErrorKind::Other,
format!("Cannot encode message of length {}", message_length),
));
}
let header = Header {
marker: [0xff; 16],
length: (message_length + BGP_MIN_MESSAGE_SIZE) as u16,
record_type: match self {
Message::Open(_) => 1,
Message::Update(_) => 2,
Message::Notification(_) => 3,
Message::KeepAlive => 4,
Message::RouteRefresh(_) => 5,
},
};
header.encode(buf)?;
buf.write_all(&message_buf)
}
}
#[derive(Clone, Debug)]
pub struct RouteRefresh {
pub afi: AFI,
pub safi: SAFI,
pub subtype: u8,
}
impl RouteRefresh {
fn parse(stream: &mut impl Read) -> Result<RouteRefresh, Error> {
let afi = AFI::try_from(stream.read_u16::<BigEndian>()?)?;
let subtype = stream.read_u8()?;
let safi = SAFI::try_from(stream.read_u8()?)?;
Ok(RouteRefresh { afi, safi, subtype })
}
pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
buf.write_u16::<BigEndian>(self.afi as u16)?;
buf.write_u8(self.subtype)?;
buf.write_u8(self.safi as u8)
}
}
pub trait CapabilitiesRef {
fn get_ref(&self) -> &Capabilities;
}
impl CapabilitiesRef for Capabilities {
fn get_ref(&self) -> &Capabilities {
self
}
}
impl<'a> CapabilitiesRef for &'a Capabilities {
fn get_ref(&self) -> &Capabilities {
self
}
}
pub struct Reader<T, C>
where
T: Read,
C: CapabilitiesRef,
{
pub stream: T,
pub capabilities: C,
}
impl<T, C> Reader<T, C>
where
T: Read,
C: CapabilitiesRef,
{
pub fn read(&mut self) -> Result<(Header, Message), Error> {
let mut marker: [u8; 16] = [0; 16];
self.stream.read_exact(&mut marker)?;
let header = Header {
marker,
length: self.stream.read_u16::<BigEndian>()?,
record_type: self.stream.read_u8()?,
};
match header.record_type {
1 => Ok((header, Message::Open(Open::parse(&mut self.stream)?))),
2 => {
let attribute = Message::Update(Update::parse(
&header,
&mut self.stream,
self.capabilities.get_ref(),
)?);
Ok((header, attribute))
}
3 => {
let attribute =
Message::Notification(Notification::parse(&header, &mut self.stream)?);
Ok((header, attribute))
}
4 => Ok((header, Message::KeepAlive)),
5 => Ok((
header,
Message::RouteRefresh(RouteRefresh::parse(&mut self.stream)?),
)),
_ => Err(Error::new(
ErrorKind::Other,
"Unknown BGP message type found in BGPHeader",
)),
}
}
}
impl<T> Reader<T, Capabilities>
where
T: Read,
{
pub fn new(stream: T) -> Self
where
T: Read,
{
Reader::<T, Capabilities> {
stream,
capabilities: Default::default(),
}
}
}