// 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 {
} else { None }
}
- fn connect_given_client(addr: SocketAddr, timeout: Duration, printer: &'static Printer, client: Arc<BGPClient>) {
+ fn connect_given_client(remote_asn: u32, addr: SocketAddr, timeout: Duration, printer: &'static Printer, client: Arc<BGPClient>) {
tokio::spawn(Delay::new(Instant::now() + timeout / 4).then(move |_| {
let connect_timeout = Delay::new(Instant::now() + timeout.clone()).then(|_| {
future::err(std::io::Error::new(std::io::ErrorKind::TimedOut, "timeout reached"))
.then(|_| {
future::err(())
}));
+ let peer_asn = if remote_asn > u16::max_value() as u32 { 23456 } else { remote_asn as u16 };
let _ = sender.try_send(Message::Open(Open {
version: 4,
- peer_asn: 23456,
+ peer_asn,
hold_timer: timeout.as_secs() as u16,
- identifier: 0x453b1215, // 69.59.18.21
+ identifier: 0x453b1215, // 69.59.18.21. Note that you never actually need to change this.
parameters: vec![OpenParameter::Capabilities(vec![
OpenCapability::MultiProtocol((AFI::IPV4, SAFI::Unicast)),
OpenCapability::MultiProtocol((AFI::IPV6, SAFI::Unicast)),
- OpenCapability::FourByteASN(397444),
+ OpenCapability::FourByteASN(remote_asn),
OpenCapability::RouteRefresh,
OpenCapability::AddPath(vec![
(AFI::IPV4, SAFI::Unicast, AddPathDirection::ReceivePaths),
}
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));
},
_ => {}
}
})
}).then(move |_| {
if !client_reconn.shutdown.load(Ordering::Relaxed) {
- BGPClient::connect_given_client(addr, timeout, printer, client_reconn);
+ BGPClient::connect_given_client(remote_asn, addr, timeout, printer, client_reconn);
}
future::ok(())
})
);
}
- pub fn new(addr: SocketAddr, timeout: Duration, printer: &'static Printer) -> Arc<BGPClient> {
+ pub fn new(remote_asn: u32, addr: SocketAddr, timeout: Duration, printer: &'static Printer) -> Arc<BGPClient> {
let client = Arc::new(BGPClient {
routes: Mutex::new(RoutingTable::new()),
shutdown: AtomicBool::new(false),
});
- BGPClient::connect_given_client(addr, timeout, printer, Arc::clone(&client));
+ BGPClient::connect_given_client(remote_asn, addr, timeout, printer, Arc::clone(&client));
client
}
}