-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from bgpkit/feature/as2rel
add bgpkit as2rel dataset access
- Loading branch information
Showing
3 changed files
with
234 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
//! AS-level relationship generated by BGPKIT | ||
//! | ||
//! Raw data files available at: <https://data.bgpkit.com/as2rel/> | ||
//! * [as2rel-latest.json.bz2](https://data.bgpkit.com/as2rel/as2rel-latest.json.bz2): latest combined | ||
//! * [as2rel-v4-latest.json.bz2](https://data.bgpkit.com/as2rel/as2rel-v4-latest.json.bz2): latest IPv4 relationship | ||
//! * [as2rel-v6-latest.json.bz2](https://data.bgpkit.com/as2rel/as2rel-v6-latest.json.bz2): latest IPv6 relationship | ||
use anyhow::Result; | ||
use serde::{Deserialize, Serialize}; | ||
use std::collections::HashMap; | ||
|
||
#[allow(dead_code)] | ||
const AS2REL_LATEST_COMBINED: &str = "https://data.bgpkit.com/as2rel/as2rel-latest.json.bz2"; | ||
|
||
const AS2REL_LATEST_V4: &str = "https://data.bgpkit.com/as2rel/as2rel-v4-latest.json.bz2"; | ||
const AS2REL_LATEST_V6: &str = "https://data.bgpkit.com/as2rel/as2rel-v6-latest.json.bz2"; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
pub enum AsRelationship { | ||
ProviderCustomer, | ||
CustomerProvider, | ||
PeerPeer, | ||
} | ||
|
||
impl Serialize for AsRelationship { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: serde::Serializer, | ||
{ | ||
match self { | ||
AsRelationship::ProviderCustomer => serializer.serialize_str("pc"), | ||
AsRelationship::CustomerProvider => serializer.serialize_str("cp"), | ||
AsRelationship::PeerPeer => serializer.serialize_str("pp"), | ||
} | ||
} | ||
} | ||
|
||
impl<'de> Deserialize<'de> for AsRelationship { | ||
fn deserialize<D>(deserializer: D) -> Result<AsRelationship, D::Error> | ||
where | ||
D: serde::Deserializer<'de>, | ||
{ | ||
let s = i8::deserialize(deserializer)?; | ||
match s { | ||
-1 | 1 => Ok(AsRelationship::ProviderCustomer), | ||
0 => Ok(AsRelationship::PeerPeer), | ||
_ => Err(serde::de::Error::custom("invalid relationship")), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)] | ||
struct As2relEntry { | ||
asn1: u32, | ||
asn2: u32, | ||
paths_count: u32, | ||
peers_count: u32, | ||
rel: AsRelationship, | ||
} | ||
|
||
impl As2relEntry { | ||
fn reverse(&self) -> Self { | ||
Self { | ||
asn1: self.asn2, | ||
asn2: self.asn1, | ||
paths_count: self.paths_count, | ||
peers_count: self.peers_count, | ||
rel: match self.rel { | ||
AsRelationship::ProviderCustomer => AsRelationship::CustomerProvider, | ||
AsRelationship::CustomerProvider => AsRelationship::ProviderCustomer, | ||
AsRelationship::PeerPeer => AsRelationship::PeerPeer, | ||
}, | ||
} | ||
} | ||
} | ||
|
||
pub struct As2relBgpkit { | ||
v4_rels_map: HashMap<(u32, u32), As2relEntry>, | ||
v6_rels_map: HashMap<(u32, u32), As2relEntry>, | ||
v4_max_peer_count: u32, | ||
v6_max_peer_count: u32, | ||
} | ||
|
||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)] | ||
pub struct As2relBgpkitData { | ||
pub rel: AsRelationship, | ||
pub peers_count: u32, | ||
pub max_peer_count: u32, | ||
} | ||
|
||
impl As2relBgpkit { | ||
pub fn new() -> Result<Self> { | ||
let v4_rels = parse_as2rel_data(AS2REL_LATEST_V4)?; | ||
let v6_rels = parse_as2rel_data(AS2REL_LATEST_V6)?; | ||
let mut v4_rels_map = HashMap::new(); | ||
let mut v6_rels_map = HashMap::new(); | ||
let mut v4_max_peer_count = 0; | ||
let mut v6_max_peer_count = 0; | ||
for entry in v4_rels { | ||
v4_rels_map.insert((entry.asn1, entry.asn2), entry); | ||
v4_rels_map.insert((entry.asn2, entry.asn1), entry.reverse()); | ||
|
||
v4_max_peer_count = v4_max_peer_count.max(entry.peers_count); | ||
} | ||
for entry in v6_rels { | ||
v6_rels_map.insert((entry.asn1, entry.asn2), entry); | ||
v6_rels_map.insert((entry.asn2, entry.asn1), entry.reverse()); | ||
v6_max_peer_count = v6_max_peer_count.max(entry.peers_count); | ||
} | ||
Ok(Self { | ||
v4_rels_map, | ||
v6_rels_map, | ||
v4_max_peer_count, | ||
v6_max_peer_count, | ||
}) | ||
} | ||
|
||
pub fn lookup_pair( | ||
&self, | ||
asn1: u32, | ||
asn2: u32, | ||
) -> (Option<As2relBgpkitData>, Option<As2relBgpkitData>) { | ||
let v4_entry = self.v4_rels_map.get(&(asn1, asn2)); | ||
let v6_entry = self.v6_rels_map.get(&(asn1, asn2)); | ||
|
||
( | ||
v4_entry.map(|entry| As2relBgpkitData { | ||
rel: entry.rel, | ||
peers_count: entry.peers_count, | ||
max_peer_count: self.v4_max_peer_count, | ||
}), | ||
v6_entry.map(|entry| As2relBgpkitData { | ||
rel: entry.rel, | ||
peers_count: entry.peers_count, | ||
max_peer_count: self.v6_max_peer_count, | ||
}), | ||
) | ||
} | ||
} | ||
|
||
fn parse_as2rel_data(url: &str) -> Result<Vec<As2relEntry>> { | ||
let data: Vec<As2relEntry> = oneio::read_json_struct(url)?; | ||
Ok(data) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
|
||
#[test] | ||
fn test_loading_raw_data() { | ||
let bgpkit = crate::as2rel::As2relBgpkit::new().unwrap(); | ||
let (v4_data, v6_data) = bgpkit.lookup_pair(400644, 54825); | ||
assert!(v4_data.is_none()); | ||
assert!(v6_data.is_some()); | ||
assert_eq!( | ||
v6_data.unwrap().rel, | ||
crate::as2rel::AsRelationship::CustomerProvider | ||
); | ||
dbg!(v6_data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters