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}