netlink_packet_route/route/
header.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_utils::{
4    nla::{NlaBuffer, NlasIterator},
5    traits::{Emitable, Parseable},
6    DecodeError,
7};
8
9use super::{super::AddressFamily, flags::RouteFlags};
10
11const ROUTE_HEADER_LEN: usize = 12;
12
13buffer!(RouteMessageBuffer(ROUTE_HEADER_LEN) {
14    address_family: (u8, 0),
15    destination_prefix_length: (u8, 1),
16    source_prefix_length: (u8, 2),
17    tos: (u8, 3),
18    table: (u8, 4),
19    protocol: (u8, 5),
20    scope: (u8, 6),
21    kind: (u8, 7),
22    flags: (u32, 8..ROUTE_HEADER_LEN),
23    payload: (slice, ROUTE_HEADER_LEN..),
24});
25
26impl<'a, T: AsRef<[u8]> + ?Sized> RouteMessageBuffer<&'a T> {
27    pub fn attributes(
28        &self,
29    ) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {
30        NlasIterator::new(self.payload())
31    }
32}
33
34/// High level representation of `RTM_GETROUTE`, `RTM_ADDROUTE`, `RTM_DELROUTE`
35/// messages headers.
36#[derive(Debug, PartialEq, Eq, Clone, Default)]
37pub struct RouteHeader {
38    /// Address family of the route: either [AddressFamily::Inet] for IPv4,
39    /// or [AddressFamily::Inet6] for IPv6.
40    pub address_family: AddressFamily,
41    /// Prefix length of the destination subnet.
42    pub destination_prefix_length: u8,
43    /// Prefix length of the source address.
44    pub source_prefix_length: u8,
45    /// Type of service.
46    pub tos: u8,
47    /// Routing table ID.
48    pub table: u8,
49    /// Route Protocol
50    pub protocol: RouteProtocol,
51    /// Route scope
52    pub scope: RouteScope,
53    /// Route type.
54    pub kind: RouteType,
55    /// Flags when querying the kernel with a `RTM_GETROUTE` message.
56    pub flags: RouteFlags,
57}
58
59impl RouteHeader {
60    pub const RT_TABLE_MAIN: u8 = 254;
61    pub const RT_TABLE_UNSPEC: u8 = 0;
62}
63
64impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RouteMessageBuffer<&'a T>>
65    for RouteHeader
66{
67    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
68        Ok(RouteHeader {
69            address_family: buf.address_family().into(),
70            destination_prefix_length: buf.destination_prefix_length(),
71            source_prefix_length: buf.source_prefix_length(),
72            tos: buf.tos(),
73            table: buf.table(),
74            protocol: buf.protocol().into(),
75            scope: buf.scope().into(),
76            kind: buf.kind().into(),
77            flags: RouteFlags::from_bits_retain(buf.flags()),
78        })
79    }
80}
81
82impl Emitable for RouteHeader {
83    fn buffer_len(&self) -> usize {
84        ROUTE_HEADER_LEN
85    }
86
87    fn emit(&self, buffer: &mut [u8]) {
88        let mut buffer = RouteMessageBuffer::new(buffer);
89        buffer.set_address_family(self.address_family.into());
90        buffer.set_destination_prefix_length(self.destination_prefix_length);
91        buffer.set_source_prefix_length(self.source_prefix_length);
92        buffer.set_tos(self.tos);
93        buffer.set_table(self.table);
94        buffer.set_protocol(self.protocol.into());
95        buffer.set_scope(self.scope.into());
96        buffer.set_kind(self.kind.into());
97        buffer.set_flags(self.flags.bits());
98    }
99}
100
101#[derive(Debug, PartialEq, Eq, Clone, Copy)]
102#[non_exhaustive]
103pub enum RouteProtocol {
104    Unspec,
105    IcmpRedirect,
106    Kernel,
107    Boot,
108    Static,
109    Gated,
110    Ra,
111    Mrt,
112    Zebra,
113    Bird,
114    DnRouted,
115    Xorp,
116    Ntk,
117    Dhcp,
118    Mrouted,
119    KeepAlived,
120    Babel,
121    Bgp,
122    Isis,
123    Ospf,
124    Rip,
125    Eigrp,
126    Other(u8),
127}
128
129const RTPROT_UNSPEC: u8 = 0;
130const RTPROT_REDIRECT: u8 = 1;
131const RTPROT_KERNEL: u8 = 2;
132const RTPROT_BOOT: u8 = 3;
133const RTPROT_STATIC: u8 = 4;
134const RTPROT_GATED: u8 = 8;
135const RTPROT_RA: u8 = 9;
136const RTPROT_MRT: u8 = 10;
137const RTPROT_ZEBRA: u8 = 11;
138const RTPROT_BIRD: u8 = 12;
139const RTPROT_DNROUTED: u8 = 13;
140const RTPROT_XORP: u8 = 14;
141const RTPROT_NTK: u8 = 15;
142const RTPROT_DHCP: u8 = 16;
143const RTPROT_MROUTED: u8 = 17;
144const RTPROT_KEEPALIVED: u8 = 18;
145const RTPROT_BABEL: u8 = 42;
146const RTPROT_BGP: u8 = 186;
147const RTPROT_ISIS: u8 = 187;
148const RTPROT_OSPF: u8 = 188;
149const RTPROT_RIP: u8 = 189;
150const RTPROT_EIGRP: u8 = 192;
151
152impl From<RouteProtocol> for u8 {
153    fn from(t: RouteProtocol) -> u8 {
154        match t {
155            RouteProtocol::Unspec => RTPROT_UNSPEC,
156            RouteProtocol::IcmpRedirect => RTPROT_REDIRECT,
157            RouteProtocol::Kernel => RTPROT_KERNEL,
158            RouteProtocol::Boot => RTPROT_BOOT,
159            RouteProtocol::Static => RTPROT_STATIC,
160            RouteProtocol::Gated => RTPROT_GATED,
161            RouteProtocol::Ra => RTPROT_RA,
162            RouteProtocol::Mrt => RTPROT_MRT,
163            RouteProtocol::Zebra => RTPROT_ZEBRA,
164            RouteProtocol::Bird => RTPROT_BIRD,
165            RouteProtocol::DnRouted => RTPROT_DNROUTED,
166            RouteProtocol::Xorp => RTPROT_XORP,
167            RouteProtocol::Ntk => RTPROT_NTK,
168            RouteProtocol::Dhcp => RTPROT_DHCP,
169            RouteProtocol::Mrouted => RTPROT_MROUTED,
170            RouteProtocol::KeepAlived => RTPROT_KEEPALIVED,
171            RouteProtocol::Babel => RTPROT_BABEL,
172            RouteProtocol::Bgp => RTPROT_BGP,
173            RouteProtocol::Isis => RTPROT_ISIS,
174            RouteProtocol::Ospf => RTPROT_OSPF,
175            RouteProtocol::Rip => RTPROT_RIP,
176            RouteProtocol::Eigrp => RTPROT_EIGRP,
177            RouteProtocol::Other(d) => d,
178        }
179    }
180}
181
182impl From<u8> for RouteProtocol {
183    fn from(d: u8) -> Self {
184        match d {
185            RTPROT_UNSPEC => RouteProtocol::Unspec,
186            RTPROT_REDIRECT => RouteProtocol::IcmpRedirect,
187            RTPROT_KERNEL => RouteProtocol::Kernel,
188            RTPROT_BOOT => RouteProtocol::Boot,
189            RTPROT_STATIC => RouteProtocol::Static,
190            RTPROT_GATED => RouteProtocol::Gated,
191            RTPROT_RA => RouteProtocol::Ra,
192            RTPROT_MRT => RouteProtocol::Mrt,
193            RTPROT_ZEBRA => RouteProtocol::Zebra,
194            RTPROT_BIRD => RouteProtocol::Bird,
195            RTPROT_DNROUTED => RouteProtocol::DnRouted,
196            RTPROT_XORP => RouteProtocol::Xorp,
197            RTPROT_NTK => RouteProtocol::Ntk,
198            RTPROT_DHCP => RouteProtocol::Dhcp,
199            RTPROT_MROUTED => RouteProtocol::Mrouted,
200            RTPROT_KEEPALIVED => RouteProtocol::KeepAlived,
201            RTPROT_BABEL => RouteProtocol::Babel,
202            RTPROT_BGP => RouteProtocol::Bgp,
203            RTPROT_ISIS => RouteProtocol::Isis,
204            RTPROT_OSPF => RouteProtocol::Ospf,
205            RTPROT_RIP => RouteProtocol::Rip,
206            RTPROT_EIGRP => RouteProtocol::Eigrp,
207            _ => RouteProtocol::Other(d),
208        }
209    }
210}
211
212impl std::fmt::Display for RouteProtocol {
213    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214        match self {
215            Self::Unspec => write!(f, "unspec"),
216            Self::IcmpRedirect => write!(f, "icmp_redirect"),
217            Self::Kernel => write!(f, "kernel"),
218            Self::Boot => write!(f, "boot"),
219            Self::Static => write!(f, "static"),
220            Self::Gated => write!(f, "gated"),
221            Self::Ra => write!(f, "ra"),
222            Self::Mrt => write!(f, "merit_mrt"),
223            Self::Zebra => write!(f, "zebra"),
224            Self::Bird => write!(f, "bird"),
225            Self::DnRouted => write!(f, "decnet_routing_daemon"),
226            Self::Xorp => write!(f, "xorp"),
227            Self::Ntk => write!(f, "netsukuku"),
228            Self::Dhcp => write!(f, "Dhcp"),
229            Self::Mrouted => write!(f, "multicast_daemon"),
230            Self::KeepAlived => write!(f, "keepalived_daemon"),
231            Self::Babel => write!(f, "babel"),
232            Self::Bgp => write!(f, "bgp"),
233            Self::Isis => write!(f, "isis"),
234            Self::Ospf => write!(f, "ospf"),
235            Self::Rip => write!(f, "rip"),
236            Self::Eigrp => write!(f, "eigrp"),
237            Self::Other(v) => write!(f, "other({v})"),
238        }
239    }
240}
241
242impl Default for RouteProtocol {
243    fn default() -> Self {
244        Self::Unspec
245    }
246}
247
248impl Parseable<[u8]> for RouteProtocol {
249    fn parse(buf: &[u8]) -> Result<Self, DecodeError> {
250        if buf.len() == 1 {
251            Ok(Self::from(buf[0]))
252        } else {
253            Err(DecodeError::from(format!(
254                "Expecting single u8 for route protocol, but got {:?}",
255                buf
256            )))
257        }
258    }
259}
260
261impl Emitable for RouteProtocol {
262    fn buffer_len(&self) -> usize {
263        1
264    }
265
266    fn emit(&self, buffer: &mut [u8]) {
267        buffer[0] = u8::from(*self);
268    }
269}
270
271const RT_SCOPE_UNIVERSE: u8 = 0;
272const RT_SCOPE_SITE: u8 = 200;
273const RT_SCOPE_LINK: u8 = 253;
274const RT_SCOPE_HOST: u8 = 254;
275const RT_SCOPE_NOWHERE: u8 = 255;
276
277#[derive(Debug, PartialEq, Eq, Clone, Copy)]
278#[non_exhaustive]
279pub enum RouteScope {
280    Universe,
281    Site,
282    Link,
283    Host,
284    NoWhere,
285    Other(u8),
286}
287
288impl From<RouteScope> for u8 {
289    fn from(v: RouteScope) -> Self {
290        match v {
291            RouteScope::Universe => RT_SCOPE_UNIVERSE,
292            RouteScope::Site => RT_SCOPE_SITE,
293            RouteScope::Link => RT_SCOPE_LINK,
294            RouteScope::Host => RT_SCOPE_HOST,
295            RouteScope::NoWhere => RT_SCOPE_NOWHERE,
296            RouteScope::Other(s) => s,
297        }
298    }
299}
300
301impl From<u8> for RouteScope {
302    fn from(d: u8) -> Self {
303        match d {
304            RT_SCOPE_UNIVERSE => RouteScope::Universe,
305            RT_SCOPE_SITE => RouteScope::Site,
306            RT_SCOPE_LINK => RouteScope::Link,
307            RT_SCOPE_HOST => RouteScope::Host,
308            RT_SCOPE_NOWHERE => RouteScope::NoWhere,
309            _ => RouteScope::Other(d),
310        }
311    }
312}
313
314impl Default for RouteScope {
315    fn default() -> Self {
316        Self::Universe
317    }
318}
319
320impl std::fmt::Display for RouteScope {
321    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
322        match self {
323            Self::Universe => write!(f, "universe"),
324            Self::Site => write!(f, "site"),
325            Self::Link => write!(f, "link"),
326            Self::Host => write!(f, "host"),
327            Self::NoWhere => write!(f, "no_where"),
328            Self::Other(s) => write!(f, "other({s})"),
329        }
330    }
331}
332
333#[derive(Debug, PartialEq, Eq, Clone, Copy)]
334#[non_exhaustive]
335pub enum RouteType {
336    /// Unknown
337    Unspec,
338    /// Gateway or direct route
339    Unicast,
340    /// Accept locally
341    Local,
342    /// Accept locally as broadcast, send as broadcast
343    Broadcast,
344    /// Accept locally as broadcast, but send as unicast
345    Anycast,
346    /// Multicast route
347    Multicast,
348    /// Drop
349    BlackHole,
350    /// Destination is unreachable
351    Unreachable,
352    /// Administratively prohibited
353    Prohibit,
354    /// Not in this table
355    Throw,
356    /// Translate this address
357    Nat,
358    /// Use external resolver
359    ExternalResolve,
360    Other(u8),
361}
362
363const RTN_UNSPEC: u8 = 0;
364const RTN_UNICAST: u8 = 1;
365const RTN_LOCAL: u8 = 2;
366const RTN_BROADCAST: u8 = 3;
367const RTN_ANYCAST: u8 = 4;
368const RTN_MULTICAST: u8 = 5;
369const RTN_BLACKHOLE: u8 = 6;
370const RTN_UNREACHABLE: u8 = 7;
371const RTN_PROHIBIT: u8 = 8;
372const RTN_THROW: u8 = 9;
373const RTN_NAT: u8 = 10;
374const RTN_XRESOLVE: u8 = 11;
375
376impl From<u8> for RouteType {
377    fn from(d: u8) -> Self {
378        match d {
379            RTN_UNSPEC => Self::Unspec,
380            RTN_UNICAST => Self::Unicast,
381            RTN_LOCAL => Self::Local,
382            RTN_BROADCAST => Self::Broadcast,
383            RTN_ANYCAST => Self::Anycast,
384            RTN_MULTICAST => Self::Multicast,
385            RTN_BLACKHOLE => Self::BlackHole,
386            RTN_UNREACHABLE => Self::Unreachable,
387            RTN_PROHIBIT => Self::Prohibit,
388            RTN_THROW => Self::Throw,
389            RTN_NAT => Self::Nat,
390            RTN_XRESOLVE => Self::ExternalResolve,
391            _ => Self::Other(d),
392        }
393    }
394}
395
396impl Default for RouteType {
397    fn default() -> Self {
398        Self::Unspec
399    }
400}
401
402impl From<RouteType> for u8 {
403    fn from(v: RouteType) -> Self {
404        match v {
405            RouteType::Unspec => RTN_UNSPEC,
406            RouteType::Unicast => RTN_UNICAST,
407            RouteType::Local => RTN_LOCAL,
408            RouteType::Broadcast => RTN_BROADCAST,
409            RouteType::Anycast => RTN_ANYCAST,
410            RouteType::Multicast => RTN_MULTICAST,
411            RouteType::BlackHole => RTN_BLACKHOLE,
412            RouteType::Unreachable => RTN_UNREACHABLE,
413            RouteType::Prohibit => RTN_PROHIBIT,
414            RouteType::Throw => RTN_THROW,
415            RouteType::Nat => RTN_NAT,
416            RouteType::ExternalResolve => RTN_XRESOLVE,
417            RouteType::Other(d) => d,
418        }
419    }
420}