use crate::{CrafterError, Result};
use super::constants::{
AFI_IPV4, AFI_IPV6, CAP_ADD_PATH, CAP_FOUR_OCTET_AS, CAP_GRACEFUL_RESTART, CAP_MULTIPROTOCOL,
CAP_ROUTE_REFRESH, SAFI_UNICAST,
};
use super::decode::take;
pub const BGP_OPT_PARAM_CAPABILITIES: u8 = 2;
pub const BGP_CAP_MULTIPROTOCOL_VALUE_LEN: usize = 4;
pub const BGP_CAP_FOUR_OCTET_AS_VALUE_LEN: usize = 4;
pub const BGP_MP_IPV4_UNICAST: (u16, u8) = (AFI_IPV4, SAFI_UNICAST);
pub const BGP_MP_IPV6_UNICAST: (u16, u8) = (AFI_IPV6, SAFI_UNICAST);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BgpCapability {
pub code: u8,
pub value: Vec<u8>,
}
impl BgpCapability {
pub fn raw(code: u8, value: impl Into<Vec<u8>>) -> Self {
Self {
code,
value: value.into(),
}
}
pub fn multiprotocol(afi: u16, safi: u8) -> Self {
let mut value = Vec::with_capacity(BGP_CAP_MULTIPROTOCOL_VALUE_LEN);
value.extend_from_slice(&afi.to_be_bytes());
value.push(0);
value.push(safi);
Self::raw(CAP_MULTIPROTOCOL, value)
}
pub fn ipv4_unicast() -> Self {
Self::multiprotocol(AFI_IPV4, SAFI_UNICAST)
}
pub fn ipv6_unicast() -> Self {
Self::multiprotocol(AFI_IPV6, SAFI_UNICAST)
}
pub fn route_refresh() -> Self {
Self::raw(CAP_ROUTE_REFRESH, Vec::new())
}
pub fn four_octet_as(asn: u32) -> Self {
Self::raw(CAP_FOUR_OCTET_AS, asn.to_be_bytes())
}
pub fn graceful_restart(flags_time: u16, tuples: &[(u16, u8, u8)]) -> Self {
let mut value = Vec::with_capacity(2 + tuples.len() * 4);
value.extend_from_slice(&flags_time.to_be_bytes());
for &(afi, safi, flags) in tuples {
value.extend_from_slice(&afi.to_be_bytes());
value.push(safi);
value.push(flags);
}
Self::raw(CAP_GRACEFUL_RESTART, value)
}
pub fn add_path(entries: &[(u16, u8, u8)]) -> Self {
let mut value = Vec::with_capacity(entries.len() * 4);
for &(afi, safi, send_receive) in entries {
value.extend_from_slice(&afi.to_be_bytes());
value.push(safi);
value.push(send_receive);
}
Self::raw(CAP_ADD_PATH, value)
}
pub fn multiprotocol_afi_safi(&self) -> Result<(u16, u8)> {
if self.code != CAP_MULTIPROTOCOL {
return Err(CrafterError::invalid_field_value(
"bgp.capability.code",
"not a multiprotocol capability",
));
}
let (value, rest) = take(
&self.value,
BGP_CAP_MULTIPROTOCOL_VALUE_LEN,
"bgp multiprotocol capability value",
)?;
if !rest.is_empty() {
return Err(CrafterError::invalid_field_value(
"bgp.capability.multiprotocol.length",
"expected 4 octets",
));
}
let afi = u16::from_be_bytes([value[0], value[1]]);
let safi = value[3];
Ok((afi, safi))
}
pub fn four_octet_asn(&self) -> Result<u32> {
if self.code != CAP_FOUR_OCTET_AS {
return Err(CrafterError::invalid_field_value(
"bgp.capability.code",
"not a four-octet AS capability",
));
}
let (value, rest) = take(
&self.value,
BGP_CAP_FOUR_OCTET_AS_VALUE_LEN,
"bgp four-octet AS capability value",
)?;
if !rest.is_empty() {
return Err(CrafterError::invalid_field_value(
"bgp.capability.four_octet_as.length",
"expected 4 octets",
));
}
Ok(u32::from_be_bytes([value[0], value[1], value[2], value[3]]))
}
pub fn encode(&self, out: &mut Vec<u8>) {
out.push(self.code);
out.push(self.value.len() as u8);
out.extend_from_slice(&self.value);
}
pub fn decode(bytes: &[u8]) -> Result<(Self, &[u8])> {
let (code, rest) = take(bytes, 1, "bgp capability")?;
let (length, rest) = take(rest, 1, "bgp capability")?;
let (value, rest) = take(rest, length[0] as usize, "bgp capability value")?;
Ok((Self::raw(code[0], value.to_vec()), rest))
}
}
pub fn encode_capabilities(capabilities: &[BgpCapability]) -> Vec<u8> {
let encoded_len = capabilities.iter().map(|cap| 2 + cap.value.len()).sum();
let mut out = Vec::with_capacity(encoded_len);
for capability in capabilities {
capability.encode(&mut out);
}
out
}
pub fn decode_capabilities(bytes: &[u8]) -> Result<Vec<BgpCapability>> {
let mut capabilities = Vec::new();
let mut rest = bytes;
while !rest.is_empty() {
let (capability, remaining) = BgpCapability::decode(rest)?;
capabilities.push(capability);
rest = remaining;
}
Ok(capabilities)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BgpOptParam {
pub param_type: u8,
pub value: Vec<u8>,
}
impl BgpOptParam {
pub fn raw(param_type: u8, value: impl Into<Vec<u8>>) -> Self {
Self {
param_type,
value: value.into(),
}
}
pub fn capabilities(value: impl Into<Vec<u8>>) -> Self {
Self::raw(BGP_OPT_PARAM_CAPABILITIES, value)
}
pub(crate) fn encoded_len(&self) -> usize {
2 + self.value.len()
}
pub fn encode(&self, out: &mut Vec<u8>) {
out.push(self.param_type);
out.push(self.value.len() as u8);
out.extend_from_slice(&self.value);
}
pub fn decode(bytes: &[u8]) -> Result<(Self, &[u8])> {
let (param_type, rest) = take(bytes, 1, "bgp optional parameter")?;
let (param_len, rest) = take(rest, 1, "bgp optional parameter")?;
let (value, rest) = take(rest, param_len[0] as usize, "bgp optional parameter value")?;
Ok((Self::raw(param_type[0], value.to_vec()), rest))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw_optional_parameter_round_trips() {
let param = BgpOptParam::raw(99, vec![0xaa, 0xbb, 0xcc]);
let mut encoded = Vec::new();
param.encode(&mut encoded);
assert_eq!(encoded, [99, 3, 0xaa, 0xbb, 0xcc]);
let (decoded, rest) = BgpOptParam::decode(&encoded).expect("parameter decodes");
assert_eq!(decoded, param);
assert!(rest.is_empty());
}
#[test]
fn capabilities_round_trip_with_unknown_code() {
let capabilities = vec![
BgpCapability::raw(2, Vec::new()),
BgpCapability::raw(200, vec![0xaa, 0xbb, 0xcc]),
];
let encoded = encode_capabilities(&capabilities);
assert_eq!(encoded, [2, 0, 200, 3, 0xaa, 0xbb, 0xcc]);
let decoded = decode_capabilities(&encoded).expect("capabilities decode");
assert_eq!(decoded, capabilities);
}
#[test]
fn multiprotocol_capability_encodes_and_parses() {
let capability = BgpCapability::multiprotocol(2, 1);
let mut encoded = Vec::new();
capability.encode(&mut encoded);
assert_eq!(encoded, [1, 4, 0x00, 0x02, 0x00, 0x01]);
assert_eq!(
capability
.multiprotocol_afi_safi()
.expect("MP-BGP capability parses"),
(2, 1)
);
assert_eq!(
BgpCapability::ipv4_unicast().multiprotocol_afi_safi(),
Ok(BGP_MP_IPV4_UNICAST)
);
assert_eq!(
BgpCapability::ipv6_unicast().multiprotocol_afi_safi(),
Ok(BGP_MP_IPV6_UNICAST)
);
}
#[test]
fn four_octet_as_capability_encodes_and_parses() {
let capability = BgpCapability::four_octet_as(4_200_000_000);
let mut encoded = Vec::new();
capability.encode(&mut encoded);
assert_eq!(encoded, [65, 4, 0xfa, 0x56, 0xea, 0x00]);
assert_eq!(
capability
.four_octet_asn()
.expect("four-octet AS capability parses"),
4_200_000_000
);
}
}