netstack3_device/
pure_ip.rs

1// Copyright 2024 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//! A pure IP device, capable of directly sending/receiving IPv4 & IPv6 packets.
6
7use alloc::vec::Vec;
8use core::convert::Infallible as Never;
9use core::fmt::Debug;
10
11use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
12use log::debug;
13use net_types::ip::{Ip, IpVersion, Ipv4, Ipv6, Mtu};
14use netstack3_base::sync::{Mutex, RwLock};
15use netstack3_base::{
16    BroadcastIpExt, CoreTimerContext, Device, DeviceIdContext, ReceivableFrameMeta,
17    RecvFrameContext, RecvIpFrameMeta, ResourceCounterContext, SendFrameError,
18    SendFrameErrorReason, SendableFrameMeta, TimerContext, TxMetadataBindingsTypes,
19    WeakDeviceIdentifier,
20};
21use netstack3_ip::{DeviceIpLayerMetadata, IpPacketDestination};
22use packet::{Buf, BufferMut, Serializer};
23
24use crate::internal::base::{
25    DeviceCounters, DeviceLayerTypes, DeviceReceiveFrameSpec, PureIpDeviceCounters,
26};
27use crate::internal::id::{BaseDeviceId, BasePrimaryDeviceId, BaseWeakDeviceId, DeviceId};
28use crate::internal::queue::tx::{
29    BufVecU8Allocator, TransmitQueue, TransmitQueueHandler, TransmitQueueState,
30};
31use crate::internal::queue::{DequeueState, TransmitQueueFrameError};
32use crate::internal::socket::{
33    DeviceSocketHandler, DeviceSocketMetadata, DeviceSocketSendTypes, Frame, IpFrame, ReceivedFrame,
34};
35use crate::internal::state::{DeviceStateSpec, IpLinkDeviceState};
36
37/// A weak device ID identifying a pure IP device.
38///
39/// This device ID is like [`WeakDeviceId`] but specifically for pure IP
40/// devices.
41///
42/// [`WeakDeviceId`]: crate::device::WeakDeviceId
43pub type PureIpWeakDeviceId<BT> = BaseWeakDeviceId<PureIpDevice, BT>;
44
45/// A strong device ID identifying a pure IP device.
46///
47/// This device ID is like [`DeviceId`] but specifically for pure IP devices.
48///
49/// [`DeviceId`]: crate::device::DeviceId
50pub type PureIpDeviceId<BT> = BaseDeviceId<PureIpDevice, BT>;
51
52/// The primary reference for a pure IP device.
53pub type PureIpPrimaryDeviceId<BT> = BasePrimaryDeviceId<PureIpDevice, BT>;
54
55/// A marker type identifying a pure IP device.
56#[derive(Copy, Clone)]
57pub enum PureIpDevice {}
58
59/// The parameters required to create a pure IP device.
60#[derive(Debug)]
61pub struct PureIpDeviceCreationProperties {
62    /// The MTU of the device.
63    pub mtu: Mtu,
64}
65
66/// Metadata for IP packets held in the TX queue.
67pub struct PureIpDeviceTxQueueFrameMetadata<BT: TxMetadataBindingsTypes> {
68    /// The IP version of the sent packet.
69    pub ip_version: IpVersion,
70    /// Tx metadata associated with the frame.
71    pub tx_metadata: BT::TxMetadata,
72}
73
74/// Metadata for sending IP packets from a device socket.
75#[derive(Debug, PartialEq)]
76pub struct PureIpHeaderParams {
77    /// The IP version of the packet to send.
78    pub ip_version: IpVersion,
79}
80
81/// State for a pure IP device.
82pub struct PureIpDeviceState<BT: TxMetadataBindingsTypes> {
83    /// The device's dynamic state.
84    dynamic_state: RwLock<DynamicPureIpDeviceState>,
85    /// The device's transmit queue.
86    pub tx_queue:
87        TransmitQueue<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>, BufVecU8Allocator>,
88    /// Counters specific to pure IP devices.
89    pub counters: PureIpDeviceCounters,
90}
91
92/// Dynamic state for a pure IP device.
93pub struct DynamicPureIpDeviceState {
94    /// The MTU of the device.
95    pub(crate) mtu: Mtu,
96}
97
98impl Device for PureIpDevice {}
99
100impl DeviceStateSpec for PureIpDevice {
101    type State<BT: DeviceLayerTypes> = PureIpDeviceState<BT>;
102    type External<BT: DeviceLayerTypes> = BT::PureIpDeviceState;
103    type CreationProperties = PureIpDeviceCreationProperties;
104    type Counters = PureIpDeviceCounters;
105    const IS_LOOPBACK: bool = false;
106    const DEBUG_TYPE: &'static str = "PureIP";
107    type TimerId<D: WeakDeviceIdentifier> = Never;
108
109    fn new_device_state<
110        CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
111        BC: DeviceLayerTypes + TimerContext,
112    >(
113        _bindings_ctx: &mut BC,
114        _self_id: CC::WeakDeviceId,
115        PureIpDeviceCreationProperties { mtu }: Self::CreationProperties,
116    ) -> Self::State<BC> {
117        PureIpDeviceState {
118            dynamic_state: RwLock::new(DynamicPureIpDeviceState { mtu }),
119            tx_queue: Default::default(),
120            counters: PureIpDeviceCounters::default(),
121        }
122    }
123}
124
125/// Metadata for IP packets received on a pure IP device.
126pub struct PureIpDeviceReceiveFrameMetadata<D> {
127    /// The device a packet was received on.
128    pub device_id: D,
129    /// The IP version of the received packet.
130    pub ip_version: IpVersion,
131}
132
133impl DeviceReceiveFrameSpec for PureIpDevice {
134    type FrameMetadata<D> = PureIpDeviceReceiveFrameMetadata<D>;
135}
136
137/// Provides access to a pure IP device's state.
138pub trait PureIpDeviceStateContext: DeviceIdContext<PureIpDevice> {
139    /// Calls the function with an immutable reference to the pure IP device's
140    /// dynamic state.
141    fn with_pure_ip_state<O, F: FnOnce(&DynamicPureIpDeviceState) -> O>(
142        &mut self,
143        device_id: &Self::DeviceId,
144        cb: F,
145    ) -> O;
146
147    /// Calls the function with a mutable reference to the pure IP device's
148    /// dynamic state.
149    fn with_pure_ip_state_mut<O, F: FnOnce(&mut DynamicPureIpDeviceState) -> O>(
150        &mut self,
151        device_id: &Self::DeviceId,
152        cb: F,
153    ) -> O;
154}
155
156impl DeviceSocketSendTypes for PureIpDevice {
157    type Metadata = PureIpHeaderParams;
158}
159
160impl<CC, BC> ReceivableFrameMeta<CC, BC> for PureIpDeviceReceiveFrameMetadata<CC::DeviceId>
161where
162    CC: DeviceIdContext<PureIpDevice>
163        + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv4>, BC>
164        + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv6>, BC>
165        + ResourceCounterContext<CC::DeviceId, DeviceCounters>
166        + DeviceSocketHandler<PureIpDevice, BC>,
167    BC: TxMetadataBindingsTypes,
168{
169    fn receive_meta<B: BufferMut + Debug>(
170        self,
171        core_ctx: &mut CC,
172        bindings_ctx: &mut BC,
173        buffer: B,
174    ) {
175        let Self { device_id, ip_version } = self;
176
177        core_ctx.add_both_usize(&device_id, buffer.len(), |counters: &DeviceCounters| {
178            &counters.recv_bytes
179        });
180        core_ctx.increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_frame);
181
182        // NB: For conformance with Linux, don't verify that the contents of
183        // of the buffer are a valid IPv4/IPv6 packet. Device sockets are
184        // allowed to receive malformed packets.
185        core_ctx.handle_frame(
186            bindings_ctx,
187            &device_id,
188            Frame::Received(ReceivedFrame::Ip(IpFrame { ip_version, body: buffer.as_ref() })),
189            buffer.as_ref(),
190        );
191
192        match ip_version {
193            IpVersion::V4 => {
194                core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
195                    &counters.recv_ipv4_delivered
196                });
197                core_ctx.receive_frame(
198                    bindings_ctx,
199                    RecvIpFrameMeta::<_, _, Ipv4>::new(
200                        device_id,
201                        None,
202                        DeviceIpLayerMetadata::default(),
203                    ),
204                    buffer,
205                )
206            }
207            IpVersion::V6 => {
208                core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
209                    &counters.recv_ipv6_delivered
210                });
211                core_ctx.receive_frame(
212                    bindings_ctx,
213                    RecvIpFrameMeta::<_, _, Ipv6>::new(
214                        device_id,
215                        None,
216                        DeviceIpLayerMetadata::default(),
217                    ),
218                    buffer,
219                )
220            }
221        }
222    }
223}
224
225impl<CC, BC> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<PureIpDevice, CC::DeviceId>
226where
227    CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
228        + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
229    BC: TxMetadataBindingsTypes,
230{
231    fn send_meta<S>(
232        self,
233        core_ctx: &mut CC,
234        bindings_ctx: &mut BC,
235        body: S,
236    ) -> Result<(), SendFrameError<S>>
237    where
238        S: Serializer,
239        S::Buffer: BufferMut,
240    {
241        let Self { device_id, metadata: PureIpHeaderParams { ip_version } } = self;
242        // TODO(https://fxbug.dev/391946195): Apply send buffer enforcement from
243        // device sockets instead of using default.
244        let tx_meta: BC::TxMetadata = Default::default();
245        net_types::for_any_ip_version!(
246            ip_version,
247            I,
248            queue_ip_frame::<_, _, I, _>(core_ctx, bindings_ctx, &device_id, body, tx_meta)
249        )
250    }
251}
252
253/// Enqueues the given IP packet on the TX queue for the given [`PureIpDevice`].
254pub fn send_ip_frame<BC, CC, I, S>(
255    core_ctx: &mut CC,
256    bindings_ctx: &mut BC,
257    device_id: &CC::DeviceId,
258    destination: IpPacketDestination<I, &DeviceId<BC>>,
259    packet: S,
260    tx_meta: BC::TxMetadata,
261) -> Result<(), SendFrameError<S>>
262where
263    BC: DeviceLayerTypes,
264    CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
265        + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
266    I: Ip + BroadcastIpExt,
267    S: Serializer,
268    S::Buffer: BufferMut,
269{
270    core_ctx.increment_both(device_id, |counters| &counters.send_total_frames);
271    core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
272
273    match destination {
274        IpPacketDestination::Broadcast(_)
275        | IpPacketDestination::Multicast(_)
276        | IpPacketDestination::Neighbor(_) => (),
277        IpPacketDestination::Loopback(_) => {
278            unreachable!("Loopback packets must be delivered through the loopback device");
279        }
280    };
281
282    queue_ip_frame::<_, _, I, _>(core_ctx, bindings_ctx, device_id, packet, tx_meta)
283}
284
285fn queue_ip_frame<BC, CC, I, S>(
286    core_ctx: &mut CC,
287    bindings_ctx: &mut BC,
288    device_id: &CC::DeviceId,
289    packet: S,
290    tx_metadata: BC::TxMetadata,
291) -> Result<(), SendFrameError<S>>
292where
293    CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
294        + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
295    BC: TxMetadataBindingsTypes,
296    I: Ip,
297    S: Serializer,
298    S::Buffer: BufferMut,
299{
300    let result = TransmitQueueHandler::<PureIpDevice, _>::queue_tx_frame(
301        core_ctx,
302        bindings_ctx,
303        device_id,
304        PureIpDeviceTxQueueFrameMetadata { ip_version: I::VERSION, tx_metadata },
305        packet,
306    );
307    match result {
308        Ok(len) => {
309            core_ctx.add_both_usize(device_id, len, |counters| &counters.send_bytes);
310            core_ctx.increment_both(device_id, |counters| &counters.send_frame);
311            Ok(())
312        }
313        Err(TransmitQueueFrameError::NoQueue(err)) => {
314            core_ctx.increment_both(device_id, |counters| &counters.send_dropped_no_queue);
315            debug!("device {device_id:?} failed to send frame: {err:?}.");
316            Ok(())
317        }
318        Err(TransmitQueueFrameError::QueueFull(serializer)) => {
319            core_ctx.increment_both(device_id, |counters| &counters.send_queue_full);
320            Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
321        }
322        Err(TransmitQueueFrameError::SerializeError(err)) => {
323            core_ctx.increment_both(device_id, |counters| &counters.send_serialize_error);
324            Err(err.err_into())
325        }
326    }
327}
328
329/// Gets the MTU of the given [`PureIpDevice`].
330pub fn get_mtu<CC: PureIpDeviceStateContext>(core_ctx: &mut CC, device_id: &CC::DeviceId) -> Mtu {
331    core_ctx.with_pure_ip_state(device_id, |DynamicPureIpDeviceState { mtu }| *mtu)
332}
333
334/// Updates the MTU of the given [`PureIpDevice`].
335pub fn set_mtu<CC: PureIpDeviceStateContext>(
336    core_ctx: &mut CC,
337    device_id: &CC::DeviceId,
338    new_mtu: Mtu,
339) {
340    core_ctx.with_pure_ip_state_mut(device_id, |DynamicPureIpDeviceState { mtu }| *mtu = new_mtu)
341}
342
343impl<BT: DeviceLayerTypes> OrderedLockAccess<DynamicPureIpDeviceState>
344    for IpLinkDeviceState<PureIpDevice, BT>
345{
346    type Lock = RwLock<DynamicPureIpDeviceState>;
347    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
348        OrderedLockRef::new(&self.link.dynamic_state)
349    }
350}
351
352impl<BT: DeviceLayerTypes>
353    OrderedLockAccess<
354        TransmitQueueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>, BufVecU8Allocator>,
355    > for IpLinkDeviceState<PureIpDevice, BT>
356{
357    type Lock = Mutex<
358        TransmitQueueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>, BufVecU8Allocator>,
359    >;
360    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
361        OrderedLockRef::new(&self.link.tx_queue.queue)
362    }
363}
364
365impl<BT: DeviceLayerTypes>
366    OrderedLockAccess<DequeueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>>>
367    for IpLinkDeviceState<PureIpDevice, BT>
368{
369    type Lock = Mutex<DequeueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>>>;
370    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
371        OrderedLockRef::new(&self.link.tx_queue.deque)
372    }
373}