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::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
23pub 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 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}