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 attributes =
103 parse_attributes(attr_data_slice, &AsnLength::Bits16, false, None, None, None)?;
104
105 Ok(TableDumpMessage {
106 view_number,
107 sequence_number,
108 prefix: NetworkPrefix::new(prefix, None),
109 status,
110 originated_time: time,
111 peer_ip,
112 peer_asn,
113 attributes,
114 })
115}
116
117impl TableDumpMessage {
118 pub fn encode(&self) -> Bytes {
119 let mut bytes = BytesMut::new();
120 bytes.put_u16(self.view_number);
121 bytes.put_u16(self.sequence_number);
122 match &self.prefix.prefix {
123 IpNet::V4(p) => {
124 bytes.put_u32(p.addr().into());
125 bytes.put_u8(p.prefix_len());
126 }
127 IpNet::V6(p) => {
128 bytes.put_u128(p.addr().into());
129 bytes.put_u8(p.prefix_len());
130 }
131 }
132 bytes.put_u8(self.status);
133 bytes.put_u32(self.originated_time as u32);
134
135 match self.peer_ip {
137 IpAddr::V4(a) => {
138 bytes.put_u32(a.into());
139 }
140 IpAddr::V6(a) => {
141 bytes.put_u128(a.into());
142 }
143 }
144 bytes.put_u16(self.peer_asn.into());
145
146 let mut attr_bytes = BytesMut::new();
148 for attr in &self.attributes.inner {
149 attr_bytes.extend(attr.encode(AsnLength::Bits16));
151 }
152
153 bytes.put_u16(attr_bytes.len() as u16);
154 bytes.put_slice(&attr_bytes);
155
156 bytes.freeze()
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use bytes::{BufMut, BytesMut};
164 use std::net::{Ipv4Addr, Ipv6Addr};
165
166 const VIEW_NUMBER: u16 = 0;
167 const SEQUENCE_NUMBER: u16 = 0;
168 const IPV4_PREFIX: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
169 const IPV6_PREFIX: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
170 const PREFIX_LEN: u8 = 0;
171 const STATUS: u8 = 0;
172 const TIME: u64 = 0;
173 const PEER_IPV4: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
174 const PEER_IPV6: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
175 const PEER_ASN_16BIT: u16 = 0;
176 const ATTRIBUTE_LENGTH: usize = 0;
177 const DUMMY_ATTRIBUTES: &[u8] = &[];
178
179 #[test]
180 fn test_parse_table_dump_message_ipv4() {
181 let mut bytes_mut = BytesMut::new();
182 bytes_mut.put_u16(VIEW_NUMBER);
184 bytes_mut.put_u16(SEQUENCE_NUMBER);
185 bytes_mut.put_u32(IPV4_PREFIX.into());
186 bytes_mut.put_u8(PREFIX_LEN);
187 bytes_mut.put_u8(STATUS);
188 bytes_mut.put_u32(TIME as u32);
189 bytes_mut.put_u32(PEER_IPV4.into());
190 bytes_mut.put_u16(PEER_ASN_16BIT);
191 bytes_mut.put_u16(ATTRIBUTE_LENGTH as u16);
192 bytes_mut.put_slice(DUMMY_ATTRIBUTES);
193
194 let bytes = bytes_mut.freeze();
196
197 let table_dump_message_res = parse_table_dump_message(1, bytes.clone());
198 assert!(
199 table_dump_message_res.is_ok(),
200 "Failed to parse TABLE_DUMP_V1 message"
201 );
202
203 let table_dump_message = table_dump_message_res.unwrap();
204 assert_eq!(
205 table_dump_message.view_number, VIEW_NUMBER,
206 "VIEW_NUMBER mismatch"
207 );
208 assert_eq!(
209 table_dump_message.sequence_number, SEQUENCE_NUMBER,
210 "SEQUENCE_NUMBER mismatch"
211 );
212 let encoded = table_dump_message.encode();
214 assert_eq!(encoded, bytes);
215 }
216 #[test]
217 fn test_parse_table_dump_message_ipv6() {
218 let mut bytes_mut = BytesMut::new();
219 bytes_mut.put_u16(VIEW_NUMBER);
221 bytes_mut.put_u16(SEQUENCE_NUMBER);
222 bytes_mut.put_u128(IPV6_PREFIX.into());
223 bytes_mut.put_u8(PREFIX_LEN);
224 bytes_mut.put_u8(STATUS);
225 bytes_mut.put_u32(TIME as u32);
226 bytes_mut.put_u128(PEER_IPV6.into());
227 bytes_mut.put_u16(PEER_ASN_16BIT);
228 bytes_mut.put_u16(ATTRIBUTE_LENGTH as u16);
229 bytes_mut.put_slice(DUMMY_ATTRIBUTES);
230
231 let bytes = bytes_mut.freeze();
233
234 let table_dump_message_res = parse_table_dump_message(2, bytes.clone());
235 assert!(
236 table_dump_message_res.is_ok(),
237 "Failed to parse TABLE_DUMP_V1 message"
238 );
239
240 let table_dump_message = table_dump_message_res.unwrap();
241 assert_eq!(
242 table_dump_message.view_number, VIEW_NUMBER,
243 "VIEW_NUMBER mismatch"
244 );
245 assert_eq!(
246 table_dump_message.sequence_number, SEQUENCE_NUMBER,
247 "SEQUENCE_NUMBER mismatch"
248 );
249 let encoded = table_dump_message.encode();
253 assert_eq!(encoded, bytes);
254 }
255
256 #[test]
257 fn test_parse_table_dump_message_invalid_subtype() {
258 let mut bytes_mut = BytesMut::new();
260 bytes_mut.put_u16(VIEW_NUMBER);
261 bytes_mut.put_u16(SEQUENCE_NUMBER);
262 let bytes = bytes_mut.freeze();
263
264 let result = parse_table_dump_message(0, bytes.clone());
266 assert!(result.is_err(), "Expected error for invalid sub_type");
267
268 if let Err(ParserError::ParseError(msg)) = result {
269 assert!(
270 msg.contains("Invalid subtype"),
271 "Expected error message to mention invalid subtype"
272 );
273 } else {
274 panic!("Expected ParseError for invalid sub_type");
275 }
276
277 let result = parse_table_dump_message(3, bytes);
279 assert!(result.is_err(), "Expected error for invalid sub_type");
280
281 if let Err(ParserError::ParseError(msg)) = result {
282 assert!(
283 msg.contains("Invalid subtype"),
284 "Expected error message to mention invalid subtype"
285 );
286 } else {
287 panic!("Expected ParseError for invalid sub_type");
288 }
289 }
290
291 #[test]
292 fn test_table_dump_message_encode_with_attributes() {
293 use crate::models::{Asn, AttributeValue, Attributes, Origin};
294 use std::str::FromStr;
295
296 let prefix = IpNet::from_str("192.168.0.0/24").unwrap();
297 let mut attributes = Attributes::default();
298 attributes.add_attr(AttributeValue::Origin(Origin::IGP).into());
299
300 let table_dump = TableDumpMessage {
301 view_number: 1,
302 sequence_number: 2,
303 prefix: NetworkPrefix::new(prefix, None),
304 status: 1,
305 originated_time: 12345,
306 peer_ip: IpAddr::V4("10.0.0.1".parse().unwrap()),
307 peer_asn: Asn::from(65000),
308 attributes,
309 };
310
311 let _encoded = table_dump.encode();
313 }
314}