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, BT::RwLock>,
100 pub tx_queue: TransmitQueue<
102 PureIpDeviceTxQueueFrameMetadata<BT>,
103 <PureIpDevice as DeviceBufferSpec<BT>>::TxBuffer,
104 <PureIpDevice as DeviceBufferSpec<BT>>::TxAllocator,
105 BT,
106 >,
107 pub counters: PureIpDeviceCounters,
109}
110
111pub struct DynamicPureIpDeviceState {
113 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
159pub struct PureIpDeviceReceiveFrameMetadata<D> {
161 pub device_id: D,
163 pub ip_version: IpVersion,
165 pub parsing_context: NetworkParsingContext,
167 pub gso_info: Option<GsoInfo>,
169}
170
171impl DeviceReceiveFrameSpec for PureIpDevice {
172 type FrameMetadata<D> = PureIpDeviceReceiveFrameMetadata<D>;
173}
174
175pub trait PureIpDeviceStateContext: DeviceIdContext<PureIpDevice> {
177 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 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 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
297pub 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
373pub 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
378pub 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}