1use alloc::vec::Vec;
8use core::fmt::Debug;
9use core::hash::Hash;
10use core::num::{NonZeroU16, NonZeroU8};
11use core::ops::{Deref, DerefMut};
12use core::time::Duration;
13
14use derivative::Derivative;
15use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
16use net_types::ip::{AddrSubnet, GenericOverIp, Ip, IpMarked, IpVersionMarker, Ipv4, Ipv6};
17use net_types::Witness as _;
18use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
19use netstack3_base::{
20 AssignedAddrIpExt, BroadcastIpExt, CoreTimerContext, ExistsError, Inspectable,
21 InspectableValue, Inspector, Instant, InstantBindingsTypes, IpAddressId,
22 NestedIntoCoreTimerCtx, NotFoundError, ReferenceNotifiers, TimerBindingsTypes, TimerContext,
23 WeakDeviceIdentifier,
24};
25use packet_formats::icmp::ndp::NonZeroNdpLifetime;
26use packet_formats::utils::NonZeroDuration;
27
28use crate::internal::counters::{IpCounters, IpCountersIpExt};
29use crate::internal::device::dad::{DadIpExt, DadState};
30use crate::internal::device::route_discovery::Ipv6RouteDiscoveryState;
31use crate::internal::device::router_solicitation::RsState;
32use crate::internal::device::slaac::{SlaacConfiguration, SlaacState};
33use crate::internal::device::{
34 IpDeviceAddr, IpDeviceTimerId, Ipv4DeviceTimerId, Ipv6DeviceTimerId, WeakIpAddressId,
35};
36use crate::internal::gmp::igmp::{IgmpConfig, IgmpCounters, IgmpTimerId, IgmpTypeLayout};
37use crate::internal::gmp::mld::{MldConfig, MldCounters, MldTimerId, MldTypeLayout};
38use crate::internal::gmp::{GmpGroupState, GmpState, GmpTimerId, GmpTypeLayout, MulticastGroupSet};
39use crate::internal::types::RawMetric;
40
41pub const RETRANS_TIMER_DEFAULT: NonZeroDuration = NonZeroDuration::from_secs(1).unwrap();
45
46const DEFAULT_HOP_LIMIT: NonZeroU8 = NonZeroU8::new(64).unwrap();
49
50pub trait IpDeviceStateIpExt:
52 DadIpExt + BroadcastIpExt + IpCountersIpExt + AssignedAddrIpExt
53{
54 type AddressConfig<I: Instant>: Default + Debug + Inspectable + PartialEq + Send + Sync;
56 type GmpProtoConfig: Default;
58 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes>: GmpTypeLayout<Self, BT>;
60 type GmpTimerId<D: WeakDeviceIdentifier>: From<GmpTimerId<Self, D>>;
62}
63
64impl IpDeviceStateIpExt for Ipv4 {
65 type AddressConfig<I: Instant> = Ipv4AddrConfig<I>;
66 type GmpTimerId<D: WeakDeviceIdentifier> = IgmpTimerId<D>;
67 type GmpProtoConfig = IgmpConfig;
68 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes> = IgmpTypeLayout;
69}
70
71impl IpDeviceStateIpExt for Ipv6 {
72 type AddressConfig<I: Instant> = Ipv6AddrConfig<I>;
73 type GmpTimerId<D: WeakDeviceIdentifier> = MldTimerId<D>;
74 type GmpProtoConfig = MldConfig;
75 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes> = MldTypeLayout;
76}
77
78pub struct PrimaryAddressId<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
81 PrimaryRc<IpAddressEntry<I, BT>>,
82);
83
84impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Debug for PrimaryAddressId<I, BT> {
85 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
86 let Self(rc) = self;
87 write!(f, "PrimaryAddressId({:?} => {})", rc.debug_id(), rc.addr_sub)
88 }
89}
90
91impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Deref for PrimaryAddressId<I, BT> {
92 type Target = IpAddressEntry<I, BT>;
93
94 fn deref(&self) -> &Self::Target {
95 let Self(inner) = self;
96 inner.deref()
97 }
98}
99
100impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> PrimaryAddressId<I, BT> {
101 fn new_with_strong_clone(addr: IpAddressEntry<I, BT>) -> (Self, AddressId<I, BT>) {
103 let primary = PrimaryRc::new(addr);
104 let strong = PrimaryRc::clone_strong(&primary);
105 (Self(primary), AddressId(strong))
106 }
107
108 pub fn clone_strong(&self) -> AddressId<I, BT> {
110 let Self(inner) = self;
111 AddressId(PrimaryRc::clone_strong(inner))
112 }
113
114 pub fn ptr_eq(&self, other: &AddressId<I, BT>) -> bool {
116 let Self(inner) = self;
117 let AddressId(other) = other;
118 PrimaryRc::ptr_eq(inner, other)
119 }
120
121 pub fn into_inner(self) -> PrimaryRc<IpAddressEntry<I, BT>> {
123 self.0
124 }
125
126 pub fn addr(&self) -> I::AssignedWitness {
128 let Self(inner) = self;
129 inner.addr_sub.addr()
130 }
131}
132
133#[derive(Derivative)]
135#[derivative(Clone(bound = ""), Eq(bound = ""), Hash(bound = ""), PartialEq(bound = ""))]
136pub struct AddressId<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
137 StrongRc<IpAddressEntry<I, BT>>,
138);
139
140impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Debug for AddressId<I, BT> {
141 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142 let Self(rc) = self;
143 write!(f, "AddressId({:?} => {})", rc.debug_id(), self.addr_sub)
144 }
145}
146
147impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Deref for AddressId<I, BT> {
148 type Target = IpAddressEntry<I, BT>;
149
150 fn deref(&self) -> &Self::Target {
151 let Self(inner) = self;
152 inner.deref()
153 }
154}
155
156impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpAddressId<I::Addr>
157 for AddressId<I, BT>
158{
159 type Weak = WeakAddressId<I, BT>;
160
161 fn downgrade(&self) -> Self::Weak {
162 let Self(inner) = self;
163 WeakAddressId(StrongRc::downgrade(inner))
164 }
165
166 fn addr(&self) -> IpDeviceAddr<I::Addr> {
167 let Self(inner) = self;
168 inner.addr_sub().addr().into()
169 }
170
171 fn addr_sub(&self) -> AddrSubnet<I::Addr, I::AssignedWitness> {
172 let Self(inner) = self;
173 *inner.addr_sub()
174 }
175}
176
177#[derive(Derivative)]
179#[derivative(Clone(bound = ""), Eq(bound = ""), Hash(bound = ""), PartialEq(bound = ""))]
180pub struct WeakAddressId<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
181 WeakRc<IpAddressEntry<I, BT>>,
182);
183
184impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Debug for WeakAddressId<I, BT> {
185 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
186 let Self(rc) = self;
187 if let Some(id) = self.upgrade() {
188 write!(f, "WeakAddressId({:?} => {})", rc.debug_id(), id.addr_sub)
189 } else {
190 write!(f, "WeakAddressId({:?} => {})", rc.debug_id(), I::NAME)
191 }
192 }
193}
194
195impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> InspectableValue
196 for WeakAddressId<I, BT>
197{
198 fn record<II: Inspector>(&self, name: &str, inspector: &mut II) {
199 inspector.record_debug(name, self);
200 }
201}
202
203impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> WeakIpAddressId<I::Addr>
204 for WeakAddressId<I, BT>
205{
206 type Strong = AddressId<I, BT>;
207
208 fn upgrade(&self) -> Option<Self::Strong> {
209 let Self(inner) = self;
210 inner.upgrade().map(AddressId)
211 }
212
213 fn is_assigned(&self) -> bool {
214 let Self(inner) = self;
215 inner.strong_count() != 0
216 }
217}
218
219#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
221pub struct IpDeviceFlags {
222 pub ip_enabled: bool,
224}
225
226pub struct IpDeviceMulticastGroups<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
228 pub groups: MulticastGroupSet<I::Addr, GmpGroupState<I, BT>>,
230 pub gmp: GmpState<I, I::GmpTypeLayout<BT>, BT>,
232 pub gmp_config: I::GmpProtoConfig,
234}
235
236#[derive(Copy, Clone, Debug)]
241pub struct DefaultHopLimit<I: Ip>(NonZeroU8, IpVersionMarker<I>);
242
243impl<I: Ip> Deref for DefaultHopLimit<I> {
244 type Target = NonZeroU8;
245 fn deref(&self) -> &NonZeroU8 {
246 let Self(value, IpVersionMarker { .. }) = self;
247 value
248 }
249}
250
251impl<I: Ip> DerefMut for DefaultHopLimit<I> {
252 fn deref_mut(&mut self) -> &mut NonZeroU8 {
253 let Self(value, IpVersionMarker { .. }) = self;
254 value
255 }
256}
257
258impl<I: Ip> Default for DefaultHopLimit<I> {
259 fn default() -> Self {
260 Self(DEFAULT_HOP_LIMIT, IpVersionMarker::new())
261 }
262}
263
264#[derive(GenericOverIp)]
266#[generic_over_ip(I, Ip)]
267pub struct IpDeviceState<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
268 addrs: RwLock<IpDeviceAddresses<I, BT>>,
275
276 multicast_groups: RwLock<IpDeviceMulticastGroups<I, BT>>,
278
279 default_hop_limit: RwLock<DefaultHopLimit<I>>,
282
283 flags: Mutex<IpMarked<I, IpDeviceFlags>>,
285
286 ip_counters: IpCounters<I>,
288}
289
290impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
291 OrderedLockAccess<IpDeviceAddresses<I, BT>> for DualStackIpDeviceState<BT>
292{
293 type Lock = RwLock<IpDeviceAddresses<I, BT>>;
294 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
295 OrderedLockRef::new(&self.ip_state::<I>().addrs)
296 }
297}
298
299impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
300 OrderedLockAccess<IpDeviceMulticastGroups<I, BT>> for DualStackIpDeviceState<BT>
301{
302 type Lock = RwLock<IpDeviceMulticastGroups<I, BT>>;
303 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
304 OrderedLockRef::new(&self.ip_state::<I>().multicast_groups)
305 }
306}
307
308impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> OrderedLockAccess<DefaultHopLimit<I>>
309 for DualStackIpDeviceState<BT>
310{
311 type Lock = RwLock<DefaultHopLimit<I>>;
312 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
313 OrderedLockRef::new(&self.ip_state::<I>().default_hop_limit)
314 }
315}
316
317impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
318 OrderedLockAccess<IpMarked<I, IpDeviceFlags>> for DualStackIpDeviceState<BT>
319{
320 type Lock = Mutex<IpMarked<I, IpDeviceFlags>>;
321 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
322 OrderedLockRef::new(&self.ip_state::<I>().flags)
323 }
324}
325
326impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<SlaacState<BT>>
327 for DualStackIpDeviceState<BT>
328{
329 type Lock = Mutex<SlaacState<BT>>;
330 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
331 OrderedLockRef::new(&self.ipv6.slaac_state)
332 }
333}
334
335impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpDeviceState<I, BT> {
336 #[cfg(any(test, feature = "testutils"))]
338 pub fn addrs(&self) -> &RwLock<IpDeviceAddresses<I, BT>> {
339 &self.addrs
340 }
341}
342
343impl<I: IpDeviceStateIpExt, BC: IpDeviceStateBindingsTypes + TimerContext> IpDeviceState<I, BC> {
344 fn new<D: WeakDeviceIdentifier, CC: CoreTimerContext<I::GmpTimerId<D>, BC>>(
345 bindings_ctx: &mut BC,
346 device_id: D,
347 ) -> IpDeviceState<I, BC> {
348 IpDeviceState {
349 addrs: Default::default(),
350 multicast_groups: RwLock::new(IpDeviceMulticastGroups {
351 groups: Default::default(),
352 gmp: GmpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, device_id),
353 gmp_config: Default::default(),
354 }),
355 default_hop_limit: Default::default(),
356 flags: Default::default(),
357 ip_counters: Default::default(),
358 }
359 }
360}
361
362#[derive(Derivative)]
364#[derivative(Default(bound = ""))]
365#[cfg_attr(test, derive(Debug))]
366pub struct IpDeviceAddresses<I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
367 addrs: Vec<PrimaryAddressId<I, BT>>,
368}
369
370impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpDeviceAddresses<I, BT> {
374 pub fn iter(
376 &self,
377 ) -> impl ExactSizeIterator<Item = &PrimaryAddressId<I, BT>> + ExactSizeIterator + Clone {
378 self.addrs.iter()
379 }
380
381 pub fn strong_iter(&self) -> AddressIdIter<'_, I, BT> {
383 AddressIdIter(self.addrs.iter())
384 }
385
386 pub fn add(&mut self, addr: IpAddressEntry<I, BT>) -> Result<AddressId<I, BT>, ExistsError> {
388 if self.iter().any(|a| a.addr() == addr.addr_sub.addr()) {
389 return Err(ExistsError);
390 }
391 let (primary, strong) = PrimaryAddressId::new_with_strong_clone(addr);
392 self.addrs.push(primary);
393 Ok(strong)
394 }
395
396 pub fn remove(&mut self, addr: &I::Addr) -> Result<PrimaryAddressId<I, BT>, NotFoundError> {
398 let (index, _entry): (_, &PrimaryAddressId<I, BT>) = self
399 .addrs
400 .iter()
401 .enumerate()
402 .find(|(_, entry)| entry.addr().get() == *addr)
403 .ok_or(NotFoundError)?;
404 Ok(self.addrs.remove(index))
405 }
406}
407
408pub struct AddressIdIter<'a, I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
410 core::slice::Iter<'a, PrimaryAddressId<I, BT>>,
411);
412
413impl<'a, I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Iterator
414 for AddressIdIter<'a, I, BT>
415{
416 type Item = AddressId<I, BT>;
417
418 fn next(&mut self) -> Option<Self::Item> {
419 let Self(inner) = self;
420 inner.next().map(|addr| addr.clone_strong())
421 }
422}
423
424pub struct Ipv4DeviceState<BT: IpDeviceStateBindingsTypes> {
426 ip_state: IpDeviceState<Ipv4, BT>,
427 config: RwLock<Ipv4DeviceConfiguration>,
428 igmp_counters: IgmpCounters,
429}
430
431impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv4DeviceConfiguration>
432 for DualStackIpDeviceState<BT>
433{
434 type Lock = RwLock<Ipv4DeviceConfiguration>;
435 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
436 OrderedLockRef::new(&self.ipv4.config)
437 }
438}
439
440impl<BC: IpDeviceStateBindingsTypes + TimerContext> Ipv4DeviceState<BC> {
441 fn new<D: WeakDeviceIdentifier, CC: CoreTimerContext<Ipv4DeviceTimerId<D, BC>, BC>>(
442 bindings_ctx: &mut BC,
443 device_id: D,
444 ) -> Ipv4DeviceState<BC> {
445 Ipv4DeviceState {
446 ip_state: IpDeviceState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
447 bindings_ctx,
448 device_id,
449 ),
450 config: Default::default(),
451 igmp_counters: Default::default(),
452 }
453 }
454}
455
456impl<BT: IpDeviceStateBindingsTypes> Ipv4DeviceState<BT> {
457 fn igmp_counters(&self) -> &IgmpCounters {
458 &self.igmp_counters
459 }
460}
461
462impl<BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
463 fn as_ref(&self) -> &IpDeviceState<Ipv4, BT> {
464 &self.ip_state
465 }
466}
467
468impl<BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
469 fn as_mut(&mut self) -> &mut IpDeviceState<Ipv4, BT> {
470 &mut self.ip_state
471 }
472}
473
474#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
476pub struct IpDeviceConfiguration {
477 pub gmp_enabled: bool,
485
486 pub unicast_forwarding_enabled: bool,
498
499 pub multicast_forwarding_enabled: bool,
512 pub dad_transmits: Option<NonZeroU16>,
522}
523
524#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
526pub struct Ipv4DeviceConfiguration {
527 pub ip_config: IpDeviceConfiguration,
529}
530
531impl Ipv4DeviceConfiguration {
532 pub const DEFAULT_DUPLICATE_ADDRESS_DETECTION_TRANSMITS: NonZeroU16 =
534 NonZeroU16::new(3).unwrap();
535}
536
537impl AsRef<IpDeviceConfiguration> for Ipv4DeviceConfiguration {
538 fn as_ref(&self) -> &IpDeviceConfiguration {
539 &self.ip_config
540 }
541}
542
543impl AsMut<IpDeviceConfiguration> for Ipv4DeviceConfiguration {
544 fn as_mut(&mut self) -> &mut IpDeviceConfiguration {
545 &mut self.ip_config
546 }
547}
548
549#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
551pub struct Ipv6DeviceConfiguration {
552 pub max_router_solicitations: Option<NonZeroU8>,
561
562 pub slaac_config: SlaacConfiguration,
564
565 pub ip_config: IpDeviceConfiguration,
567}
568
569impl Ipv6DeviceConfiguration {
570 pub const DEFAULT_MAX_RTR_SOLICITATIONS: NonZeroU8 = NonZeroU8::new(3).unwrap();
574
575 pub const DEFAULT_DUPLICATE_ADDRESS_DETECTION_TRANSMITS: NonZeroU16 =
579 NonZeroU16::new(1).unwrap();
580}
581
582impl AsRef<IpDeviceConfiguration> for Ipv6DeviceConfiguration {
583 fn as_ref(&self) -> &IpDeviceConfiguration {
584 &self.ip_config
585 }
586}
587
588impl AsMut<IpDeviceConfiguration> for Ipv6DeviceConfiguration {
589 fn as_mut(&mut self) -> &mut IpDeviceConfiguration {
590 &mut self.ip_config
591 }
592}
593
594impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6NetworkLearnedParameters>
595 for DualStackIpDeviceState<BT>
596{
597 type Lock = RwLock<Ipv6NetworkLearnedParameters>;
598 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
599 OrderedLockRef::new(&self.ipv6.learned_params)
600 }
601}
602
603impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6RouteDiscoveryState<BT>>
604 for DualStackIpDeviceState<BT>
605{
606 type Lock = Mutex<Ipv6RouteDiscoveryState<BT>>;
607 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
608 OrderedLockRef::new(&self.ipv6.route_discovery)
609 }
610}
611
612impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<RsState<BT>> for DualStackIpDeviceState<BT> {
613 type Lock = Mutex<RsState<BT>>;
614 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
615 OrderedLockRef::new(&self.ipv6.router_solicitations)
616 }
617}
618
619impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6DeviceConfiguration>
620 for DualStackIpDeviceState<BT>
621{
622 type Lock = RwLock<Ipv6DeviceConfiguration>;
623 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
624 OrderedLockRef::new(&self.ipv6.config)
625 }
626}
627
628#[derive(Default)]
630pub struct Ipv6NetworkLearnedParameters {
631 pub retrans_timer: Option<NonZeroDuration>,
640}
641
642impl Ipv6NetworkLearnedParameters {
643 pub fn retrans_timer_or_default(&self) -> NonZeroDuration {
646 self.retrans_timer.clone().unwrap_or(RETRANS_TIMER_DEFAULT)
647 }
648
649 pub fn reset(&mut self) {
651 *self = Default::default()
652 }
653}
654
655pub struct Ipv6DeviceState<BT: IpDeviceStateBindingsTypes> {
657 learned_params: RwLock<Ipv6NetworkLearnedParameters>,
658 route_discovery: Mutex<Ipv6RouteDiscoveryState<BT>>,
659 router_solicitations: Mutex<RsState<BT>>,
660 ip_state: IpDeviceState<Ipv6, BT>,
661 config: RwLock<Ipv6DeviceConfiguration>,
662 slaac_state: Mutex<SlaacState<BT>>,
663 mld_counters: MldCounters,
664}
665
666impl<BC: IpDeviceStateBindingsTypes + TimerContext> Ipv6DeviceState<BC> {
667 pub fn new<D: WeakDeviceIdentifier, CC: CoreTimerContext<Ipv6DeviceTimerId<D, BC>, BC>>(
668 bindings_ctx: &mut BC,
669 device_id: D,
670 ) -> Self {
671 Ipv6DeviceState {
672 learned_params: Default::default(),
673 route_discovery: Mutex::new(Ipv6RouteDiscoveryState::new::<
674 _,
675 NestedIntoCoreTimerCtx<CC, _>,
676 >(bindings_ctx, device_id.clone())),
677 router_solicitations: Default::default(),
678 ip_state: IpDeviceState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
679 bindings_ctx,
680 device_id.clone(),
681 ),
682 config: Default::default(),
683 slaac_state: Mutex::new(SlaacState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
684 bindings_ctx,
685 device_id,
686 )),
687 mld_counters: Default::default(),
688 }
689 }
690}
691
692impl<BT: IpDeviceStateBindingsTypes> Ipv6DeviceState<BT> {
693 fn mld_counters(&self) -> &MldCounters {
694 &self.mld_counters
695 }
696}
697
698impl<BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<Ipv6, BT>> for Ipv6DeviceState<BT> {
699 fn as_ref(&self) -> &IpDeviceState<Ipv6, BT> {
700 &self.ip_state
701 }
702}
703
704impl<BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<Ipv6, BT>> for Ipv6DeviceState<BT> {
705 fn as_mut(&mut self) -> &mut IpDeviceState<Ipv6, BT> {
706 &mut self.ip_state
707 }
708}
709
710pub trait IpDeviceStateBindingsTypes:
712 InstantBindingsTypes + TimerBindingsTypes + ReferenceNotifiers + 'static
713{
714}
715impl<BT> IpDeviceStateBindingsTypes for BT where
716 BT: InstantBindingsTypes + TimerBindingsTypes + ReferenceNotifiers + 'static
717{
718}
719
720pub struct DualStackIpDeviceState<BT: IpDeviceStateBindingsTypes> {
722 ipv4: Ipv4DeviceState<BT>,
724
725 ipv6: Ipv6DeviceState<BT>,
727
728 metric: RawMetric,
730}
731
732impl<BC: IpDeviceStateBindingsTypes + TimerContext> DualStackIpDeviceState<BC> {
733 pub fn new<
737 D: WeakDeviceIdentifier,
738 CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D, BC>, BC>
739 + CoreTimerContext<IpDeviceTimerId<Ipv4, D, BC>, BC>,
740 >(
741 bindings_ctx: &mut BC,
742 device_id: D,
743 metric: RawMetric,
744 ) -> Self {
745 let ipv4 = Ipv4DeviceState::new::<
746 D,
747 NestedIntoCoreTimerCtx<CC, IpDeviceTimerId<Ipv4, D, BC>>,
748 >(bindings_ctx, device_id.clone());
749 let ipv6 = Ipv6DeviceState::new::<
750 D,
751 NestedIntoCoreTimerCtx<CC, IpDeviceTimerId<Ipv6, D, BC>>,
752 >(bindings_ctx, device_id);
753 Self { ipv4, ipv6, metric }
754 }
755}
756
757impl<BT: IpDeviceStateBindingsTypes> DualStackIpDeviceState<BT> {
758 pub fn metric(&self) -> &RawMetric {
760 &self.metric
761 }
762
763 pub fn ip_state<I: IpDeviceStateIpExt>(&self) -> &IpDeviceState<I, BT> {
765 I::map_ip_out(
766 self,
767 |dual_stack| &dual_stack.ipv4.ip_state,
768 |dual_stack| &dual_stack.ipv6.ip_state,
769 )
770 }
771
772 pub fn igmp_counters(&self) -> &IgmpCounters {
774 self.ipv4.igmp_counters()
775 }
776
777 pub fn mld_counters(&self) -> &MldCounters {
779 self.ipv6.mld_counters()
780 }
781
782 pub fn ip_counters<I: IpDeviceStateIpExt>(&self) -> &IpCounters<I> {
784 &self.ip_state::<I>().ip_counters
785 }
786}
787
788#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
790pub struct TemporarySlaacConfig<Instant> {
791 pub valid_until: Instant,
793 pub desync_factor: Duration,
795 pub creation_time: Instant,
797 pub dad_counter: u8,
801}
802
803#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
805pub enum Lifetime<I> {
806 Finite(I),
808 Infinite,
810}
811
812impl<I: Instant> InspectableValue for Lifetime<I> {
813 fn record<N: Inspector>(&self, name: &str, inspector: &mut N) {
814 match self {
815 Self::Finite(instant) => inspector.record_inspectable_value(name, instant),
816 Self::Infinite => inspector.record_str(name, "infinite"),
817 }
818 }
819}
820
821impl<I: Instant> Lifetime<I> {
822 pub fn from_ndp(now: I, duration: NonZeroNdpLifetime) -> Self {
825 match duration {
826 NonZeroNdpLifetime::Finite(d) => Self::after(now, d.get()),
827 NonZeroNdpLifetime::Infinite => Self::Infinite,
828 }
829 }
830
831 pub fn after(now: I, duration: Duration) -> Self {
834 match now.checked_add(duration) {
835 Some(i) => Self::Finite(i),
836 None => Self::Infinite,
837 }
838 }
839}
840
841impl<Instant> Lifetime<Instant> {
842 pub fn map_instant<N, F: FnOnce(Instant) -> N>(self, f: F) -> Lifetime<N> {
844 match self {
845 Self::Infinite => Lifetime::Infinite,
846 Self::Finite(i) => Lifetime::Finite(f(i)),
847 }
848 }
849}
850
851#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
853pub enum PreferredLifetime<Instant> {
854 Preferred(Lifetime<Instant>),
859 Deprecated,
861}
862
863impl<Instant> PreferredLifetime<Instant> {
864 pub const fn preferred_until(instant: Instant) -> Self {
866 Self::Preferred(Lifetime::Finite(instant))
867 }
868
869 pub const fn preferred_forever() -> Self {
872 Self::Preferred(Lifetime::Infinite)
873 }
874
875 pub const fn is_deprecated(&self) -> bool {
877 match self {
878 Self::Preferred(_) => false,
879 Self::Deprecated => true,
880 }
881 }
882
883 pub fn map_instant<N, F: FnOnce(Instant) -> N>(self, f: F) -> PreferredLifetime<N> {
885 match self {
886 Self::Deprecated => PreferredLifetime::Deprecated,
887 Self::Preferred(l) => PreferredLifetime::Preferred(l.map_instant(f)),
888 }
889 }
890}
891
892impl<I: Instant> PreferredLifetime<I> {
893 pub fn preferred_for(now: I, duration: NonZeroNdpLifetime) -> Self {
896 Self::Preferred(Lifetime::from_ndp(now, duration))
897 }
898
899 pub fn maybe_preferred_for(now: I, duration: Option<NonZeroNdpLifetime>) -> Self {
902 match duration {
903 Some(d) => Self::preferred_for(now, d),
904 None => Self::Deprecated,
905 }
906 }
907}
908
909impl<Instant> Default for PreferredLifetime<Instant> {
910 fn default() -> Self {
911 Self::Preferred(Lifetime::Infinite)
912 }
913}
914
915impl<I: Instant> InspectableValue for PreferredLifetime<I> {
916 fn record<N: Inspector>(&self, name: &str, inspector: &mut N) {
917 match self {
918 Self::Deprecated => inspector.record_str(name, "deprecated"),
919 Self::Preferred(lifetime) => inspector.record_inspectable_value(name, lifetime),
920 }
921 }
922}
923
924#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
928pub struct CommonAddressProperties<Instant> {
929 pub valid_until: Lifetime<Instant>,
931 pub preferred_lifetime: PreferredLifetime<Instant>,
939}
940
941impl<I> Default for CommonAddressProperties<I> {
942 fn default() -> Self {
943 Self {
944 valid_until: Lifetime::Infinite,
945 preferred_lifetime: PreferredLifetime::preferred_forever(),
946 }
947 }
948}
949
950impl<Inst: Instant> Inspectable for CommonAddressProperties<Inst> {
951 fn record<I: Inspector>(&self, inspector: &mut I) {
952 let Self { valid_until, preferred_lifetime } = self;
953 inspector.record_inspectable_value("ValidUntil", valid_until);
954 inspector.record_inspectable_value("PreferredLifetime", preferred_lifetime);
955 }
956}
957
958#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
963pub struct CommonAddressConfig {
964 pub should_perform_dad: Option<bool>,
967}
968
969impl Inspectable for CommonAddressConfig {
970 fn record<I: Inspector>(&self, inspector: &mut I) {
971 let Self { should_perform_dad } = self;
972 if let Some(should_perform_dad) = should_perform_dad {
973 inspector.record_bool("DadOverride", *should_perform_dad);
974 }
975 }
976}
977
978#[derive(Clone, Copy, Debug, Derivative, PartialEq, Eq, Hash)]
980#[derivative(Default(bound = ""))]
981pub struct Ipv4AddrConfig<Instant> {
982 pub config: CommonAddressConfig,
984 pub properties: CommonAddressProperties<Instant>,
986}
987
988impl<Inst: Instant> Inspectable for Ipv4AddrConfig<Inst> {
989 fn record<I: Inspector>(&self, inspector: &mut I) {
990 let Self { config, properties } = self;
991 inspector.delegate_inspectable(config);
992 inspector.delegate_inspectable(properties);
993 }
994}
995
996#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
999pub enum SlaacConfig<Instant> {
1000 Stable {
1002 valid_until: Lifetime<Instant>,
1004 creation_time: Instant,
1006 regen_counter: u8,
1009 dad_counter: u8,
1011 },
1012 Temporary(TemporarySlaacConfig<Instant>),
1016}
1017
1018impl<Instant: Copy> SlaacConfig<Instant> {
1019 pub fn valid_until(&self) -> Lifetime<Instant> {
1021 match self {
1022 SlaacConfig::Stable { valid_until, .. } => *valid_until,
1023 SlaacConfig::Temporary(TemporarySlaacConfig { valid_until, .. }) => {
1024 Lifetime::Finite(*valid_until)
1025 }
1026 }
1027 }
1028}
1029
1030#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1032pub enum Ipv6AddrConfig<Instant> {
1033 Slaac(Ipv6AddrSlaacConfig<Instant>),
1035
1036 Manual(Ipv6AddrManualConfig<Instant>),
1038}
1039
1040impl<Instant> Default for Ipv6AddrConfig<Instant> {
1041 fn default() -> Self {
1042 Self::Manual(Default::default())
1043 }
1044}
1045
1046impl<Inst: Instant> Inspectable for Ipv6AddrConfig<Inst> {
1047 fn record<I: Inspector>(&self, inspector: &mut I) {
1048 match self {
1049 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig {
1051 config,
1052 properties: _,
1053 temporary: _,
1054 }) => {
1055 inspector.delegate_inspectable(config);
1056 }
1057 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { inner, preferred_lifetime: _ }) => {
1058 match inner {
1059 SlaacConfig::Stable {
1060 valid_until: _,
1061 creation_time,
1062 regen_counter,
1063 dad_counter,
1064 } => {
1065 inspector.record_inspectable_value("CreationTime", creation_time);
1066 inspector.record_uint("RegenCounter", *regen_counter);
1067 inspector.record_uint("DadCounter", *dad_counter);
1068 }
1069 SlaacConfig::Temporary(TemporarySlaacConfig {
1070 valid_until: _,
1071 desync_factor,
1072 creation_time,
1073 dad_counter,
1074 }) => {
1075 inspector.record_double("DesyncFactorSecs", desync_factor.as_secs_f64());
1076 inspector.record_uint("DadCounter", *dad_counter);
1077 inspector.record_inspectable_value("CreationTime", creation_time);
1078 }
1079 }
1080 }
1081 };
1082 inspector.record_bool("IsSlaac", self.is_slaac());
1083 inspector.record_inspectable_value("ValidUntil", &self.valid_until());
1084 inspector.record_inspectable_value("PreferredLifetime", &self.preferred_lifetime());
1085 inspector.record_bool("Temporary", self.is_temporary());
1086 }
1087}
1088
1089#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1091pub struct Ipv6AddrSlaacConfig<Instant> {
1092 pub inner: SlaacConfig<Instant>,
1094 pub preferred_lifetime: PreferredLifetime<Instant>,
1096}
1097
1098#[derive(Clone, Copy, Debug, Derivative, PartialEq, Eq, Hash)]
1100#[derivative(Default(bound = ""))]
1101pub struct Ipv6AddrManualConfig<Instant> {
1102 pub config: CommonAddressConfig,
1104 pub properties: CommonAddressProperties<Instant>,
1106 pub temporary: bool,
1110}
1111
1112impl<Instant> From<Ipv6AddrManualConfig<Instant>> for Ipv6AddrConfig<Instant> {
1113 fn from(value: Ipv6AddrManualConfig<Instant>) -> Self {
1114 Self::Manual(value)
1115 }
1116}
1117
1118impl<Instant: Copy + PartialEq> Ipv6AddrConfig<Instant> {
1119 pub fn valid_until(&self) -> Lifetime<Instant> {
1121 match self {
1122 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { inner, .. }) => inner.valid_until(),
1123 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig { properties, .. }) => {
1124 properties.valid_until
1125 }
1126 }
1127 }
1128
1129 pub fn preferred_lifetime(&self) -> PreferredLifetime<Instant> {
1131 match self {
1132 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig { properties, .. }) => {
1133 properties.preferred_lifetime
1134 }
1135 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { preferred_lifetime, .. }) => {
1136 *preferred_lifetime
1137 }
1138 }
1139 }
1140
1141 pub fn is_deprecated(&self) -> bool {
1143 self.preferred_lifetime().is_deprecated()
1144 }
1145
1146 pub fn is_temporary(&self) -> bool {
1148 match self {
1149 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { inner, .. }) => match inner {
1150 SlaacConfig::Stable { .. } => false,
1151 SlaacConfig::Temporary(_) => true,
1152 },
1153 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig { temporary, .. }) => *temporary,
1154 }
1155 }
1156
1157 pub fn is_slaac(&self) -> bool {
1159 match self {
1160 Ipv6AddrConfig::Slaac(_) => true,
1161 Ipv6AddrConfig::Manual(_) => false,
1162 }
1163 }
1164}
1165
1166#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1168pub struct IpAddressFlags {
1169 pub assigned: bool,
1171}
1172
1173#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1175pub struct IpAddressData<I: IpDeviceStateIpExt, Inst: Instant> {
1176 pub flags: IpAddressFlags,
1178 pub config: Option<I::AddressConfig<Inst>>,
1180}
1181
1182impl<I: IpDeviceStateIpExt, Inst: Instant> IpAddressData<I, Inst> {
1183 pub fn should_perform_dad(&self) -> bool {
1185 let Some(config) = self.config.as_ref() else {
1186 return false;
1189 };
1190
1191 #[derive(GenericOverIp)]
1192 #[generic_over_ip(I, Ip)]
1193 struct Wrap<'a, I: IpDeviceStateIpExt, Inst: Instant>(&'a I::AddressConfig<Inst>);
1194 let should_perform_dad = I::map_ip_in(
1195 Wrap(config),
1196 |Wrap(Ipv4AddrConfig { config, properties: _ })| config.should_perform_dad,
1197 |Wrap(config)| match config {
1198 Ipv6AddrConfig::Slaac(_) => None,
1199 Ipv6AddrConfig::Manual(c) => c.config.should_perform_dad,
1200 },
1201 );
1202
1203 should_perform_dad.unwrap_or(I::DEFAULT_DAD_ENABLED)
1204 }
1205}
1206
1207impl<I: IpDeviceStateIpExt, Inst: Instant> Inspectable for IpAddressData<I, Inst> {
1208 fn record<II: Inspector>(&self, inspector: &mut II) {
1209 let Self { flags: IpAddressFlags { assigned }, config } = self;
1210 inspector.record_bool("Assigned", *assigned);
1211 if let Some(config) = config {
1212 inspector.delegate_inspectable(config);
1213 }
1214 }
1215}
1216
1217#[derive(Derivative)]
1220#[derivative(Debug(bound = ""))]
1221pub struct IpAddressEntry<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
1222 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1223 dad_state: Mutex<DadState<I, BT>>,
1224 state: RwLock<IpAddressData<I, BT::Instant>>,
1225}
1226
1227impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpAddressEntry<I, BT> {
1228 pub fn new(
1230 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1231 dad_state: DadState<I, BT>,
1232 config: I::AddressConfig<BT::Instant>,
1233 ) -> Self {
1234 let assigned = match dad_state {
1235 DadState::Assigned => true,
1236 DadState::Tentative { .. } | DadState::Uninitialized => false,
1237 };
1238
1239 Self {
1240 addr_sub,
1241 dad_state: Mutex::new(dad_state),
1242 state: RwLock::new(IpAddressData {
1243 config: Some(config),
1244 flags: IpAddressFlags { assigned },
1245 }),
1246 }
1247 }
1248
1249 pub fn addr_sub(&self) -> &AddrSubnet<I::Addr, I::AssignedWitness> {
1251 &self.addr_sub
1252 }
1253}
1254
1255impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> OrderedLockAccess<DadState<I, BT>>
1256 for IpAddressEntry<I, BT>
1257{
1258 type Lock = Mutex<DadState<I, BT>>;
1259 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1260 OrderedLockRef::new(&self.dad_state)
1261 }
1262}
1263
1264impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
1265 OrderedLockAccess<IpAddressData<I, BT::Instant>> for IpAddressEntry<I, BT>
1266{
1267 type Lock = RwLock<IpAddressData<I, BT::Instant>>;
1268 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1269 OrderedLockRef::new(&self.state)
1270 }
1271}
1272
1273#[cfg(test)]
1274mod tests {
1275 use super::*;
1276
1277 use net_types::ip::{Ipv4Addr, Ipv6Addr};
1278 use netstack3_base::testutil::{FakeBindingsCtx, FakeInstant};
1279 use netstack3_base::InstantContext as _;
1280 use test_case::test_case;
1281
1282 type FakeBindingsCtxImpl = FakeBindingsCtx<(), (), (), ()>;
1283
1284 #[test_case(Lifetime::Infinite ; "with infinite valid_until")]
1285 #[test_case(Lifetime::Finite(FakeInstant::from(Duration::from_secs(1))); "with finite valid_until")]
1286 fn test_add_addr_ipv4(valid_until: Lifetime<FakeInstant>) {
1287 const ADDRESS: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1288 const PREFIX_LEN: u8 = 8;
1289
1290 let mut ipv4 = IpDeviceAddresses::<Ipv4, FakeBindingsCtxImpl>::default();
1291 let config = Ipv4AddrConfig {
1292 properties: CommonAddressProperties { valid_until, ..Default::default() },
1293 ..Default::default()
1294 };
1295
1296 let _: AddressId<_, _> = ipv4
1297 .add(IpAddressEntry::new(
1298 AddrSubnet::new(ADDRESS, PREFIX_LEN).unwrap(),
1299 DadState::Uninitialized,
1300 config,
1301 ))
1302 .unwrap();
1303 assert_eq!(
1305 ipv4.add(IpAddressEntry::new(
1306 AddrSubnet::new(ADDRESS, PREFIX_LEN + 1).unwrap(),
1307 DadState::Uninitialized,
1308 config,
1309 ))
1310 .unwrap_err(),
1311 ExistsError
1312 );
1313 }
1314
1315 #[test_case(Lifetime::Infinite ; "with infinite valid_until")]
1316 #[test_case(Lifetime::Finite(FakeInstant::from(Duration::from_secs(1))); "with finite valid_until")]
1317 fn test_add_addr_ipv6(valid_until: Lifetime<FakeInstant>) {
1318 const ADDRESS: Ipv6Addr =
1319 Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]);
1320 const PREFIX_LEN: u8 = 8;
1321
1322 let mut ipv6 = IpDeviceAddresses::<Ipv6, FakeBindingsCtxImpl>::default();
1323
1324 let mut bindings_ctx = FakeBindingsCtxImpl::default();
1325
1326 let _: AddressId<_, _> = ipv6
1327 .add(IpAddressEntry::new(
1328 AddrSubnet::new(ADDRESS, PREFIX_LEN).unwrap(),
1329 DadState::Tentative {
1330 dad_transmits_remaining: None,
1331 timer: bindings_ctx.new_timer(()),
1332 ip_specific_state: Default::default(),
1333 },
1334 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig {
1335 inner: SlaacConfig::Stable {
1336 valid_until,
1337 creation_time: bindings_ctx.now(),
1338 regen_counter: 0,
1339 dad_counter: 0,
1340 },
1341 preferred_lifetime: PreferredLifetime::Preferred(Lifetime::Infinite),
1342 }),
1343 ))
1344 .unwrap();
1345 assert_eq!(
1348 ipv6.add(IpAddressEntry::new(
1349 AddrSubnet::new(ADDRESS, PREFIX_LEN + 1).unwrap(),
1350 DadState::Assigned,
1351 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig {
1352 properties: CommonAddressProperties { valid_until, ..Default::default() },
1353 ..Default::default()
1354 }),
1355 ))
1356 .unwrap_err(),
1357 ExistsError,
1358 );
1359 }
1360
1361 #[test_case(None => false; "default")]
1362 #[test_case(Some(false) => false; "disabled")]
1363 #[test_case(Some(true) => true; "enabled")]
1364 fn should_perform_dad_ipv4(setting: Option<bool>) -> bool {
1365 let state = IpAddressData::<Ipv4, FakeInstant> {
1366 flags: IpAddressFlags { assigned: false },
1367 config: Some(Ipv4AddrConfig::<FakeInstant> {
1368 config: CommonAddressConfig { should_perform_dad: setting },
1369 ..Default::default()
1370 }),
1371 };
1372 state.should_perform_dad()
1373 }
1374
1375 #[test_case(None => true; "default")]
1376 #[test_case(Some(false) => false; "disabled")]
1377 #[test_case(Some(true) => true; "enabled")]
1378 fn should_perform_dad_ipv6(setting: Option<bool>) -> bool {
1379 let state = IpAddressData::<Ipv6, FakeInstant> {
1380 flags: IpAddressFlags { assigned: false },
1381 config: Some(Ipv6AddrConfig::Manual(Ipv6AddrManualConfig::<FakeInstant> {
1382 config: CommonAddressConfig { should_perform_dad: setting },
1383 ..Default::default()
1384 })),
1385 };
1386 state.should_perform_dad()
1387 }
1388}