X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fbgp_client.rs;h=e38cffb97208d6fdb5a85c239d6ba7a95b4b0735;hb=9a19c37ba4266971a4fd9503ac4fded63061a41b;hp=04be1360c930cc6d01f65bd57f5f44340c4777a9;hpb=7aaa26debb3bb875c5e49fbd39dec642cd535f88;p=dnsseed-rust diff --git a/src/bgp_client.rs b/src/bgp_client.rs index 04be136..e38cffb 100644 --- a/src/bgp_client.rs +++ b/src/bgp_client.rs @@ -22,15 +22,18 @@ use futures::sync::mpsc; use crate::printer::{Printer, Stat}; use crate::timeout_stream::TimeoutStream; -struct Route { - path: Vec, +const PATH_SUFFIX_LEN: usize = 3; +#[derive(Clone)] +struct Route { // 32 bytes + path_suffix: [u32; PATH_SUFFIX_LEN], + path_len: u32, pref: u32, med: u32, } struct RoutingTable { - v4_table: HashMap<(Ipv4Addr, u8), HashMap>>, - v6_table: HashMap<(Ipv6Addr, u8), HashMap>>, + v4_table: HashMap<(Ipv4Addr, u8), HashMap>, + v6_table: HashMap<(Ipv6Addr, u8), HashMap>, } impl RoutingTable { @@ -41,7 +44,7 @@ impl RoutingTable { } } - fn get_route_attrs(&self, ip: IpAddr) -> Vec> { + fn get_route_attrs(&self, ip: IpAddr) -> (u8, Vec<&Route>) { macro_rules! lookup_res { ($addrty: ty, $addr: expr, $table: expr, $addr_bits: expr) => { { //TODO: Optimize this (probably means making the tables btrees)! @@ -54,11 +57,11 @@ impl RoutingTable { let lookup_addr = <$addrty>::from(lookup); if let Some(routes) = $table.get(&(lookup_addr, $addr_bits - i as u8)).map(|hm| hm.values()) { if routes.len() > 0 { - return routes.map(|x| Arc::clone(&x)).collect(); + return ($addr_bits - i as u8, routes.collect()); } } } - vec![] + (0, vec![]) } } } match ip { @@ -87,7 +90,7 @@ impl RoutingTable { }; } - fn announce(&mut self, prefix: NLRIEncoding, route: Arc) { + fn announce(&mut self, prefix: NLRIEncoding, route: Route) { match prefix { NLRIEncoding::IP(p) => { let (ip, len) = <(IpAddr, u8)>::from(&p); @@ -175,25 +178,48 @@ pub struct BGPClient { } impl BGPClient { pub fn get_asn(&self, addr: IpAddr) -> u32 { - let mut path_vecs = self.routes.lock().unwrap().get_route_attrs(addr).clone(); + let lock = self.routes.lock().unwrap(); + let mut path_vecs = lock.get_route_attrs(addr).1; if path_vecs.is_empty() { return 0; } path_vecs.sort_unstable_by(|path_a, path_b| { path_a.pref.cmp(&path_b.pref) - .then(path_b.path.len().cmp(&path_a.path.len())) + .then(path_b.path_len.cmp(&path_a.path_len)) .then(path_b.med.cmp(&path_a.med)) }); let primary_route = path_vecs.pop().unwrap(); - 'asn_candidates: for asn in primary_route.path.iter().rev() { + 'asn_candidates: for asn in primary_route.path_suffix.iter().rev() { + if *asn == 0 { continue 'asn_candidates; } for secondary_route in path_vecs.iter() { - if !secondary_route.path.contains(asn) { + if !secondary_route.path_suffix.contains(asn) { continue 'asn_candidates; } } return *asn; } - *primary_route.path.last().unwrap_or(&0) + + for asn in primary_route.path_suffix.iter().rev() { + if *asn != 0 { + return *asn; + } + } + 0 + } + + pub fn get_path(&self, addr: IpAddr) -> (u8, [u32; PATH_SUFFIX_LEN]) { + let lock = self.routes.lock().unwrap(); + let (prefixlen, mut path_vecs) = lock.get_route_attrs(addr); + if path_vecs.is_empty() { return (0, [0; PATH_SUFFIX_LEN]); } + + path_vecs.sort_unstable_by(|path_a, path_b| { + path_a.pref.cmp(&path_b.pref) + .then(path_b.path_len.cmp(&path_a.path_len)) + .then(path_b.med.cmp(&path_a.med)) + }); + + let primary_route = path_vecs.pop().unwrap(); + (prefixlen, primary_route.path_suffix) } pub fn disconnect(&self) { @@ -215,15 +241,25 @@ impl BGPClient { } } if let Some(mut aspath) = as4_path.or(as_path) { - let mut path = Vec::new(); + let mut pathvec = Vec::new(); for seg in aspath.segments.drain(..) { match seg { - Segment::AS_SEQUENCE(mut asn) => path.append(&mut asn), + Segment::AS_SEQUENCE(mut asn) => pathvec.append(&mut asn), Segment::AS_SET(_) => {}, // Ignore sets for now, they're not that common anyway } } + let path_len = pathvec.len() as u32; + pathvec.dedup_by(|a, b| (*a).eq(b)); // Drop prepends, cause we don't care in this case + + let mut path_suffix = [0; PATH_SUFFIX_LEN]; + for (idx, asn) in pathvec.iter().rev().enumerate() { + path_suffix[PATH_SUFFIX_LEN - idx - 1] = *asn; + if idx == PATH_SUFFIX_LEN - 1 { break; } + } + return Some(Route { - path: path.clone(), + path_suffix, + path_len, pref, med, }) @@ -283,9 +319,8 @@ impl BGPClient { route_table.withdraw(r); } if let Some(path) = Self::map_attrs(upd.attributes) { - let path_arc = Arc::new(path); for r in upd.announced_routes { - route_table.announce(r, Arc::clone(&path_arc)); + route_table.announce(r, path.clone()); } } printer.set_stat(Stat::V4RoutingTableSize(route_table.v4_table.len()));