1use bytes::{Buf, BufMut};
2
3use crate::capability::{Afi, Safi};
4use crate::constants::{HEADER_LEN, MARKER, message_type};
5use crate::error::{DecodeError, EncodeError};
6use crate::orf::{
7 OrfPayload, decode_route_refresh_orf, encode_route_refresh_orf, route_refresh_orf_len,
8};
9
10const BODY_LEN: usize = 4;
13
14const TOTAL_LEN: usize = HEADER_LEN + BODY_LEN;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub enum RouteRefreshSubtype {
20 Normal,
22 BoRR,
24 EoRR,
26 Unknown(
28 u8,
30 ),
31}
32
33impl RouteRefreshSubtype {
34 #[must_use]
36 pub fn from_u8(value: u8) -> Self {
37 match value {
38 0 => Self::Normal,
39 1 => Self::BoRR,
40 2 => Self::EoRR,
41 other => Self::Unknown(other),
42 }
43 }
44
45 #[must_use]
47 pub fn as_u8(self) -> u8 {
48 match self {
49 Self::Normal => 0,
50 Self::BoRR => 1,
51 Self::EoRR => 2,
52 Self::Unknown(value) => value,
53 }
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct RouteRefreshMessage {
72 pub afi_raw: u16,
74 pub subtype_raw: u8,
76 pub safi_raw: u8,
78 pub orf: Option<OrfPayload>,
81}
82
83impl RouteRefreshMessage {
84 #[must_use]
86 pub fn new(afi: Afi, safi: Safi) -> Self {
87 Self::new_with_subtype(afi, safi, RouteRefreshSubtype::Normal)
88 }
89
90 #[must_use]
92 pub fn new_with_subtype(afi: Afi, safi: Safi, subtype: RouteRefreshSubtype) -> Self {
93 Self {
94 afi_raw: afi as u16,
95 subtype_raw: subtype.as_u8(),
96 safi_raw: safi as u8,
97 orf: None,
98 }
99 }
100
101 #[must_use]
104 pub fn new_with_orf(afi: Afi, safi: Safi, orf: OrfPayload) -> Self {
105 Self {
106 afi_raw: afi as u16,
107 subtype_raw: 0,
108 safi_raw: safi as u8,
109 orf: Some(orf),
110 }
111 }
112
113 #[must_use]
115 pub fn afi(&self) -> Option<Afi> {
116 Afi::from_u16(self.afi_raw)
117 }
118
119 #[must_use]
121 pub fn safi(&self) -> Option<Safi> {
122 Safi::from_u8(self.safi_raw)
123 }
124
125 #[must_use]
127 pub fn subtype(&self) -> RouteRefreshSubtype {
128 RouteRefreshSubtype::from_u8(self.subtype_raw)
129 }
130
131 pub fn decode(buf: &mut impl Buf, body_len: usize) -> Result<Self, DecodeError> {
145 if body_len < BODY_LEN {
146 return Err(DecodeError::InvalidLength {
147 length: u16::try_from(HEADER_LEN + body_len).unwrap_or(u16::MAX),
148 });
149 }
150 if buf.remaining() < body_len {
151 return Err(DecodeError::Incomplete {
152 needed: body_len,
153 available: buf.remaining(),
154 });
155 }
156
157 let afi_raw = buf.get_u16();
158 let subtype_raw = buf.get_u8();
159 let safi_raw = buf.get_u8();
160
161 let orf = if body_len > BODY_LEN {
162 let mut orf_buf = buf.copy_to_bytes(body_len - BODY_LEN);
165 let family = Afi::from_u16(afi_raw).zip(Safi::from_u8(safi_raw));
166 Some(decode_route_refresh_orf(&mut orf_buf, family)?)
167 } else {
168 None
169 };
170
171 Ok(Self {
172 afi_raw,
173 subtype_raw,
174 safi_raw,
175 orf,
176 })
177 }
178
179 pub fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
186 let total = self.encoded_len();
187 let total_u16 = u16::try_from(total).map_err(|_| EncodeError::ValueOutOfRange {
188 field: "route_refresh_message_length",
189 value: total.to_string(),
190 })?;
191 buf.put_slice(&MARKER);
192 buf.put_u16(total_u16);
193 buf.put_u8(message_type::ROUTE_REFRESH);
194 buf.put_u16(self.afi_raw);
195 buf.put_u8(self.subtype_raw);
196 buf.put_u8(self.safi_raw);
197 if let Some(orf) = &self.orf {
198 encode_route_refresh_orf(orf, buf)?;
199 }
200 Ok(())
201 }
202
203 #[must_use]
205 pub fn encoded_len(&self) -> usize {
206 TOTAL_LEN + self.orf.as_ref().map_or(0, route_refresh_orf_len)
207 }
208}
209
210impl std::fmt::Display for RouteRefreshMessage {
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 let subtype = match self.subtype() {
213 RouteRefreshSubtype::Normal => "Normal".to_string(),
214 RouteRefreshSubtype::BoRR => "BoRR".to_string(),
215 RouteRefreshSubtype::EoRR => "EoRR".to_string(),
216 RouteRefreshSubtype::Unknown(value) => format!("Unknown({value})"),
217 };
218
219 let orf = if let Some(payload) = &self.orf {
220 format!(
221 " ORF(when={:?}, groups={})",
222 payload.when_to_refresh,
223 payload.groups.len()
224 )
225 } else {
226 String::new()
227 };
228 match (self.afi(), self.safi()) {
229 (Some(afi), Some(safi)) => {
230 write!(
231 f,
232 "ROUTE-REFRESH subtype={subtype} AFI={afi:?} SAFI={safi:?}{orf}"
233 )
234 }
235 _ => write!(
236 f,
237 "ROUTE-REFRESH subtype={subtype} AFI={} SAFI={}{orf}",
238 self.afi_raw, self.safi_raw
239 ),
240 }
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use bytes::{Bytes, BytesMut};
247
248 use super::*;
249
250 #[test]
251 fn roundtrip_ipv4_unicast() {
252 let msg = RouteRefreshMessage::new(Afi::Ipv4, Safi::Unicast);
253 let mut buf = BytesMut::with_capacity(TOTAL_LEN);
254 msg.encode(&mut buf).unwrap();
255 assert_eq!(buf.len(), TOTAL_LEN);
256
257 let mut bytes = buf.freeze();
258 bytes.advance(HEADER_LEN);
259 let decoded = RouteRefreshMessage::decode(&mut bytes, BODY_LEN).unwrap();
260 assert_eq!(decoded, msg);
261 assert_eq!(decoded.afi(), Some(Afi::Ipv4));
262 assert_eq!(decoded.safi(), Some(Safi::Unicast));
263 assert_eq!(decoded.subtype(), RouteRefreshSubtype::Normal);
264 }
265
266 #[test]
267 fn roundtrip_ipv6_unicast() {
268 let msg = RouteRefreshMessage::new(Afi::Ipv6, Safi::Unicast);
269 let mut buf = BytesMut::with_capacity(TOTAL_LEN);
270 msg.encode(&mut buf).unwrap();
271
272 let mut bytes = buf.freeze();
273 bytes.advance(HEADER_LEN);
274 let decoded = RouteRefreshMessage::decode(&mut bytes, BODY_LEN).unwrap();
275 assert_eq!(decoded, msg);
276 assert_eq!(decoded.afi(), Some(Afi::Ipv6));
277 assert_eq!(decoded.safi(), Some(Safi::Unicast));
278 assert_eq!(decoded.subtype(), RouteRefreshSubtype::Normal);
279 }
280
281 #[test]
282 fn roundtrip_borr() {
283 let msg = RouteRefreshMessage::new_with_subtype(
284 Afi::Ipv4,
285 Safi::Unicast,
286 RouteRefreshSubtype::BoRR,
287 );
288 let mut buf = BytesMut::with_capacity(TOTAL_LEN);
289 msg.encode(&mut buf).unwrap();
290 let mut bytes = buf.freeze();
291 bytes.advance(HEADER_LEN);
292 let decoded = RouteRefreshMessage::decode(&mut bytes, BODY_LEN).unwrap();
293 assert_eq!(decoded, msg);
294 assert_eq!(decoded.subtype(), RouteRefreshSubtype::BoRR);
295 }
296
297 #[test]
298 fn roundtrip_eorr() {
299 let msg = RouteRefreshMessage::new_with_subtype(
300 Afi::Ipv6,
301 Safi::Unicast,
302 RouteRefreshSubtype::EoRR,
303 );
304 let mut buf = BytesMut::with_capacity(TOTAL_LEN);
305 msg.encode(&mut buf).unwrap();
306 let mut bytes = buf.freeze();
307 bytes.advance(HEADER_LEN);
308 let decoded = RouteRefreshMessage::decode(&mut bytes, BODY_LEN).unwrap();
309 assert_eq!(decoded, msg);
310 assert_eq!(decoded.subtype(), RouteRefreshSubtype::EoRR);
311 }
312
313 #[test]
314 fn plain_four_byte_body_has_no_orf() {
315 let data: &[u8] = &[0, 1, 0, 1];
317 let mut buf = Bytes::copy_from_slice(data);
318 let msg = RouteRefreshMessage::decode(&mut buf, 4).unwrap();
319 assert_eq!(msg.orf, None);
320 }
321
322 #[test]
323 fn reject_body_length_three() {
324 let data: &[u8] = &[0, 1, 0];
325 let mut buf = Bytes::copy_from_slice(data);
326 assert!(RouteRefreshMessage::decode(&mut buf, 3).is_err());
327 }
328
329 #[test]
330 fn reject_truncated_orf_body() {
331 let data: &[u8] = &[0, 1, 0, 1];
333 let mut buf = Bytes::copy_from_slice(data);
334 assert!(RouteRefreshMessage::decode(&mut buf, 10).is_err());
335 }
336
337 #[test]
338 fn roundtrip_orf_route_refresh() {
339 use crate::nlri::{Ipv4Prefix, Prefix};
340 use crate::orf::{
341 AddressPrefixOrf, OrfAction, OrfEntries, OrfEntryGroup, OrfMatch, OrfPayload, OrfType,
342 WhenToRefresh,
343 };
344 use std::net::Ipv4Addr;
345
346 let payload = OrfPayload {
347 when_to_refresh: WhenToRefresh::Immediate,
348 groups: vec![OrfEntryGroup {
349 orf_type: OrfType::AddressPrefix,
350 entries: OrfEntries::AddressPrefix(vec![AddressPrefixOrf {
351 action: OrfAction::Add,
352 match_: OrfMatch::Permit,
353 sequence: 10,
354 min_len: 24,
355 max_len: 32,
356 prefix: Some(Prefix::V4(Ipv4Prefix::new(Ipv4Addr::new(10, 0, 0, 0), 8))),
357 }]),
358 }],
359 };
360 let msg = RouteRefreshMessage::new_with_orf(Afi::Ipv4, Safi::Unicast, payload);
361
362 let mut buf = BytesMut::with_capacity(msg.encoded_len());
363 msg.encode(&mut buf).unwrap();
364 assert_eq!(buf.len(), msg.encoded_len());
365
366 let mut bytes = buf.freeze();
367 bytes.advance(HEADER_LEN);
368 let body_len = msg.encoded_len() - HEADER_LEN;
369 let decoded = RouteRefreshMessage::decode(&mut bytes, body_len).unwrap();
370 assert_eq!(decoded, msg);
371 assert!(decoded.orf.is_some());
372 }
373
374 #[test]
375 fn decode_unknown_afi_succeeds() {
376 let data: &[u8] = &[0, 99, 0, 1];
377 let mut buf = Bytes::copy_from_slice(data);
378 let msg = RouteRefreshMessage::decode(&mut buf, 4).unwrap();
379 assert_eq!(msg.afi_raw, 99);
380 assert_eq!(msg.afi(), None);
381 assert_eq!(msg.safi(), Some(Safi::Unicast));
382 assert_eq!(msg.subtype(), RouteRefreshSubtype::Normal);
383 }
384
385 #[test]
386 fn decode_unknown_safi_succeeds() {
387 let data: &[u8] = &[0, 1, 0, 99];
388 let mut buf = Bytes::copy_from_slice(data);
389 let msg = RouteRefreshMessage::decode(&mut buf, 4).unwrap();
390 assert_eq!(msg.safi_raw, 99);
391 assert_eq!(msg.safi(), None);
392 assert_eq!(msg.afi(), Some(Afi::Ipv4));
393 assert_eq!(msg.subtype(), RouteRefreshSubtype::Normal);
394 }
395
396 #[test]
397 fn decode_orf_unknown_safi_preserves_address_prefix_group_as_raw() {
398 use crate::constants::orf;
399 use crate::orf::{OrfEntries, OrfType, WhenToRefresh};
400
401 let data: &[u8] = &[
402 0,
403 1,
404 0,
405 128, orf::WHEN_IMMEDIATE,
407 orf::TYPE_ADDRESS_PREFIX,
408 0,
409 8,
410 orf::ACTION_ADD,
411 0,
412 0,
413 0,
414 1,
415 0,
416 0,
417 40,
418 ];
419 let mut buf = Bytes::copy_from_slice(data);
420 let msg = RouteRefreshMessage::decode(&mut buf, data.len()).unwrap();
421 let payload = msg.orf.unwrap();
422 assert_eq!(payload.when_to_refresh, WhenToRefresh::Immediate);
423 assert_eq!(payload.groups[0].orf_type, OrfType::AddressPrefix);
424 assert_eq!(
425 payload.groups[0].entries,
426 OrfEntries::Raw(Bytes::from_static(&[orf::ACTION_ADD, 0, 0, 0, 1, 0, 0, 40]))
427 );
428 }
429
430 #[test]
431 fn decode_unknown_subtype_succeeds() {
432 let data: &[u8] = &[0, 1, 9, 1];
433 let mut buf = Bytes::copy_from_slice(data);
434 let msg = RouteRefreshMessage::decode(&mut buf, 4).unwrap();
435 assert_eq!(msg.subtype(), RouteRefreshSubtype::Unknown(9));
436 }
437
438 #[test]
439 fn encoded_len_is_23() {
440 let msg = RouteRefreshMessage::new(Afi::Ipv4, Safi::Unicast);
441 assert_eq!(msg.encoded_len(), 23);
442 }
443
444 #[test]
445 fn display_known_family() {
446 let msg = RouteRefreshMessage::new(Afi::Ipv6, Safi::Unicast);
447 let s = format!("{msg}");
448 assert!(s.contains("Ipv6"));
449 assert!(s.contains("Unicast"));
450 assert!(s.contains("Normal"));
451 }
452
453 #[test]
454 fn display_unknown_family() {
455 let msg = RouteRefreshMessage {
456 afi_raw: 99,
457 subtype_raw: 7,
458 safi_raw: 42,
459 orf: None,
460 };
461 let s = format!("{msg}");
462 assert!(s.contains("99"));
463 assert!(s.contains("42"));
464 assert!(s.contains("Unknown(7)"));
465 }
466}