Refactored client binary.

This commit is contained in:
Rayhaan Jaufeerally
2024-07-07 22:34:00 +02:00
parent 75dbfc319a
commit 9be6b1d59d
34 changed files with 452 additions and 296 deletions

View File

@ -1,50 +0,0 @@
[package]
authors = ["Rayhaan Jaufeerally <rayhaan@rayhaan.ch>"]
edition = "2021"
name = "bgpd"
version = "0.1.0"
[[bin]]
name = "bgp_server"
path = "src/main.rs"
[[bin]]
name = "route_client"
path = "src/route_client/main.rs"
[[bin]]
name = "streamer_cli"
path = "src/streamer_cli/main.rs"
[dependencies]
anyhow = "1.0.71"
async-trait = "0.1.57"
byteorder = "1.4.3"
bytes = "1.*"
clap = { version = "3.2.8", features = ["cargo", "derive"] }
futures = "0.3"
ip_network_table-deps-treebitmap = "0.5.0"
ipnet = "2.3.0"
libc = "0.2.126"
log = "0.4"
netlink = "0.1.1"
netlink-packet-route = "0.19.0"
netlink-packet-utils = "0.5.2"
nom = "7.1"
prost = "0.8"
rtnetlink = "0.14.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.64"
signal-hook = { version = "0.3.17", features = ["extended-siginfo"] }
signal-hook-tokio = "0.3.0"
stderrlog = "0.5.1"
tokio = { version = "1.13.0", features = ["full"] }
tokio-stream = { version = "0.1.7", features = ["net"] }
tokio-util = { version = "0.6.7", features = ["codec"] }
tonic = { version = "0.5", features = ["compression"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
warp = "0.3.5"
[build-dependencies]
tonic-build = { version = "0.5.1", features = ["compression", "prost"] }

View File

@ -1 +0,0 @@
edition = "2018"

View File

@ -1,3 +0,0 @@
pub mod bgp_packet;
pub mod route_client;
pub mod server;

30
bin/Cargo.toml Normal file
View File

@ -0,0 +1,30 @@
[package]
edition.workspace = true
homepage.workspace = true
license.workspace = true
name = "bgpd_bin"
repository.workspace = true
rust-version.workspace = true
version.workspace = true
[dependencies]
bgp_server.workspace = true
clap.workspace = true
eyre.workspace = true
libc.workspace = true
log.workspace = true
route_client.workspace = true
serde_json.workspace = true
signal-hook = { version = "0.3.17", features = ["extended-siginfo"] }
signal-hook-tokio = "0.3.0"
tokio.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
[[bin]]
name = "bgp_server"
path = "src/bgp_server/main.rs"
[[bin]]
name = "client"
path = "src/client/main.rs"

View File

@ -12,8 +12,8 @@
// 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 bgpd::server::bgp_server::Server; use bgp_server::bgp_server::Server;
use bgpd::server::config::ServerConfig; use bgp_server::config::ServerConfig;
use clap::{App, Arg}; use clap::{App, Arg};
use core::sync::atomic::AtomicBool; use core::sync::atomic::AtomicBool;
use libc::SIGUSR1; use libc::SIGUSR1;

77
bin/src/client/main.rs Normal file
View File

@ -0,0 +1,77 @@
use clap::Parser;
use eyre::Result;
use tracing::instrument::WithSubscriber;
use tracing::log::LevelFilter;
use tracing::{info, warn};
use tracing_subscriber::filter;
use tracing_subscriber::prelude::*;
use route_client::netlink::NetlinkConnector;
use route_client::{run_connector_v4, run_connector_v6};
#[derive(Parser)]
#[clap(
author = "Rayhaan Jaufeerally <rayhaan@rayhaan.ch>",
version = "0.1",
about = "Installs routes from a BGP speaker via streaming RPC to the forwarding plane"
)]
struct Cli {
#[clap(long = "route_server")]
route_server: String,
#[clap(long = "rt_table")]
rt_table: Option<u32>,
dry_run: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
tracing_subscriber::fmt().pretty().init();
info!("Starting route client");
let rt_table = match args.rt_table {
Some(table) => table,
None => 201,
};
let v4_joinhandle = {
let server_addr = args.route_server.clone();
tokio::task::spawn(async move {
run_connector_v4::<NetlinkConnector>(
server_addr.clone(),
rt_table,
args.dry_run,
NetlinkConnector::new(Some(rt_table)).await.unwrap(),
)
.await
.unwrap();
})
};
let v6_joinhandle = {
let server_addr = args.route_server.clone();
tokio::task::spawn(async move {
run_connector_v6::<NetlinkConnector>(
server_addr,
rt_table,
args.dry_run,
NetlinkConnector::new(Some(rt_table)).await.unwrap(),
)
.await
.unwrap();
})
};
tokio::select! {
_ = v4_joinhandle => {
warn!("Unexpected exit of IPv4 connector");
},
_ = v6_joinhandle => {
warn!("Unexpected exit of IPv6 connector");
}
}
Ok(())
}

View File

