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::{FragmentationCounters, IpCounters, IpLayerIpExt};
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 inspect_ip_counters::<Ipv4>(inspector, self.core_ctx().counters());
126 });
127 inspector.record_child("IPv6", |inspector| {
128 inspect_ip_counters::<Ipv6>(inspector, self.core_ctx().counters());
129 });
130 inspector.record_child("MulticastForwarding", |inspector| {
131 inspector.record_child("V4", |inspector| {
132 inspector.delegate_inspectable(
133 CounterContext::<MulticastForwardingCounters<Ipv4>>::counters(self.core_ctx()),
134 );
135 });
136 inspector.record_child("V6", |inspector| {
137 inspector.delegate_inspectable(
138 CounterContext::<MulticastForwardingCounters<Ipv6>>::counters(self.core_ctx()),
139 );
140 });
141 });
142 inspector.record_child("DeviceSockets", |inspector| {
143 inspector.delegate_inspectable(CounterContext::<DeviceSocketCounters>::counters(
144 self.core_ctx(),
145 ));
146 });
147 inspector.record_child("RawIpSockets", |inspector| {
148 inspector.record_child("V4", |inspector| {
149 inspector.delegate_inspectable(
150 CounterContext::<RawIpSocketCounters<Ipv4>>::counters(self.core_ctx()),
151 );
152 });
153 inspector.record_child("V6", |inspector| {
154 inspector.delegate_inspectable(
155 CounterContext::<RawIpSocketCounters<Ipv6>>::counters(self.core_ctx()),
156 );
157 });
158 });
159 inspector.record_child("UDP", |inspector| {
160 inspector.record_child("V4", |inspector| {
161 let ctx = self.core_ctx();
162 let with_socket = CounterContext::<UdpCountersWithSocket<Ipv4>>::counters(ctx);
163 let without_socket =
164 CounterContext::<UdpCountersWithoutSocket<Ipv4>>::counters(ctx);
165 inspector.delegate_inspectable(&CombinedUdpCounters {
166 with_socket,
167 without_socket: Some(without_socket),
168 });
169 });
170 inspector.record_child("V6", |inspector| {
171 let ctx = self.core_ctx();
172 let with_socket = CounterContext::<UdpCountersWithSocket<Ipv6>>::counters(ctx);
173 let without_socket =
174 CounterContext::<UdpCountersWithoutSocket<Ipv6>>::counters(ctx);
175 inspector.delegate_inspectable(&CombinedUdpCounters {
176 with_socket,
177 without_socket: Some(without_socket),
178 });
179 });
180 });
181 inspector.record_child("TCP", |inspector| {
182 inspector.record_child("V4", |inspector| {
183 let ctx = self.core_ctx();
184 let with_socket = CounterContext::<TcpCountersWithSocket<Ipv4>>::counters(ctx);
185 let without_socket =
186 CounterContext::<TcpCountersWithoutSocket<Ipv4>>::counters(ctx);
187 inspector.delegate_inspectable(&CombinedTcpCounters {
188 with_socket,
189 without_socket: Some(without_socket),
190 });
191 });
192 inspector.record_child("V6", |inspector| {
193 let ctx = self.core_ctx();
194 let with_socket = CounterContext::<TcpCountersWithSocket<Ipv6>>::counters(ctx);
195 let without_socket =
196 CounterContext::<TcpCountersWithoutSocket<Ipv6>>::counters(ctx);
197 inspector.delegate_inspectable(&CombinedTcpCounters {
198 with_socket,
199 without_socket: Some(without_socket),
200 });
201 });
202 });
203 }
204}
205
206fn inspect_nud_counters<I: Ip>(inspector: &mut impl Inspector, counters: &NudCounters<I>) {
207 let NudCountersInner { icmp_dest_unreachable_dropped } = counters.as_ref();
208 inspector.record_counter("IcmpDestUnreachableDropped", icmp_dest_unreachable_dropped);
209}
210
211fn inspect_arp_counters(inspector: &mut impl Inspector, counters: &ArpCounters) {
212 let ArpCounters {
213 rx_dropped_non_local_target,
214 rx_malformed_packets,
215 rx_packets,
216 rx_requests,
217 rx_responses,
218 tx_requests,
219 tx_requests_dropped_no_local_addr,
220 tx_responses,
221 } = counters;
222 inspector.record_child("Rx", |inspector| {
223 inspector.record_counter("TotalPackets", rx_packets);
224 inspector.record_counter("Requests", rx_requests);
225 inspector.record_counter("Responses", rx_responses);
226 inspector.record_counter("Malformed", rx_malformed_packets);
227 inspector.record_counter("NonLocalDstAddr", rx_dropped_non_local_target);
228 });
229 inspector.record_child("Tx", |inspector| {
230 inspector.record_counter("Requests", tx_requests);
231 inspector.record_counter("RequestsNonLocalSrcAddr", tx_requests_dropped_no_local_addr);
232 inspector.record_counter("Responses", tx_responses);
233 });
234}
235
236fn inspect_icmp_rx_counters<I: Ip>(inspector: &mut impl Inspector, counters: &IcmpRxCounters<I>) {
237 let IcmpRxCountersInner {
238 error,
239 error_delivered_to_transport_layer,
240 error_delivered_to_socket,
241 echo_request,
242 echo_reply,
243 timestamp_request,
244 dest_unreachable,
245 time_exceeded,
246 parameter_problem,
247 packet_too_big,
248 } = counters.as_ref();
249 inspector.record_counter("EchoRequest", echo_request);
250 inspector.record_counter("EchoReply", echo_reply);
251 inspector.record_counter("TimestampRequest", timestamp_request);
252 inspector.record_counter("DestUnreachable", dest_unreachable);
253 inspector.record_counter("TimeExceeded", time_exceeded);
254 inspector.record_counter("ParameterProblem", parameter_problem);
255 inspector.record_counter("PacketTooBig", packet_too_big);
256 inspector.record_counter("Error", error);
257 inspector.record_counter("ErrorDeliveredToTransportLayer", error_delivered_to_transport_layer);
258 inspector.record_counter("ErrorDeliveredToSocket", error_delivered_to_socket);
259}
260
261fn inspect_icmp_tx_counters<I: Ip>(inspector: &mut impl Inspector, counters: &IcmpTxCounters<I>) {
262 let IcmpTxCountersInner {
263 reply,
264 protocol_unreachable,
265 port_unreachable,
266 address_unreachable,
267 net_unreachable,
268 ttl_expired,
269 packet_too_big,
270 parameter_problem,
271 dest_unreachable,
272 error,
273 } = counters.as_ref();
274 inspector.record_counter("Reply", reply);
275 inspector.record_counter("ProtocolUnreachable", protocol_unreachable);
276 inspector.record_counter("PortUnreachable", port_unreachable);
277 inspector.record_counter("AddressUnreachable", address_unreachable);
278 inspector.record_counter("NetUnreachable", net_unreachable);
279 inspector.record_counter("TtlExpired", ttl_expired);
280 inspector.record_counter("PacketTooBig", packet_too_big);
281 inspector.record_counter("ParameterProblem", parameter_problem);
282 inspector.record_counter("DestUnreachable", dest_unreachable);
283 inspector.record_counter("Error", error);
284}
285
286fn inspect_ndp_tx_counters(inspector: &mut impl Inspector, counters: &NdpTxCounters) {
287 let NdpTxCounters { neighbor_advertisement, neighbor_solicitation } = counters;
288 inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
289 inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
290}
291
292fn inspect_ndp_rx_counters(inspector: &mut impl Inspector, counters: &NdpRxCounters) {
293 let NdpRxCounters {
294 neighbor_solicitation,
295 neighbor_advertisement,
296 router_advertisement,
297 router_solicitation,
298 } = counters;
299 inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
300 inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
301 inspector.record_counter("RouterSolicitation", router_solicitation);
302 inspector.record_counter("RouterAdvertisement", router_advertisement);
303}
304
305fn inspect_ip_counters<I: IpLayerIpExt>(inspector: &mut impl Inspector, counters: &IpCounters<I>) {
306 let IpCounters {
307 deliver_unicast,
308 deliver_multicast,
309 dispatch_receive_ip_packet,
310 dispatch_receive_ip_packet_other_host,
311 receive_ip_packet,
312 send_ip_packet,
313 forwarding_disabled,
314 forward,
315 no_route_to_host,
316 mtu_exceeded,
317 ttl_expired,
318 receive_icmp_error,
319 fragment_reassembly_error,
320 need_more_fragments,
321 invalid_fragment,
322 fragment_cache_full,
323 parameter_problem,
324 unspecified_destination,
325 unspecified_source,
326 dropped,
327 tx_illegal_loopback_address,
328 version_rx,
329 multicast_no_interest,
330 invalid_cached_conntrack_entry,
331 fragmentation,
332 } = counters;
333 inspector.record_child("PacketTx", |inspector| {
334 inspector.record_counter("Sent", send_ip_packet);
335 inspector.record_counter("IllegalLoopbackAddress", tx_illegal_loopback_address);
336 });
337 inspector.record_child("PacketRx", |inspector| {
338 inspector.record_counter("Received", receive_ip_packet);
339 inspector.record_counter("Dispatched", dispatch_receive_ip_packet);
340 inspector.record_counter("OtherHost", dispatch_receive_ip_packet_other_host);
341 inspector.record_counter("ParameterProblem", parameter_problem);
342 inspector.record_counter("UnspecifiedDst", unspecified_destination);
343 inspector.record_counter("UnspecifiedSrc", unspecified_source);
344 inspector.record_counter("Dropped", dropped);
345 inspector.record_counter("MulticastNoInterest", multicast_no_interest);
346 inspector.record_counter("DeliveredUnicast", deliver_unicast);
347 inspector.record_counter("DeliveredMulticast", deliver_multicast);
348 inspector.record_counter("InvalidCachedConntrackEntry", invalid_cached_conntrack_entry);
349 inspector.delegate_inspectable(version_rx);
350 });
351 inspector.record_child("Forwarding", |inspector| {
352 inspector.record_counter("Forwarded", forward);
353 inspector.record_counter("ForwardingDisabled", forwarding_disabled);
354 inspector.record_counter("NoRouteToHost", no_route_to_host);
355 inspector.record_counter("MtuExceeded", mtu_exceeded);
356 inspector.record_counter("TtlExpired", ttl_expired);
357 });
358 inspector.record_counter("RxIcmpError", receive_icmp_error);
359 inspector.record_child("FragmentsRx", |inspector| {
360 inspector.record_counter("ReassemblyError", fragment_reassembly_error);
361 inspector.record_counter("NeedMoreFragments", need_more_fragments);
362 inspector.record_counter("InvalidFragment", invalid_fragment);
363 inspector.record_counter("CacheFull", fragment_cache_full);
364 });
365 inspector.record_child("FragmentsTx", |inspector| {
366 let FragmentationCounters {
367 fragmentation_required,
368 fragments,
369 error_not_allowed,
370 error_mtu_too_small,
371 error_body_too_long,
372 error_inner_size_limit_exceeded,
373 error_fragmented_serializer,
374 } = fragmentation;
375 inspector.record_counter("FragmentationRequired", fragmentation_required);
376 inspector.record_counter("Fragments", fragments);
377 inspector.record_counter("ErrorNotAllowed", error_not_allowed);
378 inspector.record_counter("ErrorMtuTooSmall", error_mtu_too_small);
379 inspector.record_counter("ErrorBodyTooLong", error_body_too_long);
380 inspector.record_counter("ErrorInnerSizeLimitExceeded", error_inner_size_limit_exceeded);
381 inspector.record_counter("ErrorFragmentedSerializer", error_fragmented_serializer);
382 });
383}