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::{
45 BaseDeviceState, DeviceStateSpec, DeviceTxOffloadSpecContext, IpLinkDeviceStateInner,
46};
47
48pub struct PendingDeviceConfigurationUpdate<'a, D>(DeviceConfigurationUpdate, &'a D);
57
58#[derive(RefCast)]
60#[repr(transparent)]
61pub struct DeviceApi<D, C>(C, PhantomData<D>);
62
63impl<D, C> DeviceApi<D, C> {
64 pub fn new(ctx: C) -> Self {
66 Self(ctx, PhantomData)
67 }
68}
69
70impl<D, C> DeviceApi<D, C>
71where
72 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec + DeviceBufferSpec<C::BindingsContext>,
73 C: ContextPair,
74 C::CoreContext: DeviceApiCoreContext<D, C::BindingsContext>,
75 C::BindingsContext: DeviceApiBindingsContext,
76{
77 pub(crate) fn contexts(&mut self) -> (&mut C::CoreContext, &mut C::BindingsContext) {
78 let Self(pair, PhantomData) = self;
79 pair.contexts()
80 }
81
82 pub(crate) fn core_ctx(&mut self) -> &mut C::CoreContext {
83 let Self(pair, PhantomData) = self;
84 pair.core_ctx()
85 }
86
87 pub fn add_device(
93 &mut self,
94 bindings_id: <C::BindingsContext as DeviceLayerStateTypes>::DeviceIdentifier,
95 properties: D::CreationProperties,
96 metric: RawMetric,
97 external_state: D::External<C::BindingsContext>,
98 tx_allocator: D::TxAllocator,
99 ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId
100 where
101 C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
102 {
103 debug!("adding {} device with {:?} metric:{metric}", D::DEBUG_TYPE, properties);
104 let (core_ctx, bindings_ctx) = self.contexts();
105 let origin = core_ctx.origin_tracker();
106 let primary = BasePrimaryDeviceId::new(
107 |weak_ref| {
108 let link = D::new_device_state::<C::CoreContext, _>(
109 bindings_ctx,
110 weak_ref.clone(),
111 properties,
112 tx_allocator,
113 );
114 IpLinkDeviceStateInner::new::<_, C::CoreContext>(
115 bindings_ctx,
116 weak_ref.into(),
117 link,
118 metric,
119 origin,
120 )
121 },
122 external_state,
123 bindings_id,
124 );
125 let id = primary.clone_strong();
126 core_ctx.insert(primary);
127 id
128 }
129
130 #[cfg(any(test, feature = "testutils"))]
136 pub fn add_device_with_default_state(
137 &mut self,
138 properties: D::CreationProperties,
139 metric: RawMetric,
140 ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId
141 where
142 <C::BindingsContext as DeviceLayerStateTypes>::DeviceIdentifier: Default,
143 D::External<C::BindingsContext>: Default,
144 C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
145 D::TxAllocator: Default,
146 {
147 self.add_device(
148 Default::default(),
149 properties,
150 metric,
151 Default::default(),
152 Default::default(),
153 )
154 }
155
156 pub fn remove_device(
169 &mut self,
170 device: BaseDeviceId<D, C::BindingsContext>,
171 ) -> RemoveResourceResultWithContext<D::External<C::BindingsContext>, C::BindingsContext>
172 where
173 BaseDeviceId<D, C::BindingsContext>: Into<DeviceId<C::BindingsContext>>,
175 C::CoreContext: IpDeviceConfigurationContext<Ipv4, C::BindingsContext>
176 + Ipv6DeviceConfigurationContext<C::BindingsContext>
177 + DeviceIdContext<AnyDevice, DeviceId = DeviceId<C::BindingsContext>>,
178 C::BindingsContext: IpDeviceBindingsContext<Ipv4, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>
179 + IpDeviceBindingsContext<Ipv6, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
180 {
181 let (core_ctx, bindings_ctx) = self.contexts();
185 {
186 let device = device.clone().into();
187 ip::device::clear_ipv4_device_state(core_ctx, bindings_ctx, &device);
188 ip::device::clear_ipv6_device_state(core_ctx, bindings_ctx, &device);
189 };
190
191 debug!("removing {device:?}");
192 let primary = core_ctx.remove(&device).expect("tried to remove device not in stack");
193 assert_eq!(device, primary);
194 core::mem::drop(device);
195 C::BindingsContext::unwrap_or_notify_with_new_reference_notifier(
196 primary.into_inner(),
197 |state: BaseDeviceState<_, _>| state.external_state,
198 )
199 }
200
201 pub fn receive_frame<B: BufferMut + Debug>(
203 &mut self,
204 meta: D::FrameMetadata<BaseDeviceId<D, C::BindingsContext>>,
205 frame: B,
206 ) {
207 let (core_ctx, bindings_ctx) = self.contexts();
208 core_ctx.receive_frame(bindings_ctx, meta, frame)
209 }
210
211 pub fn apply_configuration(
217 &mut self,
218 pending: PendingDeviceConfigurationUpdate<'_, BaseDeviceId<D, C::BindingsContext>>,
219 ) -> DeviceConfigurationUpdate {
220 let PendingDeviceConfigurationUpdate(DeviceConfigurationUpdate { arp, ndp }, device_id) =
221 pending;
222 let core_ctx = self.core_ctx();
223 let arp = core_ctx.with_nud_config_mut::<Ipv4, _, _>(device_id, move |device_config| {
224 let device_config = match device_config {
225 Some(c) => c,
226 None => {
227 assert!(arp.is_none());
231 return None;
232 }
233 };
234 arp.map(|ArpConfigurationUpdate { nud }| {
235 let nud = nud.map(|config| config.apply_and_take_previous(device_config));
236 ArpConfigurationUpdate { nud }
237 })
238 });
239 let ndp = core_ctx.with_nud_config_mut::<Ipv6, _, _>(device_id, move |device_config| {
240 let device_config = match device_config {
241 Some(c) => c,
242 None => {
243 assert!(ndp.is_none());
247 return None;
248 }
249 };
250 ndp.map(|NdpConfigurationUpdate { nud }| {
251 let nud = nud.map(|config| config.apply_and_take_previous(device_config));
252 NdpConfigurationUpdate { nud }
253 })
254 });
255 DeviceConfigurationUpdate { arp, ndp }
256 }
257
258 pub fn new_configuration_update<'a>(
263 &mut self,
264 device: &'a BaseDeviceId<D, C::BindingsContext>,
265 config: DeviceConfigurationUpdate,
266 ) -> Result<
267 PendingDeviceConfigurationUpdate<'a, BaseDeviceId<D, C::BindingsContext>>,
268 DeviceConfigurationUpdateError,
269 > {
270 let core_ctx = self.core_ctx();
271 let DeviceConfigurationUpdate { arp, ndp } = &config;
272 if arp.is_some() && core_ctx.with_nud_config::<Ipv4, _, _>(device, |c| c.is_none()) {
273 return Err(DeviceConfigurationUpdateError::ArpNotSupported);
274 }
275 if ndp.is_some() && core_ctx.with_nud_config::<Ipv6, _, _>(device, |c| c.is_none()) {
276 return Err(DeviceConfigurationUpdateError::NdpNotSupported);
277 }
278 Ok(PendingDeviceConfigurationUpdate(config, device))
279 }
280
281 pub fn get_configuration(
283 &mut self,
284 device: &BaseDeviceId<D, C::BindingsContext>,
285 ) -> DeviceConfiguration {
286 let core_ctx = self.core_ctx();
287 let arp = core_ctx
288 .with_nud_config::<Ipv4, _, _>(device, |config| config.cloned())
289 .map(|nud| ArpConfiguration { nud });
290 let ndp = core_ctx
291 .with_nud_config::<Ipv6, _, _>(device, |config| config.cloned())
292 .map(|nud| NdpConfiguration { nud });
293 DeviceConfiguration { arp, ndp }
294 }
295
296 pub fn get_counters<'a>(
298 &'a mut self,
299 device: &'a BaseDeviceId<D, C::BindingsContext>,
300 ) -> &'a DeviceCounters {
301 ResourceCounterContext::<_, DeviceCounters>::per_resource_counters(self.core_ctx(), device)
302 }
303
304 pub fn inspect<N: Inspector>(
306 &mut self,
307 device: &BaseDeviceId<D, C::BindingsContext>,
308 inspector: &mut N,
309 ) {
310 if let Some(tx_offload_spec) = self.core_ctx().tx_offload_spec(device) {
311 inspector.record_child("TxOffloadSpec", |inspector| {
312 inspector.delegate_inspectable(&tx_offload_spec);
313 });
314 }
315
316 inspector.record_child("Counters", |inspector| {
317 inspector.delegate_inspectable(
318 ResourceCounterContext::<_, DeviceCounters>::per_resource_counters(
319 self.core_ctx(),
320 device,
321 ),
322 );
323 inspector.delegate_inspectable(
324 ResourceCounterContext::<_, D::Counters>::per_resource_counters(
325 self.core_ctx(),
326 device,
327 ),
328 );
329 inspector.record_child("IPv4", |inspector| {
330 inspector.delegate_inspectable(
331 ResourceCounterContext::<_, IpCounters<Ipv4>>::per_resource_counters(
332 self.core_ctx(),
333 device,
334 ),
335 )
336 });
337 inspector.record_child("IPv6", |inspector| {
338 inspector.delegate_inspectable(
339 ResourceCounterContext::<_, IpCounters<Ipv6>>::per_resource_counters(
340 self.core_ctx(),
341 device,
342 ),
343 )
344 });
345 inspector.record_child("IGMP", |inspector| {
346 inspector.delegate_inspectable(
347 ResourceCounterContext::<_, IgmpCounters>::per_resource_counters(
348 self.core_ctx(),
349 device,
350 ),
351 );
352 });
353 inspector.record_child("MLD", |inspector| {
354 inspector.delegate_inspectable(
355 ResourceCounterContext::<_, MldCounters>::per_resource_counters(
356 self.core_ctx(),
357 device,
358 ),
359 );
360 });
361 });
362 }
363}
364
365#[repr(transparent)]
367pub struct DeviceAnyApi<C>(C);
368
369impl<C> DeviceAnyApi<C> {
370 pub fn new(ctx: C) -> Self {
372 Self(ctx)
373 }
374}
375
376impl<C> DeviceAnyApi<C>
377where
378 C: ContextPair,
379 C::CoreContext: DeviceApiCoreContext<EthernetLinkDevice, C::BindingsContext>
380 + DeviceApiCoreContext<LoopbackDevice, C::BindingsContext>
381 + DeviceApiCoreContext<PureIpDevice, C::BindingsContext>
382 + DeviceApiCoreContext<BlackholeDevice, C::BindingsContext>,
383 C::BindingsContext: DeviceApiBindingsContext,
384{
385 fn device<D>(&mut self) -> &mut DeviceApi<D, C> {
386 let Self(ctx) = self;
387 DeviceApi::ref_cast_mut(ctx)
388 }
389
390 pub fn apply_configuration(
392 &mut self,
393 pending: PendingDeviceConfigurationUpdate<'_, DeviceId<C::BindingsContext>>,
394 ) -> DeviceConfigurationUpdate {
395 let PendingDeviceConfigurationUpdate(config, device) = pending;
396 for_any_device_id!(DeviceId, device,
397 device => {
398 self.device().apply_configuration(PendingDeviceConfigurationUpdate(config, device))
399 }
400 )
401 }
402
403 pub fn new_configuration_update<'a>(
406 &mut self,
407 device: &'a DeviceId<C::BindingsContext>,
408 config: DeviceConfigurationUpdate,
409 ) -> Result<
410 PendingDeviceConfigurationUpdate<'a, DeviceId<C::BindingsContext>>,
411 DeviceConfigurationUpdateError,
412 > {
413 for_any_device_id!(DeviceId, device,
414 inner => {
415 self.device()
416 .new_configuration_update(inner, config)
417 .map(|PendingDeviceConfigurationUpdate(config, _)| {
418 PendingDeviceConfigurationUpdate(config, device)
419 })
420 }
421 )
422 }
423
424 pub fn update_configuration(
427 &mut self,
428 device: &DeviceId<C::BindingsContext>,
429 config: DeviceConfigurationUpdate,
430 ) -> Result<DeviceConfigurationUpdate, DeviceConfigurationUpdateError> {
431 let pending = self.new_configuration_update(device, config)?;
432 Ok(self.apply_configuration(pending))
433 }
434
435 pub fn get_configuration(
437 &mut self,
438 device: &DeviceId<C::BindingsContext>,
439 ) -> DeviceConfiguration {
440 for_any_device_id!(DeviceId, device,
441 device => self.device().get_configuration(device))
442 }
443
444 pub fn get_counters<'a>(
446 &'a mut self,
447 device: &'a DeviceId<C::BindingsContext>,
448 ) -> &'a DeviceCounters {
449 for_any_device_id!(DeviceId, device,
450 device => self.device().get_counters(device))
451 }
452
453 pub fn inspect<N: Inspector>(
455 &mut self,
456 device: &DeviceId<C::BindingsContext>,
457 inspector: &mut N,
458 ) {
459 for_any_device_id!(DeviceId, DeviceProvider, D, device,
460 device => self.device::<D>().inspect(device, inspector))
461 }
462}
463
464pub trait DeviceApiCoreContext<
467 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec,
468 BC: DeviceApiBindingsContext,
469>:
470 DeviceIdContext<D, DeviceId = BaseDeviceId<D, BC>, WeakDeviceId = BaseWeakDeviceId<D, BC>>
471 + OriginTrackerContext
472 + DeviceCollectionContext<D, BC>
473 + DeviceConfigurationContext<D>
474 + RecvFrameContext<D::FrameMetadata<BaseDeviceId<D, BC>>, BC>
475 + ResourceCounterContext<Self::DeviceId, DeviceCounters>
476 + ResourceCounterContext<Self::DeviceId, D::Counters>
477 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv4>>
478 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv6>>
479 + ResourceCounterContext<Self::DeviceId, IgmpCounters>
480 + ResourceCounterContext<Self::DeviceId, MldCounters>
481 + CoreTimerContext<D::TimerId<Self::WeakDeviceId>, BC>
482 + DeviceTxOffloadSpecContext<D, BC>
483{
484}
485
486impl<CC, D, BC> DeviceApiCoreContext<D, BC> for CC
487where
488 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec,
489 BC: DeviceApiBindingsContext,
490 CC: DeviceIdContext<D, DeviceId = BaseDeviceId<D, BC>, WeakDeviceId = BaseWeakDeviceId<D, BC>>
491 + OriginTrackerContext
492 + DeviceCollectionContext<D, BC>
493 + DeviceConfigurationContext<D>
494 + RecvFrameContext<D::FrameMetadata<BaseDeviceId<D, BC>>, BC>
495 + ResourceCounterContext<Self::DeviceId, DeviceCounters>
496 + ResourceCounterContext<Self::DeviceId, D::Counters>
497 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv4>>
498 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv6>>
499 + ResourceCounterContext<Self::DeviceId, IgmpCounters>
500 + ResourceCounterContext<Self::DeviceId, MldCounters>
501 + CoreTimerContext<D::TimerId<Self::WeakDeviceId>, BC>
502 + DeviceTxOffloadSpecContext<D, BC>,
503{
504}
505
506pub trait DeviceApiBindingsContext: DeviceLayerTypes + ReferenceNotifiers + TimerContext {}
509
510impl<O> DeviceApiBindingsContext for O where O: DeviceLayerTypes + ReferenceNotifiers + TimerContext {}
511
512pub trait DeviceApiIpLayerCoreContext<D: Device, BC: DeviceLayerTypes>:
515 DeviceIdAnyCompatContext<D>
516 + CoreTimerContext<
517 IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
518 BC,
519 > + CoreTimerContext<
520 IpDeviceTimerId<Ipv4, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
521 BC,
522 >
523{
524}
525
526impl<O, D, BC> DeviceApiIpLayerCoreContext<D, BC> for O
527where
528 D: Device,
529 BC: DeviceLayerTypes,
530 O: DeviceIdAnyCompatContext<D>
531 + CoreTimerContext<
532 IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
533 BC,
534 > + CoreTimerContext<
535 IpDeviceTimerId<Ipv4, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
536 BC,
537 >,
538{
539}