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