@ -31,7 +31,7 @@ extern crate clap;
#[clap( #[clap(
author = "Rayhaan Jaufeerally <rayhaan@rayhaan.ch>", author = "Rayhaan Jaufeerally <rayhaan@rayhaan.ch>",
version = "0.1", version = "0.1",
about = "A program to install routes from BGP into the Linux control plane" about = "A utility for dumping routes from the bgp_server."
)] )]
struct Cli { struct Cli {
server_address: String, server_address: String,

View File

@ -0,0 +1,19 @@
[package]
name = "bgp_packet"
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
version.workspace = true
[lints]
workspace = true
[dependencies]
byteorder = "1.4.3"
bytes.workspace = true
nom = "7.1"
serde.workspace = true
tokio-util = { version = "0.7.10", features = ["codec"] }

View File

@ -12,12 +12,12 @@
// 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::bgp_packet::constants::AddressFamilyIdentifier; use crate::constants::AddressFamilyIdentifier;
use crate::bgp_packet::constants::SubsequentAddressFamilyIdentifier; use crate::constants::SubsequentAddressFamilyIdentifier;
use crate::bgp_packet::traits::BGPParserError; use crate::traits::BGPParserError;
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::bgp_packet::traits::WritablePacket; use crate::traits::WritablePacket;
use byteorder::{ByteOrder, NetworkEndian}; use byteorder::{ByteOrder, NetworkEndian};
use nom::number::complete::{be_u16, be_u8}; use nom::number::complete::{be_u16, be_u8};
use nom::Err::Failure; use nom::Err::Failure;
@ -694,9 +694,9 @@ mod tests {
use super::ExtendedNextHopEncodingCapability; use super::ExtendedNextHopEncodingCapability;
use super::FourByteASNCapability; use super::FourByteASNCapability;
use super::OpenOption; use super::OpenOption;
use crate::bgp_packet::constants::AddressFamilyIdentifier::Ipv6; use crate::constants::AddressFamilyIdentifier::Ipv6;
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
#[test] #[test]
fn test_four_byte_asn_capability() { fn test_four_byte_asn_capability() {

View File

@ -12,15 +12,15 @@
// 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::bgp_packet::capabilities::OpenOption; use crate::capabilities::OpenOption;
use crate::bgp_packet::constants::AddressFamilyIdentifier; use crate::constants::AddressFamilyIdentifier;
use crate::bgp_packet::constants::SubsequentAddressFamilyIdentifier; use crate::constants::SubsequentAddressFamilyIdentifier;
use crate::bgp_packet::nlri::NLRI; use crate::nlri::NLRI;
use crate::bgp_packet::path_attributes::PathAttribute; use crate::path_attributes::PathAttribute;
use crate::bgp_packet::traits::BGPParserError; use crate::traits::BGPParserError;
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::bgp_packet::traits::WritablePacket; use crate::traits::WritablePacket;
use byteorder::{ByteOrder, NetworkEndian}; use byteorder::{ByteOrder, NetworkEndian};
use bytes::Buf; use bytes::Buf;
use bytes::BufMut; use bytes::BufMut;
@ -545,11 +545,11 @@ impl Display for UpdateMessage {
mod tests { mod tests {
use super::BGPMessage; use super::BGPMessage;
use super::Codec; use super::Codec;
use crate::bgp_packet::constants::AddressFamilyIdentifier::Ipv6; use crate::constants::AddressFamilyIdentifier::Ipv6;
use crate::bgp_packet::messages::AddressFamilyIdentifier::Ipv4; use crate::messages::AddressFamilyIdentifier::Ipv4;
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::bgp_packet::traits::WritablePacket; use crate::traits::WritablePacket;
use bytes::BufMut; use bytes::BufMut;
use tokio_util::codec::{Decoder, Encoder}; use tokio_util::codec::{Decoder, Encoder};

View File

@ -12,11 +12,11 @@
// 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::bgp_packet::constants::AddressFamilyIdentifier; use crate::constants::AddressFamilyIdentifier;
use crate::bgp_packet::traits::BGPParserError; use crate::traits::BGPParserError;
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::bgp_packet::traits::WritablePacket; use crate::traits::WritablePacket;
use nom::bytes::complete::take; use nom::bytes::complete::take;
use nom::number::complete::be_u8; use nom::number::complete::be_u8;
use nom::Err::Failure; use nom::Err::Failure;
@ -254,10 +254,10 @@ mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
use super::NLRI; use super::NLRI;
use crate::bgp_packet::constants::AddressFamilyIdentifier::{Ipv4, Ipv6}; use crate::constants::AddressFamilyIdentifier::{Ipv4, Ipv6};
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::bgp_packet::traits::WritablePacket; use crate::traits::WritablePacket;
#[test] #[test]
fn test_basic_nlri_v6() { fn test_basic_nlri_v6() {

View File

@ -12,13 +12,13 @@
// 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::bgp_packet::constants::AddressFamilyIdentifier; use crate::constants::AddressFamilyIdentifier;
use crate::bgp_packet::constants::SubsequentAddressFamilyIdentifier; use crate::constants::SubsequentAddressFamilyIdentifier;
use crate::bgp_packet::nlri::NLRI; use crate::nlri::NLRI;
use crate::bgp_packet::traits::BGPParserError; use crate::traits::BGPParserError;
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::bgp_packet::traits::WritablePacket; use crate::traits::WritablePacket;
use byteorder::ByteOrder; use byteorder::ByteOrder;
use byteorder::NetworkEndian; use byteorder::NetworkEndian;
use nom::number::complete::{be_u16, be_u32, be_u8}; use nom::number::complete::{be_u16, be_u32, be_u8};
@ -976,11 +976,11 @@ impl fmt::Display for MPUnreachNLRIPathAttribute {
mod tests { mod tests {
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use crate::bgp_packet::constants::AddressFamilyIdentifier::Ipv6; use crate::constants::AddressFamilyIdentifier::Ipv6;
use crate::bgp_packet::constants::SubsequentAddressFamilyIdentifier::Unicast; use crate::constants::SubsequentAddressFamilyIdentifier::Unicast;
use crate::bgp_packet::traits::ParserContext; use crate::traits::ParserContext;
use crate::bgp_packet::traits::ReadablePacket; use crate::traits::ReadablePacket;
use crate::bgp_packet::traits::WritablePacket; use crate::traits::WritablePacket;
use super::ASPathAttribute; use super::ASPathAttribute;
use super::CommunitiesPathAttribute; use super::CommunitiesPathAttribute;

View File

@ -14,7 +14,7 @@
//! Implements high level abstractions for use in the BGP parser. //! Implements high level abstractions for use in the BGP parser.
use crate::bgp_packet::constants::AddressFamilyIdentifier; use crate::constants::AddressFamilyIdentifier;
use nom::error::ErrorKind; use nom::error::ErrorKind;
use nom::error::ParseError; use nom::error::ParseError;
use nom::IResult; use nom::IResult;

View File

@ -0,0 +1,37 @@
[package]
name = "route_client"
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
version.workspace = true
[lints]
workspace = true
[dependencies]
async-trait.workspace = true
bgp_packet.workspace = true
byteorder = "1.4.3"
bytes.workspace = true
eyre.workspace = true
futures.workspace = true
ip_network_table-deps-treebitmap.workspace = true
log.workspace = true
netlink-packet-route.workspace = true
netlink-packet-utils.workspace = true
nom = "7.1"
prost.workspace = true
rtnetlink.workspace = true
serde.workspace = true
tokio-stream = "0.1.14"
tokio-util = { version = "0.7.10", features = ["codec"] }
tokio.workspace = true
tonic.workspace = true
tracing.workspace = true
warp.workspace = true
[build-dependencies]
tonic-build = { version = "0.5.1", features = ["compression", "prost"] }

View File

@ -12,9 +12,6 @@
// 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::bgp_packet::constants::AddressFamilyIdentifier;
use crate::bgp_packet::nlri::NLRI;
use crate::route_client::southbound_interface::SouthboundInterface;
use futures::lock::Mutex; use futures::lock::Mutex;
use ip_network_table_deps_treebitmap::address::Address; use ip_network_table_deps_treebitmap::address::Address;
use ip_network_table_deps_treebitmap::IpLookupTable; use ip_network_table_deps_treebitmap::IpLookupTable;
@ -25,6 +22,11 @@ use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc; use std::sync::Arc;
use tracing::{trace, warn}; use tracing::{trace, warn};
use bgp_packet::constants::AddressFamilyIdentifier;
use bgp_packet::nlri::NLRI;
use crate::southbound_interface::SouthboundInterface;
/// fib_state implements the logic to maintain forwarding routes in the FIB. /// fib_state implements the logic to maintain forwarding routes in the FIB.
/// This for now means the Linux Kernel via Netlink, but in the future can /// This for now means the Linux Kernel via Netlink, but in the future can
/// be extended to include other targets such as OpenFlow or even program /// be extended to include other targets such as OpenFlow or even program

View File

@ -12,9 +12,10 @@
// 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 bgpd::route_client::netlink::NetlinkConnector; pub mod fib_state;
use bgpd::route_client::southbound_interface::SouthboundInterface; pub mod netlink;
use clap::Parser; pub mod southbound_interface;
use log::trace; use log::trace;
use std::convert::TryInto; use std::convert::TryInto;
use std::net::IpAddr; use std::net::IpAddr;
@ -23,27 +24,28 @@ use std::net::Ipv4Addr;
use std::net::Ipv6Addr; use std::net::Ipv6Addr;
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
use tonic::transport::Uri;
use bgpd::bgp_packet::constants::AddressFamilyIdentifier; use bgp_packet::constants::AddressFamilyIdentifier;
use bgpd::bgp_packet::nlri::NLRI; use bgp_packet::nlri::NLRI;
use bgpd::route_client::fib_state::FibState;
use eyre::{anyhow, Result};
use ip_network_table_deps_treebitmap::IpLookupTable; use ip_network_table_deps_treebitmap::IpLookupTable;
use tonic::transport::Endpoint; use tonic::transport::Endpoint;
use tonic::transport::Uri;
use tracing::{info, warn}; use tracing::{info, warn};
use anyhow::{anyhow, Result}; use crate::fib_state::FibState;
use crate::netlink::NetlinkConnector;
use crate::proto::route_service_client::RouteServiceClient; use crate::proto::route_service_client::RouteServiceClient;
use crate::southbound_interface::SouthboundInterface;
pub mod proto { pub mod proto {
tonic::include_proto!("bgpd.grpc"); tonic::include_proto!("bgpd.grpc");
} }
fn vec_to_array<T, const N: usize>(v: Vec<T>) -> Result<[T; N], anyhow::Error> { fn vec_to_array<T, const N: usize>(v: Vec<T>) -> Result<[T; N]> {
v.try_into() v.try_into()
.map_err(|_| anyhow::Error::msg("Wrong size of Vec".to_string())) .map_err(|_| eyre::Error::msg("Wrong size of Vec".to_string()))
} }
/// Temporary hack to select the route to install to the FIB. /// Temporary hack to select the route to install to the FIB.
@ -62,12 +64,12 @@ fn select_best_route(ps: &proto::PathSet) -> Option<proto::Path> {
selected selected
} }
async fn run_connector_v4<S: SouthboundInterface>( pub async fn run_connector_v4<S: SouthboundInterface>(
route_server: String, route_server: String,
rt_table: u32, rt_table: u32,
dry_run: bool, dry_run: bool,
southbound: S, southbound: S,
) -> Result<(), anyhow::Error> { ) -> Result<()> {
// Create netlink socket. // Create netlink socket.
let mut fib_state = FibState::<Ipv4Addr, S> { let mut fib_state = FibState::<Ipv4Addr, S> {
fib: IpLookupTable::new(), fib: IpLookupTable::new(),
@ -132,7 +134,7 @@ async fn run_connector_v4<S: SouthboundInterface>(
unreachable!() unreachable!()
} }
async fn run_connector_v6<S: SouthboundInterface>( pub async fn run_connector_v6<S: SouthboundInterface>(
route_server: String, route_server: String,
rt_table: u32, rt_table: u32,
dry_run: bool, dry_run: bool,
@ -201,72 +203,3 @@ async fn run_connector_v6<S: SouthboundInterface>(
unreachable!() unreachable!()
} }
#[derive(Parser)]
#[clap(
author = "Rayhaan Jaufeerally <rayhaan@rayhaan.ch>",
version = "0.1",
about = "Installs routes from a BGP speaker via streaming RPC to the forwarding plane"
)]
struct Cli {
#[clap(long = "route_server")]
route_server: String,
#[clap(long = "rt_table")]
rt_table: Option<u32>,
dry_run: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Cli::parse();
let _init_log = stderrlog::new()
.verbosity(2) // Shows info level.
.show_module_names(true)
.init();
info!("Starting route client");
let rt_table = match args.rt_table {
Some(table) => table,
None => 201,
};
let v4_joinhandle = {
let server_addr = args.route_server.clone();
tokio::task::spawn(async move {
run_connector_v4::<NetlinkConnector>(
server_addr.clone(),
rt_table,
args.dry_run,
NetlinkConnector::new(Some(rt_table)).await.unwrap(),
)
.await
.unwrap();
})
};
let v6_joinhandle = {
let server_addr = args.route_server.clone();
tokio::task::spawn(async move {
run_connector_v6::<NetlinkConnector>(
server_addr,
rt_table,
args.dry_run,
NetlinkConnector::new(Some(rt_table)).await.unwrap(),
)
.await
.unwrap();
})
};
tokio::select! {
_ = v4_joinhandle => {
warn!("Unexpected exit of IPv4 connector");
},
_ = v6_joinhandle => {
warn!("Unexpected exit of IPv6 connector");
}
}
Ok(())
}

View File

@ -1,6 +1,6 @@
use crate::bgp_packet::{constants::AddressFamilyIdentifier, nlri::NLRI};
use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use bgp_packet::{constants::AddressFamilyIdentifier, nlri::NLRI};
use eyre::{eyre, Result};
use futures::TryStreamExt; use futures::TryStreamExt;
use netlink_packet_route::route::RouteAddress; use netlink_packet_route::route::RouteAddress;
use netlink_packet_route::route::RouteAttribute; use netlink_packet_route::route::RouteAttribute;
@ -38,7 +38,7 @@ impl SouthboundInterface for NetlinkConnector {
let addr: Ipv6Addr = match prefix.try_into()? { let addr: Ipv6Addr = match prefix.try_into()? {
IpAddr::V6(addr) => addr, IpAddr::V6(addr) => addr,
_ => { _ => {
return Err(anyhow::Error::from(std::io::Error::new( return Err(eyre::Error::from(std::io::Error::new(
ErrorKind::InvalidInput, ErrorKind::InvalidInput,
"Got non-IPv6 address from NLRI", "Got non-IPv6 address from NLRI",
))) )))
@ -47,7 +47,7 @@ impl SouthboundInterface for NetlinkConnector {
let gw_addr: Ipv6Addr = match nexthop.clone().try_into()? { let gw_addr: Ipv6Addr = match nexthop.clone().try_into()? {
IpAddr::V6(addr) => addr, IpAddr::V6(addr) => addr,
_ => { _ => {
return Err(anyhow::Error::from(std::io::Error::new( return Err(eyre::Error::from(std::io::Error::new(
ErrorKind::InvalidInput, ErrorKind::InvalidInput,
"Got non-IPv6 gateway for IPv6 NLRI", "Got non-IPv6 gateway for IPv6 NLRI",
))) )))
@ -61,14 +61,14 @@ impl SouthboundInterface for NetlinkConnector {
if let Some(table_id) = self.table { if let Some(table_id) = self.table {
mutation = mutation.table(table_id.try_into().unwrap()); mutation = mutation.table(table_id.try_into().unwrap());
} }
mutation.execute().await.map_err(|e| anyhow::Error::from(e)) mutation.execute().await.map_err(|e| eyre::Error::from(e))
} }
AddressFamilyIdentifier::Ipv4 => { AddressFamilyIdentifier::Ipv4 => {
let prefix_len = prefix.prefixlen; let prefix_len = prefix.prefixlen;
let addr: Ipv4Addr = match prefix.clone().try_into()? { let addr: Ipv4Addr = match prefix.clone().try_into()? {
IpAddr::V4(addr) => addr, IpAddr::V4(addr) => addr,
_ => { _ => {
return Err(anyhow::Error::from(std::io::Error::new( return Err(eyre::Error::from(std::io::Error::new(
ErrorKind::InvalidInput, ErrorKind::InvalidInput,
"Got non-IPv4 address from NLRI", "Got non-IPv4 address from NLRI",
))) )))
@ -77,7 +77,7 @@ impl SouthboundInterface for NetlinkConnector {
let gw_addr = match nexthop.clone().try_into()? { let gw_addr = match nexthop.clone().try_into()? {
IpAddr::V4(addr) => addr, IpAddr::V4(addr) => addr,
_ => { _ => {
return Err(anyhow::Error::from(std::io::Error::new( return Err(eyre::Error::from(std::io::Error::new(
ErrorKind::InvalidInput, ErrorKind::InvalidInput,
"Got non-IPv4 gateway for IPv4 NLRI", "Got non-IPv4 gateway for IPv4 NLRI",
))) )))
@ -91,7 +91,7 @@ impl SouthboundInterface for NetlinkConnector {
if let Some(table_id) = self.table { if let Some(table_id) = self.table {
mutation = mutation.table(table_id.try_into().unwrap()); mutation = mutation.table(table_id.try_into().unwrap());
} }
mutation.execute().await.map_err(|e| anyhow::Error::from(e)) mutation.execute().await.map_err(|e| eyre::Error::from(e))
} }
} }
} }
@ -100,10 +100,10 @@ impl SouthboundInterface for NetlinkConnector {
let rt_handle = self.handle.route(); let rt_handle = self.handle.route();
let destination = match prefix.afi { let destination = match prefix.afi {
AddressFamilyIdentifier::Ipv4 => { AddressFamilyIdentifier::Ipv4 => {
RouteAddress::Inet(prefix.clone().try_into().map_err(|e: String| anyhow!(e))?) RouteAddress::Inet(prefix.clone().try_into().map_err(|e: String| eyre!(e))?)
} }
AddressFamilyIdentifier::Ipv6 => { AddressFamilyIdentifier::Ipv6 => {
RouteAddress::Inet6(prefix.clone().try_into().map_err(|e: String| anyhow!(e))?) RouteAddress::Inet6(prefix.clone().try_into().map_err(|e: String| eyre!(e))?)
} }
}; };
let nexthop = match nexthop { let nexthop = match nexthop {
@ -131,7 +131,7 @@ impl SouthboundInterface for NetlinkConnector {
.del(rt_msg) .del(rt_msg)
.execute() .execute()
.await .await
.map_err(|e| anyhow::Error::from(e)) .map_err(|e| eyre::Error::from(e))
} }
} }

View File

@ -14,11 +14,12 @@
use std::{collections::HashMap, net::IpAddr}; use std::{collections::HashMap, net::IpAddr};
use crate::bgp_packet::{constants::AddressFamilyIdentifier, nlri::NLRI};
use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use eyre::{eyre, Result};
use log::info; use log::info;
use bgp_packet::{constants::AddressFamilyIdentifier, nlri::NLRI};
/// SouthboundInterface provides a uniform API to network forwarding elements /// SouthboundInterface provides a uniform API to network forwarding elements
/// These are devices or targets that perform packet routing and are the end /// These are devices or targets that perform packet routing and are the end
/// consumers of packet routing data. /// consumers of packet routing data.
@ -60,7 +61,7 @@ impl SouthboundInterface for DummyVerifier {
// Check that the route is not already present. // Check that the route is not already present.
match self.route_state.get(&prefix) { match self.route_state.get(&prefix) {
Some(value) => { Some(value) => {
return Err(anyhow!( return Err(eyre!(
"Prefix {} with nexthop {} already contained in route_state! when trying to add {} -> {}", "Prefix {} with nexthop {} already contained in route_state! when trying to add {} -> {}",
prefix, value, prefix, nexthop, prefix, value, prefix, nexthop,
)); ));
@ -80,7 +81,7 @@ impl SouthboundInterface for DummyVerifier {
match self.route_state.remove(&prefix) { match self.route_state.remove(&prefix) {
Some(entry) => { Some(entry) => {
if entry != nexthop { if entry != nexthop {
return Err(anyhow!( return Err(eyre!(
"Removed entry's nexthop did not match: {} vs requested {}", "Removed entry's nexthop did not match: {} vs requested {}",
entry, entry,
nexthop nexthop
@ -88,7 +89,7 @@ impl SouthboundInterface for DummyVerifier {
} }
} }
None => { None => {
return Err(anyhow!( return Err(eyre!(
"Requested removal of route {} that was not in route_state", "Requested removal of route {} that was not in route_state",
prefix prefix
)); ));

31
crates/server/Cargo.toml Normal file
View File

@ -0,0 +1,31 @@
[package]
name = "bgp_server"
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
version.workspace = true
[lints]
workspace = true
[dependencies]
bgp_packet.workspace = true
byteorder = "1.4.3"
bytes.workspace = true
ip_network_table-deps-treebitmap.workspace = true
log.workspace = true
nom = "7.1"
prost.workspace = true
serde.workspace = true
tokio-stream = "0.1.14"
tokio-util = { version = "0.7.10", features = ["codec"] }
tokio.workspace = true
tonic.workspace = true
tracing.workspace = true
warp.workspace = true
[build-dependencies]
tonic-build = { version = "0.5.1", features = ["compression", "prost"] }

View File

@ -12,6 +12,8 @@
// 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 fib_state; fn main() {
pub mod netlink; tonic_build::configure()
pub mod southbound_interface; .compile(&["proto/route_service.proto"], &["proto"])
.unwrap();
}

View File

@ -0,0 +1,83 @@
// Copyright 2021 Rayhaan Jaufeerally.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package bgpd.grpc;
enum AddressFamily {
UNKNOWN = 0;
IPv4 = 1;
IPv6 = 2;
}
message Prefix {
bytes ip_prefix = 1;
int32 prefix_len = 2;
AddressFamily address_family = 3;
}
// Path represents the metadata associated with the route to a particular
// prefix.
message Path {
bytes nexthop = 1;
string peer_name = 2;
uint32 local_pref = 3;
uint32 med = 4;
repeated uint32 as_path = 5;
// TODO: Path attributes. Not yet supported because we need to generate proto
// definitions for all of them.
}
message PathSet {
uint64 epoch = 1;
Prefix prefix = 2;
repeated Path paths = 3;
}
message StreamPathsRequest { AddressFamily address_family = 1; }
message DumpPathsRequest { AddressFamily address_family = 1; };
message DumpPathsResponse {
uint64 epoch = 1;
repeated PathSet path_sets = 2;
};
service RouteService {
// DumpPaths returns all the paths currently in the RIB.
rpc DumpPaths(DumpPathsRequest) returns (DumpPathsResponse);
// StreamPaths dumps the existing routes and starts streaming updates to the
// RIB.
rpc StreamPaths(StreamPathsRequest) returns (stream PathSet);
}
message PeerStatusRequest {}
message PeerStatus {
string peer_name = 1;
string state = 2;
uint64 session_established_time = 3;
uint64 last_messaage_time = 4;
uint64 route_updates_in = 5;
uint64 route_updates_out = 6;
}
message PeerStatusResponse { repeated PeerStatus peer_status = 1; }
// BGPServerAdminService implements an administrative interface to
// view the status and control the operation of this BGP server.
service BGPServerAdminService {
rpc PeerStatus(PeerStatusRequest) returns (PeerStatusResponse);
}

View File

@ -12,16 +12,16 @@
// 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::bgp_packet::constants::AddressFamilyIdentifier; use crate::config::PeerConfig;
use crate::server::config::PeerConfig; use crate::config::ServerConfig;
use crate::server::config::ServerConfig; use crate::peer::PeerCommands;
use crate::server::peer::PeerCommands; use crate::peer::PeerStateMachine;
use crate::server::peer::PeerStateMachine; use crate::rib_manager::RibManager;
use crate::server::rib_manager::RibManager; use crate::rib_manager::RibSnapshot;
use crate::server::rib_manager::RibSnapshot; use crate::rib_manager::RouteManagerCommands;
use crate::server::rib_manager::RouteManagerCommands; use crate::route_server;
use crate::server::route_server; use crate::route_server::route_server::route_service_server::RouteServiceServer;
use crate::server::route_server::route_server::route_service_server::RouteServiceServer; use bgp_packet::constants::AddressFamilyIdentifier;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::net::Ipv6Addr; use std::net::Ipv6Addr;

View File

@ -12,7 +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.
use crate::bgp_packet::constants::{AddressFamilyIdentifier, SubsequentAddressFamilyIdentifier}; use bgp_packet::constants::{AddressFamilyIdentifier, SubsequentAddressFamilyIdentifier};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

View File

@ -12,8 +12,8 @@
// 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::bgp_packet::nlri::NLRI; use bgp_packet::nlri::NLRI;
use crate::bgp_packet::path_attributes::PathAttribute; use bgp_packet::path_attributes::PathAttribute;
use std::time::SystemTime; use std::time::SystemTime;
/// RouteInfo encapsulates information received about a particular BGP route. /// RouteInfo encapsulates information received about a particular BGP route.

View File

@ -12,39 +12,37 @@
// 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::bgp_packet::capabilities::{ use crate::config::PrefixAnnouncement;
use crate::config::{PeerConfig, ServerConfig};
use crate::data_structures::RouteAnnounce;
use crate::data_structures::RouteWithdraw;
use crate::data_structures::{RouteInfo, RouteUpdate};
use crate::rib_manager::RouteManagerCommands;
use bgp_packet::capabilities::{
BGPCapability, BGPCapabilityTypeValues, BGPCapabilityValue, BGPOpenOptionTypeValues, BGPCapability, BGPCapabilityTypeValues, BGPCapabilityValue, BGPOpenOptionTypeValues,
FourByteASNCapability, MultiprotocolCapability, OpenOption, OpenOptionCapabilities, FourByteASNCapability, MultiprotocolCapability, OpenOption, OpenOptionCapabilities,
OpenOptions, OpenOptions,
}; };
use crate::bgp_packet::constants::{ use bgp_packet::constants::{AddressFamilyIdentifier, SubsequentAddressFamilyIdentifier, AS_TRANS};
AddressFamilyIdentifier, SubsequentAddressFamilyIdentifier, AS_TRANS, use bgp_packet::messages::BGPMessage;
}; use bgp_packet::messages::BGPMessageTypeValues;
use crate::bgp_packet::messages::BGPMessage; use bgp_packet::messages::BGPMessageTypeValues::OPEN_MESSAGE;
use crate::bgp_packet::messages::BGPMessageTypeValues; use bgp_packet::messages::BGPMessageTypeValues::UPDATE_MESSAGE;
use crate::bgp_packet::messages::BGPMessageTypeValues::OPEN_MESSAGE; use bgp_packet::messages::BGPSubmessage;
use crate::bgp_packet::messages::BGPMessageTypeValues::UPDATE_MESSAGE; use bgp_packet::messages::Codec;
use crate::bgp_packet::messages::BGPSubmessage; use bgp_packet::messages::KeepaliveMessage;
use crate::bgp_packet::messages::Codec; use bgp_packet::messages::NotificationMessage;
use crate::bgp_packet::messages::KeepaliveMessage; use bgp_packet::messages::OpenMessage;
use crate::bgp_packet::messages::NotificationMessage; use bgp_packet::messages::UpdateMessage;
use crate::bgp_packet::messages::OpenMessage; use bgp_packet::nlri::NLRI;
use crate::bgp_packet::messages::UpdateMessage; use bgp_packet::path_attributes::ASPathAttribute;
use crate::bgp_packet::nlri::NLRI; use bgp_packet::path_attributes::NextHopPathAttribute;
use crate::bgp_packet::path_attributes::ASPathAttribute; use bgp_packet::path_attributes::OriginPathAttribute;
use crate::bgp_packet::path_attributes::NextHopPathAttribute; use bgp_packet::path_attributes::PathAttribute;
use crate::bgp_packet::path_attributes::OriginPathAttribute; use bgp_packet::path_attributes::{
use crate::bgp_packet::path_attributes::PathAttribute;
use crate::bgp_packet::path_attributes::{
LargeCommunitiesPathAttribute, LargeCommunitiesPayload, MPReachNLRIPathAttribute, LargeCommunitiesPathAttribute, LargeCommunitiesPayload, MPReachNLRIPathAttribute,
}; };
use crate::bgp_packet::traits::ParserContext; use bgp_packet::traits::ParserContext;
use crate::server::config::PrefixAnnouncement;
use crate::server::config::{PeerConfig, ServerConfig};
use crate::server::data_structures::RouteAnnounce;
use crate::server::data_structures::RouteWithdraw;
use crate::server::data_structures::{RouteInfo, RouteUpdate};
use crate::server::rib_manager::RouteManagerCommands;
use bytes::BytesMut; use bytes::BytesMut;
use ip_network_table_deps_treebitmap::address::Address; use ip_network_table_deps_treebitmap::address::Address;
use ip_network_table_deps_treebitmap::IpLookupTable; use ip_network_table_deps_treebitmap::IpLookupTable;

View File

@ -12,27 +12,25 @@
// 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::bgp_packet::nlri::NLRI; use crate::config::PeerConfig;
use crate::server::data_structures::RouteAnnounce; use crate::data_structures::RouteAnnounce;
use std::collections::BTreeMap; use crate::data_structures::RouteUpdate;
use crate::peer::PeerCommands;
use crate::bgp_packet::path_attributes::PathAttribute;
use crate::server::config::PeerConfig;
use crate::server::data_structures::RouteUpdate;
use crate::server::peer::PeerCommands;
use tracing::{info, trace, warn};
use std::cmp::Eq; use std::cmp::Eq;
use std::collections::BTreeMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::sync::Mutex;
use bgp_packet::nlri::NLRI;
use bgp_packet::path_attributes::PathAttribute;
use ip_network_table_deps_treebitmap::address::Address; use ip_network_table_deps_treebitmap::address::Address;
use serde::Serialize; use serde::Serialize;
use std::sync::Mutex;
use tokio::sync::broadcast; use tokio::sync::broadcast;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio::sync::oneshot; use tokio::sync::oneshot;
use tracing::{info, trace, warn};
use super::data_structures::RouteWithdraw; use super::data_structures::RouteWithdraw;
@ -227,7 +225,7 @@ where
// reannouncement or fresh announcement. // reannouncement or fresh announcement.
match path_set.paths.get_mut(&update.peer) { match path_set.paths.get_mut(&update.peer) {
// Peer already announced this route before. // Peer already announced this route before.
Some(mut existing) => { Some(existing) => {
trace!( trace!(
"Updating existing path attributes for NLRI: {}/{}", "Updating existing path attributes for NLRI: {}/{}",
addr, addr,
@ -329,12 +327,13 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::bgp_packet::constants::AddressFamilyIdentifier; use crate::rib_manager::RibManager;
use crate::bgp_packet::nlri::NLRI; use crate::rib_manager::RouteAnnounce;
use crate::server::rib_manager::RibManager; use crate::rib_manager::RouteManagerCommands;
use crate::server::rib_manager::RouteAnnounce; use crate::rib_manager::RouteUpdate;
use crate::server::rib_manager::RouteManagerCommands;
use crate::server::rib_manager::RouteUpdate; use bgp_packet::constants::AddressFamilyIdentifier;
use bgp_packet::nlri::NLRI;
use std::net::Ipv6Addr; use std::net::Ipv6Addr;
use std::str::FromStr; use std::str::FromStr;

View File

@ -12,19 +12,19 @@
// 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::bgp_packet::constants::AddressFamilyIdentifier; use crate::peer::PeerCommands;
use crate::server::peer::PeerCommands; use crate::rib_manager;
use crate::server::rib_manager; use crate::rib_manager::RibSnapshot;
use crate::server::rib_manager::RibSnapshot; use crate::rib_manager::RouteManagerCommands;
use crate::server::rib_manager::RouteManagerCommands; use crate::route_server::route_server::route_service_server::RouteService;
use crate::server::route_server::route_server::route_service_server::RouteService; use crate::route_server::route_server::AddressFamily;
use crate::server::route_server::route_server::AddressFamily; use crate::route_server::route_server::DumpPathsRequest;
use crate::server::route_server::route_server::DumpPathsRequest; use crate::route_server::route_server::DumpPathsResponse;
use crate::server::route_server::route_server::DumpPathsResponse; use crate::route_server::route_server::Path;
use crate::server::route_server::route_server::Path; use crate::route_server::route_server::PathSet;
use crate::server::route_server::route_server::PathSet; use crate::route_server::route_server::Prefix;
use crate::server::route_server::route_server::Prefix; use crate::route_server::route_server::StreamPathsRequest;
use crate::server::route_server::route_server::StreamPathsRequest; use bgp_packet::constants::AddressFamilyIdentifier;
use log::warn; use log::warn;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;

View File

@ -1,21 +1,19 @@
[package] [package]
name = "integration_tests"
version = "0.1.0"
authors = ["Rayhaan Jaufeerally <rayhaan@rayhaan.ch>"] authors = ["Rayhaan Jaufeerally <rayhaan@rayhaan.ch>"]
edition = "2018" edition = "2018"
license = "Apache-2.0" license = "Apache-2.0"
name = "integration_tests"
version = "0.1.0"
[dependencies] [dependencies]
bgpd = { path = "../../bgpd" } bgp_packet.workspace = true
bytes = "1.*" bgp_server.workspace = true
tokio = { version = "1.6.1", features = ["full"] } bytes = "1.*"
tokio-util = { version = "0.6.7", features = ["codec"] } libc = "0.2.126"
tracing = "0.1" tokio = { version = "1.6.1", features = ["full"] }
tracing-subscriber = "0.2" tokio-util = { version = "0.7.10", features = ["codec"] }
libc = "0.2.126" tracing = "0.1"
tracing-subscriber = "0.2"
[dev-dependencies] [dev-dependencies]
serial_test = "0.5.1" serial_test = "0.5.1"
[unstable]
thread_id_value = true

View File

@ -12,12 +12,11 @@
// 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 bgpd::bgp_packet; use bgp_packet::constants::{AddressFamilyIdentifier, SubsequentAddressFamilyIdentifier};
use bgpd::bgp_packet::constants::{AddressFamilyIdentifier, SubsequentAddressFamilyIdentifier}; use bgp_packet::messages::BGPSubmessage;
use bgpd::bgp_packet::messages::BGPSubmessage; use bgp_packet::traits::ParserContext;
use bgpd::bgp_packet::traits::ParserContext; use bgp_server::bgp_server::Server;
use bgpd::server::bgp_server::Server; use bgp_server::config::{PeerConfig, ServerConfig};
use bgpd::server::config::{PeerConfig, ServerConfig};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::mem::size_of; use std::mem::size_of;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
@ -27,6 +26,7 @@ use std::net::TcpStream;
use std::net::{IpAddr, SocketAddrV6}; use std::net::{IpAddr, SocketAddrV6};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::time::Duration; use std::time::Duration;
use tokio::io::AsyncReadExt;
use tokio_util::codec::Decoder; use tokio_util::codec::Decoder;
use tracing::info; use tracing::info;