netstack3_tcp/
counters.rs

1// Copyright 2025 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//! Facilities for tracking the counts of various TCP events.
6
7use net_types::ip::IpMarked;
8use netstack3_base::{Counter, Inspectable, Inspector, InspectorExt as _};
9
10/// TCP Counters.
11///
12/// Accrued for the entire stack, rather than on a per connection basis.
13///
14/// Note that for dual stack sockets, all events will be attributed to the IPv6
15/// counters.
16pub type TcpCounters<I> = IpMarked<I, TcpCountersInner>;
17
18/// The IP agnostic version of [`TcpCounters`].
19#[derive(Default)]
20// TODO(https://fxbug.dev/42052878): Add counters for SYN cookies.
21// TODO(https://fxbug.dev/42078221): Add counters for SACK.
22pub struct TcpCountersInner {
23    /// Count of received IP packets that were dropped because they had
24    /// unexpected IP addresses (either src or dst).
25    pub invalid_ip_addrs_received: Counter,
26    /// Count of received TCP segments that were dropped because they could not
27    /// be parsed.
28    pub invalid_segments_received: Counter,
29    /// Count of received TCP segments that were valid.
30    pub valid_segments_received: Counter,
31    /// Count of received TCP segments that were successfully dispatched to a
32    /// socket.
33    pub received_segments_dispatched: Counter,
34    /// Count of received TCP segments that were not associated with any
35    /// existing sockets.
36    pub received_segments_no_dispatch: Counter,
37    /// Count of received TCP segments that were dropped because the listener
38    /// queue was full.
39    pub listener_queue_overflow: Counter,
40    /// Count of TCP segments that failed to send.
41    pub segment_send_errors: Counter,
42    /// Count of TCP segments that were sent.
43    pub segments_sent: Counter,
44    /// Count of passive open attempts that failed because the stack doesn't
45    /// have route to the peer.
46    pub passive_open_no_route_errors: Counter,
47    /// Count of passive connections that have been opened.
48    pub passive_connection_openings: Counter,
49    /// Count of active open attempts that have failed because the stack doesn't
50    /// have a route to the peer.
51    pub active_open_no_route_errors: Counter,
52    /// Count of active connections that have been opened.
53    pub active_connection_openings: Counter,
54    /// Count of all failed connection attempts, including both passive and
55    /// active opens.
56    pub failed_connection_attempts: Counter,
57    /// Count of port reservation attempts that failed.
58    pub failed_port_reservations: Counter,
59    /// Count of received segments whose checksums were invalid.
60    pub checksum_errors: Counter,
61    /// Count of received segments with the RST flag set.
62    pub resets_received: Counter,
63    /// Count of sent segments with the RST flag set.
64    pub resets_sent: Counter,
65    /// Count of received segments with the SYN flag set.
66    pub syns_received: Counter,
67    /// Count of sent segments with the SYN flag set.
68    pub syns_sent: Counter,
69    /// Count of received segments with the FIN flag set.
70    pub fins_received: Counter,
71    /// Count of sent segments with the FIN flag set.
72    pub fins_sent: Counter,
73    /// Count of retransmission timeouts.
74    pub timeouts: Counter,
75    /// Count of retransmissions of segments.
76    pub retransmits: Counter,
77    /// Count of retransmissions of segments while in slow start.
78    pub slow_start_retransmits: Counter,
79    /// Count of retransmissions of segments while in fast recovery.
80    pub fast_retransmits: Counter,
81    /// Count of times fast recovery was initiated to recover from packet loss.
82    pub fast_recovery: Counter,
83    /// Count of times an established TCP connection transitioned to CLOSED.
84    pub established_closed: Counter,
85    /// Count of times an established TCP connection transitioned to CLOSED due
86    /// to a RST segment.
87    pub established_resets: Counter,
88    /// Count of times an established TCP connection transitioned to CLOSED due
89    /// to a timeout (e.g. a keep-alive or retransmit timeout).
90    pub established_timedout: Counter,
91}
92
93impl Inspectable for TcpCountersInner {
94    fn record<I: Inspector>(&self, inspector: &mut I) {
95        let TcpCountersInner {
96            invalid_ip_addrs_received,
97            invalid_segments_received,
98            valid_segments_received,
99            received_segments_dispatched,
100            received_segments_no_dispatch,
101            listener_queue_overflow,
102            segment_send_errors,
103            segments_sent,
104            passive_open_no_route_errors,
105            passive_connection_openings,
106            active_open_no_route_errors,
107            active_connection_openings,
108            failed_connection_attempts,
109            failed_port_reservations,
110            checksum_errors,
111            resets_received,
112            resets_sent,
113            syns_received,
114            syns_sent,
115            fins_received,
116            fins_sent,
117            timeouts,
118            retransmits,
119            slow_start_retransmits,
120            fast_retransmits,
121            fast_recovery,
122            established_closed,
123            established_resets,
124            established_timedout,
125        } = self;
126        inspector.record_child("Rx", |inspector| {
127            inspector.record_counter("ValidSegmentsReceived", valid_segments_received);
128            inspector.record_counter("ReceivedSegmentsDispatched", received_segments_dispatched);
129            inspector.record_counter("ResetsReceived", resets_received);
130            inspector.record_counter("SynsReceived", syns_received);
131            inspector.record_counter("FinsReceived", fins_received);
132            inspector.record_child("Errors", |inspector| {
133                inspector.record_counter("InvalidIpAddrsReceived", invalid_ip_addrs_received);
134                inspector.record_counter("InvalidSegmentsReceived", invalid_segments_received);
135                inspector
136                    .record_counter("ReceivedSegmentsNoDispatch", received_segments_no_dispatch);
137                inspector.record_counter("ListenerQueueOverflow", listener_queue_overflow);
138                inspector.record_counter("PassiveOpenNoRouteErrors", passive_open_no_route_errors);
139                inspector.record_counter("ChecksumErrors", checksum_errors);
140            })
141        });
142        inspector.record_child("Tx", |inspector| {
143            inspector.record_counter("SegmentsSent", segments_sent);
144            inspector.record_counter("ResetsSent", resets_sent);
145            inspector.record_counter("SynsSent", syns_sent);
146            inspector.record_counter("FinsSent", fins_sent);
147            inspector.record_counter("Timeouts", timeouts);
148            inspector.record_counter("Retransmits", retransmits);
149            inspector.record_counter("SlowStartRetransmits", slow_start_retransmits);
150            inspector.record_counter("FastRetransmits", fast_retransmits);
151            inspector.record_child("Errors", |inspector| {
152                inspector.record_counter("SegmentSendErrors", segment_send_errors);
153                inspector.record_counter("ActiveOpenNoRouteErrors", active_open_no_route_errors);
154            });
155        });
156        inspector.record_counter("PassiveConnectionOpenings", passive_connection_openings);
157        inspector.record_counter("ActiveConnectionOpenings", active_connection_openings);
158        inspector.record_counter("FastRecovery", fast_recovery);
159        inspector.record_counter("EstablishedClosed", established_closed);
160        inspector.record_counter("EstablishedResets", established_resets);
161        inspector.record_counter("EstablishedTimedout", established_timedout);
162        inspector.record_child("Errors", |inspector| {
163            inspector.record_counter("FailedConnectionOpenings", failed_connection_attempts);
164            inspector.record_counter("FailedPortReservations", failed_port_reservations);
165        })
166    }
167}