Assorted cleanups.
Some checks are pending
Rust / build (push) Waiting to run

This commit is contained in:
Rayhaan Jaufeerally
2024-08-08 20:46:41 +00:00
parent 0cd3a120d0
commit 5130177bf4
8 changed files with 61 additions and 45 deletions

View File

@ -39,7 +39,7 @@ anyhow = "1.0.71"
async-trait = "0.1.80" async-trait = "0.1.80"
byteorder = "1.4.3" byteorder = "1.4.3"
bytes = "1.*" bytes = "1.*"
clap = { version = "3.2.8", features = ["cargo", "derive"] } clap = { version = "4.5.11", features = ["cargo", "derive"] }
eyre = "0.6.12" eyre = "0.6.12"
futures = "0.3" futures = "0.3"
ip_network_table-deps-treebitmap = "0.5.0" ip_network_table-deps-treebitmap = "0.5.0"

View File

@ -14,7 +14,7 @@
use bgp_server::bgp_server::Server; use bgp_server::bgp_server::Server;
use bgp_server::config::ServerConfig; use bgp_server::config::ServerConfig;
use clap::{App, Arg}; use clap::Parser;
use core::sync::atomic::AtomicBool; use core::sync::atomic::AtomicBool;
use libc::SIGUSR1; use libc::SIGUSR1;
use signal_hook::consts::signal::*; use signal_hook::consts::signal::*;
@ -28,6 +28,13 @@ use std::process::exit;
use std::sync::Arc; use std::sync::Arc;
use tracing::info; use tracing::info;
#[derive(Parser)]
#[command(author = "Rayhaan Jaufeerally <rayhaan@rayhaan.ch>", version = "0.1")]
struct Cli {
#[arg(short = 'c', long = "config")]
config_path: String,
}
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let subscriber = tracing_subscriber::fmt(); let subscriber = tracing_subscriber::fmt();
@ -40,16 +47,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
let argv_matches = App::new("bgpd") let args = Cli::parse();
.author("Rayhaan Jaufeerally <rayhaan@rayhaan.ch>")
.version("0.1")
.about("net-control-plane BGP daemon")
.arg(Arg::with_name("config").takes_value(true))
.get_matches();
info!("Starting BGP Daemon!"); info!("Starting BGP Daemon!");
let config_file = File::open(argv_matches.value_of("config").unwrap_or("config.json")).unwrap(); let config_file = File::open(args.config_path).unwrap();
let reader = BufReader::new(config_file); let reader = BufReader::new(config_file);
let server_config: ServerConfig = serde_json::from_reader(reader).unwrap(); let server_config: ServerConfig = serde_json::from_reader(reader).unwrap();

View File

@ -1,5 +1,6 @@
use clap::Parser; use clap::{Parser, Subcommand};
use eyre::Result; use eyre::{bail, Result};
use route_client::southbound_interface::{DummyVerifier, SouthboundInterface};
use tracing::{info, warn}; use tracing::{info, warn};
use route_client::netlink::NetlinkConnector; use route_client::netlink::NetlinkConnector;
@ -12,11 +13,25 @@ use route_client::{run_connector_v4, run_connector_v6};
about = "Installs routes from a BGP speaker via streaming RPC to the forwarding plane" about = "Installs routes from a BGP speaker via streaming RPC to the forwarding plane"
)] )]
struct Cli { struct Cli {
/// route_server is the gRPC endpoint to connect to for streaming routes from.
#[clap(long = "route_server")] #[clap(long = "route_server")]
route_server: String, route_server: String,
#[clap(long = "rt_table")] #[clap(subcommand)]
rt_table: Option<u32>, command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
/// InstallKernel installs the routes received into the kernel routing table.
InstallKernel {
#[arg(default_value_t = 201)]
rt_table: u32,
#[arg(default_value_t = false)]
dry_run: bool, dry_run: bool,
},
/// Verify performs consistency checks on the inbound stream of routes to ensure
/// that there are no spurious removals or duplicate entries.
Verify,
} }
#[tokio::main] #[tokio::main]
@ -27,34 +42,40 @@ async fn main() -> Result<()> {
info!("Starting route client"); info!("Starting route client");
let rt_table = match args.rt_table { match args.command {
Some(table) => table, Some(Commands::InstallKernel { rt_table, dry_run }) => {
None => 201, let southbound = NetlinkConnector::new(Some(rt_table)).await?;
run_connector::<NetlinkConnector>(args.route_server, dry_run, southbound).await
}
Some(Commands::Verify) => {
let southbound = DummyVerifier::default();
run_connector::<DummyVerifier>(args.route_server, false, southbound).await
}
None => bail!("A subcommand must be specified."),
}; };
Ok(())
}
async fn run_connector<S: SouthboundInterface + Clone + Send + Sync + 'static>(
server_addr: String,
dry_run: bool,
southbound: S,
) {
let v4_joinhandle = { let v4_joinhandle = {
let server_addr = args.route_server.clone(); let server_addr = server_addr.clone();
let southbound = southbound.clone();
tokio::task::spawn(async move { tokio::task::spawn(async move {
run_connector_v4::<NetlinkConnector>( run_connector_v4::<S>(server_addr.clone(), dry_run, southbound)
server_addr.clone(),
rt_table,
args.dry_run,
NetlinkConnector::new(Some(rt_table)).await.unwrap(),
)
.await .await
.unwrap(); .unwrap();
}) })
}; };
let v6_joinhandle = { let v6_joinhandle = {
let server_addr = args.route_server.clone(); let server_addr = server_addr.clone();
tokio::task::spawn(async move { tokio::task::spawn(async move {
run_connector_v6::<NetlinkConnector>( run_connector_v6::<S>(server_addr, dry_run, southbound)
server_addr,
rt_table,
args.dry_run,
NetlinkConnector::new(Some(rt_table)).await.unwrap(),
)
.await .await
.unwrap(); .unwrap();
}) })
@ -68,6 +89,4 @@ async fn main() -> Result<()> {
warn!("Unexpected exit of IPv6 connector"); warn!("Unexpected exit of IPv6 connector");
} }
} }
Ok(())
} }

