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::gro::GroCounters;
27use crate::internal::id::{
28 BaseDeviceId, BasePrimaryDeviceId, DeviceId, EthernetDeviceId, EthernetPrimaryDeviceId,
29 EthernetWeakDeviceId,
30};
31use crate::internal::loopback::{LoopbackDeviceId, LoopbackPrimaryDeviceId};
32use crate::internal::pure_ip::{PureIpDeviceId, PureIpPrimaryDeviceId};
33use crate::internal::queue::rx::ReceiveQueueBindingsContext;
34use crate::internal::queue::tx::{TransmitQueueBindingsContext, TxBufferAllocator};
35use crate::internal::socket::{self, DeviceSocketCounters, HeldSockets};
36use crate::internal::state::DeviceStateSpec;
37
38pub struct DevicesIter<'s, BT: DeviceLayerTypes> {
44 pub(super) ethernet:
45 netstack3_hashmap::hash_map::Values<'s, EthernetDeviceId<BT>, EthernetPrimaryDeviceId<BT>>,
46 pub(super) pure_ip:
47 netstack3_hashmap::hash_map::Values<'s, PureIpDeviceId<BT>, PureIpPrimaryDeviceId<BT>>,
48 pub(super) blackhole: netstack3_hashmap::hash_map::Values<
49 's,
50 BlackholeDeviceId<BT>,
51 BlackholePrimaryDeviceId<BT>,
52 >,
53 pub(super) loopback: core::option::Iter<'s, LoopbackPrimaryDeviceId<BT>>,
54}
55
56impl<'s, BT: DeviceLayerTypes> Iterator for DevicesIter<'s, BT> {
57 type Item = DeviceId<BT>;
58
59 fn next(&mut self) -> Option<Self::Item> {
60 let Self { ethernet, pure_ip, blackhole, loopback } = self;
61 ethernet
62 .map(|primary| primary.clone_strong().into())
63 .chain(pure_ip.map(|primary| primary.clone_strong().into()))
64 .chain(blackhole.map(|primary| primary.clone_strong().into()))
65 .chain(loopback.map(|primary| primary.clone_strong().into()))
66 .next()
67 }
68}
69
70#[allow(missing_docs)]
72pub enum Ipv6DeviceLinkLayerAddr {
73 Mac(Mac),
74 }
76
77impl Ipv6LinkLayerAddr for Ipv6DeviceLinkLayerAddr {
78 fn as_bytes(&self) -> &[u8] {
79 match self {
80 Ipv6DeviceLinkLayerAddr::Mac(a) => a.as_ref(),
81 }
82 }
83
84 fn eui64_iid(&self) -> [u8; 8] {
85 match self {
86 Ipv6DeviceLinkLayerAddr::Mac(a) => a.to_eui64(),
87 }
88 }
89}
90
91#[derive(Derivative)]
93#[derivative(
94 Clone(bound = ""),
95 Eq(bound = ""),
96 PartialEq(bound = ""),
97 Hash(bound = ""),
98 Debug(bound = "")
99)]
100pub struct DeviceLayerTimerId<BT: DeviceLayerTypes>(DeviceLayerTimerIdInner<BT>);
101
102#[derive(Derivative)]
103#[derivative(
104 Clone(bound = ""),
105 Eq(bound = ""),
106 PartialEq(bound = ""),
107 Hash(bound = ""),
108 Debug(bound = "")
109)]
110#[allow(missing_docs)]
111enum DeviceLayerTimerIdInner<BT: DeviceLayerTypes> {
112 Ethernet(EthernetTimerId<EthernetWeakDeviceId<BT>>),
113}
114
115impl<BT: DeviceLayerTypes> From<EthernetTimerId<EthernetWeakDeviceId<BT>>>
116 for DeviceLayerTimerId<BT>
117{
118 fn from(id: EthernetTimerId<EthernetWeakDeviceId<BT>>) -> DeviceLayerTimerId<BT> {
119 DeviceLayerTimerId(DeviceLayerTimerIdInner::Ethernet(id))
120 }
121}
122
123impl<CC, BT> HandleableTimer<CC, BT> for DeviceLayerTimerId<BT>
124where
125 BT: DeviceLayerTypes,
126 CC: TimerHandler<BT, EthernetTimerId<EthernetWeakDeviceId<BT>>>,
127{
128 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BT, timer: BT::UniqueTimerId) {
129 let Self(id) = self;
130 match id {
131 DeviceLayerTimerIdInner::Ethernet(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
132 }
133 }
134}
135
136#[derive(Derivative)]
138#[derivative(Default(bound = ""))]
139pub struct Devices<BT: DeviceLayerTypes> {
140 pub ethernet: HashMap<EthernetDeviceId<BT>, EthernetPrimaryDeviceId<BT>>,
142 pub pure_ip: HashMap<PureIpDeviceId<BT>, PureIpPrimaryDeviceId<BT>>,
144 pub blackhole: HashMap<BlackholeDeviceId<BT>, BlackholePrimaryDeviceId<BT>>,
146 pub loopback: Option<LoopbackPrimaryDeviceId<BT>>,
148}
149
150impl<BT: DeviceLayerTypes> Devices<BT> {
151 pub fn iter(&self) -> DevicesIter<'_, BT> {
153 let Self { ethernet, pure_ip, blackhole, loopback } = self;
154 DevicesIter {
155 ethernet: ethernet.values(),
156 pure_ip: pure_ip.values(),
157 blackhole: blackhole.values(),
158 loopback: loopback.iter(),
159 }
160 }
161}
162
163#[derive(Derivative)]
165#[derivative(Default(bound = ""))]
166pub struct DeviceLayerState<BT: DeviceLayerTypes> {
167 devices: RwLock<Devices<BT>>,
168 pub origin: OriginTracker,
170 pub shared_sockets: HeldSockets<BT>,
172 pub device_socket_counters: DeviceSocketCounters,
174 pub counters: DeviceCounters,
176 pub ethernet_counters: EthernetDeviceCounters,
178 pub pure_ip_counters: PureIpDeviceCounters,
180 pub nud_v4_counters: NudCounters<Ipv4>,
182 pub nud_v6_counters: NudCounters<Ipv6>,
184 pub arp_counters: ArpCounters,
186 pub gro_counters: GroCounters,
188}
189
190impl<BT: DeviceLayerTypes> DeviceLayerState<BT> {
191 pub fn nud_counters<I: Ip>(&self) -> &NudCounters<I> {
193 I::map_ip((), |()| &self.nud_v4_counters, |()| &self.nud_v6_counters)
194 }
195}
196
197impl<BT: DeviceLayerTypes> OrderedLockAccess<Devices<BT>> for DeviceLayerState<BT> {
198 type Lock = RwLock<Devices<BT>>;
199 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
200 OrderedLockRef::new(&self.devices)
201 }
202}
203
204#[derive(Default)]
206pub struct EthernetDeviceCounters {
207 pub recv_unsupported_ethertype: Counter,
209 pub recv_no_ethertype: Counter,
211 pub recv_single_csum_offloaded: Counter,
213 pub recv_multiple_csums_offloaded: Counter,
215 pub recv_all_csums_offloaded: Counter,
217}
218
219impl Inspectable for EthernetDeviceCounters {
220 fn record<I: Inspector>(&self, inspector: &mut I) {
221 inspector.record_child("Ethernet", |inspector| {
222 let Self {
223 recv_no_ethertype,
224 recv_unsupported_ethertype,
225 recv_single_csum_offloaded,
226 recv_multiple_csums_offloaded,
227 recv_all_csums_offloaded,
228 } = self;
229 inspector.record_child("Rx", |inspector| {
230 inspector.record_counter("NoEthertype", recv_no_ethertype);
231 inspector.record_counter("UnsupportedEthertype", recv_unsupported_ethertype);
232 inspector.record_counter("SingleCsumOffloaded", recv_single_csum_offloaded);
233 inspector.record_counter("MultipleCsumsOffloaded", recv_multiple_csums_offloaded);
234 inspector.record_counter("AllCsumsOffloaded", recv_all_csums_offloaded);
235 });
236 })
237 }
238}
239
240#[derive(Default)]
242pub struct PureIpDeviceCounters {
243 pub recv_single_csum_offloaded: Counter,
245 pub recv_multiple_csums_offloaded: Counter,
247 pub recv_all_csums_offloaded: Counter,
249}
250
251impl Inspectable for PureIpDeviceCounters {
252 fn record<I: Inspector>(&self, inspector: &mut I) {
253 inspector.record_child("PureIp", |inspector| {
254 let Self {
255 recv_single_csum_offloaded,
256 recv_multiple_csums_offloaded,
257 recv_all_csums_offloaded,
258 } = self;
259 inspector.record_child("Rx", |inspector| {
260 inspector.record_counter("SingleCsumOffloaded", recv_single_csum_offloaded);
261 inspector.record_counter("MultipleCsumsOffloaded", recv_multiple_csums_offloaded);
262 inspector.record_counter("AllCsumsOffloaded", recv_all_csums_offloaded);
263 });
264 })
265 }
266}
267
268pub struct BlackholeDeviceCounters;
270
271impl Inspectable for BlackholeDeviceCounters {
272 fn record<I: Inspector>(&self, _inspector: &mut I) {}
273}
274
275#[derive(Default, Debug)]
277#[cfg_attr(
278 any(test, feature = "testutils"),
279 derive(PartialEq, netstack3_macros::CounterCollection)
280)]
281pub struct DeviceCounters<C: CounterRepr = Counter> {
282 pub send_total_frames: C,
285 pub send_frame: C,
287 pub send_bytes: C,
289 pub send_queue_full: C,
291 pub send_serialize_error: C,
293 pub recv_frame: C,
295 pub recv_bytes: C,
297 pub recv_parse_error: C,
299 pub recv_ipv4_delivered: C,
301 pub recv_ipv6_delivered: C,
303 pub send_ipv4_frame: C,
305 pub send_ipv6_frame: C,
307 pub send_dropped_no_queue: C,
309 pub send_dropped_dequeue: C,
311}
312
313impl DeviceCounters {
314 pub fn send_frame<I: Ip>(&self) -> &Counter {
316 match I::VERSION {
317 IpVersion::V4 => &self.send_ipv4_frame,
318 IpVersion::V6 => &self.send_ipv6_frame,
319 }
320 }
321}
322
323impl Inspectable for DeviceCounters {
324 fn record<I: Inspector>(&self, inspector: &mut I) {
325 let Self {
326 recv_frame,
327 recv_bytes,
328 recv_ipv4_delivered,
329 recv_ipv6_delivered,
330 recv_parse_error,
331 send_dropped_no_queue,
332 send_frame,
333 send_bytes,
334 send_ipv4_frame,
335 send_ipv6_frame,
336 send_queue_full,
337 send_serialize_error,
338 send_total_frames,
339 send_dropped_dequeue,
340 } = self;
341 inspector.record_child("Rx", |inspector| {
342 inspector.record_counter("TotalFrames", recv_frame);
343 inspector.record_counter("TotalBytes", recv_bytes);
344 inspector.record_counter("Malformed", recv_parse_error);
345 inspector.record_counter("Ipv4Delivered", recv_ipv4_delivered);
346 inspector.record_counter("Ipv6Delivered", recv_ipv6_delivered);
347 });
348 inspector.record_child("Tx", |inspector| {
349 inspector.record_counter("TotalFrames", send_total_frames);
350 inspector.record_counter("Sent", send_frame);
351 inspector.record_counter("SentBytes", send_bytes);
352 inspector.record_counter("SendIpv4Frame", send_ipv4_frame);
353 inspector.record_counter("SendIpv6Frame", send_ipv6_frame);
354 inspector.record_counter("NoQueue", send_dropped_no_queue);
355 inspector.record_counter("QueueFull", send_queue_full);
356 inspector.record_counter("SerializeError", send_serialize_error);
357 inspector.record_counter("DequeueDrop", send_dropped_dequeue);
358 });
359 }
360}
361#[derive(Clone, Debug, PartialEq)]
372pub struct OriginTracker(#[cfg(debug_assertions)] u64);
373
374impl Default for OriginTracker {
375 fn default() -> Self {
376 Self::new()
377 }
378}
379
380impl OriginTracker {
381 #[cfg_attr(not(debug_assertions), inline)]
388 fn new() -> Self {
389 Self(
390 #[cfg(debug_assertions)]
391 {
392 static COUNTER: core::sync::atomic::AtomicU64 =
393 core::sync::atomic::AtomicU64::new(0);
394 COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed)
395 },
396 )
397 }
398}
399
400pub trait OriginTrackerContext {
405 fn origin_tracker(&mut self) -> OriginTracker;
407}
408
409pub trait DeviceCollectionContext<D: Device + DeviceStateSpec, BT: DeviceLayerTypes>:
413 DeviceIdContext<D>
414{
415 fn insert(&mut self, device: BasePrimaryDeviceId<D, BT>);
417
418 fn remove(&mut self, device: &BaseDeviceId<D, BT>) -> Option<BasePrimaryDeviceId<D, BT>>;
420}
421
422pub trait DeviceReceiveFrameSpec {
428 type FrameMetadata<D>;
430}
431
432pub trait DeviceLayerStateTypes: InstantContext + FilterBindingsTypes {
434 type LoopbackDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
436
437 type EthernetDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
439
440 type PureIpDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
442
443 type BlackholeDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
445
446 type DeviceIdentifier: Send + Sync + Debug + Display + DeviceIdAndNameMatcher;
449}
450
451pub trait DeviceClassMatcher<DeviceClass> {
454 fn device_class_matches(&self, device_class: &DeviceClass) -> bool;
457}
458
459pub trait DeviceIdAndNameMatcher {
462 fn id_matches(&self, id: &NonZeroU64) -> bool;
464
465 fn name_matches(&self, name: &str) -> bool;
467}
468
469pub trait DeviceBufferBindingsTypes: 'static {
471 type TxBuffer: packet::FragmentedBuffer + AsMut<[u8]> + Send + 'static;
473 type TxAllocator: TxBufferAllocator<Self::TxBuffer> + Send + 'static;
475}
476
477pub trait DeviceLayerTypes:
483 DeviceBufferBindingsTypes
484 + DeviceLayerStateTypes
485 + socket::DeviceSocketTypes
486 + LinkResolutionContext<EthernetLinkDevice>
487 + TimerBindingsTypes
488 + ReferenceNotifiers
489 + TxMetadataBindingsTypes
490 + 'static
491{
492}
493impl<
494 BC: DeviceLayerStateTypes
495 + socket::DeviceSocketTypes
496 + LinkResolutionContext<EthernetLinkDevice>
497 + TimerBindingsTypes
498 + ReferenceNotifiers
499 + TxMetadataBindingsTypes
500 + 'static
501 + DeviceBufferBindingsTypes,
502> DeviceLayerTypes for BC
503{
504}
505
506pub trait DeviceLayerEventDispatcher:
508 DeviceLayerTypes
509 + ReceiveQueueBindingsContext<LoopbackDeviceId<Self>>
510 + TransmitQueueBindingsContext<EthernetDeviceId<Self>>
511 + TransmitQueueBindingsContext<LoopbackDeviceId<Self>>
512 + TransmitQueueBindingsContext<PureIpDeviceId<Self>>
513 + Sized
514{
515 type DequeueContext;
521
522 fn send_ethernet_frame(
532 &mut self,
533 device: &EthernetDeviceId<Self>,
534 frame: Self::TxBuffer,
535 dequeue_context: Option<&mut Self::DequeueContext>,
536 csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
537 ) -> Result<(), DeviceSendFrameError>;
538
539 fn send_ip_packet(
549 &mut self,
550 device: &PureIpDeviceId<Self>,
551 packet: Self::TxBuffer,
552 ip_version: IpVersion,
553 dequeue_context: Option<&mut Self::DequeueContext>,
554 csum_offload: Option<netstack3_base::ChecksumOffloadResult>,
555 ) -> Result<(), DeviceSendFrameError>;
556}
557
558#[derive(Debug, PartialEq, Eq)]
560pub enum DeviceSendFrameError {
561 NoBuffers,
563}
564
565#[cfg(any(test, feature = "testutils"))]
566pub mod testutil {
567 use alloc::vec::Vec;
568 use netstack3_base::testutil::FakeBindingsCtx;
569 use netstack3_base::{CounterCollection, ResourceCounterContext};
570
571 use super::*;
572 use crate::internal::queue::tx::BufVecU8Allocator;
573
574 pub type DeviceCounterExpectations = DeviceCounters<u64>;
576
577 impl DeviceCounterExpectations {
578 #[track_caller]
580 pub fn assert_counters<D, CC: ResourceCounterContext<D, DeviceCounters>>(
581 &self,
582 core_ctx: &CC,
583 device: &D,
584 ) {
585 assert_eq!(&core_ctx.counters().cast::<u64>(), self, "stack-wide counters");
586 assert_eq!(
587 &core_ctx.per_resource_counters(device).cast::<u64>(),
588 self,
589 "per-device counters"
590 );
591 }
592 }
593
594 impl<TimerId: 'static, Event: Debug + 'static, State: 'static, FrameMeta: 'static>
595 DeviceBufferBindingsTypes for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
596 {
597 type TxBuffer = packet::Buf<Vec<u8>>;
598 type TxAllocator = BufVecU8Allocator;
599 }
600}
601
602#[cfg(test)]
603mod tests {
604 use super::*;
605
606 #[test]
607 fn origin_tracker() {
608 let tracker = OriginTracker::new();
609 if cfg!(debug_assertions) {
610 assert_ne!(tracker, OriginTracker::new());
611 } else {
612 assert_eq!(tracker, OriginTracker::new());
613 }
614 assert_eq!(tracker.clone(), tracker);
615 }
616}