From e9413e51f1bdfb593f24baa73ed35b59e12b2f36 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Mon, 11 Mar 2024 17:22:39 -0300 Subject: [PATCH] bgp, routing: convert RIB to use prefix-trie For storing routing tables, we need a data structure where we can do longest-prefix matches, a requirement for things like BGP nexthop resolution, policy application, among others. For that, we'll be using the prefix-trie crate, which has excellent performance numbers, an ergonomic API similar to std::collections, and no additional dependencies. The transition to prefix-trie is straightforward due to its API's similarity to BTreeMap. Signed-off-by: Renato Westphal --- Cargo.toml | 1 + holo-bgp/Cargo.toml | 1 + holo-bgp/src/af.rs | 2 +- holo-bgp/src/neighbor.rs | 2 +- holo-bgp/src/northbound/state.rs | 8 ++++---- holo-bgp/src/rib.rs | 3 ++- holo-routing/Cargo.toml | 1 + holo-routing/src/rib.rs | 5 +++-- 8 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 36a50168..9405162b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ netlink-sys = "0.8" num-derive = "0.3" num-traits = "0.2" pickledb = "0.5" +prefix-trie = { version = "0.3", features = ["ipnetwork"] } prost = "0.12" rand = "0.8.5" rtnetlink = "0.13" diff --git a/holo-bgp/Cargo.toml b/holo-bgp/Cargo.toml index 566c34f7..b318ab6d 100644 --- a/holo-bgp/Cargo.toml +++ b/holo-bgp/Cargo.toml @@ -19,6 +19,7 @@ itertools.workspace = true libc.workspace = true num-derive.workspace = true num-traits.workspace = true +prefix-trie.workspace = true rand.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/holo-bgp/src/af.rs b/holo-bgp/src/af.rs index 003ab143..9c50ec83 100644 --- a/holo-bgp/src/af.rs +++ b/holo-bgp/src/af.rs @@ -33,7 +33,7 @@ pub trait AddressFamily: Sized { // The type of IP address used by this address family. type IpAddr: IpAddrKind; // The type of IP network used by this address family. - type IpNetwork: IpNetworkKind; + type IpNetwork: IpNetworkKind + prefix_trie::Prefix; // Get the routing table for this address family from the provided // `RoutingTables`. diff --git a/holo-bgp/src/neighbor.rs b/holo-bgp/src/neighbor.rs index af96b069..aa45fb50 100644 --- a/holo-bgp/src/neighbor.rs +++ b/holo-bgp/src/neighbor.rs @@ -913,7 +913,7 @@ impl Neighbor { A: AddressFamily, { let table = A::table(&mut rib.tables); - for (prefix, dest) in &mut table.prefixes { + for (prefix, dest) in table.prefixes.iter_mut() { dest.adj_rib.remove(&self.remote_addr); table.queued_prefixes.insert(*prefix); } diff --git a/holo-bgp/src/northbound/state.rs b/holo-bgp/src/northbound/state.rs index 7b916aa6..9657d8cc 100644 --- a/holo-bgp/src/northbound/state.rs +++ b/holo-bgp/src/northbound/state.rs @@ -91,8 +91,8 @@ fn load_callbacks() -> Callbacks { let afi_safi = args.list_entry.as_global_afi_safi().unwrap(); let state = instance.state.as_ref().unwrap(); let total = match afi_safi { - AfiSafi::Ipv4Unicast => state.rib.tables.ipv4_unicast.prefixes.len(), - AfiSafi::Ipv6Unicast => state.rib.tables.ipv6_unicast.prefixes.len(), + AfiSafi::Ipv4Unicast => state.rib.tables.ipv4_unicast.prefixes.iter().count(), + AfiSafi::Ipv6Unicast => state.rib.tables.ipv6_unicast.prefixes.iter().count(), }; Some(total as u32) }) @@ -134,8 +134,8 @@ fn load_callbacks() -> Callbacks { .path(bgp::global::statistics::total_prefixes::PATH) .get_element_u32(|instance, _args| { if let Some(state) = &instance.state { - let total = state.rib.tables.ipv4_unicast.prefixes.len() - + state.rib.tables.ipv6_unicast.prefixes.len(); + let total = state.rib.tables.ipv4_unicast.prefixes.iter().count() + + state.rib.tables.ipv6_unicast.prefixes.iter().count(); Some(total as u32) } else { None diff --git a/holo-bgp/src/rib.rs b/holo-bgp/src/rib.rs index 0c72459e..2a3bbc92 100644 --- a/holo-bgp/src/rib.rs +++ b/holo-bgp/src/rib.rs @@ -13,6 +13,7 @@ use std::time::Instant; use holo_utils::bgp::RouteType; use holo_utils::ibus::IbusSender; use holo_utils::protocol::Protocol; +use prefix_trie::map::PrefixMap; use serde::{Deserialize, Serialize}; use crate::af::{AddressFamily, Ipv4Unicast, Ipv6Unicast}; @@ -46,7 +47,7 @@ pub struct RoutingTables { #[derive(Debug)] pub struct RoutingTable { - pub prefixes: BTreeMap, + pub prefixes: PrefixMap, pub queued_prefixes: BTreeSet, } diff --git a/holo-routing/Cargo.toml b/holo-routing/Cargo.toml index cca0e03f..25b6beb5 100644 --- a/holo-routing/Cargo.toml +++ b/holo-routing/Cargo.toml @@ -16,6 +16,7 @@ derive-new.workspace = true enum-as-inner.workspace = true futures.workspace = true ipnetwork.workspace = true +prefix-trie.workspace = true rtnetlink.workspace = true tokio.workspace = true tracing.workspace = true diff --git a/holo-routing/src/rib.rs b/holo-routing/src/rib.rs index 2caeb905..770b3997 100644 --- a/holo-routing/src/rib.rs +++ b/holo-routing/src/rib.rs @@ -20,14 +20,15 @@ use holo_utils::southbound::{ }; use holo_utils::{UnboundedReceiver, UnboundedSender}; use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; +use prefix_trie::map::PrefixMap; use tokio::sync::mpsc; use crate::{ibus, netlink}; #[derive(Debug)] pub struct Rib { - pub ipv4: BTreeMap>, - pub ipv6: BTreeMap>, + pub ipv4: PrefixMap>, + pub ipv6: PrefixMap>, pub mpls: BTreeMap, pub ip_update_queue: BTreeSet, pub mpls_update_queue: BTreeSet