1use core::fmt::{Debug, Display};
6use core::num::NonZeroU64;
7
8use derivative::Derivative;
9use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
10use net_types::ethernet::Mac;
11use net_types::ip::{Ip, IpVersion, Ipv4, Ipv6};
12use netstack3_base::sync::RwLock;
13use netstack3_base::{
14 Counter, CounterRepr, Device, DeviceIdContext, HandleableTimer, Inspectable, Inspector,
15 InspectorExt as _, InstantContext, ReferenceNotifiers, TimerBindingsTypes, TimerHandler,
16 TxMetadataBindingsTypes,
17};
18use netstack3_filter::FilterBindingsTypes;
19use netstack3_hashmap::HashMap;
20use netstack3_ip::device::Ipv6LinkLayerAddr;
21use netstack3_ip::nud::{LinkResolutionContext, NudCounters};
22
23use crate::blackhole::{BlackholeDeviceId, BlackholePrimaryDeviceId};
24use crate::internal::arp::ArpCounters;
25use crate::internal::ethernet::{EthernetLinkDevice, EthernetTimerId};
26use crate::internal::id::{
27 BaseDeviceId, BasePrimaryDeviceId, DeviceId, EthernetDeviceId, EthernetPrimaryDeviceId,
28 EthernetWeakDeviceId,
29};
30use crate::internal::loopback::{LoopbackDeviceId, LoopbackPrimaryDeviceId};
31use crate::internal::pure_ip::{PureIpDeviceId, PureIpPrimaryDeviceId};
32use crate::internal::queue::rx::ReceiveQueueBindingsContext;
33use crate::internal::queue::tx::{TransmitQueueBindingsContext, TxBufferAllocator};
34use crate::internal::socket::{self, DeviceSocketCounters, HeldSockets};
35use crate::internal::state::DeviceStateSpec;
36
37pub struct DevicesIter<'s, BT: DeviceLayerTypes> {
43 pub(super) ethernet:
44 netstack3_hashmap::hash_map::Values<'s, EthernetDeviceId<BT>, EthernetPrimaryDeviceId<BT>>,
45 pub(super) pure_ip:
46 netstack3_hashmap::hash_map::Values<'s, PureIpDeviceId<BT>, PureIpPrimaryDeviceId<BT>>,
47 pub(super) blackhole: netstack3_hashmap::hash_map::Values<
48 's,
49 BlackholeDeviceId<BT>,
50 BlackholePrimaryDeviceId<BT>,
51 >,
52 pub(super) loopback: core::option::Iter<'s, LoopbackPrimaryDeviceId<BT>>,
53}
54
55impl<'s, BT: DeviceLayerTypes> Iterator for DevicesIter<'s, BT> {
56 type Item = DeviceId<BT>;
57
58 fn next(&mut self) -> Option<Self::Item> {
59 let Self { ethernet, pure_ip, blackhole, loopback } = self;
60 ethernet
61 .map(|primary| primary.clone_strong().into())
62 .chain(pure_ip.map(|primary| primary.clone_strong().into()))
63 .chain(blackhole.map(|primary| primary.clone_strong().into()))
64 .chain(loopback.map(|primary| primary.clone_strong().into()))
65 .next()
66 }
67}
68
69#[allow(missing_docs)]
71pub enum Ipv6DeviceLinkLayerAddr {
72 Mac(Mac),
73 }
75
76impl Ipv6LinkLayerAddr for Ipv6DeviceLinkLayerAddr {
77 fn as_bytes(&self) -> &[u8] {
78 match self {
79 Ipv6DeviceLinkLayerAddr::Mac(a) => a.as_ref(),
80 }
81 }
82
83 fn eui64_iid(&self) -> [u8; 8] {
84 match self {
85 Ipv6DeviceLinkLayerAddr::Mac(a) => a.to_eui64(),
86 }
87 }
88}
89
90#[derive(Derivative)]
92#[derivative(
93 Clone(bound = ""),
94 Eq(bound = ""),
95 PartialEq(bound = ""),
96 Hash(bound = ""),
97 Debug(bound = "")
98)]
99pub struct DeviceLayerTimerId<BT: DeviceLayerTypes>(DeviceLayerTimerIdInner<BT>);
100
101#[derive(Derivative)]
102#[derivative(
103 Clone(bound = ""),
104 Eq(bound = ""),
105 PartialEq(bound = ""),
106 Hash(bound = ""),
107 Debug(bound = "")
108)]
109#[allow(missing_docs)]
110enum DeviceLayerTimerIdInner<BT: DeviceLayerTypes> {
111 Ethernet(EthernetTimerId<EthernetWeakDeviceId<BT>>),
112}
113
114impl<BT: DeviceLayerTypes> From<EthernetTimerId<EthernetWeakDeviceId<BT>>>
115 for DeviceLayerTimerId<BT>
116{
117 fn from(id: EthernetTimerId<EthernetWeakDeviceId<BT>>) -> DeviceLayerTimerId<BT> {
118 DeviceLayerTimerId(DeviceLayerTimerIdInner::Ethernet(id))
119 }
120}
121
122impl<CC, BT> HandleableTimer<CC, BT> for DeviceLayerTimerId<BT>
123where
124 BT: DeviceLayerTypes,
125 CC: TimerHandler<BT, EthernetTimerId<EthernetWeakDeviceId<BT>>>,
126{
127 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BT, timer: BT::UniqueTimerId) {
128 let Self(id) = self;
129 match id {
130 DeviceLayerTimerIdInner::Ethernet(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
131 }
132 }
133}
134
135#[derive(Derivative)]
137#[derivative(Default(bound = ""))]
138pub struct Devices<BT: DeviceLayerTypes> {
139 pub ethernet: HashMap<EthernetDeviceId<BT>, EthernetPrimaryDeviceId<BT>>,
141 pub pure_ip: HashMap<PureIpDeviceId<BT>, PureIpPrimaryDeviceId<BT>>,
143 pub blackhole: HashMap<BlackholeDeviceId<BT>, BlackholePrimaryDeviceId<BT>>,
145 pub loopback: Option<LoopbackPrimaryDeviceId<BT>>,
147}
148
149impl<BT: DeviceLayerTypes> Devices<BT> {
150 pub fn iter(&self) -> DevicesIter<'_, BT> {
152 let Self { ethernet, pure_ip, blackhole, loopback } = self;
153 DevicesIter {
154 ethernet: ethernet.values(),
155 pure_ip: pure_ip.values(),
156 blackhole: blackhole.values(),
157 loopback: loopback.iter(),
158 }
159 }
160}
161
162#[derive(Derivative)]
164#[derivative(Default(bound = ""))]
165pub struct DeviceLayerState<BT: DeviceLayerTypes> {
166 devices: RwLock<Devices<BT>>,
167 pub origin: OriginTracker,
169 pub shared_sockets: HeldSockets<BT>,
171 pub device_socket_counters: DeviceSocketCounters,
173 pub counters: DeviceCounters,
175 pub ethernet_counters: EthernetDeviceCounters,
177 pub pure_ip_counters: PureIpDeviceCounters,
179 pub nud_v4_counters: NudCounters<Ipv4>,
181 pub nud_v6_counters: NudCounters<Ipv6>,
183 pub arp_counters: ArpCounters,
185}
186
187impl<BT: DeviceLayerTypes> DeviceLayerState<BT> {
188 pub fn nud_counters<I: Ip>(&self) -> &NudCounters<I> {
190 I::map_ip((), |()| &self.nud_v4_counters, |()| &self.nud_v6_counters)
191 }
192}
193
194impl<BT: DeviceLayerTypes> OrderedLockAccess<Devices<BT>> for DeviceLayerState<BT> {
195 type Lock = RwLock<Devices<BT>>;
196 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
197 OrderedLockRef::new(&self.devices)
198 }
199}
200
201#[derive(Default)]
203pub struct EthernetDeviceCounters {
204 pub recv_unsupported_ethertype: Counter,
206 pub recv_no_ethertype: Counter,
208 pub recv_single_csum_offloaded: Counter,
210 pub recv_multiple_csums_offloaded: Counter,
212 pub recv_all_csums_offloaded: Counter,
214}
215
216impl Inspectable for EthernetDeviceCounters {
217 fn record<I: Inspector>(&self, inspector: &mut I) {
218 inspector.record_child("Ethernet", |inspector| {
219 let Self {
220 recv_no_ethertype,
221 recv_unsupported_ethertype,
222 recv_single_csum_offloaded,
223 recv_multiple_csums_offloaded,
224 recv_all_csums_offloaded,
225 } = self;
226 inspector.record_child("Rx", |inspector| {
227 inspector.record_counter("NoEthertype", recv_no_ethertype);
228 inspector.record_counter("UnsupportedEthertype", recv_unsupported_ethertype);
229 inspector.record_counter("SingleCsumOffloaded", recv_single_csum_offloaded);
230 inspector.record_counter("MultipleCsumsOffloaded", recv_multiple_csums_offloaded);
231 inspector.record_counter("AllCsumsOffloaded", recv_all_csums_offloaded);
232 });
233 })
234 }
235}
236
237#[derive(Default)]
239pub struct PureIpDeviceCounters {
240 pub recv_single_csum_offloaded: Counter,
242 pub recv_multiple_csums_offloaded: Counter,
244 pub recv_all_csums_offloaded: Counter,
246}
247
248impl Inspectable for PureIpDeviceCounters {
249 fn record<I: Inspector>(&self, inspector: &mut I) {
250 inspector.record_child("PureIp", |inspector| {
251 let Self {
252 recv_single_csum_offloaded,
253 recv_multiple_csums_offloaded,
254 recv_all_csums_offloaded,
255 } = self;
256 inspector.record_child("Rx", |inspector| {
257 inspector.record_counter("SingleCsumOffloaded", recv_single_csum_offloaded);
258 inspector.record_counter("MultipleCsumsOffloaded", recv_multiple_csums_offloaded);
259 inspector.record_counter("AllCsumsOffloaded", recv_all_csums_offloaded);
260 });
261 })
262 }
263}
264
265pub struct BlackholeDeviceCounters;
267
268impl Inspectable for BlackholeDeviceCounters {
269 fn record<I: Inspector>(&self, _inspector: &mut I) {}
270}
271
272#[derive(Default, Debug)]
274#[cfg_attr(
275 any(test, feature = "testutils"),
276 derive(PartialEq, netstack3_macros::CounterCollection)
277)]
278pub struct DeviceCounters<C: CounterRepr = Counter> {
279 pub send_total_frames: C,
282 pub send_frame: C,
284 pub send_bytes: C,
286 pub send_queue_full: C,
288 pub send_serialize_error: C,
290 pub recv_frame: C,
292 pub recv_bytes: C,
294 pub recv_parse_error: C,
296 pub recv_ipv4_delivered: C,
298 pub recv_ipv6_delivered: C,
300 pub send_ipv4_frame: C,
302 pub send_ipv6_frame: C,
304 pub send_dropped_no_queue: C,
306 pub send_dropped_dequeue: C,
308}
309
310impl DeviceCounters {
311 pub fn send_frame<I: Ip>(&self) -> &Counter {
313 match I::VERSION {
314 IpVersion::V4 => &self.send_ipv4_frame,
315 IpVersion::V6 => &self.send_ipv6_frame,
316 }
317 }
318}
319
320impl Inspectable for DeviceCounters {
321 fn record<I: Inspector>(&self, inspector: &mut I) {
322 let Self {
323 recv_frame,
324 recv_bytes,
325 recv_ipv4_delivered,
326 recv_ipv6_delivered,
327 recv_parse_error,
328 send_dropped_no_queue,
329 send_frame,
330 send_bytes,
331 send_ipv4_frame,
332 send_ipv6_frame,
333 send_queue_full,
334 send_serialize_error,
335 send_total_frames,
336 send_dropped_dequeue,
337 } = self;
338 inspector.record_child("Rx", |inspector| {
339 inspector.record_counter("TotalFrames", recv_frame);
340 inspector.record_counter("TotalBytes", recv_bytes);
341 inspector.record_counter("Malformed", recv_parse_error);
342 inspector.record_counter("Ipv4Delivered", recv_ipv4_delivered);
343 inspector.record_counter("Ipv6Delivered", recv_ipv6_delivered);
344 });
345 inspector.record_child("Tx", |inspector| {
346 inspector.record_counter("TotalFrames", send_total_frames);
347 inspector.record_counter("Sent", send_frame);
348 inspector.record_counter("SentBytes", send_bytes);
349 inspector.record_counter("SendIpv4Frame", send_ipv4_frame);
350 inspector.record_counter("SendIpv6Frame", send_ipv6_frame);
351 inspector.record_counter("NoQueue", send_dropped_no_queue);
352 inspector.record_counter("QueueFull", send_queue_full);
353 inspector.record_counter("SerializeError", send_serialize_error);
354 inspector.record_counter("DequeueDrop", send_dropped_dequeue);
355 });
356 }
357}
358#[derive(Clone, Debug, PartialEq)]
369pub struct OriginTracker(#[cfg(debug_assertions)] u64);
370
371impl Default for OriginTracker {
372 fn default() -> Self {
373 Self::new()
374 }
375}
376
377impl OriginTracker {
378 #[cfg_attr(not(debug_assertions), inline)]
385 fn new() -> Self {
386 Self(
387 #[cfg(debug_assertions)]
388 {
389 static COUNTER: core::sync::atomic::AtomicU64 =
390 core::sync::atomic::AtomicU64::new(0);
391 COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed)
392 },
393 )
394 }
395}
396
397pub trait OriginTrackerContext {
402 fn origin_tracker(&mut self) -> OriginTracker;
404}
405
406pub trait DeviceCollectionContext<D: Device + DeviceStateSpec, BT: DeviceLayerTypes>:
410 DeviceIdContext<D>
411{
412 fn insert(&mut self, device: BasePrimaryDeviceId<D, BT>);
414
415 fn remove(&mut self, device: &BaseDeviceId<D, BT>) -> Option<BasePrimaryDeviceId<D, BT>>;
417}
418
419pub trait DeviceReceiveFrameSpec {
425 type FrameMetadata<D>;
427}
428
429pub trait DeviceLayerStateTypes: InstantContext + FilterBindingsTypes {
431 type LoopbackDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
433
434 type EthernetDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
436
437 type PureIpDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
439
440 type BlackholeDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
442
443 type DeviceIdentifier: Send + Sync + Debug + Display + DeviceIdAndNameMatcher;
446}
447
448pub trait DeviceClassMatcher<DeviceClass> {
451 fn device_class_matches(&self, device_class: &DeviceClass) -> bool;
454}
455
456pub trait DeviceIdAndNameMatcher {
459 fn id_matches(&self, id: &NonZeroU64) -> bool;
461
462 fn name_matches(&self, name: &str) -> bool;
464}
465
466pub trait DeviceBufferBindingsTypes: 'static {
468 type TxBuffer: packet::FragmentedBuffer + AsMut<[u8]> + Send + 'static;
470 type TxAllocator: TxBufferAllocator<Self::TxBuffer> + Send + 'static;
472}
473
474pub trait DeviceLayerTypes:
480 DeviceBufferBindingsTypes
481 + DeviceLayerStateTypes
482 + socket::DeviceSocketTypes
483 + LinkResolutionContext<EthernetLinkDevice>
484 + TimerBindingsTypes
485 + ReferenceNotifiers
486 + TxMetadataBindingsTypes
487 + 'static
488{
489}
490impl<
491 BC: DeviceLayerStateTypes
492 + socket::DeviceSocketTypes
493 + LinkResolutionContext<EthernetLinkDevice>
494 + TimerBindingsTypes
495 + ReferenceNotifiers
496 + TxMetadataBindingsTypes
497 + 'static
498 + DeviceBufferBindingsTypes,
499> DeviceLayerTypes for BC
500{
501}
502
503pub trait DeviceLayerEventDispatcher:
505 DeviceLayerTypes
506 + ReceiveQueueBindingsContext<LoopbackDeviceId<Self>>
507 + TransmitQueueBindingsContext<EthernetDeviceId<Self>>
508 + TransmitQueueBindingsContext<LoopbackDeviceId<Self>>
509 + TransmitQueueBindingsContext<PureIpDeviceId<Self>>
510 + Sized
511{
512 type DequeueContext;
518
519 fn send_ethernet_frame(
529 &mut self,
530 device: &EthernetDeviceId<Self>,
531 frame: Self::TxBuffer,
532 dequeue_context: Option<&mut Self::DequeueContext>,
533 csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
534 ) -> Result<(), DeviceSendFrameError>;
535
536 fn send_ip_packet(
546 &mut self,
547 device: &PureIpDeviceId<Self>,
548 packet: Self::TxBuffer,
549 ip_version: IpVersion,
550 dequeue_context: Option<&mut Self::DequeueContext>,
551 csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
552 ) -> Result<(), DeviceSendFrameError>;
553}
554
555#[derive(Debug, PartialEq, Eq)]
557pub enum DeviceSendFrameError {
558 NoBuffers,
560}
561
562#[cfg(any(test, feature = "testutils"))]
563pub mod testutil {
564 use alloc::vec::Vec;
565 use netstack3_base::testutil::FakeBindingsCtx;
566 use netstack3_base::{CounterCollection, ResourceCounterContext};
567
568 use super::*;
569 use crate::internal::queue::tx::BufVecU8Allocator;
570
571 pub type DeviceCounterExpectations = DeviceCounters<u64>;
573
574 impl DeviceCounterExpectations {
575 #[track_caller]
577 pub fn assert_counters<D, CC: ResourceCounterContext<D, DeviceCounters>>(
578 &self,
579 core_ctx: &CC,
580 device: &D,
581 ) {
582 assert_eq!(&core_ctx.counters().cast::<u64>(), self, "stack-wide counters");
583 assert_eq!(
584 &core_ctx.per_resource_counters(device).cast::<u64>(),
585 self,
586 "per-device counters"
587 );
588 }
589 }
590
591 impl<TimerId: 'static, Event: Debug + 'static, State: 'static, FrameMeta: 'static>
592 DeviceBufferBindingsTypes for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
593 {
594 type TxBuffer = packet::Buf<Vec<u8>>;
595 type TxAllocator = BufVecU8Allocator;
596 }
597}
598
599#[cfg(test)]
600mod tests {
601 use super::*;
602
603 #[test]
604 fn origin_tracker() {
605 let tracker = OriginTracker::new();
606 if cfg!(debug_assertions) {
607 assert_ne!(tracker, OriginTracker::new());
608 } else {
609 assert_eq!(tracker, OriginTracker::new());
610 }
611 assert_eq!(tracker.clone(), tracker);
612 }
613}