1#![doc = "Management interface for TCP metrics\\.\n"]
2#![allow(clippy::all)]
3#![allow(unused_imports)]
4#![allow(unused_assignments)]
5#![allow(non_snake_case)]
6#![allow(unused_variables)]
7#![allow(irrefutable_let_patterns)]
8#![allow(unreachable_code)]
9#![allow(unreachable_patterns)]
10use crate::builtin::{BuiltinBitfield32, BuiltinNfgenmsg, Nlmsghdr, PushDummy};
11use crate::{
12 consts,
13 traits::{NetlinkRequest, Protocol},
14 utils::*,
15};
16pub const PROTONAME: &str = "tcp_metrics";
17pub const PROTONAME_CSTR: &CStr = c"tcp_metrics";
18pub const TCP_FASTOPEN_COOKIE_MAX: u64 = 16u64;
19#[derive(Clone)]
20pub enum TcpMetrics<'a> {
21 AddrIpv4(std::net::Ipv4Addr),
22 AddrIpv6(std::net::Ipv6Addr),
23 Age(u64),
24 #[doc = "unused"]
25 TwTsval(u32),
26 #[doc = "unused"]
27 TwTsStamp(i32),
28 Vals(IterableMetrics<'a>),
29 FopenMss(u16),
30 FopenSynDrops(u16),
31 FopenSynDropTs(u64),
32 FopenCookie(&'a [u8]),
33 SaddrIpv4(std::net::Ipv4Addr),
34 SaddrIpv6(std::net::Ipv6Addr),
35 Pad(&'a [u8]),
36}
37impl<'a> IterableTcpMetrics<'a> {
38 pub fn get_addr_ipv4(&self) -> Result<std::net::Ipv4Addr, ErrorContext> {
39 let mut iter = self.clone();
40 iter.pos = 0;
41 for attr in iter {
42 if let TcpMetrics::AddrIpv4(val) = attr? {
43 return Ok(val);
44 }
45 }
46 Err(ErrorContext::new_missing(
47 "TcpMetrics",
48 "AddrIpv4",
49 self.orig_loc,
50 self.buf.as_ptr() as usize,
51 ))
52 }
53 pub fn get_addr_ipv6(&self) -> Result<std::net::Ipv6Addr, ErrorContext> {
54 let mut iter = self.clone();
55 iter.pos = 0;
56 for attr in iter {
57 if let TcpMetrics::AddrIpv6(val) = attr? {
58 return Ok(val);
59 }
60 }
61 Err(ErrorContext::new_missing(
62 "TcpMetrics",
63 "AddrIpv6",
64 self.orig_loc,
65 self.buf.as_ptr() as usize,
66 ))
67 }
68 pub fn get_age(&self) -> Result<u64, ErrorContext> {
69 let mut iter = self.clone();
70 iter.pos = 0;
71 for attr in iter {
72 if let TcpMetrics::Age(val) = attr? {
73 return Ok(val);
74 }
75 }
76 Err(ErrorContext::new_missing(
77 "TcpMetrics",
78 "Age",
79 self.orig_loc,
80 self.buf.as_ptr() as usize,
81 ))
82 }
83 #[doc = "unused"]
84 pub fn get_tw_tsval(&self) -> Result<u32, ErrorContext> {
85 let mut iter = self.clone();
86 iter.pos = 0;
87 for attr in iter {
88 if let TcpMetrics::TwTsval(val) = attr? {
89 return Ok(val);
90 }
91 }
92 Err(ErrorContext::new_missing(
93 "TcpMetrics",
94 "TwTsval",
95 self.orig_loc,
96 self.buf.as_ptr() as usize,
97 ))
98 }
99 #[doc = "unused"]
100 pub fn get_tw_ts_stamp(&self) -> Result<i32, ErrorContext> {
101 let mut iter = self.clone();
102 iter.pos = 0;
103 for attr in iter {
104 if let TcpMetrics::TwTsStamp(val) = attr? {
105 return Ok(val);
106 }
107 }
108 Err(ErrorContext::new_missing(
109 "TcpMetrics",
110 "TwTsStamp",
111 self.orig_loc,
112 self.buf.as_ptr() as usize,
113 ))
114 }
115 pub fn get_vals(&self) -> Result<IterableMetrics<'a>, ErrorContext> {
116 let mut iter = self.clone();
117 iter.pos = 0;
118 for attr in iter {
119 if let TcpMetrics::Vals(val) = attr? {
120 return Ok(val);
121 }
122 }
123 Err(ErrorContext::new_missing(
124 "TcpMetrics",
125 "Vals",
126 self.orig_loc,
127 self.buf.as_ptr() as usize,
128 ))
129 }
130 pub fn get_fopen_mss(&self) -> Result<u16, ErrorContext> {
131 let mut iter = self.clone();
132 iter.pos = 0;
133 for attr in iter {
134 if let TcpMetrics::FopenMss(val) = attr? {
135 return Ok(val);
136 }
137 }
138 Err(ErrorContext::new_missing(
139 "TcpMetrics",
140 "FopenMss",
141 self.orig_loc,
142 self.buf.as_ptr() as usize,
143 ))
144 }
145 pub fn get_fopen_syn_drops(&self) -> Result<u16, ErrorContext> {
146 let mut iter = self.clone();
147 iter.pos = 0;
148 for attr in iter {
149 if let TcpMetrics::FopenSynDrops(val) = attr? {
150 return Ok(val);
151 }
152 }
153 Err(ErrorContext::new_missing(
154 "TcpMetrics",
155 "FopenSynDrops",
156 self.orig_loc,
157 self.buf.as_ptr() as usize,
158 ))
159 }
160 pub fn get_fopen_syn_drop_ts(&self) -> Result<u64, ErrorContext> {
161 let mut iter = self.clone();
162 iter.pos = 0;
163 for attr in iter {
164 if let TcpMetrics::FopenSynDropTs(val) = attr? {
165 return Ok(val);
166 }
167 }
168 Err(ErrorContext::new_missing(
169 "TcpMetrics",
170 "FopenSynDropTs",
171 self.orig_loc,
172 self.buf.as_ptr() as usize,
173 ))
174 }
175 pub fn get_fopen_cookie(&self) -> Result<&'a [u8], ErrorContext> {
176 let mut iter = self.clone();
177 iter.pos = 0;
178 for attr in iter {
179 if let TcpMetrics::FopenCookie(val) = attr? {
180 return Ok(val);
181 }
182 }
183 Err(ErrorContext::new_missing(
184 "TcpMetrics",
185 "FopenCookie",
186 self.orig_loc,
187 self.buf.as_ptr() as usize,
188 ))
189 }
190 pub fn get_saddr_ipv4(&self) -> Result<std::net::Ipv4Addr, ErrorContext> {
191 let mut iter = self.clone();
192 iter.pos = 0;
193 for attr in iter {
194 if let TcpMetrics::SaddrIpv4(val) = attr? {
195 return Ok(val);
196 }
197 }
198 Err(ErrorContext::new_missing(
199 "TcpMetrics",
200 "SaddrIpv4",
201 self.orig_loc,
202 self.buf.as_ptr() as usize,
203 ))
204 }
205 pub fn get_saddr_ipv6(&self) -> Result<std::net::Ipv6Addr, ErrorContext> {
206 let mut iter = self.clone();
207 iter.pos = 0;
208 for attr in iter {
209 if let TcpMetrics::SaddrIpv6(val) = attr? {
210 return Ok(val);
211 }
212 }
213 Err(ErrorContext::new_missing(
214 "TcpMetrics",
215 "SaddrIpv6",
216 self.orig_loc,
217 self.buf.as_ptr() as usize,
218 ))
219 }
220 pub fn get_pad(&self) -> Result<&'a [u8], ErrorContext> {
221 let mut iter = self.clone();
222 iter.pos = 0;
223 for attr in iter {
224 if let TcpMetrics::Pad(val) = attr? {
225 return Ok(val);
226 }
227 }
228 Err(ErrorContext::new_missing(
229 "TcpMetrics",
230 "Pad",
231 self.orig_loc,
232 self.buf.as_ptr() as usize,
233 ))
234 }
235}
236impl TcpMetrics<'_> {
237 pub fn new<'a>(buf: &'a [u8]) -> IterableTcpMetrics<'a> {
238 IterableTcpMetrics::with_loc(buf, buf.as_ptr() as usize)
239 }
240 fn attr_from_type(r#type: u16) -> Option<&'static str> {
241 let res = match r#type {
242 1u16 => "AddrIpv4",
243 2u16 => "AddrIpv6",
244 3u16 => "Age",
245 4u16 => "TwTsval",
246 5u16 => "TwTsStamp",
247 6u16 => "Vals",
248 7u16 => "FopenMss",
249 8u16 => "FopenSynDrops",
250 9u16 => "FopenSynDropTs",
251 10u16 => "FopenCookie",
252 11u16 => "SaddrIpv4",
253 12u16 => "SaddrIpv6",
254 13u16 => "Pad",
255 _ => return None,
256 };
257 Some(res)
258 }
259}
260#[derive(Clone, Copy, Default)]
261pub struct IterableTcpMetrics<'a> {
262 buf: &'a [u8],
263 pos: usize,
264 orig_loc: usize,
265}
266impl<'a> IterableTcpMetrics<'a> {
267 fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
268 Self {
269 buf,
270 pos: 0,
271 orig_loc,
272 }
273 }
274 pub fn get_buf(&self) -> &'a [u8] {
275 self.buf
276 }
277}
278impl<'a> Iterator for IterableTcpMetrics<'a> {
279 type Item = Result<TcpMetrics<'a>, ErrorContext>;
280 fn next(&mut self) -> Option<Self::Item> {
281 let pos = self.pos;
282 let mut r#type;
283 loop {
284 r#type = None;
285 if self.buf.len() == self.pos {
286 return None;
287 }
288 let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
289 break;
290 };
291 r#type = Some(header.r#type);
292 let res = match header.r#type {
293 1u16 => TcpMetrics::AddrIpv4({
294 let res = parse_be_u32(next).map(Ipv4Addr::from_bits);
295 let Some(val) = res else { break };
296 val
297 }),
298 2u16 => TcpMetrics::AddrIpv6({
299 let res = parse_be_u128(next).map(Ipv6Addr::from_bits);
300 let Some(val) = res else { break };
301 val
302 }),
303 3u16 => TcpMetrics::Age({
304 let res = parse_u64(next);
305 let Some(val) = res else { break };
306 val
307 }),
308 4u16 => TcpMetrics::TwTsval({
309 let res = parse_u32(next);
310 let Some(val) = res else { break };
311 val
312 }),
313 5u16 => TcpMetrics::TwTsStamp({
314 let res = parse_i32(next);
315 let Some(val) = res else { break };
316 val
317 }),
318 6u16 => TcpMetrics::Vals({
319 let res = Some(IterableMetrics::with_loc(next, self.orig_loc));
320 let Some(val) = res else { break };
321 val
322 }),
323 7u16 => TcpMetrics::FopenMss({
324 let res = parse_u16(next);
325 let Some(val) = res else { break };
326 val
327 }),
328 8u16 => TcpMetrics::FopenSynDrops({
329 let res = parse_u16(next);
330 let Some(val) = res else { break };
331 val
332 }),
333 9u16 => TcpMetrics::FopenSynDropTs({
334 let res = parse_u64(next);
335 let Some(val) = res else { break };
336 val
337 }),
338 10u16 => TcpMetrics::FopenCookie({
339 let res = Some(next);
340 let Some(val) = res else { break };
341 val
342 }),
343 11u16 => TcpMetrics::SaddrIpv4({
344 let res = parse_be_u32(next).map(Ipv4Addr::from_bits);
345 let Some(val) = res else { break };
346 val
347 }),
348 12u16 => TcpMetrics::SaddrIpv6({
349 let res = parse_be_u128(next).map(Ipv6Addr::from_bits);
350 let Some(val) = res else { break };
351 val
352 }),
353 13u16 => TcpMetrics::Pad({
354 let res = Some(next);
355 let Some(val) = res else { break };
356 val
357 }),
358 n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
359 n => continue,
360 };
361 return Some(Ok(res));
362 }
363 Some(Err(ErrorContext::new(
364 "TcpMetrics",
365 r#type.and_then(|t| TcpMetrics::attr_from_type(t)),
366 self.orig_loc,
367 self.buf.as_ptr().wrapping_add(pos) as usize,
368 )))
369 }
370}
371impl<'a> std::fmt::Debug for IterableTcpMetrics<'_> {
372 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
373 let mut fmt = f.debug_struct("TcpMetrics");
374 for attr in self.clone() {
375 let attr = match attr {
376 Ok(a) => a,
377 Err(err) => {
378 fmt.finish()?;
379 f.write_str("Err(")?;
380 err.fmt(f)?;
381 return f.write_str(")");
382 }
383 };
384 match attr {
385 TcpMetrics::AddrIpv4(val) => fmt.field("AddrIpv4", &val),
386 TcpMetrics::AddrIpv6(val) => fmt.field("AddrIpv6", &val),
387 TcpMetrics::Age(val) => fmt.field("Age", &val),
388 TcpMetrics::TwTsval(val) => fmt.field("TwTsval", &val),
389 TcpMetrics::TwTsStamp(val) => fmt.field("TwTsStamp", &val),
390 TcpMetrics::Vals(val) => fmt.field("Vals", &val),
391 TcpMetrics::FopenMss(val) => fmt.field("FopenMss", &val),
392 TcpMetrics::FopenSynDrops(val) => fmt.field("FopenSynDrops", &val),
393 TcpMetrics::FopenSynDropTs(val) => fmt.field("FopenSynDropTs", &val),
394 TcpMetrics::FopenCookie(val) => fmt.field("FopenCookie", &val),
395 TcpMetrics::SaddrIpv4(val) => fmt.field("SaddrIpv4", &val),
396 TcpMetrics::SaddrIpv6(val) => fmt.field("SaddrIpv6", &val),
397 TcpMetrics::Pad(val) => fmt.field("Pad", &val),
398 };
399 }
400 fmt.finish()
401 }
402}
403impl IterableTcpMetrics<'_> {
404 pub fn lookup_attr(
405 &self,
406 offset: usize,
407 missing_type: Option<u16>,
408 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
409 let mut stack = Vec::new();
410 let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
411 if missing_type.is_some() && cur == offset {
412 stack.push(("TcpMetrics", offset));
413 return (
414 stack,
415 missing_type.and_then(|t| TcpMetrics::attr_from_type(t)),
416 );
417 }
418 if cur > offset || cur + self.buf.len() < offset {
419 return (stack, None);
420 }
421 let mut attrs = self.clone();
422 let mut last_off = cur + attrs.pos;
423 let mut missing = None;
424 while let Some(attr) = attrs.next() {
425 let Ok(attr) = attr else { break };
426 match attr {
427 TcpMetrics::AddrIpv4(val) => {
428 if last_off == offset {
429 stack.push(("AddrIpv4", last_off));
430 break;
431 }
432 }
433 TcpMetrics::AddrIpv6(val) => {
434 if last_off == offset {
435 stack.push(("AddrIpv6", last_off));
436 break;
437 }
438 }
439 TcpMetrics::Age(val) => {
440 if last_off == offset {
441 stack.push(("Age", last_off));
442 break;
443 }
444 }
445 TcpMetrics::TwTsval(val) => {
446 if last_off == offset {
447 stack.push(("TwTsval", last_off));
448 break;
449 }
450 }
451 TcpMetrics::TwTsStamp(val) => {
452 if last_off == offset {
453 stack.push(("TwTsStamp", last_off));
454 break;
455 }
456 }
457 TcpMetrics::Vals(val) => {
458 (stack, missing) = val.lookup_attr(offset, missing_type);
459 if !stack.is_empty() {
460 break;
461 }
462 }
463 TcpMetrics::FopenMss(val) => {
464 if last_off == offset {
465 stack.push(("FopenMss", last_off));
466 break;
467 }
468 }
469 TcpMetrics::FopenSynDrops(val) => {
470 if last_off == offset {
471 stack.push(("FopenSynDrops", last_off));
472 break;
473 }
474 }
475 TcpMetrics::FopenSynDropTs(val) => {
476 if last_off == offset {
477 stack.push(("FopenSynDropTs", last_off));
478 break;
479 }
480 }
481 TcpMetrics::FopenCookie(val) => {
482 if last_off == offset {
483 stack.push(("FopenCookie", last_off));
484 break;
485 }
486 }
487 TcpMetrics::SaddrIpv4(val) => {
488 if last_off == offset {
489 stack.push(("SaddrIpv4", last_off));
490 break;
491 }
492 }
493 TcpMetrics::SaddrIpv6(val) => {
494 if last_off == offset {
495 stack.push(("SaddrIpv6", last_off));
496 break;
497 }
498 }
499 TcpMetrics::Pad(val) => {
500 if last_off == offset {
501 stack.push(("Pad", last_off));
502 break;
503 }
504 }
505 _ => {}
506 };
507 last_off = cur + attrs.pos;
508 }
509 if !stack.is_empty() {
510 stack.push(("TcpMetrics", cur));
511 }
512 (stack, missing)
513 }
514}
515#[derive(Clone)]
516pub enum Metrics {
517 #[doc = "Round Trip Time (RTT), in msecs with 3 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
518 Rtt(u32),
519 #[doc = "Round Trip Time VARiance (RTT), in msecs with 2 bits fractional\n(left\\-shift by 2 to get the msec value)\\.\n"]
520 Rttvar(u32),
521 #[doc = "Slow Start THRESHold\\."]
522 Ssthresh(u32),
523 #[doc = "Congestion Window\\."]
524 Cwnd(u32),
525 #[doc = "Reodering metric\\."]
526 Reodering(u32),
527 #[doc = "Round Trip Time (RTT), in usecs, with 3 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
528 RttUs(u32),
529 #[doc = "Round Trip Time (RTT), in usecs, with 2 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
530 RttvarUs(u32),
531}
532impl<'a> IterableMetrics<'a> {
533 #[doc = "Round Trip Time (RTT), in msecs with 3 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
534 pub fn get_rtt(&self) -> Result<u32, ErrorContext> {
535 let mut iter = self.clone();
536 iter.pos = 0;
537 for attr in iter {
538 if let Metrics::Rtt(val) = attr? {
539 return Ok(val);
540 }
541 }
542 Err(ErrorContext::new_missing(
543 "Metrics",
544 "Rtt",
545 self.orig_loc,
546 self.buf.as_ptr() as usize,
547 ))
548 }
549 #[doc = "Round Trip Time VARiance (RTT), in msecs with 2 bits fractional\n(left\\-shift by 2 to get the msec value)\\.\n"]
550 pub fn get_rttvar(&self) -> Result<u32, ErrorContext> {
551 let mut iter = self.clone();
552 iter.pos = 0;
553 for attr in iter {
554 if let Metrics::Rttvar(val) = attr? {
555 return Ok(val);
556 }
557 }
558 Err(ErrorContext::new_missing(
559 "Metrics",
560 "Rttvar",
561 self.orig_loc,
562 self.buf.as_ptr() as usize,
563 ))
564 }
565 #[doc = "Slow Start THRESHold\\."]
566 pub fn get_ssthresh(&self) -> Result<u32, ErrorContext> {
567 let mut iter = self.clone();
568 iter.pos = 0;
569 for attr in iter {
570 if let Metrics::Ssthresh(val) = attr? {
571 return Ok(val);
572 }
573 }
574 Err(ErrorContext::new_missing(
575 "Metrics",
576 "Ssthresh",
577 self.orig_loc,
578 self.buf.as_ptr() as usize,
579 ))
580 }
581 #[doc = "Congestion Window\\."]
582 pub fn get_cwnd(&self) -> Result<u32, ErrorContext> {
583 let mut iter = self.clone();
584 iter.pos = 0;
585 for attr in iter {
586 if let Metrics::Cwnd(val) = attr? {
587 return Ok(val);
588 }
589 }
590 Err(ErrorContext::new_missing(
591 "Metrics",
592 "Cwnd",
593 self.orig_loc,
594 self.buf.as_ptr() as usize,
595 ))
596 }
597 #[doc = "Reodering metric\\."]
598 pub fn get_reodering(&self) -> Result<u32, ErrorContext> {
599 let mut iter = self.clone();
600 iter.pos = 0;
601 for attr in iter {
602 if let Metrics::Reodering(val) = attr? {
603 return Ok(val);
604 }
605 }
606 Err(ErrorContext::new_missing(
607 "Metrics",
608 "Reodering",
609 self.orig_loc,
610 self.buf.as_ptr() as usize,
611 ))
612 }
613 #[doc = "Round Trip Time (RTT), in usecs, with 3 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
614 pub fn get_rtt_us(&self) -> Result<u32, ErrorContext> {
615 let mut iter = self.clone();
616 iter.pos = 0;
617 for attr in iter {
618 if let Metrics::RttUs(val) = attr? {
619 return Ok(val);
620 }
621 }
622 Err(ErrorContext::new_missing(
623 "Metrics",
624 "RttUs",
625 self.orig_loc,
626 self.buf.as_ptr() as usize,
627 ))
628 }
629 #[doc = "Round Trip Time (RTT), in usecs, with 2 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
630 pub fn get_rttvar_us(&self) -> Result<u32, ErrorContext> {
631 let mut iter = self.clone();
632 iter.pos = 0;
633 for attr in iter {
634 if let Metrics::RttvarUs(val) = attr? {
635 return Ok(val);
636 }
637 }
638 Err(ErrorContext::new_missing(
639 "Metrics",
640 "RttvarUs",
641 self.orig_loc,
642 self.buf.as_ptr() as usize,
643 ))
644 }
645}
646impl Metrics {
647 pub fn new<'a>(buf: &'a [u8]) -> IterableMetrics<'a> {
648 IterableMetrics::with_loc(buf, buf.as_ptr() as usize)
649 }
650 fn attr_from_type(r#type: u16) -> Option<&'static str> {
651 let res = match r#type {
652 1u16 => "Rtt",
653 2u16 => "Rttvar",
654 3u16 => "Ssthresh",
655 4u16 => "Cwnd",
656 5u16 => "Reodering",
657 6u16 => "RttUs",
658 7u16 => "RttvarUs",
659 _ => return None,
660 };
661 Some(res)
662 }
663}
664#[derive(Clone, Copy, Default)]
665pub struct IterableMetrics<'a> {
666 buf: &'a [u8],
667 pos: usize,
668 orig_loc: usize,
669}
670impl<'a> IterableMetrics<'a> {
671 fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
672 Self {
673 buf,
674 pos: 0,
675 orig_loc,
676 }
677 }
678 pub fn get_buf(&self) -> &'a [u8] {
679 self.buf
680 }
681}
682impl<'a> Iterator for IterableMetrics<'a> {
683 type Item = Result<Metrics, ErrorContext>;
684 fn next(&mut self) -> Option<Self::Item> {
685 let pos = self.pos;
686 let mut r#type;
687 loop {
688 r#type = None;
689 if self.buf.len() == self.pos {
690 return None;
691 }
692 let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
693 break;
694 };
695 r#type = Some(header.r#type);
696 let res = match header.r#type {
697 1u16 => Metrics::Rtt({
698 let res = parse_u32(next);
699 let Some(val) = res else { break };
700 val
701 }),
702 2u16 => Metrics::Rttvar({
703 let res = parse_u32(next);
704 let Some(val) = res else { break };
705 val
706 }),
707 3u16 => Metrics::Ssthresh({
708 let res = parse_u32(next);
709 let Some(val) = res else { break };
710 val
711 }),
712 4u16 => Metrics::Cwnd({
713 let res = parse_u32(next);
714 let Some(val) = res else { break };
715 val
716 }),
717 5u16 => Metrics::Reodering({
718 let res = parse_u32(next);
719 let Some(val) = res else { break };
720 val
721 }),
722 6u16 => Metrics::RttUs({
723 let res = parse_u32(next);
724 let Some(val) = res else { break };
725 val
726 }),
727 7u16 => Metrics::RttvarUs({
728 let res = parse_u32(next);
729 let Some(val) = res else { break };
730 val
731 }),
732 n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
733 n => continue,
734 };
735 return Some(Ok(res));
736 }
737 Some(Err(ErrorContext::new(
738 "Metrics",
739 r#type.and_then(|t| Metrics::attr_from_type(t)),
740 self.orig_loc,
741 self.buf.as_ptr().wrapping_add(pos) as usize,
742 )))
743 }
744}
745impl std::fmt::Debug for IterableMetrics<'_> {
746 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
747 let mut fmt = f.debug_struct("Metrics");
748 for attr in self.clone() {
749 let attr = match attr {
750 Ok(a) => a,
751 Err(err) => {
752 fmt.finish()?;
753 f.write_str("Err(")?;
754 err.fmt(f)?;
755 return f.write_str(")");
756 }
757 };
758 match attr {
759 Metrics::Rtt(val) => fmt.field("Rtt", &val),
760 Metrics::Rttvar(val) => fmt.field("Rttvar", &val),
761 Metrics::Ssthresh(val) => fmt.field("Ssthresh", &val),
762 Metrics::Cwnd(val) => fmt.field("Cwnd", &val),
763 Metrics::Reodering(val) => fmt.field("Reodering", &val),
764 Metrics::RttUs(val) => fmt.field("RttUs", &val),
765 Metrics::RttvarUs(val) => fmt.field("RttvarUs", &val),
766 };
767 }
768 fmt.finish()
769 }
770}
771impl IterableMetrics<'_> {
772 pub fn lookup_attr(
773 &self,
774 offset: usize,
775 missing_type: Option<u16>,
776 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
777 let mut stack = Vec::new();
778 let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
779 if missing_type.is_some() && cur == offset {
780 stack.push(("Metrics", offset));
781 return (stack, missing_type.and_then(|t| Metrics::attr_from_type(t)));
782 }
783 if cur > offset || cur + self.buf.len() < offset {
784 return (stack, None);
785 }
786 let mut attrs = self.clone();
787 let mut last_off = cur + attrs.pos;
788 while let Some(attr) = attrs.next() {
789 let Ok(attr) = attr else { break };
790 match attr {
791 Metrics::Rtt(val) => {
792 if last_off == offset {
793 stack.push(("Rtt", last_off));
794 break;
795 }
796 }
797 Metrics::Rttvar(val) => {
798 if last_off == offset {
799 stack.push(("Rttvar", last_off));
800 break;
801 }
802 }
803 Metrics::Ssthresh(val) => {
804 if last_off == offset {
805 stack.push(("Ssthresh", last_off));
806 break;
807 }
808 }
809 Metrics::Cwnd(val) => {
810 if last_off == offset {
811 stack.push(("Cwnd", last_off));
812 break;
813 }
814 }
815 Metrics::Reodering(val) => {
816 if last_off == offset {
817 stack.push(("Reodering", last_off));
818 break;
819 }
820 }
821 Metrics::RttUs(val) => {
822 if last_off == offset {
823 stack.push(("RttUs", last_off));
824 break;
825 }
826 }
827 Metrics::RttvarUs(val) => {
828 if last_off == offset {
829 stack.push(("RttvarUs", last_off));
830 break;
831 }
832 }
833 _ => {}
834 };
835 last_off = cur + attrs.pos;
836 }
837 if !stack.is_empty() {
838 stack.push(("Metrics", cur));
839 }
840 (stack, None)
841 }
842}
843pub struct PushTcpMetrics<Prev: Rec> {
844 pub(crate) prev: Option<Prev>,
845 pub(crate) header_offset: Option<usize>,
846}
847impl<Prev: Rec> Rec for PushTcpMetrics<Prev> {
848 fn as_rec_mut(&mut self) -> &mut Vec<u8> {
849 self.prev.as_mut().unwrap().as_rec_mut()
850 }
851 fn as_rec(&self) -> &Vec<u8> {
852 self.prev.as_ref().unwrap().as_rec()
853 }
854}
855impl<Prev: Rec> PushTcpMetrics<Prev> {
856 pub fn new(prev: Prev) -> Self {
857 Self {
858 prev: Some(prev),
859 header_offset: None,
860 }
861 }
862 pub fn end_nested(mut self) -> Prev {
863 let mut prev = self.prev.take().unwrap();
864 if let Some(header_offset) = &self.header_offset {
865 finalize_nested_header(prev.as_rec_mut(), *header_offset);
866 }
867 prev
868 }
869 pub fn push_addr_ipv4(mut self, value: std::net::Ipv4Addr) -> Self {
870 push_header(self.as_rec_mut(), 1u16, 4 as u16);
871 self.as_rec_mut().extend(&value.to_bits().to_be_bytes());
872 self
873 }
874 pub fn push_addr_ipv6(mut self, value: std::net::Ipv6Addr) -> Self {
875 push_header(self.as_rec_mut(), 2u16, 16 as u16);
876 self.as_rec_mut().extend(&value.to_bits().to_be_bytes());
877 self
878 }
879 pub fn push_age(mut self, value: u64) -> Self {
880 push_header(self.as_rec_mut(), 3u16, 8 as u16);
881 self.as_rec_mut().extend(value.to_ne_bytes());
882 self
883 }
884 #[doc = "unused"]
885 pub fn push_tw_tsval(mut self, value: u32) -> Self {
886 push_header(self.as_rec_mut(), 4u16, 4 as u16);
887 self.as_rec_mut().extend(value.to_ne_bytes());
888 self
889 }
890 #[doc = "unused"]
891 pub fn push_tw_ts_stamp(mut self, value: i32) -> Self {
892 push_header(self.as_rec_mut(), 5u16, 4 as u16);
893 self.as_rec_mut().extend(value.to_ne_bytes());
894 self
895 }
896 pub fn nested_vals(mut self) -> PushMetrics<Self> {
897 let header_offset = push_nested_header(self.as_rec_mut(), 6u16);
898 PushMetrics {
899 prev: Some(self),
900 header_offset: Some(header_offset),
901 }
902 }
903 pub fn push_fopen_mss(mut self, value: u16) -> Self {
904 push_header(self.as_rec_mut(), 7u16, 2 as u16);
905 self.as_rec_mut().extend(value.to_ne_bytes());
906 self
907 }
908 pub fn push_fopen_syn_drops(mut self, value: u16) -> Self {
909 push_header(self.as_rec_mut(), 8u16, 2 as u16);
910 self.as_rec_mut().extend(value.to_ne_bytes());
911 self
912 }
913 pub fn push_fopen_syn_drop_ts(mut self, value: u64) -> Self {
914 push_header(self.as_rec_mut(), 9u16, 8 as u16);
915 self.as_rec_mut().extend(value.to_ne_bytes());
916 self
917 }
918 pub fn push_fopen_cookie(mut self, value: &[u8]) -> Self {
919 push_header(self.as_rec_mut(), 10u16, value.len() as u16);
920 self.as_rec_mut().extend(value);
921 self
922 }
923 pub fn push_saddr_ipv4(mut self, value: std::net::Ipv4Addr) -> Self {
924 push_header(self.as_rec_mut(), 11u16, 4 as u16);
925 self.as_rec_mut().extend(&value.to_bits().to_be_bytes());
926 self
927 }
928 pub fn push_saddr_ipv6(mut self, value: std::net::Ipv6Addr) -> Self {
929 push_header(self.as_rec_mut(), 12u16, 16 as u16);
930 self.as_rec_mut().extend(&value.to_bits().to_be_bytes());
931 self
932 }
933 pub fn push_pad(mut self, value: &[u8]) -> Self {
934 push_header(self.as_rec_mut(), 13u16, value.len() as u16);
935 self.as_rec_mut().extend(value);
936 self
937 }
938}
939impl<Prev: Rec> Drop for PushTcpMetrics<Prev> {
940 fn drop(&mut self) {
941 if let Some(prev) = &mut self.prev {
942 if let Some(header_offset) = &self.header_offset {
943 finalize_nested_header(prev.as_rec_mut(), *header_offset);
944 }
945 }
946 }
947}
948pub struct PushMetrics<Prev: Rec> {
949 pub(crate) prev: Option<Prev>,
950 pub(crate) header_offset: Option<usize>,
951}
952impl<Prev: Rec> Rec for PushMetrics<Prev> {
953 fn as_rec_mut(&mut self) -> &mut Vec<u8> {
954 self.prev.as_mut().unwrap().as_rec_mut()
955 }
956 fn as_rec(&self) -> &Vec<u8> {
957 self.prev.as_ref().unwrap().as_rec()
958 }
959}
960impl<Prev: Rec> PushMetrics<Prev> {
961 pub fn new(prev: Prev) -> Self {
962 Self {
963 prev: Some(prev),
964 header_offset: None,
965 }
966 }
967 pub fn end_nested(mut self) -> Prev {
968 let mut prev = self.prev.take().unwrap();
969 if let Some(header_offset) = &self.header_offset {
970 finalize_nested_header(prev.as_rec_mut(), *header_offset);
971 }
972 prev
973 }
974 #[doc = "Round Trip Time (RTT), in msecs with 3 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
975 pub fn push_rtt(mut self, value: u32) -> Self {
976 push_header(self.as_rec_mut(), 1u16, 4 as u16);
977 self.as_rec_mut().extend(value.to_ne_bytes());
978 self
979 }
980 #[doc = "Round Trip Time VARiance (RTT), in msecs with 2 bits fractional\n(left\\-shift by 2 to get the msec value)\\.\n"]
981 pub fn push_rttvar(mut self, value: u32) -> Self {
982 push_header(self.as_rec_mut(), 2u16, 4 as u16);
983 self.as_rec_mut().extend(value.to_ne_bytes());
984 self
985 }
986 #[doc = "Slow Start THRESHold\\."]
987 pub fn push_ssthresh(mut self, value: u32) -> Self {
988 push_header(self.as_rec_mut(), 3u16, 4 as u16);
989 self.as_rec_mut().extend(value.to_ne_bytes());
990 self
991 }
992 #[doc = "Congestion Window\\."]
993 pub fn push_cwnd(mut self, value: u32) -> Self {
994 push_header(self.as_rec_mut(), 4u16, 4 as u16);
995 self.as_rec_mut().extend(value.to_ne_bytes());
996 self
997 }
998 #[doc = "Reodering metric\\."]
999 pub fn push_reodering(mut self, value: u32) -> Self {
1000 push_header(self.as_rec_mut(), 5u16, 4 as u16);
1001 self.as_rec_mut().extend(value.to_ne_bytes());
1002 self
1003 }
1004 #[doc = "Round Trip Time (RTT), in usecs, with 3 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
1005 pub fn push_rtt_us(mut self, value: u32) -> Self {
1006 push_header(self.as_rec_mut(), 6u16, 4 as u16);
1007 self.as_rec_mut().extend(value.to_ne_bytes());
1008 self
1009 }
1010 #[doc = "Round Trip Time (RTT), in usecs, with 2 bits fractional\n(left\\-shift by 3 to get the msec value)\\.\n"]
1011 pub fn push_rttvar_us(mut self, value: u32) -> Self {
1012 push_header(self.as_rec_mut(), 7u16, 4 as u16);
1013 self.as_rec_mut().extend(value.to_ne_bytes());
1014 self
1015 }
1016}
1017impl<Prev: Rec> Drop for PushMetrics<Prev> {
1018 fn drop(&mut self) {
1019 if let Some(prev) = &mut self.prev {
1020 if let Some(header_offset) = &self.header_offset {
1021 finalize_nested_header(prev.as_rec_mut(), *header_offset);
1022 }
1023 }
1024 }
1025}
1026#[doc = "Retrieve metrics\\.\n\nReply attributes:\n- [.get_addr_ipv4()](IterableTcpMetrics::get_addr_ipv4)\n- [.get_addr_ipv6()](IterableTcpMetrics::get_addr_ipv6)\n- [.get_age()](IterableTcpMetrics::get_age)\n- [.get_vals()](IterableTcpMetrics::get_vals)\n- [.get_fopen_mss()](IterableTcpMetrics::get_fopen_mss)\n- [.get_fopen_syn_drops()](IterableTcpMetrics::get_fopen_syn_drops)\n- [.get_fopen_syn_drop_ts()](IterableTcpMetrics::get_fopen_syn_drop_ts)\n- [.get_fopen_cookie()](IterableTcpMetrics::get_fopen_cookie)\n- [.get_saddr_ipv4()](IterableTcpMetrics::get_saddr_ipv4)\n- [.get_saddr_ipv6()](IterableTcpMetrics::get_saddr_ipv6)\n"]
1027#[derive(Debug)]
1028pub struct OpGetDump<'r> {
1029 request: Request<'r>,
1030}
1031impl<'r> OpGetDump<'r> {
1032 pub fn new(mut request: Request<'r>) -> Self {
1033 Self::write_header(request.buf_mut());
1034 Self {
1035 request: request.set_dump(),
1036 }
1037 }
1038 pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushTcpMetrics<&'buf mut Vec<u8>> {
1039 Self::write_header(buf);
1040 PushTcpMetrics::new(buf)
1041 }
1042 pub fn encode(&mut self) -> PushTcpMetrics<&mut Vec<u8>> {
1043 PushTcpMetrics::new(self.request.buf_mut())
1044 }
1045 pub fn into_encoder(self) -> PushTcpMetrics<RequestBuf<'r>> {
1046 PushTcpMetrics::new(self.request.buf)
1047 }
1048 pub fn decode_request<'a>(buf: &'a [u8]) -> IterableTcpMetrics<'a> {
1049 let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
1050 IterableTcpMetrics::with_loc(attrs, buf.as_ptr() as usize)
1051 }
1052 fn write_header<Prev: Rec>(prev: &mut Prev) {
1053 let mut header = BuiltinNfgenmsg::new();
1054 header.cmd = 1u8;
1055 header.version = 1u8;
1056 prev.as_rec_mut().extend(header.as_slice());
1057 }
1058}
1059impl NetlinkRequest for OpGetDump<'_> {
1060 fn protocol(&self) -> Protocol {
1061 Protocol::Generic("tcp_metrics".as_bytes())
1062 }
1063 fn flags(&self) -> u16 {
1064 self.request.flags
1065 }
1066 fn payload(&self) -> &[u8] {
1067 self.request.buf()
1068 }
1069 type ReplyType<'buf> = IterableTcpMetrics<'buf>;
1070 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
1071 Self::decode_request(buf)
1072 }
1073 fn lookup(
1074 buf: &[u8],
1075 offset: usize,
1076 missing_type: Option<u16>,
1077 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
1078 Self::decode_request(buf).lookup_attr(offset, missing_type)
1079 }
1080}
1081#[doc = "Retrieve metrics\\.\nRequest attributes:\n- [.push_addr_ipv4()](PushTcpMetrics::push_addr_ipv4)\n- [.push_addr_ipv6()](PushTcpMetrics::push_addr_ipv6)\n- [.push_saddr_ipv4()](PushTcpMetrics::push_saddr_ipv4)\n- [.push_saddr_ipv6()](PushTcpMetrics::push_saddr_ipv6)\n\nReply attributes:\n- [.get_addr_ipv4()](IterableTcpMetrics::get_addr_ipv4)\n- [.get_addr_ipv6()](IterableTcpMetrics::get_addr_ipv6)\n- [.get_age()](IterableTcpMetrics::get_age)\n- [.get_vals()](IterableTcpMetrics::get_vals)\n- [.get_fopen_mss()](IterableTcpMetrics::get_fopen_mss)\n- [.get_fopen_syn_drops()](IterableTcpMetrics::get_fopen_syn_drops)\n- [.get_fopen_syn_drop_ts()](IterableTcpMetrics::get_fopen_syn_drop_ts)\n- [.get_fopen_cookie()](IterableTcpMetrics::get_fopen_cookie)\n- [.get_saddr_ipv4()](IterableTcpMetrics::get_saddr_ipv4)\n- [.get_saddr_ipv6()](IterableTcpMetrics::get_saddr_ipv6)\n"]
1082#[derive(Debug)]
1083pub struct OpGetDo<'r> {
1084 request: Request<'r>,
1085}
1086impl<'r> OpGetDo<'r> {
1087 pub fn new(mut request: Request<'r>) -> Self {
1088 Self::write_header(request.buf_mut());
1089 Self { request: request }
1090 }
1091 pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushTcpMetrics<&'buf mut Vec<u8>> {
1092 Self::write_header(buf);
1093 PushTcpMetrics::new(buf)
1094 }
1095 pub fn encode(&mut self) -> PushTcpMetrics<&mut Vec<u8>> {
1096 PushTcpMetrics::new(self.request.buf_mut())
1097 }
1098 pub fn into_encoder(self) -> PushTcpMetrics<RequestBuf<'r>> {
1099 PushTcpMetrics::new(self.request.buf)
1100 }
1101 pub fn decode_request<'a>(buf: &'a [u8]) -> IterableTcpMetrics<'a> {
1102 let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
1103 IterableTcpMetrics::with_loc(attrs, buf.as_ptr() as usize)
1104 }
1105 fn write_header<Prev: Rec>(prev: &mut Prev) {
1106 let mut header = BuiltinNfgenmsg::new();
1107 header.cmd = 1u8;
1108 header.version = 1u8;
1109 prev.as_rec_mut().extend(header.as_slice());
1110 }
1111}
1112impl NetlinkRequest for OpGetDo<'_> {
1113 fn protocol(&self) -> Protocol {
1114 Protocol::Generic("tcp_metrics".as_bytes())
1115 }
1116 fn flags(&self) -> u16 {
1117 self.request.flags
1118 }
1119 fn payload(&self) -> &[u8] {
1120 self.request.buf()
1121 }
1122 type ReplyType<'buf> = IterableTcpMetrics<'buf>;
1123 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
1124 Self::decode_request(buf)
1125 }
1126 fn lookup(
1127 buf: &[u8],
1128 offset: usize,
1129 missing_type: Option<u16>,
1130 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
1131 Self::decode_request(buf).lookup_attr(offset, missing_type)
1132 }
1133}
1134#[doc = "Delete metrics\\.\nFlags: admin-perm\nRequest attributes:\n- [.push_addr_ipv4()](PushTcpMetrics::push_addr_ipv4)\n- [.push_addr_ipv6()](PushTcpMetrics::push_addr_ipv6)\n- [.push_saddr_ipv4()](PushTcpMetrics::push_saddr_ipv4)\n- [.push_saddr_ipv6()](PushTcpMetrics::push_saddr_ipv6)\n"]
1135#[derive(Debug)]
1136pub struct OpDelDo<'r> {
1137 request: Request<'r>,
1138}
1139impl<'r> OpDelDo<'r> {
1140 pub fn new(mut request: Request<'r>) -> Self {
1141 Self::write_header(request.buf_mut());
1142 Self { request: request }
1143 }
1144 pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushTcpMetrics<&'buf mut Vec<u8>> {
1145 Self::write_header(buf);
1146 PushTcpMetrics::new(buf)
1147 }
1148 pub fn encode(&mut self) -> PushTcpMetrics<&mut Vec<u8>> {
1149 PushTcpMetrics::new(self.request.buf_mut())
1150 }
1151 pub fn into_encoder(self) -> PushTcpMetrics<RequestBuf<'r>> {
1152 PushTcpMetrics::new(self.request.buf)
1153 }
1154 pub fn decode_request<'a>(buf: &'a [u8]) -> IterableTcpMetrics<'a> {
1155 let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
1156 IterableTcpMetrics::with_loc(attrs, buf.as_ptr() as usize)
1157 }
1158 fn write_header<Prev: Rec>(prev: &mut Prev) {
1159 let mut header = BuiltinNfgenmsg::new();
1160 header.cmd = 2u8;
1161 header.version = 1u8;
1162 prev.as_rec_mut().extend(header.as_slice());
1163 }
1164}
1165impl NetlinkRequest for OpDelDo<'_> {
1166 fn protocol(&self) -> Protocol {
1167 Protocol::Generic("tcp_metrics".as_bytes())
1168 }
1169 fn flags(&self) -> u16 {
1170 self.request.flags
1171 }
1172 fn payload(&self) -> &[u8] {
1173 self.request.buf()
1174 }
1175 type ReplyType<'buf> = IterableTcpMetrics<'buf>;
1176 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
1177 Self::decode_request(buf)
1178 }
1179 fn lookup(
1180 buf: &[u8],
1181 offset: usize,
1182 missing_type: Option<u16>,
1183 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
1184 Self::decode_request(buf).lookup_attr(offset, missing_type)
1185 }
1186}
1187use crate::traits::LookupFn;
1188use crate::utils::RequestBuf;
1189#[derive(Debug)]
1190pub struct Request<'buf> {
1191 buf: RequestBuf<'buf>,
1192 flags: u16,
1193 writeback: Option<&'buf mut Option<RequestInfo>>,
1194}
1195#[allow(unused)]
1196#[derive(Debug, Clone)]
1197pub struct RequestInfo {
1198 protocol: Protocol,
1199 flags: u16,
1200 name: &'static str,
1201 lookup: LookupFn,
1202}
1203impl Request<'static> {
1204 pub fn new() -> Self {
1205 Self::new_from_buf(Vec::new())
1206 }
1207 pub fn new_from_buf(buf: Vec<u8>) -> Self {
1208 Self {
1209 flags: 0,
1210 buf: RequestBuf::Own(buf),
1211 writeback: None,
1212 }
1213 }
1214 pub fn into_buf(self) -> Vec<u8> {
1215 match self.buf {
1216 RequestBuf::Own(buf) => buf,
1217 _ => unreachable!(),
1218 }
1219 }
1220}
1221impl<'buf> Request<'buf> {
1222 pub fn new_with_buf(buf: &'buf mut Vec<u8>) -> Self {
1223 buf.clear();
1224 Self::new_extend(buf)
1225 }
1226 pub fn new_extend(buf: &'buf mut Vec<u8>) -> Self {
1227 Self {
1228 flags: 0,
1229 buf: RequestBuf::Ref(buf),
1230 writeback: None,
1231 }
1232 }
1233 fn do_writeback(&mut self, protocol: Protocol, name: &'static str, lookup: LookupFn) {
1234 let Some(writeback) = &mut self.writeback else {
1235 return;
1236 };
1237 **writeback = Some(RequestInfo {
1238 protocol,
1239 flags: self.flags,
1240 name,
1241 lookup,
1242 })
1243 }
1244 pub fn buf(&self) -> &Vec<u8> {
1245 self.buf.buf()
1246 }
1247 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
1248 self.buf.buf_mut()
1249 }
1250 #[doc = "Set `NLM_F_CREATE` flag"]
1251 pub fn set_create(mut self) -> Self {
1252 self.flags |= consts::NLM_F_CREATE as u16;
1253 self
1254 }
1255 #[doc = "Set `NLM_F_EXCL` flag"]
1256 pub fn set_excl(mut self) -> Self {
1257 self.flags |= consts::NLM_F_EXCL as u16;
1258 self
1259 }
1260 #[doc = "Set `NLM_F_REPLACE` flag"]
1261 pub fn set_replace(mut self) -> Self {
1262 self.flags |= consts::NLM_F_REPLACE as u16;
1263 self
1264 }
1265 #[doc = "Set `NLM_F_CREATE` and `NLM_F_REPLACE` flag"]
1266 pub fn set_change(self) -> Self {
1267 self.set_create().set_replace()
1268 }
1269 #[doc = "Set `NLM_F_APPEND` flag"]
1270 pub fn set_append(mut self) -> Self {
1271 self.flags |= consts::NLM_F_APPEND as u16;
1272 self
1273 }
1274 #[doc = "Set `self.flags |= flags`"]
1275 pub fn set_flags(mut self, flags: u16) -> Self {
1276 self.flags |= flags;
1277 self
1278 }
1279 #[doc = "Set `self.flags ^= self.flags & flags`"]
1280 pub fn unset_flags(mut self, flags: u16) -> Self {
1281 self.flags ^= self.flags & flags;
1282 self
1283 }
1284 #[doc = "Set `NLM_F_DUMP` flag"]
1285 fn set_dump(mut self) -> Self {
1286 self.flags |= consts::NLM_F_DUMP as u16;
1287 self
1288 }
1289 #[doc = "Retrieve metrics\\.\n\nReply attributes:\n- [.get_addr_ipv4()](IterableTcpMetrics::get_addr_ipv4)\n- [.get_addr_ipv6()](IterableTcpMetrics::get_addr_ipv6)\n- [.get_age()](IterableTcpMetrics::get_age)\n- [.get_vals()](IterableTcpMetrics::get_vals)\n- [.get_fopen_mss()](IterableTcpMetrics::get_fopen_mss)\n- [.get_fopen_syn_drops()](IterableTcpMetrics::get_fopen_syn_drops)\n- [.get_fopen_syn_drop_ts()](IterableTcpMetrics::get_fopen_syn_drop_ts)\n- [.get_fopen_cookie()](IterableTcpMetrics::get_fopen_cookie)\n- [.get_saddr_ipv4()](IterableTcpMetrics::get_saddr_ipv4)\n- [.get_saddr_ipv6()](IterableTcpMetrics::get_saddr_ipv6)\n"]
1290 pub fn op_get_dump(self) -> OpGetDump<'buf> {
1291 let mut res = OpGetDump::new(self);
1292 res.request
1293 .do_writeback(res.protocol(), "op-get-dump", OpGetDump::lookup);
1294 res
1295 }
1296 #[doc = "Retrieve metrics\\.\nRequest attributes:\n- [.push_addr_ipv4()](PushTcpMetrics::push_addr_ipv4)\n- [.push_addr_ipv6()](PushTcpMetrics::push_addr_ipv6)\n- [.push_saddr_ipv4()](PushTcpMetrics::push_saddr_ipv4)\n- [.push_saddr_ipv6()](PushTcpMetrics::push_saddr_ipv6)\n\nReply attributes:\n- [.get_addr_ipv4()](IterableTcpMetrics::get_addr_ipv4)\n- [.get_addr_ipv6()](IterableTcpMetrics::get_addr_ipv6)\n- [.get_age()](IterableTcpMetrics::get_age)\n- [.get_vals()](IterableTcpMetrics::get_vals)\n- [.get_fopen_mss()](IterableTcpMetrics::get_fopen_mss)\n- [.get_fopen_syn_drops()](IterableTcpMetrics::get_fopen_syn_drops)\n- [.get_fopen_syn_drop_ts()](IterableTcpMetrics::get_fopen_syn_drop_ts)\n- [.get_fopen_cookie()](IterableTcpMetrics::get_fopen_cookie)\n- [.get_saddr_ipv4()](IterableTcpMetrics::get_saddr_ipv4)\n- [.get_saddr_ipv6()](IterableTcpMetrics::get_saddr_ipv6)\n"]
1297 pub fn op_get_do(self) -> OpGetDo<'buf> {
1298 let mut res = OpGetDo::new(self);
1299 res.request
1300 .do_writeback(res.protocol(), "op-get-do", OpGetDo::lookup);
1301 res
1302 }
1303 #[doc = "Delete metrics\\.\nFlags: admin-perm\nRequest attributes:\n- [.push_addr_ipv4()](PushTcpMetrics::push_addr_ipv4)\n- [.push_addr_ipv6()](PushTcpMetrics::push_addr_ipv6)\n- [.push_saddr_ipv4()](PushTcpMetrics::push_saddr_ipv4)\n- [.push_saddr_ipv6()](PushTcpMetrics::push_saddr_ipv6)\n"]
1304 pub fn op_del_do(self) -> OpDelDo<'buf> {
1305 let mut res = OpDelDo::new(self);
1306 res.request
1307 .do_writeback(res.protocol(), "op-del-do", OpDelDo::lookup);
1308 res
1309 }
1310}
1311#[cfg(test)]
1312mod generated_tests {
1313 use super::*;
1314 #[test]
1315 fn tests() {
1316 let _ = IterableTcpMetrics::get_addr_ipv4;
1317 let _ = IterableTcpMetrics::get_addr_ipv6;
1318 let _ = IterableTcpMetrics::get_age;
1319 let _ = IterableTcpMetrics::get_fopen_cookie;
1320 let _ = IterableTcpMetrics::get_fopen_mss;
1321 let _ = IterableTcpMetrics::get_fopen_syn_drop_ts;
1322 let _ = IterableTcpMetrics::get_fopen_syn_drops;
1323 let _ = IterableTcpMetrics::get_saddr_ipv4;
1324 let _ = IterableTcpMetrics::get_saddr_ipv6;
1325 let _ = IterableTcpMetrics::get_vals;
1326 let _ = PushTcpMetrics::<&mut Vec<u8>>::push_addr_ipv4;
1327 let _ = PushTcpMetrics::<&mut Vec<u8>>::push_addr_ipv6;
1328 let _ = PushTcpMetrics::<&mut Vec<u8>>::push_saddr_ipv4;
1329 let _ = PushTcpMetrics::<&mut Vec<u8>>::push_saddr_ipv6;
1330 }
1331}