1use 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#[derive(Debug, PartialEq, Eq, Clone, Default)]
35pub struct RouteHeader {
36 pub address_family: AddressFamily,
39 pub destination_prefix_length: u8,
41 pub source_prefix_length: u8,
43 pub tos: u8,
45 pub table: u8,
47 pub protocol: RouteProtocol,
49 pub scope: RouteScope,
51 pub kind: RouteType,
53 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 #[default]
328 Unspec,
329 Unicast,
331 Local,
333 Broadcast,
335 Anycast,
337 Multicast,
339 BlackHole,
341 Unreachable,
343 Prohibit,
345 Throw,
347 Nat,
349 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}