1use net_types::ip::{Ip, Ipv4, Ipv6};
8use netstack3_base::{ContextPair, CounterContext, Inspector, InspectorExt as _};
9use netstack3_device::ethernet::EthernetDeviceCounters;
10use netstack3_device::socket::DeviceSocketCounters;
11use netstack3_device::{ArpCounters, DeviceCounters};
12use netstack3_ip::gmp::{IgmpCounters, MldCounters};
13use netstack3_ip::icmp::{
14 IcmpRxCounters, IcmpRxCountersInner, IcmpTxCounters, IcmpTxCountersInner, NdpCounters,
15 NdpRxCounters, NdpTxCounters,
16};
17use netstack3_ip::multicast_forwarding::MulticastForwardingCounters;
18use netstack3_ip::nud::{NudCounters, NudCountersInner};
19use netstack3_ip::raw::RawIpSocketCounters;
20use netstack3_ip::IpCounters;
21use netstack3_tcp::{CombinedTcpCounters, TcpCountersWithSocket, TcpCountersWithoutSocket};
22use netstack3_udp::{CombinedUdpCounters, UdpCountersWithSocket, UdpCountersWithoutSocket};
23
24pub struct CountersApi<C>(C);
26
27impl<C> CountersApi<C> {
28 pub(crate) fn new(ctx: C) -> Self {
29 Self(ctx)
30 }
31}
32
33impl<C> CountersApi<C>
34where
35 C: ContextPair,
36 C::CoreContext: CounterContext<IpCounters<Ipv4>>
37 + CounterContext<IpCounters<Ipv6>>
38 + CounterContext<MulticastForwardingCounters<Ipv4>>
39 + CounterContext<MulticastForwardingCounters<Ipv6>>
40 + CounterContext<RawIpSocketCounters<Ipv4>>
41 + CounterContext<RawIpSocketCounters<Ipv6>>
42 + CounterContext<UdpCountersWithSocket<Ipv4>>
43 + CounterContext<UdpCountersWithSocket<Ipv6>>
44 + CounterContext<UdpCountersWithoutSocket<Ipv4>>
45 + CounterContext<UdpCountersWithoutSocket<Ipv6>>
46 + CounterContext<TcpCountersWithSocket<Ipv4>>
47 + CounterContext<TcpCountersWithSocket<Ipv6>>
48 + CounterContext<TcpCountersWithoutSocket<Ipv4>>
49 + CounterContext<TcpCountersWithoutSocket<Ipv6>>
50 + CounterContext<IcmpRxCounters<Ipv4>>
51 + CounterContext<IcmpRxCounters<Ipv6>>
52 + CounterContext<IcmpTxCounters<Ipv4>>
53 + CounterContext<IcmpTxCounters<Ipv4>>
54 + CounterContext<IcmpTxCounters<Ipv6>>
55 + CounterContext<IgmpCounters>
56 + CounterContext<MldCounters>
57 + CounterContext<NudCounters<Ipv4>>
58 + CounterContext<NudCounters<Ipv6>>
59 + CounterContext<NdpCounters>
60 + CounterContext<ArpCounters>
61 + CounterContext<DeviceCounters>
62 + CounterContext<EthernetDeviceCounters>
63 + CounterContext<DeviceSocketCounters>,
64{
65 fn core_ctx(&mut self) -> &mut C::CoreContext {
66 let Self(pair) = self;
67 pair.core_ctx()
68 }
69
70 pub fn inspect_stack_counters<I: Inspector>(&mut self, inspector: &mut I) {
72 inspector.record_child("Device", |inspector| {
73 inspector
74 .delegate_inspectable(CounterContext::<DeviceCounters>::counters(self.core_ctx()));
75 inspector.delegate_inspectable(CounterContext::<EthernetDeviceCounters>::counters(
76 self.core_ctx(),
77 ));
78 });
79 inspector.record_child("Arp", |inspector| {
80 inspect_arp_counters(inspector, self.core_ctx().counters());
81 });
82 inspector.record_child("NUD", |inspector| {
83 inspector.record_child("V4", |inspector| {
84 inspect_nud_counters::<Ipv4>(inspector, self.core_ctx().counters());
85 });
86 inspector.record_child("V6", |inspector| {
87 inspect_nud_counters::<Ipv6>(inspector, self.core_ctx().counters());
88 });
89 });
90 inspector.record_child("ICMP", |inspector| {
91 inspector.record_child("V4", |inspector| {
92 inspector.record_child("Rx", |inspector| {
93 inspect_icmp_rx_counters::<Ipv4>(inspector, self.core_ctx().counters());
94 });
95 inspector.record_child("Tx", |inspector| {
96 inspect_icmp_tx_counters::<Ipv4>(inspector, self.core_ctx().counters());
97 });
98 });
99 inspector.record_child("V6", |inspector| {
100 inspector.record_child("Rx", |inspector| {
101 inspect_icmp_rx_counters::<Ipv6>(inspector, self.core_ctx().counters());
102 inspector.record_child("NDP", |inspector| {
103 let NdpCounters { rx, tx: _ } = self.core_ctx().counters();
104 inspect_ndp_rx_counters(inspector, rx);
105 })
106 });
107 inspector.record_child("Tx", |inspector| {
108 inspect_icmp_tx_counters::<Ipv6>(inspector, self.core_ctx().counters());
109 inspector.record_child("NDP", |inspector| {
110 let NdpCounters { rx: _, tx } = self.core_ctx().counters();
111 inspect_ndp_tx_counters(inspector, tx);
112 })
113 });
114 });
115 });
116 inspector.record_child("IGMP", |inspector| {
117 inspector
118 .delegate_inspectable(CounterContext::<IgmpCounters>::counters(self.core_ctx()));
119 });
120 inspector.record_child("MLD", |inspector| {
121 inspector
122 .delegate_inspectable(CounterContext::<MldCounters>::counters(self.core_ctx()));
123 });
124 inspector.record_child("IPv4", |inspector| {
125 inspector.delegate_inspectable(CounterContext::<IpCounters<Ipv4>>::counters(
126 self.core_ctx(),
127 ));
128 });
129 inspector.record_child("IPv6", |inspector| {
130 inspector.delegate_inspectable(CounterContext::<IpCounters<Ipv6>>::counters(
131 self.core_ctx(),
132 ));
133 });
134 inspector.record_child("MulticastForwarding", |inspector| {
135 inspector.record_child("V4", |inspector| {
136 inspector.delegate_inspectable(
137 CounterContext::<MulticastForwardingCounters<Ipv4>>::counters(self.core_ctx()),
138 );
139 });
140 inspector.record_child("V6", |inspector| {
141 inspector.delegate_inspectable(
142 CounterContext::<MulticastForwardingCounters<Ipv6>>::counters(self.core_ctx()),
143 );
144 });
145 });
146 inspector.record_child("DeviceSockets", |inspector| {
147 inspector.delegate_inspectable(CounterContext::<DeviceSocketCounters>::counters(
148 self.core_ctx(),
149 ));
150 });
151 inspector.record_child("RawIpSockets", |inspector| {
152 inspector.record_child("V4", |inspector| {
153 inspector.delegate_inspectable(
154 CounterContext::<RawIpSocketCounters<Ipv4>>::counters(self.core_ctx()),
155 );
156 });
157 inspector.record_child("V6", |inspector| {
158 inspector.delegate_inspectable(
159 CounterContext::<RawIpSocketCounters<Ipv6>>::counters(self.core_ctx()),
160 );
161 });
162 });
163 inspector.record_child("UDP", |inspector| {
164 inspector.record_child("V4", |inspector| {
165 let ctx = self.core_ctx();
166 let with_socket = CounterContext::<UdpCountersWithSocket<Ipv4>>::counters(ctx);
167 let without_socket =
168 CounterContext::<UdpCountersWithoutSocket<Ipv4>>::counters(ctx);
169 inspector.delegate_inspectable(&CombinedUdpCounters {
170 with_socket,
171 without_socket: Some(without_socket),
172 });
173 });
174 inspector.record_child("V6", |inspector| {
175 let ctx = self.core_ctx();
176 let with_socket = CounterContext::<UdpCountersWithSocket<Ipv6>>::counters(ctx);
177 let without_socket =
178 CounterContext::<UdpCountersWithoutSocket<Ipv6>>::counters(ctx);
179 inspector.delegate_inspectable(&CombinedUdpCounters {
180 with_socket,
181 without_socket: Some(without_socket),
182 });
183 });
184 });
185 inspector.record_child("TCP", |inspector| {
186 inspector.record_child("V4", |inspector| {
187 let ctx = self.core_ctx();
188 let with_socket = CounterContext::<TcpCountersWithSocket<Ipv4>>::counters(ctx);
189 let without_socket =
190 CounterContext::<TcpCountersWithoutSocket<Ipv4>>::counters(ctx);
191 inspector.delegate_inspectable(&CombinedTcpCounters {
192 with_socket,
193 without_socket: Some(without_socket),
194 });
195 });
196 inspector.record_child("V6", |inspector| {
197 let ctx = self.core_ctx();
198 let with_socket = CounterContext::<TcpCountersWithSocket<Ipv6>>::counters(ctx);
199 let without_socket =
200 CounterContext::<TcpCountersWithoutSocket<Ipv6>>::counters(ctx);
201 inspector.delegate_inspectable(&CombinedTcpCounters {
202 with_socket,
203 without_socket: Some(without_socket),
204 });
205 });
206 });
207 }
208}
209
210fn inspect_nud_counters<I: Ip>(inspector: &mut impl Inspector, counters: &NudCounters<I>) {
211 let NudCountersInner { icmp_dest_unreachable_dropped } = counters.as_ref();
212 inspector.record_counter("IcmpDestUnreachableDropped", icmp_dest_unreachable_dropped);
213}
214
215fn inspect_arp_counters(inspector: &mut impl Inspector, counters: &ArpCounters) {
216 let ArpCounters {
217 rx_dropped_non_local_target,
218 rx_malformed_packets,
219 rx_echoed_packets,
220 rx_packets,
221 rx_requests,
222 rx_responses,
223 tx_requests,
224 tx_requests_dropped_no_local_addr,
225 tx_responses,
226 } = counters;
227 inspector.record_child("Rx", |inspector| {
228 inspector.record_counter("TotalPackets", rx_packets);
229 inspector.record_counter("Requests", rx_requests);
230 inspector.record_counter("Responses", rx_responses);
231 inspector.record_counter("Malformed", rx_malformed_packets);
232 inspector.record_counter("Echoed", rx_echoed_packets);
233 inspector.record_counter("NonLocalDstAddr", rx_dropped_non_local_target);
234 });
235 inspector.record_child("Tx", |inspector| {
236 inspector.record_counter("Requests", tx_requests);
237 inspector.record_counter("RequestsNonLocalSrcAddr", tx_requests_dropped_no_local_addr);
238 inspector.record_counter("Responses", tx_responses);
239 });
240}
241
242fn inspect_icmp_rx_counters<I: Ip>(inspector: &mut impl Inspector, counters: &IcmpRxCounters<I>) {
243 let IcmpRxCountersInner {
244 error,
245 error_delivered_to_transport_layer,
246 error_delivered_to_socket,
247 echo_request,
248 echo_reply,
249 timestamp_request,
250 dest_unreachable,
251 time_exceeded,
252 parameter_problem,
253 packet_too_big,
254 } = counters.as_ref();
255 inspector.record_counter("EchoRequest", echo_request);
256 inspector.record_counter("EchoReply", echo_reply);
257 inspector.record_counter("TimestampRequest", timestamp_request);
258 inspector.record_counter("DestUnreachable", dest_unreachable);
259 inspector.record_counter("TimeExceeded", time_exceeded);
260 inspector.record_counter("ParameterProblem", parameter_problem);
261 inspector.record_counter("PacketTooBig", packet_too_big);
262 inspector.record_counter("Error", error);
263 inspector.record_counter("ErrorDeliveredToTransportLayer", error_delivered_to_transport_layer);
264 inspector.record_counter("ErrorDeliveredToSocket", error_delivered_to_socket);
265}
266
267fn inspect_icmp_tx_counters<I: Ip>(inspector: &mut impl Inspector, counters: &IcmpTxCounters<I>) {
268 let IcmpTxCountersInner {
269 reply,
270 protocol_unreachable,
271 port_unreachable,
272 address_unreachable,
273 net_unreachable,
274 ttl_expired,
275 packet_too_big,
276 parameter_problem,
277 dest_unreachable,
278 error,
279 } = counters.as_ref();
280 inspector.record_counter("Reply", reply);
281 inspector.record_counter("ProtocolUnreachable", protocol_unreachable);
282 inspector.record_counter("PortUnreachable", port_unreachable);
283 inspector.record_counter("AddressUnreachable", address_unreachable);
284 inspector.record_counter("NetUnreachable", net_unreachable);
285 inspector.record_counter("TtlExpired", ttl_expired);
286 inspector.record_counter("PacketTooBig", packet_too_big);
287 inspector.record_counter("ParameterProblem", parameter_problem);
288 inspector.record_counter("DestUnreachable", dest_unreachable);
289 inspector.record_counter("Error", error);
290}
291
292fn inspect_ndp_tx_counters(inspector: &mut impl Inspector, counters: &NdpTxCounters) {
293 let NdpTxCounters { neighbor_advertisement, neighbor_solicitation } = counters;
294 inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
295 inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
296}
297
298fn inspect_ndp_rx_counters(inspector: &mut impl Inspector, counters: &NdpRxCounters) {
299 let NdpRxCounters {
300 neighbor_solicitation,
301 neighbor_advertisement,
302 router_advertisement,
303 router_solicitation,
304 } = counters;
305 inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
306 inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
307 inspector.record_counter("RouterSolicitation", router_solicitation);
308 inspector.record_counter("RouterAdvertisement", router_advertisement);
309}