This commit is contained in:
@ -8,6 +8,7 @@ rust-version.workspace = true
|
|||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bgp_packet.workspace = true
|
||||||
bgp_server.workspace = true
|
bgp_server.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
eyre.workspace = true
|
eyre.workspace = true
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use bgp_packet::constants::AddressFamilyIdentifier;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use eyre::{bail, Result};
|
use eyre::{bail, Result};
|
||||||
use route_client::southbound_interface::{DummyVerifier, SouthboundInterface};
|
use route_client::southbound_interface::{DummyVerifier, SouthboundInterface};
|
||||||
@ -21,6 +22,8 @@ struct Cli {
|
|||||||
route_server: String,
|
route_server: String,
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Option<Commands>,
|
command: Option<Commands>,
|
||||||
|
#[clap(long = "af")]
|
||||||
|
address_family: Vec<AddressFamilyIdentifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
|
|||||||
@ -14,6 +14,7 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
bytes.workspace = true
|
bytes.workspace = true
|
||||||
|
clap.workspace = true
|
||||||
eyre.workspace = true
|
eyre.workspace = true
|
||||||
netlink-packet-route.workspace = true
|
netlink-packet-route.workspace = true
|
||||||
nom = "7.1"
|
nom = "7.1"
|
||||||
|
|||||||
@ -21,7 +21,7 @@ use super::traits::{BGPParserError, ParserContext, ReadablePacket};
|
|||||||
|
|
||||||
// Address Family Identifiers as per
|
// Address Family Identifiers as per
|
||||||
// https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml
|
// https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml
|
||||||
#[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize, Deserialize, Hash)]
|
#[derive(Eq, PartialEq, Debug, Copy, Clone, Serialize, Deserialize, Hash, clap::ValueEnum)]
|
||||||
pub enum AddressFamilyIdentifier {
|
pub enum AddressFamilyIdentifier {
|
||||||
Ipv4,
|
Ipv4,
|
||||||
Ipv6,
|
Ipv6,
|
||||||
|
|||||||
@ -30,6 +30,7 @@ tokio-stream = "0.1.14"
|
|||||||
tokio-util = { version = "0.7.10", features = ["codec"] }
|
tokio-util = { version = "0.7.10", features = ["codec"] }
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
tonic.workspace = true
|
tonic.workspace = true
|
||||||
|
tracing-subscriber.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
warp.workspace = true
|
warp.workspace = true
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ use std::net::Ipv6Addr;
|
|||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tracing::{trace, warn};
|
use tracing::{info, trace, warn};
|
||||||
|
|
||||||
use bgp_packet::constants::AddressFamilyIdentifier;
|
use bgp_packet::constants::AddressFamilyIdentifier;
|
||||||
use bgp_packet::nlri::NLRI;
|
use bgp_packet::nlri::NLRI;
|
||||||
@ -88,6 +88,7 @@ where
|
|||||||
/// route_add requests updating the nexthop to a particular path if it is not already
|
/// route_add requests updating the nexthop to a particular path if it is not already
|
||||||
/// the best path.
|
/// the best path.
|
||||||
pub async fn route_add(&mut self, nlri: &NLRI, nexthop: IpAddr) -> Result<(), String> {
|
pub async fn route_add(&mut self, nlri: &NLRI, nexthop: IpAddr) -> Result<(), String> {
|
||||||
|
info!(af = ?self.af, %nlri, %nexthop);
|
||||||
// Lookup the path in the Fib, there are three possible outcomes:
|
// Lookup the path in the Fib, there are three possible outcomes:
|
||||||
// 1. The route is not yet known, we add it to the FibState and inject it into the kernel,
|
// 1. The route is not yet known, we add it to the FibState and inject it into the kernel,
|
||||||
// 2. The route is known and has a prior nexthop that needs to be updated
|
// 2. The route is known and has a prior nexthop that needs to be updated
|
||||||
@ -156,7 +157,7 @@ where
|
|||||||
let addr: A = nlri.clone().try_into()?;
|
let addr: A = nlri.clone().try_into()?;
|
||||||
self.fib
|
self.fib
|
||||||
.insert(addr, nlri.prefixlen.into(), Arc::new(Mutex::new(entry)));
|
.insert(addr, nlri.prefixlen.into(), Arc::new(Mutex::new(entry)));
|
||||||
trace!(nlri = %nlri, "Added to kernel");
|
trace!(af = ?self.af, nlri = %nlri, nexthop = %nexthop, "Added to kernel");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -168,6 +169,7 @@ where
|
|||||||
if let Some(entry_wrapped) = self.fib.exact_match(prefix_addr, nlri.prefixlen.into()) {
|
if let Some(entry_wrapped) = self.fib.exact_match(prefix_addr, nlri.prefixlen.into()) {
|
||||||
{
|
{
|
||||||
let entry = entry_wrapped.lock().await;
|
let entry = entry_wrapped.lock().await;
|
||||||
|
info!(%nlri, %prefix_addr, %entry.nexthop, "route_del");
|
||||||
if let Err(e) = self.southbound.route_del(nlri.clone(), entry.nexthop).await {
|
if let Err(e) = self.southbound.route_del(nlri.clone(), entry.nexthop).await {
|
||||||
warn!(
|
warn!(
|
||||||
"Failed to apply route mutation to remove NLRI: {}, error: {}",
|
"Failed to apply route mutation to remove NLRI: {}, error: {}",
|
||||||
@ -183,3 +185,52 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{
|
||||||
|
net::{IpAddr, Ipv6Addr},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bgp_packet::nlri::NLRI;
|
||||||
|
use eyre::{eyre, Result};
|
||||||
|
use ip_network_table_deps_treebitmap::IpLookupTable;
|
||||||
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||||
|
|
||||||
|
use crate::southbound_interface::DummyVerifier;
|
||||||
|
|
||||||
|
use super::FibState;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_double_add() -> Result<()> {
|
||||||
|
tracing_subscriber::registry()
|
||||||
|
.with(tracing_subscriber::fmt::layer())
|
||||||
|
.with(EnvFilter::from_default_env())
|
||||||
|
.init();
|
||||||
|
|
||||||
|
let southbound = DummyVerifier::default();
|
||||||
|
let mut fib_state: FibState<Ipv6Addr, DummyVerifier> = FibState {
|
||||||
|
fib: IpLookupTable::default(),
|
||||||
|
southbound,
|
||||||
|
af: bgp_packet::constants::AddressFamilyIdentifier::Ipv6,
|
||||||
|
};
|
||||||
|
|
||||||
|
let nlri = NLRI::try_from("2602:feda:b8d::/48").map_err(|e| eyre!(e))?;
|
||||||
|
let nexthop = IpAddr::V6(Ipv6Addr::from_str("2001:db8:cafe::1")?);
|
||||||
|
|
||||||
|
fib_state
|
||||||
|
.route_add(&nlri, nexthop)
|
||||||
|
.await
|
||||||
|
.map_err(|e| eyre!(e))?;
|
||||||
|
|
||||||
|
let nexthop_2 = IpAddr::V6(Ipv6Addr::from_str("2001:db8:babe::1")?);
|
||||||
|
|
||||||
|
fib_state
|
||||||
|
.route_add(&nlri, nexthop_2)
|
||||||
|
.await
|
||||||
|
.map_err(|e| eyre!(e))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user