1use netlink_packet_utils::{
4 nla::{NlaBuffer, NlasIterator},
5 traits::{Emitable, Parseable},
6 DecodeError,
7};
8
9use super::{super::AddressFamily, flags::RouteFlags};
10
11const ROUTE_HEADER_LEN: usize = 12;
12
13buffer!(RouteMessageBuffer(ROUTE_HEADER_LEN) {
14 address_family: (u8, 0),
15 destination_prefix_length: (u8, 1),
16 source_prefix_length: (u8, 2),
17 tos: (u8, 3),
18 table: (u8, 4),
19 protocol: (u8, 5),
20 scope: (u8, 6),
21 kind: (u8, 7),
22 flags: (u32, 8..ROUTE_HEADER_LEN),
23 payload: (slice, ROUTE_HEADER_LEN..),
24});
25
26impl<'a, T: AsRef<[u8]> + ?Sized> RouteMessageBuffer<&'a T> {
27 pub fn attributes(
28 &self,
29 ) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {
30 NlasIterator::new(self.payload())
31 }
32}
33
34#[derive(Debug, PartialEq, Eq, Clone, Default)]
37pub struct RouteHeader {
38 pub address_family: AddressFamily,
41 pub destination_prefix_length: u8,
43 pub source_prefix_length: u8,
45 pub tos: u8,
47 pub table: u8,
49 pub protocol: RouteProtocol,
51 pub scope: RouteScope,
53 pub kind: RouteType,
55 pub flags: RouteFlags,
57}
58
59impl RouteHeader {
60 pub const RT_TABLE_MAIN: u8 = 254;
61 pub const RT_TABLE_UNSPEC: u8 = 0;
62}
63
64impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RouteMessageBuffer<&'a T>>
65 for RouteHeader
66{
67 fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
68 Ok(RouteHeader {
69 address_family: buf.address_family().into(),
70 destination_prefix_length: buf.destination_prefix_length(),
71 source_prefix_length: buf.source_prefix_length(),
72 tos: buf.tos(),
73 table: buf.table(),
74 protocol: buf.protocol().into(),
75 scope: buf.scope().into(),
76 kind: buf.kind().into(),
77 flags: RouteFlags::from_bits_retain(buf.flags()),
78 })
79 }
80}
81
82impl Emitable for RouteHeader {
83 fn buffer_len(&self) -> usize {
84 ROUTE_HEADER_LEN
85 }
86
87 fn emit(&self, buffer: &mut [u8]) {
88 let mut buffer = RouteMessageBuffer::new(buffer);
89 buffer.set_address_family(self.address_family.into());
90 buffer.set_destination_prefix_length(self.destination_prefix_length);
91 buffer.set_source_prefix_length(self.source_prefix_length);
92 buffer.set_tos(self.tos);
93 buffer.set_table(self.table);
94 buffer.set_protocol(self.protocol.into());
95 buffer.set_scope(self.scope.into());
96 buffer.set_kind(self.kind.into());
97 buffer.set_flags(self.flags.bits());
98 }
99}
100
101#[derive(Debug, PartialEq, Eq, Clone, Copy)]
102#[non_exhaustive]
103pub enum RouteProtocol {
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 Default for RouteProtocol {
243 fn default() -> Self {
244 Self::Unspec
245 }
246}
247
248impl Parseable<[u8]> for RouteProtocol {
249 fn parse(buf: &[u8]) -> Result<Self, DecodeError> {
250 if buf.len() == 1 {
251 Ok(Self::from(buf[0]))
252 } else {
253 Err(DecodeError::from(format!(
254 "Expecting single u8 for route protocol, but got {:?}",
255 buf
256 )))
257 }
258 }
259}
260
261impl Emitable for RouteProtocol {
262 fn buffer_len(&self) -> usize {
263 1
264 }
265
266 fn emit(&self, buffer: &mut [u8]) {
267 buffer[0] = u8::from(*self);
268 }
269}
270
271const RT_SCOPE_UNIVERSE: u8 = 0;
272const RT_SCOPE_SITE: u8 = 200;
273const RT_SCOPE_LINK: u8 = 253;
274const RT_SCOPE_HOST: u8 = 254;
275const RT_SCOPE_NOWHERE: u8 = 255;
276
277#[derive(Debug, PartialEq, Eq, Clone, Copy)]
278#[non_exhaustive]
279pub enum RouteScope {
280 Universe,
281 Site,
282 Link,
283 Host,
284 NoWhere,
285 Other(u8),
286}
287
288impl From<RouteScope> for u8 {
289 fn from(v: RouteScope) -> Self {
290 match v {
291 RouteScope::Universe => RT_SCOPE_UNIVERSE,
292 RouteScope::Site => RT_SCOPE_SITE,
293 RouteScope::Link => RT_SCOPE_LINK,
294 RouteScope::Host => RT_SCOPE_HOST,
295 RouteScope::NoWhere => RT_SCOPE_NOWHERE,
296 RouteScope::Other(s) => s,
297 }
298 }
299}
300
301impl From<u8> for RouteScope {
302 fn from(d: u8) -> Self {
303 match d {
304 RT_SCOPE_UNIVERSE => RouteScope::Universe,
305 RT_SCOPE_SITE => RouteScope::Site,
306 RT_SCOPE_LINK => RouteScope::Link,
307 RT_SCOPE_HOST => RouteScope::Host,
308 RT_SCOPE_NOWHERE => RouteScope::NoWhere,
309 _ => RouteScope::Other(d),
310 }
311 }
312}
313
314impl Default for RouteScope {
315 fn default() -> Self {
316 Self::Universe
317 }
318}
319
320impl std::fmt::Display for RouteScope {
321 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
322 match self {
323 Self::Universe => write!(f, "universe"),
324 Self::Site => write!(f, "site"),
325 Self::Link => write!(f, "link"),
326 Self::Host => write!(f, "host"),
327 Self::NoWhere => write!(f, "no_where"),
328 Self::Other(s) => write!(f, "other({s})"),
329 }
330 }
331}
332
333#[derive(Debug, PartialEq, Eq, Clone, Copy)]
334#[non_exhaustive]
335pub enum RouteType {
336 Unspec,
338 Unicast,
340 Local,
342 Broadcast,
344 Anycast,
346 Multicast,
348 BlackHole,
350 Unreachable,
352 Prohibit,
354 Throw,
356 Nat,
358 ExternalResolve,
360 Other(u8),
361}
362
363const RTN_UNSPEC: u8 = 0;
364const RTN_UNICAST: u8 = 1;
365const RTN_LOCAL: u8 = 2;
366const RTN_BROADCAST: u8 = 3;
367const RTN_ANYCAST: u8 = 4;
368const RTN_MULTICAST: u8 = 5;
369const RTN_BLACKHOLE: u8 = 6;
370const RTN_UNREACHABLE: u8 = 7;
371const RTN_PROHIBIT: u8 = 8;
372const RTN_THROW: u8 = 9;
373const RTN_NAT: u8 = 10;
374const RTN_XRESOLVE: u8 = 11;
375
376impl From<u8> for RouteType {
377 fn from(d: u8) -> Self {
378 match d {
379 RTN_UNSPEC => Self::Unspec,
380 RTN_UNICAST => Self::Unicast,
381 RTN_LOCAL => Self::Local,
382 RTN_BROADCAST => Self::Broadcast,
383 RTN_ANYCAST => Self::Anycast,
384 RTN_MULTICAST => Self::Multicast,
385 RTN_BLACKHOLE => Self::BlackHole,
386 RTN_UNREACHABLE => Self::Unreachable,
387 RTN_PROHIBIT => Self::Prohibit,
388 RTN_THROW => Self::Throw,
389 RTN_NAT => Self::Nat,
390 RTN_XRESOLVE => Self::ExternalResolve,
391 _ => Self::Other(d),
392 }
393 }
394}
395
396impl Default for RouteType {
397 fn default() -> Self {
398 Self::Unspec
399 }
400}
401
402impl From<RouteType> for u8 {
403 fn from(v: RouteType) -> Self {
404 match v {
405 RouteType::Unspec => RTN_UNSPEC,
406 RouteType::Unicast => RTN_UNICAST,
407 RouteType::Local => RTN_LOCAL,
408 RouteType::Broadcast => RTN_BROADCAST,
409 RouteType::Anycast => RTN_ANYCAST,
410 RouteType::Multicast => RTN_MULTICAST,
411 RouteType::BlackHole => RTN_BLACKHOLE,
412 RouteType::Unreachable => RTN_UNREACHABLE,
413 RouteType::Prohibit => RTN_PROHIBIT,
414 RouteType::Throw => RTN_THROW,
415 RouteType::Nat => RTN_NAT,
416 RouteType::ExternalResolve => RTN_XRESOLVE,
417 RouteType::Other(d) => d,
418 }
419 }
420}