1use alloc::vec::Vec;
6use core::fmt::{Debug, Display};
7use core::num::NonZeroU64;
8
9use derivative::Derivative;
10use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
11use net_types::ethernet::Mac;
12use net_types::ip::{Ip, IpVersion, Ipv4, Ipv6};
13use netstack3_base::sync::RwLock;
14use netstack3_base::{
15 Counter, CounterRepr, Device, DeviceIdContext, HandleableTimer, Inspectable, Inspector,
16 InspectorExt as _, InstantContext, ReferenceNotifiers, TimerBindingsTypes, TimerHandler,
17 TxMetadataBindingsTypes,
18};
19use netstack3_filter::FilterBindingsTypes;
20use netstack3_hashmap::HashMap;
21use netstack3_ip::device::Ipv6LinkLayerAddr;
22use netstack3_ip::nud::{LinkResolutionContext, NudCounters};
23use packet::Buf;
24
25use crate::blackhole::{BlackholeDeviceId, BlackholePrimaryDeviceId};
26use crate::internal::arp::ArpCounters;
27use crate::internal::ethernet::{EthernetLinkDevice, EthernetTimerId};
28use crate::internal::id::{
29 BaseDeviceId, BasePrimaryDeviceId, DeviceId, EthernetDeviceId, EthernetPrimaryDeviceId,
30 EthernetWeakDeviceId,
31};
32use crate::internal::loopback::{LoopbackDeviceId, LoopbackPrimaryDeviceId};
33use crate::internal::pure_ip::{PureIpDeviceId, PureIpPrimaryDeviceId};
34use crate::internal::queue::rx::ReceiveQueueBindingsContext;
35use crate::internal::queue::tx::TransmitQueueBindingsContext;
36use crate::internal::socket::{self, DeviceSocketCounters, HeldSockets};
37use crate::internal::state::DeviceStateSpec;
38
39pub struct DevicesIter<'s, BT: DeviceLayerTypes> {
45 pub(super) ethernet:
46 netstack3_hashmap::hash_map::Values<'s, EthernetDeviceId<BT>, EthernetPrimaryDeviceId<BT>>,
47 pub(super) pure_ip:
48 netstack3_hashmap::hash_map::Values<'s, PureIpDeviceId<BT>, PureIpPrimaryDeviceId<BT>>,
49 pub(super) blackhole: netstack3_hashmap::hash_map::Values<
50 's,
51 BlackholeDeviceId<BT>,
52 BlackholePrimaryDeviceId<BT>,
53 >,
54 pub(super) loopback: core::option::Iter<'s, LoopbackPrimaryDeviceId<BT>>,
55}
56
57impl<'s, BT: DeviceLayerTypes> Iterator for DevicesIter<'s, BT> {
58 type Item = DeviceId<BT>;
59
60 fn next(&mut self) -> Option<Self::Item> {
61 let Self { ethernet, pure_ip, blackhole, loopback } = self;
62 ethernet
63 .map(|primary| primary.clone_strong().into())
64 .chain(pure_ip.map(|primary| primary.clone_strong().into()))
65 .chain(blackhole.map(|primary| primary.clone_strong().into()))
66 .chain(loopback.map(|primary| primary.clone_strong().into()))
67 .next()
68 }
69}
70
71#[allow(missing_docs)]
73pub enum Ipv6DeviceLinkLayerAddr {
74 Mac(Mac),
75 }
77
78impl Ipv6LinkLayerAddr for Ipv6DeviceLinkLayerAddr {
79 fn as_bytes(&self) -> &[u8] {
80 match self {
81 Ipv6DeviceLinkLayerAddr::Mac(a) => a.as_ref(),
82 }
83 }
84
85 fn eui64_iid(&self) -> [u8; 8] {
86 match self {
87 Ipv6DeviceLinkLayerAddr::Mac(a) => a.to_eui64(),
88 }
89 }
90}
91
92#[derive(Derivative)]
94#[derivative(
95 Clone(bound = ""),
96 Eq(bound = ""),
97 PartialEq(bound = ""),
98 Hash(bound = ""),
99 Debug(bound = "")
100)]
101pub struct DeviceLayerTimerId<BT: DeviceLayerTypes>(DeviceLayerTimerIdInner<BT>);
102
103#[derive(Derivative)]
104#[derivative(
105 Clone(bound = ""),
106 Eq(bound = ""),
107 PartialEq(bound = ""),
108 Hash(bound = ""),
109 Debug(bound = "")
110)]
111#[allow(missing_docs)]
112enum DeviceLayerTimerIdInner<BT: DeviceLayerTypes> {
113 Ethernet(EthernetTimerId<EthernetWeakDeviceId<BT>>),
114}
115
116impl<BT: DeviceLayerTypes> From<EthernetTimerId<EthernetWeakDeviceId<BT>>>
117 for DeviceLayerTimerId<BT>
118{
119 fn from(id: EthernetTimerId<EthernetWeakDeviceId<BT>>) -> DeviceLayerTimerId<BT> {
120 DeviceLayerTimerId(DeviceLayerTimerIdInner::Ethernet(id))
121 }
122}
123
124impl<CC, BT> HandleableTimer<CC, BT> for DeviceLayerTimerId<BT>
125where
126 BT: DeviceLayerTypes,
127 CC: TimerHandler<BT, EthernetTimerId<EthernetWeakDeviceId<BT>>>,
128{
129 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BT, timer: BT::UniqueTimerId) {
130 let Self(id) = self;
131 match id {
132 DeviceLayerTimerIdInner::Ethernet(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
133 }
134 }
135}
136
137#[derive(Derivative)]
139#[derivative(Default(bound = ""))]
140pub struct Devices<BT: DeviceLayerTypes> {
141 pub ethernet: HashMap<EthernetDeviceId<BT>, EthernetPrimaryDeviceId<BT>>,
143 pub pure_ip: HashMap<PureIpDeviceId<BT>, PureIpPrimaryDeviceId<BT>>,
145 pub blackhole: HashMap<BlackholeDeviceId<BT>, BlackholePrimaryDeviceId<BT>>,
147 pub loopback: Option<LoopbackPrimaryDeviceId<BT>>,
149}
150
151impl<BT: DeviceLayerTypes> Devices<BT> {
152 pub fn iter(&self) -> DevicesIter<'_, BT> {
154 let Self { ethernet, pure_ip, blackhole, loopback } = self;
155 DevicesIter {
156 ethernet: ethernet.values(),
157 pure_ip: pure_ip.values(),
158 blackhole: blackhole.values(),
159 loopback: loopback.iter(),
160 }
161 }
162}
163
164#[derive(Derivative)]
166#[derivative(Default(bound = ""))]
167pub struct DeviceLayerState<BT: DeviceLayerTypes> {
168 devices: RwLock<Devices<BT>>,
169 pub origin: OriginTracker,
171 pub shared_sockets: HeldSockets<BT>,
173 pub device_socket_counters: DeviceSocketCounters,
175 pub counters: DeviceCounters,
177 pub ethernet_counters: EthernetDeviceCounters,
179 pub pure_ip_counters: PureIpDeviceCounters,
181 pub nud_v4_counters: NudCounters<Ipv4>,
183 pub nud_v6_counters: NudCounters<Ipv6>,
185 pub arp_counters: ArpCounters,
187}
188
189impl<BT: DeviceLayerTypes> DeviceLayerState<BT> {
190 pub fn nud_counters<I: Ip>(&self) -> &NudCounters<I> {
192 I::map_ip((), |()| &self.nud_v4_counters, |()| &self.nud_v6_counters)
193 }
194}
195
196impl<BT: DeviceLayerTypes> OrderedLockAccess<Devices<BT>> for DeviceLayerState<BT> {
197 type Lock = RwLock<Devices<BT>>;
198 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
199 OrderedLockRef::new(&self.devices)
200 }
201}
202
203#[derive(Default)]
205pub struct EthernetDeviceCounters {
206 pub recv_unsupported_ethertype: Counter,
208 pub recv_no_ethertype: Counter,
210}
211
212impl Inspectable for EthernetDeviceCounters {
213 fn record<I: Inspector>(&self, inspector: &mut I) {
214 inspector.record_child("Ethernet", |inspector| {
215 let Self { recv_no_ethertype, recv_unsupported_ethertype } = self;
216 inspector.record_child("Rx", |inspector| {
217 inspector.record_counter("NoEthertype", recv_no_ethertype);
218 inspector.record_counter("UnsupportedEthertype", recv_unsupported_ethertype);
219 });
220 })
221 }
222}
223
224#[derive(Default)]
226pub struct PureIpDeviceCounters {}
227
228impl Inspectable for PureIpDeviceCounters {
229 fn record<I: Inspector>(&self, _inspector: &mut I) {}
230}
231
232pub struct BlackholeDeviceCounters;
234
235impl Inspectable for BlackholeDeviceCounters {
236 fn record<I: Inspector>(&self, _inspector: &mut I) {}
237}
238
239#[derive(Default, Debug)]
241#[cfg_attr(
242 any(test, feature = "testutils"),
243 derive(PartialEq, netstack3_macros::CounterCollection)
244)]
245pub struct DeviceCounters<C: CounterRepr = Counter> {
246 pub send_total_frames: C,
249 pub send_frame: C,
251 pub send_bytes: C,
253 pub send_queue_full: C,
255 pub send_serialize_error: C,
257 pub recv_frame: C,
259 pub recv_bytes: C,
261 pub recv_parse_error: C,
263 pub recv_ipv4_delivered: C,
265 pub recv_ipv6_delivered: C,
267 pub send_ipv4_frame: C,
269 pub send_ipv6_frame: C,
271 pub send_dropped_no_queue: C,
273 pub send_dropped_dequeue: C,
275}
276
277impl DeviceCounters {
278 pub fn send_frame<I: Ip>(&self) -> &Counter {
280 match I::VERSION {
281 IpVersion::V4 => &self.send_ipv4_frame,
282 IpVersion::V6 => &self.send_ipv6_frame,
283 }
284 }
285}
286
287impl Inspectable for DeviceCounters {
288 fn record<I: Inspector>(&self, inspector: &mut I) {
289 let Self {
290 recv_frame,
291 recv_bytes,
292 recv_ipv4_delivered,
293 recv_ipv6_delivered,
294 recv_parse_error,
295 send_dropped_no_queue,
296 send_frame,
297 send_bytes,
298 send_ipv4_frame,
299 send_ipv6_frame,
300 send_queue_full,
301 send_serialize_error,
302 send_total_frames,
303 send_dropped_dequeue,
304 } = self;
305 inspector.record_child("Rx", |inspector| {
306 inspector.record_counter("TotalFrames", recv_frame);
307 inspector.record_counter("TotalBytes", recv_bytes);
308 inspector.record_counter("Malformed", recv_parse_error);
309 inspector.record_counter("Ipv4Delivered", recv_ipv4_delivered);
310 inspector.record_counter("Ipv6Delivered", recv_ipv6_delivered);
311 });
312 inspector.record_child("Tx", |inspector| {
313 inspector.record_counter("TotalFrames", send_total_frames);
314 inspector.record_counter("Sent", send_frame);
315 inspector.record_counter("SentBytes", send_bytes);
316 inspector.record_counter("SendIpv4Frame", send_ipv4_frame);
317 inspector.record_counter("SendIpv6Frame", send_ipv6_frame);
318 inspector.record_counter("NoQueue", send_dropped_no_queue);
319 inspector.record_counter("QueueFull", send_queue_full);
320 inspector.record_counter("SerializeError", send_serialize_error);
321 inspector.record_counter("DequeueDrop", send_dropped_dequeue);
322 });
323 }
324}
325#[derive(Clone, Debug, PartialEq)]
336pub struct OriginTracker(#[cfg(debug_assertions)] u64);
337
338impl Default for OriginTracker {
339 fn default() -> Self {
340 Self::new()
341 }
342}
343
344impl OriginTracker {
345 #[cfg_attr(not(debug_assertions), inline)]
352 fn new() -> Self {
353 Self(
354 #[cfg(debug_assertions)]
355 {
356 static COUNTER: core::sync::atomic::AtomicU64 =
357 core::sync::atomic::AtomicU64::new(0);
358 COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed)
359 },
360 )
361 }
362}
363
364pub trait OriginTrackerContext {
369 fn origin_tracker(&mut self) -> OriginTracker;
371}
372
373pub trait DeviceCollectionContext<D: Device + DeviceStateSpec, BT: DeviceLayerTypes>:
377 DeviceIdContext<D>
378{
379 fn insert(&mut self, device: BasePrimaryDeviceId<D, BT>);
381
382 fn remove(&mut self, device: &BaseDeviceId<D, BT>) -> Option<BasePrimaryDeviceId<D, BT>>;
384}
385
386pub trait DeviceReceiveFrameSpec {
392 type FrameMetadata<D>;
394}
395
396pub trait DeviceLayerStateTypes: InstantContext + FilterBindingsTypes {
398 type LoopbackDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
400
401 type EthernetDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
403
404 type PureIpDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
406
407 type BlackholeDeviceState: Send + Sync + DeviceClassMatcher<Self::DeviceClass>;
409
410 type DeviceIdentifier: Send + Sync + Debug + Display + DeviceIdAndNameMatcher;
413}
414
415pub trait DeviceClassMatcher<DeviceClass> {
418 fn device_class_matches(&self, device_class: &DeviceClass) -> bool;
421}
422
423pub trait DeviceIdAndNameMatcher {
426 fn id_matches(&self, id: &NonZeroU64) -> bool;
428
429 fn name_matches(&self, name: &str) -> bool;
431}
432
433pub trait DeviceLayerTypes:
439 DeviceLayerStateTypes
440 + socket::DeviceSocketTypes
441 + LinkResolutionContext<EthernetLinkDevice>
442 + TimerBindingsTypes
443 + ReferenceNotifiers
444 + TxMetadataBindingsTypes
445 + 'static
446{
447}
448impl<
449 BC: DeviceLayerStateTypes
450 + socket::DeviceSocketTypes
451 + LinkResolutionContext<EthernetLinkDevice>
452 + TimerBindingsTypes
453 + ReferenceNotifiers
454 + TxMetadataBindingsTypes
455 + 'static,
456> DeviceLayerTypes for BC
457{
458}
459
460pub trait DeviceLayerEventDispatcher:
462 DeviceLayerTypes
463 + ReceiveQueueBindingsContext<LoopbackDeviceId<Self>>
464 + TransmitQueueBindingsContext<EthernetDeviceId<Self>>
465 + TransmitQueueBindingsContext<LoopbackDeviceId<Self>>
466 + TransmitQueueBindingsContext<PureIpDeviceId<Self>>
467 + Sized
468{
469 type DequeueContext;
475
476 fn send_ethernet_frame(
486 &mut self,
487 device: &EthernetDeviceId<Self>,
488 frame: Buf<Vec<u8>>,
489 dequeue_context: Option<&mut Self::DequeueContext>,
490 ) -> Result<(), DeviceSendFrameError>;
491
492 fn send_ip_packet(
502 &mut self,
503 device: &PureIpDeviceId<Self>,
504 packet: Buf<Vec<u8>>,
505 ip_version: IpVersion,
506 dequeue_context: Option<&mut Self::DequeueContext>,
507 ) -> Result<(), DeviceSendFrameError>;
508}
509
510#[derive(Debug, PartialEq, Eq)]
512pub enum DeviceSendFrameError {
513 NoBuffers,
515}
516
517#[cfg(any(test, feature = "testutils"))]
518pub mod testutil {
519 use super::*;
520
521 use netstack3_base::{CounterCollection, ResourceCounterContext};
522
523 pub type DeviceCounterExpectations = DeviceCounters<u64>;
525
526 impl DeviceCounterExpectations {
527 #[track_caller]
529 pub fn assert_counters<D, CC: ResourceCounterContext<D, DeviceCounters>>(
530 &self,
531 core_ctx: &CC,
532 device: &D,
533 ) {
534 assert_eq!(&core_ctx.counters().cast::<u64>(), self, "stack-wide counters");
535 assert_eq!(
536 &core_ctx.per_resource_counters(device).cast::<u64>(),
537 self,
538 "per-device counters"
539 );
540 }
541 }
542}
543
544#[cfg(test)]
545mod tests {
546 use super::*;
547
548 #[test]
549 fn origin_tracker() {
550 let tracker = OriginTracker::new();
551 if cfg!(debug_assertions) {
552 assert_ne!(tracker, OriginTracker::new());
553 } else {
554 assert_eq!(tracker, OriginTracker::new());
555 }
556 assert_eq!(tracker.clone(), tracker);
557 }
558}