netlink_packet_route/rtnl/route/
header.rs

1// SPDX-License-Identifier: MIT
2
3use crate::{
4    constants::*,
5    traits::{Emitable, Parseable},
6    DecodeError,
7    RouteMessageBuffer,
8    ROUTE_HEADER_LEN,
9};
10
11bitflags! {
12    /// Flags that can be set in a `RTM_GETROUTE` ([`RtnlMessage::GetRoute`]) message.
13    pub struct RouteFlags: u32 {
14        /// If the route changes, notify the user via rtnetlink
15        const RTM_F_NOTIFY = RTM_F_NOTIFY;
16        /// This route is cloned. Cloned routes are routes coming from the cache instead of the
17        /// FIB. For IPv4, the cache was removed in Linux 3.6 (see [IPv4 route lookup on Linux] for
18        /// more information about IPv4 routing)
19        ///
20        /// [IPv4 route lookup on Linux]: https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-linux
21        const RTM_F_CLONED = RTM_F_CLONED;
22        /// Multipath equalizer (not yet implemented)
23        const RTM_F_EQUALIZE = RTM_F_EQUALIZE;
24        /// Prefix addresses
25        const RTM_F_PREFIX = RTM_F_PREFIX;
26        /// Show the table from which the lookup result comes. Note that before commit
27        /// `c36ba6603a11`, Linux would always hardcode [`RouteMessageHeader.table`] (known as
28        /// `rtmsg.rtm_table` in the kernel) to `RT_TABLE_MAIN`.
29        ///
30        /// [`RouteMessageHeader.table`]: ../struct.RouteMessageHeader.html#structfield.table
31        const RTM_F_LOOKUP_TABLE = RTM_F_LOOKUP_TABLE;
32        /// Return the full FIB lookup match (see commit `b61798130f1be5bff08712308126c2d7ebe390ef`)
33        const RTM_F_FIB_MATCH = RTM_F_FIB_MATCH;
34    }
35}
36
37impl Default for RouteFlags {
38    fn default() -> Self {
39        Self::empty()
40    }
41}
42
43/// High level representation of `RTM_GETROUTE`, `RTM_ADDROUTE`, `RTM_DELROUTE`
44/// messages headers.
45///
46/// These headers have the following structure:
47///
48/// ```no_rust
49/// 0                8                16              24               32
50/// +----------------+----------------+----------------+----------------+
51/// | address family | dest. length   | source length  |      tos       |
52/// +----------------+----------------+----------------+----------------+
53/// |     table      |   protocol     |      scope     | type (kind)    |
54/// +----------------+----------------+----------------+----------------+
55/// |                               flags                               |
56/// +----------------+----------------+----------------+----------------+
57/// ```
58///
59/// # Example
60///
61/// ```rust
62/// extern crate netlink_packet_route;
63/// use netlink_packet_route::{constants::*, RouteFlags, RouteHeader};
64///
65/// fn main() {
66///     let mut hdr = RouteHeader::default();
67///     assert_eq!(hdr.address_family, 0u8);
68///     assert_eq!(hdr.destination_prefix_length, 0u8);
69///     assert_eq!(hdr.source_prefix_length, 0u8);
70///     assert_eq!(hdr.tos, 0u8);
71///     assert_eq!(hdr.table, RT_TABLE_UNSPEC);
72///     assert_eq!(hdr.protocol, RTPROT_UNSPEC);
73///     assert_eq!(hdr.scope, RT_SCOPE_UNIVERSE);
74///     assert_eq!(hdr.kind, RTN_UNSPEC);
75///     assert_eq!(hdr.flags.bits(), 0u32);
76///
77///     // set some values
78///     hdr.destination_prefix_length = 8;
79///     hdr.table = RT_TABLE_MAIN;
80///     hdr.protocol = RTPROT_KERNEL;
81///     hdr.scope = RT_SCOPE_NOWHERE;
82///
83///     // ...
84/// }
85/// ```
86#[derive(Debug, PartialEq, Eq, Hash, Clone, Default)]
87pub struct RouteHeader {
88    /// Address family of the route: either [`AF_INET`] for IPv4 prefixes, or [`AF_INET6`] for IPv6
89    /// prefixes.
90    pub address_family: u8,
91    /// Prefix length of the destination subnet.
92    ///
93    /// Note that setting
94    pub destination_prefix_length: u8,
95    /// Prefix length of the source address.
96    ///
97    /// There could be multiple addresses from which a certain network is reachable. To decide which
98    /// source address to use to reach and address in that network, the kernel rely on the route's
99    /// source address for this destination.
100    ///
101    /// For instance, interface `if1` could have two addresses `10.0.0.1/24` and `10.0.0.128/24`,
102    /// and we could have the following routes:
103    ///
104    /// ```no_rust
105    /// 10.0.0.10/32 dev if1 scope link src 10.0.0.1
106    /// 10.0.0.11/32 dev if1 scope link src 10.0.0.1
107    /// 10.0.0.12/32 dev if1 scope link src 10.0.0.1
108    /// 10.0.0.0/24 dev if1 scope link src 10.0.0.128
109    /// ```
110    ///
111    /// It means that for `10.0.0.10`, `10.0.0.11` and `10.0.0.12` the packets will be sent with
112    /// `10.0.0.1` as source address, while for the rest of the `10.0.0.0/24` subnet, the source
113    /// address will be `10.0.0.128`
114    pub source_prefix_length: u8,
115    /// TOS filter
116    pub tos: u8,
117    /// Routing table ID. It can be one of the `RT_TABLE_*` constants or a custom table number
118    /// between 1 and 251 (included). Note that Linux supports routing table with an ID greater than
119    /// 255, in which case this attribute will be set to [`RT_TABLE_COMPAT`] and an [`Nla::Table`]
120    /// netlink attribute will be present in the message.
121    pub table: u8,
122    /// Protocol from which the route was learnt. It should be set to one of the `RTPROT_*`
123    /// constants.
124    pub protocol: u8,
125    /// The scope of the area where the addresses in the destination subnet are valid. Predefined
126    /// scope values are the `RT_SCOPE_*` constants.
127    pub scope: u8,
128    /// Route type. It should be set to one of the `RTN_*` constants.
129    pub kind: u8,
130    /// Flags when querying the kernel with a `RTM_GETROUTE` message. See [`RouteFlags`].
131    pub flags: RouteFlags,
132}
133
134impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RouteMessageBuffer<&'a T>> for RouteHeader {
135    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
136        Ok(RouteHeader {
137            address_family: buf.address_family(),
138            destination_prefix_length: buf.destination_prefix_length(),
139            source_prefix_length: buf.source_prefix_length(),
140            tos: buf.tos(),
141            table: buf.table(),
142            protocol: buf.protocol(),
143            scope: buf.scope(),
144            kind: buf.kind(),
145            flags: RouteFlags::from_bits_truncate(buf.flags()),
146        })
147    }
148}
149
150impl Emitable for RouteHeader {
151    fn buffer_len(&self) -> usize {
152        ROUTE_HEADER_LEN
153    }
154
155    fn emit(&self, buffer: &mut [u8]) {
156        let mut buffer = RouteMessageBuffer::new(buffer);
157        buffer.set_address_family(self.address_family);
158        buffer.set_destination_prefix_length(self.destination_prefix_length);
159        buffer.set_source_prefix_length(self.source_prefix_length);
160        buffer.set_tos(self.tos);
161        buffer.set_table(self.table);
162        buffer.set_protocol(self.protocol);
163        buffer.set_scope(self.scope);
164        buffer.set_kind(self.kind);
165        buffer.set_flags(self.flags.bits());
166    }
167}