1use alloc::vec::Vec;
8use core::convert::Infallible as Never;
9use core::fmt::Debug;
10use derivative::Derivative;
11
12use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
13use log::trace;
14use net_types::ethernet::Mac;
15use net_types::ip::{Ipv4, Ipv6, Mtu};
16use netstack3_base::sync::Mutex;
17use netstack3_base::{
18 AnyDevice, BroadcastIpExt, ChecksumOffloadSpec, ChecksumRxOffloading, CoreTimerContext, Device,
19 DeviceIdAnyCompatContext, DeviceIdContext, FrameDestination, NetworkParsingContext,
20 NetworkSerializer, RecvFrameContext, RecvIpFrameMeta, ResourceCounterContext, SendFrameError,
21 SendFrameErrorReason, SendableFrameMeta, StrongDeviceIdentifier, TimerContext,
22 TxMetadataBindingsTypes, WeakDeviceIdentifier,
23};
24use netstack3_ip::{DeviceIpLayerMetadata, IpCounters, IpPacketDestination};
25use packet::{Buf, Buffer as _, BufferMut, FragmentedBuffer as _, NestablePacketBuilder as _};
26use packet_formats::ethernet::{
27 EtherType, EthernetFrame, EthernetFrameBuilder, EthernetFrameLengthCheck, EthernetIpExt,
28};
29
30use crate::internal::base::{
31 DeviceCounters, DeviceLayerTypes, DeviceReceiveFrameSpec, EthernetDeviceCounters,
32};
33use crate::internal::id::{BaseDeviceId, BasePrimaryDeviceId, BaseWeakDeviceId, WeakDeviceId};
34use crate::internal::queue::rx::{
35 ReceiveDequeFrameContext, ReceiveQueue, ReceiveQueueState, ReceiveQueueTypes,
36};
37use crate::internal::queue::tx::{
38 BufVecU8Allocator, TransmitQueue, TransmitQueueHandler, TransmitQueueState,
39 TxQueuePacketMetadataCommon,
40};
41use crate::internal::queue::{DequeueState, DeviceBufferSpec, TransmitQueueFrameError};
42use crate::internal::socket::{
43 DeviceSocketHandler, DeviceSocketMetadata, DeviceSocketSendTypes, EthernetHeaderParams,
44 ReceivedFrame,
45};
46use crate::internal::state::{DeviceStateSpec, IpLinkDeviceState};
47
48const LOOPBACK_MAC: Mac = Mac::UNSPECIFIED;
50
51pub type LoopbackWeakDeviceId<BT> = BaseWeakDeviceId<LoopbackDevice, BT>;
58
59pub type LoopbackDeviceId<BT> = BaseDeviceId<LoopbackDevice, BT>;
65
66pub type LoopbackPrimaryDeviceId<BT> = BasePrimaryDeviceId<LoopbackDevice, BT>;
68
69#[derive(Copy, Clone)]
71pub enum LoopbackDevice {}
72
73impl Device for LoopbackDevice {}
74
75impl<BT> DeviceBufferSpec<BT> for LoopbackDevice {
76 type TxBuffer = Buf<Vec<u8>>;
77 type TxAllocator = BufVecU8Allocator;
78}
79
80impl DeviceStateSpec for LoopbackDevice {
81 type State<BT: DeviceLayerTypes> = LoopbackDeviceState<WeakDeviceId<BT>, BT>;
82 type External<BT: DeviceLayerTypes> = BT::LoopbackDeviceState;
83 type CreationProperties = LoopbackCreationProperties;
84 type Counters = EthernetDeviceCounters;
85 type TimerId<D: WeakDeviceIdentifier> = Never;
86
87 fn new_device_state<
88 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
89 BC: DeviceLayerTypes + TimerContext,
90 >(
91 _bindings_ctx: &mut BC,
92 _self_id: CC::WeakDeviceId,
93 LoopbackCreationProperties { mtu }: Self::CreationProperties,
94 tx_allocator: <Self as DeviceBufferSpec<BC>>::TxAllocator,
95 ) -> Self::State<BC>
96 where
97 Self: DeviceBufferSpec<BC>,
98 {
99 LoopbackDeviceState {
100 counters: Default::default(),
101 mtu,
102 rx_queue: Default::default(),
103 tx_queue: TransmitQueue::new(tx_allocator, ChecksumOffloadSpec::generic()),
104 }
105 }
106
107 const IS_LOOPBACK: bool = true;
108 const DEBUG_TYPE: &'static str = "Loopback";
109}
110
111#[derive(Debug)]
113pub struct LoopbackCreationProperties {
114 pub mtu: Mtu,
116}
117
118pub struct LoopbackDeviceState<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
120 pub counters: EthernetDeviceCounters,
122 pub mtu: Mtu,
124 pub rx_queue: ReceiveQueue<LoopbackRxQueueMeta<D, BT>, Buf<Vec<u8>>>,
126 pub tx_queue: TransmitQueue<
128 LoopbackTxQueueMeta<D, BT>,
129 <LoopbackDevice as DeviceBufferSpec<BT>>::TxBuffer,
130 <LoopbackDevice as DeviceBufferSpec<BT>>::TxAllocator,
131 >,
132}
133
134#[derive(Derivative)]
135#[derivative(Default(bound = ""))]
136pub struct LoopbackTxQueueMeta<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
138 target_device: Option<D>,
141 ip_layer_metadata: DeviceIpLayerMetadata<BT>,
144}
145
146impl<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> TxQueuePacketMetadataCommon
147 for LoopbackTxQueueMeta<D, BT>
148{
149 fn set_checksum_offload_result(
150 &mut self,
151 _result: Option<netstack3_base::ChecksumOffloadResult>,
152 ) {
153 }
156}
157
158#[derive(Derivative)]
160#[derivative(Debug(bound = ""))]
161pub struct LoopbackRxQueueMeta<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
162 target_device: Option<D>,
165 ip_layer_metadata: DeviceIpLayerMetadata<BT>,
168}
169
170impl<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> From<LoopbackTxQueueMeta<D, BT>>
171 for LoopbackRxQueueMeta<D, BT>
172{
173 fn from(
174 LoopbackTxQueueMeta { target_device, ip_layer_metadata }: LoopbackTxQueueMeta<D, BT>,
175 ) -> Self {
176 Self { target_device, ip_layer_metadata }
177 }
178}
179
180impl<BT: DeviceLayerTypes>
181 OrderedLockAccess<ReceiveQueueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
182 for IpLinkDeviceState<LoopbackDevice, BT>
183{
184 type Lock = Mutex<ReceiveQueueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
185 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
186 OrderedLockRef::new(&self.link.rx_queue.queue)
187 }
188}
189
190impl<BT: DeviceLayerTypes>
191 OrderedLockAccess<DequeueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
192 for IpLinkDeviceState<LoopbackDevice, BT>
193{
194 type Lock = Mutex<DequeueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
195 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
196 OrderedLockRef::new(&self.link.rx_queue.deque)
197 }
198}
199
200impl<BT: DeviceLayerTypes>
201 OrderedLockAccess<
202 TransmitQueueState<
203 LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>,
204 Buf<Vec<u8>>,
205 BufVecU8Allocator,
206 >,
207 > for IpLinkDeviceState<LoopbackDevice, BT>
208{
209 type Lock = Mutex<
210 TransmitQueueState<
211 LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>,
212 Buf<Vec<u8>>,
213 BufVecU8Allocator,
214 >,
215 >;
216 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
217 OrderedLockRef::new(&self.link.tx_queue.queue)
218 }
219}
220
221impl<BT: DeviceLayerTypes>
222 OrderedLockAccess<DequeueState<LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
223 for IpLinkDeviceState<LoopbackDevice, BT>
224{
225 type Lock = Mutex<DequeueState<LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
226 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
227 OrderedLockRef::new(&self.link.tx_queue.deque)
228 }
229}
230
231impl DeviceSocketSendTypes for LoopbackDevice {
232 type Metadata = Option<EthernetHeaderParams>;
235}
236
237impl<CC, BC> ReceiveDequeFrameContext<LoopbackDevice, BC> for CC
238where
239 CC: DeviceIdContext<LoopbackDevice>
240 + ResourceCounterContext<Self::DeviceId, EthernetDeviceCounters>
241 + ReceiveQueueTypes<
242 LoopbackDevice,
243 BC,
244 Meta = LoopbackRxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
245 >,
246 CC: DeviceIdAnyCompatContext<LoopbackDevice>
248 + RecvFrameContext<
249 RecvIpFrameMeta<
250 <CC as DeviceIdContext<AnyDevice>>::DeviceId,
251 DeviceIpLayerMetadata<BC>,
252 Ipv4,
253 >,
254 BC,
255 > + RecvFrameContext<
256 RecvIpFrameMeta<
257 <CC as DeviceIdContext<AnyDevice>>::DeviceId,
258 DeviceIpLayerMetadata<BC>,
259 Ipv6,
260 >,
261 BC,
262 > + ResourceCounterContext<<CC as DeviceIdContext<AnyDevice>>::DeviceId, DeviceCounters>
263 + ResourceCounterContext<<CC as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<Ipv4>>
264 + ResourceCounterContext<<CC as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<Ipv6>>
265 + DeviceSocketHandler<AnyDevice, BC>,
266 CC::Buffer: BufferMut + Debug,
267 BC: DeviceLayerTypes,
268{
269 fn handle_frame(
270 &mut self,
271 bindings_ctx: &mut BC,
272 device_id: &Self::DeviceId,
273 rx_meta: Self::Meta,
274 mut buf: Self::Buffer,
275 ) {
276 let mut buf = Buf::new(buf.as_mut(), ..);
285 let buflen = buf.len();
286
287 let (frame, whole_body) =
288 match buf.parse_with_view::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck) {
289 Err(e) => {
290 self.increment_both(&device_id.clone().into(), |counters: &DeviceCounters| {
291 &counters.recv_parse_error
292 });
293 trace!("dropping invalid ethernet frame over loopback: {:?}", e);
294 return;
295 }
296 Ok(e) => e,
297 };
298
299 let LoopbackRxQueueMeta { target_device, ip_layer_metadata } = rx_meta;
300 let target_device: <CC as DeviceIdContext<AnyDevice>>::DeviceId =
301 match target_device.map(|d| d.upgrade()) {
302 Some(Some(dev)) => dev,
304
305 Some(None) => return,
307
308 None => device_id.clone().into(),
310 };
311
312 self.add_both_usize(&target_device, buflen, |counters: &DeviceCounters| {
313 &counters.recv_bytes
314 });
315 self.increment_both(&target_device, |counters: &DeviceCounters| &counters.recv_frame);
316
317 let frame_dest = FrameDestination::from_dest(frame.dst_mac(), Mac::UNSPECIFIED);
318 let ethertype = frame.ethertype();
319
320 DeviceSocketHandler::<AnyDevice, _>::handle_frame(
321 self,
322 bindings_ctx,
323 &target_device,
324 ReceivedFrame::from_ethernet(frame, frame_dest).into(),
325 whole_body,
326 );
327
328 match ethertype {
329 Some(EtherType::Ipv4) => {
330 let local_frame_dst = match frame_dest.check_local() {
331 Some(dst) => dst,
332 None => {
333 self.increment_both(&target_device, |counters: &IpCounters<Ipv4>| {
334 &counters.drop_ip_packet_other_host
335 });
336 return;
337 }
338 };
339 self.increment_both(&target_device, |counters: &DeviceCounters| {
340 &counters.recv_ipv4_delivered
341 });
342 self.receive_frame(
343 bindings_ctx,
344 RecvIpFrameMeta::<_, _, Ipv4>::new(
345 target_device,
346 Some(local_frame_dst),
347 ip_layer_metadata,
348 NetworkParsingContext::new(ChecksumRxOffloading::FullyOffloaded),
349 ),
350 buf,
351 );
352 }
353 Some(EtherType::Ipv6) => {
354 let local_frame_dst = match frame_dest.check_local() {
355 Some(dst) => dst,
356 None => {
357 self.increment_both(&target_device, |counters: &IpCounters<Ipv6>| {
358 &counters.drop_ip_packet_other_host
359 });
360 return;
361 }
362 };
363 self.increment_both(&target_device, |counters: &DeviceCounters| {
364 &counters.recv_ipv6_delivered
365 });
366 self.receive_frame(
367 bindings_ctx,
368 RecvIpFrameMeta::<_, _, Ipv6>::new(
369 target_device,
370 Some(local_frame_dst),
371 ip_layer_metadata,
372 NetworkParsingContext::new(ChecksumRxOffloading::FullyOffloaded),
373 ),
374 buf,
375 );
376 }
377 Some(ethertype @ (EtherType::Arp | EtherType::Other(_))) => {
378 self.increment_both(device_id, |counters: &EthernetDeviceCounters| {
379 &counters.recv_unsupported_ethertype
380 });
381 trace!("not handling loopback frame of type {:?}", ethertype)
382 }
383 None => {
384 self.increment_both(device_id, |counters: &EthernetDeviceCounters| {
385 &counters.recv_no_ethertype
386 });
387 trace!("dropping ethernet frame without ethertype");
388 }
389 }
390 }
391}
392
393impl<CC, BC> SendableFrameMeta<CC, BC>
394 for DeviceSocketMetadata<LoopbackDevice, <CC as DeviceIdContext<LoopbackDevice>>::DeviceId>
395where
396 CC: TransmitQueueHandler<
397 LoopbackDevice,
398 BC,
399 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
400 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
401 + DeviceIdContext<AnyDevice>,
402 BC: DeviceLayerTypes,
403{
404 fn send_meta<S>(
405 self,
406 core_ctx: &mut CC,
407 bindings_ctx: &mut BC,
408 body: S,
409 ) -> Result<(), SendFrameError<S>>
410 where
411 S: NetworkSerializer,
412 S::Buffer: BufferMut,
413 {
414 let Self { device_id, metadata } = self;
415 let tx_meta = LoopbackTxQueueMeta::default();
416 match metadata {
417 Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
418 core_ctx,
419 bindings_ctx,
420 &device_id,
421 body,
422 protocol,
423 dest_addr,
424 tx_meta,
425 ),
426 None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
427 }
428 }
429}
430
431pub fn send_ip_frame<CC, BC, I, S>(
433 core_ctx: &mut CC,
434 bindings_ctx: &mut BC,
435 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
436 destination: IpPacketDestination<I, &<CC as DeviceIdContext<AnyDevice>>::DeviceId>,
437 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
438 packet: S,
439) -> Result<(), SendFrameError<S>>
440where
441 CC: TransmitQueueHandler<
442 LoopbackDevice,
443 BC,
444 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
445 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
446 + DeviceIdContext<AnyDevice>,
447 BC: DeviceLayerTypes,
448 I: EthernetIpExt + BroadcastIpExt,
449 S: NetworkSerializer,
450 S::Buffer: BufferMut,
451{
452 core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
453
454 let target_device = match destination {
455 IpPacketDestination::Loopback(device) => Some(device.downgrade()),
456 IpPacketDestination::Broadcast(_)
457 | IpPacketDestination::Multicast(_)
458 | IpPacketDestination::Neighbor(_) => None,
459 };
460 send_as_ethernet_frame_to_dst(
461 core_ctx,
462 bindings_ctx,
463 device_id,
464 packet,
465 I::ETHER_TYPE,
466 LOOPBACK_MAC,
467 LoopbackTxQueueMeta { target_device, ip_layer_metadata },
468 )
469}
470
471fn send_as_ethernet_frame_to_dst<CC, BC, S>(
472 core_ctx: &mut CC,
473 bindings_ctx: &mut BC,
474 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
475 packet: S,
476 protocol: EtherType,
477 dst_mac: Mac,
478 meta: LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
479) -> Result<(), SendFrameError<S>>
480where
481 CC: TransmitQueueHandler<
482 LoopbackDevice,
483 BC,
484 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
485 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
486 + DeviceIdContext<AnyDevice>,
487 BC: DeviceLayerTypes,
488 S: NetworkSerializer,
489 S::Buffer: BufferMut,
490{
491 const MIN_BODY_LEN: usize = 0;
497
498 let frame =
499 EthernetFrameBuilder::new(LOOPBACK_MAC, dst_mac, protocol, MIN_BODY_LEN).wrap_body(packet);
500
501 send_ethernet_frame(core_ctx, bindings_ctx, device_id, frame, meta)
502 .map_err(|err| err.into_inner())
503}
504
505fn send_ethernet_frame<CC, BC, S>(
506 core_ctx: &mut CC,
507 bindings_ctx: &mut BC,
508 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
509 frame: S,
510 meta: LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
511) -> Result<(), SendFrameError<S>>
512where
513 CC: TransmitQueueHandler<
514 LoopbackDevice,
515 BC,
516 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
517 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
518 + DeviceIdContext<AnyDevice>,
519 S: NetworkSerializer,
520 S::Buffer: BufferMut,
521 BC: DeviceLayerTypes,
522{
523 core_ctx.increment_both(device_id, |counters: &DeviceCounters| &counters.send_total_frames);
524 match TransmitQueueHandler::<LoopbackDevice, _>::queue_tx_frame(
525 core_ctx,
526 bindings_ctx,
527 device_id,
528 meta,
529 frame,
530 ) {
531 Ok(len) => {
532 core_ctx.add_both_usize(device_id, len, |counters| &counters.send_bytes);
533 core_ctx.increment_both(device_id, |counters: &DeviceCounters| &counters.send_frame);
534 Ok(())
535 }
536 Err(TransmitQueueFrameError::NoQueue(err)) => {
537 unreachable!("loopback never fails to send a frame: {err:?}")
538 }
539 Err(TransmitQueueFrameError::QueueFull(serializer)) => {
540 core_ctx
541 .increment_both(device_id, |counters: &DeviceCounters| &counters.send_queue_full);
542 Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
543 }
544 Err(TransmitQueueFrameError::SerializeError(err)) => {
545 core_ctx.increment_both(device_id, |counters: &DeviceCounters| {
546 &counters.send_serialize_error
547 });
548 Err(err.err_into())
549 }
550 }
551}
552
553impl DeviceReceiveFrameSpec for LoopbackDevice {
554 type FrameMetadata<D> = Never;
557}