Skip to main content

bgpkit_parser/parser/mrt/messages/
mod.rs

1use crate::error::EncodingError;
2use crate::models::{AsnLength, Bgp4MpEnum, Bgp4MpType, MrtMessage, TableDumpV2Message};
3use bytes::Bytes;
4
5pub(crate) mod bgp4mp;
6pub(crate) mod legacy_bgp;
7pub(crate) mod table_dump;
8pub(crate) mod table_dump_v2;
9
10impl MrtMessage {
11    pub fn encode(&self, sub_type: u16) -> Result<Bytes, EncodingError> {
12        let msg_bytes: Bytes = match self {
13            MrtMessage::TableDumpMessage(m) => m.encode()?,
14            MrtMessage::TableDumpMessageBatch(messages) => {
15                crate::parser::mrt::messages::table_dump::encode_table_dump_batch(
16                    messages, sub_type,
17                )?
18            }
19            MrtMessage::TableDumpV2Message(m) => match m {
20                TableDumpV2Message::PeerIndexTable(p) => p.encode()?,
21                TableDumpV2Message::RibAfi(r) => r.encode()?,
22                TableDumpV2Message::RibGeneric(_) => {
23                    return Err(EncodingError::unencodable(
24                        "MRT TABLE_DUMP_V2 RIB_GENERIC message",
25                        "encoding not implemented",
26                    ));
27                }
28                TableDumpV2Message::GeoPeerTable(g) => g.encode()?,
29            },
30            MrtMessage::Bgp4Mp(m) => {
31                let msg_type = Bgp4MpType::try_from(sub_type).map_err(|_| {
32                    EncodingError::unencodable(
33                        "BGP4MP subtype",
34                        format!("invalid subtype {sub_type}"),
35                    )
36                })?;
37
38                match m {
39                    Bgp4MpEnum::StateChange(msg) => {
40                        let asn_len = match matches!(msg_type, Bgp4MpType::StateChangeAs4) {
41                            true => AsnLength::Bits32,
42                            false => AsnLength::Bits16,
43                        };
44                        msg.encode(asn_len)
45                    }
46                    Bgp4MpEnum::Message(msg) => {
47                        let asn_len = match matches!(
48                            msg_type,
49                            Bgp4MpType::MessageAs4
50                                | Bgp4MpType::MessageAs4Addpath
51                                | Bgp4MpType::MessageLocalAs4Addpath
52                                | Bgp4MpType::MessageAs4Local
53                        ) {
54                            true => AsnLength::Bits32,
55                            false => AsnLength::Bits16,
56                        };
57                        msg.encode(asn_len)?
58                    }
59                }
60            }
61            MrtMessage::LegacyBgp(m) => {
62                crate::parser::mrt::messages::legacy_bgp::encode_legacy_bgp(m, sub_type)?
63            }
64        };
65
66        Ok(msg_bytes)
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::models::{Asn, Bgp4MpMessage, BgpMessage, GeoPeerTable, TableDumpV2Type};
74    use std::net::Ipv4Addr;
75    use std::str::FromStr;
76
77    #[test]
78    fn test_mrt_message_encode_geo_peer_table() {
79        // Test MrtMessage::encode path for GeoPeerTable
80        let geo_table = GeoPeerTable::new(
81            Ipv4Addr::from_str("192.0.2.1").unwrap(),
82            "test-view".to_string(),
83            0.0,
84            0.0,
85        );
86
87        let mrt_message =
88            MrtMessage::TableDumpV2Message(TableDumpV2Message::GeoPeerTable(geo_table));
89
90        let subtype = TableDumpV2Type::GeoPeerTable as u16;
91        let encoded = mrt_message.encode(subtype).unwrap();
92
93        // Should produce some encoded bytes
94        assert!(!encoded.is_empty());
95    }
96
97    #[test]
98    fn test_mrt_message_encode_rejects_invalid_bgp4mp_subtype() {
99        let message = MrtMessage::Bgp4Mp(Bgp4MpEnum::Message(Bgp4MpMessage {
100            msg_type: Bgp4MpType::Message,
101            peer_asn: Asn::new_32bit(65000),
102            local_asn: Asn::new_32bit(65001),
103            interface_index: 0,
104            peer_ip: Ipv4Addr::LOCALHOST.into(),
105            local_ip: Ipv4Addr::UNSPECIFIED.into(),
106            bgp_message: BgpMessage::KeepAlive,
107        }));
108
109        assert_eq!(
110            message.encode(u16::MAX),
111            Err(EncodingError::Unencodable {
112                field: "BGP4MP subtype",
113                reason: format!("invalid subtype {}", u16::MAX),
114            })
115        );
116    }
117}