1use byteorder::{BigEndian, ReadBytesExt};
2
3use std::convert::TryFrom;
4use std::io::{Cursor, Error, ErrorKind, Read};
5
6use crate::*;
7
8#[derive(Debug, Clone)]
10pub struct MPReachNLRI {
11 pub afi: AFI,
13
14 pub safi: SAFI,
16
17 pub next_hop: Vec<u8>,
19
20 pub announced_routes: Vec<NLRIEncoding>,
22}
23
24impl MPReachNLRI {
25 pub(crate) fn parse(
27 stream: &mut impl Read,
28 length: u16,
29 capabilities: &Capabilities,
30 ) -> Result<MPReachNLRI, Error> {
31 let afi = AFI::try_from(stream.read_u16::<BigEndian>()?)?;
32 let safi = SAFI::try_from(stream.read_u8()?)?;
33
34 let next_hop_length = stream.read_u8()?;
35 let mut next_hop = vec![0; usize::from(next_hop_length)];
36 stream.read_exact(&mut next_hop)?;
37
38 let _reserved = stream.read_u8()?;
39
40 let size = length - u16::from(5 + next_hop_length);
44
45 let mut buffer = vec![0; usize::from(size)];
46 stream.read_exact(&mut buffer)?;
47 let mut cursor = Cursor::new(buffer);
48 let mut announced_routes: Vec<NLRIEncoding> = Vec::with_capacity(4);
49
50 match afi {
51 AFI::IPV4 | AFI::IPV6 => {
52 while cursor.position() < u64::from(size) {
53 match safi {
54 SAFI::Mpls => {
57 let path_id = if util::detect_add_path_prefix(&mut cursor, 255)? {
58 Some(cursor.read_u32::<BigEndian>()?)
59 } else {
60 None
61 };
62 let len_bits = cursor.read_u8()?;
63 if len_bits == 0 {
65 return Err(Error::new(
66 ErrorKind::Other,
67 "Invalid prefix length 0",
68 ));
69 }
70
71 let len_bytes = (f32::from(len_bits) / 8.0).ceil() as u8;
72 cursor.read_exact(&mut [0u8; 3])?;
74 let remaining = (len_bytes - 3) as usize;
75
76 let mut pfx_buf = afi.empty_buffer();
77 cursor.read_exact(&mut pfx_buf[..remaining])?;
78
79 let pfx_len = len_bits - 24;
81 let prefix = Prefix::new(afi, pfx_len, pfx_buf);
82
83 match path_id {
84 Some(path_id) => announced_routes.push(
85 NLRIEncoding::IP_MPLS_WITH_PATH_ID((prefix, 0u32, path_id)),
86 ),
87 None => {
88 announced_routes.push(NLRIEncoding::IP_MPLS((prefix, 0u32)))
89 }
90 };
91 }
92 SAFI::MplsVpn => {
93 let len_bits = cursor.read_u8()?;
94 let len_bytes = (f32::from(len_bits) / 8.0).ceil() as u8;
95 cursor.read_exact(&mut [0u8; 3])?;
97 let remaining = (len_bytes - 3) as usize;
98
99 let rd = cursor.read_u64::<BigEndian>()?;
100 let mut pfx_buf = afi.empty_buffer();
101 cursor.read_exact(&mut pfx_buf[..(remaining - 8)])?;
102
103 let pfx_len = len_bits - 24 - 64;
105 let prefix = Prefix::new(afi, pfx_len, pfx_buf);
106
107 announced_routes.push(NLRIEncoding::IP_VPN_MPLS((rd, prefix, 0u32)));
108 }
109 #[cfg(feature = "flowspec")]
110 SAFI::Flowspec => {
111 let mut nlri_length = cursor.read_u8()?;
112 let mut filters: Vec<FlowspecFilter> = vec![];
113 while nlri_length > 0 {
114 let cur_position = cursor.position();
115 filters.push(FlowspecFilter::parse(&mut cursor, afi)?);
116 nlri_length -= (cursor.position() - cur_position) as u8;
117 }
118 announced_routes.push(NLRIEncoding::FLOWSPEC(filters));
119 }
120 #[cfg(feature = "flowspec")]
121 SAFI::FlowspecVPN => {
122 unimplemented!();
123 }
124 _ => {
125 if capabilities.EXTENDED_PATH_NLRI_SUPPORT {
126 while cursor.position() < u64::from(size) {
127 let path_id = cursor.read_u32::<BigEndian>()?;
128 let prefix = Prefix::parse(&mut cursor, afi)?;
129 announced_routes
130 .push(NLRIEncoding::IP_WITH_PATH_ID((prefix, path_id)));
131 }
132 } else {
133 while cursor.position() < u64::from(size) {
134 let prefix = Prefix::parse(&mut cursor, afi)?;
135 announced_routes.push(NLRIEncoding::IP(prefix));
136 }
137 }
138 }
139 };
140 }
141 }
142 AFI::L2VPN => {
143 let _len = cursor.read_u16::<BigEndian>()?;
144 let rd = cursor.read_u64::<BigEndian>()?;
145 let ve_id = cursor.read_u16::<BigEndian>()?;
146 let label_block_offset = cursor.read_u16::<BigEndian>()?;
147 let label_block_size = cursor.read_u16::<BigEndian>()?;
148 let label_base = cursor.read_u24::<BigEndian>()?;
149
150 announced_routes.push(NLRIEncoding::L2VPN((
151 rd,
152 ve_id,
153 label_block_offset,
154 label_block_size,
155 label_base,
156 )));
157 }
158 AFI::BGPLS => unimplemented!(),
159 };
160
161 Ok(MPReachNLRI {
162 afi,
163 safi,
164 next_hop,
165 announced_routes,
166 })
167 }
168
169 pub fn encode(&self, mut buf: &mut impl Write) -> Result<(), Error> {
171 buf.write_u16::<BigEndian>(self.afi as u16)?;
172 buf.write_u8(self.safi as u8)?;
173 buf.write_u8(self.next_hop.len() as u8)?;
174 buf.write_all(&self.next_hop)?;
175 buf.write_u8(0u8)?; for nlri in &self.announced_routes {
177 nlri.encode(&mut buf)?;
178 }
179 Ok(())
180 }
181}
182
183#[derive(Debug, Clone)]
185pub struct MPUnreachNLRI {
186 pub afi: AFI,
188
189 pub safi: SAFI,
191
192 pub withdrawn_routes: Vec<NLRIEncoding>,
194}
195
196impl MPUnreachNLRI {
197 pub(crate) fn parse(
199 stream: &mut impl Read,
200 length: u16,
201 capabilities: &Capabilities,
202 ) -> Result<MPUnreachNLRI, Error> {
203 let afi = AFI::try_from(stream.read_u16::<BigEndian>()?)?;
204 let safi = SAFI::try_from(stream.read_u8()?)?;
205
206 let size = length - 3;
210
211 let mut buffer = vec![0; usize::from(size)];
212 stream.read_exact(&mut buffer)?;
213 let mut cursor = Cursor::new(buffer);
214 let mut withdrawn_routes: Vec<NLRIEncoding> = Vec::with_capacity(4);
215
216 while cursor.position() < u64::from(size) {
217 match safi {
218 SAFI::Mpls => {
221 let path_id = if util::detect_add_path_prefix(&mut cursor, 255)? {
222 Some(cursor.read_u32::<BigEndian>()?)
223 } else {
224 None
225 };
226 let len_bits = cursor.read_u8()?;
227 if len_bits == 0 {
229 return Err(Error::new(ErrorKind::Other, "Invalid prefix length 0"));
230 }
231
232 let len_bytes = (f32::from(len_bits) / 8.0).ceil() as u8;
233 cursor.read_exact(&mut [0u8; 3])?;
235 let remaining = (len_bytes - 3) as usize;
236
237 let mut pfx_buf = afi.empty_buffer();
238 cursor.read_exact(&mut pfx_buf[..remaining])?;
239
240 let pfx_len = len_bits - 24;
242 match path_id {
243 Some(path_id) => withdrawn_routes.push(NLRIEncoding::IP_MPLS_WITH_PATH_ID(
244 (Prefix::new(afi, pfx_len, pfx_buf), 0, path_id),
245 )),
246 None => withdrawn_routes.push(NLRIEncoding::IP_MPLS((
247 Prefix::new(afi, pfx_len, pfx_buf),
248 0,
249 ))),
250 };
251 }
252 SAFI::MplsVpn => {
253 let len_bits = cursor.read_u8()?;
254 let len_bytes = (f32::from(len_bits) / 8.0).ceil() as u8;
255
256 cursor.read_exact(&mut [0u8; 3])?;
258
259 let remaining = (len_bytes - 3) as usize;
260
261 let rd = cursor.read_u64::<BigEndian>()?;
262 let mut pfx_buf = afi.empty_buffer();
263 cursor.read_exact(&mut pfx_buf[..(remaining - 8)])?;
264
265 let pfx_len = len_bits - 24 - 64;
267 withdrawn_routes.push(NLRIEncoding::IP_VPN_MPLS((
268 rd,
269 Prefix::new(afi, pfx_len, pfx_buf),
270 0u32,
271 )));
272 }
273 #[cfg(feature = "flowspec")]
274 SAFI::Flowspec => {
275 let mut nlri_length = cursor.read_u8()?;
276 let mut filters: Vec<FlowspecFilter> = vec![];
277 while nlri_length > 0 {
278 let cur_position = cursor.position();
279 filters.push(FlowspecFilter::parse(&mut cursor, afi)?);
280 nlri_length -= (cursor.position() - cur_position) as u8;
281 }
282 withdrawn_routes.push(NLRIEncoding::FLOWSPEC(filters));
283 }
284 #[cfg(feature = "flowspec")]
285 SAFI::FlowspecVPN => {
286 unimplemented!();
287 }
288 _ => {
290 if capabilities.EXTENDED_PATH_NLRI_SUPPORT {
291 while cursor.position() < u64::from(size) {
292 let path_id = cursor.read_u32::<BigEndian>()?;
293 let prefix = Prefix::parse(&mut cursor, afi)?;
294 withdrawn_routes.push(NLRIEncoding::IP_WITH_PATH_ID((prefix, path_id)));
295 }
296 } else {
297 while cursor.position() < u64::from(size) {
298 let prefix = Prefix::parse(&mut cursor, afi)?;
299 withdrawn_routes.push(NLRIEncoding::IP(prefix));
300 }
301 }
302 }
303 };
304 }
305
306 Ok(MPUnreachNLRI {
307 afi,
308 safi,
309 withdrawn_routes,
310 })
311 }
312
313 pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
315 buf.write_u16::<BigEndian>(self.afi as u16)?;
316 buf.write_u8(self.safi as u8)?;
317 for nlri in &self.withdrawn_routes {
318 nlri.encode(buf)?;
319 }
320 Ok(())
321 }
322}