netlink_packet_route/rtnl/route/header.rs
1// SPDX-License-Identifier: MIT
2
3use netlink_packet_utils::{
4 traits::{Emitable, Parseable},
5 DecodeError,
6};
7
8use crate::{constants::*, RouteMessageBuffer, ROUTE_HEADER_LEN};
9
10bitflags! {
11 /// Flags that can be set in a `RTM_GETROUTE` ([`RtnlMessage::GetRoute`]) message.
12 #[non_exhaustive]
13pub 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
89 /// [`AF_INET6`] for IPv6 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
98 /// reachable. To decide which source address to use to reach and
99 /// address in that network, the kernel rely on the route's
100 /// source address for this destination.
101 ///
102 /// For instance, interface `if1` could have two addresses `10.0.0.1/24`
103 /// and `10.0.0.128/24`, and we could have the following routes:
104 ///
105 /// ```no_rust
106 /// 10.0.0.10/32 dev if1 scope link src 10.0.0.1
107 /// 10.0.0.11/32 dev if1 scope link src 10.0.0.1
108 /// 10.0.0.12/32 dev if1 scope link src 10.0.0.1
109 /// 10.0.0.0/24 dev if1 scope link src 10.0.0.128
110 /// ```
111 ///
112 /// It means that for `10.0.0.10`, `10.0.0.11` and `10.0.0.12` the packets
113 /// will be sent with `10.0.0.1` as source address, while for the rest
114 /// of the `10.0.0.0/24` subnet, the source address will be
115 /// `10.0.0.128`
116 pub source_prefix_length: u8,
117 /// TOS filter
118 pub tos: u8,
119 /// Routing table ID. It can be one of the `RT_TABLE_*` constants or a
120 /// custom table number between 1 and 251 (included). Note that Linux
121 /// supports routing table with an ID greater than 255, in which case
122 /// this attribute will be set to [`RT_TABLE_COMPAT`] and an [`Nla::Table`]
123 /// netlink attribute will be present in the message.
124 pub table: u8,
125 /// Protocol from which the route was learnt. It should be set to one of
126 /// the `RTPROT_*` constants.
127 pub protocol: u8,
128 /// The scope of the area where the addresses in the destination subnet are
129 /// valid. Predefined scope values are the `RT_SCOPE_*` constants.
130 pub scope: u8,
131 /// Route type. It should be set to one of the `RTN_*` constants.
132 pub kind: u8,
133 /// Flags when querying the kernel with a `RTM_GETROUTE` message. See
134 /// [`RouteFlags`].
135 pub flags: RouteFlags,
136}
137
138impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RouteMessageBuffer<&'a T>>
139 for RouteHeader
140{
141 fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
142 Ok(RouteHeader {
143 address_family: buf.address_family(),
144 destination_prefix_length: buf.destination_prefix_length(),
145 source_prefix_length: buf.source_prefix_length(),
146 tos: buf.tos(),
147 table: buf.table(),
148 protocol: buf.protocol(),
149 scope: buf.scope(),
150 kind: buf.kind(),
151 flags: RouteFlags::from_bits_truncate(buf.flags()),
152 })
153 }
154}
155
156impl Emitable for RouteHeader {
157 fn buffer_len(&self) -> usize {
158 ROUTE_HEADER_LEN
159 }
160
161 fn emit(&self, buffer: &mut [u8]) {
162 let mut buffer = RouteMessageBuffer::new(buffer);
163 buffer.set_address_family(self.address_family);
164 buffer.set_destination_prefix_length(self.destination_prefix_length);
165 buffer.set_source_prefix_length(self.source_prefix_length);
166 buffer.set_tos(self.tos);
167 buffer.set_table(self.table);
168 buffer.set_protocol(self.protocol);
169 buffer.set_scope(self.scope);
170 buffer.set_kind(self.kind);
171 buffer.set_flags(self.flags.bits());
172 }
173}