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        core_ctx.increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_frame);
177
178        // NB: For conformance with Linux, don't verify that the contents of
179        // of the buffer are a valid IPv4/IPv6 packet. Device sockets are
180        // allowed to receive malformed packets.
181        core_ctx.handle_frame(
182            bindings_ctx,
183            &device_id,
184            Frame::Received(ReceivedFrame::Ip(IpFrame { ip_version, body: buffer.as_ref() })),
185            buffer.as_ref(),
186        );
187
188        match ip_version {
189            IpVersion::V4 => {
190                core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
191                    &counters.recv_ipv4_delivered
192                });
193                core_ctx.receive_frame(
194                    bindings_ctx,
195                    RecvIpFrameMeta::<_, _, Ipv4>::new(
196                        device_id,
197                        None,
198                        DeviceIpLayerMetadata::default(),
199                    ),
200                    buffer,
201                )
202            }
203            IpVersion::V6 => {
204                core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
205                    &counters.recv_ipv6_delivered
206                });
207                core_ctx.receive_frame(
208                    bindings_ctx,
209                    RecvIpFrameMeta::<_, _, Ipv6>::new(
210                        device_id,
211                        None,
212                        DeviceIpLayerMetadata::default(),
213                    ),
214                    buffer,
215                )
216            }
217        }
218    }
219}
220
221impl<CC, BC> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<PureIpDevice, CC::DeviceId>
222where
223    CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
224        + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
225    BC: TxMetadataBindingsTypes,
226{
227    fn send_meta<S>(
228        self,
229        core_ctx: &mut CC,
230        bindings_ctx: &mut BC,
231        body: S,
232    ) -> Result<(), SendFrameError<S>>
233    where
234        S: Serializer,
235        S::Buffer: BufferMut,
236    {
237        let Self { device_id, metadata: PureIpHeaderParams { ip_version } } = self;
238        // TODO(https://fxbug.dev/391946195): Apply send buffer enforcement from
239        // device sockets instead of using default.
240        let tx_meta: BC::TxMetadata = Default::default();
241        net_types::for_any_ip_version!(
242            ip_version,
243            I,
244            queue_ip_frame::<_, _, I, _>(core_ctx, bindings_ctx, &device_id, body, tx_meta)
245        )
246    }
247}
248
249/// Enqueues the given IP packet on the TX queue for the given [`PureIpDevice`].
250pub fn send_ip_frame<BC, CC, I, S>(
251    core_ctx: &mut CC,
252    bindings_ctx: &mut BC,
253    device_id: &CC::DeviceId,
254    destination: IpPacketDestination<I, &DeviceId<BC>>,
255    packet: S,
256    tx_meta: BC::TxMetadata,
257) -> Result<(), SendFrameError<S>>
258where
259    BC: DeviceLayerTypes,
260    CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
261        + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
262    I: Ip + BroadcastIpExt,
263    S: Serializer,
264    S::Buffer: BufferMut,
265{
266    core_ctx.increment_both(device_id, |counters| &counters.send_total_frames);
267    core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
268
269    match destination {
270        IpPacketDestination::Broadcast(_)
271        | IpPacketDestination::Multicast(_)
272        | IpPacketDestination::Neighbor(_) => (),
273        IpPacketDestination::Loopback(_) => {
274            unreachable!("Loopback packets must be delivered through the loopback device");
275        }
276    };
277
278    queue_ip_frame::<_, _, I, _>(core_ctx, bindings_ctx, device_id, packet, tx_meta)
279}
280
281fn queue_ip_frame<BC, CC, I, S>(
282    core_ctx: &mut CC,
283    bindings_ctx: &mut BC,
284    device_id: &CC::DeviceId,
285    packet: S,
286    tx_metadata: BC::TxMetadata,
287) -> Result<(), SendFrameError<S>>
288where
289    CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
290        + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
291    BC: TxMetadataBindingsTypes,
292    I: Ip,
293    S: Serializer,
294    S::Buffer: BufferMut,
295{
296    let result = TransmitQueueHandler::<PureIpDevice, _>::queue_tx_frame(
297        core_ctx,
298        bindings_ctx,
299        device_id,
300        PureIpDeviceTxQueueFrameMetadata { ip_version: I::VERSION, tx_metadata },
301        packet,
302    );
303    match result {
304        Ok(()) => {
305            core_ctx.increment_both(device_id, |counters| &counters.send_frame);
306            Ok(())
307        }
308        Err(TransmitQueueFrameError::NoQueue(err)) => {
309            core_ctx.increment_both(device_id, |counters| &counters.send_dropped_no_queue);
310            debug!("device {device_id:?} failed to send frame: {err:?}.");
311            Ok(())
312        }
313        Err(TransmitQueueFrameError::QueueFull(serializer)) => {
314            core_ctx.increment_both(device_id, |counters| &counters.send_queue_full);
315            Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
316        }
317        Err(TransmitQueueFrameError::SerializeError(err)) => {
318            core_ctx.increment_both(device_id, |counters| &counters.send_serialize_error);
319            Err(err.err_into())
320        }
321    }
322}
323
324/// Gets the MTU of the given [`PureIpDevice`].
325pub fn get_mtu<CC: PureIpDeviceStateContext>(core_ctx: &mut CC, device_id: &CC::DeviceId) -> Mtu {
326    core_ctx.with_pure_ip_state(device_id, |DynamicPureIpDeviceState { mtu }| *mtu)
327}
328
329/// Updates the MTU of the given [`PureIpDevice`].
330pub fn set_mtu<CC: PureIpDeviceStateContext>(
331    core_ctx: &mut CC,
332    device_id: &CC::DeviceId,
333    new_mtu: Mtu,
334) {
335    core_ctx.with_pure_ip_state_mut(device_id, |DynamicPureIpDeviceState { mtu }| *mtu = new_mtu)
336}
337
338impl<BT: DeviceLayerTypes> OrderedLockAccess<DynamicPureIpDeviceState>
339    for IpLinkDeviceState<PureIpDevice, BT>
340{
341    type Lock = RwLock<DynamicPureIpDeviceState>;
342    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
343        OrderedLockRef::new(&self.link.dynamic_state)
344    }
345}
346
347impl<BT: DeviceLayerTypes>
348    OrderedLockAccess<
349        TransmitQueueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>, BufVecU8Allocator>,
350    > for IpLinkDeviceState<PureIpDevice, BT>
351{
352    type Lock = Mutex<
353        TransmitQueueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>, BufVecU8Allocator>,
354    >;
355    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
356        OrderedLockRef::new(&self.link.tx_queue.queue)
357    }
358}
359
360impl<BT: DeviceLayerTypes>
361    OrderedLockAccess<DequeueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>>>
362    for IpLinkDeviceState<PureIpDevice, BT>
363{
364    type Lock = Mutex<DequeueState<PureIpDeviceTxQueueFrameMetadata<BT>, Buf<Vec<u8>>>>;
365    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
366        OrderedLockRef::new(&self.link.tx_queue.deque)
367    }
368}