bgpkit_parser/parser/mrt/messages/table_dump_v2/
rib_afi_entries.rsuse crate::bgp::attributes::parse_attributes;
use crate::models::{
Afi, AsnLength, NetworkPrefix, RibAfiEntries, RibEntry, Safi, TableDumpV2Type,
};
use crate::parser::ReadUtils;
use crate::ParserError;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use log::warn;
fn extract_afi_safi_from_rib_type(rib_type: &TableDumpV2Type) -> Result<(Afi, Safi), ParserError> {
let afi: Afi;
let safi: Safi;
match rib_type {
TableDumpV2Type::RibIpv4Unicast | TableDumpV2Type::RibIpv4UnicastAddPath => {
afi = Afi::Ipv4;
safi = Safi::Unicast
}
TableDumpV2Type::RibIpv4Multicast | TableDumpV2Type::RibIpv4MulticastAddPath => {
afi = Afi::Ipv4;
safi = Safi::Multicast
}
TableDumpV2Type::RibIpv6Unicast | TableDumpV2Type::RibIpv6UnicastAddPath => {
afi = Afi::Ipv6;
safi = Safi::Unicast
}
TableDumpV2Type::RibIpv6Multicast | TableDumpV2Type::RibIpv6MulticastAddPath => {
afi = Afi::Ipv6;
safi = Safi::Multicast
}
_ => {
return Err(ParserError::ParseError(format!(
"wrong RIB type for parsing: {:?}",
rib_type
)))
}
};
Ok((afi, safi))
}
pub fn parse_rib_afi_entries(
data: &mut Bytes,
rib_type: TableDumpV2Type,
) -> Result<RibAfiEntries, ParserError> {
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type)?;
let add_path = matches!(
rib_type,
TableDumpV2Type::RibIpv4UnicastAddPath
| TableDumpV2Type::RibIpv4MulticastAddPath
| TableDumpV2Type::RibIpv6UnicastAddPath
| TableDumpV2Type::RibIpv6MulticastAddPath
);
let sequence_number = data.read_u32()?;
let prefix = data.read_nlri_prefix(&afi, false)?;
let entry_count = data.read_u16()?;
let mut rib_entries = Vec::with_capacity((entry_count * 2) as usize);
for _i in 0..entry_count {
let entry = match parse_rib_entry(data, add_path, &afi, &safi, prefix) {
Ok(entry) => entry,
Err(e) => {
warn!("early break due to error {}", e.to_string());
break;
}
};
rib_entries.push(entry);
}
Ok(RibAfiEntries {
rib_type,
sequence_number,
prefix,
rib_entries,
})
}
pub fn parse_rib_entry(
input: &mut Bytes,
add_path: bool,
afi: &Afi,
safi: &Safi,
prefix: NetworkPrefix,
) -> Result<RibEntry, ParserError> {
if input.remaining() < 8 {
return Err(ParserError::TruncatedMsg("truncated msg".to_string()));
}
let peer_index = input.read_u16()?;
let originated_time = input.read_u32()?;
if add_path {
let _path_id = input.read_u32()?;
}
let attribute_length = input.read_u16()? as usize;
input.has_n_remaining(attribute_length)?;
let attr_data_slice = input.split_to(attribute_length);
let attributes = parse_attributes(
attr_data_slice,
&AsnLength::Bits32,
add_path,
Some(*afi),
Some(*safi),
Some(&[prefix]),
)?;
Ok(RibEntry {
peer_index,
originated_time,
attributes,
})
}
impl RibAfiEntries {
pub fn encode(&self) -> Bytes {
let mut bytes = BytesMut::new();
bytes.put_u32(self.sequence_number);
bytes.extend(self.prefix.encode(false));
let entry_count = self.rib_entries.len();
bytes.put_u16(entry_count as u16);
for entry in &self.rib_entries {
bytes.extend(entry.encode());
}
bytes.freeze()
}
}
impl RibEntry {
pub fn encode(&self) -> Bytes {
let mut bytes = BytesMut::new();
bytes.put_u16(self.peer_index);
bytes.put_u32(self.originated_time);
let attr_bytes = self.attributes.encode(false, AsnLength::Bits32);
bytes.put_u16(attr_bytes.len() as u16);
bytes.extend(attr_bytes);
bytes.freeze()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_afi_safi_from_rib_type() {
let rib_type = TableDumpV2Type::RibIpv4Unicast;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv4);
assert_eq!(safi, Safi::Unicast);
let rib_type = TableDumpV2Type::RibIpv4Multicast;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv4);
assert_eq!(safi, Safi::Multicast);
let rib_type = TableDumpV2Type::RibIpv6Unicast;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv6);
assert_eq!(safi, Safi::Unicast);
let rib_type = TableDumpV2Type::RibIpv6Multicast;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv6);
assert_eq!(safi, Safi::Multicast);
let rib_type = TableDumpV2Type::RibIpv4UnicastAddPath;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv4);
assert_eq!(safi, Safi::Unicast);
let rib_type = TableDumpV2Type::RibIpv4MulticastAddPath;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv4);
assert_eq!(safi, Safi::Multicast);
let rib_type = TableDumpV2Type::RibIpv6UnicastAddPath;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv6);
assert_eq!(safi, Safi::Unicast);
let rib_type = TableDumpV2Type::RibIpv6MulticastAddPath;
let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
assert_eq!(afi, Afi::Ipv6);
assert_eq!(safi, Safi::Multicast);
let rib_type = TableDumpV2Type::RibGeneric;
let res = extract_afi_safi_from_rib_type(&rib_type);
assert!(res.is_err());
}
}