netlink_packet_route/route/
next_hops.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    DecodeError, Emitable, ErrorContext, NlaBuffer, NlasIterator,
5    ParseableParametrized,
6};
7
8use super::{
9    super::AddressFamily, RouteAttribute, RouteLwEnCapType, RouteType,
10};
11
12pub(crate) const RTNH_F_DEAD: u8 = 1;
13pub(crate) const RTNH_F_PERVASIVE: u8 = 2;
14pub(crate) const RTNH_F_ONLINK: u8 = 4;
15pub(crate) const RTNH_F_OFFLOAD: u8 = 8;
16pub(crate) const RTNH_F_LINKDOWN: u8 = 16;
17pub(crate) const RTNH_F_UNRESOLVED: u8 = 32;
18pub(crate) const RTNH_F_TRAP: u8 = 64;
19
20bitflags! {
21    #[derive(Clone, Eq, PartialEq, Debug, Copy, Default)]
22    #[non_exhaustive]
23    pub struct RouteNextHopFlags: u8 {
24        const Dead = RTNH_F_DEAD;
25        const Pervasive = RTNH_F_PERVASIVE;
26        const Onlink = RTNH_F_ONLINK;
27        const Offload = RTNH_F_OFFLOAD;
28        const Linkdown = RTNH_F_LINKDOWN;
29        const Unresolved = RTNH_F_UNRESOLVED;
30        const Trap = RTNH_F_TRAP;
31        const _ = !0;
32    }
33}
34
35const PAYLOAD_OFFSET: usize = 8;
36
37buffer!(RouteNextHopBuffer {
38    length: (u16, 0..2),
39    flags: (u8, 2),
40    hops: (u8, 3),
41    interface_index: (u32, 4..8),
42    payload: (slice, PAYLOAD_OFFSET..),
43});
44
45impl<T: AsRef<[u8]>> RouteNextHopBuffer<T> {
46    pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {
47        let packet = Self::new(buffer);
48        packet.check_buffer_length()?;
49        Ok(packet)
50    }
51
52    fn check_buffer_length(&self) -> Result<(), DecodeError> {
53        let len = self.buffer.as_ref().len();
54        if len < PAYLOAD_OFFSET {
55            return Err(format!(
56                "invalid RouteNextHopBuffer: length {len} < {PAYLOAD_OFFSET}"
57            )
58            .into());
59        }
60        if len < self.length() as usize {
61            return Err(format!(
62                "invalid RouteNextHopBuffer: length {} < {}",
63                len,
64                self.length(),
65            )
66            .into());
67        }
68        if (self.length() as usize) < PAYLOAD_OFFSET {
69            return Err(format!(
70                "invalid RouteNextHopBuffer: length {} < {}",
71                self.length(),
72                PAYLOAD_OFFSET
73            )
74            .into());
75        }
76        Ok(())
77    }
78}
79
80impl<'a, T: AsRef<[u8]> + ?Sized> RouteNextHopBuffer<&'a T> {
81    pub fn attributes(
82        &self,
83    ) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {
84        NlasIterator::new(
85            &self.payload()[..(self.length() as usize - PAYLOAD_OFFSET)],
86        )
87    }
88}
89
90#[derive(Debug, Clone, Eq, PartialEq, Default)]
91#[non_exhaustive]
92pub struct RouteNextHop {
93    /// Next-hop flags
94    pub flags: RouteNextHopFlags,
95    /// Next-hop priority
96    pub hops: u8,
97    /// Interface index for the next-hop
98    pub interface_index: u32,
99    /// Attributes
100    pub attributes: Vec<RouteAttribute>,
101}
102
103impl<T: AsRef<[u8]>>
104    ParseableParametrized<
105        RouteNextHopBuffer<&T>,
106        (AddressFamily, RouteType, RouteLwEnCapType),
107    > for RouteNextHop
108{
109    fn parse_with_param(
110        buf: &RouteNextHopBuffer<&T>,
111        (address_family, route_type, encap_type): (
112            AddressFamily,
113            RouteType,
114            RouteLwEnCapType,
115        ),
116    ) -> Result<RouteNextHop, DecodeError> {
117        let attributes = Vec::<RouteAttribute>::parse_with_param(
118            &RouteNextHopBuffer::new_checked(buf.buffer)
119                .context("cannot parse route attributes in next-hop")?,
120            (address_family, route_type, encap_type),
121        )
122        .context("cannot parse route attributes in next-hop")?;
123        Ok(RouteNextHop {
124            flags: RouteNextHopFlags::from_bits_retain(buf.flags()),
125            hops: buf.hops(),
126            interface_index: buf.interface_index(),
127            attributes,
128        })
129    }
130}
131
132impl<'a, T: AsRef<[u8]> + 'a>
133    ParseableParametrized<
134        RouteNextHopBuffer<&'a T>,
135        (AddressFamily, RouteType, RouteLwEnCapType),
136    > for Vec<RouteAttribute>
137{
138    fn parse_with_param(
139        buf: &RouteNextHopBuffer<&'a T>,
140        (address_family, route_type, encap_type): (
141            AddressFamily,
142            RouteType,
143            RouteLwEnCapType,
144        ),
145    ) -> Result<Self, DecodeError> {
146        let mut nlas = vec![];
147        for nla_buf in buf.attributes() {
148            nlas.push(RouteAttribute::parse_with_param(
149                &nla_buf?,
150                (address_family, route_type, encap_type),
151            )?);
152        }
153        Ok(nlas)
154    }
155}
156
157impl Emitable for RouteNextHop {
158    fn buffer_len(&self) -> usize {
159        // len, flags, hops and interface id fields
160        PAYLOAD_OFFSET + self.attributes.as_slice().buffer_len()
161    }
162
163    fn emit(&self, buffer: &mut [u8]) {
164        let mut nh_buffer = RouteNextHopBuffer::new(buffer);
165        nh_buffer.set_length(self.buffer_len() as u16);
166        nh_buffer.set_flags(self.flags.bits());
167        nh_buffer.set_hops(self.hops);
168        nh_buffer.set_interface_index(self.interface_index);
169        self.attributes.as_slice().emit(nh_buffer.payload_mut())
170    }
171}