bgpkit_parser/parser/mrt/messages/table_dump_v2/
rib_afi_entries.rs1use crate::bgp::attributes::parse_attributes;
2use crate::models::{
3 Afi, AsnLength, NetworkPrefix, RibAfiEntries, RibEntry, Safi, TableDumpV2Type,
4};
5use crate::parser::ReadUtils;
6use crate::ParserError;
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8use log::warn;
9
10fn extract_afi_safi_from_rib_type(rib_type: &TableDumpV2Type) -> Result<(Afi, Safi), ParserError> {
11 let afi: Afi;
12 let safi: Safi;
13 match rib_type {
14 TableDumpV2Type::RibIpv4Unicast | TableDumpV2Type::RibIpv4UnicastAddPath => {
15 afi = Afi::Ipv4;
16 safi = Safi::Unicast
17 }
18 TableDumpV2Type::RibIpv4Multicast | TableDumpV2Type::RibIpv4MulticastAddPath => {
19 afi = Afi::Ipv4;
20 safi = Safi::Multicast
21 }
22 TableDumpV2Type::RibIpv6Unicast | TableDumpV2Type::RibIpv6UnicastAddPath => {
23 afi = Afi::Ipv6;
24 safi = Safi::Unicast
25 }
26 TableDumpV2Type::RibIpv6Multicast | TableDumpV2Type::RibIpv6MulticastAddPath => {
27 afi = Afi::Ipv6;
28 safi = Safi::Multicast
29 }
30 _ => {
31 return Err(ParserError::ParseError(format!(
32 "wrong RIB type for parsing: {rib_type:?}"
33 )))
34 }
35 };
36
37 Ok((afi, safi))
38}
39
40pub fn parse_rib_afi_entries(
44 data: &mut Bytes,
45 rib_type: TableDumpV2Type,
46) -> Result<RibAfiEntries, ParserError> {
47 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type)?;
48
49 let is_add_path = matches!(
50 rib_type,
51 TableDumpV2Type::RibIpv4UnicastAddPath
52 | TableDumpV2Type::RibIpv4MulticastAddPath
53 | TableDumpV2Type::RibIpv6UnicastAddPath
54 | TableDumpV2Type::RibIpv6MulticastAddPath
55 );
56
57 let sequence_number = data.read_u32()?;
58
59 let prefix = data.read_nlri_prefix(&afi, false)?;
62
63 let entry_count = data.read_u16()?;
64 let mut rib_entries = Vec::with_capacity((entry_count * 2) as usize);
65
66 for _i in 0..entry_count {
70 let entry = match parse_rib_entry(data, is_add_path, &afi, &safi, prefix) {
71 Ok(entry) => entry,
72 Err(e) => {
73 warn!("early break due to error {}", e);
74 break;
75 }
76 };
77 rib_entries.push(entry);
78 }
79
80 Ok(RibAfiEntries {
81 rib_type,
82 sequence_number,
83 prefix,
84 rib_entries,
85 })
86}
87
88pub fn parse_rib_entry(
108 input: &mut Bytes,
109 is_add_path: bool,
110 afi: &Afi,
111 safi: &Safi,
112 prefix: NetworkPrefix,
113) -> Result<RibEntry, ParserError> {
114 if input.remaining() < 8 {
115 return Err(ParserError::TruncatedMsg("truncated msg".to_string()));
118 }
119
120 let peer_index = input.read_u16()?;
121 let originated_time = input.read_u32()?;
122
123 let path_id = match is_add_path {
124 true => Some(input.read_u32()?),
125 false => None,
126 };
127
128 let attribute_length = input.read_u16()? as usize;
129
130 input.has_n_remaining(attribute_length)?;
131 let attr_data_slice = input.split_to(attribute_length);
132 let attributes = parse_attributes(
133 attr_data_slice,
134 &AsnLength::Bits32,
135 is_add_path,
136 Some(*afi),
137 Some(*safi),
138 Some(&[prefix]),
139 )?;
140
141 Ok(RibEntry {
142 peer_index,
143 originated_time,
144 path_id,
145 attributes,
146 })
147}
148
149impl RibAfiEntries {
150 pub fn encode(&self) -> Bytes {
151 let mut bytes = BytesMut::new();
152
153 bytes.put_u32(self.sequence_number);
154 bytes.extend(self.prefix.encode());
155
156 let entry_count = self.rib_entries.len();
157 bytes.put_u16(entry_count as u16);
158
159 for entry in &self.rib_entries {
160 bytes.extend(entry.encode());
161 }
162
163 bytes.freeze()
164 }
165}
166
167impl RibEntry {
168 pub fn encode(&self) -> Bytes {
169 let mut bytes = BytesMut::new();
170 bytes.put_u16(self.peer_index);
171 bytes.put_u32(self.originated_time);
172 let attr_bytes = self.attributes.encode(AsnLength::Bits32);
173 bytes.put_u16(attr_bytes.len() as u16);
174 bytes.extend(attr_bytes);
175 bytes.freeze()
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn test_extract_afi_safi_from_rib_type() {
185 let rib_type = TableDumpV2Type::RibIpv4Unicast;
186 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
187 assert_eq!(afi, Afi::Ipv4);
188 assert_eq!(safi, Safi::Unicast);
189
190 let rib_type = TableDumpV2Type::RibIpv4Multicast;
191 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
192 assert_eq!(afi, Afi::Ipv4);
193 assert_eq!(safi, Safi::Multicast);
194
195 let rib_type = TableDumpV2Type::RibIpv6Unicast;
196 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
197 assert_eq!(afi, Afi::Ipv6);
198 assert_eq!(safi, Safi::Unicast);
199
200 let rib_type = TableDumpV2Type::RibIpv6Multicast;
201 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
202 assert_eq!(afi, Afi::Ipv6);
203 assert_eq!(safi, Safi::Multicast);
204
205 let rib_type = TableDumpV2Type::RibIpv4UnicastAddPath;
206 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
207 assert_eq!(afi, Afi::Ipv4);
208 assert_eq!(safi, Safi::Unicast);
209
210 let rib_type = TableDumpV2Type::RibIpv4MulticastAddPath;
211 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
212 assert_eq!(afi, Afi::Ipv4);
213 assert_eq!(safi, Safi::Multicast);
214
215 let rib_type = TableDumpV2Type::RibIpv6UnicastAddPath;
216 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
217 assert_eq!(afi, Afi::Ipv6);
218 assert_eq!(safi, Safi::Unicast);
219
220 let rib_type = TableDumpV2Type::RibIpv6MulticastAddPath;
221 let (afi, safi) = extract_afi_safi_from_rib_type(&rib_type).unwrap();
222 assert_eq!(afi, Afi::Ipv6);
223 assert_eq!(safi, Safi::Multicast);
224
225 let rib_type = TableDumpV2Type::RibGeneric;
226 let res = extract_afi_safi_from_rib_type(&rib_type);
227 assert!(res.is_err());
228 }
229
230 #[test]
231 fn test_rib_entry_encode() {
232 use crate::models::{AttributeValue, Attributes, Origin};
233
234 let mut attributes = Attributes::default();
235 attributes.add_attr(AttributeValue::Origin(Origin::IGP).into());
236
237 let rib_entry = RibEntry {
238 peer_index: 1,
239 originated_time: 12345,
240 path_id: Some(42),
241 attributes,
242 };
243
244 let _encoded = rib_entry.encode();
246 }
247}