Cleanup clippy warnings.
Some checks failed
Rust / build (push) Has been cancelled

This commit is contained in:
Rayhaan Jaufeerally
2024-12-08 22:09:00 +00:00
parent cc3842b384
commit b0f2995ed8
18 changed files with 1547 additions and 189 deletions

View File

@ -8,6 +8,7 @@ rust-version.workspace = true
version.workspace = true version.workspace = true
[dependencies] [dependencies]
axum = "0.7.7"
bgp_packet.workspace = true bgp_packet.workspace = true
bgp_server.workspace = true bgp_server.workspace = true
clap.workspace = true clap.workspace = true
@ -33,3 +34,7 @@ path = "src/client/main.rs"
[[bin]] [[bin]]
name = "util" name = "util"
path = "src/util/main.rs" path = "src/util/main.rs"
[[bin]]
name = "api_server"
path = "src/api_server/main.rs"

124
bin/src/api_server/main.rs Normal file
View File

@ -0,0 +1,124 @@
use std::sync::Arc;
use axum::extract::{Path, State};
use axum::http::StatusCode;
use axum::routing::post;
use axum::Router;
use bgp_packet::nlri::NLRI;
use clap::{Parser, Subcommand};
use eyre::{bail, Result};
use route_client::connector::Connector;
use tokio::sync::Mutex;
use tracing::info;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;
#[derive(Parser)]
#[clap(
author = "Rayhaan Jaufeerally <rayhaan@rayhaan.ch>",
version = "0.1",
about = "API Server"
)]
struct Cli {
#[clap(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
/// Run runs the API server connected to a given gRPC backend.
Run {
/// The route server gRPC backend.
backend: String,
},
}
struct AppState {
pub connector: Connector,
}
async fn handle_announce(
State(state): State<Arc<Mutex<AppState>>>,
Path((prefix, prefixlen)): Path<(String, u8)>,
) -> Result<(StatusCode, String), (StatusCode, String)> {
state
.lock()
.await
.connector
.send_announce(
"pr01_rue_rayhaan_net".to_owned(),
NLRI::try_from(format!("{}/{}", prefix, prefixlen).as_str()).map_err(|e| {
(
StatusCode::BAD_REQUEST,
format!("failed to parse NLRI: {}", e),
)
})?,
)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("failed to make RPC to backend: {}", e),
)
})?;
Ok((StatusCode::OK, "Success".to_owned()))
}
async fn handle_withdraw(
State(state): State<Arc<Mutex<AppState>>>,
Path((prefix, prefixlen)): Path<(String, u8)>,
) -> Result<(StatusCode, String), (StatusCode, String)> {
state
.lock()
.await
.connector
.send_withdraw(
"pr01_rue_rayhaan_net".to_owned(),
NLRI::try_from(format!("{}/{}", prefix, prefixlen).as_str()).map_err(|e| {
(
StatusCode::BAD_REQUEST,
format!("failed to parse NLRI: {}", e),
)
})?,
)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("failed to make RPC to backend: {}", e),
)
})?;
Ok((StatusCode::OK, "Success".to_owned()))
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(EnvFilter::from_default_env())
.init();
info!("Starting API Server");
match args.command {
Some(Commands::Run { backend }) => {
let connector = Connector::new(backend).await?;
let app = Router::new()
.route("/announce/:prefix/:prefixlen", post(handle_announce))
.route("/withdraw/:prefix/:prefixlen", post(handle_withdraw))
.with_state(Arc::new(Mutex::new(AppState { connector })));
let listener = tokio::net::TcpListener::bind("localhost:8179")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
None => bail!("A subcommand must be specified."),
};
Ok(())
}

