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