Skip to main content

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