netlink_packet_route/route/
header.rs

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