1000
configs/bgplab.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ use nom::number::complete::{be_u16, be_u8};
use nom::Err::Failure; use nom::Err::Failure;
use nom::IResult; use nom::IResult;
use std::fmt; use std::fmt;
use std::fmt::Display;
/// BGPOpenOptionType represents the option types in the Open message. /// BGPOpenOptionType represents the option types in the Open message.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
@ -34,9 +35,9 @@ impl BGPOpenOptionType {
} }
} }
impl Into<u8> for BGPOpenOptionType { impl From<BGPOpenOptionType> for u8 {
fn into(self) -> u8 { fn from(val: BGPOpenOptionType) -> Self {
self.0 val.0
} }
} }
@ -95,14 +96,12 @@ impl WritablePacket for OpenOption {
} }
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> { fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
match &self.oval { match &self.oval {
OpenOptions::Capabilities(c) => { OpenOptions::Capabilities(c) => Ok(2 + c.wire_len(ctx)?),
return Ok(2 + c.wire_len(ctx)?);
}
} }
} }
} }
impl fmt::Display for OpenOption { impl Display for OpenOption {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "OpenOption: {}", self.oval) write!(f, "OpenOption: {}", self.oval)
} }
@ -113,11 +112,11 @@ pub enum OpenOptions {
Capabilities(OpenOptionCapabilities), Capabilities(OpenOptionCapabilities),
} }
impl fmt::Display for OpenOptions { impl Display for OpenOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
return match &self { match &self {
OpenOptions::Capabilities(c) => write!(f, "Capabilities: {}", c), OpenOptions::Capabilities(c) => write!(f, "Capabilities: {}", c),
}; }
} }
} }
@ -137,7 +136,7 @@ impl ReadablePacket for OpenOptionCapabilities {
be_u8, be_u8,
nom::multi::many0(|i| BGPCapability::from_wire(ctx, i)), nom::multi::many0(|i| BGPCapability::from_wire(ctx, i)),
)(buf)?; )(buf)?;
return IResult::Ok((buf, OpenOptionCapabilities { caps })); IResult::Ok((buf, OpenOptionCapabilities { caps }))
} }
} }
@ -161,7 +160,7 @@ impl WritablePacket for OpenOptionCapabilities {
} }
} }
impl fmt::Display for OpenOptionCapabilities { impl Display for OpenOptionCapabilities {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Capabilities: [")?; write!(f, "Capabilities: [")?;
for cap in &self.caps { for cap in &self.caps {
@ -181,9 +180,9 @@ impl BGPCapabilityType {
} }
} }
impl Into<u8> for BGPCapabilityType { impl From<BGPCapabilityType> for u8 {
fn into(self) -> u8 { fn from(val: BGPCapabilityType) -> Self {
return self.0; val.0
} }
} }
@ -306,17 +305,17 @@ impl WritablePacket for BGPCapability {
} }
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> { fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
// BGPCapabilityType(u8) + cap_len(u8) + val // BGPCapabilityType(u8) + cap_len(u8) + val
return match &self.val { match &self.val {
BGPCapabilityValue::FourByteASN(v) => Ok(2 + v.wire_len(ctx)?), BGPCapabilityValue::FourByteASN(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::Multiprotocol(v) => Ok(2 + v.wire_len(ctx)?), BGPCapabilityValue::Multiprotocol(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::RouteRefresh(v) => Ok(2 + v.wire_len(ctx)?), BGPCapabilityValue::RouteRefresh(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::GracefulRestart(v) => Ok(2 + v.wire_len(ctx)?), BGPCapabilityValue::GracefulRestart(v) => Ok(2 + v.wire_len(ctx)?),
BGPCapabilityValue::UnknownCapability(v) => Ok(2 + v.wire_len(ctx)?), BGPCapabilityValue::UnknownCapability(v) => Ok(2 + v.wire_len(ctx)?),
}; }
} }
} }
impl fmt::Display for BGPCapability { impl Display for BGPCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
std::fmt::Display::fmt(&self.val, f) std::fmt::Display::fmt(&self.val, f)
} }
@ -331,7 +330,7 @@ pub enum BGPCapabilityValue {
UnknownCapability(UnknownCapability), UnknownCapability(UnknownCapability),
} }
impl fmt::Display for BGPCapabilityValue { impl Display for BGPCapabilityValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self { match &self {
BGPCapabilityValue::FourByteASN(v) => std::fmt::Display::fmt(v, f), BGPCapabilityValue::FourByteASN(v) => std::fmt::Display::fmt(v, f),
@ -379,7 +378,7 @@ impl WritablePacket for UnknownCapability {
} }
} }
impl fmt::Display for UnknownCapability { impl Display for UnknownCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "UnknownCapability type: {}", self.cap_code) write!(f, "UnknownCapability type: {}", self.cap_code)
} }
@ -403,7 +402,7 @@ impl ReadablePacket for FourByteASNCapability {
buf: &'a [u8], buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> { ) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
let (buf, asn) = nom::combinator::complete(nom::number::complete::be_u32)(buf)?; let (buf, asn) = nom::combinator::complete(nom::number::complete::be_u32)(buf)?;
return IResult::Ok((buf, FourByteASNCapability::new(asn))); IResult::Ok((buf, FourByteASNCapability::new(asn)))
} }
} }
@ -418,7 +417,7 @@ impl WritablePacket for FourByteASNCapability {
} }
} }
impl fmt::Display for FourByteASNCapability { impl Display for FourByteASNCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FourByteASN: asn: {}", self.asn) write!(f, "FourByteASN: asn: {}", self.asn)
} }
@ -445,17 +444,12 @@ impl ReadablePacket for MultiprotocolCapability {
ctx: &ParserContext, ctx: &ParserContext,
buf: &'a [u8], buf: &'a [u8],
) -> IResult<&'a [u8], MultiprotocolCapability, BGPParserError<&'a [u8]>> { ) -> IResult<&'a [u8], MultiprotocolCapability, BGPParserError<&'a [u8]>> {
let (buf, (afi_raw, _, safi_raw)) = nom::combinator::complete(nom::sequence::tuple(( let (buf, (afi, _, safi)) = nom::combinator::complete(nom::sequence::tuple((
|i| AddressFamilyIdentifier::from_wire(ctx, i), |i| AddressFamilyIdentifier::from_wire(ctx, i),
nom::bytes::complete::take(1u8), nom::bytes::complete::take(1u8),
|i| SubsequentAddressFamilyIdentifier::from_wire(ctx, i), |i| SubsequentAddressFamilyIdentifier::from_wire(ctx, i),
)))(buf)?; )))(buf)?;
let afi = AddressFamilyIdentifier::try_from(afi_raw)
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
let safi = SubsequentAddressFamilyIdentifier::try_from(safi_raw)
.map_err(|e| nom::Err::Error(BGPParserError::CustomText(e.to_string())))?;
IResult::Ok((buf, MultiprotocolCapability::new(afi, safi))) IResult::Ok((buf, MultiprotocolCapability::new(afi, safi)))
} }
} }
@ -473,7 +467,7 @@ impl WritablePacket for MultiprotocolCapability {
} }
} }
impl fmt::Display for MultiprotocolCapability { impl Display for MultiprotocolCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MultiprotocolCapbility: [ {} {} ]", self.afi, self.safi,) write!(f, "MultiprotocolCapbility: [ {} {} ]", self.afi, self.safi,)
} }
@ -501,7 +495,7 @@ impl ReadablePacket for RouteRefreshCapability {
} }
} }
impl fmt::Display for RouteRefreshCapability { impl Display for RouteRefreshCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RouteRefreshCapability") write!(f, "RouteRefreshCapability")
} }
@ -548,7 +542,7 @@ impl WritablePacket for GracefulRestartPayload {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> { fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
let afi: u16 = self.afi.into(); let afi: u16 = self.afi.into();
let mut res = vec![0u8; 2]; let mut res = vec![0u8; 2];
byteorder::NetworkEndian::write_u16(res.as_mut(), afi.into()); byteorder::NetworkEndian::write_u16(res.as_mut(), afi);
res.push(self.safi.into()); res.push(self.safi.into());
res.push(if self.af_flags { 0x80 } else { 0 }); res.push(if self.af_flags { 0x80 } else { 0 });
Ok(res) Ok(res)
@ -558,7 +552,7 @@ impl WritablePacket for GracefulRestartPayload {
} }
} }
impl fmt::Display for GracefulRestartPayload { impl Display for GracefulRestartPayload {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
@ -604,7 +598,7 @@ impl WritablePacket for GracefulRestartCapability {
} }
} }
impl fmt::Display for GracefulRestartCapability { impl Display for GracefulRestartCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "GracefulRestartCapability: [")?; write!(f, "GracefulRestartCapability: [")?;
for value in &self.payloads { for value in &self.payloads {
@ -630,14 +624,13 @@ impl WritablePacket for ExtendedNextHopEncodingCapability {
Ok(self Ok(self
.afi_safi_nhafi .afi_safi_nhafi
.iter() .iter()
.map(|e| { .flat_map(|e| {
Into::<Vec<u8>>::into(e.0) Into::<Vec<u8>>::into(e.0)
.into_iter() .into_iter()
.chain(vec![0x00, Into::<u8>::into(e.1)].into_iter()) .chain(vec![0x00, Into::<u8>::into(e.1)])
.chain(Into::<Vec<u8>>::into(e.2).into_iter()) .chain(Into::<Vec<u8>>::into(e.2))
.collect::<Vec<u8>>() .collect::<Vec<u8>>()
}) })
.flatten()
.collect::<Vec<u8>>()) .collect::<Vec<u8>>())
} }
@ -672,7 +665,7 @@ impl ReadablePacket for ExtendedNextHopEncodingCapability {
} }
} }
impl fmt::Display for ExtendedNextHopEncodingCapability { impl Display for ExtendedNextHopEncodingCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ExtendednextHopEncodingCapability [")?; write!(f, "ExtendednextHopEncodingCapability [")?;
for entry in &self.afi_safi_nhafi { for entry in &self.afi_safi_nhafi {
@ -698,7 +691,9 @@ mod tests {
#[test] #[test]
fn test_four_byte_asn_capability() { fn test_four_byte_asn_capability() {
let bytes: &[u8] = &[0x41, 0x04, 0x00, 0x00, 0x00, 0x2a]; let bytes: &[u8] = &[0x41, 0x04, 0x00, 0x00, 0x00, 0x2a];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let (buf, result) = BGPCapability::from_wire(ctx, bytes).unwrap(); let (buf, result) = BGPCapability::from_wire(ctx, bytes).unwrap();
assert_eq!( assert_eq!(
result, result,
@ -716,7 +711,9 @@ mod tests {
0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02, 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02,
0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00, 0x2a,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let (_buf, result) = let (_buf, result) =
nom::multi::many0(|buf: &'a [u8]| OpenOption::from_wire(ctx, buf))(option_bytes) nom::multi::many0(|buf: &'a [u8]| OpenOption::from_wire(ctx, buf))(option_bytes)
.unwrap(); .unwrap();
@ -728,7 +725,9 @@ mod tests {
#[test] #[test]
fn test_extended_next_hop_encoding_capability() { fn test_extended_next_hop_encoding_capability() {
let bytes: Vec<u8> = vec![0x00, 0x01, 0x00, 0x01, 0x00, 0x02]; let bytes: Vec<u8> = vec![0x00, 0x01, 0x00, 0x01, 0x00, 0x02];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let (_, cap) = ExtendedNextHopEncodingCapability::from_wire(ctx, &bytes).unwrap(); let (_, cap) = ExtendedNextHopEncodingCapability::from_wire(ctx, &bytes).unwrap();
let expected_str = let expected_str =

View File

@ -27,11 +27,11 @@ pub enum AddressFamilyIdentifier {
Ipv6, Ipv6,
} }
impl Into<u16> for AddressFamilyIdentifier { impl From<AddressFamilyIdentifier> for u16 {
fn into(self) -> u16 { fn from(val: AddressFamilyIdentifier) -> Self {
match self { match val {
Self::Ipv4 => 1, AddressFamilyIdentifier::Ipv4 => 1,
Self::Ipv6 => 2, AddressFamilyIdentifier::Ipv6 => 2,
} }
} }
} }
@ -50,28 +50,28 @@ impl TryFrom<u16> for AddressFamilyIdentifier {
} }
} }
impl Into<Vec<u8>> for AddressFamilyIdentifier { impl From<AddressFamilyIdentifier> for Vec<u8> {
fn into(self) -> Vec<u8> { fn from(val: AddressFamilyIdentifier) -> Self {
match self { match val {
Self::Ipv4 => 1_u16.to_be_bytes().to_vec(), AddressFamilyIdentifier::Ipv4 => 1_u16.to_be_bytes().to_vec(),
Self::Ipv6 => 2_u16.to_be_bytes().to_vec(), AddressFamilyIdentifier::Ipv6 => 2_u16.to_be_bytes().to_vec(),
} }
} }
} }
/// Convenience functions to convert AddressFamilyIdentifier into those used by netlink. /// Convenience functions to convert AddressFamilyIdentifier into those used by netlink.
impl Into<netlink_packet_route::AddressFamily> for AddressFamilyIdentifier { impl From<AddressFamilyIdentifier> for netlink_packet_route::AddressFamily {
fn into(self) -> netlink_packet_route::AddressFamily { fn from(val: AddressFamilyIdentifier) -> Self {
match self { match val {
AddressFamilyIdentifier::Ipv4 => netlink_packet_route::AddressFamily::Inet, AddressFamilyIdentifier::Ipv4 => netlink_packet_route::AddressFamily::Inet,
AddressFamilyIdentifier::Ipv6 => netlink_packet_route::AddressFamily::Inet6, AddressFamilyIdentifier::Ipv6 => netlink_packet_route::AddressFamily::Inet6,
} }
} }
} }
impl Into<rtnetlink::IpVersion> for AddressFamilyIdentifier { impl From<AddressFamilyIdentifier> for rtnetlink::IpVersion {
fn into(self) -> rtnetlink::IpVersion { fn from(val: AddressFamilyIdentifier) -> Self {
match self { match val {
AddressFamilyIdentifier::Ipv4 => rtnetlink::IpVersion::V4, AddressFamilyIdentifier::Ipv4 => rtnetlink::IpVersion::V4,
AddressFamilyIdentifier::Ipv6 => rtnetlink::IpVersion::V6, AddressFamilyIdentifier::Ipv6 => rtnetlink::IpVersion::V6,
} }
@ -113,14 +113,14 @@ pub enum SubsequentAddressFamilyIdentifier {
MulticastMplsVpn, MulticastMplsVpn,
} }
impl Into<u8> for SubsequentAddressFamilyIdentifier { impl From<SubsequentAddressFamilyIdentifier> for u8 {
fn into(self) -> u8 { fn from(val: SubsequentAddressFamilyIdentifier) -> Self {
match self { match val {
Self::Unicast => 1, SubsequentAddressFamilyIdentifier::Unicast => 1,
Self::Multicast => 2, SubsequentAddressFamilyIdentifier::Multicast => 2,
Self::NlriWithMpls => 4, SubsequentAddressFamilyIdentifier::NlriWithMpls => 4,
Self::MplsLabeledVPN => 128, SubsequentAddressFamilyIdentifier::MplsLabeledVPN => 128,
Self::MulticastMplsVpn => 129, SubsequentAddressFamilyIdentifier::MulticastMplsVpn => 129,
} }
} }
} }

View File

@ -45,9 +45,9 @@ impl BGPMessageType {
} }
} }
impl Into<u8> for BGPMessageType { impl From<BGPMessageType> for u8 {
fn into(self) -> u8 { fn from(val: BGPMessageType) -> Self {
self.0 val.0
} }
} }
impl From<u8> for BGPMessageType { impl From<u8> for BGPMessageType {
@ -264,7 +264,7 @@ impl Decoder for Codec {
let len: u16 = byteorder::BigEndian::read_u16(&buf[16..18]); let len: u16 = byteorder::BigEndian::read_u16(&buf[16..18]);
if buf.len() < len.into() { if buf.len() < len.into() {
// Not enough data to read this frame. // Not enough data to read this frame.
return Ok(None); Ok(None)
} else if buf.len() == len as usize { } else if buf.len() == len as usize {
// Exactly one message here, parse and clear buf. // Exactly one message here, parse and clear buf.
let parse_result = BGPMessage::from_wire(&self.ctx, buf.as_ref()); let parse_result = BGPMessage::from_wire(&self.ctx, buf.as_ref());
@ -306,7 +306,7 @@ impl WritablePacket for BGPMessage {
{ {
let mut tmp: [u8; 2] = [0u8; 2]; let mut tmp: [u8; 2] = [0u8; 2];
NetworkEndian::write_u16(&mut tmp, self.wire_len(ctx)?); NetworkEndian::write_u16(&mut tmp, self.wire_len(ctx)?);
buf.extend_from_slice(&mut tmp); buf.extend_from_slice(&tmp);
} }
// Type // Type
buf.push(self.msg_type.into()); buf.push(self.msg_type.into());
@ -428,9 +428,9 @@ impl WritablePacket for OpenMessage {
for opt in &self.options { for opt in &self.options {
count += (*opt).to_wire(ctx)?.len(); count += (*opt).to_wire(ctx)?.len();
} }
Ok(count count
.try_into() .try_into()
.map_err(|_| "overflow in wire_len in OpenMessage")?) .map_err(|_| "overflow in wire_len in OpenMessage")
} }
} }
@ -485,12 +485,12 @@ impl ReadablePacket for UpdateMessage {
impl WritablePacket for UpdateMessage { impl WritablePacket for UpdateMessage {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> { fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
let mut buf: Vec<u8> = Vec::new(); let mut buf: Vec<u8> = Vec::new();
let mut tmp: &mut [u8] = &mut [0u8; 2]; let tmp: &mut [u8] = &mut [0u8; 2];
let mut wd_len: u16 = 0; let mut wd_len: u16 = 0;
for wd in &self.withdrawn_nlri { for wd in &self.withdrawn_nlri {
wd_len += wd.wire_len(ctx)?; wd_len += wd.wire_len(ctx)?;
} }
NetworkEndian::write_u16(&mut tmp, wd_len); NetworkEndian::write_u16(tmp, wd_len);
buf.append(&mut tmp.to_vec()); buf.append(&mut tmp.to_vec());
for wd in &self.withdrawn_nlri { for wd in &self.withdrawn_nlri {
buf.extend(wd.to_wire(ctx)?); buf.extend(wd.to_wire(ctx)?);
@ -499,7 +499,7 @@ impl WritablePacket for UpdateMessage {
for pattr in &self.path_attributes { for pattr in &self.path_attributes {
pattr_len += pattr.wire_len(ctx)?; pattr_len += pattr.wire_len(ctx)?;
} }
NetworkEndian::write_u16(&mut tmp, pattr_len); NetworkEndian::write_u16(tmp, pattr_len);
buf.extend(tmp.to_vec()); buf.extend(tmp.to_vec());
for pattr in &self.path_attributes { for pattr in &self.path_attributes {
buf.extend(pattr.to_wire(ctx)?); buf.extend(pattr.to_wire(ctx)?);
@ -566,7 +566,9 @@ mod tests {
0x02, 0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x46, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x00,
0x2a, 0x2a,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv4);
let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap(); let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap();
assert_eq!(buf.len(), 0); assert_eq!(buf.len(), 0);
@ -585,7 +587,9 @@ mod tests {
0x18, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02, 0x18, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00, 0x02,
0x02, 0x80, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x22, 0x36, 0x02, 0x80, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0x22, 0x36,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv4);
let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap(); let (buf, result) = BGPMessage::from_wire(ctx, open_msg_bytes).unwrap();
assert_eq!(buf.len(), 0); assert_eq!(buf.len(), 0);
@ -609,14 +613,16 @@ mod tests {
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xcb, 0x01, 0x4e, 0x14, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xcb, 0x01, 0x4e,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv4);
let (buf, result) = BGPMessage::from_wire(ctx, update_msg_bytes).unwrap(); let (buf, result) = BGPMessage::from_wire(ctx, update_msg_bytes).unwrap();
assert_eq!(buf.len(), 0); assert_eq!(buf.len(), 0);
let want_str = "UpdateMessage [ withdrawn: announced: 203.1.78.0/24 path attributes: OriginPathAttribute::INCOMPLETEAS Path: { Segment [ Type: AS_SEGMENT 39540 57118 29691 1299 4739 ]] }NextHop: 185.95.219.36Communities: [ 1299:35000, 29691:4000, 29691:4021, 39540:4000, 39540:4010, 57118:2000, 57118:2010, ] LargeCommunities: [ 57118:20:0, 57118:20:10, ] ]"; let want_str = "UpdateMessage [ withdrawn: announced: 203.1.78.0/24 path attributes: OriginPathAttribute::INCOMPLETEAS Path: { Segment [ Type: AS_SEGMENT 39540 57118 29691 1299 4739 ]] }NextHop: 185.95.219.36Communities: [ 1299:35000, 29691:4000, 29691:4021, 39540:4000, 39540:4010, 57118:2000, 57118:2010, ] LargeCommunities: [ 57118:20:0, 57118:20:10, ] ]";
assert_eq!(format!("{}", result), want_str); assert_eq!(format!("{}", result), want_str);
let reencoded = result.to_wire(&ctx).unwrap(); let reencoded = result.to_wire(ctx).unwrap();
assert_eq!(&reencoded, update_msg_bytes); assert_eq!(&reencoded, update_msg_bytes);
} }
@ -664,7 +670,7 @@ mod tests {
for b in &buf { for b in &buf {
print!("0x{:02x}, ", b); print!("0x{:02x}, ", b);
} }
assert_eq!(buf.as_ref(), update_msg_bytes.as_ref()); assert_eq!(buf.as_ref(), update_msg_bytes);
} }
#[test] #[test]

View File

@ -72,11 +72,9 @@ impl ReadablePacket for NLRI {
let (buf, prefix) = take(octet_len)(buf)?; let (buf, prefix) = take(octet_len)(buf)?;
match ctx.nlri_mode { match ctx.nlri_mode {
None => { None => Err(Failure(BGPParserError::CustomText(
return Err(Failure(BGPParserError::CustomText( "nlri_mode not set in the context for NLRI::from_wire".to_string(),
"nlri_mode not set in the context for NLRI::from_wire".to_string(), ))),
)));
}
Some(afi) => Ok(( Some(afi) => Ok((
buf, buf,
NLRI { NLRI {
@ -115,8 +113,7 @@ impl<'de> Deserialize<'de> for NLRI {
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
Self::try_from(String::deserialize(deserializer)?.as_str()) Self::try_from(String::deserialize(deserializer)?.as_str()).map_err(de::Error::custom)
.map_err(|e| de::Error::custom(e))
} }
} }
@ -207,7 +204,7 @@ impl TryInto<IpAddr> for NLRI {
impl TryFrom<&str> for NLRI { impl TryFrom<&str> for NLRI {
type Error = eyre::ErrReport; type Error = eyre::ErrReport;
fn try_from(value: &str) -> Result<Self, Self::Error> { fn try_from(value: &str) -> Result<Self, Self::Error> {
let parts: Vec<&str> = value.split("/").collect(); let parts: Vec<&str> = value.split('/').collect();
if parts.len() != 2 { if parts.len() != 2 {
bail!("Expected ip_addr/prefixlen but got: {}", value); bail!("Expected ip_addr/prefixlen but got: {}", value);
} }
@ -217,11 +214,11 @@ impl TryFrom<&str> for NLRI {
let mut octets: Vec<u8>; let mut octets: Vec<u8>;
let afi: AddressFamilyIdentifier; let afi: AddressFamilyIdentifier;
if parts[0].contains(":") { if parts[0].contains(':') {
afi = AddressFamilyIdentifier::Ipv6; afi = AddressFamilyIdentifier::Ipv6;
let addr: Ipv6Addr = Ipv6Addr::from_str(parts[0]).map_err(|e| eyre!(e))?; let addr: Ipv6Addr = Ipv6Addr::from_str(parts[0]).map_err(|e| eyre!(e))?;
octets = addr.octets().to_vec(); octets = addr.octets().to_vec();
} else if parts[0].contains(".") { } else if parts[0].contains('.') {
afi = AddressFamilyIdentifier::Ipv4; afi = AddressFamilyIdentifier::Ipv4;
let addr: Ipv4Addr = Ipv4Addr::from_str(parts[0]).map_err(|e| eyre!(e))?; let addr: Ipv4Addr = Ipv4Addr::from_str(parts[0]).map_err(|e| eyre!(e))?;
octets = addr.octets().to_vec(); octets = addr.octets().to_vec();
@ -237,7 +234,7 @@ impl TryFrom<&str> for NLRI {
let num_bytes = (prefixlen / 8) + 1; let num_bytes = (prefixlen / 8) + 1;
let mask = u8::MAX << (8 - (prefixlen % 8)); let mask = u8::MAX << (8 - (prefixlen % 8));
octets.truncate(num_bytes.into()); octets.truncate(num_bytes.into());
if octets.len() > 0 { if !octets.is_empty() {
let last_pos = octets.len() - 1; let last_pos = octets.len() - 1;
octets[last_pos] &= mask; octets[last_pos] &= mask;
} }
@ -282,7 +279,7 @@ mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
use super::NLRI; use super::NLRI;
use crate::constants::AddressFamilyIdentifier::{self, Ipv4, Ipv6}; use crate::constants::AddressFamilyIdentifier::{Ipv4, Ipv6};
use crate::traits::ParserContext; use crate::traits::ParserContext;
use crate::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::traits::WritablePacket; use crate::traits::WritablePacket;
@ -290,7 +287,9 @@ mod tests {
#[test] #[test]
fn test_basic_nlri_v6() { fn test_basic_nlri_v6() {
let nlri_bytes: &[u8] = &[0x20, 0x20, 0x01, 0xdb, 0x8]; let nlri_bytes: &[u8] = &[0x20, 0x20, 0x01, 0xdb, 0x8];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap(); let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap();
assert_eq!(nlri_res.1.afi, Ipv6); assert_eq!(nlri_res.1.afi, Ipv6);
assert_eq!(nlri_res.1.prefixlen, 32); assert_eq!(nlri_res.1.prefixlen, 32);
@ -305,7 +304,9 @@ mod tests {
#[test] #[test]
fn test_basic_nlri_v4() { fn test_basic_nlri_v4() {
let nlri_bytes: &[u8] = &[0x18, 192, 168, 1]; let nlri_bytes: &[u8] = &[0x18, 192, 168, 1];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv4); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv4);
let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap(); let nlri_res: (&[u8], NLRI) = NLRI::from_wire(ctx, nlri_bytes).unwrap();
assert_eq!(nlri_res.1.afi, Ipv4); assert_eq!(nlri_res.1.afi, Ipv4);
assert_eq!(nlri_res.1.prefixlen, 24); assert_eq!(nlri_res.1.prefixlen, 24);

View File

@ -472,10 +472,10 @@ impl ReadablePacket for NextHopPathAttribute {
impl WritablePacket for NextHopPathAttribute { impl WritablePacket for NextHopPathAttribute {
fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> { fn to_wire(&self, _: &ParserContext) -> Result<Vec<u8>, &'static str> {
return Ok(self.0.octets().to_vec()); Ok(self.0.octets().to_vec())
} }
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> { fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
return Ok(4); Ok(4)
} }
} }
@ -584,7 +584,7 @@ impl ReadablePacket for AggregatorPathAttribute {
ctx: &ParserContext, ctx: &ParserContext,
buf: &'a [u8], buf: &'a [u8],
) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> { ) -> IResult<&'a [u8], Self, BGPParserError<&'a [u8]>> {
if !ctx.four_octet_asn.is_some() { if ctx.four_octet_asn.is_none() {
return Err(Failure(BGPParserError::CustomText( return Err(Failure(BGPParserError::CustomText(
"Non four byte ASN not supported (AggregatorPathAttribute from_wire)".to_string(), "Non four byte ASN not supported (AggregatorPathAttribute from_wire)".to_string(),
))); )));
@ -604,7 +604,8 @@ impl ReadablePacket for AggregatorPathAttribute {
impl WritablePacket for AggregatorPathAttribute { impl WritablePacket for AggregatorPathAttribute {
fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> { fn to_wire(&self, ctx: &ParserContext) -> Result<Vec<u8>, &'static str> {
if !ctx.four_octet_asn.is_some() { if ctx.four_octet_asn.is_none() {
// TODO: This should be gracefully handled, not panic!
panic!("Non four byte ASN not supported (AggregatorPathAttribute from_wire)"); panic!("Non four byte ASN not supported (AggregatorPathAttribute from_wire)");
} }
let mut buf: Vec<u8> = vec![0u8; 4]; let mut buf: Vec<u8> = vec![0u8; 4];
@ -613,7 +614,8 @@ impl WritablePacket for AggregatorPathAttribute {
Ok(buf) Ok(buf)
} }
fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> { fn wire_len(&self, ctx: &ParserContext) -> Result<u16, &'static str> {
if !ctx.four_octet_asn.is_some() { if ctx.four_octet_asn.is_none() {
// TODO: This should be gracefully handled, not panic!
panic!("Non four byte ASN not supported (AggregatorPathAttribute from_wire)"); panic!("Non four byte ASN not supported (AggregatorPathAttribute from_wire)");
} }
Ok(8) Ok(8)
@ -733,7 +735,7 @@ impl WritablePacket for ExtendedCommunitiesPathAttribute {
if !self.value.len() == 7 { if !self.value.len() == 7 {
return Err("ExtendedCommunitiesPathAttribute value length != 7"); return Err("ExtendedCommunitiesPathAttribute value length != 7");
} }
Ok(vec![vec![self.t_high], self.value.to_owned()].concat()) Ok([vec![self.t_high], self.value.to_owned()].concat())
} }
fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> { fn wire_len(&self, _: &ParserContext) -> Result<u16, &'static str> {
Ok(8) Ok(8)
@ -847,7 +849,7 @@ impl MPReachNLRIPathAttribute {
// https://datatracker.ietf.org/doc/html/rfc2545 describes what the nexthop // https://datatracker.ietf.org/doc/html/rfc2545 describes what the nexthop
// field can contain. Returns a tuple of (global_nh, linklocal_nh) // field can contain. Returns a tuple of (global_nh, linklocal_nh)
pub fn nexthop_to_v6(self) -> Option<(Ipv6Addr, Option<Ipv6Addr>)> { pub fn nexthop_to_v6(self) -> Option<(Ipv6Addr, Option<Ipv6Addr>)> {
return match self.nexthop.len() { match self.nexthop.len() {
16 => { 16 => {
let nh_bytes: [u8; 16] = self.nexthop.try_into().unwrap(); let nh_bytes: [u8; 16] = self.nexthop.try_into().unwrap();
Some((Ipv6Addr::from(nh_bytes), None)) Some((Ipv6Addr::from(nh_bytes), None))
@ -861,7 +863,7 @@ impl MPReachNLRIPathAttribute {
)) ))
} }
_ => None, _ => None,
}; }
} }
} }
@ -1010,7 +1012,9 @@ mod tests {
0x02, 0x04, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x20, 0x1a, 0x02, 0x04, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x20, 0x1a,
0x00, 0x00, 0x78, 0xfc, 0x00, 0x00, 0x78, 0xfc,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result = &ASPathAttribute::from_wire(ctx, as_path_bytes).unwrap(); let result = &ASPathAttribute::from_wire(ctx, as_path_bytes).unwrap();
let expected_aspath: Vec<u32> = vec![39540, 57118, 8218, 30972]; let expected_aspath: Vec<u32> = vec![39540, 57118, 8218, 30972];
@ -1029,7 +1033,9 @@ mod tests {
0x02, 0x04, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x20, 0x1a, 0x02, 0x04, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x20, 0x1a,
0x00, 0x00, 0x78, 0xfc, 0x01, 0x02, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x78, 0xfc, 0x01, 0x02, 0x00, 0x00, 0x9a, 0x74, 0x00, 0x00, 0xdf, 0x1e,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result = &ASPathAttribute::from_wire(ctx, as_path_bytes).unwrap(); let result = &ASPathAttribute::from_wire(ctx, as_path_bytes).unwrap();
let expected_aspath: Vec<u32> = vec![39540, 57118, 8218, 30972]; let expected_aspath: Vec<u32> = vec![39540, 57118, 8218, 30972];
@ -1048,7 +1054,9 @@ mod tests {
#[test] #[test]
fn test_next_hop_path_attribute() { fn test_next_hop_path_attribute() {
let nh_bytes: &[u8] = &[192, 168, 1, 1]; let nh_bytes: &[u8] = &[192, 168, 1, 1];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result = NextHopPathAttribute::from_wire(ctx, nh_bytes).unwrap(); let result = NextHopPathAttribute::from_wire(ctx, nh_bytes).unwrap();
assert_eq!(result.1 .0, "192.168.1.1".parse::<Ipv4Addr>().unwrap()); assert_eq!(result.1 .0, "192.168.1.1".parse::<Ipv4Addr>().unwrap());
@ -1060,7 +1068,9 @@ mod tests {
#[test] #[test]
fn test_multi_exit_discriminator_path_attribute() { fn test_multi_exit_discriminator_path_attribute() {
let med_bytes: &[u8] = &[0xca, 0x00, 0x00, 0xbe]; let med_bytes: &[u8] = &[0xca, 0x00, 0x00, 0xbe];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result = MultiExitDiscPathAttribute::from_wire(ctx, med_bytes).unwrap(); let result = MultiExitDiscPathAttribute::from_wire(ctx, med_bytes).unwrap();
assert_eq!(result.1 .0, 3388997822); assert_eq!(result.1 .0, 3388997822);
@ -1072,7 +1082,9 @@ mod tests {
#[test] #[test]
fn test_local_pref_path_attribute() { fn test_local_pref_path_attribute() {
let local_pref_bytes: &[u8] = &[0xca, 0x00, 0x00, 0xbe]; let local_pref_bytes: &[u8] = &[0xca, 0x00, 0x00, 0xbe];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result = LocalPrefPathAttribute::from_wire(ctx, local_pref_bytes).unwrap(); let result = LocalPrefPathAttribute::from_wire(ctx, local_pref_bytes).unwrap();
assert_eq!(result.1 .0, 3388997822); assert_eq!(result.1 .0, 3388997822);
@ -1090,7 +1102,9 @@ mod tests {
0xff, 0xf1, 0x73, 0xfb, 0x0f, 0xa0, 0x73, 0xfb, 0x0f, 0xc8, 0x9a, 0x74, 0x0f, 0xa0, 0xff, 0xf1, 0x73, 0xfb, 0x0f, 0xa0, 0x73, 0xfb, 0x0f, 0xc8, 0x9a, 0x74, 0x0f, 0xa0,
0x9a, 0x74, 0x0f, 0xb4, 0xdf, 0x1e, 0x07, 0xd0, 0xdf, 0x1e, 0x07, 0xe4, 0x9a, 0x74, 0x0f, 0xb4, 0xdf, 0x1e, 0x07, 0xd0, 0xdf, 0x1e, 0x07, 0xe4,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result = CommunitiesPathAttribute::from_wire(ctx, communities_bytes).unwrap(); let result = CommunitiesPathAttribute::from_wire(ctx, communities_bytes).unwrap();
let expected_communities: Vec<(u16, u16)> = vec![ let expected_communities: Vec<(u16, u16)> = vec![
(0, 0x32bd), (0, 0x32bd),
@ -1127,7 +1141,9 @@ mod tests {
0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0xdf, 0x1e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result = LargeCommunitiesPathAttribute::from_wire(ctx, large_community_bytes).unwrap(); let result = LargeCommunitiesPathAttribute::from_wire(ctx, large_community_bytes).unwrap();
assert_eq!(result.1.values.len(), 2); assert_eq!(result.1.values.len(), 2);
assert_eq!(result.1.values[0].global_admin, 57118); assert_eq!(result.1.values[0].global_admin, 57118);
@ -1154,7 +1170,9 @@ mod tests {
0x20, 0x20, 0x01, 0x0d, 0xb8, // NLRI 1 0x20, 0x20, 0x01, 0x0d, 0xb8, // NLRI 1
0x10, 0xfe, 0x80, // NLRI 2 0x10, 0xfe, 0x80, // NLRI 2
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result: (&[u8], MPReachNLRIPathAttribute) = let result: (&[u8], MPReachNLRIPathAttribute) =
MPReachNLRIPathAttribute::from_wire(ctx, mp_reach_bytes).unwrap(); MPReachNLRIPathAttribute::from_wire(ctx, mp_reach_bytes).unwrap();
assert_eq!(result.1.afi, Ipv6); assert_eq!(result.1.afi, Ipv6);
@ -1184,7 +1202,9 @@ mod tests {
0x20, 0x20, 0x01, 0x0d, 0xb8, // NLRI 1 0x20, 0x20, 0x01, 0x0d, 0xb8, // NLRI 1
0x10, 0xfe, 0x80, // NLRI 2 0x10, 0xfe, 0x80, // NLRI 2
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let result: (&[u8], MPUnreachNLRIPathAttribute) = let result: (&[u8], MPUnreachNLRIPathAttribute) =
MPUnreachNLRIPathAttribute::from_wire(ctx, mp_unreach_bytes).unwrap(); MPUnreachNLRIPathAttribute::from_wire(ctx, mp_unreach_bytes).unwrap();
assert_eq!(result.1.afi, Ipv6); assert_eq!(result.1.afi, Ipv6);
@ -1201,7 +1221,7 @@ mod tests {
// Tests the high level dispatching of the path attribute parser // Tests the high level dispatching of the path attribute parser
#[test] #[test]
fn test_path_attribute_parsing<'a>() { fn test_path_attribute_parsing() {
let path_attr_bytes: &[u8] = &[ let path_attr_bytes: &[u8] = &[
0x40, 0x01, 0x01, 0x00, 0x50, 0x02, 0x00, 0x1a, 0x02, 0x06, 0x00, 0x00, 0x9a, 0x74, 0x40, 0x01, 0x01, 0x00, 0x50, 0x02, 0x00, 0x1a, 0x02, 0x06, 0x00, 0x00, 0x9a, 0x74,
0x00, 0x00, 0x62, 0x03, 0x00, 0x00, 0x0b, 0x62, 0x00, 0x00, 0x19, 0x35, 0x00, 0x00, 0x00, 0x00, 0x62, 0x03, 0x00, 0x00, 0x0b, 0x62, 0x00, 0x00, 0x19, 0x35, 0x00, 0x00,
@ -1212,10 +1232,14 @@ mod tests {
0x9a, 0x74, 0x0f, 0xbe, 0x9a, 0x74, 0x0f, 0xbe,
]; ];
let ctx = &ParserContext::new().four_octet_asn(true).nlri_mode(Ipv6); let ctx = &ParserContext::default()
.four_octet_asn(true)
.nlri_mode(Ipv6);
let (buf, res): (_, Vec<PathAttribute>) = let (buf, res): (_, Vec<PathAttribute>) =
nom::multi::many0(|buf: &'a [u8]| PathAttribute::from_wire(ctx, buf))(path_attr_bytes) nom::multi::many0(|buf: &'static [u8]| PathAttribute::from_wire(ctx, buf))(
.unwrap(); path_attr_bytes,
)
.unwrap();
assert_eq!(buf.len(), 0); assert_eq!(buf.len(), 0);
let expected_str = "[OriginPathAttribute(IGP), \ let expected_str = "[OriginPathAttribute(IGP), \
ASPathAttribute(ASPathAttribute { segments: \ ASPathAttribute(ASPathAttribute { segments: \

View File

@ -21,7 +21,7 @@ use nom::IResult;
// ParserContext contains information pertinent to configurations which affect // ParserContext contains information pertinent to configurations which affect
// how message parsing is to be handled. // how message parsing is to be handled.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, Default, PartialEq, Clone)]
pub struct ParserContext { pub struct ParserContext {
// Whether the peer is RFC6793 compliant. // Whether the peer is RFC6793 compliant.
pub four_octet_asn: Option<bool>, pub four_octet_asn: Option<bool>,
@ -30,13 +30,6 @@ pub struct ParserContext {
} }
impl ParserContext { impl ParserContext {
pub fn new() -> ParserContext {
ParserContext {
four_octet_asn: None,
nlri_mode: None,
}
}
pub fn four_octet_asn(mut self, v: bool) -> Self { pub fn four_octet_asn(mut self, v: bool) -> Self {
self.four_octet_asn = Some(v); self.four_octet_asn = Some(v);
self self

View File

@ -81,6 +81,8 @@ message AnnouncementRequest {
string peer_name = 1; string peer_name = 1;
Prefix prefix = 2; Prefix prefix = 2;
repeated string large_communities = 3; repeated string large_communities = 3;
// When set to true inserts the route, when set to false withdraws the route.
bool add = 4;
} }
message AnnouncementResponse {} message AnnouncementResponse {}

View File

@ -0,0 +1,66 @@
use std::str::FromStr;
use std::time::Duration;
use bgp_packet::nlri::NLRI;
use eyre::Result;
use tonic::transport::{Channel, Endpoint, Uri};
use crate::proto::bgp_server_admin_service_client::BgpServerAdminServiceClient;
use crate::proto::{AnnouncementRequest, Prefix};
pub struct Connector {
client: BgpServerAdminServiceClient<Channel>,
}
impl Connector {
pub async fn new(addr: String) -> Result<Self> {
let uri = Uri::from_str(addr.as_str()).unwrap();
let endpoint = Endpoint::from(uri).keep_alive_timeout(Duration::from_secs(10));
let client = BgpServerAdminServiceClient::connect(endpoint).await?;
Ok(Self { client })
}
pub async fn send_announce(&mut self, peer_name: String, prefix: NLRI) -> Result<()> {
let request = AnnouncementRequest {
peer_name,
prefix: Some(Prefix {
ip_prefix: prefix.prefix,
prefix_len: prefix.prefixlen as i32,
address_family: match prefix.afi {
bgp_packet::constants::AddressFamilyIdentifier::Ipv4 => {
crate::proto::AddressFamily::IPv4.into()
}
bgp_packet::constants::AddressFamilyIdentifier::Ipv6 => {
crate::proto::AddressFamily::IPv6.into()
}
},
}),
large_communities: vec![],
add: true,
};
self.client.announce_to_peer(request).await?;
Ok(())
}
pub async fn send_withdraw(&mut self, peer_name: String, prefix: NLRI) -> Result<()> {
let request = AnnouncementRequest {
peer_name,
prefix: Some(Prefix {
ip_prefix: prefix.prefix,
prefix_len: prefix.prefixlen as i32,
address_family: match prefix.afi {
bgp_packet::constants::AddressFamilyIdentifier::Ipv4 => {
crate::proto::AddressFamily::IPv4.into()
}
bgp_packet::constants::AddressFamilyIdentifier::Ipv6 => {
crate::proto::AddressFamily::IPv6.into()
}
},
}),
large_communities: vec![],
add: false,
};
self.client.announce_to_peer(request).await?;
Ok(())
}
}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
pub mod connector;
pub mod fib_state; pub mod fib_state;
pub mod netlink; pub mod netlink;
pub mod southbound_interface; pub mod southbound_interface;

View File

@ -43,24 +43,16 @@ pub trait SouthboundInterface {
/// DummyVerifier is a SouthboundInterface that checks that routes are not added more than /// DummyVerifier is a SouthboundInterface that checks that routes are not added more than
/// once and not removed when there are none. /// once and not removed when there are none.
#[derive(Clone)] #[derive(Clone, Default)]
pub struct DummyVerifier { pub struct DummyVerifier {
route_state: HashMap<NLRI, IpAddr>, route_state: HashMap<NLRI, IpAddr>,
} }
impl std::default::Default for DummyVerifier {
fn default() -> DummyVerifier {
DummyVerifier {
route_state: HashMap::default(),
}
}
}
#[async_trait] #[async_trait]
impl SouthboundInterface for DummyVerifier { impl SouthboundInterface for DummyVerifier {
async fn get_all_routes( async fn get_all_routes(
&mut self, &mut self,
address_family: AddressFamilyIdentifier, _address_family: AddressFamilyIdentifier,
) -> Result<Vec<(NLRI, IpAddr)>> { ) -> Result<Vec<(NLRI, IpAddr)>> {
todo!(); todo!();
} }

View File

@ -81,6 +81,8 @@ message AnnouncementRequest {
string peer_name = 1; string peer_name = 1;
Prefix prefix = 2; Prefix prefix = 2;
repeated string large_communities = 3; repeated string large_communities = 3;
// When set to true inserts the route, when set to false withdraws the route.
bool add = 4;
} }
message AnnouncementResponse {} message AnnouncementResponse {}

View File

@ -20,8 +20,8 @@ use crate::rib_manager::RibManager;
use crate::rib_manager::RibSnapshot; use crate::rib_manager::RibSnapshot;
use crate::rib_manager::RouteManagerCommands; use crate::rib_manager::RouteManagerCommands;
use crate::route_server; use crate::route_server;
use crate::route_server::route_server::bgp_server_admin_service_server::BgpServerAdminServiceServer; use crate::route_server::proto::bgp_server_admin_service_server::BgpServerAdminServiceServer;
use crate::route_server::route_server::route_service_server::RouteServiceServer; use crate::route_server::proto::route_service_server::RouteServiceServer;
use bgp_packet::constants::AddressFamilyIdentifier; use bgp_packet::constants::AddressFamilyIdentifier;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;

View File

@ -19,7 +19,7 @@ use crate::filter_eval::FilterEvaluator;
use crate::path::path_data::PathData; use crate::path::path_data::PathData;
use crate::path::path_set::PathSource; use crate::path::path_set::PathSource;
use crate::rib_manager::RouteManagerCommands; use crate::rib_manager::RouteManagerCommands;
use crate::route_server::route_server::PeerStatus; use crate::route_server::proto::PeerStatus;
use bgp_packet::capabilities::{ use bgp_packet::capabilities::{
BGPCapability, BGPCapabilityTypeValues, BGPCapabilityValue, BGPOpenOptionTypeValues, BGPCapability, BGPCapabilityTypeValues, BGPCapabilityValue, BGPOpenOptionTypeValues,
@ -38,10 +38,10 @@ use bgp_packet::messages::NotificationMessage;
use bgp_packet::messages::OpenMessage; use bgp_packet::messages::OpenMessage;
use bgp_packet::messages::UpdateMessage; use bgp_packet::messages::UpdateMessage;
use bgp_packet::nlri::NLRI; use bgp_packet::nlri::NLRI;
use bgp_packet::path_attributes::ASPathAttribute;
use bgp_packet::path_attributes::NextHopPathAttribute; use bgp_packet::path_attributes::NextHopPathAttribute;
use bgp_packet::path_attributes::OriginPathAttribute; use bgp_packet::path_attributes::OriginPathAttribute;
use bgp_packet::path_attributes::PathAttribute; use bgp_packet::path_attributes::PathAttribute;
use bgp_packet::path_attributes::{ASPathAttribute, MPUnreachNLRIPathAttribute};
use bgp_packet::path_attributes::{ use bgp_packet::path_attributes::{
LargeCommunitiesPathAttribute, LargeCommunitiesPayload, MPReachNLRIPathAttribute, LargeCommunitiesPathAttribute, LargeCommunitiesPayload, MPReachNLRIPathAttribute,
}; };
@ -485,7 +485,7 @@ where
}; };
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
self.codec.lock().await.encode(bgp_message, &mut buf)?; self.codec.lock().await.encode(bgp_message, &mut buf)?;
conn.write(&buf).await?; conn.write_all(&buf).await?;
// Update state // Update state
self.state = BGPState::OpenSent; self.state = BGPState::OpenSent;
@ -530,8 +530,104 @@ where
} }
PeerCommands::Announce(route_update) => match route_update { PeerCommands::Announce(route_update) => match route_update {
RouteUpdate::Announce(announcement) => todo!(), RouteUpdate::Announce(announcement) => {
RouteUpdate::Withdraw(withdrawal) => todo!(), // nexthop is not populated in announcement so we set it ourselves here.
let nexthop = if let Some(stream) = &self.tcp_stream {
stream.local_addr()?
} else {
bail!("Cannot send route announcement since tcp stream is closed");
};
let nexthop_attribute: PathAttribute = match nexthop.ip() {
IpAddr::V4(ipv4_addr) => {
// TODO: In the IPv4 case we also need to add the NLRI to the update msg.
PathAttribute::NextHopPathAttribute(NextHopPathAttribute(ipv4_addr))
}
IpAddr::V6(ipv6_addr) => {
PathAttribute::MPReachNLRIPathAttribute(MPReachNLRIPathAttribute {
afi: AddressFamilyIdentifier::Ipv6,
safi: SubsequentAddressFamilyIdentifier::Unicast,
nexthop: ipv6_addr.octets().to_vec(),
nlris: announcement.0.clone(),
})
}
};
let mut path_attributes = vec![
PathAttribute::OriginPathAttribute(announcement.1.origin),
ASPathAttribute::from_asns(announcement.1.as_path.clone()),
nexthop_attribute,
];
for nlri in &announcement.0 {
if !self.filter_evaluator.evaluate_out(
&mut path_attributes,
&announcement.1.as_path,
&nlri,
) {
bail!("Filter rejected NLRI: {}", nlri);
}
}
let update_message = UpdateMessage {
path_attributes,
withdrawn_nlri: Vec::default(),
announced_nlri: Vec::default(),
};
let bgp_message = BGPMessage {
msg_type: UPDATE_MESSAGE,
payload: BGPSubmessage::UpdateMessage(update_message),
};
let mut buf = BytesMut::new();
self.codec
.lock()
.await
.encode(bgp_message, &mut buf)
.map_err(|e| eyre!("failed to encode BGP message: {}", e))?;
if let Some(stream) = self.tcp_stream.as_mut() {
stream
.write(&buf)
.await
.map_err(|e| eyre!("Failed to write msg to peer: {}", e))?;
}
}
RouteUpdate::Withdraw(withdrawal) => {
// Only IPv6 NLRIs are supported for now.
let path_attributes = vec![PathAttribute::MPUnreachNLRIPathAttribute(
MPUnreachNLRIPathAttribute {
afi: AddressFamilyIdentifier::Ipv6,
safi: SubsequentAddressFamilyIdentifier::Unicast,
nlris: withdrawal.prefixes,
},
)];
let update_message = UpdateMessage {
path_attributes,
withdrawn_nlri: vec![],
announced_nlri: vec![],
};
let bgp_message = BGPMessage {
msg_type: UPDATE_MESSAGE,
payload: BGPSubmessage::UpdateMessage(update_message),
};
let mut buf = BytesMut::new();
self.codec
.lock()
.await
.encode(bgp_message, &mut buf)
.map_err(|e| eyre!("failed to encode BGP message: {}", e))?;
if let Some(stream) = self.tcp_stream.as_mut() {
stream
.write(&buf)
.await
.map_err(|e| eyre!("Failed to write msg to peer: {}", e))?;
}
}
}, },
PeerCommands::MessageFromPeer(msg) => match self.handle_msg(msg).await { PeerCommands::MessageFromPeer(msg) => match self.handle_msg(msg).await {
@ -666,7 +762,7 @@ where
self.codec.lock().await.encode(bgp_msg, &mut buf)?; self.codec.lock().await.encode(bgp_msg, &mut buf)?;
match self.tcp_stream.as_mut() { match self.tcp_stream.as_mut() {
Some(stream) => { Some(stream) => {
stream.write(&buf).await?; stream.write_all(&buf).await?;
} }
None => warn!("Dropped notification message to peer"), None => warn!("Dropped notification message to peer"),
} }
@ -927,7 +1023,7 @@ where
}; };
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
self.codec.lock().await.encode(keepalive, &mut buf)?; self.codec.lock().await.encode(keepalive, &mut buf)?;
conn.write(buf.as_ref()).await?; conn.write_all(buf.as_ref()).await?;
Ok(()) Ok(())
} }
None => Err(std::io::Error::new( None => Err(std::io::Error::new(

View File

@ -12,29 +12,36 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::data_structures::RouteUpdate;
use crate::data_structures::RouteWithdraw;
use crate::path::path_data::PathData;
use crate::path::path_set::PathSet; use crate::path::path_set::PathSet;
use crate::path::path_set::PathSource; use crate::path::path_set::PathSource;
use crate::peer::PeerCommands; use crate::peer::PeerCommands;
use crate::rib_manager::RibSnapshot; use crate::rib_manager::RibSnapshot;
use crate::rib_manager::RouteManagerCommands; use crate::rib_manager::RouteManagerCommands;
use crate::route_server::route_server::bgp_server_admin_service_server::BgpServerAdminService; use crate::route_server::proto::bgp_server_admin_service_server::BgpServerAdminService;
use crate::route_server::route_server::route_service_server::RouteService; use crate::route_server::proto::route_service_server::RouteService;
use crate::route_server::route_server::AddressFamily; use crate::route_server::proto::AddressFamily;
use crate::route_server::route_server::AnnouncementRequest; use crate::route_server::proto::AnnouncementRequest;
use crate::route_server::route_server::AnnouncementResponse; use crate::route_server::proto::AnnouncementResponse;
use crate::route_server::route_server::DumpPathsRequest; use crate::route_server::proto::DumpPathsRequest;
use crate::route_server::route_server::DumpPathsResponse; use crate::route_server::proto::DumpPathsResponse;
use crate::route_server::route_server::Path; use crate::route_server::proto::Path;
use crate::route_server::route_server::Prefix; use crate::route_server::proto::Prefix;
use crate::route_server::route_server::StreamPathsRequest; use crate::route_server::proto::StreamPathsRequest;
use bgp_packet::constants::AddressFamilyIdentifier; use bgp_packet::constants::AddressFamilyIdentifier;
use route_server::PeerStatusRequest; use bgp_packet::nlri::NLRI;
use route_server::PeerStatusResponse; use bgp_packet::path_attributes::OriginPathAttribute;
use chrono::Utc;
use proto::PeerStatusRequest;
use proto::PeerStatusResponse;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::net::Ipv6Addr; use std::net::Ipv6Addr;
use std::sync::Arc;
use tokio::sync::broadcast; use tokio::sync::broadcast;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
@ -44,7 +51,7 @@ use tonic::Response;
use tonic::Status; use tonic::Status;
use tracing::{info, warn}; use tracing::{info, warn};
pub mod route_server { pub mod proto {
tonic::include_proto!("bgpd.grpc"); tonic::include_proto!("bgpd.grpc");
} }
@ -78,11 +85,8 @@ impl RouteServer {
/// Converts a rib_manager::PathSet into the proto format PathSet using the /// Converts a rib_manager::PathSet into the proto format PathSet using the
/// appropriate address family. /// appropriate address family.
fn transform_pathset<A>( fn transform_pathset<A>(mgr_ps: (u64, PathSet<A>), address_family: i32) -> proto::PathSet {
mgr_ps: (u64, PathSet<A>), let mut proto_pathset = proto::PathSet {
address_family: i32,
) -> route_server::PathSet {
let mut proto_pathset = route_server::PathSet {
epoch: mgr_ps.0, epoch: mgr_ps.0,
prefix: Some(Prefix { prefix: Some(Prefix {
ip_prefix: mgr_ps.1.nlri().prefix.clone(), ip_prefix: mgr_ps.1.nlri().prefix.clone(),
@ -151,7 +155,50 @@ impl BgpServerAdminService for RouteServer {
let request = request.get_ref(); let request = request.get_ref();
if let Some(peer) = self.peer_state_machines.get(&request.peer_name) { if let Some(peer) = self.peer_state_machines.get(&request.peer_name) {
info!("Would make announcement to peer: {}", &request.peer_name); let prefix = request
.prefix
.as_ref()
.ok_or(Status::invalid_argument("Missing prefix"))?;
let nlri = NLRI {
afi: AddressFamilyIdentifier::Ipv6,
prefix: prefix.ip_prefix.clone(),
prefixlen: prefix.prefix_len as u8,
};
if request.add {
let path_data = PathData {
origin: OriginPathAttribute::IGP,
nexthop: Vec::default(),
path_source: PathSource::LocallyConfigured,
local_pref: 100,
med: 100,
as_path: vec![210036],
path_attributes: Vec::default(),
learn_time: Utc::now(),
};
if let Err(e) = peer.send(PeerCommands::Announce(RouteUpdate::Announce((
vec![nlri],
Arc::new(path_data),
)))) {
warn!("Failed to send announcement to peer: {}", e);
return Err(Status::internal(format!(
"Failed to send message to PeerStateMachine: {}",
e
)));
}
} else {
let update = PeerCommands::Announce(RouteUpdate::Withdraw(RouteWithdraw {
peer_id: Ipv4Addr::new(0, 0, 0, 0),
prefixes: vec![nlri],
}));
if let Err(e) = peer.send(update) {
warn!("Failed to send withdrawal to peer: {}", e);
return Err(Status::internal(format!(
"Failed to send message to PeerStateMachine: {}",
e
)));
}
}
} else { } else {
return Err(Status::invalid_argument(format!( return Err(Status::invalid_argument(format!(
"No such peer: {}", "No such peer: {}",
@ -189,7 +236,7 @@ impl RouteService for RouteServer {
Ok(result) => { Ok(result) => {
response.epoch = result.epoch; response.epoch = result.epoch;
for pathset in result.routes { for pathset in result.routes {
let mut proto_pathset = route_server::PathSet { let mut proto_pathset = proto::PathSet {
epoch: result.epoch, epoch: result.epoch,
prefix: Some(Prefix { prefix: Some(Prefix {
ip_prefix: pathset.nlri().prefix.clone(), ip_prefix: pathset.nlri().prefix.clone(),
@ -236,7 +283,7 @@ impl RouteService for RouteServer {
Ok(result) => { Ok(result) => {
response.epoch = result.epoch; response.epoch = result.epoch;
for pathset in result.routes { for pathset in result.routes {
let mut proto_pathset = route_server::PathSet { let mut proto_pathset = proto::PathSet {
epoch: result.epoch, epoch: result.epoch,
prefix: Some(Prefix { prefix: Some(Prefix {
ip_prefix: pathset.nlri().prefix.clone(), ip_prefix: pathset.nlri().prefix.clone(),
@ -274,7 +321,7 @@ impl RouteService for RouteServer {
} }
} }
type StreamPathsStream = ReceiverStream<Result<route_server::PathSet, Status>>; type StreamPathsStream = ReceiverStream<Result<proto::PathSet, Status>>;
async fn stream_paths( async fn stream_paths(
&self, &self,

View File

@ -29,8 +29,8 @@ use bgp_packet::messages::BGPSubmessage;
use bgp_packet::traits::ParserContext; use bgp_packet::traits::ParserContext;
use bgp_server::bgp_server::Server; use bgp_server::bgp_server::Server;
use bgp_server::config::{PeerConfig, PrefixAnnouncement, ServerConfig}; use bgp_server::config::{PeerConfig, PrefixAnnouncement, ServerConfig};
use bgp_server::route_server::route_server::bgp_server_admin_service_client::BgpServerAdminServiceClient; use bgp_server::route_server::proto::bgp_server_admin_service_client::BgpServerAdminServiceClient;
use bgp_server::route_server::route_server::PeerStatusRequest; use bgp_server::route_server::proto::PeerStatusRequest;
#[macro_use] #[macro_use]
extern crate serial_test; extern crate serial_test;
@ -151,7 +151,7 @@ async fn test_bgp_listener_known_peer() {
assert!(conn.write_all(open_msg_bytes).is_ok()); assert!(conn.write_all(open_msg_bytes).is_ok());
let mut open_buf = vec![0u8; 65536]; let mut open_buf = vec![0u8; 65536];
conn.read(&mut open_buf).unwrap(); let _ = conn.read(&mut open_buf).unwrap();
let mut codec = bgp_packet::messages::Codec { let mut codec = bgp_packet::messages::Codec {
ctx: ParserContext { ctx: ParserContext {
@ -168,14 +168,14 @@ async fn test_bgp_listener_known_peer() {
match response_open_msg.unwrap().payload { match response_open_msg.unwrap().payload {
BGPSubmessage::OpenMessage(_open) => {} BGPSubmessage::OpenMessage(_open) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
// Check that the server sends a keepalive after the open message. // Check that the server sends a keepalive after the open message.
let mut ka_buf = vec![0u8; 65536]; let mut ka_buf = vec![0u8; 65536];
conn.read(&mut ka_buf).unwrap(); let _ = conn.read(&mut ka_buf).unwrap();
let response_ka_message = codec let response_ka_message = codec
.decode(&mut bytes::BytesMut::from(ka_buf.as_slice())) .decode(&mut bytes::BytesMut::from(ka_buf.as_slice()))
.unwrap(); .unwrap();
@ -183,7 +183,7 @@ async fn test_bgp_listener_known_peer() {
match response_ka_message.unwrap().payload { match response_ka_message.unwrap().payload {
BGPSubmessage::KeepaliveMessage(_ka) => {} BGPSubmessage::KeepaliveMessage(_ka) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
@ -240,7 +240,7 @@ async fn test_bgp_peer_statemachine_outbound_conn() {
assert!(conn.write_all(open_msg_bytes).is_ok()); assert!(conn.write_all(open_msg_bytes).is_ok());
let mut open_buf = vec![0u8; 65536]; let mut open_buf = vec![0u8; 65536];
conn.read(&mut open_buf).unwrap(); let _ = conn.read(&mut open_buf).unwrap();
let mut codec = bgp_packet::messages::Codec { let mut codec = bgp_packet::messages::Codec {
ctx: ParserContext { ctx: ParserContext {
@ -257,14 +257,14 @@ async fn test_bgp_peer_statemachine_outbound_conn() {
match response_open_msg.unwrap().payload { match response_open_msg.unwrap().payload {
BGPSubmessage::OpenMessage(_open) => {} BGPSubmessage::OpenMessage(_open) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
// Check that the server sends a keepalive after the open message. // Check that the server sends a keepalive after the open message.
let mut ka_buf = vec![0u8; 65536]; let mut ka_buf = vec![0u8; 65536];
conn.read(&mut ka_buf).unwrap(); let _ = conn.read(&mut ka_buf).unwrap();
let response_ka_message = codec let response_ka_message = codec
.decode(&mut bytes::BytesMut::from(ka_buf.as_slice())) .decode(&mut bytes::BytesMut::from(ka_buf.as_slice()))
.unwrap(); .unwrap();
@ -272,7 +272,7 @@ async fn test_bgp_peer_statemachine_outbound_conn() {
match response_ka_message.unwrap().payload { match response_ka_message.unwrap().payload {
BGPSubmessage::KeepaliveMessage(_ka) => {} BGPSubmessage::KeepaliveMessage(_ka) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
@ -330,7 +330,7 @@ async fn test_bgp_peer_statemachine_outbound_reconnection() {
assert!(conn.write_all(open_msg_bytes).is_ok()); assert!(conn.write_all(open_msg_bytes).is_ok());
let mut open_buf = vec![0u8; 65536]; let mut open_buf = vec![0u8; 65536];
conn.read(&mut open_buf).unwrap(); let _ = conn.read(&mut open_buf).unwrap();
let mut codec = bgp_packet::messages::Codec { let mut codec = bgp_packet::messages::Codec {
ctx: ParserContext { ctx: ParserContext {
@ -347,14 +347,14 @@ async fn test_bgp_peer_statemachine_outbound_reconnection() {
match response_open_msg.unwrap().payload { match response_open_msg.unwrap().payload {
BGPSubmessage::OpenMessage(_open) => {} BGPSubmessage::OpenMessage(_open) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
// Check that the server sends a keepalive after the open message. // Check that the server sends a keepalive after the open message.
let mut ka_buf = vec![0u8; 65536]; let mut ka_buf = vec![0u8; 65536];
conn.read(&mut ka_buf).unwrap(); let _ = conn.read(&mut ka_buf).unwrap();
let response_ka_message = codec let response_ka_message = codec
.decode(&mut bytes::BytesMut::from(ka_buf.as_slice())) .decode(&mut bytes::BytesMut::from(ka_buf.as_slice()))
.unwrap(); .unwrap();
@ -362,7 +362,7 @@ async fn test_bgp_peer_statemachine_outbound_reconnection() {
match response_ka_message.unwrap().payload { match response_ka_message.unwrap().payload {
BGPSubmessage::KeepaliveMessage(_ka) => {} BGPSubmessage::KeepaliveMessage(_ka) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
@ -383,7 +383,7 @@ async fn test_bgp_peer_statemachine_outbound_reconnection() {
assert!(conn.write_all(open_msg_bytes).is_ok()); assert!(conn.write_all(open_msg_bytes).is_ok());
let mut open_buf = vec![0u8; 65536]; let mut open_buf = vec![0u8; 65536];
conn.read(&mut open_buf).unwrap(); let _ = conn.read(&mut open_buf).unwrap();
let mut codec = bgp_packet::messages::Codec { let mut codec = bgp_packet::messages::Codec {
ctx: ParserContext { ctx: ParserContext {
@ -400,14 +400,14 @@ async fn test_bgp_peer_statemachine_outbound_reconnection() {
match response_open_msg.unwrap().payload { match response_open_msg.unwrap().payload {
BGPSubmessage::OpenMessage(_open) => {} BGPSubmessage::OpenMessage(_open) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
// Check that the server sends a keepalive after the open message. // Check that the server sends a keepalive after the open message.
let mut ka_buf = vec![0u8; 65536]; let mut ka_buf = vec![0u8; 65536];
conn.read(&mut ka_buf).unwrap(); let _ = conn.read(&mut ka_buf).unwrap();
let response_ka_message = codec let response_ka_message = codec
.decode(&mut bytes::BytesMut::from(ka_buf.as_slice())) .decode(&mut bytes::BytesMut::from(ka_buf.as_slice()))
.unwrap(); .unwrap();
@ -415,7 +415,7 @@ async fn test_bgp_peer_statemachine_outbound_reconnection() {
match response_ka_message.unwrap().payload { match response_ka_message.unwrap().payload {
BGPSubmessage::KeepaliveMessage(_ka) => {} BGPSubmessage::KeepaliveMessage(_ka) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
@ -487,7 +487,7 @@ async fn test_bgp_listener_known_peer_inbound_reconnection() {
assert!(conn.write_all(open_msg_bytes).is_ok()); assert!(conn.write_all(open_msg_bytes).is_ok());
let mut open_buf = vec![0u8; 65536]; let mut open_buf = vec![0u8; 65536];
conn.read(&mut open_buf).unwrap(); let _ = conn.read(&mut open_buf).unwrap();
let mut codec = bgp_packet::messages::Codec { let mut codec = bgp_packet::messages::Codec {
ctx: ParserContext { ctx: ParserContext {
@ -504,14 +504,14 @@ async fn test_bgp_listener_known_peer_inbound_reconnection() {
match response_open_msg.unwrap().payload { match response_open_msg.unwrap().payload {
BGPSubmessage::OpenMessage(_open) => {} BGPSubmessage::OpenMessage(_open) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
// Check that the server sends a keepalive after the open message. // Check that the server sends a keepalive after the open message.
let mut ka_buf = vec![0u8; 65536]; let mut ka_buf = vec![0u8; 65536];
conn.read(&mut ka_buf).unwrap(); let _ = conn.read(&mut ka_buf).unwrap();
let response_ka_message = codec let response_ka_message = codec
.decode(&mut bytes::BytesMut::from(ka_buf.as_slice())) .decode(&mut bytes::BytesMut::from(ka_buf.as_slice()))
.unwrap(); .unwrap();
@ -519,7 +519,7 @@ async fn test_bgp_listener_known_peer_inbound_reconnection() {
match response_ka_message.unwrap().payload { match response_ka_message.unwrap().payload {
BGPSubmessage::KeepaliveMessage(_ka) => {} BGPSubmessage::KeepaliveMessage(_ka) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
@ -540,7 +540,7 @@ async fn test_bgp_listener_known_peer_inbound_reconnection() {
let mut open_buf = vec![0u8; 65536]; let mut open_buf = vec![0u8; 65536];
conn.set_read_timeout(Some(Duration::from_secs(3))).unwrap(); conn.set_read_timeout(Some(Duration::from_secs(3))).unwrap();
conn.read(&mut open_buf).unwrap(); let _ = conn.read(&mut open_buf).unwrap();
let mut codec = bgp_packet::messages::Codec { let mut codec = bgp_packet::messages::Codec {
ctx: ParserContext { ctx: ParserContext {
@ -557,7 +557,7 @@ async fn test_bgp_listener_known_peer_inbound_reconnection() {
match response_open_msg.unwrap().payload { match response_open_msg.unwrap().payload {
BGPSubmessage::OpenMessage(_open) => {} BGPSubmessage::OpenMessage(_open) => {}
_ => { _ => {
assert!(false); unreachable!();
} }
} }
@ -607,7 +607,7 @@ async fn test_multi_instance_announce() {
config_b.grpc_addr = Some("[::]:9182".to_owned()); config_b.grpc_addr = Some("[::]:9182".to_owned());
config_b.peers[0].asn = 65535; config_b.peers[0].asn = 65535;
config_b.peers[0].port = Some(9179); config_b.peers[0].port = Some(9179);
config_b.peers[0].name = "config-a-peer".to_owned(); config_b.peers[0].name = "config-a-peer".to_string();
let mut server_a = Server::new(config_a); let mut server_a = Server::new(config_a);
server_a.start(true).await.unwrap(); server_a.start(true).await.unwrap();