From 49bc8f28ebaae8dc3045916fb4de719adb0c8e4d Mon Sep 17 00:00:00 2001 From: Ryan Goodfellow Date: Tue, 9 Jan 2024 21:41:30 -0800 Subject: [PATCH] reticulating splines --- Cargo.lock | 1 + mg-lower/src/lib.rs | 7 +++ mgadm/Cargo.toml | 1 + mgadm/src/main.rs | 9 ++++ mgadm/src/static_routing.rs | 97 +++++++++++++++++++++++++++++++++++++ mgd/src/admin.rs | 1 - mgd/src/bgp_admin.rs | 10 ---- mgd/src/main.rs | 11 +++++ mgd/src/static_admin.rs | 2 +- rdb/src/db.rs | 29 +++++++---- rdb/src/types.rs | 6 +-- 11 files changed, 150 insertions(+), 24 deletions(-) create mode 100644 mgadm/src/static_routing.rs diff --git a/Cargo.lock b/Cargo.lock index b6989433..ac8c9924 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1837,6 +1837,7 @@ dependencies = [ "slog-envlogger", "slog-term", "tabwriter", + "thiserror", "tokio", ] diff --git a/mg-lower/src/lib.rs b/mg-lower/src/lib.rs index 941dffa1..8730df7b 100644 --- a/mg-lower/src/lib.rs +++ b/mg-lower/src/lib.rs @@ -160,6 +160,13 @@ fn handle_change( generation: u64, rt: Arc, ) -> Result { + info!( + log, + "mg-lower: handling rib change generation {} -> {}", + generation, + change.generation + ); + if change.generation > generation + 1 { return initialize(tep, db, log, dpd, ddm, rt.clone()); } diff --git a/mgadm/Cargo.toml b/mgadm/Cargo.toml index 18797021..6f943505 100644 --- a/mgadm/Cargo.toml +++ b/mgadm/Cargo.toml @@ -18,3 +18,4 @@ tabwriter.workspace = true colored.workspace = true humantime.workspace = true serde_json.workspace = true +thiserror.workspace = true diff --git a/mgadm/src/main.rs b/mgadm/src/main.rs index 9b2ee978..a7dbdedd 100644 --- a/mgadm/src/main.rs +++ b/mgadm/src/main.rs @@ -11,6 +11,7 @@ use slog::Logger; use std::net::{IpAddr, SocketAddr}; mod bgp; +mod static_routing; #[derive(Parser, Debug)] #[command(version, about, long_about = None, styles = oxide_cli_style())] @@ -29,8 +30,13 @@ struct Cli { #[derive(Subcommand, Debug)] enum Commands { + /// BGP management commands. #[command(subcommand)] Bgp(bgp::Commands), + + /// Static routing management commands. + #[command(subcommand)] + Static(static_routing::Commands), } #[tokio::main] @@ -45,6 +51,9 @@ async fn main() -> Result<()> { match cli.command { Commands::Bgp(command) => bgp::commands(command, client).await?, + Commands::Static(command) => { + static_routing::commands(command, client).await? + } } Ok(()) } diff --git a/mgadm/src/static_routing.rs b/mgadm/src/static_routing.rs new file mode 100644 index 00000000..6f3f7531 --- /dev/null +++ b/mgadm/src/static_routing.rs @@ -0,0 +1,97 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use anyhow::Result; +use clap::{Args, Subcommand}; +use mg_admin_client::types; +use mg_admin_client::Client; +use rdb::Prefix4; +use std::net::{AddrParseError, Ipv4Addr}; +use std::num::ParseIntError; +use thiserror::Error; + +#[derive(Subcommand, Debug)] +pub enum Commands { + GetV4Routes, + AddV4Route(StaticRoute4), + RemoveV4Routes(StaticRoute4), +} + +#[derive(Debug, Error)] +pub enum Ipv4PrefixParseError { + #[error("expected CIDR representation /")] + Cidr, + + #[error("address parse error: {0}")] + Addr(#[from] AddrParseError), + + #[error("mask parse error: {0}")] + Mask(#[from] ParseIntError), +} + +#[derive(Debug, Args)] +pub struct StaticRoute4 { + pub destination: Ipv4Prefix, + pub nexthop: Ipv4Addr, +} + +#[derive(Debug, Clone, Copy)] +pub struct Ipv4Prefix { + pub addr: Ipv4Addr, + pub len: u8, +} + +impl std::str::FromStr for Ipv4Prefix { + type Err = Ipv4PrefixParseError; + + fn from_str(s: &str) -> Result { + let parts: Vec<&str> = s.split('/').collect(); + if parts.len() < 2 { + return Err(Ipv4PrefixParseError::Cidr); + } + + Ok(Ipv4Prefix { + addr: Ipv4Addr::from_str(parts[0])?, + len: u8::from_str(parts[1])?, + }) + } +} + +pub async fn commands(command: Commands, client: Client) -> Result<()> { + match command { + Commands::GetV4Routes => { + let routes = client.static_list_v4_routes().await?; + println!("{:#?}", routes); + } + Commands::AddV4Route(route) => { + let arg = types::AddStaticRoute4Request { + routes: types::StaticRoute4List { + list: vec![types::StaticRoute4 { + prefix: Prefix4 { + value: route.destination.addr, + length: route.destination.len, + }, + nexthop: route.nexthop, + }], + }, + }; + client.static_add_v4_route(&arg).await?; + } + Commands::RemoveV4Routes(route) => { + let arg = types::AddStaticRoute4Request { + routes: types::StaticRoute4List { + list: vec![types::StaticRoute4 { + prefix: Prefix4 { + value: route.destination.addr, + length: route.destination.len, + }, + nexthop: route.nexthop, + }], + }, + }; + client.static_add_v4_route(&arg).await?; + } + } + Ok(()) +} diff --git a/mgd/src/admin.rs b/mgd/src/admin.rs index 4a9fbe1c..065f8330 100644 --- a/mgd/src/admin.rs +++ b/mgd/src/admin.rs @@ -28,7 +28,6 @@ pub fn start_server( context: Arc, ) -> Result, String> { let sa = SocketAddr::new(addr, port); - let ds_config = ConfigDropshot { bind_address: sa, ..Default::default() diff --git a/mgd/src/bgp_admin.rs b/mgd/src/bgp_admin.rs index 0afccffd..ae51542a 100644 --- a/mgd/src/bgp_admin.rs +++ b/mgd/src/bgp_admin.rs @@ -307,16 +307,6 @@ pub(crate) fn add_router( router.run(); - #[cfg(feature = "default")] - { - let rt = Arc::new(tokio::runtime::Handle::current()); - let log = ctx.log.clone(); - let db = db.clone(); - std::thread::spawn(move || { - mg_lower::run(ctx.tep, db, log, rt); - }); - } - routers.insert(rq.asn, router); db.add_bgp_router( rq.asn, diff --git a/mgd/src/main.rs b/mgd/src/main.rs index 09eb3a43..5e3ffcfa 100644 --- a/mgd/src/main.rs +++ b/mgd/src/main.rs @@ -82,6 +82,17 @@ async fn run(args: RunArgs) { db: db.clone(), }); + #[cfg(feature = "default")] + { + let rt = Arc::new(tokio::runtime::Handle::current()); + let ctx = context.clone(); + let log = log.clone(); + let db = ctx.db.clone(); + std::thread::spawn(move || { + mg_lower::run(ctx.tep, db, log, rt); + }); + } + start_bgp_routers( context.clone(), db.get_bgp_routers() diff --git a/mgd/src/static_admin.rs b/mgd/src/static_admin.rs index 9450cf57..05adf00a 100644 --- a/mgd/src/static_admin.rs +++ b/mgd/src/static_admin.rs @@ -39,7 +39,7 @@ impl From for Route4ImportKey { prefix: val.prefix, nexthop: val.nexthop, id: 0, - priority: 0, + priority: 100, } } } diff --git a/rdb/src/db.rs b/rdb/src/db.rs index 263a0b8e..45ed6337 100644 --- a/rdb/src/db.rs +++ b/rdb/src/db.rs @@ -12,7 +12,7 @@ use crate::error::Error; use crate::types::*; use mg_common::{lock, read_lock, write_lock}; -use slog::{error, Logger}; +use slog::{error, info, Logger}; use std::collections::{HashMap, HashSet}; use std::net::IpAddr; use std::sync::atomic::{AtomicU64, Ordering}; @@ -271,8 +271,18 @@ impl Db { lock!(self.imported).replace(r); let after = self.effective_set_for_prefix4(r.prefix); - if let Some(change_set) = self.import_route_change_set(before, after) { + if let Some(change_set) = self.import_route_change_set(&before, &after) + { + info!( + self.log, + "sending notification for change set {:#?}", change_set, + ); self.notify(change_set); + } else { + info!( + self.log, + "no effective change for {:#?} -> {:#?}", before, after + ); } } @@ -281,7 +291,8 @@ impl Db { lock!(self.imported).remove(&r); let after = self.effective_set_for_prefix4(r.prefix); - if let Some(change_set) = self.import_route_change_set(before, after) { + if let Some(change_set) = self.import_route_change_set(&before, &after) + { self.notify(change_set); } } @@ -342,21 +353,21 @@ impl Db { /// bumping the RIB generation number if there are changes. fn import_route_change_set( &self, - before: HashSet, - after: HashSet, + before: &HashSet, + after: &HashSet, ) -> Option { let added: HashSet = - after.difference(&before).copied().collect(); + after.difference(before).copied().collect(); let removed: HashSet = - before.difference(&after).copied().collect(); - - let gen = self.generation.fetch_add(1, Ordering::SeqCst); + before.difference(after).copied().collect(); if added.is_empty() && removed.is_empty() { return None; } + let gen = self.generation.fetch_add(1, Ordering::SeqCst); + Some(ChangeSet::from_import( ImportChangeSet { added, removed }, gen, diff --git a/rdb/src/types.rs b/rdb/src/types.rs index a7c4b6f2..72bae162 100644 --- a/rdb/src/types.rs +++ b/rdb/src/types.rs @@ -253,7 +253,7 @@ pub struct Policy { pub priority: u16, } -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct ImportChangeSet { pub added: HashSet, pub removed: HashSet, @@ -274,7 +274,7 @@ impl ImportChangeSet { } } -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct OriginChangeSet { pub added: HashSet, pub removed: HashSet, @@ -295,7 +295,7 @@ impl OriginChangeSet { } } -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct ChangeSet { pub generation: u64, pub import: ImportChangeSet,