View File

@ -41,12 +41,11 @@ pub struct FibState<A: Address, S: SouthboundInterface> {
pub fib: IpLookupTable<A, Arc<Mutex<FibEntry>>>, pub fib: IpLookupTable<A, Arc<Mutex<FibEntry>>>,
pub southbound: S, pub southbound: S,
pub af: AddressFamilyIdentifier, pub af: AddressFamilyIdentifier,
pub table: u32,
} }
impl<A: Address, S: SouthboundInterface> std::fmt::Debug for FibState<A, S> { impl<A: Address, S: SouthboundInterface> std::fmt::Debug for FibState<A, S> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "FibState af: {:?}, table: {}", self.af, self.table) write!(f, "FibState af: {:?}", self.af)
} }
} }

View File

@ -65,7 +65,6 @@ fn select_best_route(ps: &proto::PathSet) -> Option<proto::Path> {
pub async fn run_connector_v4<S: SouthboundInterface>( pub async fn run_connector_v4<S: SouthboundInterface>(
route_server: String, route_server: String,
rt_table: u32,
dry_run: bool, dry_run: bool,
southbound: S, southbound: S,
) -> Result<()> { ) -> Result<()> {
@ -74,7 +73,6 @@ pub async fn run_connector_v4<S: SouthboundInterface>(
fib: IpLookupTable::new(), fib: IpLookupTable::new(),
southbound, southbound,
af: AddressFamilyIdentifier::Ipv4, af: AddressFamilyIdentifier::Ipv4,
table: rt_table,
}; };
let uri = Uri::from_str(route_server.as_str()).unwrap(); let uri = Uri::from_str(route_server.as_str()).unwrap();
@ -135,7 +133,6 @@ pub async fn run_connector_v4<S: SouthboundInterface>(
pub async fn run_connector_v6<S: SouthboundInterface>( pub async fn run_connector_v6<S: SouthboundInterface>(
route_server: String, route_server: String,
rt_table: u32,
dry_run: bool, dry_run: bool,
southbound: S, southbound: S,
) -> Result<()> { ) -> Result<()> {
@ -143,7 +140,6 @@ pub async fn run_connector_v6<S: SouthboundInterface>(
fib: IpLookupTable::new(), fib: IpLookupTable::new(),
southbound, southbound,
af: AddressFamilyIdentifier::Ipv6, af: AddressFamilyIdentifier::Ipv6,
table: rt_table,
}; };
let uri = Uri::from_str(route_server.as_str()).unwrap(); let uri = Uri::from_str(route_server.as_str()).unwrap();

View File

@ -17,6 +17,7 @@ use super::southbound_interface::SouthboundInterface;
/// NetlinkConnector implements methods to read/update Linux networking stuff including /// NetlinkConnector implements methods to read/update Linux networking stuff including
/// routes and link level info. /// routes and link level info.
#[derive(Clone)]
pub struct NetlinkConnector { pub struct NetlinkConnector {
handle: rtnetlink::Handle, handle: rtnetlink::Handle,
table: Option<u32>, table: Option<u32>,

View File

@ -38,6 +38,7 @@ 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)]
pub struct DummyVerifier { pub struct DummyVerifier {
route_state: HashMap<NLRI, IpAddr>, route_state: HashMap<NLRI, IpAddr>,
} }

View File

@ -568,7 +568,6 @@ where
self.hold_timer_expired().await?; self.hold_timer_expired().await?;
} }
PeerTimerEvent::KeepaliveTimerExpire() => { PeerTimerEvent::KeepaliveTimerExpire() => {
trace!("Keepalive timer expired");
self.send_keepalive().await?; self.send_keepalive().await?;
} }
}, },
@ -867,7 +866,6 @@ where
/// keepalive message. /// keepalive message.
/// Takes a lock on the peer object. /// Takes a lock on the peer object.
async fn send_keepalive(&mut self) -> Result<(), std::io::Error> { async fn send_keepalive(&mut self) -> Result<(), std::io::Error> {
info!("Sending keepalive");
match self.tcp_stream.as_mut() { match self.tcp_stream.as_mut() {
Some(conn) => { Some(conn) => {
let keepalive = BGPMessage { let keepalive = BGPMessage {