use crate::afi::{BgpItem, MplsLabels};
use crate::message::attributes::*;
#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
pub struct BgpPMSITaRSVP {
pub ext_tunnel_id: std::net::Ipv4Addr,
pub reserved: u16,
pub tunnel_id: u16,
pub p2mp_id: std::net::Ipv4Addr,
}
impl std::fmt::Display for BgpPMSITaRSVP {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"RSVP-TE P2MP LSP:{}:{}:{}:{}",
self.ext_tunnel_id, self.reserved, self.tunnel_id, self.p2mp_id
)
}
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
pub struct BgpPMSITaIngressRepl {
pub endpoint: std::net::Ipv4Addr,
}
impl std::fmt::Display for BgpPMSITaIngressRepl {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Ingress replication:{}", self.endpoint)
}
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
pub struct BgpPMSITaMLDP {
pub rootnode: std::net::IpAddr,
pub opaque: Vec<u8>,
}
impl std::fmt::Display for BgpPMSITaMLDP {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "mLDP P2MP LSP:{}", self.rootnode)
}
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
pub enum BgpPMSITunnelAttr {
None,
RSVPTe(BgpPMSITaRSVP),
IngressRepl(BgpPMSITaIngressRepl),
MLDP(BgpPMSITaMLDP),
}
impl std::fmt::Display for BgpPMSITunnelAttr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
BgpPMSITunnelAttr::None => "".fmt(f),
BgpPMSITunnelAttr::RSVPTe(r) => r.fmt(f),
BgpPMSITunnelAttr::IngressRepl(r) => r.fmt(f),
BgpPMSITunnelAttr::MLDP(r) => r.fmt(f),
}
}
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg(feature = "serialization")]
#[derive(Serialize, Deserialize)]
pub struct BgpPMSITunnel {
pub flags: u8,
pub tunnel_type: u8,
pub label: MplsLabels,
pub tunnel_attribute: BgpPMSITunnelAttr,
}
impl BgpPMSITunnel {
pub fn decode_from(_peer: &BgpSessionParams, buf: &[u8]) -> Result<BgpPMSITunnel, BgpError> {
if buf.len() < 5 {
return Err(BgpError::static_str("Invalid PMSI buffer length"));
}
let lbls = MplsLabels::extract_bits_from(24, &buf[2..])?;
let curpos = 2 + lbls.1;
Ok(BgpPMSITunnel {
flags: buf[0],
tunnel_type: buf[1],
label: lbls.0,
tunnel_attribute: match buf[1] {
0 => BgpPMSITunnelAttr::None,
1 =>
{
BgpPMSITunnelAttr::RSVPTe(BgpPMSITaRSVP {
ext_tunnel_id: std::net::Ipv4Addr::new(
buf[curpos],
buf[curpos + 1],
buf[curpos + 2],
buf[curpos + 3],
),
reserved: getn_u16(&buf[curpos + 4..]),
tunnel_id: getn_u16(&buf[curpos + 6..]),
p2mp_id: std::net::Ipv4Addr::new(
buf[curpos + 8],
buf[curpos + 9],
buf[curpos + 10],
buf[curpos + 11],
),
})
}
2 => {
if buf[5] != 6 {
return Err(BgpError::from_string(format!(
"Unknown PMSI tunnel type mLDP p2mp: {}",
buf[5]
)));
}
if buf.len() < 16 {
return Err(BgpError::from_string(format!(
"PMSI tunnel type mLDP p2mp too short: {}",
buf.len()
)));
}
if getn_u16(&buf[6..8]) != 1 {
return Err(BgpError::Static("Invalid root node address family"));
}
if buf[8] != 4 {
return Err(BgpError::Static("Invalid root node address length"));
}
let rootnode = decode_addr_from(&buf[9..13])?;
let opaquelen = getn_u16(&buf[13..15]) as usize;
if buf.len() < (15 + opaquelen) {
return Err(BgpError::from_string(format!(
"PMSI tunnel type mLDP p2mp too short: {} < 15+{}",
buf.len(),
opaquelen
)));
}
BgpPMSITunnelAttr::MLDP(BgpPMSITaMLDP {
rootnode,
opaque: buf[15..(15 + opaquelen)].to_vec(),
})
}
6 =>
{
BgpPMSITunnelAttr::IngressRepl(BgpPMSITaIngressRepl {
endpoint: std::net::Ipv4Addr::new(
buf[curpos],
buf[curpos + 1],
buf[curpos + 2],
buf[curpos + 3],
),
})
}
_ => {
return Err(BgpError::from_string(format!(
"Unknown PMSI tunnel type: {}, flags {}, buf: {:?}",
buf[1], buf[0], buf
)));
}
},
})
}
}
impl std::fmt::Debug for BgpPMSITunnel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BgpPMSITunnel")
.field("flags", &self.flags)
.field("tunnel_type", &self.tunnel_type)
.field("label", &self.label)
.field("tunnel_attribute", &self.tunnel_attribute)
.finish()
}
}
impl std::fmt::Display for BgpPMSITunnel {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"BgpPMSITunnel flags={} type={} label={} attribute={}",
self.flags, self.tunnel_type, self.label, self.tunnel_attribute
)
}
}
impl BgpAttr for BgpPMSITunnel {
fn attr(&self) -> BgpAttrParams {
BgpAttrParams {
typecode: 22,
flags: 192,
}
}
fn encode_to(&self, _peer: &BgpSessionParams, _buf: &mut [u8]) -> Result<usize, BgpError> {
unimplemented!();
}
}