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::state::{BaseDeviceState, DeviceStateSpec, IpLinkDeviceStateInner};
44
45pub struct PendingDeviceConfigurationUpdate<'a, D>(DeviceConfigurationUpdate, &'a D);
54
55#[derive(RefCast)]
57#[repr(transparent)]
58pub struct DeviceApi<D, C>(C, PhantomData<D>);
59
60impl<D, C> DeviceApi<D, C> {
61 pub fn new(ctx: C) -> Self {
63 Self(ctx, PhantomData)
64 }
65}
66
67impl<D, C> DeviceApi<D, C>
68where
69 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec,
70 C: ContextPair,
71 C::CoreContext: DeviceApiCoreContext<D, C::BindingsContext>,
72 C::BindingsContext: DeviceApiBindingsContext,
73{
74 pub(crate) fn contexts(&mut self) -> (&mut C::CoreContext, &mut C::BindingsContext) {
75 let Self(pair, PhantomData) = self;
76 pair.contexts()
77 }
78
79 pub(crate) fn core_ctx(&mut self) -> &mut C::CoreContext {
80 let Self(pair, PhantomData) = self;
81 pair.core_ctx()
82 }
83
84 pub fn add_device(
90 &mut self,
91 bindings_id: <C::BindingsContext as DeviceLayerStateTypes>::DeviceIdentifier,
92 properties: D::CreationProperties,
93 metric: RawMetric,
94 external_state: D::External<C::BindingsContext>,
95 ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId
96 where
97 C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
98 {
99 debug!("adding {} device with {:?} metric:{metric}", D::DEBUG_TYPE, properties);
100 let (core_ctx, bindings_ctx) = self.contexts();
101 let origin = core_ctx.origin_tracker();
102 let primary = BasePrimaryDeviceId::new(
103 |weak_ref| {
104 let link = D::new_device_state::<C::CoreContext, _>(
105 bindings_ctx,
106 weak_ref.clone(),
107 properties,
108 );
109 IpLinkDeviceStateInner::new::<_, C::CoreContext>(
110 bindings_ctx,
111 weak_ref.into(),
112 link,
113 metric,
114 origin,
115 )
116 },
117 external_state,
118 bindings_id,
119 );
120 let id = primary.clone_strong();
121 core_ctx.insert(primary);
122 id
123 }
124
125 #[cfg(any(test, feature = "testutils"))]
131 pub fn add_device_with_default_state(
132 &mut self,
133 properties: D::CreationProperties,
134 metric: RawMetric,
135 ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId
136 where
137 <C::BindingsContext as DeviceLayerStateTypes>::DeviceIdentifier: Default,
138 D::External<C::BindingsContext>: Default,
139 C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
140 {
141 self.add_device(Default::default(), properties, metric, Default::default())
142 }
143
144 pub fn remove_device(
157 &mut self,
158 device: BaseDeviceId<D, C::BindingsContext>,
159 ) -> RemoveResourceResultWithContext<D::External<C::BindingsContext>, C::BindingsContext>
160 where
161 BaseDeviceId<D, C::BindingsContext>: Into<DeviceId<C::BindingsContext>>,
163 C::CoreContext: IpDeviceConfigurationContext<Ipv4, C::BindingsContext>
164 + Ipv6DeviceConfigurationContext<C::BindingsContext>
165 + DeviceIdContext<AnyDevice, DeviceId = DeviceId<C::BindingsContext>>,
166 C::BindingsContext: IpDeviceBindingsContext<Ipv4, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>
167 + IpDeviceBindingsContext<Ipv6, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
168 {
169 let (core_ctx, bindings_ctx) = self.contexts();
173 {
174 let device = device.clone().into();
175 ip::device::clear_ipv4_device_state(core_ctx, bindings_ctx, &device);
176 ip::device::clear_ipv6_device_state(core_ctx, bindings_ctx, &device);
177 };
178
179 debug!("removing {device:?}");
180 let primary = core_ctx.remove(&device).expect("tried to remove device not in stack");
181 assert_eq!(device, primary);
182 core::mem::drop(device);
183 C::BindingsContext::unwrap_or_notify_with_new_reference_notifier(
184 primary.into_inner(),
185 |state: BaseDeviceState<_, _>| state.external_state,
186 )
187 }
188
189 pub fn receive_frame<B: BufferMut + Debug>(
191 &mut self,
192 meta: D::FrameMetadata<BaseDeviceId<D, C::BindingsContext>>,
193 frame: B,
194 ) {
195 let (core_ctx, bindings_ctx) = self.contexts();
196 core_ctx.receive_frame(bindings_ctx, meta, frame)
197 }
198
199 pub fn apply_configuration(
205 &mut self,
206 pending: PendingDeviceConfigurationUpdate<'_, BaseDeviceId<D, C::BindingsContext>>,
207 ) -> DeviceConfigurationUpdate {
208 let PendingDeviceConfigurationUpdate(DeviceConfigurationUpdate { arp, ndp }, device_id) =
209 pending;
210 let core_ctx = self.core_ctx();
211 let arp = core_ctx.with_nud_config_mut::<Ipv4, _, _>(device_id, move |device_config| {
212 let device_config = match device_config {
213 Some(c) => c,
214 None => {
215 assert!(arp.is_none());
219 return None;
220 }
221 };
222 arp.map(|ArpConfigurationUpdate { nud }| {
223 let nud = nud.map(|config| config.apply_and_take_previous(device_config));
224 ArpConfigurationUpdate { nud }
225 })
226 });
227 let ndp = core_ctx.with_nud_config_mut::<Ipv6, _, _>(device_id, move |device_config| {
228 let device_config = match device_config {
229 Some(c) => c,
230 None => {
231 assert!(ndp.is_none());
235 return None;
236 }
237 };
238 ndp.map(|NdpConfigurationUpdate { nud }| {
239 let nud = nud.map(|config| config.apply_and_take_previous(device_config));
240 NdpConfigurationUpdate { nud }
241 })
242 });
243 DeviceConfigurationUpdate { arp, ndp }
244 }
245
246 pub fn new_configuration_update<'a>(
251 &mut self,
252 device: &'a BaseDeviceId<D, C::BindingsContext>,
253 config: DeviceConfigurationUpdate,
254 ) -> Result<
255 PendingDeviceConfigurationUpdate<'a, BaseDeviceId<D, C::BindingsContext>>,
256 DeviceConfigurationUpdateError,
257 > {
258 let core_ctx = self.core_ctx();
259 let DeviceConfigurationUpdate { arp, ndp } = &config;
260 if arp.is_some() && core_ctx.with_nud_config::<Ipv4, _, _>(device, |c| c.is_none()) {
261 return Err(DeviceConfigurationUpdateError::ArpNotSupported);
262 }
263 if ndp.is_some() && core_ctx.with_nud_config::<Ipv6, _, _>(device, |c| c.is_none()) {
264 return Err(DeviceConfigurationUpdateError::NdpNotSupported);
265 }
266 Ok(PendingDeviceConfigurationUpdate(config, device))
267 }
268
269 pub fn get_configuration(
271 &mut self,
272 device: &BaseDeviceId<D, C::BindingsContext>,
273 ) -> DeviceConfiguration {
274 let core_ctx = self.core_ctx();
275 let arp = core_ctx
276 .with_nud_config::<Ipv4, _, _>(device, |config| config.cloned())
277 .map(|nud| ArpConfiguration { nud });
278 let ndp = core_ctx
279 .with_nud_config::<Ipv6, _, _>(device, |config| config.cloned())
280 .map(|nud| NdpConfiguration { nud });
281 DeviceConfiguration { arp, ndp }
282 }
283
284 pub fn get_counters<'a>(
286 &'a mut self,
287 device: &'a BaseDeviceId<D, C::BindingsContext>,
288 ) -> &'a DeviceCounters {
289 ResourceCounterContext::<_, DeviceCounters>::per_resource_counters(self.core_ctx(), device)
290 }
291
292 pub fn inspect<N: Inspector>(
294 &mut self,
295 device: &BaseDeviceId<D, C::BindingsContext>,
296 inspector: &mut N,
297 ) {
298 inspector.record_child("Counters", |inspector| {
299 inspector.delegate_inspectable(
300 ResourceCounterContext::<_, DeviceCounters>::per_resource_counters(
301 self.core_ctx(),
302 device,
303 ),
304 );
305 inspector.delegate_inspectable(
306 ResourceCounterContext::<_, D::Counters>::per_resource_counters(
307 self.core_ctx(),
308 device,
309 ),
310 );
311 inspector.record_child("IPv4", |inspector| {
312 inspector.delegate_inspectable(
313 ResourceCounterContext::<_, IpCounters<Ipv4>>::per_resource_counters(
314 self.core_ctx(),
315 device,
316 ),
317 )
318 });
319 inspector.record_child("IPv6", |inspector| {
320 inspector.delegate_inspectable(
321 ResourceCounterContext::<_, IpCounters<Ipv6>>::per_resource_counters(
322 self.core_ctx(),
323 device,
324 ),
325 )
326 });
327 inspector.record_child("IGMP", |inspector| {
328 inspector.delegate_inspectable(
329 ResourceCounterContext::<_, IgmpCounters>::per_resource_counters(
330 self.core_ctx(),
331 device,
332 ),
333 );
334 });
335 inspector.record_child("MLD", |inspector| {
336 inspector.delegate_inspectable(
337 ResourceCounterContext::<_, MldCounters>::per_resource_counters(
338 self.core_ctx(),
339 device,
340 ),
341 );
342 });
343 });
344 }
345}
346
347#[repr(transparent)]
349pub struct DeviceAnyApi<C>(C);
350
351impl<C> DeviceAnyApi<C> {
352 pub fn new(ctx: C) -> Self {
354 Self(ctx)
355 }
356}
357
358impl<C> DeviceAnyApi<C>
359where
360 C: ContextPair,
361 C::CoreContext: DeviceApiCoreContext<EthernetLinkDevice, C::BindingsContext>
362 + DeviceApiCoreContext<LoopbackDevice, C::BindingsContext>
363 + DeviceApiCoreContext<PureIpDevice, C::BindingsContext>
364 + DeviceApiCoreContext<BlackholeDevice, C::BindingsContext>,
365 C::BindingsContext: DeviceApiBindingsContext,
366{
367 fn device<D>(&mut self) -> &mut DeviceApi<D, C> {
368 let Self(ctx) = self;
369 DeviceApi::ref_cast_mut(ctx)
370 }
371
372 pub fn apply_configuration(
374 &mut self,
375 pending: PendingDeviceConfigurationUpdate<'_, DeviceId<C::BindingsContext>>,
376 ) -> DeviceConfigurationUpdate {
377 let PendingDeviceConfigurationUpdate(config, device) = pending;
378 for_any_device_id!(DeviceId, device,
379 device => {
380 self.device().apply_configuration(PendingDeviceConfigurationUpdate(config, device))
381 }
382 )
383 }
384
385 pub fn new_configuration_update<'a>(
388 &mut self,
389 device: &'a DeviceId<C::BindingsContext>,
390 config: DeviceConfigurationUpdate,
391 ) -> Result<
392 PendingDeviceConfigurationUpdate<'a, DeviceId<C::BindingsContext>>,
393 DeviceConfigurationUpdateError,
394 > {
395 for_any_device_id!(DeviceId, device,
396 inner => {
397 self.device()
398 .new_configuration_update(inner, config)
399 .map(|PendingDeviceConfigurationUpdate(config, _)| {
400 PendingDeviceConfigurationUpdate(config, device)
401 })
402 }
403 )
404 }
405
406 pub fn update_configuration(
409 &mut self,
410 device: &DeviceId<C::BindingsContext>,
411 config: DeviceConfigurationUpdate,
412 ) -> Result<DeviceConfigurationUpdate, DeviceConfigurationUpdateError> {
413 let pending = self.new_configuration_update(device, config)?;
414 Ok(self.apply_configuration(pending))
415 }
416
417 pub fn get_configuration(
419 &mut self,
420 device: &DeviceId<C::BindingsContext>,
421 ) -> DeviceConfiguration {
422 for_any_device_id!(DeviceId, device,
423 device => self.device().get_configuration(device))
424 }
425
426 pub fn get_counters<'a>(
428 &'a mut self,
429 device: &'a DeviceId<C::BindingsContext>,
430 ) -> &'a DeviceCounters {
431 for_any_device_id!(DeviceId, device,
432 device => self.device().get_counters(device))
433 }
434
435 pub fn inspect<N: Inspector>(
437 &mut self,
438 device: &DeviceId<C::BindingsContext>,
439 inspector: &mut N,
440 ) {
441 for_any_device_id!(DeviceId, DeviceProvider, D, device,
442 device => self.device::<D>().inspect(device, inspector))
443 }
444}
445
446pub trait DeviceApiCoreContext<
449 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec,
450 BC: DeviceApiBindingsContext,
451>:
452 DeviceIdContext<D, DeviceId = BaseDeviceId<D, BC>, WeakDeviceId = BaseWeakDeviceId<D, BC>>
453 + OriginTrackerContext
454 + DeviceCollectionContext<D, BC>
455 + DeviceConfigurationContext<D>
456 + RecvFrameContext<D::FrameMetadata<BaseDeviceId<D, BC>>, BC>
457 + ResourceCounterContext<Self::DeviceId, DeviceCounters>
458 + ResourceCounterContext<Self::DeviceId, D::Counters>
459 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv4>>
460 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv6>>
461 + ResourceCounterContext<Self::DeviceId, IgmpCounters>
462 + ResourceCounterContext<Self::DeviceId, MldCounters>
463 + CoreTimerContext<D::TimerId<Self::WeakDeviceId>, BC>
464{
465}
466
467impl<CC, D, BC> DeviceApiCoreContext<D, BC> for CC
468where
469 D: Device + DeviceStateSpec + DeviceReceiveFrameSpec,
470 BC: DeviceApiBindingsContext,
471 CC: DeviceIdContext<D, DeviceId = BaseDeviceId<D, BC>, WeakDeviceId = BaseWeakDeviceId<D, BC>>
472 + OriginTrackerContext
473 + DeviceCollectionContext<D, BC>
474 + DeviceConfigurationContext<D>
475 + RecvFrameContext<D::FrameMetadata<BaseDeviceId<D, BC>>, BC>
476 + ResourceCounterContext<Self::DeviceId, DeviceCounters>
477 + ResourceCounterContext<Self::DeviceId, D::Counters>
478 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv4>>
479 + ResourceCounterContext<Self::DeviceId, IpCounters<Ipv6>>
480 + ResourceCounterContext<Self::DeviceId, IgmpCounters>
481 + ResourceCounterContext<Self::DeviceId, MldCounters>
482 + CoreTimerContext<D::TimerId<Self::WeakDeviceId>, BC>,
483{
484}
485
486pub trait DeviceApiBindingsContext: DeviceLayerTypes + ReferenceNotifiers + TimerContext {}
489
490impl<O> DeviceApiBindingsContext for O where O: DeviceLayerTypes + ReferenceNotifiers + TimerContext {}
491
492pub trait DeviceApiIpLayerCoreContext<D: Device, BC: DeviceLayerTypes>:
495 DeviceIdAnyCompatContext<D>
496 + CoreTimerContext<
497 IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
498 BC,
499 > + CoreTimerContext<
500 IpDeviceTimerId<Ipv4, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
501 BC,
502 >
503{
504}
505
506impl<O, D, BC> DeviceApiIpLayerCoreContext<D, BC> for O
507where
508 D: Device,
509 BC: DeviceLayerTypes,
510 O: DeviceIdAnyCompatContext<D>
511 + CoreTimerContext<
512 IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
513 BC,
514 > + CoreTimerContext<
515 IpDeviceTimerId<Ipv4, <Self as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
516 BC,
517 >,
518{
519}