Skip to main content

bgpkit_parser/parser/mrt/messages/table_dump_v2/
mod.rs

1mod geo_peer_table;
2mod peer_index_table;
3mod rib_afi_entries;
4
5use crate::error::ParserError;
6use crate::messages::table_dump_v2::geo_peer_table::parse_geo_peer_table;
7use crate::messages::table_dump_v2::peer_index_table::parse_peer_index_table;
8use crate::messages::table_dump_v2::rib_afi_entries::parse_rib_afi_entries;
9pub(crate) use crate::messages::table_dump_v2::rib_afi_entries::rib_entry_min_len;
10use crate::models::*;
11#[cfg(test)]
12use bytes::BufMut;
13use bytes::Bytes;
14use std::convert::TryFrom;
15
16/// Parse TABLE_DUMP V2 format MRT message.
17///
18/// RFC: <https://www.rfc-editor.org/rfc/rfc6396#section-4.3>
19///
20/// Subtypes include
21/// 1. PEER_INDEX_TABLE
22/// 2. RIB_IPV4_UNICAST
23/// 3. RIB_IPV4_MULTICAST
24/// 4. RIB_IPV6_UNICAST
25/// 5. RIB_IPV6_MULTICAST
26/// 6. RIB_GENERIC
27/// 7. GEO_PEER_TABLE
28///
29pub fn parse_table_dump_v2_message(
30    sub_type: u16,
31    mut input: Bytes,
32) -> Result<TableDumpV2Message, ParserError> {
33    let v2_type: TableDumpV2Type = TableDumpV2Type::try_from(sub_type)?;
34
35    let msg: TableDumpV2Message = match v2_type {
36        TableDumpV2Type::PeerIndexTable => {
37            // peer index table type
38            TableDumpV2Message::PeerIndexTable(parse_peer_index_table(&mut input)?)
39        }
40        TableDumpV2Type::RibIpv4Unicast
41        | TableDumpV2Type::RibIpv4Multicast
42        | TableDumpV2Type::RibIpv6Unicast
43        | TableDumpV2Type::RibIpv6Multicast
44        | TableDumpV2Type::RibIpv4UnicastAddPath
45        | TableDumpV2Type::RibIpv4MulticastAddPath
46        | TableDumpV2Type::RibIpv6UnicastAddPath
47        | TableDumpV2Type::RibIpv6MulticastAddPath => {
48            TableDumpV2Message::RibAfi(parse_rib_afi_entries(&mut input, v2_type)?)
49        }
50        TableDumpV2Type::RibGeneric | TableDumpV2Type::RibGenericAddPath => {
51            return Err(ParserError::Unsupported(
52                "TableDumpV2 RibGeneric is not currently supported".to_string(),
53            ))
54        }
55        TableDumpV2Type::GeoPeerTable => {
56            TableDumpV2Message::GeoPeerTable(parse_geo_peer_table(&mut input)?)
57        }
58    };
59
60    Ok(msg)
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_unsupported_type() {
69        // Test RibGeneric (subtype 6) - should be unsupported
70        let msg = parse_table_dump_v2_message(6, Bytes::new());
71        assert!(msg.is_err());
72
73        // Test RibGenericAddPath (subtype 13) - should be unsupported
74        let msg = parse_table_dump_v2_message(13, Bytes::new());
75        assert!(msg.is_err());
76    }
77
78    #[test]
79    fn test_geo_peer_table_parsing() {
80        // Test GeoPeerTable (subtype 7) parsing path
81        // Create minimal valid GeoPeerTable bytes
82        let mut bytes = bytes::BytesMut::new();
83
84        // Collector BGP ID (4 bytes)
85        bytes.put_u32(0x01020304);
86
87        // View name length (2 bytes) and name (0 bytes for empty string)
88        bytes.put_u16(0);
89
90        // Collector coordinates (8 bytes)
91        bytes.put_f32(0.0); // latitude
92        bytes.put_f32(0.0); // longitude
93
94        // Peer count (2 bytes) - 0 peers
95        bytes.put_u16(0);
96
97        let bytes = bytes.freeze();
98        let result = parse_table_dump_v2_message(7, bytes);
99        assert!(result.is_ok());
100
101        if let Ok(TableDumpV2Message::GeoPeerTable(geo_table)) = result {
102            assert_eq!(geo_table.view_name, "");
103            assert_eq!(geo_table.geo_peers.len(), 0);
104        } else {
105            panic!("Expected GeoPeerTable message");
106        }
107    }
108}