use bgpkit_parser::models::{AttributeValue, ElemType};
use bgpkit_parser::{BgpkitParser, MrtUpdate};
use std::time::Instant;
fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let url = "https://archive.routeviews.org/bgpdata/2024.11/RIBS/rib.20241101.0000.bz2";
log::info!("Parsing MRT file: {}", url);
log::info!("");
log::info!("=== Method 1: UpdateIterator ===");
let start = Instant::now();
let parser = BgpkitParser::new(url).unwrap();
let mut bgp4mp_update_count = 0;
let mut rib_entry_count = 0;
let mut table_dump_v1_count = 0;
let mut update_iter_announced = 0;
let mut update_iter_withdrawn = 0;
for update in parser.into_update_iter() {
match update {
MrtUpdate::Bgp4MpUpdate(update) => {
bgp4mp_update_count += 1;
let announced_count = update.message.announced_prefixes.len();
let mp_reach_count: usize = update
.message
.attributes
.iter()
.filter_map(|attr| {
if let AttributeValue::MpReachNlri(nlri) = attr {
Some(nlri.prefixes.len())
} else {
None
}
})
.sum();
update_iter_announced += announced_count + mp_reach_count;
let withdrawn_count = update.message.withdrawn_prefixes.len();
let mp_unreach_count: usize = update
.message
.attributes
.iter()
.filter_map(|attr| {
if let AttributeValue::MpUnreachNlri(nlri) = attr {
Some(nlri.prefixes.len())
} else {
None
}
})
.sum();
update_iter_withdrawn += withdrawn_count + mp_unreach_count;
}
MrtUpdate::TableDumpV2Entry(entry) => {
rib_entry_count += 1;
update_iter_announced += entry.rib_entries.len();
}
MrtUpdate::TableDumpMessage(_msg) => {
table_dump_v1_count += 1;
update_iter_announced += 1;
}
}
}
let update_iter_duration = start.elapsed();
log::info!("Message counts:");
log::info!(" - BGP4MP UPDATE messages: {}", bgp4mp_update_count);
log::info!(" - TableDumpV2 RIB entries: {}", rib_entry_count);
log::info!(" - TableDump v1 messages: {}", table_dump_v1_count);
log::info!("Total announced prefixes: {}", update_iter_announced);
log::info!("Total withdrawn prefixes: {}", update_iter_withdrawn);
log::info!("Time elapsed: {:?}", update_iter_duration);
log::info!("");
log::info!("=== Method 2: ElemIterator ===");
let start = Instant::now();
let parser = BgpkitParser::new(url).unwrap();
let mut elem_count = 0;
let mut elem_iter_announced = 0;
let mut elem_iter_withdrawn = 0;
for elem in parser.into_elem_iter() {
elem_count += 1;
match elem.elem_type {
ElemType::ANNOUNCE => elem_iter_announced += 1,
ElemType::WITHDRAW => elem_iter_withdrawn += 1,
}
}
let elem_iter_duration = start.elapsed();
log::info!("Total BGP elements: {}", elem_count);
log::info!("Total announced prefixes: {}", elem_iter_announced);
log::info!("Total withdrawn prefixes: {}", elem_iter_withdrawn);
log::info!("Time elapsed: {:?}", elem_iter_duration);
log::info!("");
log::info!("=== Comparison ===");
let announced_match = update_iter_announced == elem_iter_announced;
let withdrawn_match = update_iter_withdrawn == elem_iter_withdrawn;
log::info!(
"Announced prefixes match: {} (UpdateIter: {}, ElemIter: {})",
if announced_match { "✓" } else { "✗" },
update_iter_announced,
elem_iter_announced
);
log::info!(
"Withdrawn prefixes match: {} (UpdateIter: {}, ElemIter: {})",
if withdrawn_match { "✓" } else { "✗" },
update_iter_withdrawn,
elem_iter_withdrawn
);
if update_iter_duration.as_nanos() > 0 {
let speedup = elem_iter_duration.as_secs_f64() / update_iter_duration.as_secs_f64();
log::info!(
"Performance: UpdateIterator is {:.2}x {} than ElemIterator",
if speedup >= 1.0 {
speedup
} else {
1.0 / speedup
},
if speedup >= 1.0 { "faster" } else { "slower" }
);
}
log::info!(" - UpdateIterator: {:?}", update_iter_duration);
log::info!(" - ElemIterator: {:?}", elem_iter_duration);
assert_eq!(
update_iter_announced, elem_iter_announced,
"Announced prefix counts should match!"
);
assert_eq!(
update_iter_withdrawn, elem_iter_withdrawn,
"Withdrawn prefix counts should match!"
);
log::info!("");
log::info!("All counts verified successfully!");
}