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