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