netlink_packet_route/route/
header.rs

1// SPDX-License-Identifier: MIT
2
3use super::super::AddressFamily;
4use super::RouteError;
5use super::flags::RouteFlags;
6use netlink_packet_utils::DecodeError;
7use netlink_packet_utils::nla::{NlaBuffer, NlaError, NlasIterator};
8use netlink_packet_utils::traits::{Emitable, Parseable};
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 { Ok(Self::from(buf[0])) } else { Err(RouteError::ParseRouteProtocol) }
248    }
249}
250
251impl Emitable for RouteProtocol {
252    fn buffer_len(&self) -> usize {
253        1
254    }
255
256    fn emit(&self, buffer: &mut [u8]) {
257        buffer[0] = u8::from(*self);
258    }
259}
260
261const RT_SCOPE_UNIVERSE: u8 = 0;
262const RT_SCOPE_SITE: u8 = 200;
263const RT_SCOPE_LINK: u8 = 253;
264const RT_SCOPE_HOST: u8 = 254;
265const RT_SCOPE_NOWHERE: u8 = 255;
266
267#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
268#[non_exhaustive]
269pub enum RouteScope {
270    Universe,
271    Site,
272    Link,
273    Host,
274    NoWhere,
275    Other(u8),
276}
277
278impl From<RouteScope> for u8 {
279    fn from(v: RouteScope) -> Self {
280        match v {
281            RouteScope::Universe => RT_SCOPE_UNIVERSE,
282            RouteScope::Site => RT_SCOPE_SITE,
283            RouteScope::Link => RT_SCOPE_LINK,
284            RouteScope::Host => RT_SCOPE_HOST,
285            RouteScope::NoWhere => RT_SCOPE_NOWHERE,
286            RouteScope::Other(s) => s,
287        }
288    }
289}
290
291impl From<u8> for RouteScope {
292    fn from(d: u8) -> Self {
293        match d {
294            RT_SCOPE_UNIVERSE => RouteScope::Universe,
295            RT_SCOPE_SITE => RouteScope::Site,
296            RT_SCOPE_LINK => RouteScope::Link,
297            RT_SCOPE_HOST => RouteScope::Host,
298            RT_SCOPE_NOWHERE => RouteScope::NoWhere,
299            _ => RouteScope::Other(d),
300        }
301    }
302}
303
304impl Default for RouteScope {
305    fn default() -> Self {
306        Self::Universe
307    }
308}
309
310impl std::fmt::Display for RouteScope {
311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312        match self {
313            Self::Universe => write!(f, "universe"),
314            Self::Site => write!(f, "site"),
315            Self::Link => write!(f, "link"),
316            Self::Host => write!(f, "host"),
317            Self::NoWhere => write!(f, "no_where"),
318            Self::Other(s) => write!(f, "other({s})"),
319        }
320    }
321}
322
323#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
324#[non_exhaustive]
325pub enum RouteType {
326    /// Unknown
327    Unspec,
328    /// Gateway or direct route
329    Unicast,
330    /// Accept locally
331    Local,
332    /// Accept locally as broadcast, send as broadcast
333    Broadcast,
334    /// Accept locally as broadcast, but send as unicast
335    Anycast,
336    /// Multicast route
337    Multicast,
338    /// Drop
339    BlackHole,
340    /// Destination is unreachable
341    Unreachable,
342    /// Administratively prohibited
343    Prohibit,
344    /// Not in this table
345    Throw,
346    /// Translate this address
347    Nat,
348    /// Use external resolver
349    ExternalResolve,
350    Other(u8),
351}
352
353const RTN_UNSPEC: u8 = 0;
354const RTN_UNICAST: u8 = 1;
355const RTN_LOCAL: u8 = 2;
356const RTN_BROADCAST: u8 = 3;
357const RTN_ANYCAST: u8 = 4;
358const RTN_MULTICAST: u8 = 5;
359const RTN_BLACKHOLE: u8 = 6;
360const RTN_UNREACHABLE: u8 = 7;
361const RTN_PROHIBIT: u8 = 8;
362const RTN_THROW: u8 = 9;
363const RTN_NAT: u8 = 10;
364const RTN_XRESOLVE: u8 = 11;
365
366impl From<u8> for RouteType {
367    fn from(d: u8) -> Self {
368        match d {
369            RTN_UNSPEC => Self::Unspec,
370            RTN_UNICAST => Self::Unicast,
371            RTN_LOCAL => Self::Local,
372            RTN_BROADCAST => Self::Broadcast,
373            RTN_ANYCAST => Self::Anycast,
374            RTN_MULTICAST => Self::Multicast,
375            RTN_BLACKHOLE => Self::BlackHole,
376            RTN_UNREACHABLE => Self::Unreachable,
377            RTN_PROHIBIT => Self::Prohibit,
378            RTN_THROW => Self::Throw,
379            RTN_NAT => Self::Nat,
380            RTN_XRESOLVE => Self::ExternalResolve,
381            _ => Self::Other(d),
382        }
383    }
384}
385
386impl Default for RouteType {
387    fn default() -> Self {
388        Self::Unspec
389    }
390}
391
392impl From<RouteType> for u8 {
393    fn from(v: RouteType) -> Self {
394        match v {
395            RouteType::Unspec => RTN_UNSPEC,
396            RouteType::Unicast => RTN_UNICAST,
397            RouteType::Local => RTN_LOCAL,
398            RouteType::Broadcast => RTN_BROADCAST,
399            RouteType::Anycast => RTN_ANYCAST,
400            RouteType::Multicast => RTN_MULTICAST,
401            RouteType::BlackHole => RTN_BLACKHOLE,
402            RouteType::Unreachable => RTN_UNREACHABLE,
403            RouteType::Prohibit => RTN_PROHIBIT,
404            RouteType::Throw => RTN_THROW,
405            RouteType::Nat => RTN_NAT,
406            RouteType::ExternalResolve => RTN_XRESOLVE,
407            RouteType::Other(d) => d,
408        }
409    }
410}