Skip to main content

netlink_bindings/tcp_metrics/
mod.rs

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}