1use core::fmt::Debug;
8use net_types::ip::{Ip, Ipv4, Ipv6};
9use netstack3_base::{
10 Counter, CounterCollectionSpec, CounterRepr, Inspectable, Inspector, InspectorExt,
11 TestOnlyPartialEq,
12};
13use packet_formats::icmp::{
14 Icmpv4DestUnreachableCode, Icmpv4ParameterProblemCode, Icmpv4TimeExceededCode,
15 Icmpv6DestUnreachableCode, Icmpv6ParameterProblemCode, Icmpv6TimeExceededCode,
16};
17
18pub trait IcmpCountersIpExt: Ip {
20 type DestUnreachableCounters: CounterCollectionSpec<CounterCollection<Counter>: Inspectable>
22 + Default
23 + Debug
24 + TestOnlyPartialEq;
25
26 type TimeExceededCounters: CounterCollectionSpec<CounterCollection<Counter>: Inspectable>
28 + Default
29 + Debug
30 + TestOnlyPartialEq;
31
32 type ParameterProblemCounters: CounterCollectionSpec<CounterCollection<Counter>: Inspectable>
34 + Default
35 + Debug
36 + TestOnlyPartialEq;
37}
38
39impl IcmpCountersIpExt for Ipv4 {
40 type DestUnreachableCounters = Icmpv4DestUnreachableCounters;
41 type TimeExceededCounters = Icmpv4TimeExceededCounters;
42 type ParameterProblemCounters = Icmpv4ParameterProblemCounters;
43}
44
45impl IcmpCountersIpExt for Ipv6 {
46 type DestUnreachableCounters = Icmpv6DestUnreachableCounters;
47 type TimeExceededCounters = Icmpv6TimeExceededCounters;
48 type ParameterProblemCounters = Icmpv6ParameterProblemCounters;
49}
50
51#[derive(Default, Debug)]
53#[cfg_attr(
54 any(test, feature = "testutils"),
55 derive(PartialEq, netstack3_macros::CounterCollection)
56)]
57pub struct IcmpTxCounters<I: IcmpCountersIpExt, C: CounterRepr = Counter> {
58 pub reply: C,
60 pub time_exceeded: <I::TimeExceededCounters as CounterCollectionSpec>::CounterCollection<C>,
62 pub packet_too_big: C,
64 pub parameter_problem:
66 <I::ParameterProblemCounters as CounterCollectionSpec>::CounterCollection<C>,
67 pub dest_unreachable:
69 <I::DestUnreachableCounters as CounterCollectionSpec>::CounterCollection<C>,
70 pub error: C,
72}
73
74impl<I: IcmpCountersIpExt> Inspectable for IcmpTxCounters<I> {
75 fn record<II: Inspector>(&self, inspector: &mut II) {
76 let IcmpTxCounters {
77 reply,
78 time_exceeded,
79 packet_too_big,
80 parameter_problem,
81 dest_unreachable,
82 error,
83 } = self;
84 inspector.record_counter("Reply", reply);
85 inspector.record_inspectable("TimeExceeded", time_exceeded);
86 inspector.record_counter("PacketTooBig", packet_too_big);
87 inspector.record_inspectable("ParameterProblem", parameter_problem);
88 inspector.record_inspectable("DestUnreachable", dest_unreachable);
89 inspector.record_counter("Error", error);
90 }
91}
92
93#[derive(Default, Debug)]
95#[cfg_attr(
96 any(test, feature = "testutils"),
97 derive(PartialEq, netstack3_macros::CounterCollection)
98)]
99pub struct IcmpRxCounters<I: IcmpCountersIpExt, C: CounterRepr = Counter> {
100 pub error: C,
102 pub error_delivered_to_transport_layer: C,
104 pub error_delivered_to_socket: C,
106 pub echo_request: C,
108 pub echo_reply: C,
110 pub timestamp_request: C,
112 pub dest_unreachable:
114 <I::DestUnreachableCounters as CounterCollectionSpec>::CounterCollection<C>,
115 pub time_exceeded: <I::TimeExceededCounters as CounterCollectionSpec>::CounterCollection<C>,
117 pub parameter_problem:
119 <I::ParameterProblemCounters as CounterCollectionSpec>::CounterCollection<C>,
120 pub packet_too_big: C,
122 pub queue_full: C,
125}
126
127impl<I: IcmpCountersIpExt> Inspectable for IcmpRxCounters<I> {
128 fn record<II: Inspector>(&self, inspector: &mut II) {
129 let IcmpRxCounters {
130 error,
131 error_delivered_to_transport_layer,
132 error_delivered_to_socket,
133 echo_request,
134 echo_reply,
135 timestamp_request,
136 dest_unreachable,
137 time_exceeded,
138 parameter_problem,
139 packet_too_big,
140 queue_full,
141 } = self;
142 inspector.record_counter("EchoRequest", echo_request);
143 inspector.record_counter("EchoReply", echo_reply);
144 inspector.record_counter("TimestampRequest", timestamp_request);
145 inspector.record_inspectable("DestUnreachable", dest_unreachable);
146 inspector.record_inspectable("TimeExceeded", time_exceeded);
147 inspector.record_inspectable("ParameterProblem", parameter_problem);
148 inspector.record_counter("PacketTooBig", packet_too_big);
149 inspector.record_counter("Error", error);
150 inspector
151 .record_counter("ErrorDeliveredToTransportLayer", error_delivered_to_transport_layer);
152 inspector.record_counter("ErrorDeliveredToSocket", error_delivered_to_socket);
153 inspector.record_counter("DroppedQueueFull", queue_full);
154 }
155}
156
157#[derive(Default, Debug, netstack3_macros::CounterCollection)]
162#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq,))]
163pub struct Icmpv4DestUnreachableCounters<C: CounterRepr = Counter> {
164 pub dest_network_unreachable: C,
166 pub dest_host_unreachable: C,
168 pub dest_protocol_unreachable: C,
170 pub dest_port_unreachable: C,
172 pub fragmentation_required: C,
174 pub source_route_failed: C,
176 pub dest_network_unknown: C,
178 pub dest_host_unknown: C,
180 pub source_host_isolated: C,
182 pub network_administratively_prohibited: C,
184 pub host_administratively_prohibited: C,
186 pub network_unreachable_for_tos: C,
188 pub host_unreachable_for_tos: C,
190 pub comm_administratively_prohibited: C,
192 pub host_precedence_violation: C,
194 pub precedence_cutoff_in_effect: C,
196}
197
198impl Icmpv4DestUnreachableCounters<Counter> {
199 pub(crate) fn increment_code(&self, code: Icmpv4DestUnreachableCode) {
200 use Icmpv4DestUnreachableCode::*;
201 let counter = match code {
202 DestNetworkUnreachable => &self.dest_network_unreachable,
203 DestHostUnreachable => &self.dest_host_unreachable,
204 DestProtocolUnreachable => &self.dest_protocol_unreachable,
205 DestPortUnreachable => &self.dest_port_unreachable,
206 FragmentationRequired => &self.fragmentation_required,
207 SourceRouteFailed => &self.source_route_failed,
208 DestNetworkUnknown => &self.dest_network_unknown,
209 DestHostUnknown => &self.dest_host_unknown,
210 SourceHostIsolated => &self.source_host_isolated,
211 NetworkAdministrativelyProhibited => &self.network_administratively_prohibited,
212 HostAdministrativelyProhibited => &self.host_administratively_prohibited,
213 NetworkUnreachableForToS => &self.network_unreachable_for_tos,
214 HostUnreachableForToS => &self.host_unreachable_for_tos,
215 CommAdministrativelyProhibited => &self.comm_administratively_prohibited,
216 HostPrecedenceViolation => &self.host_precedence_violation,
217 PrecedenceCutoffInEffect => &self.precedence_cutoff_in_effect,
218 };
219 counter.increment()
220 }
221}
222
223impl<C: CounterRepr> Inspectable for Icmpv4DestUnreachableCounters<C> {
224 fn record<I: Inspector>(&self, inspector: &mut I) {
225 let Icmpv4DestUnreachableCounters {
226 dest_network_unreachable,
227 dest_host_unreachable,
228 dest_protocol_unreachable,
229 dest_port_unreachable,
230 fragmentation_required,
231 source_route_failed,
232 dest_network_unknown,
233 dest_host_unknown,
234 source_host_isolated,
235 network_administratively_prohibited,
236 host_administratively_prohibited,
237 network_unreachable_for_tos,
238 host_unreachable_for_tos,
239 comm_administratively_prohibited,
240 host_precedence_violation,
241 precedence_cutoff_in_effect,
242 } = self;
243 inspector.record_counter("DestNetworkUnreachable", dest_network_unreachable);
244 inspector.record_counter("DestHostUnreachable", dest_host_unreachable);
245 inspector.record_counter("DestProtocolUnreachable", dest_protocol_unreachable);
246 inspector.record_counter("DestPortUnreachable", dest_port_unreachable);
247 inspector.record_counter("FragmentationRequired", fragmentation_required);
248 inspector.record_counter("SourceRouteFailed", source_route_failed);
249 inspector.record_counter("DestNetworkUnknown", dest_network_unknown);
250 inspector.record_counter("DestHostUnknown", dest_host_unknown);
251 inspector.record_counter("SourceHostIsolated", source_host_isolated);
252 inspector.record_counter(
253 "NetworkAdministrativelyProhibited",
254 network_administratively_prohibited,
255 );
256 inspector
257 .record_counter("HostAdministrativelyProhibited", host_administratively_prohibited);
258 inspector.record_counter("NetworkUnreachableForTos", network_unreachable_for_tos);
259 inspector.record_counter("HostUnreachableForTos", host_unreachable_for_tos);
260 inspector
261 .record_counter("CommAdministrativelyProhibited", comm_administratively_prohibited);
262 inspector.record_counter("HostPrecedenceViolation", host_precedence_violation);
263 inspector.record_counter("PrecedenceCutoffInEffect", precedence_cutoff_in_effect);
264 }
265}
266
267#[derive(Default, Debug, netstack3_macros::CounterCollection)]
272#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq,))]
273pub struct Icmpv6DestUnreachableCounters<C: CounterRepr = Counter> {
274 pub no_route: C,
276 pub comm_administratively_prohibited: C,
278 pub beyond_scope: C,
280 pub addr_unreachable: C,
282 pub port_unreachable: C,
284 pub src_addr_failed_policy: C,
286 pub reject_route: C,
288}
289
290impl Icmpv6DestUnreachableCounters<Counter> {
291 pub(crate) fn increment_code(&self, code: Icmpv6DestUnreachableCode) {
292 use Icmpv6DestUnreachableCode::*;
293 let counter = match code {
294 NoRoute => &self.no_route,
295 CommAdministrativelyProhibited => &self.comm_administratively_prohibited,
296 BeyondScope => &self.beyond_scope,
297 AddrUnreachable => &self.addr_unreachable,
298 PortUnreachable => &self.port_unreachable,
299 SrcAddrFailedPolicy => &self.src_addr_failed_policy,
300 RejectRoute => &self.reject_route,
301 };
302 counter.increment();
303 }
304}
305
306impl<C: CounterRepr> Inspectable for Icmpv6DestUnreachableCounters<C> {
307 fn record<I: Inspector>(&self, inspector: &mut I) {
308 let Icmpv6DestUnreachableCounters {
309 no_route,
310 comm_administratively_prohibited,
311 beyond_scope,
312 addr_unreachable,
313 port_unreachable,
314 src_addr_failed_policy,
315 reject_route,
316 } = self;
317 inspector.record_counter("NoRoute", no_route);
318 inspector.record_counter(
319 "CommunicationAdministrativelyProhibited",
320 comm_administratively_prohibited,
321 );
322 inspector.record_counter("BeyondScope", beyond_scope);
323 inspector.record_counter("AddrUnreachable", addr_unreachable);
324 inspector.record_counter("PortUnreachable", port_unreachable);
325 inspector.record_counter("SrcAddrFailedPolicy", src_addr_failed_policy);
326 inspector.record_counter("RejectRoute", reject_route);
327 }
328}
329
330#[derive(Default, Debug, netstack3_macros::CounterCollection)]
335#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq,))]
336pub struct Icmpv4TimeExceededCounters<C: CounterRepr = Counter> {
337 pub ttl_expired: C,
339 pub fragment_reassembly_time_exceeded: C,
341}
342
343impl Icmpv4TimeExceededCounters<Counter> {
344 pub(crate) fn increment_code(&self, code: Icmpv4TimeExceededCode) {
345 use Icmpv4TimeExceededCode::*;
346 let counter = match code {
347 TtlExpired => &self.ttl_expired,
348 FragmentReassemblyTimeExceeded => &self.fragment_reassembly_time_exceeded,
349 };
350 counter.increment();
351 }
352}
353
354impl<C: CounterRepr> Inspectable for Icmpv4TimeExceededCounters<C> {
355 fn record<I: Inspector>(&self, inspector: &mut I) {
356 let Icmpv4TimeExceededCounters { ttl_expired, fragment_reassembly_time_exceeded } = self;
357 inspector.record_counter("TtlExpired", ttl_expired);
358 inspector
359 .record_counter("FragmentReassemblyTimeExceeded", fragment_reassembly_time_exceeded);
360 }
361}
362
363#[derive(Default, Debug, netstack3_macros::CounterCollection)]
368#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq,))]
369pub struct Icmpv6TimeExceededCounters<C: CounterRepr = Counter> {
370 pub hop_limit_exceeded: C,
372 pub fragment_reassembly_time_exceeded: C,
374}
375
376impl Icmpv6TimeExceededCounters<Counter> {
377 pub(crate) fn increment_code(&self, code: Icmpv6TimeExceededCode) {
378 use Icmpv6TimeExceededCode::*;
379 let counter = match code {
380 HopLimitExceeded => &self.hop_limit_exceeded,
381 FragmentReassemblyTimeExceeded => &self.fragment_reassembly_time_exceeded,
382 };
383 counter.increment();
384 }
385}
386
387impl<C: CounterRepr> Inspectable for Icmpv6TimeExceededCounters<C> {
388 fn record<I: Inspector>(&self, inspector: &mut I) {
389 let Icmpv6TimeExceededCounters { hop_limit_exceeded, fragment_reassembly_time_exceeded } =
390 self;
391 inspector.record_counter("HopLimitExceeded", hop_limit_exceeded);
392 inspector
393 .record_counter("FragmentReassemblyTimeExceeded", fragment_reassembly_time_exceeded);
394 }
395}
396
397#[derive(Default, Debug, netstack3_macros::CounterCollection)]
402#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq,))]
403pub struct Icmpv4ParameterProblemCounters<C: CounterRepr = Counter> {
404 pub pointer_indicates_error: C,
406 pub missing_required_option: C,
408 pub bad_length: C,
410}
411
412impl Icmpv4ParameterProblemCounters<Counter> {
413 pub(crate) fn increment_code(&self, code: Icmpv4ParameterProblemCode) {
414 use Icmpv4ParameterProblemCode::*;
415 let counter = match code {
416 PointerIndicatesError => &self.pointer_indicates_error,
417 MissingRequiredOption => &self.missing_required_option,
418 BadLength => &self.bad_length,
419 };
420 counter.increment()
421 }
422}
423
424impl<C: CounterRepr> Inspectable for Icmpv4ParameterProblemCounters<C> {
425 fn record<I: Inspector>(&self, inspector: &mut I) {
426 let Icmpv4ParameterProblemCounters {
427 pointer_indicates_error,
428 missing_required_option,
429 bad_length,
430 } = self;
431 inspector.record_counter("PointerIndicatesError", pointer_indicates_error);
432 inspector.record_counter("MissingRequiredOption", missing_required_option);
433 inspector.record_counter("BadLength", bad_length);
434 }
435}
436
437#[derive(Default, Debug, netstack3_macros::CounterCollection)]
442#[cfg_attr(any(test, feature = "testutils"), derive(PartialEq,))]
443pub struct Icmpv6ParameterProblemCounters<C: CounterRepr = Counter> {
444 pub erroneous_header_field: C,
446 pub unrecognized_next_header_type: C,
448 pub unrecognized_ipv6_option: C,
450}
451
452impl Icmpv6ParameterProblemCounters<Counter> {
453 pub(crate) fn increment_code(&self, code: Icmpv6ParameterProblemCode) {
454 use Icmpv6ParameterProblemCode::*;
455 let counter = match code {
456 ErroneousHeaderField => &self.erroneous_header_field,
457 UnrecognizedNextHeaderType => &self.unrecognized_next_header_type,
458 UnrecognizedIpv6Option => &self.unrecognized_ipv6_option,
459 };
460 counter.increment()
461 }
462}
463
464impl<C: CounterRepr> Inspectable for Icmpv6ParameterProblemCounters<C> {
465 fn record<I: Inspector>(&self, inspector: &mut I) {
466 let Icmpv6ParameterProblemCounters {
467 erroneous_header_field,
468 unrecognized_next_header_type,
469 unrecognized_ipv6_option,
470 } = self;
471 inspector.record_counter("ErroneousHeaderField", erroneous_header_field);
472 inspector.record_counter("UnrecognizedNextHeaderType", unrecognized_next_header_type);
473 inspector.record_counter("UnrecognizedIpv6Option", unrecognized_ipv6_option);
474 }
475}