bgpkit_parser/parser/mrt/messages/
table_dump.rs1use crate::error::*;
2use crate::models::*;
3use crate::parser::bgp::attributes::parse_attributes;
4use crate::parser::ReadUtils;
5use bytes::{BufMut, Bytes, BytesMut};
6use ipnet::IpNet;
7use std::net::IpAddr;
8
9pub fn parse_table_dump_message(
39 sub_type: u16,
40 mut data: Bytes,
41) -> Result<TableDumpMessage, ParserError> {
42 let afi = match sub_type {
50 1 => Afi::Ipv4,
51 2 => Afi::Ipv6,
52 _ => {
53 return Err(ParserError::ParseError(format!(
54 "Invalid subtype found for TABLE_DUMP (V1) message: {sub_type}"
55 )))
56 }
57 };
58
59 let view_number = data.read_u16()?;
72 let sequence_number = data.read_u16()?;
73 let prefix = match &afi {
74 Afi::Ipv4 => data.read_ipv4_prefix().map(ipnet::IpNet::V4),
75 Afi::Ipv6 => data.read_ipv6_prefix().map(ipnet::IpNet::V6),
76 Afi::LinkState => {
77 Ok(ipnet::IpNet::V4(
80 ipnet::Ipv4Net::new(std::net::Ipv4Addr::new(0, 0, 0, 0), 0).unwrap(),
81 ))
82 }
83 }?;
84
85 let status = data.read_u8()?;
86 let time = data.read_u32()? as u64;
87
88 let peer_ip: IpAddr = data.read_address(&afi)?;
89 let peer_asn = Asn::new_16bit(data.read_u16()?);
90
91 let attribute_length = data.read_u16()? as usize;
92
93 data.has_n_remaining(attribute_length)?;
99 let attr_data_slice = data.split_to(attribute_length);
100
101 let mut attributes =
103 parse_attributes(attr_data_slice, &AsnLength::Bits16, false, None, None, None)?;
104
105 attributes.check_mandatory_attributes(true, afi == Afi::Ipv4);
107
108 Ok(TableDumpMessage {
109 view_number,
110 sequence_number,
111 prefix: NetworkPrefix::new(prefix, None),
112 status,
113 originated_time: time,
114 peer_ip,
115 peer_asn,
116 attributes,
117 })
118}
119
120impl TableDumpMessage {
121 pub fn encode(&self) -> Bytes {
122 let mut bytes = BytesMut::new();
123 bytes.put_u16(self.view_number);
124 bytes.put_u16(self.sequence_number);
125 match &self.prefix.prefix {
126 IpNet::V4(p) => {
127 bytes.put_u32(p.addr().into());
128 bytes.put_u8(p.prefix_len());
129 }
130 IpNet::V6(p) => {
131 bytes.put_u128(p.addr().into());
132 bytes.put_u8(p.prefix_len());
133 }
134 }
135 bytes.put_u8(self.status);
136 bytes.put_u32(self.originated_time as u32);
137
138 match self.peer_ip {
140 IpAddr::V4(a) => {
141 bytes.put_u32(a.into());
142 }
143 IpAddr::V6(a) => {
144 bytes.put_u128(a.into());
145 }
146 }
147 bytes.put_u16(self.peer_asn.into());
148
149 let mut attr_bytes = BytesMut::new();
151 for attr in &self.attributes.inner {
152 attr_bytes.extend(attr.encode(AsnLength::Bits16));
154 }
155
156 bytes.put_u16(attr_bytes.len() as u16);
157 bytes.put_slice(&attr_bytes);
158
159 bytes.freeze()
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use bytes::{BufMut, BytesMut};
167 use std::net::{Ipv4Addr, Ipv6Addr};
168
169 const VIEW_NUMBER: u16 = 0;
170 const SEQUENCE_NUMBER: u16 = 0;
171 const IPV4_PREFIX: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
172 const IPV6_PREFIX: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
173 const PREFIX_LEN: u8 = 0;
174 const STATUS: u8 = 0;
175 const TIME: u64 = 0;
176 const PEER_IPV4: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
177 const PEER_IPV6: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
178 const PEER_ASN_16BIT: u16 = 0;
179 const ATTRIBUTE_LENGTH: usize = 0;
180 const DUMMY_ATTRIBUTES: &[u8] = &[];
181
182 #[test]
183 fn test_parse_table_dump_message_ipv4() {
184 let mut bytes_mut = BytesMut::new();
185 bytes_mut.put_u16(VIEW_NUMBER);
187 bytes_mut.put_u16(SEQUENCE_NUMBER);
188 bytes_mut.put_u32(IPV4_PREFIX.into());
189 bytes_mut.put_u8(PREFIX_LEN);
190 bytes_mut.put_u8(STATUS);
191 bytes_mut.put_u32(TIME as u32);
192 bytes_mut.put_u32(PEER_IPV4.into());
193 bytes_mut.put_u16(PEER_ASN_16BIT);
194 bytes_mut.put_u16(ATTRIBUTE_LENGTH as u16);
195 bytes_mut.put_slice(DUMMY_ATTRIBUTES);
196
197 let bytes = bytes_mut.freeze();
199
200 let table_dump_message_res = parse_table_dump_message(1, bytes.clone());
201 assert!(
202 table_dump_message_res.is_ok(),
203 "Failed to parse TABLE_DUMP_V1 message"
204 );
205
206 let table_dump_message = table_dump_message_res.unwrap();
207 assert_eq!(
208 table_dump_message.view_number, VIEW_NUMBER,
209 "VIEW_NUMBER mismatch"
210 );
211 assert_eq!(
212 table_dump_message.sequence_number, SEQUENCE_NUMBER,
213 "SEQUENCE_NUMBER mismatch"
214 );
215 let encoded = table_dump_message.encode();
217 assert_eq!(encoded, bytes);
218 }
219 #[test]
220 fn test_parse_table_dump_message_ipv6() {
221 let mut bytes_mut = BytesMut::new();
222 bytes_mut.put_u16(VIEW_NUMBER);
224 bytes_mut.put_u16(SEQUENCE_NUMBER);
225 bytes_mut.put_u128(IPV6_PREFIX.into());
226 bytes_mut.put_u8(PREFIX_LEN);
227 bytes_mut.put_u8(STATUS);
228 bytes_mut.put_u32(TIME as u32);
229 bytes_mut.put_u128(PEER_IPV6.into());
230 bytes_mut.put_u16(PEER_ASN_16BIT);
231 bytes_mut.put_u16(ATTRIBUTE_LENGTH as u16);
232 bytes_mut.put_slice(DUMMY_ATTRIBUTES);
233
234 let bytes = bytes_mut.freeze();
236
237 let table_dump_message_res = parse_table_dump_message(2, bytes.clone());
238 assert!(
239 table_dump_message_res.is_ok(),
240 "Failed to parse TABLE_DUMP_V1 message"
241 );
242
243 let table_dump_message = table_dump_message_res.unwrap();
244 assert_eq!(
245 table_dump_message.view_number, VIEW_NUMBER,
246 "VIEW_NUMBER mismatch"
247 );
248 assert_eq!(
249 table_dump_message.sequence_number, SEQUENCE_NUMBER,
250 "SEQUENCE_NUMBER mismatch"
251 );
252 let encoded = table_dump_message.encode();
256 assert_eq!(encoded, bytes);
257 }
258
259 #[test]
260 fn test_parse_table_dump_message_invalid_subtype() {
261 let mut bytes_mut = BytesMut::new();
263 bytes_mut.put_u16(VIEW_NUMBER);
264 bytes_mut.put_u16(SEQUENCE_NUMBER);
265 let bytes = bytes_mut.freeze();
266
267 let result = parse_table_dump_message(0, bytes.clone());
269 assert!(result.is_err(), "Expected error for invalid sub_type");
270
271 if let Err(ParserError::ParseError(msg)) = result {
272 assert!(
273 msg.contains("Invalid subtype"),
274 "Expected error message to mention invalid subtype"
275 );
276 } else {
277 panic!("Expected ParseError for invalid sub_type");
278 }
279
280 let result = parse_table_dump_message(3, bytes);
282 assert!(result.is_err(), "Expected error for invalid sub_type");
283
284 if let Err(ParserError::ParseError(msg)) = result {
285 assert!(
286 msg.contains("Invalid subtype"),
287 "Expected error message to mention invalid subtype"
288 );
289 } else {
290 panic!("Expected ParseError for invalid sub_type");
291 }
292 }
293
294 #[test]
295 fn test_table_dump_message_encode_with_attributes() {
296 use crate::models::{Asn, AttributeValue, Attributes, Origin};
297 use std::str::FromStr;
298
299 let prefix = IpNet::from_str("192.168.0.0/24").unwrap();
300 let mut attributes = Attributes::default();
301 attributes.add_attr(AttributeValue::Origin(Origin::IGP).into());
302
303 let table_dump = TableDumpMessage {
304 view_number: 1,
305 sequence_number: 2,
306 prefix: NetworkPrefix::new(prefix, None),
307 status: 1,
308 originated_time: 12345,
309 peer_ip: IpAddr::V4("10.0.0.1".parse().unwrap()),
310 peer_asn: Asn::from(65000),
311 attributes,
312 };
313
314 let _encoded = table_dump.encode();
316 }
317}