netlink_packet_route/route/
header.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    DecodeError, Emitable, NlaBuffer, NlasIterator, Parseable,
5};
6
7use super::{super::AddressFamily, flags::RouteFlags};
8
9const ROUTE_HEADER_LEN: usize = 12;
10
11buffer!(RouteMessageBuffer(ROUTE_HEADER_LEN) {
12    address_family: (u8, 0),
13    destination_prefix_length: (u8, 1),
14    source_prefix_length: (u8, 2),
15    tos: (u8, 3),
16    table: (u8, 4),
17    protocol: (u8, 5),
18    scope: (u8, 6),
19    kind: (u8, 7),
20    flags: (u32, 8..ROUTE_HEADER_LEN),
21    payload: (slice, ROUTE_HEADER_LEN..),
22});
23
24impl<'a, T: AsRef<[u8]> + ?Sized> RouteMessageBuffer<&'a T> {
25    pub fn attributes(
26        &self,
27    ) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {
28        NlasIterator::new(self.payload())
29    }
30}
31
32/// High level representation of `RTM_GETROUTE`, `RTM_ADDROUTE`, `RTM_DELROUTE`
33/// messages headers.
34#[derive(Debug, PartialEq, Eq, Clone, Default)]
35pub struct RouteHeader {
36    /// Address family of the route: either [AddressFamily::Inet] for IPv4,
37    /// or [AddressFamily::Inet6] for IPv6.
38    pub address_family: AddressFamily,
39    /// Prefix length of the destination subnet.
40    pub destination_prefix_length: u8,
41    /// Prefix length of the source address.
42    pub source_prefix_length: u8,
43    /// Type of service.
44    pub tos: u8,
45    /// Routing table ID.
46    pub table: u8,
47    /// Route Protocol
48    pub protocol: RouteProtocol,
49    /// Route scope
50    pub scope: RouteScope,
51    /// Route type.
52    pub kind: RouteType,
53    /// Flags when querying the kernel with a `RTM_GETROUTE` message.
54    pub flags: RouteFlags,
55}
56
57impl RouteHeader {
58    pub const RT_TABLE_MAIN: u8 = 254;
59    pub const RT_TABLE_UNSPEC: u8 = 0;
60}
61
62impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RouteMessageBuffer<&'a T>>
63    for RouteHeader
64{
65    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
66        Ok(RouteHeader {
67            address_family: buf.address_family().into(),
68            destination_prefix_length: buf.destination_prefix_length(),
69            source_prefix_length: buf.source_prefix_length(),
70            tos: buf.tos(),
71            table: buf.table(),
72            protocol: buf.protocol().into(),
73            scope: buf.scope().into(),
74            kind: buf.kind().into(),
75            flags: RouteFlags::from_bits_retain(buf.flags()),
76        })
77    }
78}
79
80impl Emitable for RouteHeader {
81    fn buffer_len(&self) -> usize {
82        ROUTE_HEADER_LEN
83    }
84
85    fn emit(&self, buffer: &mut [u8]) {
86        let mut buffer = RouteMessageBuffer::new(buffer);
87        buffer.set_address_family(self.address_family.into());
88        buffer.set_destination_prefix_length(self.destination_prefix_length);
89        buffer.set_source_prefix_length(self.source_prefix_length);
90        buffer.set_tos(self.tos);
91        buffer.set_table(self.table);
92        buffer.set_protocol(self.protocol.into());
93        buffer.set_scope(self.scope.into());
94        buffer.set_kind(self.kind.into());
95        buffer.set_flags(self.flags.bits());
96    }
97}
98
99#[derive(Debug, PartialEq, Eq, Clone, Copy)]
100#[non_exhaustive]
101#[derive(Default)]
102pub enum RouteProtocol {
103    #[default]
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 Parseable<[u8]> for RouteProtocol {
243    fn parse(buf: &[u8]) -> Result<Self, DecodeError> {
244        if buf.len() == 1 {
245            Ok(Self::from(buf[0]))
246        } else {
247            Err(DecodeError::from(format!(
248                "Expecting single u8 for route protocol, but got {buf:?}"
249            )))
250        }
251    }
252}
253
254impl Emitable for RouteProtocol {
255    fn buffer_len(&self) -> usize {
256        1
257    }
258
259    fn emit(&self, buffer: &mut [u8]) {
260        buffer[0] = u8::from(*self);
261    }
262}
263
264const RT_SCOPE_UNIVERSE: u8 = 0;
265const RT_SCOPE_SITE: u8 = 200;
266const RT_SCOPE_LINK: u8 = 253;
267const RT_SCOPE_HOST: u8 = 254;
268const RT_SCOPE_NOWHERE: u8 = 255;
269
270#[derive(Debug, PartialEq, Eq, Clone, Copy)]
271#[non_exhaustive]
272#[derive(Default)]
273pub enum RouteScope {
274    #[default]
275    Universe,
276    Site,
277    Link,
278    Host,
279    NoWhere,
280    Other(u8),
281}
282
283impl From<RouteScope> for u8 {
284    fn from(v: RouteScope) -> Self {
285        match v {
286            RouteScope::Universe => RT_SCOPE_UNIVERSE,
287            RouteScope::Site => RT_SCOPE_SITE,
288            RouteScope::Link => RT_SCOPE_LINK,
289            RouteScope::Host => RT_SCOPE_HOST,
290            RouteScope::NoWhere => RT_SCOPE_NOWHERE,
291            RouteScope::Other(s) => s,
292        }
293    }
294}
295
296impl From<u8> for RouteScope {
297    fn from(d: u8) -> Self {
298        match d {
299            RT_SCOPE_UNIVERSE => RouteScope::Universe,
300            RT_SCOPE_SITE => RouteScope::Site,
301            RT_SCOPE_LINK => RouteScope::Link,
302            RT_SCOPE_HOST => RouteScope::Host,
303            RT_SCOPE_NOWHERE => RouteScope::NoWhere,
304            _ => RouteScope::Other(d),
305        }
306    }
307}
308
309impl std::fmt::Display for RouteScope {
310    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311        match self {
312            Self::Universe => write!(f, "universe"),
313            Self::Site => write!(f, "site"),
314            Self::Link => write!(f, "link"),
315            Self::Host => write!(f, "host"),
316            Self::NoWhere => write!(f, "no_where"),
317            Self::Other(s) => write!(f, "other({s})"),
318        }
319    }
320}
321
322#[derive(Debug, PartialEq, Eq, Clone, Copy)]
323#[non_exhaustive]
324#[derive(Default)]
325pub enum RouteType {
326    /// Unknown
327    #[default]
328    Unspec,
329    /// Gateway or direct route
330    Unicast,
331    /// Accept locally
332    Local,
333    /// Accept locally as broadcast, send as broadcast
334    Broadcast,
335    /// Accept locally as broadcast, but send as unicast
336    Anycast,
337    /// Multicast route
338    Multicast,
339    /// Drop
340    BlackHole,
341    /// Destination is unreachable
342    Unreachable,
343    /// Administratively prohibited
344    Prohibit,
345    /// Not in this table
346    Throw,
347    /// Translate this address
348    Nat,
349    /// Use external resolver
350    ExternalResolve,
351    Other(u8),
352}
353
354const RTN_UNSPEC: u8 = 0;
355const RTN_UNICAST: u8 = 1;
356const RTN_LOCAL: u8 = 2;
357const RTN_BROADCAST: u8 = 3;
358const RTN_ANYCAST: u8 = 4;
359const RTN_MULTICAST: u8 = 5;
360const RTN_BLACKHOLE: u8 = 6;
361const RTN_UNREACHABLE: u8 = 7;
362const RTN_PROHIBIT: u8 = 8;
363const RTN_THROW: u8 = 9;
364const RTN_NAT: u8 = 10;
365const RTN_XRESOLVE: u8 = 11;
366
367impl From<u8> for RouteType {
368    fn from(d: u8) -> Self {
369        match d {
370            RTN_UNSPEC => Self::Unspec,
371            RTN_UNICAST => Self::Unicast,
372            RTN_LOCAL => Self::Local,
373            RTN_BROADCAST => Self::Broadcast,
374            RTN_ANYCAST => Self::Anycast,
375            RTN_MULTICAST => Self::Multicast,
376            RTN_BLACKHOLE => Self::BlackHole,
377            RTN_UNREACHABLE => Self::Unreachable,
378            RTN_PROHIBIT => Self::Prohibit,
379            RTN_THROW => Self::Throw,
380            RTN_NAT => Self::Nat,
381            RTN_XRESOLVE => Self::ExternalResolve,
382            _ => Self::Other(d),
383        }
384    }
385}
386
387impl From<RouteType> for u8 {
388    fn from(v: RouteType) -> Self {
389        match v {
390            RouteType::Unspec => RTN_UNSPEC,
391            RouteType::Unicast => RTN_UNICAST,
392            RouteType::Local => RTN_LOCAL,
393            RouteType::Broadcast => RTN_BROADCAST,
394            RouteType::Anycast => RTN_ANYCAST,
395            RouteType::Multicast => RTN_MULTICAST,
396            RouteType::BlackHole => RTN_BLACKHOLE,
397            RouteType::Unreachable => RTN_UNREACHABLE,
398            RouteType::Prohibit => RTN_PROHIBIT,
399            RouteType::Throw => RTN_THROW,
400            RouteType::Nat => RTN_NAT,
401            RouteType::ExternalResolve => RTN_XRESOLVE,
402            RouteType::Other(d) => d,
403        }
404    }
405}