1use alloc::fmt::Debug;
8use core::marker::PhantomData;
9
10use log::debug;
11use net_types::ip::{Ipv4, Ipv6};
12use netstack3_base::{
13 AnyDevice, ContextPair, CoreTimerContext, Device, DeviceIdAnyCompatContext, DeviceIdContext,
14 Inspector, RecvFrameContext, ReferenceNotifiers, ReferenceNotifiersExt as _,
15 RemoveResourceResultWithContext, ResourceCounterContext, TimerContext,
16};
17use netstack3_ip::device::{
18 IpDeviceBindingsContext, IpDeviceConfigurationContext, IpDeviceTimerId,
19 Ipv6DeviceConfigurationContext,
20};
21use netstack3_ip::gmp::{IgmpCounters, MldCounters};
22use netstack3_ip::{self as ip, IpCounters, RawMetric};
23use packet::BufferMut;
24use ref_cast::RefCast;
25
26use crate::internal::base::{
27 DeviceCollectionContext, DeviceCounters, DeviceLayerStateTypes, DeviceLayerTypes,
28 DeviceReceiveFrameSpec, OriginTrackerContext,
29};
30use crate::internal::blackhole::BlackholeDevice;
31use crate::internal::config::{
32 ArpConfiguration, ArpConfigurationUpdate, DeviceConfiguration, DeviceConfigurationContext,
33 DeviceConfigurationUpdate, DeviceConfigurationUpdateError, NdpConfiguration,
34 NdpConfigurationUpdate,
35};
36use crate::internal::ethernet::EthernetLinkDevice;
37use crate::internal::id::{
38 BaseDeviceId, BasePrimaryDeviceId, BaseWeakDeviceId, DeviceId, DeviceProvider,
39 for_any_device_id,
40};
41use crate::internal::loopback::LoopbackDevice;
42use crate::internal::pure_ip::PureIpDevice;
43use crate::internal::queue::DeviceBufferSpec;
44use crate::internal::state::{BaseDeviceState, DeviceStateSpec, IpLinkDeviceStateInner};
45
46pub struct PendingDeviceConfigurationUpdate<'a, D>(DeviceConfigurationUpdate, &'a D);
55
56#[derive(RefCast)]
58#[repr(transparent)]
59pub struct DeviceApi<D, C>(C, PhantomData<D>);
60
61impl<D, C> DeviceApi<D, C> {
62 pub fn new(ctx: C) -> Self {
64 Self(ctx, PhantomData)
65 }
66}
67
68impl<D, C> DeviceApi<D, C>
69where
70 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec + DeviceBufferSpec<C::BindingsContext>,
71 C: ContextPair,
72 C::CoreContext: DeviceApiCoreContext<D, C::BindingsContext>,
73 C::BindingsContext: DeviceApiBindingsContext,
74{
75 pub(crate) fn contexts(&mut self) -> (&mut C::CoreContext, &mut C::BindingsContext) {
76 let Self(pair, PhantomData) = self;
77 pair.contexts()
78 }
79
80 pub(crate) fn core_ctx(&mut self) -> &mut C::CoreContext {
81 let Self(pair, PhantomData) = self;
82 pair.core_ctx()
83 }
84
85 pub fn add_device(
91 &mut self,
92 bindings_id: <C::BindingsContext as DeviceLayerStateTypes>::DeviceIdentifier,
93 properties: D::CreationProperties,
94 metric: RawMetric,
95 external_state: D::External<C::BindingsContext>,
96 tx_allocator: D::TxAllocator,
97 ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId
98 where
99 C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
100 {
101 debug!("adding {} device with {:?} metric:{metric}", D::DEBUG_TYPE, properties);
102 let (core_ctx, bindings_ctx) = self.contexts();
103 let origin = core_ctx.origin_tracker();
104 let primary = BasePrimaryDeviceId::new(
105 |weak_ref| {
106 let link = D::new_device_state::<C::CoreContext, _>(
107 bindings_ctx,
108 weak_ref.clone(),
109 properties,
110 tx_allocator,
111 );
112 IpLinkDeviceStateInner::new::<_, C::CoreContext>(
113 bindings_ctx,
114 weak_ref.into(),
115 link,
116 metric,
117 origin,
118 )
119 },
120 external_state,
121 bindings_id,
122 );
123 let id = primary.clone_strong();
124 core_ctx.insert(primary);
125 id
126 }
127
128 #[cfg(any(test, feature = "testutils"))]
134 pub fn add_device_with_default_state(
135 &mut self,
136 properties: D::CreationProperties,
137 metric: RawMetric,
138 ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId
139 where
140 <C::BindingsContext as DeviceLayerStateTypes>::DeviceIdentifier: Default,
141 D::External<C::BindingsContext>: Default,
142 C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
143 D::TxAllocator: Default,
144 {
145 self.add_device(
146 Default::default(),
147 properties,
148 metric,
149 Default::default(),
150 Default::default(),
151 )
152 }
153
154 pub fn remove_device(
167 &mut self,
168 device: BaseDeviceId<D, C::BindingsContext>,
169 ) -> RemoveResourceResultWithContext<D::External<C::BindingsContext>, C::BindingsContext>
170 where
171 BaseDeviceId<D, C::BindingsContext>: Into<DeviceId<C::BindingsContext>>,
173 C::CoreContext: IpDeviceConfigurationContext<Ipv4, C::BindingsContext>
174 + Ipv6DeviceConfigurationContext<C::BindingsContext>
175 + DeviceIdContext<AnyDevice, DeviceId = DeviceId<C::BindingsContext>>,
176 C::BindingsContext: IpDeviceBindingsContext<Ipv4, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>
177 + IpDeviceBindingsContext<Ipv6, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
178 {
179 let (core_ctx, bindings_ctx) = self.contexts();
183 {
184 let device = device.clone().into();
185 ip::device::clear_ipv4_device_state(core_ctx, bindings_ctx, &device);
186 ip::device::clear_ipv6_device_state(core_ctx, bindings_ctx, &device);
187 };
188
189 debug!("removing {device:?}");
190 let primary = core_ctx.remove(&device).expect("tried to remove device not in stack");
191 assert_eq!(device, primary);
192 core::mem::drop(device);
193 C::BindingsContext::unwrap_or_notify_with_new_reference_notifier(
194 primary.into_inner(),
195 |state: BaseDeviceState<_, _>| state.external_state,
196 )
197 }
198
199 pub fn receive_frame<B: BufferMut + Debug>(
201 &mut self,
202 meta: D::FrameMetadata<BaseDeviceId<D, C::BindingsContext>>,
203 frame: B,
204 ) {
205 let (core_ctx, bindings_ctx) = self.contexts();
206 core_ctx.receive_frame(bindings_ctx, meta, frame)
207 }
208
209 pub fn apply_configuration(
215 &mut self,
216 pending: PendingDeviceConfigurationUpdate<'_, BaseDeviceId<D, C::BindingsContext>>,
217 ) -> DeviceConfigurationUpdate {
218 let PendingDeviceConfigurationUpdate(DeviceConfigurationUpdate { arp, ndp }, device_id) =
219 pending;
220 let core_ctx = self.core_ctx();
221 let arp = core_ctx.with_nud_config_mut::<Ipv4, _, _>(device_id, move |device_config| {
222 let device_config = match device_config {
223 Some(c) => c,
224 None => {
225 assert!(arp.is_none());
229 return None;
230 }
231 };
232 arp.map(|ArpConfigurationUpdate { nud }| {
233 let nud = nud.map(|config| config.apply_and_take_previous(device_config));
234 ArpConfigurationUpdate { nud }
235 })
236 });
237 let ndp = core_ctx.with_nud_config_mut::<Ipv6, _, _>(device_id, move |device_config| {
238 let device_config = match device_config {
239 Some(c) => c,
240 None => {
241 assert!(ndp.is_none());
245 return None;
246 }
247 };
248 ndp.map(|NdpConfigurationUpdate { nud }| {
249 let nud = nud.map(|config| config.apply_and_take_previous(device_config));
250 NdpConfigurationUpdate { nud }
251 })
252 });
253 DeviceConfigurationUpdate { arp, ndp }
254 }
255
256 pub fn new_configuration_update<'a>(
261 &mut self,
262 device: &'a BaseDeviceId<D, C::BindingsContext>,
263 config: DeviceConfigurationUpdate,
264 ) -> Result<
265 PendingDeviceConfigurationUpdate<'a, BaseDeviceId<D, C::BindingsContext>>,
266 DeviceConfigurationUpdateError,
267 > {
268 let core_ctx = self.core_ctx();
269 let DeviceConfigurationUpdate { arp, ndp } = &config;
270 if arp.is_some() && core_ctx.with_nud_config::<Ipv4, _, _>(device, |c| c.is_none()) {
271 return Err(DeviceConfigurationUpdateError::ArpNotSupported);
272 }
273 if ndp.is_some() && core_ctx.with_nud_config::<Ipv6, _, _>(device, |c| c.is_none()) {
274 return Err(DeviceConfigurationUpdateError::NdpNotSupported);
275 }
276 Ok(PendingDeviceConfigurationUpdate(config, device))
277 }
278
279 pub fn get_configuration(
281 &mut self,
282 device: &BaseDeviceId<D, C::BindingsContext>,
283 ) -> DeviceConfiguration {
284 let core_ctx = self.core_ctx();
285 let arp = core_ctx
286 .with_nud_config::<Ipv4, _, _>(device, |config| config.cloned())
287 .map(|nud| ArpConfiguration { nud });
288 let ndp = core_ctx
289 .with_nud_config::<Ipv6, _, _>(device, |config| config.cloned())
290 .map(|nud| NdpConfiguration { nud });
291 DeviceConfiguration { arp, ndp }
292 }
293
294 pub fn get_counters<'a>(
296 &'a mut self,
297 device: &'a BaseDeviceId<D, C::BindingsContext>,
298 ) -> &'a DeviceCounters {
299 ResourceCounterContext::<_, DeviceCounters>::per_resource_counters(self.core_ctx(), device)
300 }
301
302 pub fn inspect<N: Inspector>(
304 &mut self,
305 device: &BaseDeviceId<D, C::BindingsContext>,
306 inspector: &mut N,
307 ) {
308 inspector.record_child("Counters", |inspector| {
309 inspector.delegate_inspectable(
310 ResourceCounterContext::<_, DeviceCounters>::per_resource_counters(
311 self.core_ctx(),
312 device,
313 ),
314 );
315 inspector.delegate_inspectable(
316 ResourceCounterContext::<_, D::Counters>::per_resource_counters(
317 self.core_ctx(),
318 device,
319 ),
320 );
321 inspector.record_child("IPv4", |inspector| {
322 inspector.delegate_inspectable(
323 ResourceCounterContext::<_, IpCounters<Ipv4>>::per_resource_counters(
324 self.core_ctx(),
325 device,
326 ),
327 )
328 });
329 inspector.record_child("IPv6", |inspector| {
330 inspector.delegate_inspectable(
331 ResourceCounterContext::<_, IpCounters<Ipv6>>::per_resource_counters(
332 self.core_ctx(),
333 device,
334 ),
335 )
336 });
337 inspector.record_child("IGMP", |inspector| {
338 inspector.delegate_inspectable(
339 ResourceCounterContext::<_, IgmpCounters>::per_resource_counters(
340 self.core_ctx(),
341 device,
342 ),
343 );
344 });
345 inspector.record_child("MLD", |inspector| {
346 inspector.delegate_inspectable(
347 ResourceCounterContext::<_, MldCounters>::per_resource_counters(
348 self.core_ctx(),
349 device,
350 ),
351 );
352 });
353 });
354 }
355}
356
357#[repr(transparent)]
359pub struct DeviceAnyApi<C>(C);
360
361impl<C> DeviceAnyApi<C> {
362 pub fn new(ctx: C) -> Self {
364 Self(ctx)
365 }
366}
367
368impl<C> DeviceAnyApi<C>
369where
370 C: ContextPair,
371 C::CoreContext: DeviceApiCoreContext<EthernetLinkDevice, C::BindingsContext>
372 + DeviceApiCoreContext<LoopbackDevice, C::BindingsContext>
373 + DeviceApiCoreContext<PureIpDevice, C::BindingsContext>
374 + DeviceApiCoreContext<BlackholeDevice, C::BindingsContext>,
375 C::BindingsContext: DeviceApiBindingsContext,
376{
377 fn device<D>(&mut self) -> &mut DeviceApi<D, C> {
378 let Self(ctx) = self;
379 DeviceApi::ref_cast_mut(ctx)
380 }
381
382 pub fn apply_configuration(
384 &mut self,
385 pending: PendingDeviceConfigurationUpdate<'_, DeviceId<C::BindingsContext>>,
386 ) -> DeviceConfigurationUpdate {
387 let PendingDeviceConfigurationUpdate(config, device) = pending;
388 for_any_device_id!(DeviceId, device,
389 device => {
390 self.device().apply_configuration(PendingDeviceConfigurationUpdate(config, device))
391 }
392 )
393 }
394
395 pub fn new_configuration_update<'a>(
398 &mut self,
399 device: &'a DeviceId<C::BindingsContext>,
400 config: DeviceConfigurationUpdate,
401 ) -> Result<
402 PendingDeviceConfigurationUpdate<'a, DeviceId<C::BindingsContext>>,
403 DeviceConfigurationUpdateError,
404 > {
405 for_any_device_id!(DeviceId, device,
406 inner => {
407 self.device()
408 .new_configuration_update(inner, config)
409 .map(|PendingDeviceConfigurationUpdate(config, _)| {
410 PendingDeviceConfigurationUpdate(config, device)
411 })
412 }
413 )
414 }
415
416 pub fn update_configuration(
419 &mut self,
420 device: &DeviceId<C::BindingsContext>,
421 config: DeviceConfigurationUpdate,
422 ) -> Result<DeviceConfigurationUpdate, DeviceConfigurationUpdateError> {
423 let pending = self.new_configuration_update(device, config)?;
424 Ok(self.apply_configuration(pending))
425 }
426
427 pub fn get_configuration(
429 &mut self,
430 device: &DeviceId<C::BindingsContext>,
431 ) -> DeviceConfiguration {
432 for_any_device_id!(DeviceId, device,
433 device => self.device().get_configuration(device))
434 }
435
436 pub fn get_counters<'a>(
438 &'a mut self,
439 device: &'a DeviceId<C::BindingsContext>,
440 ) -> &'a DeviceCounters {
441 for_any_device_id!(DeviceId, device,
442 device => self.device().get_counters(device))
443 }
444
445 pub fn inspect<N: Inspector>(
447 &mut self,
448 device: &DeviceId<C::BindingsContext>,
449 inspector: &mut N,
450 ) {
451 for_any_device_id!(DeviceId, DeviceProvider, D, device,
452 device => self.device::<D>().inspect(device, inspector))
453 }
454}
455
456pub trait DeviceApiCoreContext<
459 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec,
460 BC: DeviceApiBindingsContext,
461>:
462 DeviceIdContext<D, DeviceId = BaseDeviceId<D, BC>, WeakDeviceId = BaseWeakDeviceId<D, BC>>
463 + OriginTrackerContext
464 + DeviceCollectionContext<D, BC>
465 + DeviceConfigurationContext<D>
466 + RecvFrameContext<D::FrameMetadata<BaseDeviceId<D, BC>>, BC>
467 + ResourceCounterContext<Self::DeviceId, DeviceCounters>
468 + ResourceCounterContext<Self::DeviceId, D::Counters>
469 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv4>>
470 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv6>>
471 + ResourceCounterContext<Self::DeviceId, IgmpCounters>
472 + ResourceCounterContext<Self::DeviceId, MldCounters>
473 + CoreTimerContext<D::TimerId<Self::WeakDeviceId>, BC>
474{
475}
476
477impl<CC, D, BC> DeviceApiCoreContext<D, BC> for CC
478where
479 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec,
480 BC: DeviceApiBindingsContext,
481 CC: DeviceIdContext<D, DeviceId = BaseDeviceId<D, BC>, WeakDeviceId = BaseWeakDeviceId<D, BC>>
482 + OriginTrackerContext
483 + DeviceCollectionContext<D, BC>
484 + DeviceConfigurationContext<D>
485 + RecvFrameContext<D::FrameMetadata<BaseDeviceId<D, BC>>, BC>
486 + ResourceCounterContext<Self::DeviceId, DeviceCounters>
487 + ResourceCounterContext<Self::DeviceId, D::Counters>
488 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv4>>
489 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv6>>
490 + ResourceCounterContext<Self::DeviceId, IgmpCounters>
491 + ResourceCounterContext<Self::DeviceId, MldCounters>
492 + CoreTimerContext<D::TimerId<Self::WeakDeviceId>, BC>,
493{
494}
495
496pub trait DeviceApiBindingsContext: DeviceLayerTypes + ReferenceNotifiers + TimerContext {}
499
500impl<O> DeviceApiBindingsContext for O where O: DeviceLayerTypes + ReferenceNotifiers + TimerContext {}
501
502pub trait DeviceApiIpLayerCoreContext<D: Device, BC: DeviceLayerTypes>:
505 DeviceIdAnyCompatContext<D>
506 + CoreTimerContext<
507 IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
508 BC,
509 > + CoreTimerContext<
510 IpDeviceTimerId<Ipv4, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
511 BC,
512 >
513{
514}
515
516impl<O, D, BC> DeviceApiIpLayerCoreContext<D, BC> for O
517where
518 D: Device,
519 BC: DeviceLayerTypes,
520 O: DeviceIdAnyCompatContext<D>
521 + CoreTimerContext<
522 IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
523 BC,
524 > + CoreTimerContext<
525 IpDeviceTimerId<Ipv4, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
526 BC,
527 >,
528{
529}