netstack3_core/
counters.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Types for working with and exposing packet statistic counters.
6
7use 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
24/// An API struct for accessing all stack counters.
25pub 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    /// Exposes all of the stack wide counters through `inspector`.
69    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}