Skip to main content

rustbgpd_wire/
route_refresh.rs

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
10/// ROUTE-REFRESH base body length (AFI u16 + subtype u8 + SAFI u8). An ORF
11/// message (RFC 5291 §5.2) extends the body beyond this with ORF entries.
12const BODY_LEN: usize = 4;
13
14/// Total wire length of a plain ROUTE-REFRESH message (header + base body).
15const TOTAL_LEN: usize = HEADER_LEN + BODY_LEN;
16
17/// ROUTE-REFRESH demarcation subtype (RFC 7313).
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub enum RouteRefreshSubtype {
20    /// Normal route refresh request (subtype 0).
21    Normal,
22    /// Beginning of Route Refresh (subtype 1, RFC 7313).
23    BoRR,
24    /// End of Route Refresh (subtype 2, RFC 7313).
25    EoRR,
26    /// Unrecognized subtype value.
27    Unknown(
28        /// The raw subtype byte.
29        u8,
30    ),
31}
32
33impl RouteRefreshSubtype {
34    /// Create from a raw subtype byte.
35    #[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    /// Return the raw byte value for this subtype.
46    #[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/// BGP ROUTE-REFRESH message (RFC 2918 + RFC 7313 + RFC 5291 ORF).
58///
59/// Requests a peer to re-advertise its Adj-RIB-Out for the specified
60/// address family. RFC 7313 reuses the third octet as a demarcation subtype
61/// (BoRR/EoRR). Raw wire values are stored so that unknown AFI/SAFI or
62/// subtype values can be decoded without error — the transport layer decides
63/// whether to act on or ignore them.
64///
65/// When the message body extends beyond the 4-byte AFI/Reserved/SAFI header,
66/// the trailing bytes are an RFC 5291 ORF section, decoded into [`orf`]. A
67/// plain or Enhanced Route Refresh has [`orf`] set to `None`.
68///
69/// [`orf`]: RouteRefreshMessage::orf
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct RouteRefreshMessage {
72    /// Raw AFI value from the wire.
73    pub afi_raw: u16,
74    /// Raw demarcation subtype byte from the wire.
75    pub subtype_raw: u8,
76    /// Raw SAFI value from the wire.
77    pub safi_raw: u8,
78    /// RFC 5291 ORF section, present when the body extends past the 4-byte
79    /// header. `None` for a plain (RFC 2918) or Enhanced (RFC 7313) refresh.
80    pub orf: Option<OrfPayload>,
81}
82
83impl RouteRefreshMessage {
84    /// Create a normal (subtype 0) ROUTE-REFRESH from typed AFI/SAFI values.
85    #[must_use]
86    pub fn new(afi: Afi, safi: Safi) -> Self {
87        Self::new_with_subtype(afi, safi, RouteRefreshSubtype::Normal)
88    }
89
90    /// Create a ROUTE-REFRESH with an explicit subtype.
91    #[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    /// Create an ORF-carrying ROUTE-REFRESH (RFC 5291 §5.2). The third octet
102    /// is Reserved (subtype 0) for an ORF message.
103    #[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    /// Try to interpret the raw AFI as a known address family.
114    #[must_use]
115    pub fn afi(&self) -> Option<Afi> {
116        Afi::from_u16(self.afi_raw)
117    }
118
119    /// Try to interpret the raw SAFI as a known sub-address family.
120    #[must_use]
121    pub fn safi(&self) -> Option<Safi> {
122        Safi::from_u8(self.safi_raw)
123    }
124
125    /// Decode the demarcation subtype.
126    #[must_use]
127    pub fn subtype(&self) -> RouteRefreshSubtype {
128        RouteRefreshSubtype::from_u8(self.subtype_raw)
129    }
130
131    /// Decode a ROUTE-REFRESH message body from a buffer.
132    ///
133    /// A 4-byte body is a plain/Enhanced refresh (`orf: None`). A longer body
134    /// carries an RFC 5291 ORF section, decoded into `orf`. A malformed ORF
135    /// *entry* does not fail the decode — it is surfaced via
136    /// [`crate::orf::OrfEntries::Malformed`] so the caller can apply the RFC
137    /// 5291 §5.2 reset semantics instead of tearing the session down.
138    ///
139    /// # Errors
140    ///
141    /// Returns [`DecodeError`] if the body length is below 4 or the buffer is
142    /// truncated relative to the declared body length. Unknown AFI/SAFI values
143    /// and unknown subtypes are preserved.
144    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            // Bound the ORF parse to the declared body so a buffer carrying
163            // more than one message cannot over-read.
164            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    /// Encode a complete ROUTE-REFRESH message (header + body) into a buffer.
180    ///
181    /// # Errors
182    ///
183    /// Returns [`EncodeError`] if the total message length (with an ORF
184    /// section) exceeds the 16-bit length field.
185    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    /// Total encoded size on the wire (header + base body + any ORF section).
204    #[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        // Regression: a 4-byte body is a plain/Enhanced refresh, never ORF.
316        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        // body_len claims 10 but only 4 bytes are present.
332        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, // AFI IPv4, Reserved, future/unknown SAFI.
406            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}