1use core::fmt::{Debug, Display, Formatter};
8use core::hash::Hash;
9
10use net_types::SpecifiedAddr;
11use net_types::ip::{GenericOverIp, Ip, IpAddress, Ipv4Addr, Ipv6Addr, Subnet, SubnetEither};
12use netstack3_base::socket::SocketIpAddr;
13use netstack3_base::{BroadcastIpExt, IpDeviceAddr};
14
15#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
17pub enum RoutePreference {
18 Low,
20 #[default]
22 Medium,
23 High,
25}
26
27impl From<packet_formats::icmp::ndp::RoutePreference> for RoutePreference {
28 fn from(p: packet_formats::icmp::ndp::RoutePreference) -> Self {
29 match p {
30 packet_formats::icmp::ndp::RoutePreference::Low => RoutePreference::Low,
31 packet_formats::icmp::ndp::RoutePreference::Medium => RoutePreference::Medium,
32 packet_formats::icmp::ndp::RoutePreference::High => RoutePreference::High,
33 }
34 }
35}
36
37impl From<RoutePreference> for packet_formats::icmp::ndp::RoutePreference {
38 fn from(p: RoutePreference) -> Self {
39 match p {
40 RoutePreference::Low => packet_formats::icmp::ndp::RoutePreference::Low,
41 RoutePreference::Medium => packet_formats::icmp::ndp::RoutePreference::Medium,
42 RoutePreference::High => packet_formats::icmp::ndp::RoutePreference::High,
43 }
44 }
45}
46
47#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
49pub struct RawMetric(pub u32);
50
51impl RawMetric {
52 pub const HIGHEST_PREFERENCE: Self = Self(u32::MIN);
55 pub const LOWEST_PREFERENCE: Self = Self(u32::MAX);
58}
59
60impl Display for RawMetric {
61 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
62 let RawMetric(metric) = self;
63 write!(f, "{}", metric)
64 }
65}
66
67impl From<RawMetric> for u32 {
68 fn from(RawMetric(metric): RawMetric) -> u32 {
69 metric
70 }
71}
72
73impl From<RawMetric> for u64 {
74 fn from(RawMetric(metric): RawMetric) -> u64 {
75 u64::from(metric)
76 }
77}
78
79#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
81pub enum AddableMetric {
82 MetricTracksInterface,
85 ExplicitMetric(RawMetric),
87}
88
89impl From<Metric> for AddableMetric {
90 fn from(metric: Metric) -> AddableMetric {
91 match metric {
92 Metric::MetricTracksInterface(_) => AddableMetric::MetricTracksInterface,
93 Metric::ExplicitMetric(metric) => AddableMetric::ExplicitMetric(metric),
94 }
95 }
96}
97
98#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
104#[generic_over_ip(A, IpAddress)]
105pub struct AddableEntry<A: IpAddress, D> {
106 pub subnet: Subnet<A>,
108 pub device: D,
110 pub gateway: Option<SpecifiedAddr<A>>,
112 pub metric: AddableMetric,
114 pub route_preference: RoutePreference,
117}
118
119impl<D, A: IpAddress> AddableEntry<A, D> {
120 pub fn with_gateway(
122 subnet: Subnet<A>,
123 device: D,
124 gateway: SpecifiedAddr<A>,
125 metric: AddableMetric,
126 ) -> Self {
127 Self {
128 subnet,
129 device,
130 gateway: Some(gateway),
131 metric,
132 route_preference: Default::default(),
133 }
134 }
135
136 pub fn without_gateway(subnet: Subnet<A>, device: D, metric: AddableMetric) -> Self {
138 Self { subnet, device, gateway: None, metric, route_preference: Default::default() }
139 }
140
141 pub fn resolve_metric(self, device_metric: RawMetric) -> Entry<A, D> {
143 let Self { subnet, device, gateway, metric, route_preference } = self;
144 let metric = match metric {
145 AddableMetric::MetricTracksInterface => Metric::MetricTracksInterface(device_metric),
146 AddableMetric::ExplicitMetric(metric) => Metric::ExplicitMetric(metric),
147 };
148 Entry { subnet, device, gateway, metric, route_preference }
149 }
150
151 pub fn map_device_id<D2>(self, f: impl FnOnce(D) -> D2) -> AddableEntry<A, D2> {
153 let Self { subnet, device, gateway, metric, route_preference } = self;
154 AddableEntry { subnet, device: f(device), gateway, metric, route_preference }
155 }
156
157 pub fn try_map_device_id<D2, E>(
159 self,
160 f: impl FnOnce(D) -> Result<D2, E>,
161 ) -> Result<AddableEntry<A, D2>, E> {
162 let Self { subnet, device, gateway, metric, route_preference } = self;
163 Ok(AddableEntry { subnet, device: f(device)?, gateway, metric, route_preference })
164 }
165
166 pub fn with_generation(self, generation: Generation) -> AddableEntryAndGeneration<A, D> {
168 AddableEntryAndGeneration { entry: self, generation }
169 }
170}
171
172#[allow(missing_docs)]
174#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
175#[generic_over_ip()]
176pub enum AddableEntryEither<D> {
177 V4(AddableEntry<Ipv4Addr, D>),
178 V6(AddableEntry<Ipv6Addr, D>),
179}
180
181impl<D> AddableEntryEither<D> {
182 pub fn without_gateway(subnet: SubnetEither, device: D, metric: AddableMetric) -> Self {
185 match subnet {
186 SubnetEither::V4(subnet) => {
187 AddableEntry::without_gateway(subnet, device, metric).into()
188 }
189 SubnetEither::V6(subnet) => {
190 AddableEntry::without_gateway(subnet, device, metric).into()
191 }
192 }
193 }
194}
195
196impl<A: IpAddress, D> From<AddableEntry<A, D>> for AddableEntryEither<D> {
197 fn from(entry: AddableEntry<A, D>) -> AddableEntryEither<D> {
198 A::Version::map_ip(entry, AddableEntryEither::V4, AddableEntryEither::V6)
199 }
200}
201
202#[derive(Debug, Copy, Clone, GenericOverIp)]
204#[generic_over_ip(A, IpAddress)]
205pub struct AddableEntryAndGeneration<A: IpAddress, D> {
206 pub entry: AddableEntry<A, D>,
208 pub generation: Generation,
210}
211
212impl<A: IpAddress, D> From<Entry<A, D>> for AddableEntry<A, D> {
213 fn from(Entry { subnet, device, gateway, metric, route_preference }: Entry<A, D>) -> Self {
214 Self {
215 subnet: subnet,
216 device: device,
217 gateway: gateway,
218 metric: metric.into(),
219 route_preference,
220 }
221 }
222}
223
224#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
226pub enum Metric {
227 MetricTracksInterface(RawMetric),
230 ExplicitMetric(RawMetric),
232}
233
234impl Metric {
235 pub fn value(&self) -> RawMetric {
237 match self {
238 Self::MetricTracksInterface(value) => *value,
239 Self::ExplicitMetric(value) => *value,
240 }
241 }
242}
243
244#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
248#[generic_over_ip(A, IpAddress)]
249pub struct Entry<A: IpAddress, D> {
250 pub subnet: Subnet<A>,
252 pub device: D,
254 pub gateway: Option<SpecifiedAddr<A>>,
257 pub metric: Metric,
259 pub route_preference: RoutePreference,
261}
262
263#[derive(Debug, Copy, Clone, GenericOverIp, PartialEq, Eq)]
265#[generic_over_ip(A, IpAddress)]
266pub struct EntryAndGeneration<A: IpAddress, D> {
267 pub entry: Entry<A, D>,
269 pub generation: Generation,
271}
272
273impl<A: IpAddress, D: Debug> Display for EntryAndGeneration<A, D> {
274 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
275 let EntryAndGeneration { entry, generation: Generation(generation) } = self;
276 write!(f, "{} (generation = {})", entry, generation)
277 }
278}
279
280#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
286pub struct Generation(u64);
287
288impl Generation {
289 pub fn initial() -> Self {
291 Self(0)
292 }
293
294 pub fn next(&self) -> Generation {
296 let Self(n) = self;
297 Generation(n + 1)
298 }
299}
300
301impl<A: IpAddress, D> Entry<A, D> {
302 pub fn map_device_id<D2>(self, f: impl FnOnce(D) -> D2) -> Entry<A, D2> {
304 let Self { subnet, device, gateway, metric, route_preference } = self;
305 Entry { subnet, device: f(device), gateway, metric, route_preference }
306 }
307
308 pub fn with_generation(self, generation: Generation) -> EntryAndGeneration<A, D> {
310 EntryAndGeneration { entry: self, generation }
311 }
312}
313
314impl<A: IpAddress, D: Debug> Display for Entry<A, D> {
315 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
316 let Entry { subnet, device, gateway, metric, route_preference } = self;
317 match gateway {
318 Some(gateway) => {
319 write!(
320 f,
321 "{:?} (via {}) -> {} metric {} pref {:?}",
322 device,
323 gateway,
324 subnet,
325 metric.value(),
326 route_preference
327 )
328 }
329 None => write!(
330 f,
331 "{:?} -> {} metric {} pref {:?}",
332 device,
333 subnet,
334 metric.value(),
335 route_preference
336 ),
337 }
338 }
339}
340
341#[allow(missing_docs)]
343#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq)]
344#[generic_over_ip()]
345pub enum EntryEither<D> {
346 V4(Entry<Ipv4Addr, D>),
347 V6(Entry<Ipv6Addr, D>),
348}
349
350impl<A: IpAddress, D> From<Entry<A, D>> for EntryEither<D> {
351 fn from(entry: Entry<A, D>) -> EntryEither<D> {
352 A::Version::map_ip(entry, EntryEither::V4, EntryEither::V6)
353 }
354}
355
356#[derive(PartialEq, PartialOrd, Eq, Ord)]
362pub(crate) enum OrderedLocality {
363 OnLink,
365 OffLink,
367}
368
369#[derive(PartialEq, PartialOrd, Eq, Ord)]
374pub(crate) struct OrderedEntry<'a, A: IpAddress, D> {
375 prefix_len: core::cmp::Reverse<u8>,
377 locality: OrderedLocality,
382 metric: u32,
384 route_preference: core::cmp::Reverse<RoutePreference>,
386 generation: Generation,
388 subnet_addr: A,
391 device: &'a D,
392 gateway: Option<SpecifiedAddr<A>>,
398}
399
400impl<'a, A: IpAddress, D> From<&'a EntryAndGeneration<A, D>> for OrderedEntry<'a, A, D> {
401 fn from(entry: &'a EntryAndGeneration<A, D>) -> OrderedEntry<'a, A, D> {
402 let EntryAndGeneration {
403 entry: Entry { subnet, device, gateway, metric, route_preference },
404 generation,
405 } = entry;
406 OrderedEntry {
407 prefix_len: core::cmp::Reverse(subnet.prefix()),
408 locality: gateway.map_or(OrderedLocality::OnLink, |_gateway| OrderedLocality::OffLink),
409 route_preference: core::cmp::Reverse(*route_preference),
410 metric: metric.value().into(),
411 generation: *generation,
412 subnet_addr: subnet.network(),
413 device: &device,
414 gateway: *gateway,
415 }
416 }
417}
418
419#[derive(Debug, Copy, Clone, PartialEq, Eq)]
421pub enum NextHop<A: IpAddress>
422where
423 A::Version: BroadcastIpExt,
424{
425 RemoteAsNeighbor,
428 Gateway(SpecifiedAddr<A>),
431 Broadcast(<A::Version as BroadcastIpExt>::BroadcastMarker),
434}
435
436impl<A: IpAddress> NextHop<A>
437where
438 A::Version: BroadcastIpExt,
439{
440 pub fn is_broadcast(self) -> bool {
442 match self {
443 Self::Broadcast(_) => true,
444 Self::RemoteAsNeighbor | Self::Gateway(_) => false,
445 }
446 }
447}
448
449impl<A: IpAddress, NewIp: BroadcastIpExt> GenericOverIp<NewIp> for NextHop<A>
450where
451 A::Version: BroadcastIpExt,
452{
453 type Type = NextHop<NewIp::Addr>;
454}
455
456pub type RoutableIpAddr<A> = SocketIpAddr<A>;
458
459#[derive(Debug, Copy, Clone, PartialEq, Eq, GenericOverIp)]
461#[generic_over_ip(I, Ip)]
462pub struct ResolvedRoute<I: BroadcastIpExt, D> {
463 pub src_addr: IpDeviceAddr<I::Addr>,
466 pub device: D,
468 pub local_delivery_device: Option<D>,
473 pub next_hop: NextHop<I::Addr>,
475 pub internal_forwarding: InternalForwarding<D>,
477}
478
479#[derive(Debug, Copy, Clone, PartialEq, Eq)]
494pub enum InternalForwarding<D> {
495 Used(D),
498 NotUsed,
500}
501
502impl<D> InternalForwarding<D> {
503 pub fn map_device<F: FnOnce(D) -> O, O>(self, cb: F) -> InternalForwarding<O> {
505 match self {
506 InternalForwarding::NotUsed => InternalForwarding::NotUsed,
507 InternalForwarding::Used(d) => InternalForwarding::Used(cb(d)),
508 }
509 }
510}
511
512#[derive(Debug, Copy, Clone, PartialEq, Eq)]
517pub struct Destination<A: IpAddress, D>
518where
519 A::Version: BroadcastIpExt,
520{
521 pub next_hop: NextHop<A>,
523 pub device: D,
525}