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::IpCounters;
13use netstack3_ip::gmp::{IgmpCounters, MldCounters};
14use netstack3_ip::icmp::{
15    IcmpRxCounters, IcmpTxCounters, NdpCounters, NdpRxCounters, NdpTxCounters,
16};
17use netstack3_ip::multicast_forwarding::MulticastForwardingCounters;
18use netstack3_ip::nud::{NudCounters, NudCountersInner};
19use netstack3_ip::raw::RawIpSocketCounters;
20use netstack3_tcp::{CombinedTcpCounters, TcpCountersWithSocket, TcpCountersWithoutSocket};
21use netstack3_udp::{CombinedUdpCounters, UdpCountersWithSocket, UdpCountersWithoutSocket};
22
23/// An API struct for accessing all stack counters.
24pub struct CountersApi<C>(C);
25
26impl<C> CountersApi<C> {
27    pub(crate) fn new(ctx: C) -> Self {
28        Self(ctx)
29    }
30}
31
32impl<C> CountersApi<C>
33where
34    C: ContextPair,
35    C::CoreContext: CounterContext<IpCounters<Ipv4>>
36        + CounterContext<IpCounters<Ipv6>>
37        + CounterContext<MulticastForwardingCounters<Ipv4>>
38        + CounterContext<MulticastForwardingCounters<Ipv6>>
39        + CounterContext<RawIpSocketCounters<Ipv4>>
40        + CounterContext<RawIpSocketCounters<Ipv6>>
41        + CounterContext<UdpCountersWithSocket<Ipv4>>
42        + CounterContext<UdpCountersWithSocket<Ipv6>>
43        + CounterContext<UdpCountersWithoutSocket<Ipv4>>
44        + CounterContext<UdpCountersWithoutSocket<Ipv6>>
45        + CounterContext<TcpCountersWithSocket<Ipv4>>
46        + CounterContext<TcpCountersWithSocket<Ipv6>>
47        + CounterContext<TcpCountersWithoutSocket<Ipv4>>
48        + CounterContext<TcpCountersWithoutSocket<Ipv6>>
49        + CounterContext<IcmpRxCounters<Ipv4>>
50        + CounterContext<IcmpRxCounters<Ipv6>>
51        + CounterContext<IcmpTxCounters<Ipv4>>
52        + CounterContext<IcmpTxCounters<Ipv4>>
53        + CounterContext<IcmpTxCounters<Ipv6>>
54        + CounterContext<IgmpCounters>
55        + CounterContext<MldCounters>
56        + CounterContext<NudCounters<Ipv4>>
57        + CounterContext<NudCounters<Ipv6>>
58        + CounterContext<NdpCounters>
59        + CounterContext<ArpCounters>
60        + CounterContext<DeviceCounters>
61        + CounterContext<EthernetDeviceCounters>
62        + CounterContext<DeviceSocketCounters>,
63{
64    fn core_ctx(&mut self) -> &mut C::CoreContext {
65        let Self(pair) = self;
66        pair.core_ctx()
67    }
68
69    /// Exposes all of the stack wide counters through `inspector`.
70    pub fn inspect_stack_counters<I: Inspector>(&mut self, inspector: &mut I) {
71        inspector.record_child("Device", |inspector| {
72            inspector
73                .delegate_inspectable(CounterContext::<DeviceCounters>::counters(self.core_ctx()));
74            inspector.delegate_inspectable(CounterContext::<EthernetDeviceCounters>::counters(
75                self.core_ctx(),
76            ));
77        });
78        inspector.record_child("Arp", |inspector| {
79            inspect_arp_counters(inspector, self.core_ctx().counters());
80        });
81        inspector.record_child("NUD", |inspector| {
82            inspector.record_child("V4", |inspector| {
83                inspect_nud_counters::<Ipv4>(inspector, self.core_ctx().counters());
84            });
85            inspector.record_child("V6", |inspector| {
86                inspect_nud_counters::<Ipv6>(inspector, self.core_ctx().counters());
87            });
88        });
89        inspector.record_child("ICMP", |inspector| {
90            inspector.record_child("V4", |inspector| {
91                inspector.record_child("Rx", |inspector| {
92                    inspector.delegate_inspectable(
93                        CounterContext::<IcmpRxCounters<Ipv4>>::counters(self.core_ctx()),
94                    );
95                });
96                inspector.record_child("Tx", |inspector| {
97                    inspector.delegate_inspectable(
98                        CounterContext::<IcmpTxCounters<Ipv4>>::counters(self.core_ctx()),
99                    );
100                });
101            });
102            inspector.record_child("V6", |inspector| {
103                inspector.record_child("Rx", |inspector| {
104                    inspector.delegate_inspectable(
105                        CounterContext::<IcmpRxCounters<Ipv6>>::counters(self.core_ctx()),
106                    );
107                    inspector.record_child("NDP", |inspector| {
108                        let NdpCounters { rx, tx: _ } = self.core_ctx().counters();
109                        inspect_ndp_rx_counters(inspector, rx);
110                    })
111                });
112                inspector.record_child("Tx", |inspector| {
113                    inspector.delegate_inspectable(
114                        CounterContext::<IcmpTxCounters<Ipv6>>::counters(self.core_ctx()),
115                    );
116                    inspector.record_child("NDP", |inspector| {
117                        let NdpCounters { rx: _, tx } = self.core_ctx().counters();
118                        inspect_ndp_tx_counters(inspector, tx);
119                    })
120                });
121            });
122        });
123        inspector.record_child("IGMP", |inspector| {
124            inspector
125                .delegate_inspectable(CounterContext::<IgmpCounters>::counters(self.core_ctx()));
126        });
127        inspector.record_child("MLD", |inspector| {
128            inspector
129                .delegate_inspectable(CounterContext::<MldCounters>::counters(self.core_ctx()));
130        });
131        inspector.record_child("IPv4", |inspector| {
132            inspector.delegate_inspectable(CounterContext::<IpCounters<Ipv4>>::counters(
133                self.core_ctx(),
134            ));
135        });
136        inspector.record_child("IPv6", |inspector| {
137            inspector.delegate_inspectable(CounterContext::<IpCounters<Ipv6>>::counters(
138                self.core_ctx(),
139            ));
140        });
141        inspector.record_child("MulticastForwarding", |inspector| {
142            inspector.record_child("V4", |inspector| {
143                inspector.delegate_inspectable(
144                    CounterContext::<MulticastForwardingCounters<Ipv4>>::counters(self.core_ctx()),
145                );
146            });
147            inspector.record_child("V6", |inspector| {
148                inspector.delegate_inspectable(
149                    CounterContext::<MulticastForwardingCounters<Ipv6>>::counters(self.core_ctx()),
150                );
151            });
152        });
153        inspector.record_child("DeviceSockets", |inspector| {
154            inspector.delegate_inspectable(CounterContext::<DeviceSocketCounters>::counters(
155                self.core_ctx(),
156            ));
157        });
158        inspector.record_child("RawIpSockets", |inspector| {
159            inspector.record_child("V4", |inspector| {
160                inspector.delegate_inspectable(
161                    CounterContext::<RawIpSocketCounters<Ipv4>>::counters(self.core_ctx()),
162                );
163            });
164            inspector.record_child("V6", |inspector| {
165                inspector.delegate_inspectable(
166                    CounterContext::<RawIpSocketCounters<Ipv6>>::counters(self.core_ctx()),
167                );
168            });
169        });
170        inspector.record_child("UDP", |inspector| {
171            inspector.record_child("V4", |inspector| {
172                let ctx = self.core_ctx();
173                let with_socket = CounterContext::<UdpCountersWithSocket<Ipv4>>::counters(ctx);
174                let without_socket =
175                    CounterContext::<UdpCountersWithoutSocket<Ipv4>>::counters(ctx);
176                inspector.delegate_inspectable(&CombinedUdpCounters {
177                    with_socket,
178                    without_socket: Some(without_socket),
179                });
180            });
181            inspector.record_child("V6", |inspector| {
182                let ctx = self.core_ctx();
183                let with_socket = CounterContext::<UdpCountersWithSocket<Ipv6>>::counters(ctx);
184                let without_socket =
185                    CounterContext::<UdpCountersWithoutSocket<Ipv6>>::counters(ctx);
186                inspector.delegate_inspectable(&CombinedUdpCounters {
187                    with_socket,
188                    without_socket: Some(without_socket),
189                });
190            });
191        });
192        inspector.record_child("TCP", |inspector| {
193            inspector.record_child("V4", |inspector| {
194                let ctx = self.core_ctx();
195                let with_socket = CounterContext::<TcpCountersWithSocket<Ipv4>>::counters(ctx);
196                let without_socket =
197                    CounterContext::<TcpCountersWithoutSocket<Ipv4>>::counters(ctx);
198                inspector.delegate_inspectable(&CombinedTcpCounters {
199                    with_socket,
200                    without_socket: Some(without_socket),
201                });
202            });
203            inspector.record_child("V6", |inspector| {
204                let ctx = self.core_ctx();
205                let with_socket = CounterContext::<TcpCountersWithSocket<Ipv6>>::counters(ctx);
206                let without_socket =
207                    CounterContext::<TcpCountersWithoutSocket<Ipv6>>::counters(ctx);
208                inspector.delegate_inspectable(&CombinedTcpCounters {
209                    with_socket,
210                    without_socket: Some(without_socket),
211                });
212            });
213        });
214    }
215}
216
217fn inspect_nud_counters<I: Ip>(inspector: &mut impl Inspector, counters: &NudCounters<I>) {
218    let NudCountersInner { icmp_dest_unreachable_dropped } = counters.as_ref();
219    inspector.record_counter("IcmpDestUnreachableDropped", icmp_dest_unreachable_dropped);
220}
221
222fn inspect_arp_counters(inspector: &mut impl Inspector, counters: &ArpCounters) {
223    let ArpCounters {
224        rx_dropped_non_local_target,
225        rx_malformed_packets,
226        rx_echoed_packets,
227        rx_packets,
228        rx_requests,
229        rx_responses,
230        tx_requests,
231        tx_requests_dropped_no_local_addr,
232        tx_responses,
233    } = counters;
234    inspector.record_child("Rx", |inspector| {
235        inspector.record_counter("TotalPackets", rx_packets);
236        inspector.record_counter("Requests", rx_requests);
237        inspector.record_counter("Responses", rx_responses);
238        inspector.record_counter("Malformed", rx_malformed_packets);
239        inspector.record_counter("Echoed", rx_echoed_packets);
240        inspector.record_counter("NonLocalDstAddr", rx_dropped_non_local_target);
241    });
242    inspector.record_child("Tx", |inspector| {
243        inspector.record_counter("Requests", tx_requests);
244        inspector.record_counter("RequestsNonLocalSrcAddr", tx_requests_dropped_no_local_addr);
245        inspector.record_counter("Responses", tx_responses);
246    });
247}
248
249fn inspect_ndp_tx_counters(inspector: &mut impl Inspector, counters: &NdpTxCounters) {
250    let NdpTxCounters { neighbor_advertisement, neighbor_solicitation } = counters;
251    inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
252    inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
253}
254
255fn inspect_ndp_rx_counters(inspector: &mut impl Inspector, counters: &NdpRxCounters) {
256    let NdpRxCounters {
257        neighbor_solicitation,
258        neighbor_advertisement,
259        router_advertisement,
260        router_solicitation,
261    } = counters;
262    inspector.record_counter("NeighborSolicitation", neighbor_solicitation);
263    inspector.record_counter("NeighborAdvertisement", neighbor_advertisement);
264    inspector.record_counter("RouterSolicitation", router_solicitation);
265    inspector.record_counter("RouterAdvertisement", router_advertisement);
266}