// and Vecs are way more memory-effecient in that case.
v4_table: HashMap<V4Addr, Vec<(u32, Route)>>,
v6_table: HashMap<V6Addr, Vec<(u32, Route)>>,
+ max_paths: usize,
+ routes_with_max: usize,
}
impl RoutingTable {
Self {
v4_table: HashMap::with_capacity(900_000),
v6_table: HashMap::with_capacity(100_000),
+ max_paths: 0,
+ routes_with_max: 0,
}
}
($rt: expr, $v: expr, $id: expr) => { {
match $rt.entry($v.into()) {
hash_map::Entry::Occupied(mut entry) => {
+ if entry.get().len() == self.max_paths {
+ self.routes_with_max -= 1;
+ if self.routes_with_max == 0 {
+ self.max_paths = 0;
+ }
+ }
entry.get_mut().retain(|e| e.0 != $id);
if entry.get_mut().is_empty() {
entry.remove();
fn announce(&mut self, prefix: NLRIEncoding, route: Route) {
macro_rules! insert {
($rt: expr, $v: expr, $id: expr) => { {
- let entry = $rt.entry($v.into()).or_insert(Vec::new());
+ let old_max_paths = self.max_paths;
+ let entry = $rt.entry($v.into()).or_insert_with(|| Vec::with_capacity(old_max_paths));
+ let entry_had_max = entry.len() == self.max_paths;
entry.retain(|e| e.0 != $id);
+ if entry_had_max {
+ entry.reserve_exact(1);
+ } else {
+ entry.reserve_exact(cmp::max(self.max_paths, entry.len() + 1) - entry.len());
+ }
entry.push(($id, route));
+ if entry.len() > self.max_paths {
+ self.max_paths = entry.len();
+ self.routes_with_max = 1;
+ } else if entry.len() == self.max_paths {
+ if !entry_had_max { self.routes_with_max += 1; }
+ }
} }
}
match prefix {
}
printer.set_stat(Stat::V4RoutingTableSize(route_table.v4_table.len()));
printer.set_stat(Stat::V6RoutingTableSize(route_table.v6_table.len()));
+ printer.set_stat(Stat::RoutingTablePaths(route_table.max_paths));
},
_ => {}
}
ConnectionClosed,
V4RoutingTableSize(usize),
V6RoutingTableSize(usize),
+ RoutingTablePaths(usize),
}
struct Stats {
connection_count: u64,
v4_table_size: usize,
v6_table_size: usize,
+ paths: usize,
}
pub struct Printer {
connection_count: 0,
v4_table_size: 0,
v6_table_size: 0,
+ paths: 0,
}));
let thread_arc = Arc::clone(&stats);
std::thread::spawn(move || {
}
out.write_all(format!(
- "\nBGP Routing Table: {} v4 paths, {} v6 paths\n",
- stats.v4_table_size, stats.v6_table_size).as_bytes()).expect("stdout broken?");
+ "\nBGP Routing Table: {} v4 nets, {} v6 nets, {} max paths\n",
+ stats.v4_table_size, stats.v6_table_size, stats.paths).as_bytes()).expect("stdout broken?");
out.write_all(b"\nCommands:\n").expect("stdout broken?");
out.write_all(b"q: quit\n").expect("stdout broken?");
Stat::ConnectionClosed => self.stats.lock().unwrap().connection_count -= 1,
Stat::V4RoutingTableSize(c) => self.stats.lock().unwrap().v4_table_size = c,
Stat::V6RoutingTableSize(c) => self.stats.lock().unwrap().v6_table_size = c,
+ Stat::RoutingTablePaths(c) => self.stats.lock().unwrap().paths = c,
}
}
}