netlink_packet_sock_diag/inet/
nlas.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use byteorder::{ByteOrder, NativeEndian};
5
6use netlink_packet_utils::nla::{self, DefaultNla, NlaBuffer};
7use netlink_packet_utils::parsers::{parse_string, parse_u8, parse_u32};
8use netlink_packet_utils::traits::{Emitable, Parseable};
9use netlink_packet_utils::{DecodeError, buffer};
10
11use crate::constants::*;
12
13pub const LEGACY_MEM_INFO_LEN: usize = 16;
14
15buffer!(LegacyMemInfoBuffer(LEGACY_MEM_INFO_LEN) {
16    receive_queue: (u32, 0..4),
17    bottom_send_queue: (u32, 4..8),
18    cache: (u32, 8..12),
19    send_queue: (u32, 12..16)
20});
21
22/// In recent Linux kernels, this NLA is not used anymore to report
23/// AF_INET and AF_INET6 sockets memory information. See [`MemInfo`]
24/// instead.
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct LegacyMemInfo {
27    /// Amount of data in the receive queue.
28    pub receive_queue: u32,
29    /// Amount of data that is queued by TCP but not yet sent.
30    pub bottom_send_queue: u32,
31    /// Amount of memory scheduled for future use (TCP only).
32    pub cache: u32,
33    /// Amount of data in the send queue.
34    pub send_queue: u32,
35}
36
37impl<T: AsRef<[u8]>> Parseable<LegacyMemInfoBuffer<T>> for LegacyMemInfo {
38    type Error = DecodeError;
39    fn parse(buf: &LegacyMemInfoBuffer<T>) -> Result<Self, DecodeError> {
40        Ok(Self {
41            receive_queue: buf.receive_queue(),
42            bottom_send_queue: buf.bottom_send_queue(),
43            cache: buf.cache(),
44            send_queue: buf.send_queue(),
45        })
46    }
47}
48
49impl Emitable for LegacyMemInfo {
50    fn buffer_len(&self) -> usize {
51        LEGACY_MEM_INFO_LEN
52    }
53
54    fn emit(&self, buf: &mut [u8]) {
55        let mut buf = LegacyMemInfoBuffer::new_unchecked(buf);
56        buf.set_receive_queue(self.receive_queue);
57        buf.set_bottom_send_queue(self.bottom_send_queue);
58        buf.set_cache(self.cache);
59        buf.set_send_queue(self.send_queue);
60    }
61}
62
63pub const MEM_INFO_LEN: usize = 36;
64
65// FIXME: the last 2 fields are not present on old linux kernels. We
66// should support optional fields in the `buffer!` macro.
67buffer!(MemInfoBuffer(MEM_INFO_LEN) {
68    receive_queue: (u32, 0..4),
69    receive_queue_max: (u32, 4..8),
70    bottom_send_queues: (u32, 8..12),
71    send_queue_max: (u32, 12..16),
72    cache: (u32, 16..20),
73    send_queue: (u32, 20..24),
74    options: (u32, 24..28),
75    backlog_queue_length: (u32, 28..32),
76    drops: (u32, 32..36),
77});
78
79/// Socket memory information. To understand this information, one
80/// must understand how the memory allocated for the send and receive
81/// queues of a socket is managed.
82///
83/// # Warning
84///
85/// This data structure is not well documented. The explanations given
86/// here are the results of my personal research on this topic, but I
87/// am by no mean an expert in Linux networking, so take this
88/// documentation with a huge grain of salt. Please report any error
89/// you may notice. Here are the references I used:
90///
91/// - [https://wiki.linuxfoundation.org/networking/sk_buff](a short introduction
92///   to `sk_buff`, the struct used in the kernel to store packets)
93/// - [vger.kernel.org has a lot of documentation about the low level network stack APIs](http://vger.kernel.org/~davem/skb_data.html)
94/// - [thorough high level explanation of buffering in the network stack](https://www.coverfire.com/articles/queueing-in-the-linux-network-stack/)
95/// - [understanding the backlog queue](http://veithen.io/2014/01/01/how-tcp-backlog-works-in-linux.html)
96/// - [high level explanation of packet reception](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/s-network-packet-reception)
97/// - [a StackExchange question about the different send queues used by a socket](https://unix.stackexchange.com/questions/551444/what-is-the-difference-between-sock-sk-wmem-alloc-and-sock-sk-wmem-queued)
98/// - other useful resources: [here](https://www.cl.cam.ac.uk/~pes20/Netsem/linuxnet.pdf)
99///   and [here](https://people.cs.clemson.edu/~westall/853/notes/skbuff.pdf)
100/// - [explanation of the socket backlog queue](https://medium.com/@c0ngwang/the-design-of-lock-sock-in-linux-kernel-69c3406e504b)
101///
102/// # Linux networking in a nutshell
103///
104/// The network stack uses multiple queues, both for sending an
105/// receiving data. Let's start with the simplest case: packet
106/// receptions.
107///
108/// When data is received, it is first handled by the device driver
109/// and put in the device driver queue. The kernel then move the
110/// packet to the socket receive queue (also called _receive
111/// buffer_). Finally, this application reads it (with `recv`, `read`
112/// or `recvfrom`) and the packet is dequeued.
113///
114/// Sending packet it slightly more complicated and the exact workflow
115/// may differ from one protocol to the other so we'll just give a
116/// high level overview. When an application sends data, a packet is
117/// created and stored in the socket send queue (also called _send
118/// buffer_). It is then passed down to the QDisc (Queuing
119/// Disciplines) queue. The QDisc facility enables quality of service:
120/// if some data is more urgent to transmit than other, QDisc will
121/// make sure it is sent in priority. Finally, the data is put on the
122/// device driver queue to be sent out.
123#[derive(Debug, PartialEq, Eq, Clone)]
124pub struct MemInfo {
125    /// Memory currently allocated for the socket's receive
126    /// queue. This attribute is known as `sk_rmem_alloc` in the
127    /// kernel.
128    pub receive_queue: u32,
129    /// Maximum amount of memory that can be allocated for the
130    /// socket's receive queue. This is set by `SO_RCVBUF`. This is
131    /// _not_ the amount of memory currently allocated. This attribute
132    /// is known as `sk_rcvbuf` in the kernel.
133    pub receive_queue_max: u32,
134    /// Memory currently allocated for the socket send queue. This
135    /// attribute is known as `sk_wmem_queued` in the kernel. This
136    /// does does not account for data that have been passed down the
137    /// network stack (i.e. to the QDisc and device driver queues),
138    /// which is reported by the `bottow_send_queue` (known as
139    /// `sk_wmem_alloc` in the kernel).
140    ///
141    /// For a TCP socket, if the congestion window is small, the
142    /// kernel will move the data fron the socket send queue to the
143    /// QDisc queues more slowly. Thus, if the process sends of lot of
144    /// data, the socket send queue (which memory is tracked by
145    /// `sk_wmem_queued`) will grow while `sk_wmem_alloc` will remain
146    /// small.
147    pub send_queue: u32,
148    /// Maximum amount of memory (in bytes) that can be allocated for
149    /// this socket's send queue. This is set by `SO_SNDBUF`. This is
150    /// _not_ the amount of memory currently allocated. This attribute
151    /// is known as `sk_sndbuf` in the kernel.
152    pub send_queue_max: u32,
153    /// Memory used for packets that have been passed down the network
154    /// stack, i.e. that are either in the QDisc or device driver
155    /// queues. This attribute is known as `sk_wmem_alloc` in the
156    /// kernel. See also [`send_queue`].
157    pub bottom_send_queues: u32,
158    /// The amount of memory already allocated for this socket but
159    /// currently unused. When more memory is needed either for
160    /// sending or for receiving data, it will be taken from this
161    /// pool. This attribute is known as `sk_fwd_alloc` in the kernel.
162    pub cache: u32,
163    /// The amount of memory allocated for storing socket options, for
164    /// instance the key for TCP MD5 signature. This attribute is
165    /// known as `sk_optmem` in the kernel.
166    pub options: u32,
167    /// The length of the backlog queue. When the process is using the
168    /// socket, the socket is locked so the kernel cannot enqueue new
169    /// packets in the receive queue. To avoid blocking the bottom
170    /// half of network stack waiting for the process to release the
171    /// socket, the packets are enqueued in the backlog queue. Upon
172    /// releasing the socket, those packets are processed and put in
173    /// the regular receive queue.
174    // FIXME: this should be an Option because it's not present on old
175    // linux kernels.
176    pub backlog_queue_length: u32,
177    /// The amount of packets dropped. Depending on the kernel
178    /// version, this field may not be present.
179    // FIXME: this should be an Option because it's not present on old
180    // linux kernels.
181    pub drops: u32,
182}
183
184impl<T: AsRef<[u8]>> Parseable<MemInfoBuffer<T>> for MemInfo {
185    type Error = DecodeError;
186    fn parse(buf: &MemInfoBuffer<T>) -> Result<Self, DecodeError> {
187        Ok(Self {
188            receive_queue: buf.receive_queue(),
189            receive_queue_max: buf.receive_queue_max(),
190            bottom_send_queues: buf.bottom_send_queues(),
191            send_queue_max: buf.send_queue_max(),
192            cache: buf.cache(),
193            send_queue: buf.send_queue(),
194            options: buf.options(),
195            backlog_queue_length: buf.backlog_queue_length(),
196            drops: buf.drops(),
197        })
198    }
199}
200
201impl Emitable for MemInfo {
202    fn buffer_len(&self) -> usize {
203        MEM_INFO_LEN
204    }
205
206    fn emit(&self, buf: &mut [u8]) {
207        let mut buf = MemInfoBuffer::new_unchecked(buf);
208        buf.set_receive_queue(self.receive_queue);
209        buf.set_receive_queue_max(self.receive_queue_max);
210        buf.set_bottom_send_queues(self.bottom_send_queues);
211        buf.set_send_queue_max(self.send_queue_max);
212        buf.set_cache(self.cache);
213        buf.set_send_queue(self.send_queue);
214        buf.set_options(self.options);
215        buf.set_backlog_queue_length(self.backlog_queue_length);
216        buf.set_drops(self.drops);
217    }
218}
219
220#[derive(Debug, PartialEq, Eq, Clone)]
221pub enum Nla {
222    /// The memory information of the socket. This attribute is
223    /// similar to `Nla::MemInfo` but provides less information. On
224    /// recent kernels, `Nla::MemInfo` is used instead.
225    // ref: https://patchwork.ozlabs.org/patch/154816/
226    LegacyMemInfo(LegacyMemInfo),
227    /// the TCP information
228    TcpInfo(TcpInfo),
229    /// the congestion control algorithm used
230    Congestion(String),
231    /// the TOS of the socket.
232    Tos(u8),
233    /// the traffic class of the socket.
234    Tc(u8),
235    /// The memory information of the socket
236    MemInfo(MemInfo),
237    /// Shutown state: one of [`SHUT_RD`], [`SHUT_WR`] or [`SHUT_RDWR`]
238    Shutdown(u8),
239    /// The protocol
240    Protocol(u8),
241    /// Whether the socket is IPv6 only
242    SkV6Only(bool),
243    /// The mark of the socket.
244    Mark(u32),
245    /// The class ID of the socket.
246    ClassId(u32),
247    /// other attribute
248    Other(DefaultNla),
249}
250
251impl nla::Nla for Nla {
252    fn value_len(&self) -> usize {
253        use self::Nla::*;
254        match *self {
255            LegacyMemInfo(_) => LEGACY_MEM_INFO_LEN,
256            TcpInfo(_) => TCP_INFO_LEN,
257            // +1 because we need to append a null byte
258            Congestion(ref s) => s.as_bytes().len() + 1,
259            Tos(_) | Tc(_) | Shutdown(_) | Protocol(_) | SkV6Only(_) => 1,
260            MemInfo(_) => MEM_INFO_LEN,
261            Mark(_) | ClassId(_) => 4,
262            Other(ref attr) => attr.value_len(),
263        }
264    }
265
266    fn kind(&self) -> u16 {
267        use self::Nla::*;
268        match *self {
269            LegacyMemInfo(_) => INET_DIAG_MEMINFO,
270            TcpInfo(_) => INET_DIAG_INFO,
271            Congestion(_) => INET_DIAG_CONG,
272            Tos(_) => INET_DIAG_TOS,
273            Tc(_) => INET_DIAG_TCLASS,
274            MemInfo(_) => INET_DIAG_SKMEMINFO,
275            Shutdown(_) => INET_DIAG_SHUTDOWN,
276            Protocol(_) => INET_DIAG_PROTOCOL,
277            SkV6Only(_) => INET_DIAG_SKV6ONLY,
278            Mark(_) => INET_DIAG_MARK,
279            ClassId(_) => INET_DIAG_CLASS_ID,
280            Other(ref attr) => attr.kind(),
281        }
282    }
283
284    fn emit_value(&self, buffer: &mut [u8]) {
285        use self::Nla::*;
286        match *self {
287            LegacyMemInfo(ref value) => value.emit(buffer),
288            TcpInfo(ref value) => value.emit(buffer),
289            Congestion(ref s) => {
290                buffer[..s.len()].copy_from_slice(s.as_bytes());
291                buffer[s.len()] = 0;
292            }
293            Tos(b) | Tc(b) | Shutdown(b) | Protocol(b) => buffer[0] = b,
294            SkV6Only(value) => buffer[0] = value.into(),
295            MemInfo(ref value) => value.emit(buffer),
296            Mark(value) | ClassId(value) => NativeEndian::write_u32(buffer, value),
297            Other(ref attr) => attr.emit_value(buffer),
298        }
299    }
300}
301
302impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {
303    type Error = DecodeError;
304    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
305        let payload = buf.value();
306        Ok(match buf.kind() {
307            INET_DIAG_MEMINFO => {
308                let err = "invalid INET_DIAG_MEMINFO value";
309                let buf = LegacyMemInfoBuffer::new(payload).context(err)?;
310                Self::LegacyMemInfo(LegacyMemInfo::parse(&buf).context(err)?)
311            }
312            INET_DIAG_INFO => {
313                let err = "invalid INET_DIAG_INFO value";
314                let buf = TcpInfoBuffer::new(payload).context(err)?;
315                Self::TcpInfo(TcpInfo::parse(&buf).context(err)?)
316            }
317            INET_DIAG_CONG => {
318                Self::Congestion(parse_string(payload).context("invalid INET_DIAG_CONG value")?)
319            }
320            INET_DIAG_TOS => Self::Tos(parse_u8(payload).context("invalid INET_DIAG_TOS value")?),
321            INET_DIAG_TCLASS => {
322                Self::Tc(parse_u8(payload).context("invalid INET_DIAG_TCLASS value")?)
323            }
324            INET_DIAG_SKMEMINFO => {
325                let err = "invalid INET_DIAG_SKMEMINFO value";
326                let buf = MemInfoBuffer::new(payload).context(err)?;
327                Self::MemInfo(MemInfo::parse(&buf).context(err)?)
328            }
329            INET_DIAG_SHUTDOWN => {
330                Self::Shutdown(parse_u8(payload).context("invalid INET_DIAG_SHUTDOWN value")?)
331            }
332            INET_DIAG_PROTOCOL => {
333                Self::Protocol(parse_u8(payload).context("invalid INET_DIAG_PROTOCOL value")?)
334            }
335            INET_DIAG_SKV6ONLY => {
336                Self::SkV6Only(parse_u8(payload).context("invalid INET_DIAG_SKV6ONLY value")? != 0)
337            }
338            INET_DIAG_MARK => {
339                Self::Mark(parse_u32(payload).context("invalid INET_DIAG_MARK value")?)
340            }
341            INET_DIAG_CLASS_ID => {
342                Self::ClassId(parse_u32(payload).context("invalid INET_DIAG_CLASS_ID value")?)
343            }
344            kind => {
345                Self::Other(DefaultNla::parse(buf).context(format!("unknown NLA type {kind}"))?)
346            }
347        })
348    }
349}
350
351pub const TCP_INFO_LEN: usize = 232;
352
353buffer!(TcpInfoBuffer(TCP_INFO_LEN) {
354    // State of the TCP connection. This should be set to one of the
355    // `TCP_*` constants: `TCP_ESTABLISHED`, `TCP_SYN_SENT`, etc. This
356    // attribute is known as `tcpi_state` in the kernel.
357    state: (u8, 0),
358    // State of congestion avoidance. Sender's congestion state
359    // indicating normal or abnormal situations in the last round of
360    // packets sent. The state is driven by the ACK information and
361    // timer events. This should be set to one of the `TCP_CA_*`
362    // constants. This attribute is known as `tcpi_ca_state` in the
363    // kernel.
364    congestion_avoidance_state: (u8, 1),
365    // Number of retranmissions on timeout invoked. This attribute is
366    // known as `tcpi_retransmits` in the kernel.
367    retransmits: (u8, 2),
368    // Number of window or keep alive probes sent. This attribute is
369    // known as `tcpi_probes`.
370    probes: (u8, 3),
371    // Number of times the retransmission backoff timer invoked
372    backoff: (u8, 4),
373    options: (u8, 5),
374    wscale: (u8, 6),
375    delivery_rate_app_limited: (u8, 7),
376
377    rto: (u32, 8..12),
378    ato: (u32, 12..16),
379    snd_mss: (u32, 16..20),
380    rcv_mss: (u32, 20..24),
381
382    unacked: (u32, 24..28),
383    sacked: (u32, 28..32),
384    lost: (u32, 32..36),
385    retrans: (u32, 36..40),
386    fackets: (u32, 40..44),
387
388    // Times
389    last_data_sent: (u32, 44..48),
390    last_ack_sent: (u32, 48..52),
391    last_data_recv: (u32, 52..56),
392    last_ack_recv: (u32, 56..60),
393
394    // Metrics
395    pmtu: (u32, 60..64),
396    rcv_ssthresh: (u32, 64..68),
397    rtt: (u32, 68..72),
398    rttvar: (u32, 72..76),
399    snd_ssthresh: (u32, 76..80),
400    snd_cwnd: (u32, 80..84),
401    advmss: (u32, 84..88),
402    reordering: (u32, 88..92),
403
404    rcv_rtt: (u32, 92..96),
405    rcv_space: (u32, 96..100),
406
407    total_retrans: (u32, 100..104),
408
409    pacing_rate: (u64, 104..112),
410    max_pacing_rate: (u64, 112..120),
411    bytes_acked: (u64, 120..128),       // RFC4898 tcpEStatsAppHCThruOctetsAcked
412    bytes_received: (u64, 128..136),    // RFC4898 tcpEStatsAppHCThruOctetsReceived
413    segs_out: (u32, 136..140),          // RFC4898 tcpEStatsPerfSegsOut
414    segs_in: (u32, 140..144),           // RFC4898 tcpEStatsPerfSegsIn
415
416    notsent_bytes: (u32, 144..148),
417    min_rtt: (u32, 148..152),
418    data_segs_in: (u32, 152..156),      // RFC4898 tcpEStatsDataSegsIn
419    data_segs_out: (u32, 156..160),     // RFC4898 tcpEStatsDataSegsOut
420
421    delivery_rate: (u64, 160..168),
422
423    busy_time: (u64, 168..176),         // Time (usec) busy sending data
424    rwnd_limited: (u64, 176..184),      // Time (usec) limited by receive window
425    sndbuf_limited: (u64, 184..192),    // Time (usec) limited by send buffer
426
427    delivered: (u32, 192..196),
428    delivered_ce: (u32, 196..200),
429
430    bytes_sent: (u64, 200..208),       // RFC4898 tcpEStatsPerfHCDataOctetsOut
431    bytes_retrans: (u64, 208..216),    // RFC4898 tcpEStatsPerfOctetsRetrans
432    dsack_dups: (u32,   216..220),     // RFC4898 tcpEStatsStackDSACKDups
433    reord_seen: (u32,   220..224),     // reordering events seen
434    rcv_ooopack: (u32, 224..228),      // Out-of-order packets received
435    snd_wnd: (u32, 228..232),          // peer's advertised receive window after scaling (bytes)
436});
437
438// https://unix.stackexchange.com/questions/542712/detailed-output-of-ss-command
439
440#[derive(Debug, Clone, PartialEq, Eq)]
441pub struct TcpInfo {
442    /// State of the TCP connection: one of `TCP_ESTABLISHED`,
443    /// `TCP_SYN_SENT`, `TP_SYN_RECV`, `TCP_FIN_WAIT1`,
444    /// `TCP_FIN_WAIT2` `TCP_TIME_WAIT`, `TCP_CLOSE`,
445    /// `TCP_CLOSE_WAIT`, `TCP_LAST_ACK` `TCP_LISTEN`, `TCP_CLOSING`.
446    pub state: u8,
447    /// Congestion algorithm state: one of `TCP_CA_OPEN`,
448    /// `TCP_CA_DISORDER`, `TCP_CA_CWR`, `TCP_CA_RECOVERY`,
449    /// `TCP_CA_LOSS`
450    pub ca_state: u8,
451    ///
452    pub retransmits: u8,
453    pub probes: u8,
454    pub backoff: u8,
455    pub options: u8,
456    // First 4 bits are snd_wscale, last 4 bits rcv_wscale
457    pub wscale: u8,
458    /// A boolean indicating if the goodput was measured when the
459    /// socket's throughput was limited by the sending application.
460    /// tcpi_delivery_rate_app_limited:1, tcpi_fastopen_client_fail:2
461    pub delivery_rate_app_limited: u8,
462
463    /// Value of the RTO (Retransmission TimeOut) timer. This value is
464    /// calculated using the RTT.
465    pub rto: u32,
466    /// Value of the ATO (ACK TimeOut) timer.
467    pub ato: u32,
468    /// MSS (Maximum Segment Size). Not shure how it differs from
469    /// `advmss`.
470    pub snd_mss: u32,
471    /// MSS (Maximum Segment Size) advertised by peer
472    pub rcv_mss: u32,
473
474    /// Number of segments that have not been ACKnowledged yet, ie the
475    /// number of in-flight segments.
476    pub unacked: u32,
477    /// Number of segments that have been SACKed
478    pub sacked: u32,
479    /// Number of segments that have been lost
480    pub lost: u32,
481    /// Number of segments that have been retransmitted
482    pub retrans: u32,
483    /// Number of segments that have been FACKed
484    pub fackets: u32,
485
486    pub last_data_sent: u32,
487    pub last_ack_sent: u32,
488    pub last_data_recv: u32,
489    pub last_ack_recv: u32,
490
491    pub pmtu: u32,
492    pub rcv_ssthresh: u32,
493    /// RTT (Round Trip Time). There RTT is the time between the
494    /// moment a segment is sent out and the moment it is
495    /// acknowledged. There are different kinds of RTT values, and I
496    /// don't know which one this value corresponds to: mRTT (measured
497    /// RTT), sRTT (smoothed RTT), RTTd (deviated RTT), etc.
498    pub rtt: u32,
499    /// RTT variance (or variation?)
500    pub rttvar: u32,
501    /// Slow-Start Threshold
502    pub snd_ssthresh: u32,
503    /// Size of the congestion window
504    pub snd_cwnd: u32,
505    /// MSS advertised by this peer
506    pub advmss: u32,
507
508    pub reordering: u32,
509
510    pub rcv_rtt: u32,
511    pub rcv_space: u32,
512
513    pub total_retrans: u32,
514
515    pub pacing_rate: u64,
516    pub max_pacing_rate: u64,
517    pub bytes_acked: u64,    // RFC4898 tcpEStatsAppHCThruOctetsAcked
518    pub bytes_received: u64, // RFC4898 tcpEStatsAppHCThruOctetsReceived
519    pub segs_out: u32,       // RFC4898 tcpEStatsPerfSegsOut
520    pub segs_in: u32,        // RFC4898 tcpEStatsPerfSegsIn
521
522    pub notsent_bytes: u32,
523    pub min_rtt: u32,
524    pub data_segs_in: u32,  // RFC4898 tcpEStatsDataSegsIn
525    pub data_segs_out: u32, // RFC4898 tcpEStatsDataSegsOut
526
527    /// The most recent goodput, as measured by tcp_rate_gen(). If the
528    /// socket is limited by the sending application (e.g., no data to
529    /// send), it reports the highest measurement instead of the most
530    /// recent. The unit is bytes per second (like other rate fields
531    /// in tcp_info).
532    pub delivery_rate: u64,
533
534    pub busy_time: u64,      // Time (usec) busy sending data
535    pub rwnd_limited: u64,   // Time (usec) limited by receive window
536    pub sndbuf_limited: u64, // Time (usec) limited by send buffer
537
538    pub delivered: u32,
539    pub delivered_ce: u32,
540
541    pub bytes_sent: u64,    // RFC4898 tcpEStatsPerfHCDataOctetsOut
542    pub bytes_retrans: u64, // RFC4898 tcpEStatsPerfOctetsRetrans
543    pub dsack_dups: u32,    // RFC4898 tcpEStatsStackDSACKDups
544    /// reordering events seen
545    pub reord_seen: u32,
546
547    /// Out-of-order packets received
548    pub rcv_ooopack: u32,
549    /// peer's advertised receive window after scaling (bytes)
550    pub snd_wnd: u32,
551}
552
553impl<T: AsRef<[u8]>> Parseable<TcpInfoBuffer<T>> for TcpInfo {
554    type Error = DecodeError;
555    fn parse(buf: &TcpInfoBuffer<T>) -> Result<Self, DecodeError> {
556        Ok(Self {
557            state: buf.state(),
558            ca_state: buf.congestion_avoidance_state(),
559            retransmits: buf.retransmits(),
560            probes: buf.probes(),
561            backoff: buf.backoff(),
562            options: buf.options(),
563            wscale: buf.wscale(),
564            delivery_rate_app_limited: buf.delivery_rate_app_limited(),
565            rto: buf.rto(),
566            ato: buf.ato(),
567            snd_mss: buf.snd_mss(),
568            rcv_mss: buf.rcv_mss(),
569            unacked: buf.unacked(),
570            sacked: buf.sacked(),
571            lost: buf.lost(),
572            retrans: buf.retrans(),
573            fackets: buf.fackets(),
574            last_data_sent: buf.last_data_sent(),
575            last_ack_sent: buf.last_ack_sent(),
576            last_data_recv: buf.last_data_recv(),
577            last_ack_recv: buf.last_ack_recv(),
578            pmtu: buf.pmtu(),
579            rcv_ssthresh: buf.rcv_ssthresh(),
580            rtt: buf.rtt(),
581            rttvar: buf.rttvar(),
582            snd_ssthresh: buf.snd_ssthresh(),
583            snd_cwnd: buf.snd_cwnd(),
584            advmss: buf.advmss(),
585            reordering: buf.reordering(),
586            rcv_rtt: buf.rcv_rtt(),
587            rcv_space: buf.rcv_space(),
588            total_retrans: buf.total_retrans(),
589            pacing_rate: buf.pacing_rate(),
590            max_pacing_rate: buf.max_pacing_rate(),
591            bytes_acked: buf.bytes_acked(),
592            bytes_received: buf.bytes_received(),
593            segs_out: buf.segs_out(),
594            segs_in: buf.segs_in(),
595            notsent_bytes: buf.notsent_bytes(),
596            min_rtt: buf.min_rtt(),
597            data_segs_in: buf.data_segs_in(),
598            data_segs_out: buf.data_segs_out(),
599            delivery_rate: buf.delivery_rate(),
600            busy_time: buf.busy_time(),
601            rwnd_limited: buf.rwnd_limited(),
602            sndbuf_limited: buf.sndbuf_limited(),
603            delivered: buf.delivered(),
604            delivered_ce: buf.delivered_ce(),
605            bytes_sent: buf.bytes_sent(),
606            bytes_retrans: buf.bytes_retrans(),
607            dsack_dups: buf.dsack_dups(),
608            reord_seen: buf.reord_seen(),
609            rcv_ooopack: buf.rcv_ooopack(),
610            snd_wnd: buf.snd_wnd(),
611        })
612    }
613}
614
615impl Emitable for TcpInfo {
616    fn buffer_len(&self) -> usize {
617        TCP_INFO_LEN
618    }
619
620    fn emit(&self, buf: &mut [u8]) {
621        let mut buf = TcpInfoBuffer::new(buf).expect("buffer too small");
622        buf.set_state(self.state);
623        buf.set_congestion_avoidance_state(self.ca_state);
624        buf.set_retransmits(self.retransmits);
625        buf.set_probes(self.probes);
626        buf.set_backoff(self.backoff);
627        buf.set_options(self.options);
628        buf.set_wscale(self.wscale);
629        buf.set_delivery_rate_app_limited(self.delivery_rate_app_limited);
630        buf.set_rto(self.rto);
631        buf.set_ato(self.ato);
632        buf.set_snd_mss(self.snd_mss);
633        buf.set_rcv_mss(self.rcv_mss);
634        buf.set_unacked(self.unacked);
635        buf.set_sacked(self.sacked);
636        buf.set_lost(self.lost);
637        buf.set_retrans(self.retrans);
638        buf.set_fackets(self.fackets);
639        buf.set_last_data_sent(self.last_data_sent);
640        buf.set_last_ack_sent(self.last_ack_sent);
641        buf.set_last_data_recv(self.last_data_recv);
642        buf.set_last_ack_recv(self.last_ack_recv);
643        buf.set_pmtu(self.pmtu);
644        buf.set_rcv_ssthresh(self.rcv_ssthresh);
645        buf.set_rtt(self.rtt);
646        buf.set_rttvar(self.rttvar);
647        buf.set_snd_ssthresh(self.snd_ssthresh);
648        buf.set_snd_cwnd(self.snd_cwnd);
649        buf.set_advmss(self.advmss);
650        buf.set_reordering(self.reordering);
651        buf.set_rcv_rtt(self.rcv_rtt);
652        buf.set_rcv_space(self.rcv_space);
653        buf.set_total_retrans(self.total_retrans);
654        buf.set_pacing_rate(self.pacing_rate);
655        buf.set_max_pacing_rate(self.max_pacing_rate);
656        buf.set_bytes_acked(self.bytes_acked);
657        buf.set_bytes_received(self.bytes_received);
658        buf.set_segs_out(self.segs_out);
659        buf.set_segs_in(self.segs_in);
660        buf.set_notsent_bytes(self.notsent_bytes);
661        buf.set_min_rtt(self.min_rtt);
662        buf.set_data_segs_in(self.data_segs_in);
663        buf.set_data_segs_out(self.data_segs_out);
664        buf.set_delivery_rate(self.delivery_rate);
665        buf.set_busy_time(self.busy_time);
666        buf.set_rwnd_limited(self.rwnd_limited);
667        buf.set_sndbuf_limited(self.sndbuf_limited);
668        buf.set_delivered(self.delivered);
669        buf.set_delivered_ce(self.delivered_ce);
670        buf.set_bytes_sent(self.bytes_sent);
671        buf.set_bytes_retrans(self.bytes_retrans);
672        buf.set_dsack_dups(self.dsack_dups);
673        buf.set_reord_seen(self.reord_seen);
674        buf.set_rcv_ooopack(self.rcv_ooopack);
675        buf.set_snd_wnd(self.snd_wnd);
676    }
677}