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