1use core::fmt::{Debug, Display, Formatter};
8use core::hash::Hash;
9
10use net_types::ip::{GenericOverIp, Ip, IpAddress, Ipv4Addr, Ipv6Addr, Subnet, SubnetEither};
11use net_types::SpecifiedAddr;
12use netstack3_base::socket::SocketIpAddr;
13use netstack3_base::{BroadcastIpExt, IpDeviceAddr};
14
15#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
17pub struct RawMetric(pub u32);
18
19impl RawMetric {
20 pub const HIGHEST_PREFERENCE: Self = Self(u32::MIN);
23 pub const LOWEST_PREFERENCE: Self = Self(u32::MAX);
26}
27
28impl Display for RawMetric {
29 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
30 let RawMetric(metric) = self;
31 write!(f, "{}", metric)
32 }
33}
34
35impl From<RawMetric> for u32 {
36 fn from(RawMetric(metric): RawMetric) -> u32 {
37 metric
38 }
39}
40
41impl From<RawMetric> for u64 {
42 fn from(RawMetric(metric): RawMetric) -> u64 {
43 u64::from(metric)
44 }
45}
46
47#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
49pub enum AddableMetric {
50 MetricTracksInterface,
53 ExplicitMetric(RawMetric),
55}
56
57impl From<Metric> for AddableMetric {
58 fn from(metric: Metric) -> AddableMetric {
59 match metric {
60 Metric::MetricTracksInterface(_) => AddableMetric::MetricTracksInterface,
61 Metric::ExplicitMetric(metric) => AddableMetric::ExplicitMetric(metric),
62 }
63 }
64}
65
66#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
72#[generic_over_ip(A, IpAddress)]
73pub struct AddableEntry<A: IpAddress, D> {
74 pub subnet: Subnet<A>,
76 pub device: D,
78 pub gateway: Option<SpecifiedAddr<A>>,
80 pub metric: AddableMetric,
82}
83
84impl<D, A: IpAddress> AddableEntry<A, D> {
85 pub fn with_gateway(
87 subnet: Subnet<A>,
88 device: D,
89 gateway: SpecifiedAddr<A>,
90 metric: AddableMetric,
91 ) -> Self {
92 Self { subnet, device, gateway: Some(gateway), metric }
93 }
94
95 pub fn without_gateway(subnet: Subnet<A>, device: D, metric: AddableMetric) -> Self {
97 Self { subnet, device, gateway: None, metric }
98 }
99
100 pub fn resolve_metric(self, device_metric: RawMetric) -> Entry<A, D> {
102 let Self { subnet, device, gateway, metric } = self;
103 let metric = match metric {
104 AddableMetric::MetricTracksInterface => Metric::MetricTracksInterface(device_metric),
105 AddableMetric::ExplicitMetric(metric) => Metric::ExplicitMetric(metric),
106 };
107 Entry { subnet, device, gateway, metric }
108 }
109
110 pub fn map_device_id<D2>(self, f: impl FnOnce(D) -> D2) -> AddableEntry<A, D2> {
112 let Self { subnet, device, gateway, metric } = self;
113 AddableEntry { subnet, device: f(device), gateway, metric }
114 }
115
116 pub fn try_map_device_id<D2, E>(
118 self,
119 f: impl FnOnce(D) -> Result<D2, E>,
120 ) -> Result<AddableEntry<A, D2>, E> {
121 let Self { subnet, device, gateway, metric } = self;
122 Ok(AddableEntry { subnet, device: f(device)?, gateway, metric })
123 }
124
125 pub fn with_generation(self, generation: Generation) -> AddableEntryAndGeneration<A, D> {
127 AddableEntryAndGeneration { entry: self, generation }
128 }
129}
130
131#[allow(missing_docs)]
133#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
134#[generic_over_ip()]
135pub enum AddableEntryEither<D> {
136 V4(AddableEntry<Ipv4Addr, D>),
137 V6(AddableEntry<Ipv6Addr, D>),
138}
139
140impl<D> AddableEntryEither<D> {
141 pub fn without_gateway(subnet: SubnetEither, device: D, metric: AddableMetric) -> Self {
144 match subnet {
145 SubnetEither::V4(subnet) => {
146 AddableEntry::without_gateway(subnet, device, metric).into()
147 }
148 SubnetEither::V6(subnet) => {
149 AddableEntry::without_gateway(subnet, device, metric).into()
150 }
151 }
152 }
153}
154
155impl<A: IpAddress, D> From<AddableEntry<A, D>> for AddableEntryEither<D> {
156 fn from(entry: AddableEntry<A, D>) -> AddableEntryEither<D> {
157 A::Version::map_ip(entry, AddableEntryEither::V4, AddableEntryEither::V6)
158 }
159}
160
161#[derive(Debug, Copy, Clone, GenericOverIp)]
163#[generic_over_ip(A, IpAddress)]
164pub struct AddableEntryAndGeneration<A: IpAddress, D> {
165 pub entry: AddableEntry<A, D>,
167 pub generation: Generation,
169}
170
171impl<A: IpAddress, D> From<Entry<A, D>> for AddableEntry<A, D> {
172 fn from(Entry { subnet, device, gateway, metric }: Entry<A, D>) -> Self {
173 Self { subnet: subnet, device: device, gateway: gateway, metric: metric.into() }
174 }
175}
176
177#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
179pub enum Metric {
180 MetricTracksInterface(RawMetric),
183 ExplicitMetric(RawMetric),
185}
186
187impl Metric {
188 pub fn value(&self) -> RawMetric {
190 match self {
191 Self::MetricTracksInterface(value) => *value,
192 Self::ExplicitMetric(value) => *value,
193 }
194 }
195}
196
197#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq, Hash)]
201#[generic_over_ip(A, IpAddress)]
202pub struct Entry<A: IpAddress, D> {
203 pub subnet: Subnet<A>,
205 pub device: D,
207 pub gateway: Option<SpecifiedAddr<A>>,
210 pub metric: Metric,
212}
213
214#[derive(Debug, Copy, Clone, GenericOverIp, PartialEq, Eq)]
216#[generic_over_ip(A, IpAddress)]
217pub struct EntryAndGeneration<A: IpAddress, D> {
218 pub entry: Entry<A, D>,
220 pub generation: Generation,
222}
223
224impl<A: IpAddress, D: Debug> Display for EntryAndGeneration<A, D> {
225 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
226 let EntryAndGeneration { entry, generation: Generation(generation) } = self;
227 write!(f, "{} (generation = {})", entry, generation)
228 }
229}
230
231#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
237pub struct Generation(u64);
238
239impl Generation {
240 pub fn initial() -> Self {
242 Self(0)
243 }
244
245 pub fn next(&self) -> Generation {
247 let Self(n) = self;
248 Generation(n + 1)
249 }
250}
251
252impl<A: IpAddress, D> Entry<A, D> {
253 pub fn map_device_id<D2>(self, f: impl FnOnce(D) -> D2) -> Entry<A, D2> {
255 let Self { subnet, device, gateway, metric } = self;
256 Entry { subnet, device: f(device), gateway, metric }
257 }
258
259 pub fn with_generation(self, generation: Generation) -> EntryAndGeneration<A, D> {
261 EntryAndGeneration { entry: self, generation }
262 }
263}
264
265impl<A: IpAddress, D: Debug> Display for Entry<A, D> {
266 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
267 let Entry { subnet, device, gateway, metric } = self;
268 match gateway {
269 Some(gateway) => {
270 write!(f, "{:?} (via {}) -> {} metric {}", device, gateway, subnet, metric.value())
271 }
272 None => write!(f, "{:?} -> {} metric {}", device, subnet, metric.value()),
273 }
274 }
275}
276
277#[allow(missing_docs)]
279#[derive(Debug, Copy, Clone, Eq, GenericOverIp, PartialEq)]
280#[generic_over_ip()]
281pub enum EntryEither<D> {
282 V4(Entry<Ipv4Addr, D>),
283 V6(Entry<Ipv6Addr, D>),
284}
285
286impl<A: IpAddress, D> From<Entry<A, D>> for EntryEither<D> {
287 fn from(entry: Entry<A, D>) -> EntryEither<D> {
288 A::Version::map_ip(entry, EntryEither::V4, EntryEither::V6)
289 }
290}
291
292#[derive(PartialEq, PartialOrd, Eq, Ord)]
298pub(crate) enum OrderedLocality {
299 OnLink,
301 OffLink,
303}
304
305#[derive(PartialEq, PartialOrd, Eq, Ord)]
310pub(crate) struct OrderedEntry<'a, A: IpAddress, D> {
311 prefix_len: core::cmp::Reverse<u8>,
313 locality: OrderedLocality,
318 metric: u32,
320 generation: Generation,
322 subnet_addr: A,
325 device: &'a D,
326 gateway: Option<SpecifiedAddr<A>>,
332}
333
334impl<'a, A: IpAddress, D> From<&'a EntryAndGeneration<A, D>> for OrderedEntry<'a, A, D> {
335 fn from(entry: &'a EntryAndGeneration<A, D>) -> OrderedEntry<'a, A, D> {
336 let EntryAndGeneration { entry: Entry { subnet, device, gateway, metric }, generation } =
337 entry;
338 OrderedEntry {
339 prefix_len: core::cmp::Reverse(subnet.prefix()),
340 metric: metric.value().into(),
341 locality: gateway.map_or(OrderedLocality::OnLink, |_gateway| OrderedLocality::OffLink),
342 generation: *generation,
343 subnet_addr: subnet.network(),
344 device: &device,
345 gateway: *gateway,
346 }
347 }
348}
349
350#[derive(Debug, Copy, Clone, PartialEq, Eq)]
352pub enum NextHop<A: IpAddress>
353where
354 A::Version: BroadcastIpExt,
355{
356 RemoteAsNeighbor,
359 Gateway(SpecifiedAddr<A>),
362 Broadcast(<A::Version as BroadcastIpExt>::BroadcastMarker),
365}
366
367impl<A: IpAddress> NextHop<A>
368where
369 A::Version: BroadcastIpExt,
370{
371 pub fn is_broadcast(self) -> bool {
373 match self {
374 Self::Broadcast(_) => true,
375 Self::RemoteAsNeighbor | Self::Gateway(_) => false,
376 }
377 }
378}
379
380impl<A: IpAddress, NewIp: BroadcastIpExt> GenericOverIp<NewIp> for NextHop<A>
381where
382 A::Version: BroadcastIpExt,
383{
384 type Type = NextHop<NewIp::Addr>;
385}
386
387pub type RoutableIpAddr<A> = SocketIpAddr<A>;
389
390#[derive(Debug, Copy, Clone, PartialEq, Eq, GenericOverIp)]
392#[generic_over_ip(I, Ip)]
393pub struct ResolvedRoute<I: BroadcastIpExt, D> {
394 pub src_addr: IpDeviceAddr<I::Addr>,
397 pub device: D,
399 pub local_delivery_device: Option<D>,
404 pub next_hop: NextHop<I::Addr>,
406 pub internal_forwarding: InternalForwarding<D>,
408}
409
410#[derive(Debug, Copy, Clone, PartialEq, Eq)]
425pub enum InternalForwarding<D> {
426 Used(D),
429 NotUsed,
431}
432
433impl<D> InternalForwarding<D> {
434 pub fn map_device<F: FnOnce(D) -> O, O>(self, cb: F) -> InternalForwarding<O> {
436 match self {
437 InternalForwarding::NotUsed => InternalForwarding::NotUsed,
438 InternalForwarding::Used(d) => InternalForwarding::Used(cb(d)),
439 }
440 }
441}
442
443#[derive(Debug, Copy, Clone, PartialEq, Eq)]
448pub struct Destination<A: IpAddress, D>
449where
450 A::Version: BroadcastIpExt,
451{
452 pub next_hop: NextHop<A>,
454 pub device: D,
456}