1use alloc::vec::Vec;
8use core::fmt::Debug;
9use core::hash::Hash;
10use core::num::{NonZeroU8, NonZeroU16};
11use core::ops::{Deref, DerefMut};
12use core::time::Duration;
13
14use derivative::Derivative;
15use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
16use net_types::Witness as _;
17use net_types::ip::{AddrSubnet, GenericOverIp, Ip, IpMarked, IpVersionMarker, Ipv4, Ipv6};
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::{
31 Ipv6RouteDiscoveryState, RouteDiscoveryConfiguration,
32};
33use crate::internal::device::router_solicitation::RsState;
34use crate::internal::device::slaac::{SlaacConfiguration, SlaacState};
35use crate::internal::device::{
36 IpDeviceAddr, IpDeviceTimerId, Ipv4DeviceTimerId, Ipv6DeviceTimerId, WeakIpAddressId,
37};
38use crate::internal::gmp::igmp::{IgmpConfig, IgmpCounters, IgmpTimerId, IgmpTypeLayout};
39use crate::internal::gmp::mld::{MldConfig, MldCounters, MldTimerId, MldTypeLayout};
40use crate::internal::gmp::{GmpGroupState, GmpState, GmpTimerId, GmpTypeLayout, MulticastGroupSet};
41use crate::internal::types::RawMetric;
42
43const DEFAULT_HOP_LIMIT: NonZeroU8 = NonZeroU8::new(64).unwrap();
46
47pub trait IpDeviceStateIpExt:
49 DadIpExt + BroadcastIpExt + IpCountersIpExt + AssignedAddrIpExt
50{
51 type AddressConfig<I: Instant>: Default + Debug + Inspectable + PartialEq + Send + Sync;
53 type GmpProtoConfig: Default;
55 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes>: GmpTypeLayout<Self, BT>;
57 type GmpTimerId<D: WeakDeviceIdentifier>: From<GmpTimerId<Self, D>>;
59}
60
61impl IpDeviceStateIpExt for Ipv4 {
62 type AddressConfig<I: Instant> = Ipv4AddrConfig<I>;
63 type GmpTimerId<D: WeakDeviceIdentifier> = IgmpTimerId<D>;
64 type GmpProtoConfig = IgmpConfig;
65 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes> = IgmpTypeLayout;
66}
67
68impl IpDeviceStateIpExt for Ipv6 {
69 type AddressConfig<I: Instant> = Ipv6AddrConfig<I>;
70 type GmpTimerId<D: WeakDeviceIdentifier> = MldTimerId<D>;
71 type GmpProtoConfig = MldConfig;
72 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes> = MldTypeLayout;
73}
74
75pub struct PrimaryAddressId<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
78 PrimaryRc<IpAddressEntry<I, BT>>,
79);
80
81impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Debug for PrimaryAddressId<I, BT> {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 let Self(rc) = self;
84 write!(f, "PrimaryAddressId({:?} => {})", rc.debug_id(), rc.addr_sub)
85 }
86}
87
88impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Deref for PrimaryAddressId<I, BT> {
89 type Target = IpAddressEntry<I, BT>;
90
91 fn deref(&self) -> &Self::Target {
92 let Self(inner) = self;
93 inner.deref()
94 }
95}
96
97impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> PrimaryAddressId<I, BT> {
98 fn new_with_strong_clone(addr: IpAddressEntry<I, BT>) -> (Self, AddressId<I, BT>) {
100 let primary = PrimaryRc::new(addr);
101 let strong = PrimaryRc::clone_strong(&primary);
102 (Self(primary), AddressId(strong))
103 }
104
105 pub fn clone_strong(&self) -> AddressId<I, BT> {
107 let Self(inner) = self;
108 AddressId(PrimaryRc::clone_strong(inner))
109 }
110
111 pub fn ptr_eq(&self, other: &AddressId<I, BT>) -> bool {
113 let Self(inner) = self;
114 let AddressId(other) = other;
115 PrimaryRc::ptr_eq(inner, other)
116 }
117
118 pub fn into_inner(self) -> PrimaryRc<IpAddressEntry<I, BT>> {
120 self.0
121 }
122
123 pub fn addr(&self) -> I::AssignedWitness {
125 let Self(inner) = self;
126 inner.addr_sub.addr()
127 }
128}
129
130#[derive(Derivative)]
132#[derivative(Clone(bound = ""), Eq(bound = ""), Hash(bound = ""), PartialEq(bound = ""))]
133pub struct AddressId<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
134 StrongRc<IpAddressEntry<I, BT>>,
135);
136
137impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Debug for AddressId<I, BT> {
138 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
139 let Self(rc) = self;
140 write!(f, "AddressId({:?} => {})", rc.debug_id(), self.addr_sub)
141 }
142}
143
144impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Deref for AddressId<I, BT> {
145 type Target = IpAddressEntry<I, BT>;
146
147 fn deref(&self) -> &Self::Target {
148 let Self(inner) = self;
149 inner.deref()
150 }
151}
152
153impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpAddressId<I::Addr>
154 for AddressId<I, BT>
155{
156 type Weak = WeakAddressId<I, BT>;
157
158 fn downgrade(&self) -> Self::Weak {
159 let Self(inner) = self;
160 WeakAddressId(StrongRc::downgrade(inner))
161 }
162
163 fn addr(&self) -> IpDeviceAddr<I::Addr> {
164 let Self(inner) = self;
165 inner.addr_sub().addr().into()
166 }
167
168 fn addr_sub(&self) -> AddrSubnet<I::Addr, I::AssignedWitness> {
169 let Self(inner) = self;
170 *inner.addr_sub()
171 }
172}
173
174#[derive(Derivative)]
176#[derivative(Clone(bound = ""), Eq(bound = ""), Hash(bound = ""), PartialEq(bound = ""))]
177pub struct WeakAddressId<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
178 WeakRc<IpAddressEntry<I, BT>>,
179);
180
181impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Debug for WeakAddressId<I, BT> {
182 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
183 let Self(rc) = self;
184 if let Some(id) = self.upgrade() {
185 write!(f, "WeakAddressId({:?} => {})", rc.debug_id(), id.addr_sub)
186 } else {
187 write!(f, "WeakAddressId({:?} => {})", rc.debug_id(), I::NAME)
188 }
189 }
190}
191
192impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> InspectableValue
193 for WeakAddressId<I, BT>
194{
195 fn record<II: Inspector>(&self, name: &str, inspector: &mut II) {
196 inspector.record_debug(name, self);
197 }
198}
199
200impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> WeakIpAddressId<I::Addr>
201 for WeakAddressId<I, BT>
202{
203 type Strong = AddressId<I, BT>;
204
205 fn upgrade(&self) -> Option<Self::Strong> {
206 let Self(inner) = self;
207 inner.upgrade().map(AddressId)
208 }
209
210 fn is_assigned(&self) -> bool {
211 let Self(inner) = self;
212 inner.strong_count() != 0
213 }
214}
215
216#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
218pub struct IpDeviceFlags {
219 pub ip_enabled: bool,
221}
222
223pub struct IpDeviceMulticastGroups<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
225 pub groups: MulticastGroupSet<I::Addr, GmpGroupState<I, BT>>,
227 pub gmp: GmpState<I, I::GmpTypeLayout<BT>, BT>,
229 pub gmp_config: I::GmpProtoConfig,
231}
232
233#[derive(Copy, Clone, Debug)]
238pub struct DefaultHopLimit<I: Ip>(NonZeroU8, IpVersionMarker<I>);
239
240impl<I: Ip> Deref for DefaultHopLimit<I> {
241 type Target = NonZeroU8;
242 fn deref(&self) -> &NonZeroU8 {
243 let Self(value, IpVersionMarker { .. }) = self;
244 value
245 }
246}
247
248impl<I: Ip> DerefMut for DefaultHopLimit<I> {
249 fn deref_mut(&mut self) -> &mut NonZeroU8 {
250 let Self(value, IpVersionMarker { .. }) = self;
251 value
252 }
253}
254
255impl<I: Ip> Default for DefaultHopLimit<I> {
256 fn default() -> Self {
257 Self(DEFAULT_HOP_LIMIT, IpVersionMarker::new())
258 }
259}
260
261#[derive(GenericOverIp)]
263#[generic_over_ip(I, Ip)]
264pub struct IpDeviceState<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
265 addrs: RwLock<IpDeviceAddresses<I, BT>>,
272
273 multicast_groups: RwLock<IpDeviceMulticastGroups<I, BT>>,
275
276 default_hop_limit: RwLock<DefaultHopLimit<I>>,
279
280 flags: Mutex<IpMarked<I, IpDeviceFlags>>,
282
283 ip_counters: IpCounters<I>,
285}
286
287impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
288 OrderedLockAccess<IpDeviceAddresses<I, BT>> for DualStackIpDeviceState<BT>
289{
290 type Lock = RwLock<IpDeviceAddresses<I, BT>>;
291 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
292 OrderedLockRef::new(&self.ip_state::<I>().addrs)
293 }
294}
295
296impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
297 OrderedLockAccess<IpDeviceMulticastGroups<I, BT>> for DualStackIpDeviceState<BT>
298{
299 type Lock = RwLock<IpDeviceMulticastGroups<I, BT>>;
300 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
301 OrderedLockRef::new(&self.ip_state::<I>().multicast_groups)
302 }
303}
304
305impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> OrderedLockAccess<DefaultHopLimit<I>>
306 for DualStackIpDeviceState<BT>
307{
308 type Lock = RwLock<DefaultHopLimit<I>>;
309 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
310 OrderedLockRef::new(&self.ip_state::<I>().default_hop_limit)
311 }
312}
313
314impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
315 OrderedLockAccess<IpMarked<I, IpDeviceFlags>> for DualStackIpDeviceState<BT>
316{
317 type Lock = Mutex<IpMarked<I, IpDeviceFlags>>;
318 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
319 OrderedLockRef::new(&self.ip_state::<I>().flags)
320 }
321}
322
323impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<SlaacState<BT>>
324 for DualStackIpDeviceState<BT>
325{
326 type Lock = Mutex<SlaacState<BT>>;
327 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
328 OrderedLockRef::new(&self.ipv6.slaac_state)
329 }
330}
331
332impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpDeviceState<I, BT> {
333 #[cfg(any(test, feature = "testutils"))]
335 pub fn addrs(&self) -> &RwLock<IpDeviceAddresses<I, BT>> {
336 &self.addrs
337 }
338}
339
340impl<I: IpDeviceStateIpExt, BC: IpDeviceStateBindingsTypes + TimerContext> IpDeviceState<I, BC> {
341 fn new<D: WeakDeviceIdentifier, CC: CoreTimerContext<I::GmpTimerId<D>, BC>>(
342 bindings_ctx: &mut BC,
343 device_id: D,
344 ) -> IpDeviceState<I, BC> {
345 IpDeviceState {
346 addrs: Default::default(),
347 multicast_groups: RwLock::new(IpDeviceMulticastGroups {
348 groups: Default::default(),
349 gmp: GmpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, device_id),
350 gmp_config: Default::default(),
351 }),
352 default_hop_limit: Default::default(),
353 flags: Default::default(),
354 ip_counters: Default::default(),
355 }
356 }
357}
358
359#[derive(Derivative)]
361#[derivative(Default(bound = ""))]
362#[cfg_attr(test, derive(Debug))]
363pub struct IpDeviceAddresses<I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
364 addrs: Vec<PrimaryAddressId<I, BT>>,
365}
366
367impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpDeviceAddresses<I, BT> {
371 pub fn iter(
373 &self,
374 ) -> impl ExactSizeIterator<Item = &PrimaryAddressId<I, BT>> + ExactSizeIterator + Clone {
375 self.addrs.iter()
376 }
377
378 pub fn strong_iter(&self) -> AddressIdIter<'_, I, BT> {
380 AddressIdIter(self.addrs.iter())
381 }
382
383 pub fn add(&mut self, addr: IpAddressEntry<I, BT>) -> Result<AddressId<I, BT>, ExistsError> {
385 if self.iter().any(|a| a.addr() == addr.addr_sub.addr()) {
386 return Err(ExistsError);
387 }
388 let (primary, strong) = PrimaryAddressId::new_with_strong_clone(addr);
389 self.addrs.push(primary);
390 Ok(strong)
391 }
392
393 pub fn remove(&mut self, addr: &I::Addr) -> Result<PrimaryAddressId<I, BT>, NotFoundError> {
395 let (index, _entry): (_, &PrimaryAddressId<I, BT>) = self
396 .addrs
397 .iter()
398 .enumerate()
399 .find(|(_, entry)| entry.addr().get() == *addr)
400 .ok_or(NotFoundError)?;
401 Ok(self.addrs.remove(index))
402 }
403}
404
405pub struct AddressIdIter<'a, I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
407 core::slice::Iter<'a, PrimaryAddressId<I, BT>>,
408);
409
410impl<'a, I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Iterator
411 for AddressIdIter<'a, I, BT>
412{
413 type Item = AddressId<I, BT>;
414
415 fn next(&mut self) -> Option<Self::Item> {
416 let Self(inner) = self;
417 inner.next().map(|addr| addr.clone_strong())
418 }
419}
420
421pub struct Ipv4DeviceState<BT: IpDeviceStateBindingsTypes> {
423 ip_state: IpDeviceState<Ipv4, BT>,
424 config: RwLock<Ipv4DeviceConfiguration>,
425 igmp_counters: IgmpCounters,
426}
427
428impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv4DeviceConfiguration>
429 for DualStackIpDeviceState<BT>
430{
431 type Lock = RwLock<Ipv4DeviceConfiguration>;
432 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
433 OrderedLockRef::new(&self.ipv4.config)
434 }
435}
436
437impl<BC: IpDeviceStateBindingsTypes + TimerContext> Ipv4DeviceState<BC> {
438 fn new<D: WeakDeviceIdentifier, CC: CoreTimerContext<Ipv4DeviceTimerId<D, BC>, BC>>(
439 bindings_ctx: &mut BC,
440 device_id: D,
441 ) -> Ipv4DeviceState<BC> {
442 Ipv4DeviceState {
443 ip_state: IpDeviceState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
444 bindings_ctx,
445 device_id,
446 ),
447 config: Default::default(),
448 igmp_counters: Default::default(),
449 }
450 }
451}
452
453impl<BT: IpDeviceStateBindingsTypes> Ipv4DeviceState<BT> {
454 fn igmp_counters(&self) -> &IgmpCounters {
455 &self.igmp_counters
456 }
457}
458
459impl<BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
460 fn as_ref(&self) -> &IpDeviceState<Ipv4, BT> {
461 &self.ip_state
462 }
463}
464
465impl<BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
466 fn as_mut(&mut self) -> &mut IpDeviceState<Ipv4, BT> {
467 &mut self.ip_state
468 }
469}
470
471#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
473pub struct IpDeviceConfiguration {
474 pub gmp_enabled: bool,
482
483 pub unicast_forwarding_enabled: bool,
495
496 pub multicast_forwarding_enabled: bool,
509 pub dad_transmits: Option<NonZeroU16>,
519}
520
521#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
523pub struct Ipv4DeviceConfiguration {
524 pub ip_config: IpDeviceConfiguration,
526}
527
528impl Ipv4DeviceConfiguration {
529 pub const DEFAULT_DUPLICATE_ADDRESS_DETECTION_TRANSMITS: NonZeroU16 =
531 NonZeroU16::new(3).unwrap();
532}
533
534impl AsRef<IpDeviceConfiguration> for Ipv4DeviceConfiguration {
535 fn as_ref(&self) -> &IpDeviceConfiguration {
536 &self.ip_config
537 }
538}
539
540impl AsMut<IpDeviceConfiguration> for Ipv4DeviceConfiguration {
541 fn as_mut(&mut self) -> &mut IpDeviceConfiguration {
542 &mut self.ip_config
543 }
544}
545
546#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
548pub struct Ipv6DeviceConfiguration {
549 pub max_router_solicitations: Option<NonZeroU8>,
558
559 pub slaac_config: SlaacConfiguration,
561
562 pub route_discovery_config: RouteDiscoveryConfiguration,
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(&self) -> Option<NonZeroDuration> {
646 self.retrans_timer.clone()
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 = dad_state.is_assigned();
1235 Self {
1236 addr_sub,
1237 dad_state: Mutex::new(dad_state),
1238 state: RwLock::new(IpAddressData {
1239 config: Some(config),
1240 flags: IpAddressFlags { assigned },
1241 }),
1242 }
1243 }
1244
1245 pub fn addr_sub(&self) -> &AddrSubnet<I::Addr, I::AssignedWitness> {
1247 &self.addr_sub
1248 }
1249}
1250
1251impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> OrderedLockAccess<DadState<I, BT>>
1252 for IpAddressEntry<I, BT>
1253{
1254 type Lock = Mutex<DadState<I, BT>>;
1255 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1256 OrderedLockRef::new(&self.dad_state)
1257 }
1258}
1259
1260impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
1261 OrderedLockAccess<IpAddressData<I, BT::Instant>> for IpAddressEntry<I, BT>
1262{
1263 type Lock = RwLock<IpAddressData<I, BT::Instant>>;
1264 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1265 OrderedLockRef::new(&self.state)
1266 }
1267}
1268
1269#[cfg(test)]
1270mod tests {
1271 use super::*;
1272
1273 use net_types::ip::{Ipv4Addr, Ipv6Addr};
1274 use netstack3_base::InstantContext as _;
1275 use netstack3_base::testutil::{FakeBindingsCtx, FakeInstant};
1276 use test_case::test_case;
1277
1278 type FakeBindingsCtxImpl = FakeBindingsCtx<(), (), (), ()>;
1279
1280 #[test_case(Lifetime::Infinite ; "with infinite valid_until")]
1281 #[test_case(Lifetime::Finite(FakeInstant::from(Duration::from_secs(1))); "with finite valid_until")]
1282 fn test_add_addr_ipv4(valid_until: Lifetime<FakeInstant>) {
1283 const ADDRESS: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1284 const PREFIX_LEN: u8 = 8;
1285
1286 let mut ipv4 = IpDeviceAddresses::<Ipv4, FakeBindingsCtxImpl>::default();
1287 let config = Ipv4AddrConfig {
1288 properties: CommonAddressProperties { valid_until, ..Default::default() },
1289 ..Default::default()
1290 };
1291
1292 let _: AddressId<_, _> = ipv4
1293 .add(IpAddressEntry::new(
1294 AddrSubnet::new(ADDRESS, PREFIX_LEN).unwrap(),
1295 DadState::Uninitialized,
1296 config,
1297 ))
1298 .unwrap();
1299 assert_eq!(
1301 ipv4.add(IpAddressEntry::new(
1302 AddrSubnet::new(ADDRESS, PREFIX_LEN + 1).unwrap(),
1303 DadState::Uninitialized,
1304 config,
1305 ))
1306 .unwrap_err(),
1307 ExistsError
1308 );
1309 }
1310
1311 #[test_case(Lifetime::Infinite ; "with infinite valid_until")]
1312 #[test_case(Lifetime::Finite(FakeInstant::from(Duration::from_secs(1))); "with finite valid_until")]
1313 fn test_add_addr_ipv6(valid_until: Lifetime<FakeInstant>) {
1314 const ADDRESS: Ipv6Addr =
1315 Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]);
1316 const PREFIX_LEN: u8 = 8;
1317
1318 let mut ipv6 = IpDeviceAddresses::<Ipv6, FakeBindingsCtxImpl>::default();
1319
1320 let mut bindings_ctx = FakeBindingsCtxImpl::default();
1321
1322 let _: AddressId<_, _> = ipv6
1323 .add(IpAddressEntry::new(
1324 AddrSubnet::new(ADDRESS, PREFIX_LEN).unwrap(),
1325 DadState::Tentative {
1326 dad_transmits_remaining: None,
1327 timer: bindings_ctx.new_timer(()),
1328 ip_specific_state: Default::default(),
1329 probe_wait: None,
1330 },
1331 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig {
1332 inner: SlaacConfig::Stable {
1333 valid_until,
1334 creation_time: bindings_ctx.now(),
1335 regen_counter: 0,
1336 dad_counter: 0,
1337 },
1338 preferred_lifetime: PreferredLifetime::Preferred(Lifetime::Infinite),
1339 }),
1340 ))
1341 .unwrap();
1342 assert_eq!(
1345 ipv6.add(IpAddressEntry::new(
1346 AddrSubnet::new(ADDRESS, PREFIX_LEN + 1).unwrap(),
1347 DadState::Assigned { ran_dad: false },
1348 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig {
1349 properties: CommonAddressProperties { valid_until, ..Default::default() },
1350 ..Default::default()
1351 }),
1352 ))
1353 .unwrap_err(),
1354 ExistsError,
1355 );
1356 }
1357
1358 #[test_case(None => false; "default")]
1359 #[test_case(Some(false) => false; "disabled")]
1360 #[test_case(Some(true) => true; "enabled")]
1361 fn should_perform_dad_ipv4(setting: Option<bool>) -> bool {
1362 let state = IpAddressData::<Ipv4, FakeInstant> {
1363 flags: IpAddressFlags { assigned: false },
1364 config: Some(Ipv4AddrConfig::<FakeInstant> {
1365 config: CommonAddressConfig { should_perform_dad: setting },
1366 ..Default::default()
1367 }),
1368 };
1369 state.should_perform_dad()
1370 }
1371
1372 #[test_case(None => true; "default")]
1373 #[test_case(Some(false) => false; "disabled")]
1374 #[test_case(Some(true) => true; "enabled")]
1375 fn should_perform_dad_ipv6(setting: Option<bool>) -> bool {
1376 let state = IpAddressData::<Ipv6, FakeInstant> {
1377 flags: IpAddressFlags { assigned: false },
1378 config: Some(Ipv6AddrConfig::Manual(Ipv6AddrManualConfig::<FakeInstant> {
1379 config: CommonAddressConfig { should_perform_dad: setting },
1380 ..Default::default()
1381 })),
1382 };
1383 state.should_perform_dad()
1384 }
1385}