1use net_types::ip::{Ip, IpMarked};
8use netstack3_base::{
9 Counter, CounterContext, Inspectable, Inspector, InspectorExt as _, ResourceCounterContext,
10 WeakDeviceIdentifier,
11};
12use netstack3_datagram::IpExt;
13
14use crate::internal::base::{UdpBindingsTypes, UdpSocketId};
15
16pub trait UdpCounterContext<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>:
18 ResourceCounterContext<UdpSocketId<I, D, BT>, UdpCountersWithSocket<I>>
19 + CounterContext<UdpCountersWithoutSocket<I>>
20{
21}
22
23impl<I, D, BT, CC> UdpCounterContext<I, D, BT> for CC
24where
25 I: IpExt,
26 D: WeakDeviceIdentifier,
27 BT: UdpBindingsTypes,
28 CC: ResourceCounterContext<UdpSocketId<I, D, BT>, UdpCountersWithSocket<I>>
29 + CounterContext<UdpCountersWithoutSocket<I>>,
30{
31}
32
33pub type UdpCountersWithoutSocket<I> = IpMarked<I, UdpCountersWithoutSocketInner>;
39
40#[derive(Default)]
44#[cfg_attr(test, derive(Debug, PartialEq))]
45pub struct UdpCountersWithoutSocketInner<C = Counter> {
46 pub rx_icmp_error: C,
48 pub rx: C,
51 pub rx_mapped_addr: C,
54 pub rx_unknown_dest_port: C,
57 pub rx_malformed: C,
60}
61
62pub type UdpCountersWithSocket<I> = IpMarked<I, UdpCountersWithSocketInner>;
72
73#[derive(Default, Debug)]
77#[cfg_attr(test, derive(PartialEq))]
78pub struct UdpCountersWithSocketInner<C = Counter> {
79 pub rx_delivered: C,
84 pub tx: C,
87 pub tx_error: C,
90}
91
92pub struct CombinedUdpCounters<'a, I: Ip> {
94 pub with_socket: &'a UdpCountersWithSocket<I>,
96 pub without_socket: Option<&'a UdpCountersWithoutSocket<I>>,
102}
103
104impl<I: Ip> Inspectable for CombinedUdpCounters<'_, I> {
105 fn record<II: Inspector>(&self, inspector: &mut II) {
106 let CombinedUdpCounters { with_socket, without_socket } = self;
107 let UdpCountersWithSocketInner { rx_delivered, tx, tx_error } = with_socket.as_ref();
108
109 struct WithoutSocketRx<'a> {
112 rx: &'a Counter,
113 rx_mapped_addr: &'a Counter,
114 rx_unknown_dest_port: &'a Counter,
115 rx_malformed: &'a Counter,
116 }
117 struct WithoutSocketError<'a> {
118 rx_icmp_error: &'a Counter,
119 }
120 let (without_socket_rx, without_socket_error) = match without_socket.map(AsRef::as_ref) {
121 None => (None, None),
122 Some(UdpCountersWithoutSocketInner {
123 rx_icmp_error,
124 rx,
125 rx_mapped_addr,
126 rx_unknown_dest_port,
127 rx_malformed,
128 }) => (
129 Some(WithoutSocketRx { rx, rx_mapped_addr, rx_unknown_dest_port, rx_malformed }),
130 Some(WithoutSocketError { rx_icmp_error }),
131 ),
132 };
133 inspector.record_child("Rx", |inspector| {
134 inspector.record_counter("Delivered", rx_delivered);
135 if let Some(WithoutSocketRx {
136 rx,
137 rx_mapped_addr,
138 rx_unknown_dest_port,
139 rx_malformed,
140 }) = without_socket_rx
141 {
142 inspector.record_counter("Received", rx);
143 inspector.record_child("Errors", |inspector| {
144 inspector.record_counter("MappedAddr", rx_mapped_addr);
145 inspector.record_counter("UnknownDstPort", rx_unknown_dest_port);
146 inspector.record_counter("Malformed", rx_malformed);
147 });
148 }
149 });
150 inspector.record_child("Tx", |inspector| {
151 inspector.record_counter("Sent", tx);
152 inspector.record_counter("Errors", tx_error);
153 });
154 if let Some(WithoutSocketError { rx_icmp_error }) = without_socket_error {
155 inspector.record_counter("IcmpErrors", rx_icmp_error);
156 }
157 }
158}
159
160#[cfg(test)]
161pub(crate) mod testutil {
162 use super::*;
163
164 pub(crate) type CounterExpectationsWithSocket = UdpCountersWithSocketInner<u64>;
165
166 impl From<&UdpCountersWithSocketInner> for CounterExpectationsWithSocket {
167 fn from(counters: &UdpCountersWithSocketInner) -> CounterExpectationsWithSocket {
168 let UdpCountersWithSocketInner { rx_delivered, tx, tx_error } = counters;
169 CounterExpectationsWithSocket {
170 rx_delivered: rx_delivered.get(),
171 tx: tx.get(),
172 tx_error: tx_error.get(),
173 }
174 }
175 }
176
177 pub(crate) type CounterExpectationsWithoutSocket = UdpCountersWithoutSocketInner<u64>;
178
179 impl From<&UdpCountersWithoutSocketInner> for CounterExpectationsWithoutSocket {
180 fn from(counters: &UdpCountersWithoutSocketInner) -> CounterExpectationsWithoutSocket {
181 let UdpCountersWithoutSocketInner {
182 rx_icmp_error,
183 rx,
184 rx_mapped_addr,
185 rx_unknown_dest_port,
186 rx_malformed,
187 } = counters;
188 CounterExpectationsWithoutSocket {
189 rx_icmp_error: rx_icmp_error.get(),
190 rx: rx.get(),
191 rx_mapped_addr: rx_mapped_addr.get(),
192 rx_unknown_dest_port: rx_unknown_dest_port.get(),
193 rx_malformed: rx_malformed.get(),
194 }
195 }
196 }
197}