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::IpCounters;
21use netstack3_tcp::{CombinedTcpCounters, TcpCountersWithSocket, TcpCountersWithoutSocket};
22use netstack3_udp::{CombinedUdpCounters, UdpCountersWithSocket, UdpCountersWithoutSocket};
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<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    /// Exposes all of the stack wide counters through `inspector`.
71    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}