bgpkit_parser/parser/mrt/messages/
mod.rs1use 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 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 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}