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}