1use 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
37pub type PureIpWeakDeviceId<BT> = BaseWeakDeviceId<PureIpDevice, BT>;
44
45pub type PureIpDeviceId<BT> = BaseDeviceId<PureIpDevice, BT>;
51
52pub type PureIpPrimaryDeviceId<BT> = BasePrimaryDeviceId<PureIpDevice, BT>;
54
55#[derive(Copy, Clone)]
57pub enum PureIpDevice {}
58
59#[derive(Debug)]
61pub struct PureIpDeviceCreationProperties {
62 pub mtu: Mtu,
64 pub tx_offload_spec: netstack3_base::ChecksumOffloadSpec,
66}
67
68pub struct PureIpDeviceTxQueueFrameMetadata<BT: TxMetadataBindingsTypes> {
70 pub ip_version: IpVersion,
72 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#[derive(Debug, PartialEq)]
91pub struct PureIpHeaderParams {
92 pub ip_version: IpVersion,
94}
95
96pub struct PureIpDeviceState<BT: DeviceLayerTypes> {
98 dynamic_state: RwLock<DynamicPureIpDeviceState>,
100 pub tx_queue: TransmitQueue<
102 PureIpDeviceTxQueueFrameMetadata<BT>,
103 <PureIpDevice as DeviceBufferSpec<BT>>::TxBuffer,
104 <PureIpDevice as DeviceBufferSpec<BT>>::TxAllocator,
105 >,
106 pub counters: PureIpDeviceCounters,
108}
109
110pub struct DynamicPureIpDeviceState {
112 pub(crate) mtu: Mtu,
114}
115
116impl Device for PureIpDevice {}
117
118impl<BT: DeviceBufferBindingsTypes> DeviceBufferSpec<BT> for PureIpDevice {
119 type TxBuffer = BT::TxBuffer;
120 type TxAllocator = BT::TxAllocator;
121}
122
123impl DeviceStateSpec for PureIpDevice {
124 type State<BT: DeviceLayerTypes> = PureIpDeviceState<BT>;
125 type External<BT: DeviceLayerTypes> = BT::PureIpDeviceState;
126 type CreationProperties = PureIpDeviceCreationProperties;
127 type Counters = PureIpDeviceCounters;
128 const IS_LOOPBACK: bool = false;
129 const DEBUG_TYPE: &'static str = "PureIP";
130 type TimerId<D: WeakDeviceIdentifier> = !;
131
132 fn new_device_state<
133 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
134 BC: DeviceLayerTypes + TimerContext,
135 >(
136 _bindings_ctx: &mut BC,
137 _self_id: CC::WeakDeviceId,
138 PureIpDeviceCreationProperties { mtu, tx_offload_spec }: Self::CreationProperties,
139 tx_allocator: <Self as DeviceBufferSpec<BC>>::TxAllocator,
140 ) -> Self::State<BC>
141 where
142 Self: DeviceBufferSpec<BC>,
143 {
144 PureIpDeviceState {
145 dynamic_state: RwLock::new(DynamicPureIpDeviceState { mtu }),
146 tx_queue: TransmitQueue::new(tx_allocator, tx_offload_spec),
147 counters: PureIpDeviceCounters::default(),
148 }
149 }
150
151 fn tx_offload_spec<BT: DeviceLayerTypes>(
152 state: &Self::State<BT>,
153 ) -> Option<ChecksumOffloadSpec> {
154 Some(state.tx_queue.tx_offload_spec())
155 }
156}
157
158pub struct PureIpDeviceReceiveFrameMetadata<D> {
160 pub device_id: D,
162 pub ip_version: IpVersion,
164 pub parsing_context: NetworkParsingContext,
166 pub gso_info: Option<GsoInfo>,
168}
169
170impl DeviceReceiveFrameSpec for PureIpDevice {
171 type FrameMetadata<D> = PureIpDeviceReceiveFrameMetadata<D>;
172}
173
174pub trait PureIpDeviceStateContext: DeviceIdContext<PureIpDevice> {
176 fn with_pure_ip_state<O, F: FnOnce(&DynamicPureIpDeviceState) -> O>(
179 &mut self,
180 device_id: &Self::DeviceId,
181 cb: F,
182 ) -> O;
183
184 fn with_pure_ip_state_mut<O, F: FnOnce(&mut DynamicPureIpDeviceState) -> O>(
187 &mut self,
188 device_id: &Self::DeviceId,
189 cb: F,
190 ) -> O;
191}
192
193impl DeviceSocketSendTypes for PureIpDevice {
194 type Metadata = PureIpHeaderParams;
195}
196
197impl<CC, BC> ReceivableFrameMeta<CC, BC> for PureIpDeviceReceiveFrameMetadata<CC::DeviceId>
198where
199 CC: DeviceIdContext<PureIpDevice>
200 + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv4>, BC>
201 + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv6>, BC>
202 + ResourceCounterContext<CC::DeviceId, DeviceCounters>
203 + DeviceSocketHandler<PureIpDevice, BC>,
204 BC: TxMetadataBindingsTypes,
205{
206 fn receive_meta<B: BufferMut + Debug>(
207 self,
208 core_ctx: &mut CC,
209 bindings_ctx: &mut BC,
210 buffer: B,
211 ) {
212 let Self { device_id, ip_version, parsing_context, gso_info } = self;
213
214 core_ctx.add_both_usize(&device_id, buffer.len(), |counters: &DeviceCounters| {
215 &counters.recv_bytes
216 });
217 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_frame);
218
219 core_ctx.handle_frame(
223 bindings_ctx,
224 &device_id,
225 Frame::Received(ReceivedFrame::Ip {
226 frame: IpFrame { ip_version, body: buffer.as_ref() },
227 gso_info,
228 }),
229 buffer.as_ref(),
230 );
231
232 match ip_version {
233 IpVersion::V4 => {
234 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
235 &counters.recv_ipv4_delivered
236 });
237 core_ctx.receive_frame(
238 bindings_ctx,
239 RecvIpFrameMeta::<_, _, Ipv4>::new(
240 device_id,
241 None,
242 DeviceIpLayerMetadata::new_for_rx_packet(PURE_IP_PACKET_TYPE),
243 parsing_context,
244 gso_info,
245 ),
246 buffer,
247 )
248 }
249 IpVersion::V6 => {
250 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
251 &counters.recv_ipv6_delivered
252 });
253 core_ctx.receive_frame(
254 bindings_ctx,
255 RecvIpFrameMeta::<_, _, Ipv6>::new(
256 device_id,
257 None,
258 DeviceIpLayerMetadata::new_for_rx_packet(PURE_IP_PACKET_TYPE),
259 parsing_context,
260 gso_info,
261 ),
262 buffer,
263 )
264 }
265 }
266 }
267}
268
269impl<CC, BC> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<PureIpDevice, CC, BC>
270where
271 CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
272 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
273 BC: TxMetadataBindingsTypes,
274{
275 fn send_meta<S>(
276 self,
277 core_ctx: &mut CC,
278 bindings_ctx: &mut BC,
279 body: S,
280 ) -> Result<(), SendFrameError<S>>
281 where
282 S: NetworkSerializer,
283 S::Buffer: BufferMut,
284 {
285 let Self { device_id, metadata: PureIpHeaderParams { ip_version }, ip_layer_metadata } =
286 self;
287 let tx_meta = ip_layer_metadata.into_tx_metadata();
288 net_types::for_any_ip_version!(
289 ip_version,
290 I,
291 queue_ip_frame::<_, _, I, _>(core_ctx, bindings_ctx, &device_id, body, tx_meta)
292 )
293 }
294}
295
296pub fn send_ip_frame<BC, CC, I, S>(
298 core_ctx: &mut CC,
299 bindings_ctx: &mut BC,
300 device_id: &CC::DeviceId,
301 destination: IpPacketDestination<I, &DeviceId<BC>>,
302 packet: S,
303 tx_meta: BC::TxMetadata,
304) -> Result<(), SendFrameError<S>>
305where
306 BC: DeviceLayerTypes,
307 CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
308 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
309 I: Ip + BroadcastIpExt,
310 S: NetworkSerializer,
311 S::Buffer: BufferMut,
312{
313 core_ctx.increment_both(device_id, |counters| &counters.send_total_frames);
314 core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
315
316 match destination {
317 IpPacketDestination::Broadcast(_)
318 | IpPacketDestination::Multicast(_)
319 | IpPacketDestination::Neighbor(_) => (),
320 IpPacketDestination::Loopback(_) => {
321 unreachable!("Loopback packets must be delivered through the loopback device");
322 }
323 };
324
325 queue_ip_frame::<_, _, I, _>(core_ctx, bindings_ctx, device_id, packet, tx_meta)
326}
327
328fn queue_ip_frame<BC, CC, I, S>(
329 core_ctx: &mut CC,
330 bindings_ctx: &mut BC,
331 device_id: &CC::DeviceId,
332 packet: S,
333 tx_metadata: BC::TxMetadata,
334) -> Result<(), SendFrameError<S>>
335where
336 CC: TransmitQueueHandler<PureIpDevice, BC, Meta = PureIpDeviceTxQueueFrameMetadata<BC>>
337 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
338 BC: TxMetadataBindingsTypes,
339 I: Ip,
340 S: NetworkSerializer,
341 S::Buffer: BufferMut,
342{
343 let result = TransmitQueueHandler::<PureIpDevice, _>::queue_tx_frame(
344 core_ctx,
345 bindings_ctx,
346 device_id,
347 PureIpDeviceTxQueueFrameMetadata { ip_version: I::VERSION, tx_metadata },
348 packet,
349 );
350 match result {
351 Ok(len) => {
352 core_ctx.add_both_usize(device_id, len, |counters| &counters.send_bytes);
353 core_ctx.increment_both(device_id, |counters| &counters.send_frame);
354 Ok(())
355 }
356 Err(TransmitQueueFrameError::NoQueue(err)) => {
357 core_ctx.increment_both(device_id, |counters| &counters.send_dropped_no_queue);
358 debug!("device {device_id:?} failed to send frame: {err:?}.");
359 Ok(())
360 }
361 Err(TransmitQueueFrameError::QueueFull(serializer)) => {
362 core_ctx.increment_both(device_id, |counters| &counters.send_queue_full);
363 Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
364 }
365 Err(TransmitQueueFrameError::SerializeError(err)) => {
366 core_ctx.increment_both(device_id, |counters| &counters.send_serialize_error);
367 Err(err.err_into())
368 }
369 }
370}
371
372pub fn get_mtu<CC: PureIpDeviceStateContext>(core_ctx: &mut CC, device_id: &CC::DeviceId) -> Mtu {
374 core_ctx.with_pure_ip_state(device_id, |DynamicPureIpDeviceState { mtu }| *mtu)
375}
376
377pub fn set_mtu<CC: PureIpDeviceStateContext>(
379 core_ctx: &mut CC,
380 device_id: &CC::DeviceId,
381 new_mtu: Mtu,
382) {
383 core_ctx.with_pure_ip_state_mut(device_id, |DynamicPureIpDeviceState { mtu }| *mtu = new_mtu)
384}
385
386impl<BT: DeviceLayerTypes> OrderedLockAccess<DynamicPureIpDeviceState>
387 for IpLinkDeviceState<PureIpDevice, BT>
388{
389 type Lock = RwLock<DynamicPureIpDeviceState>;
390 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
391 OrderedLockRef::new(&self.link.dynamic_state)
392 }
393}
394
395impl<BT: DeviceLayerTypes>
396 OrderedLockAccess<
397 TransmitQueueState<PureIpDeviceTxQueueFrameMetadata<BT>, BT::TxBuffer, BT::TxAllocator>,
398 > for IpLinkDeviceState<PureIpDevice, BT>
399{
400 type Lock = Mutex<
401 TransmitQueueState<PureIpDeviceTxQueueFrameMetadata<BT>, BT::TxBuffer, BT::TxAllocator>,
402 >;
403 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
404 OrderedLockRef::new(&self.link.tx_queue.queue)
405 }
406}
407
408impl<BT: DeviceLayerTypes>
409 OrderedLockAccess<DequeueState<PureIpDeviceTxQueueFrameMetadata<BT>, BT::TxBuffer>>
410 for IpLinkDeviceState<PureIpDevice, BT>
411{
412 type Lock = Mutex<DequeueState<PureIpDeviceTxQueueFrameMetadata<BT>, BT::TxBuffer>>;
413 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
414 OrderedLockRef::new(&self.link.tx_queue.deque)
415 }
416}