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::{UdpCounters, UdpCountersInner};
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<UdpCounters<Ipv4>>
43 + CounterContext<UdpCounters<Ipv6>>
44 + CounterContext<TcpCountersWithSocket<Ipv4>>
45 + CounterContext<TcpCountersWithSocket<Ipv6>>
46 + CounterContext<TcpCountersWithoutSocket<Ipv4>>
47 + CounterContext<TcpCountersWithoutSocket<Ipv6>>
48 + CounterContext<IcmpRxCounters<Ipv4>>
49 + CounterContext<IcmpRxCounters<Ipv6>>
50 + CounterContext<IcmpTxCounters<Ipv4>>
51 + CounterContext<IcmpTxCounters<Ipv4>>
52 + CounterContext<IcmpTxCounters<Ipv6>>
53 + CounterContext<IgmpCounters>
54 + CounterContext<MldCounters>
55 + CounterContext<NudCounters<Ipv4>>
56 + CounterContext<NudCounters<Ipv6>>
57 + CounterContext<NdpCounters>
58 + CounterContext<ArpCounters>
59 + CounterContext<DeviceCounters>
60 + CounterContext<EthernetDeviceCounters>
61 + CounterContext<DeviceSocketCounters>,
62{
63 fn core_ctx(&mut self) -> &mut C::CoreContext {
64 let Self(pair) = self;
65 pair.core_ctx()
66 }
67
68 pub fn inspect_stack_counters<I: Inspector>(&mut self, inspector: &mut I) {
70 inspector.record_child("Device", |inspector| {
71 inspector
72 .delegate_inspectable(CounterContext::<DeviceCounters>::counters(self.core_ctx()));
73 inspector.delegate_inspectable(CounterContext::<EthernetDeviceCounters>::counters(
74 self.core_ctx(),
75 ));
76 });
77 inspector.record_child("Arp", |inspector| {
78 inspect_arp_counters(inspector, self.core_ctx().counters());
79 });
80 inspector.record_child("NUD", |inspector| {
81 inspector.record_child("V4", |inspector| {
82 inspect_nud_counters::<Ipv4>(inspector, self.core_ctx().counters());
83 });
84 inspector.record_child("V6", |inspector| {
85 inspect_nud_counters::<Ipv6>(inspector, self.core_ctx().counters());
86 });
87 });
88 inspector.record_child("ICMP", |inspector| {
89 inspector.record_child("V4", |inspector| {
90 inspector.record_child("Rx", |inspector| {
91 inspect_icmp_rx_counters::<Ipv4>(inspector, self.core_ctx().counters());
92 });
93 inspector.record_child("Tx", |inspector| {
94 inspect_icmp_tx_counters::<Ipv4>(inspector, self.core_ctx().counters());
95 });
96 });
97 inspector.record_child("V6", |inspector| {
98 inspector.record_child("Rx", |inspector| {
99 inspect_icmp_rx_counters::<Ipv6>(inspector, self.core_ctx().counters());
100 inspector.record_child("NDP", |inspector| {
101 let NdpCounters { rx, tx: _ } = self.core_ctx().counters();
102 inspect_ndp_rx_counters(inspector, rx);
103 })
104 });
105 inspector.record_child("Tx", |inspector| {
106 inspect_icmp_tx_counters::<Ipv6>(inspector, self.core_ctx().counters());
107 inspector.record_child("NDP", |inspector| {
108 let NdpCounters { rx: _, tx } = self.core_ctx().counters();
109 inspect_ndp_tx_counters(inspector, tx);
110 })
111 });
112 });
113 });
114 inspector.record_child("IGMP", |inspector| {
115 inspector
116 .delegate_inspectable(CounterContext::<IgmpCounters>::counters(self.core_ctx()));
117 });
118 inspector.record_child("MLD", |inspector| {
119 inspector
120 .delegate_inspectable(CounterContext::<MldCounters>::counters(self.core_ctx()));
121 });
122 inspector.record_child("IPv4", |inspector| {
123 inspect_ip_counters::<Ipv4>(inspector, self.core_ctx().counters());
124 });
125 inspector.record_child("IPv6", |inspector| {
126 inspect_ip_counters::<Ipv6>(inspector, self.core_ctx().counters());
127 });
128 inspector.record_child("MulticastForwarding", |inspector| {
129 inspector.record_child("V4", |inspector| {
130 inspector.delegate_inspectable(
131 CounterContext::<MulticastForwardingCounters<Ipv4>>::counters(self.core_ctx()),
132 );
133 });
134 inspector.record_child("V6", |inspector| {
135 inspector.delegate_inspectable(
136 CounterContext::<MulticastForwardingCounters<Ipv6>>::counters(self.core_ctx()),
137 );
138 });
139 });
140 inspector.record_child("DeviceSockets", |inspector| {
141 inspector.delegate_inspectable(CounterContext::<DeviceSocketCounters>::counters(
142 self.core_ctx(),
143 ));
144 });
145 inspector.record_child("RawIpSockets", |inspector| {
146 inspector.record_child("V4", |inspector| {
147 inspector.delegate_inspectable(
148 CounterContext::<RawIpSocketCounters<Ipv4>>::counters(self.core_ctx()),
149 );
150 });
151 inspector.record_child("V6", |inspector| {
152 inspector.delegate_inspectable(
153 CounterContext::<RawIpSocketCounters<Ipv6>>::counters(self.core_ctx()),
154 );
155 });
156 });
157 inspector.record_child("UDP", |inspector| {
158 inspector.record_child("V4", |inspector| {
159 inspect_udp_counters::<Ipv4>(inspector, self.core_ctx().counters());
160 });
161 inspector.record_child("V6", |inspector| {
162 inspect_udp_counters::<Ipv6>(inspector, self.core_ctx().counters());
163 });
164 });
165 inspector.record_child("TCP", |inspector| {
166 inspector.record_child("V4", |inspector| {
167 let ctx = self.core_ctx();
168 let with_socket = CounterContext::<TcpCountersWithSocket<Ipv4>>::counters(ctx);
169 let without_socket =
170 CounterContext::<TcpCountersWithoutSocket<Ipv4>>::counters(ctx);
171 inspector.delegate_inspectable(&CombinedTcpCounters {
172 with_socket,
173 without_socket: Some(without_socket),
174 });
175 });
176 inspector.record_child("V6", |inspector| {
177 let ctx = self.core_ctx();
178 let with_socket = CounterContext::<TcpCountersWithSocket<Ipv6>>::counters(ctx);
179 let without_socket =
180 CounterContext::<TcpCountersWithoutSocket<Ipv6>>::counters(ctx);
181 inspector.delegate_inspectable(&CombinedTcpCounters {
182 with_socket,
183 without_socket: Some(without_socket),
184 });
185 });
186 });
187 }
188}
189
190fn inspect_nud_counters<I: Ip>(inspector: &mut impl Inspector, counters: &NudCounters<I>) {
191 let NudCountersInner { icmp_dest_unreachable_dropped } = counters.as_ref();
192 inspector.record_counter("IcmpDestUnreachableDropped", icmp_dest_unreachable_dropped);
193}
194
195fn inspect_arp_counters(inspector: &mut impl Inspector, counters: &ArpCounters) {
196 let ArpCounters {
197 rx_dropped_non_local_target,
198 rx_malformed_packets,
199 rx_packets,
200 rx_requests,
201 rx_responses,
202 tx_requests,
203 tx_requests_dropped_no_local_addr,
204 tx_responses,
205 } = counters;
206 inspector.record_child("Rx", |inspector| {
207 inspector.record_counter("TotalPackets", rx_packets);
208 inspector.record_counter("Requests", rx_requests);
209 inspector.record_counter("Responses", rx_responses);
210 inspector.record_counter("Malformed", rx_malformed_packets);
211 inspector.record_counter("NonLocalDstAddr", rx_dropped_non_local_target);
212 });
213 inspector.record_child("Tx", |inspector| {
214 inspector.record_counter("Requests", tx_requests);
215 inspector.record_counter("RequestsNonLocalSrcAddr", tx_requests_dropped_no_local_addr);
216 inspector.record_counter("Responses", tx_responses);
217 });
218}
219
220fn inspect_icmp_rx_counters<I: Ip>(inspector: &mut impl Inspector, counters: &IcmpRxCounters<I>) {
221 let IcmpRxCountersInner {
222 error,
223 error_delivered_to_transport_layer,
224 error_delivered_to_socket,
225 echo_request,
226 echo_reply,
227 timestamp_request,
228 dest_unreachable,
229 time_exceeded,
230 parameter_problem,
231 packet_too_big,
232 } = counters.as_ref();
233 inspector.record_counter("EchoRequest", echo_request);
234 inspector.record_counter("EchoReply", echo_reply);
235 inspector.record_counter("TimestampRequest", timestamp_request);
236 inspector.record_counter("DestUnreachable", dest_unreachable);
237 inspector.record_counter("TimeExceeded", time_exceeded);
238 inspector.record_counter("ParameterProblem", parameter_problem);
239 inspector.record_counter("PacketTooBig", packet_too_big);
240 inspector.record_counter("Error", error);
241 inspector.record_counter("ErrorDeliveredToTransportLayer", error_delivered_to_transport_layer);
242 inspector.record_counter("ErrorDeliveredToSocket", error_delivered_to_socket);
243}
244
245fn inspect_icmp_tx_counters<I: Ip>(inspector: &mut impl Inspector, counters: &IcmpTxCounters<I>) {
246 let IcmpTxCountersInner {
247 reply,
248 protocol_unreachable,
249 port_unreachable,
250 address_unreachable,
251 net_unreachable,
252 ttl_expired,
253 packet_too_big,
254 parameter_problem,
255 dest_unreachable,
256 error,
257 } = counters.as_ref();
258 inspector.record_counter("Reply", reply);
259 inspector.record_counter("ProtocolUnreachable", protocol_unreachable);
260 inspector.record_counter("PortUnreachable", port_unreachable);
261 inspector.record_counter("AddressUnreachable", address_unreachable);
262 inspector.record_counter("NetUnreachable", net_unreachable);
263 inspector.record_counter("TtlExpired", ttl_expired);
264 inspector.record_counter("PacketTooBig", packet_too_big);
265 inspector.record_counter("ParameterProblem", parameter_problem);
266 inspector.record_counter("DestUnreachable", dest_unreachable);
267 inspector.record_counter("Error", error);
268}
269
270fn inspect_ndp_tx_counters(inspector: &mut impl Inspector, counters: &NdpTxCounters) {
271 let NdpTxCounters { neighbor_advertisement, neighbor_solicitation } = counters;
272 inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
273 inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
274}
275
276fn inspect_ndp_rx_counters(inspector: &mut impl Inspector, counters: &NdpRxCounters) {
277 let NdpRxCounters {
278 neighbor_solicitation,
279 neighbor_advertisement,
280 router_advertisement,
281 router_solicitation,
282 } = counters;
283 inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
284 inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
285 inspector.record_counter("RouterSolicitation", router_solicitation);
286 inspector.record_counter("RouterAdvertisement", router_advertisement);
287}
288
289fn inspect_ip_counters<I: IpLayerIpExt>(inspector: &mut impl Inspector, counters: &IpCounters<I>) {
290 let IpCounters {
291 deliver_unicast,
292 deliver_multicast,
293 dispatch_receive_ip_packet,
294 dispatch_receive_ip_packet_other_host,
295 receive_ip_packet,
296 send_ip_packet,
297 forwarding_disabled,
298 forward,
299 no_route_to_host,
300 mtu_exceeded,
301 ttl_expired,
302 receive_icmp_error,
303 fragment_reassembly_error,
304 need_more_fragments,
305 invalid_fragment,
306 fragment_cache_full,
307 parameter_problem,
308 unspecified_destination,
309 unspecified_source,
310 dropped,
311 tx_illegal_loopback_address,
312 version_rx,
313 multicast_no_interest,
314 invalid_cached_conntrack_entry,
315 fragmentation,
316 } = counters;
317 inspector.record_child("PacketTx", |inspector| {
318 inspector.record_counter("Sent", send_ip_packet);
319 inspector.record_counter("IllegalLoopbackAddress", tx_illegal_loopback_address);
320 });
321 inspector.record_child("PacketRx", |inspector| {
322 inspector.record_counter("Received", receive_ip_packet);
323 inspector.record_counter("Dispatched", dispatch_receive_ip_packet);
324 inspector.record_counter("OtherHost", dispatch_receive_ip_packet_other_host);
325 inspector.record_counter("ParameterProblem", parameter_problem);
326 inspector.record_counter("UnspecifiedDst", unspecified_destination);
327 inspector.record_counter("UnspecifiedSrc", unspecified_source);
328 inspector.record_counter("Dropped", dropped);
329 inspector.record_counter("MulticastNoInterest", multicast_no_interest);
330 inspector.record_counter("DeliveredUnicast", deliver_unicast);
331 inspector.record_counter("DeliveredMulticast", deliver_multicast);
332 inspector.record_counter("InvalidCachedConntrackEntry", invalid_cached_conntrack_entry);
333 inspector.delegate_inspectable(version_rx);
334 });
335 inspector.record_child("Forwarding", |inspector| {
336 inspector.record_counter("Forwarded", forward);
337 inspector.record_counter("ForwardingDisabled", forwarding_disabled);
338 inspector.record_counter("NoRouteToHost", no_route_to_host);
339 inspector.record_counter("MtuExceeded", mtu_exceeded);
340 inspector.record_counter("TtlExpired", ttl_expired);
341 });
342 inspector.record_counter("RxIcmpError", receive_icmp_error);
343 inspector.record_child("FragmentsRx", |inspector| {
344 inspector.record_counter("ReassemblyError", fragment_reassembly_error);
345 inspector.record_counter("NeedMoreFragments", need_more_fragments);
346 inspector.record_counter("InvalidFragment", invalid_fragment);
347 inspector.record_counter("CacheFull", fragment_cache_full);
348 });
349 inspector.record_child("FragmentsTx", |inspector| {
350 let FragmentationCounters {
351 fragmentation_required,
352 fragments,
353 error_not_allowed,
354 error_mtu_too_small,
355 error_body_too_long,
356 error_inner_size_limit_exceeded,
357 error_fragmented_serializer,
358 } = fragmentation;
359 inspector.record_counter("FragmentationRequired", fragmentation_required);
360 inspector.record_counter("Fragments", fragments);
361 inspector.record_counter("ErrorNotAllowed", error_not_allowed);
362 inspector.record_counter("ErrorMtuTooSmall", error_mtu_too_small);
363 inspector.record_counter("ErrorBodyTooLong", error_body_too_long);
364 inspector.record_counter("ErrorInnerSizeLimitExceeded", error_inner_size_limit_exceeded);
365 inspector.record_counter("ErrorFragmentedSerializer", error_fragmented_serializer);
366 });
367}
368
369fn inspect_udp_counters<I: Ip>(inspector: &mut impl Inspector, counters: &UdpCounters<I>) {
370 let UdpCountersInner {
371 rx_icmp_error,
372 rx,
373 rx_mapped_addr,
374 rx_unknown_dest_port,
375 rx_malformed,
376 tx,
377 tx_error,
378 } = counters.as_ref();
379 inspector.record_child("Rx", |inspector| {
380 inspector.record_counter("Received", rx);
381 inspector.record_child("Errors", |inspector| {
382 inspector.record_counter("MappedAddr", rx_mapped_addr);
383 inspector.record_counter("UnknownDstPort", rx_unknown_dest_port);
384 inspector.record_counter("Malformed", rx_malformed);
385 });
386 });
387 inspector.record_child("Tx", |inspector| {
388 inspector.record_counter("Sent", tx);
389 inspector.record_counter("Errors", tx_error);
390 });
391 inspector.record_counter("IcmpErrors", rx_icmp_error);
392}