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, CoreTimerContext, Device, DeviceIdAnyCompatContext, DeviceIdContext,
19 FrameDestination, RecvFrameContext, RecvIpFrameMeta, ResourceCounterContext, SendFrameError,
20 SendFrameErrorReason, SendableFrameMeta, StrongDeviceIdentifier, TimerContext,
21 TxMetadataBindingsTypes, WeakDeviceIdentifier,
22};
23use netstack3_ip::{DeviceIpLayerMetadata, IpPacketDestination};
24use packet::{Buf, Buffer as _, BufferMut, FragmentedBuffer as _, PacketBuilder, Serializer};
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};
39use crate::internal::queue::{DequeueState, TransmitQueueFrameError};
40use crate::internal::socket::{
41 DeviceSocketHandler, DeviceSocketMetadata, DeviceSocketSendTypes, EthernetHeaderParams,
42 ReceivedFrame,
43};
44use crate::internal::state::{DeviceStateSpec, IpLinkDeviceState};
45
46const LOOPBACK_MAC: Mac = Mac::UNSPECIFIED;
48
49pub type LoopbackWeakDeviceId<BT> = BaseWeakDeviceId<LoopbackDevice, BT>;
56
57pub type LoopbackDeviceId<BT> = BaseDeviceId<LoopbackDevice, BT>;
63
64pub type LoopbackPrimaryDeviceId<BT> = BasePrimaryDeviceId<LoopbackDevice, BT>;
66
67#[derive(Copy, Clone)]
69pub enum LoopbackDevice {}
70
71impl Device for LoopbackDevice {}
72
73impl DeviceStateSpec for LoopbackDevice {
74 type State<BT: DeviceLayerTypes> = LoopbackDeviceState<WeakDeviceId<BT>, BT>;
75 type External<BT: DeviceLayerTypes> = BT::LoopbackDeviceState;
76 type CreationProperties = LoopbackCreationProperties;
77 type Counters = EthernetDeviceCounters;
78 type TimerId<D: WeakDeviceIdentifier> = Never;
79
80 fn new_device_state<
81 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
82 BC: DeviceLayerTypes + TimerContext,
83 >(
84 _bindings_ctx: &mut BC,
85 _self_id: CC::WeakDeviceId,
86 LoopbackCreationProperties { mtu }: Self::CreationProperties,
87 ) -> Self::State<BC> {
88 LoopbackDeviceState {
89 counters: Default::default(),
90 mtu,
91 rx_queue: Default::default(),
92 tx_queue: Default::default(),
93 }
94 }
95
96 const IS_LOOPBACK: bool = true;
97 const DEBUG_TYPE: &'static str = "Loopback";
98}
99
100#[derive(Debug)]
102pub struct LoopbackCreationProperties {
103 pub mtu: Mtu,
105}
106
107pub struct LoopbackDeviceState<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
109 pub counters: EthernetDeviceCounters,
111 pub mtu: Mtu,
113 pub rx_queue: ReceiveQueue<LoopbackRxQueueMeta<D, BT>, Buf<Vec<u8>>>,
115 pub tx_queue: TransmitQueue<LoopbackTxQueueMeta<D, BT>, Buf<Vec<u8>>, BufVecU8Allocator>,
117}
118
119#[derive(Derivative)]
120#[derivative(Default(bound = ""))]
121pub struct LoopbackTxQueueMeta<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
123 target_device: Option<D>,
126 ip_layer_metadata: DeviceIpLayerMetadata<BT>,
129}
130
131#[derive(Derivative)]
133#[derivative(Debug(bound = ""))]
134pub struct LoopbackRxQueueMeta<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> {
135 target_device: Option<D>,
138 ip_layer_metadata: DeviceIpLayerMetadata<BT>,
141}
142
143impl<D: WeakDeviceIdentifier, BT: TxMetadataBindingsTypes> From<LoopbackTxQueueMeta<D, BT>>
144 for LoopbackRxQueueMeta<D, BT>
145{
146 fn from(
147 LoopbackTxQueueMeta { target_device, ip_layer_metadata }: LoopbackTxQueueMeta<D, BT>,
148 ) -> Self {
149 Self { target_device, ip_layer_metadata }
150 }
151}
152
153impl<BT: DeviceLayerTypes>
154 OrderedLockAccess<ReceiveQueueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
155 for IpLinkDeviceState<LoopbackDevice, BT>
156{
157 type Lock = Mutex<ReceiveQueueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
158 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
159 OrderedLockRef::new(&self.link.rx_queue.queue)
160 }
161}
162
163impl<BT: DeviceLayerTypes>
164 OrderedLockAccess<DequeueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
165 for IpLinkDeviceState<LoopbackDevice, BT>
166{
167 type Lock = Mutex<DequeueState<LoopbackRxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
168 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
169 OrderedLockRef::new(&self.link.rx_queue.deque)
170 }
171}
172
173impl<BT: DeviceLayerTypes>
174 OrderedLockAccess<
175 TransmitQueueState<
176 LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>,
177 Buf<Vec<u8>>,
178 BufVecU8Allocator,
179 >,
180 > for IpLinkDeviceState<LoopbackDevice, BT>
181{
182 type Lock = Mutex<
183 TransmitQueueState<
184 LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>,
185 Buf<Vec<u8>>,
186 BufVecU8Allocator,
187 >,
188 >;
189 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
190 OrderedLockRef::new(&self.link.tx_queue.queue)
191 }
192}
193
194impl<BT: DeviceLayerTypes>
195 OrderedLockAccess<DequeueState<LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>
196 for IpLinkDeviceState<LoopbackDevice, BT>
197{
198 type Lock = Mutex<DequeueState<LoopbackTxQueueMeta<WeakDeviceId<BT>, BT>, Buf<Vec<u8>>>>;
199 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
200 OrderedLockRef::new(&self.link.tx_queue.deque)
201 }
202}
203
204impl DeviceSocketSendTypes for LoopbackDevice {
205 type Metadata = Option<EthernetHeaderParams>;
208}
209
210impl<CC, BC> ReceiveDequeFrameContext<LoopbackDevice, BC> for CC
211where
212 CC: DeviceIdContext<LoopbackDevice>
213 + ResourceCounterContext<Self::DeviceId, EthernetDeviceCounters>
214 + ReceiveQueueTypes<
215 LoopbackDevice,
216 BC,
217 Meta = LoopbackRxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
218 >,
219 CC: DeviceIdAnyCompatContext<LoopbackDevice>
221 + RecvFrameContext<
222 RecvIpFrameMeta<
223 <CC as DeviceIdContext<AnyDevice>>::DeviceId,
224 DeviceIpLayerMetadata<BC>,
225 Ipv4,
226 >,
227 BC,
228 > + RecvFrameContext<
229 RecvIpFrameMeta<
230 <CC as DeviceIdContext<AnyDevice>>::DeviceId,
231 DeviceIpLayerMetadata<BC>,
232 Ipv6,
233 >,
234 BC,
235 > + ResourceCounterContext<<CC as DeviceIdContext<AnyDevice>>::DeviceId, DeviceCounters>
236 + DeviceSocketHandler<AnyDevice, BC>,
237 CC::Buffer: BufferMut + Debug,
238 BC: DeviceLayerTypes,
239{
240 fn handle_frame(
241 &mut self,
242 bindings_ctx: &mut BC,
243 device_id: &Self::DeviceId,
244 rx_meta: Self::Meta,
245 mut buf: Self::Buffer,
246 ) {
247 let mut buf = Buf::new(buf.as_mut(), ..);
256 let buflen = buf.len();
257
258 let (frame, whole_body) =
259 match buf.parse_with_view::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck) {
260 Err(e) => {
261 self.increment_both(&device_id.clone().into(), |counters: &DeviceCounters| {
262 &counters.recv_parse_error
263 });
264 trace!("dropping invalid ethernet frame over loopback: {:?}", e);
265 return;
266 }
267 Ok(e) => e,
268 };
269
270 let LoopbackRxQueueMeta { target_device, ip_layer_metadata } = rx_meta;
271 let target_device: <CC as DeviceIdContext<AnyDevice>>::DeviceId =
272 match target_device.map(|d| d.upgrade()) {
273 Some(Some(dev)) => dev,
275
276 Some(None) => return,
278
279 None => device_id.clone().into(),
281 };
282
283 self.add_both_usize(&target_device, buflen, |counters: &DeviceCounters| {
284 &counters.recv_bytes
285 });
286 self.increment_both(&target_device, |counters: &DeviceCounters| &counters.recv_frame);
287
288 let frame_dest = FrameDestination::from_dest(frame.dst_mac(), Mac::UNSPECIFIED);
289 let ethertype = frame.ethertype();
290
291 DeviceSocketHandler::<AnyDevice, _>::handle_frame(
292 self,
293 bindings_ctx,
294 &target_device,
295 ReceivedFrame::from_ethernet(frame, frame_dest).into(),
296 whole_body,
297 );
298
299 match ethertype {
300 Some(EtherType::Ipv4) => {
301 self.increment_both(&target_device, |counters: &DeviceCounters| {
302 &counters.recv_ipv4_delivered
303 });
304 self.receive_frame(
305 bindings_ctx,
306 RecvIpFrameMeta::<_, _, Ipv4>::new(
307 target_device,
308 Some(frame_dest),
309 ip_layer_metadata,
310 ),
311 buf,
312 );
313 }
314 Some(EtherType::Ipv6) => {
315 self.increment_both(&target_device, |counters: &DeviceCounters| {
316 &counters.recv_ipv6_delivered
317 });
318 self.receive_frame(
319 bindings_ctx,
320 RecvIpFrameMeta::<_, _, Ipv6>::new(
321 target_device,
322 Some(frame_dest),
323 ip_layer_metadata,
324 ),
325 buf,
326 );
327 }
328 Some(ethertype @ (EtherType::Arp | EtherType::Other(_))) => {
329 self.increment_both(device_id, |counters: &EthernetDeviceCounters| {
330 &counters.recv_unsupported_ethertype
331 });
332 trace!("not handling loopback frame of type {:?}", ethertype)
333 }
334 None => {
335 self.increment_both(device_id, |counters: &EthernetDeviceCounters| {
336 &counters.recv_no_ethertype
337 });
338 trace!("dropping ethernet frame without ethertype");
339 }
340 }
341 }
342}
343
344impl<CC, BC> SendableFrameMeta<CC, BC>
345 for DeviceSocketMetadata<LoopbackDevice, <CC as DeviceIdContext<LoopbackDevice>>::DeviceId>
346where
347 CC: TransmitQueueHandler<
348 LoopbackDevice,
349 BC,
350 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
351 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
352 + DeviceIdContext<AnyDevice>,
353 BC: DeviceLayerTypes,
354{
355 fn send_meta<S>(
356 self,
357 core_ctx: &mut CC,
358 bindings_ctx: &mut BC,
359 body: S,
360 ) -> Result<(), SendFrameError<S>>
361 where
362 S: Serializer,
363 S::Buffer: BufferMut,
364 {
365 let Self { device_id, metadata } = self;
366 let tx_meta = LoopbackTxQueueMeta::default();
367 match metadata {
368 Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
369 core_ctx,
370 bindings_ctx,
371 &device_id,
372 body,
373 protocol,
374 dest_addr,
375 LoopbackTxQueueMeta::default(),
376 ),
377 None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
378 }
379 }
380}
381
382pub fn send_ip_frame<CC, BC, I, S>(
384 core_ctx: &mut CC,
385 bindings_ctx: &mut BC,
386 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
387 destination: IpPacketDestination<I, &<CC as DeviceIdContext<AnyDevice>>::DeviceId>,
388 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
389 packet: S,
390) -> Result<(), SendFrameError<S>>
391where
392 CC: TransmitQueueHandler<
393 LoopbackDevice,
394 BC,
395 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
396 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
397 + DeviceIdContext<AnyDevice>,
398 BC: DeviceLayerTypes,
399 I: EthernetIpExt + BroadcastIpExt,
400 S: Serializer,
401 S::Buffer: BufferMut,
402{
403 core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
404
405 let target_device = match destination {
406 IpPacketDestination::Loopback(device) => Some(device.downgrade()),
407 IpPacketDestination::Broadcast(_)
408 | IpPacketDestination::Multicast(_)
409 | IpPacketDestination::Neighbor(_) => None,
410 };
411 send_as_ethernet_frame_to_dst(
412 core_ctx,
413 bindings_ctx,
414 device_id,
415 packet,
416 I::ETHER_TYPE,
417 LOOPBACK_MAC,
418 LoopbackTxQueueMeta { target_device, ip_layer_metadata },
419 )
420}
421
422fn send_as_ethernet_frame_to_dst<CC, BC, S>(
423 core_ctx: &mut CC,
424 bindings_ctx: &mut BC,
425 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
426 packet: S,
427 protocol: EtherType,
428 dst_mac: Mac,
429 meta: LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
430) -> Result<(), SendFrameError<S>>
431where
432 CC: TransmitQueueHandler<
433 LoopbackDevice,
434 BC,
435 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
436 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
437 + DeviceIdContext<AnyDevice>,
438 BC: DeviceLayerTypes,
439 S: Serializer,
440 S::Buffer: BufferMut,
441{
442 const MIN_BODY_LEN: usize = 0;
448
449 let frame =
450 EthernetFrameBuilder::new(LOOPBACK_MAC, dst_mac, protocol, MIN_BODY_LEN).wrap_body(packet);
451
452 send_ethernet_frame(core_ctx, bindings_ctx, device_id, frame, meta)
453 .map_err(|err| err.into_inner())
454}
455
456fn send_ethernet_frame<CC, BC, S>(
457 core_ctx: &mut CC,
458 bindings_ctx: &mut BC,
459 device_id: &<CC as DeviceIdContext<LoopbackDevice>>::DeviceId,
460 frame: S,
461 meta: LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
462) -> Result<(), SendFrameError<S>>
463where
464 CC: TransmitQueueHandler<
465 LoopbackDevice,
466 BC,
467 Meta = LoopbackTxQueueMeta<<CC as DeviceIdContext<AnyDevice>>::WeakDeviceId, BC>,
468 > + ResourceCounterContext<<CC as DeviceIdContext<LoopbackDevice>>::DeviceId, DeviceCounters>
469 + DeviceIdContext<AnyDevice>,
470 S: Serializer,
471 S::Buffer: BufferMut,
472 BC: DeviceLayerTypes,
473{
474 core_ctx.increment_both(device_id, |counters: &DeviceCounters| &counters.send_total_frames);
475 match TransmitQueueHandler::<LoopbackDevice, _>::queue_tx_frame(
476 core_ctx,
477 bindings_ctx,
478 device_id,
479 meta,
480 frame,
481 ) {
482 Ok(len) => {
483 core_ctx.add_both_usize(device_id, len, |counters| &counters.send_bytes);
484 core_ctx.increment_both(device_id, |counters: &DeviceCounters| &counters.send_frame);
485 Ok(())
486 }
487 Err(TransmitQueueFrameError::NoQueue(err)) => {
488 unreachable!("loopback never fails to send a frame: {err:?}")
489 }
490 Err(TransmitQueueFrameError::QueueFull(serializer)) => {
491 core_ctx
492 .increment_both(device_id, |counters: &DeviceCounters| &counters.send_queue_full);
493 Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
494 }
495 Err(TransmitQueueFrameError::SerializeError(err)) => {
496 core_ctx.increment_both(device_id, |counters: &DeviceCounters| {
497 &counters.send_serialize_error
498 });
499 Err(err.err_into())
500 }
501 }
502}
503
504impl DeviceReceiveFrameSpec for LoopbackDevice {
505 type FrameMetadata<D> = Never;
508}