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::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<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
125 pub counters: EthernetDeviceCounters,
127 pub mtu: Mtu,
129 pub rx_queue: ReceiveQueue<LoopbackRxQueueMeta<D, BT>, Buf<Vec<u8>>>,
131 pub tx_queue: TransmitQueue<
133 LoopbackTxQueueMeta<D, BT>,
134 <LoopbackDevice as DeviceBufferSpec<BT>>::TxBuffer,
135 <LoopbackDevice as DeviceBufferSpec<BT>>::TxAllocator,
136 >,
137}
138
139pub struct LoopbackTxQueueMeta<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
141 target_device: Option<D>,
144 ip_layer_metadata: DeviceIpLayerMetadata<BT>,
147}
148
149impl<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> TxQueuePacketMetadataCommon
150 for LoopbackTxQueueMeta<D, BT>
151{
152 fn set_checksum_offload_result(
153 &mut self,
154 _result: Option<netstack3_base::ChecksumOffloadResult>,
155 ) {
156 }
159}
160
161#[derive(Derivative)]
163#[derivative(Debug(bound = ""))]
164pub struct LoopbackRxQueueMeta<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
165 target_device: Option<D>,
168 ip_layer_metadata: DeviceIpLayerMetadata<BT>,
171}
172
173impl<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> From<LoopbackTxQueueMeta<D, BT>>
174 for LoopbackRxQueueMeta<D, BT>
175{
176 fn from(
177 LoopbackTxQueueMeta { target_device, ip_layer_metadata }: LoopbackTxQueueMeta<D, BT>,
178 ) -> Self {
179 Self { target_device, ip_layer_metadata }
180 }
181}
182
183impl<BT: DeviceLayerTypes>
184 OrderedLockAccess<ReceiveQueueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
185 for IpLinkDeviceState<LoopbackDevice, BT>
186{
187 type Lock = Mutex<ReceiveQueueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
188 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
189 OrderedLockRef::new(&self.link.rx_queue.queue)
190 }
191}
192
193impl<BT: DeviceLayerTypes>
194 OrderedLockAccess<DequeueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
195 for IpLinkDeviceState<LoopbackDevice, BT>
196{
197 type Lock = Mutex<DequeueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
198 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
199 OrderedLockRef::new(&self.link.rx_queue.deque)
200 }
201}
202
203impl<BT: DeviceLayerTypes>
204 OrderedLockAccess<
205 TransmitQueueState<
206 LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>,
207 Buf<Vec<u8>>,
208 BufVecU8Allocator,
209 >,
210 > for IpLinkDeviceState<LoopbackDevice, BT>
211{
212 type Lock = Mutex<
213 TransmitQueueState<
214 LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>,
215 Buf<Vec<u8>>,
216 BufVecU8Allocator,
217 >,
218 >;
219 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
220 OrderedLockRef::new(&self.link.tx_queue.queue)
221 }
222}
223
224impl<BT: DeviceLayerTypes>
225 OrderedLockAccess<DequeueState<LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
226 for IpLinkDeviceState<LoopbackDevice, BT>
227{
228 type Lock = Mutex<DequeueState<LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
229 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
230 OrderedLockRef::new(&self.link.tx_queue.deque)
231 }
232}
233
234impl DeviceSocketSendTypes for LoopbackDevice {
235 type Metadata = Option<EthernetHeaderParams>;
238}
239
240impl<CC, BC> ReceiveDequeFrameContext<LoopbackDevice, BC> for CC
241where
242 CC: DeviceIdContext<LoopbackDevice>
243 + ResourceCounterContext<Self::DeviceId, EthernetDeviceCounters>
244 + ReceiveQueueTypes<
245 LoopbackDevice,
246 BC,
247 Meta = LoopbackRxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
248 >,
249 CC: DeviceIdAnyCompatContext<LoopbackDevice>
251 + RecvFrameContext<
252 RecvIpFrameMeta<
253 <CC as DeviceIdContext<AnyDevice>>::DeviceId,
254 DeviceIpLayerMetadata<BC>,
255 Ipv4,
256 >,
257 BC,
258 > + RecvFrameContext<
259 RecvIpFrameMeta<
260 <CC as DeviceIdContext<AnyDevice>>::DeviceId,
261 DeviceIpLayerMetadata<BC>,
262 Ipv6,
263 >,
264 BC,
265 > + ResourceCounterContext<<CC as DeviceIdContext<AnyDevice>>::DeviceId, DeviceCounters>
266 + ResourceCounterContext<<CC as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<Ipv4>>
267 + ResourceCounterContext<<CC as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<Ipv6>>
268 + DeviceSocketHandler<AnyDevice, BC>,
269 CC::Buffer: BufferMut + Debug,
270 BC: DeviceLayerTypes,
271{
272 fn handle_frame(
273 &mut self,
274 bindings_ctx: &mut BC,
275 device_id: &Self::DeviceId,
276 rx_meta: Self::Meta,
277 mut buf: Self::Buffer,
278 ) {
279 let mut buf = Buf::new(buf.as_mut(), ..);
288 let buflen = buf.len();
289
290 let (frame, whole_body) =
291 match buf.parse_with_view::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck) {
292 Err(e) => {
293 self.increment_both(&device_id.clone().into(), |counters: &DeviceCounters| {
294 &counters.recv_parse_error
295 });
296 trace!("dropping invalid ethernet frame over loopback: {:?}", e);
297 return;
298 }
299 Ok(e) => e,
300 };
301
302 let LoopbackRxQueueMeta { target_device, mut ip_layer_metadata } = rx_meta;
303 let target_device: <CC as DeviceIdContext<AnyDevice>>::DeviceId =
304 match target_device.map(|d| d.upgrade()) {
305 Some(Some(dev)) => dev,
307
308 Some(None) => return,
310
311 None => device_id.clone().into(),
313 };
314
315 self.add_both_usize(&target_device, buflen, |counters: &DeviceCounters| {
316 &counters.recv_bytes
317 });
318 self.increment_both(&target_device, |counters: &DeviceCounters| &counters.recv_frame);
319
320 let frame_dest = FrameDestination::from_dest(frame.dst_mac(), Mac::UNSPECIFIED);
321 let ethertype = frame.ethertype();
322
323 let packet_type = match ip_layer_metadata.packet_type() {
324 PacketType::Loopback => PacketType::Loopback,
325 _ => PacketType::from(frame_dest),
326 };
327 ip_layer_metadata.set_packet_type(packet_type);
328
329 DeviceSocketHandler::<AnyDevice, _>::handle_frame(
330 self,
331 bindings_ctx,
332 &target_device,
333 ReceivedFrame::from_ethernet(frame, frame_dest, packet_type, None).into(),
334 whole_body,
335 );
336
337 match ethertype {
338 Some(EtherType::Ipv4) => {
339 let local_frame_dst = match frame_dest.check_local() {
340 Some(dst) => dst,
341 None => {
342 self.increment_both(&target_device, |counters: &IpCounters<Ipv4>| {
343 &counters.drop_ip_packet_other_host
344 });
345 return;
346 }
347 };
348 self.increment_both(&target_device, |counters: &DeviceCounters| {
349 &counters.recv_ipv4_delivered
350 });
351 self.receive_frame(
352 bindings_ctx,
353 RecvIpFrameMeta::<_, _, Ipv4>::new(
354 target_device,
355 Some(local_frame_dst),
356 ip_layer_metadata,
357 NetworkParsingContext::new(ChecksumRxOffloading::FullyOffloaded),
358 None,
359 ),
360 buf,
361 );
362 }
363 Some(EtherType::Ipv6) => {
364 let local_frame_dst = match frame_dest.check_local() {
365 Some(dst) => dst,
366 None => {
367 self.increment_both(&target_device, |counters: &IpCounters<Ipv6>| {
368 &counters.drop_ip_packet_other_host
369 });
370 return;
371 }
372 };
373 self.increment_both(&target_device, |counters: &DeviceCounters| {
374 &counters.recv_ipv6_delivered
375 });
376 self.receive_frame(
377 bindings_ctx,
378 RecvIpFrameMeta::<_, _, Ipv6>::new(
379 target_device,
380 Some(local_frame_dst),
381 ip_layer_metadata,
382 NetworkParsingContext::new(ChecksumRxOffloading::FullyOffloaded),
383 None,
384 ),
385 buf,
386 );
387 }
388 Some(ethertype @ (EtherType::Arp | EtherType::Other(_))) => {
389 self.increment_both(device_id, |counters: &EthernetDeviceCounters| {
390 &counters.recv_unsupported_ethertype
391 });
392 trace!("not handling loopback frame of type {:?}", ethertype)
393 }
394 None => {
395 self.increment_both(device_id, |counters: &EthernetDeviceCounters| {
396 &counters.recv_no_ethertype
397 });
398 trace!("dropping ethernet frame without ethertype");
399 }
400 }
401 }
402}
403
404impl<CC, BC> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<LoopbackDevice, CC, BC>
405where
406 CC: TransmitQueueHandler<
407 LoopbackDevice,
408 BC,
409 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
410 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
411 + DeviceIdContext<AnyDevice>,
412 BC: DeviceLayerTypes,
413{
414 fn send_meta<S>(
415 self,
416 core_ctx: &mut CC,
417 bindings_ctx: &mut BC,
418 body: S,
419 ) -> Result<(), SendFrameError<S>>
420 where
421 S: NetworkSerializer,
422 S::Buffer: BufferMut,
423 {
424 let Self { device_id, metadata, ip_layer_metadata } = self;
425 let tx_meta = LoopbackTxQueueMeta { target_device: None, ip_layer_metadata };
426 match metadata {
427 Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
428 core_ctx,
429 bindings_ctx,
430 &device_id,
431 body,
432 protocol,
433 dest_addr,
434 tx_meta,
435 ),
436 None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
437 }
438 }
439}
440
441pub fn send_ip_frame<CC, BC, I, S>(
443 core_ctx: &mut CC,
444 bindings_ctx: &mut BC,
445 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
446 destination: IpPacketDestination<I, &<CC as DeviceIdContext<AnyDevice>>::DeviceId>,
447 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
448 packet: S,
449) -> Result<(), SendFrameError<S>>
450where
451 CC: TransmitQueueHandler<
452 LoopbackDevice,
453 BC,
454 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
455 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
456 + DeviceIdContext<AnyDevice>,
457 BC: DeviceLayerTypes,
458 I: EthernetIpExt + BroadcastIpExt,
459 S: NetworkSerializer,
460 S::Buffer: BufferMut,
461{
462 core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
463
464 let (target_device, dst_mac) = match destination {
465 IpPacketDestination::Loopback(device) => (Some(device.downgrade()), LOOPBACK_MAC),
466 IpPacketDestination::Broadcast(_marker) => (None, Mac::BROADCAST),
467 IpPacketDestination::Multicast(multicast_ip) => (None, Mac::from(&multicast_ip)),
468 IpPacketDestination::Neighbor(_) => (None, LOOPBACK_MAC),
469 };
470 send_as_ethernet_frame_to_dst(
471 core_ctx,
472 bindings_ctx,
473 device_id,
474 packet,
475 I::ETHER_TYPE,
476 dst_mac,
477 LoopbackTxQueueMeta { target_device, ip_layer_metadata },
478 )
479}
480
481fn send_as_ethernet_frame_to_dst<CC, BC, S>(
482 core_ctx: &mut CC,
483 bindings_ctx: &mut BC,
484 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
485 packet: S,
486 protocol: EtherType,
487 dst_mac: Mac,
488 meta: LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
489) -> Result<(), SendFrameError<S>>
490where
491 CC: TransmitQueueHandler<
492 LoopbackDevice,
493 BC,
494 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
495 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
496 + DeviceIdContext<AnyDevice>,
497 BC: DeviceLayerTypes,
498 S: NetworkSerializer,
499 S::Buffer: BufferMut,
500{
501 const MIN_BODY_LEN: usize = 0;
507
508 let frame =
509 EthernetFrameBuilder::new(LOOPBACK_MAC, dst_mac, protocol, MIN_BODY_LEN).wrap_body(packet);
510
511 send_ethernet_frame(core_ctx, bindings_ctx, device_id, frame, meta)
512 .map_err(|err| err.into_inner())
513}
514
515fn send_ethernet_frame<CC, BC, S>(
516 core_ctx: &mut CC,
517 bindings_ctx: &mut BC,
518 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
519 frame: S,
520 meta: LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
521) -> Result<(), SendFrameError<S>>
522where
523 CC: TransmitQueueHandler<
524 LoopbackDevice,
525 BC,
526 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
527 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
528 + DeviceIdContext<AnyDevice>,
529 S: NetworkSerializer,
530 S::Buffer: BufferMut,
531 BC: DeviceLayerTypes,
532{
533 core_ctx.increment_both(device_id, |counters: &DeviceCounters| &counters.send_total_frames);
534 match TransmitQueueHandler::<LoopbackDevice, _>::queue_tx_frame(
535 core_ctx,
536 bindings_ctx,
537 device_id,
538 meta,
539 frame,
540 ) {
541 Ok(len) => {
542 core_ctx.add_both_usize(device_id, len, |counters| &counters.send_bytes);
543 core_ctx.increment_both(device_id, |counters: &DeviceCounters| &counters.send_frame);
544 Ok(())
545 }
546 Err(TransmitQueueFrameError::NoQueue(err)) => {
547 unreachable!("loopback never fails to send a frame: {err:?}")
548 }
549 Err(TransmitQueueFrameError::QueueFull(serializer)) => {
550 core_ctx
551 .increment_both(device_id, |counters: &DeviceCounters| &counters.send_queue_full);
552 Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
553 }
554 Err(TransmitQueueFrameError::SerializeError(err)) => {
555 core_ctx.increment_both(device_id, |counters: &DeviceCounters| {
556 &counters.send_serialize_error
557 });
558 Err(err.err_into())
559 }
560 }
561}
562
563impl DeviceReceiveFrameSpec for LoopbackDevice {
564 type FrameMetadata<D> = !;
567}