Skip to main content

netstack3_device/
state.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! State maintained by the device layer.
6
7use alloc::sync::Arc;
8use core::fmt::Debug;
9
10use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
11use net_types::ip::{Ipv4, Ipv6};
12use netstack3_base::sync::{RwLock, WeakRc};
13use netstack3_base::{
14    ChecksumOffloadSpec, CoreTimerContext, Device, DeviceIdContext, Inspectable, TimerContext,
15    WeakDeviceIdentifier,
16};
17use netstack3_ip::RawMetric;
18use netstack3_ip::device::{DualStackIpDeviceState, IpDeviceTimerId};
19
20use crate::internal::base::{DeviceCounters, DeviceLayerTypes, OriginTracker};
21use crate::internal::queue::DeviceBufferSpec;
22use crate::internal::socket::HeldDeviceSockets;
23
24/// Provides the specifications for device state held by [`BaseDeviceId`] in
25/// [`BaseDeviceState`].
26pub trait DeviceStateSpec: Device + Sized + Send + Sync + 'static {
27    /// The device state.
28    type State<BT: DeviceLayerTypes>: Send + Sync;
29    /// The external (bindings) state.
30    type External<BT: DeviceLayerTypes>: Send + Sync;
31    /// Properties given to device creation.
32    type CreationProperties: Debug;
33    /// Device-specific counters.
34    type Counters: Inspectable;
35    /// The timer identifier required by this device state.
36    type TimerId<D: WeakDeviceIdentifier>;
37
38    /// Creates a new device state from the given properties.
39    fn new_device_state<
40        CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
41        BC: DeviceLayerTypes + TimerContext,
42    >(
43        bindings_ctx: &mut BC,
44        self_id: CC::WeakDeviceId,
45        properties: Self::CreationProperties,
46        tx_allocator: <Self as DeviceBufferSpec<BC>>::TxAllocator,
47    ) -> Self::State<BC>
48    where
49        Self: DeviceBufferSpec<BC>;
50
51    /// Marker for loopback devices.
52    const IS_LOOPBACK: bool;
53    /// Marker used to print debug information for device identifiers.
54    const DEBUG_TYPE: &'static str;
55
56    /// Returns the TX checksum offload specification for the device, if it has one.
57    fn tx_offload_spec<BT: DeviceLayerTypes>(
58        state: &Self::State<BT>,
59    ) -> Option<ChecksumOffloadSpec>;
60}
61
62/// Groups state kept by weak device references.
63///
64/// A weak device reference must be able to carry the bindings identifier
65/// infallibly. The `WeakCookie` is kept inside [`BaseDeviceState`] in an `Arc`
66/// to group all the information that is cloned out to support weak device
67/// references.
68pub(crate) struct WeakCookie<T: DeviceStateSpec, BT: DeviceLayerTypes> {
69    pub(crate) bindings_id: BT::DeviceIdentifier,
70    pub(crate) weak_ref: WeakRc<BaseDeviceState<T, BT>>,
71}
72
73pub(crate) struct BaseDeviceState<T: DeviceStateSpec, BT: DeviceLayerTypes> {
74    pub(crate) ip: IpLinkDeviceState<T, BT>,
75    pub(crate) external_state: T::External<BT>,
76    pub(crate) weak_cookie: Arc<WeakCookie<T, BT>>,
77}
78
79/// A convenience wrapper around `IpLinkDeviceStateInner` that uses
80/// `DeviceStateSpec` to extract the link state type and make type signatures
81/// shorter.
82pub type IpLinkDeviceState<T, BT> = IpLinkDeviceStateInner<<T as DeviceStateSpec>::State<BT>, BT>;
83
84/// State for a link-device that is also an IP device.
85///
86/// `D` is the link-specific state.
87pub struct IpLinkDeviceStateInner<T, BT: DeviceLayerTypes> {
88    /// The device's IP state.
89    pub ip: DualStackIpDeviceState<BT>,
90    /// The device's link state.
91    pub link: T,
92    pub(crate) origin: OriginTracker,
93    pub(super) sockets: RwLock<HeldDeviceSockets<BT>>,
94    /// Common device counters.
95    pub counters: DeviceCounters,
96}
97
98impl<T, BC: DeviceLayerTypes + TimerContext> IpLinkDeviceStateInner<T, BC> {
99    /// Create a new `IpLinkDeviceState` with a link-specific state `link`.
100    pub fn new<
101        D: WeakDeviceIdentifier,
102        CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D, BC>, BC>
103            + CoreTimerContext<IpDeviceTimerId<Ipv4, D, BC>, BC>,
104    >(
105        bindings_ctx: &mut BC,
106        device_id: D,
107        link: T,
108        metric: RawMetric,
109        origin: OriginTracker,
110    ) -> Self {
111        Self {
112            ip: DualStackIpDeviceState::new::<D, CC>(bindings_ctx, device_id, metric),
113            link,
114            origin,
115            sockets: RwLock::new(HeldDeviceSockets::default()),
116            counters: DeviceCounters::default(),
117        }
118    }
119}
120
121impl<T, BT: DeviceLayerTypes> AsRef<DualStackIpDeviceState<BT>> for IpLinkDeviceStateInner<T, BT> {
122    fn as_ref(&self) -> &DualStackIpDeviceState<BT> {
123        &self.ip
124    }
125}
126
127impl<T, BT: DeviceLayerTypes> OrderedLockAccess<HeldDeviceSockets<BT>>
128    for IpLinkDeviceStateInner<T, BT>
129{
130    type Lock = RwLock<HeldDeviceSockets<BT>>;
131    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
132        OrderedLockRef::new(&self.sockets)
133    }
134}
135
136/// Context for getting the TX checksum offload specification for a device.
137pub trait DeviceTxOffloadSpecContext<D: DeviceStateSpec, BT: DeviceLayerTypes>:
138    DeviceIdContext<D>
139{
140    /// Returns the TX checksum offload specification for `device`, if it has one.
141    fn tx_offload_spec(&self, device: &Self::DeviceId) -> Option<ChecksumOffloadSpec>;
142}