Skip to main content

netlink_bindings/netdev/
mod.rs

1#![doc = "netdev configuration over generic netlink\\."]
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 = "netdev";
17pub const PROTONAME_CSTR: &CStr = c"netdev";
18#[doc = "Flags - defines an integer enumeration, with values for each entry occupying a bit, starting from bit 0, (e.g. 1, 2, 4, 8)"]
19#[derive(Debug, Clone, Copy)]
20pub enum XdpAct {
21    #[doc = "XDP features set supported by all drivers (XDP\\_ABORTED, XDP\\_DROP, XDP\\_PASS, XDP\\_TX)"]
22    Basic = 1 << 0,
23    #[doc = "The netdev supports XDP\\_REDIRECT"]
24    Redirect = 1 << 1,
25    #[doc = "This feature informs if netdev implements ndo\\_xdp\\_xmit callback\\."]
26    NdoXmit = 1 << 2,
27    #[doc = "This feature informs if netdev supports AF\\_XDP in zero copy mode\\."]
28    XskZerocopy = 1 << 3,
29    #[doc = "This feature informs if netdev supports XDP hw offloading\\."]
30    HwOffload = 1 << 4,
31    #[doc = "This feature informs if netdev implements non\\-linear XDP buffer support in the driver napi callback\\."]
32    RxSg = 1 << 5,
33    #[doc = "This feature informs if netdev implements non\\-linear XDP buffer support in ndo\\_xdp\\_xmit callback\\."]
34    NdoXmitSg = 1 << 6,
35}
36impl XdpAct {
37    pub fn from_value(value: u64) -> Option<Self> {
38        Some(match value {
39            n if n == 1 << 0 => Self::Basic,
40            n if n == 1 << 1 => Self::Redirect,
41            n if n == 1 << 2 => Self::NdoXmit,
42            n if n == 1 << 3 => Self::XskZerocopy,
43            n if n == 1 << 4 => Self::HwOffload,
44            n if n == 1 << 5 => Self::RxSg,
45            n if n == 1 << 6 => Self::NdoXmitSg,
46            _ => return None,
47        })
48    }
49}
50#[doc = "Flags - defines an integer enumeration, with values for each entry occupying a bit, starting from bit 0, (e.g. 1, 2, 4, 8)"]
51#[derive(Debug, Clone, Copy)]
52pub enum XdpRxMetadata {
53    #[doc = "Device is capable of exposing receive HW timestamp via\nbpf\\_xdp\\_metadata\\_rx\\_timestamp()\\.\n"]
54    Timestamp = 1 << 0,
55    #[doc = "Device is capable of exposing receive packet hash via\nbpf\\_xdp\\_metadata\\_rx\\_hash()\\.\n"]
56    Hash = 1 << 1,
57    #[doc = "Device is capable of exposing receive packet VLAN tag via\nbpf\\_xdp\\_metadata\\_rx\\_vlan\\_tag()\\.\n"]
58    VlanTag = 1 << 2,
59}
60impl XdpRxMetadata {
61    pub fn from_value(value: u64) -> Option<Self> {
62        Some(match value {
63            n if n == 1 << 0 => Self::Timestamp,
64            n if n == 1 << 1 => Self::Hash,
65            n if n == 1 << 2 => Self::VlanTag,
66            _ => return None,
67        })
68    }
69}
70#[doc = "Flags - defines an integer enumeration, with values for each entry occupying a bit, starting from bit 0, (e.g. 1, 2, 4, 8)"]
71#[derive(Debug, Clone, Copy)]
72pub enum XskFlags {
73    #[doc = "HW timestamping egress packets is supported by the driver\\."]
74    TxTimestamp = 1 << 0,
75    #[doc = "L3 checksum HW offload is supported by the driver\\."]
76    TxChecksum = 1 << 1,
77    #[doc = "Launch time HW offload is supported by the driver\\."]
78    TxLaunchTimeFifo = 1 << 2,
79}
80impl XskFlags {
81    pub fn from_value(value: u64) -> Option<Self> {
82        Some(match value {
83            n if n == 1 << 0 => Self::TxTimestamp,
84            n if n == 1 << 1 => Self::TxChecksum,
85            n if n == 1 << 2 => Self::TxLaunchTimeFifo,
86            _ => return None,
87        })
88    }
89}
90#[doc = "Enum - defines an integer enumeration, with values for each entry incrementing by 1, (e.g. 0, 1, 2, 3)"]
91#[derive(Debug, Clone, Copy)]
92pub enum QueueType {
93    Rx = 0,
94    Tx = 1,
95}
96impl QueueType {
97    pub fn from_value(value: u64) -> Option<Self> {
98        Some(match value {
99            0 => Self::Rx,
100            1 => Self::Tx,
101            _ => return None,
102        })
103    }
104}
105#[doc = "Flags - defines an integer enumeration, with values for each entry occupying a bit, starting from bit 0, (e.g. 1, 2, 4, 8)"]
106#[derive(Debug, Clone, Copy)]
107pub enum QstatsScope {
108    Queue = 1 << 0,
109}
110impl QstatsScope {
111    pub fn from_value(value: u64) -> Option<Self> {
112        Some(match value {
113            n if n == 1 << 0 => Self::Queue,
114            _ => return None,
115        })
116    }
117}
118#[doc = "Enum - defines an integer enumeration, with values for each entry incrementing by 1, (e.g. 0, 1, 2, 3)"]
119#[derive(Debug, Clone, Copy)]
120pub enum NapiThreaded {
121    Disabled = 0,
122    Enabled = 1,
123    BusyPoll = 2,
124}
125impl NapiThreaded {
126    pub fn from_value(value: u64) -> Option<Self> {
127        Some(match value {
128            0 => Self::Disabled,
129            1 => Self::Enabled,
130            2 => Self::BusyPoll,
131            _ => return None,
132        })
133    }
134}
135#[derive(Clone)]
136pub enum Dev<'a> {
137    #[doc = "netdev ifindex"]
138    Ifindex(u32),
139    Pad(&'a [u8]),
140    #[doc = "Bitmask of enabled xdp\\-features\\.\nAssociated type: [`XdpAct`] (enum)"]
141    XdpFeatures(u64),
142    #[doc = "max fragment count supported by ZC driver"]
143    XdpZcMaxSegs(u32),
144    #[doc = "Bitmask of supported XDP receive metadata features\\. See Documentation/networking/xdp\\-rx\\-metadata\\.rst for more details\\.\nAssociated type: [`XdpRxMetadata`] (enum)"]
145    XdpRxMetadataFeatures(u64),
146    #[doc = "Bitmask of enabled AF\\_XDP features\\.\nAssociated type: [`XskFlags`] (enum)"]
147    XskFeatures(u64),
148}
149impl<'a> IterableDev<'a> {
150    #[doc = "netdev ifindex"]
151    pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
152        let mut iter = self.clone();
153        iter.pos = 0;
154        for attr in iter {
155            if let Dev::Ifindex(val) = attr? {
156                return Ok(val);
157            }
158        }
159        Err(ErrorContext::new_missing(
160            "Dev",
161            "Ifindex",
162            self.orig_loc,
163            self.buf.as_ptr() as usize,
164        ))
165    }
166    pub fn get_pad(&self) -> Result<&'a [u8], ErrorContext> {
167        let mut iter = self.clone();
168        iter.pos = 0;
169        for attr in iter {
170            if let Dev::Pad(val) = attr? {
171                return Ok(val);
172            }
173        }
174        Err(ErrorContext::new_missing(
175            "Dev",
176            "Pad",
177            self.orig_loc,
178            self.buf.as_ptr() as usize,
179        ))
180    }
181    #[doc = "Bitmask of enabled xdp\\-features\\.\nAssociated type: [`XdpAct`] (enum)"]
182    pub fn get_xdp_features(&self) -> Result<u64, ErrorContext> {
183        let mut iter = self.clone();
184        iter.pos = 0;
185        for attr in iter {
186            if let Dev::XdpFeatures(val) = attr? {
187                return Ok(val);
188            }
189        }
190        Err(ErrorContext::new_missing(
191            "Dev",
192            "XdpFeatures",
193            self.orig_loc,
194            self.buf.as_ptr() as usize,
195        ))
196    }
197    #[doc = "max fragment count supported by ZC driver"]
198    pub fn get_xdp_zc_max_segs(&self) -> Result<u32, ErrorContext> {
199        let mut iter = self.clone();
200        iter.pos = 0;
201        for attr in iter {
202            if let Dev::XdpZcMaxSegs(val) = attr? {
203                return Ok(val);
204            }
205        }
206        Err(ErrorContext::new_missing(
207            "Dev",
208            "XdpZcMaxSegs",
209            self.orig_loc,
210            self.buf.as_ptr() as usize,
211        ))
212    }
213    #[doc = "Bitmask of supported XDP receive metadata features\\. See Documentation/networking/xdp\\-rx\\-metadata\\.rst for more details\\.\nAssociated type: [`XdpRxMetadata`] (enum)"]
214    pub fn get_xdp_rx_metadata_features(&self) -> Result<u64, ErrorContext> {
215        let mut iter = self.clone();
216        iter.pos = 0;
217        for attr in iter {
218            if let Dev::XdpRxMetadataFeatures(val) = attr? {
219                return Ok(val);
220            }
221        }
222        Err(ErrorContext::new_missing(
223            "Dev",
224            "XdpRxMetadataFeatures",
225            self.orig_loc,
226            self.buf.as_ptr() as usize,
227        ))
228    }
229    #[doc = "Bitmask of enabled AF\\_XDP features\\.\nAssociated type: [`XskFlags`] (enum)"]
230    pub fn get_xsk_features(&self) -> Result<u64, ErrorContext> {
231        let mut iter = self.clone();
232        iter.pos = 0;
233        for attr in iter {
234            if let Dev::XskFeatures(val) = attr? {
235                return Ok(val);
236            }
237        }
238        Err(ErrorContext::new_missing(
239            "Dev",
240            "XskFeatures",
241            self.orig_loc,
242            self.buf.as_ptr() as usize,
243        ))
244    }
245}
246impl Dev<'_> {
247    pub fn new<'a>(buf: &'a [u8]) -> IterableDev<'a> {
248        IterableDev::with_loc(buf, buf.as_ptr() as usize)
249    }
250    fn attr_from_type(r#type: u16) -> Option<&'static str> {
251        let res = match r#type {
252            1u16 => "Ifindex",
253            2u16 => "Pad",
254            3u16 => "XdpFeatures",
255            4u16 => "XdpZcMaxSegs",
256            5u16 => "XdpRxMetadataFeatures",
257            6u16 => "XskFeatures",
258            _ => return None,
259        };
260        Some(res)
261    }
262}
263#[derive(Clone, Copy, Default)]
264pub struct IterableDev<'a> {
265    buf: &'a [u8],
266    pos: usize,
267    orig_loc: usize,
268}
269impl<'a> IterableDev<'a> {
270    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
271        Self {
272            buf,
273            pos: 0,
274            orig_loc,
275        }
276    }
277    pub fn get_buf(&self) -> &'a [u8] {
278        self.buf
279    }
280}
281impl<'a> Iterator for IterableDev<'a> {
282    type Item = Result<Dev<'a>, ErrorContext>;
283    fn next(&mut self) -> Option<Self::Item> {
284        let pos = self.pos;
285        let mut r#type;
286        loop {
287            r#type = None;
288            if self.buf.len() == self.pos {
289                return None;
290            }
291            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
292                break;
293            };
294            r#type = Some(header.r#type);
295            let res = match header.r#type {
296                1u16 => Dev::Ifindex({
297                    let res = parse_u32(next);
298                    let Some(val) = res else { break };
299                    val
300                }),
301                2u16 => Dev::Pad({
302                    let res = Some(next);
303                    let Some(val) = res else { break };
304                    val
305                }),
306                3u16 => Dev::XdpFeatures({
307                    let res = parse_u64(next);
308                    let Some(val) = res else { break };
309                    val
310                }),
311                4u16 => Dev::XdpZcMaxSegs({
312                    let res = parse_u32(next);
313                    let Some(val) = res else { break };
314                    val
315                }),
316                5u16 => Dev::XdpRxMetadataFeatures({
317                    let res = parse_u64(next);
318                    let Some(val) = res else { break };
319                    val
320                }),
321                6u16 => Dev::XskFeatures({
322                    let res = parse_u64(next);
323                    let Some(val) = res else { break };
324                    val
325                }),
326                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
327                n => continue,
328            };
329            return Some(Ok(res));
330        }
331        Some(Err(ErrorContext::new(
332            "Dev",
333            r#type.and_then(|t| Dev::attr_from_type(t)),
334            self.orig_loc,
335            self.buf.as_ptr().wrapping_add(pos) as usize,
336        )))
337    }
338}
339impl<'a> std::fmt::Debug for IterableDev<'_> {
340    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
341        let mut fmt = f.debug_struct("Dev");
342        for attr in self.clone() {
343            let attr = match attr {
344                Ok(a) => a,
345                Err(err) => {
346                    fmt.finish()?;
347                    f.write_str("Err(")?;
348                    err.fmt(f)?;
349                    return f.write_str(")");
350                }
351            };
352            match attr {
353                Dev::Ifindex(val) => fmt.field("Ifindex", &val),
354                Dev::Pad(val) => fmt.field("Pad", &val),
355                Dev::XdpFeatures(val) => {
356                    fmt.field("XdpFeatures", &FormatFlags(val.into(), XdpAct::from_value))
357                }
358                Dev::XdpZcMaxSegs(val) => fmt.field("XdpZcMaxSegs", &val),
359                Dev::XdpRxMetadataFeatures(val) => fmt.field(
360                    "XdpRxMetadataFeatures",
361                    &FormatFlags(val.into(), XdpRxMetadata::from_value),
362                ),
363                Dev::XskFeatures(val) => fmt.field(
364                    "XskFeatures",
365                    &FormatFlags(val.into(), XskFlags::from_value),
366                ),
367            };
368        }
369        fmt.finish()
370    }
371}
372impl IterableDev<'_> {
373    pub fn lookup_attr(
374        &self,
375        offset: usize,
376        missing_type: Option<u16>,
377    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
378        let mut stack = Vec::new();
379        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
380        if missing_type.is_some() && cur == offset {
381            stack.push(("Dev", offset));
382            return (stack, missing_type.and_then(|t| Dev::attr_from_type(t)));
383        }
384        if cur > offset || cur + self.buf.len() < offset {
385            return (stack, None);
386        }
387        let mut attrs = self.clone();
388        let mut last_off = cur + attrs.pos;
389        while let Some(attr) = attrs.next() {
390            let Ok(attr) = attr else { break };
391            match attr {
392                Dev::Ifindex(val) => {
393                    if last_off == offset {
394                        stack.push(("Ifindex", last_off));
395                        break;
396                    }
397                }
398                Dev::Pad(val) => {
399                    if last_off == offset {
400                        stack.push(("Pad", last_off));
401                        break;
402                    }
403                }
404                Dev::XdpFeatures(val) => {
405                    if last_off == offset {
406                        stack.push(("XdpFeatures", last_off));
407                        break;
408                    }
409                }
410                Dev::XdpZcMaxSegs(val) => {
411                    if last_off == offset {
412                        stack.push(("XdpZcMaxSegs", last_off));
413                        break;
414                    }
415                }
416                Dev::XdpRxMetadataFeatures(val) => {
417                    if last_off == offset {
418                        stack.push(("XdpRxMetadataFeatures", last_off));
419                        break;
420                    }
421                }
422                Dev::XskFeatures(val) => {
423                    if last_off == offset {
424                        stack.push(("XskFeatures", last_off));
425                        break;
426                    }
427                }
428                _ => {}
429            };
430            last_off = cur + attrs.pos;
431        }
432        if !stack.is_empty() {
433            stack.push(("Dev", cur));
434        }
435        (stack, None)
436    }
437}
438#[derive(Clone)]
439pub enum IoUringProviderInfo {}
440impl<'a> IterableIoUringProviderInfo<'a> {}
441impl IoUringProviderInfo {
442    pub fn new<'a>(buf: &'a [u8]) -> IterableIoUringProviderInfo<'a> {
443        IterableIoUringProviderInfo::with_loc(buf, buf.as_ptr() as usize)
444    }
445    fn attr_from_type(r#type: u16) -> Option<&'static str> {
446        None
447    }
448}
449#[derive(Clone, Copy, Default)]
450pub struct IterableIoUringProviderInfo<'a> {
451    buf: &'a [u8],
452    pos: usize,
453    orig_loc: usize,
454}
455impl<'a> IterableIoUringProviderInfo<'a> {
456    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
457        Self {
458            buf,
459            pos: 0,
460            orig_loc,
461        }
462    }
463    pub fn get_buf(&self) -> &'a [u8] {
464        self.buf
465    }
466}
467impl<'a> Iterator for IterableIoUringProviderInfo<'a> {
468    type Item = Result<IoUringProviderInfo, ErrorContext>;
469    fn next(&mut self) -> Option<Self::Item> {
470        let pos = self.pos;
471        let mut r#type;
472        loop {
473            r#type = None;
474            if self.buf.len() == self.pos {
475                return None;
476            }
477            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
478                break;
479            };
480            r#type = Some(header.r#type);
481            let res = match header.r#type {
482                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
483                n => continue,
484            };
485            return Some(Ok(res));
486        }
487        Some(Err(ErrorContext::new(
488            "IoUringProviderInfo",
489            r#type.and_then(|t| IoUringProviderInfo::attr_from_type(t)),
490            self.orig_loc,
491            self.buf.as_ptr().wrapping_add(pos) as usize,
492        )))
493    }
494}
495impl std::fmt::Debug for IterableIoUringProviderInfo<'_> {
496    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
497        let mut fmt = f.debug_struct("IoUringProviderInfo");
498        for attr in self.clone() {
499            let attr = match attr {
500                Ok(a) => a,
501                Err(err) => {
502                    fmt.finish()?;
503                    f.write_str("Err(")?;
504                    err.fmt(f)?;
505                    return f.write_str(")");
506                }
507            };
508            match attr {};
509        }
510        fmt.finish()
511    }
512}
513impl IterableIoUringProviderInfo<'_> {
514    pub fn lookup_attr(
515        &self,
516        offset: usize,
517        missing_type: Option<u16>,
518    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
519        let mut stack = Vec::new();
520        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
521        if missing_type.is_some() && cur == offset {
522            stack.push(("IoUringProviderInfo", offset));
523            return (
524                stack,
525                missing_type.and_then(|t| IoUringProviderInfo::attr_from_type(t)),
526            );
527        }
528        (stack, None)
529    }
530}
531#[derive(Clone)]
532pub enum PagePool<'a> {
533    #[doc = "Unique ID of a Page Pool instance\\."]
534    Id(u32),
535    #[doc = "ifindex of the netdev to which the pool belongs\\.\nMay not be reported if the page pool was allocated for a netdev\nwhich got destroyed already (page pools may outlast their netdevs\nbecause they wait for all memory to be returned)\\.\n"]
536    Ifindex(u32),
537    #[doc = "Id of NAPI using this Page Pool instance\\."]
538    NapiId(u32),
539    #[doc = "Number of outstanding references to this page pool (allocated\nbut yet to be freed pages)\\. Allocated pages may be held in\nsocket receive queues, driver receive ring, page pool recycling\nring, the page pool cache, etc\\.\n"]
540    Inflight(u32),
541    #[doc = "Amount of memory held by inflight pages\\.\n"]
542    InflightMem(u32),
543    #[doc = "Seconds in CLOCK\\_BOOTTIME of when Page Pool was detached by\nthe driver\\. Once detached Page Pool can no longer be used to\nallocate memory\\.\nPage Pools wait for all the memory allocated from them to be freed\nbefore truly disappearing\\. \"Detached\" Page Pools cannot be\n\"re\\-attached\", they are just waiting to disappear\\.\nAttribute is absent if Page Pool has not been detached, and\ncan still be used to allocate new memory\\.\n"]
544    DetachTime(u32),
545    #[doc = "ID of the dmabuf this page\\-pool is attached to\\."]
546    Dmabuf(u32),
547    #[doc = "io\\-uring memory provider information\\."]
548    IoUring(IterableIoUringProviderInfo<'a>),
549}
550impl<'a> IterablePagePool<'a> {
551    #[doc = "Unique ID of a Page Pool instance\\."]
552    pub fn get_id(&self) -> Result<u32, ErrorContext> {
553        let mut iter = self.clone();
554        iter.pos = 0;
555        for attr in iter {
556            if let PagePool::Id(val) = attr? {
557                return Ok(val);
558            }
559        }
560        Err(ErrorContext::new_missing(
561            "PagePool",
562            "Id",
563            self.orig_loc,
564            self.buf.as_ptr() as usize,
565        ))
566    }
567    #[doc = "ifindex of the netdev to which the pool belongs\\.\nMay not be reported if the page pool was allocated for a netdev\nwhich got destroyed already (page pools may outlast their netdevs\nbecause they wait for all memory to be returned)\\.\n"]
568    pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
569        let mut iter = self.clone();
570        iter.pos = 0;
571        for attr in iter {
572            if let PagePool::Ifindex(val) = attr? {
573                return Ok(val);
574            }
575        }
576        Err(ErrorContext::new_missing(
577            "PagePool",
578            "Ifindex",
579            self.orig_loc,
580            self.buf.as_ptr() as usize,
581        ))
582    }
583    #[doc = "Id of NAPI using this Page Pool instance\\."]
584    pub fn get_napi_id(&self) -> Result<u32, ErrorContext> {
585        let mut iter = self.clone();
586        iter.pos = 0;
587        for attr in iter {
588            if let PagePool::NapiId(val) = attr? {
589                return Ok(val);
590            }
591        }
592        Err(ErrorContext::new_missing(
593            "PagePool",
594            "NapiId",
595            self.orig_loc,
596            self.buf.as_ptr() as usize,
597        ))
598    }
599    #[doc = "Number of outstanding references to this page pool (allocated\nbut yet to be freed pages)\\. Allocated pages may be held in\nsocket receive queues, driver receive ring, page pool recycling\nring, the page pool cache, etc\\.\n"]
600    pub fn get_inflight(&self) -> Result<u32, ErrorContext> {
601        let mut iter = self.clone();
602        iter.pos = 0;
603        for attr in iter {
604            if let PagePool::Inflight(val) = attr? {
605                return Ok(val);
606            }
607        }
608        Err(ErrorContext::new_missing(
609            "PagePool",
610            "Inflight",
611            self.orig_loc,
612            self.buf.as_ptr() as usize,
613        ))
614    }
615    #[doc = "Amount of memory held by inflight pages\\.\n"]
616    pub fn get_inflight_mem(&self) -> Result<u32, ErrorContext> {
617        let mut iter = self.clone();
618        iter.pos = 0;
619        for attr in iter {
620            if let PagePool::InflightMem(val) = attr? {
621                return Ok(val);
622            }
623        }
624        Err(ErrorContext::new_missing(
625            "PagePool",
626            "InflightMem",
627            self.orig_loc,
628            self.buf.as_ptr() as usize,
629        ))
630    }
631    #[doc = "Seconds in CLOCK\\_BOOTTIME of when Page Pool was detached by\nthe driver\\. Once detached Page Pool can no longer be used to\nallocate memory\\.\nPage Pools wait for all the memory allocated from them to be freed\nbefore truly disappearing\\. \"Detached\" Page Pools cannot be\n\"re\\-attached\", they are just waiting to disappear\\.\nAttribute is absent if Page Pool has not been detached, and\ncan still be used to allocate new memory\\.\n"]
632    pub fn get_detach_time(&self) -> Result<u32, ErrorContext> {
633        let mut iter = self.clone();
634        iter.pos = 0;
635        for attr in iter {
636            if let PagePool::DetachTime(val) = attr? {
637                return Ok(val);
638            }
639        }
640        Err(ErrorContext::new_missing(
641            "PagePool",
642            "DetachTime",
643            self.orig_loc,
644            self.buf.as_ptr() as usize,
645        ))
646    }
647    #[doc = "ID of the dmabuf this page\\-pool is attached to\\."]
648    pub fn get_dmabuf(&self) -> Result<u32, ErrorContext> {
649        let mut iter = self.clone();
650        iter.pos = 0;
651        for attr in iter {
652            if let PagePool::Dmabuf(val) = attr? {
653                return Ok(val);
654            }
655        }
656        Err(ErrorContext::new_missing(
657            "PagePool",
658            "Dmabuf",
659            self.orig_loc,
660            self.buf.as_ptr() as usize,
661        ))
662    }
663    #[doc = "io\\-uring memory provider information\\."]
664    pub fn get_io_uring(&self) -> Result<IterableIoUringProviderInfo<'a>, ErrorContext> {
665        let mut iter = self.clone();
666        iter.pos = 0;
667        for attr in iter {
668            if let PagePool::IoUring(val) = attr? {
669                return Ok(val);
670            }
671        }
672        Err(ErrorContext::new_missing(
673            "PagePool",
674            "IoUring",
675            self.orig_loc,
676            self.buf.as_ptr() as usize,
677        ))
678    }
679}
680impl PagePool<'_> {
681    pub fn new<'a>(buf: &'a [u8]) -> IterablePagePool<'a> {
682        IterablePagePool::with_loc(buf, buf.as_ptr() as usize)
683    }
684    fn attr_from_type(r#type: u16) -> Option<&'static str> {
685        let res = match r#type {
686            1u16 => "Id",
687            2u16 => "Ifindex",
688            3u16 => "NapiId",
689            4u16 => "Inflight",
690            5u16 => "InflightMem",
691            6u16 => "DetachTime",
692            7u16 => "Dmabuf",
693            8u16 => "IoUring",
694            _ => return None,
695        };
696        Some(res)
697    }
698}
699#[derive(Clone, Copy, Default)]
700pub struct IterablePagePool<'a> {
701    buf: &'a [u8],
702    pos: usize,
703    orig_loc: usize,
704}
705impl<'a> IterablePagePool<'a> {
706    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
707        Self {
708            buf,
709            pos: 0,
710            orig_loc,
711        }
712    }
713    pub fn get_buf(&self) -> &'a [u8] {
714        self.buf
715    }
716}
717impl<'a> Iterator for IterablePagePool<'a> {
718    type Item = Result<PagePool<'a>, ErrorContext>;
719    fn next(&mut self) -> Option<Self::Item> {
720        let pos = self.pos;
721        let mut r#type;
722        loop {
723            r#type = None;
724            if self.buf.len() == self.pos {
725                return None;
726            }
727            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
728                break;
729            };
730            r#type = Some(header.r#type);
731            let res = match header.r#type {
732                1u16 => PagePool::Id({
733                    let res = parse_u32(next);
734                    let Some(val) = res else { break };
735                    val
736                }),
737                2u16 => PagePool::Ifindex({
738                    let res = parse_u32(next);
739                    let Some(val) = res else { break };
740                    val
741                }),
742                3u16 => PagePool::NapiId({
743                    let res = parse_u32(next);
744                    let Some(val) = res else { break };
745                    val
746                }),
747                4u16 => PagePool::Inflight({
748                    let res = parse_u32(next);
749                    let Some(val) = res else { break };
750                    val
751                }),
752                5u16 => PagePool::InflightMem({
753                    let res = parse_u32(next);
754                    let Some(val) = res else { break };
755                    val
756                }),
757                6u16 => PagePool::DetachTime({
758                    let res = parse_u32(next);
759                    let Some(val) = res else { break };
760                    val
761                }),
762                7u16 => PagePool::Dmabuf({
763                    let res = parse_u32(next);
764                    let Some(val) = res else { break };
765                    val
766                }),
767                8u16 => PagePool::IoUring({
768                    let res = Some(IterableIoUringProviderInfo::with_loc(next, self.orig_loc));
769                    let Some(val) = res else { break };
770                    val
771                }),
772                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
773                n => continue,
774            };
775            return Some(Ok(res));
776        }
777        Some(Err(ErrorContext::new(
778            "PagePool",
779            r#type.and_then(|t| PagePool::attr_from_type(t)),
780            self.orig_loc,
781            self.buf.as_ptr().wrapping_add(pos) as usize,
782        )))
783    }
784}
785impl<'a> std::fmt::Debug for IterablePagePool<'_> {
786    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
787        let mut fmt = f.debug_struct("PagePool");
788        for attr in self.clone() {
789            let attr = match attr {
790                Ok(a) => a,
791                Err(err) => {
792                    fmt.finish()?;
793                    f.write_str("Err(")?;
794                    err.fmt(f)?;
795                    return f.write_str(")");
796                }
797            };
798            match attr {
799                PagePool::Id(val) => fmt.field("Id", &val),
800                PagePool::Ifindex(val) => fmt.field("Ifindex", &val),
801                PagePool::NapiId(val) => fmt.field("NapiId", &val),
802                PagePool::Inflight(val) => fmt.field("Inflight", &val),
803                PagePool::InflightMem(val) => fmt.field("InflightMem", &val),
804                PagePool::DetachTime(val) => fmt.field("DetachTime", &val),
805                PagePool::Dmabuf(val) => fmt.field("Dmabuf", &val),
806                PagePool::IoUring(val) => fmt.field("IoUring", &val),
807            };
808        }
809        fmt.finish()
810    }
811}
812impl IterablePagePool<'_> {
813    pub fn lookup_attr(
814        &self,
815        offset: usize,
816        missing_type: Option<u16>,
817    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
818        let mut stack = Vec::new();
819        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
820        if missing_type.is_some() && cur == offset {
821            stack.push(("PagePool", offset));
822            return (
823                stack,
824                missing_type.and_then(|t| PagePool::attr_from_type(t)),
825            );
826        }
827        if cur > offset || cur + self.buf.len() < offset {
828            return (stack, None);
829        }
830        let mut attrs = self.clone();
831        let mut last_off = cur + attrs.pos;
832        let mut missing = None;
833        while let Some(attr) = attrs.next() {
834            let Ok(attr) = attr else { break };
835            match attr {
836                PagePool::Id(val) => {
837                    if last_off == offset {
838                        stack.push(("Id", last_off));
839                        break;
840                    }
841                }
842                PagePool::Ifindex(val) => {
843                    if last_off == offset {
844                        stack.push(("Ifindex", last_off));
845                        break;
846                    }
847                }
848                PagePool::NapiId(val) => {
849                    if last_off == offset {
850                        stack.push(("NapiId", last_off));
851                        break;
852                    }
853                }
854                PagePool::Inflight(val) => {
855                    if last_off == offset {
856                        stack.push(("Inflight", last_off));
857                        break;
858                    }
859                }
860                PagePool::InflightMem(val) => {
861                    if last_off == offset {
862                        stack.push(("InflightMem", last_off));
863                        break;
864                    }
865                }
866                PagePool::DetachTime(val) => {
867                    if last_off == offset {
868                        stack.push(("DetachTime", last_off));
869                        break;
870                    }
871                }
872                PagePool::Dmabuf(val) => {
873                    if last_off == offset {
874                        stack.push(("Dmabuf", last_off));
875                        break;
876                    }
877                }
878                PagePool::IoUring(val) => {
879                    (stack, missing) = val.lookup_attr(offset, missing_type);
880                    if !stack.is_empty() {
881                        break;
882                    }
883                }
884                _ => {}
885            };
886            last_off = cur + attrs.pos;
887        }
888        if !stack.is_empty() {
889            stack.push(("PagePool", cur));
890        }
891        (stack, missing)
892    }
893}
894#[derive(Clone)]
895pub enum PagePoolInfo {
896    #[doc = "Unique ID of a Page Pool instance\\."]
897    Id(u32),
898    #[doc = "ifindex of the netdev to which the pool belongs\\.\nMay not be reported if the page pool was allocated for a netdev\nwhich got destroyed already (page pools may outlast their netdevs\nbecause they wait for all memory to be returned)\\.\n"]
899    Ifindex(u32),
900}
901impl<'a> IterablePagePoolInfo<'a> {
902    #[doc = "Unique ID of a Page Pool instance\\."]
903    pub fn get_id(&self) -> Result<u32, ErrorContext> {
904        let mut iter = self.clone();
905        iter.pos = 0;
906        for attr in iter {
907            if let PagePoolInfo::Id(val) = attr? {
908                return Ok(val);
909            }
910        }
911        Err(ErrorContext::new_missing(
912            "PagePoolInfo",
913            "Id",
914            self.orig_loc,
915            self.buf.as_ptr() as usize,
916        ))
917    }
918    #[doc = "ifindex of the netdev to which the pool belongs\\.\nMay not be reported if the page pool was allocated for a netdev\nwhich got destroyed already (page pools may outlast their netdevs\nbecause they wait for all memory to be returned)\\.\n"]
919    pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
920        let mut iter = self.clone();
921        iter.pos = 0;
922        for attr in iter {
923            if let PagePoolInfo::Ifindex(val) = attr? {
924                return Ok(val);
925            }
926        }
927        Err(ErrorContext::new_missing(
928            "PagePoolInfo",
929            "Ifindex",
930            self.orig_loc,
931            self.buf.as_ptr() as usize,
932        ))
933    }
934}
935impl PagePoolInfo {
936    pub fn new<'a>(buf: &'a [u8]) -> IterablePagePoolInfo<'a> {
937        IterablePagePoolInfo::with_loc(buf, buf.as_ptr() as usize)
938    }
939    fn attr_from_type(r#type: u16) -> Option<&'static str> {
940        PagePool::attr_from_type(r#type)
941    }
942}
943#[derive(Clone, Copy, Default)]
944pub struct IterablePagePoolInfo<'a> {
945    buf: &'a [u8],
946    pos: usize,
947    orig_loc: usize,
948}
949impl<'a> IterablePagePoolInfo<'a> {
950    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
951        Self {
952            buf,
953            pos: 0,
954            orig_loc,
955        }
956    }
957    pub fn get_buf(&self) -> &'a [u8] {
958        self.buf
959    }
960}
961impl<'a> Iterator for IterablePagePoolInfo<'a> {
962    type Item = Result<PagePoolInfo, ErrorContext>;
963    fn next(&mut self) -> Option<Self::Item> {
964        let pos = self.pos;
965        let mut r#type;
966        loop {
967            r#type = None;
968            if self.buf.len() == self.pos {
969                return None;
970            }
971            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
972                break;
973            };
974            r#type = Some(header.r#type);
975            let res = match header.r#type {
976                1u16 => PagePoolInfo::Id({
977                    let res = parse_u32(next);
978                    let Some(val) = res else { break };
979                    val
980                }),
981                2u16 => PagePoolInfo::Ifindex({
982                    let res = parse_u32(next);
983                    let Some(val) = res else { break };
984                    val
985                }),
986                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
987                n => continue,
988            };
989            return Some(Ok(res));
990        }
991        Some(Err(ErrorContext::new(
992            "PagePoolInfo",
993            r#type.and_then(|t| PagePoolInfo::attr_from_type(t)),
994            self.orig_loc,
995            self.buf.as_ptr().wrapping_add(pos) as usize,
996        )))
997    }
998}
999impl std::fmt::Debug for IterablePagePoolInfo<'_> {
1000    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1001        let mut fmt = f.debug_struct("PagePoolInfo");
1002        for attr in self.clone() {
1003            let attr = match attr {
1004                Ok(a) => a,
1005                Err(err) => {
1006                    fmt.finish()?;
1007                    f.write_str("Err(")?;
1008                    err.fmt(f)?;
1009                    return f.write_str(")");
1010                }
1011            };
1012            match attr {
1013                PagePoolInfo::Id(val) => fmt.field("Id", &val),
1014                PagePoolInfo::Ifindex(val) => fmt.field("Ifindex", &val),
1015            };
1016        }
1017        fmt.finish()
1018    }
1019}
1020impl IterablePagePoolInfo<'_> {
1021    pub fn lookup_attr(
1022        &self,
1023        offset: usize,
1024        missing_type: Option<u16>,
1025    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
1026        let mut stack = Vec::new();
1027        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
1028        if missing_type.is_some() && cur == offset {
1029            stack.push(("PagePoolInfo", offset));
1030            return (
1031                stack,
1032                missing_type.and_then(|t| PagePoolInfo::attr_from_type(t)),
1033            );
1034        }
1035        if cur > offset || cur + self.buf.len() < offset {
1036            return (stack, None);
1037        }
1038        let mut attrs = self.clone();
1039        let mut last_off = cur + attrs.pos;
1040        while let Some(attr) = attrs.next() {
1041            let Ok(attr) = attr else { break };
1042            match attr {
1043                PagePoolInfo::Id(val) => {
1044                    if last_off == offset {
1045                        stack.push(("Id", last_off));
1046                        break;
1047                    }
1048                }
1049                PagePoolInfo::Ifindex(val) => {
1050                    if last_off == offset {
1051                        stack.push(("Ifindex", last_off));
1052                        break;
1053                    }
1054                }
1055                _ => {}
1056            };
1057            last_off = cur + attrs.pos;
1058        }
1059        if !stack.is_empty() {
1060            stack.push(("PagePoolInfo", cur));
1061        }
1062        (stack, None)
1063    }
1064}
1065#[derive(Clone)]
1066pub enum PagePoolStats<'a> {
1067    #[doc = "Page pool identifying information\\."]
1068    Info(IterablePagePoolInfo<'a>),
1069    AllocFast(u32),
1070    AllocSlow(u32),
1071    AllocSlowHighOrder(u32),
1072    AllocEmpty(u32),
1073    AllocRefill(u32),
1074    AllocWaive(u32),
1075    RecycleCached(u32),
1076    RecycleCacheFull(u32),
1077    RecycleRing(u32),
1078    RecycleRingFull(u32),
1079    RecycleReleasedRefcnt(u32),
1080}
1081impl<'a> IterablePagePoolStats<'a> {
1082    #[doc = "Page pool identifying information\\."]
1083    pub fn get_info(&self) -> Result<IterablePagePoolInfo<'a>, ErrorContext> {
1084        let mut iter = self.clone();
1085        iter.pos = 0;
1086        for attr in iter {
1087            if let PagePoolStats::Info(val) = attr? {
1088                return Ok(val);
1089            }
1090        }
1091        Err(ErrorContext::new_missing(
1092            "PagePoolStats",
1093            "Info",
1094            self.orig_loc,
1095            self.buf.as_ptr() as usize,
1096        ))
1097    }
1098    pub fn get_alloc_fast(&self) -> Result<u32, ErrorContext> {
1099        let mut iter = self.clone();
1100        iter.pos = 0;
1101        for attr in iter {
1102            if let PagePoolStats::AllocFast(val) = attr? {
1103                return Ok(val);
1104            }
1105        }
1106        Err(ErrorContext::new_missing(
1107            "PagePoolStats",
1108            "AllocFast",
1109            self.orig_loc,
1110            self.buf.as_ptr() as usize,
1111        ))
1112    }
1113    pub fn get_alloc_slow(&self) -> Result<u32, ErrorContext> {
1114        let mut iter = self.clone();
1115        iter.pos = 0;
1116        for attr in iter {
1117            if let PagePoolStats::AllocSlow(val) = attr? {
1118                return Ok(val);
1119            }
1120        }
1121        Err(ErrorContext::new_missing(
1122            "PagePoolStats",
1123            "AllocSlow",
1124            self.orig_loc,
1125            self.buf.as_ptr() as usize,
1126        ))
1127    }
1128    pub fn get_alloc_slow_high_order(&self) -> Result<u32, ErrorContext> {
1129        let mut iter = self.clone();
1130        iter.pos = 0;
1131        for attr in iter {
1132            if let PagePoolStats::AllocSlowHighOrder(val) = attr? {
1133                return Ok(val);
1134            }
1135        }
1136        Err(ErrorContext::new_missing(
1137            "PagePoolStats",
1138            "AllocSlowHighOrder",
1139            self.orig_loc,
1140            self.buf.as_ptr() as usize,
1141        ))
1142    }
1143    pub fn get_alloc_empty(&self) -> Result<u32, ErrorContext> {
1144        let mut iter = self.clone();
1145        iter.pos = 0;
1146        for attr in iter {
1147            if let PagePoolStats::AllocEmpty(val) = attr? {
1148                return Ok(val);
1149            }
1150        }
1151        Err(ErrorContext::new_missing(
1152            "PagePoolStats",
1153            "AllocEmpty",
1154            self.orig_loc,
1155            self.buf.as_ptr() as usize,
1156        ))
1157    }
1158    pub fn get_alloc_refill(&self) -> Result<u32, ErrorContext> {
1159        let mut iter = self.clone();
1160        iter.pos = 0;
1161        for attr in iter {
1162            if let PagePoolStats::AllocRefill(val) = attr? {
1163                return Ok(val);
1164            }
1165        }
1166        Err(ErrorContext::new_missing(
1167            "PagePoolStats",
1168            "AllocRefill",
1169            self.orig_loc,
1170            self.buf.as_ptr() as usize,
1171        ))
1172    }
1173    pub fn get_alloc_waive(&self) -> Result<u32, ErrorContext> {
1174        let mut iter = self.clone();
1175        iter.pos = 0;
1176        for attr in iter {
1177            if let PagePoolStats::AllocWaive(val) = attr? {
1178                return Ok(val);
1179            }
1180        }
1181        Err(ErrorContext::new_missing(
1182            "PagePoolStats",
1183            "AllocWaive",
1184            self.orig_loc,
1185            self.buf.as_ptr() as usize,
1186        ))
1187    }
1188    pub fn get_recycle_cached(&self) -> Result<u32, ErrorContext> {
1189        let mut iter = self.clone();
1190        iter.pos = 0;
1191        for attr in iter {
1192            if let PagePoolStats::RecycleCached(val) = attr? {
1193                return Ok(val);
1194            }
1195        }
1196        Err(ErrorContext::new_missing(
1197            "PagePoolStats",
1198            "RecycleCached",
1199            self.orig_loc,
1200            self.buf.as_ptr() as usize,
1201        ))
1202    }
1203    pub fn get_recycle_cache_full(&self) -> Result<u32, ErrorContext> {
1204        let mut iter = self.clone();
1205        iter.pos = 0;
1206        for attr in iter {
1207            if let PagePoolStats::RecycleCacheFull(val) = attr? {
1208                return Ok(val);
1209            }
1210        }
1211        Err(ErrorContext::new_missing(
1212            "PagePoolStats",
1213            "RecycleCacheFull",
1214            self.orig_loc,
1215            self.buf.as_ptr() as usize,
1216        ))
1217    }
1218    pub fn get_recycle_ring(&self) -> Result<u32, ErrorContext> {
1219        let mut iter = self.clone();
1220        iter.pos = 0;
1221        for attr in iter {
1222            if let PagePoolStats::RecycleRing(val) = attr? {
1223                return Ok(val);
1224            }
1225        }
1226        Err(ErrorContext::new_missing(
1227            "PagePoolStats",
1228            "RecycleRing",
1229            self.orig_loc,
1230            self.buf.as_ptr() as usize,
1231        ))
1232    }
1233    pub fn get_recycle_ring_full(&self) -> Result<u32, ErrorContext> {
1234        let mut iter = self.clone();
1235        iter.pos = 0;
1236        for attr in iter {
1237            if let PagePoolStats::RecycleRingFull(val) = attr? {
1238                return Ok(val);
1239            }
1240        }
1241        Err(ErrorContext::new_missing(
1242            "PagePoolStats",
1243            "RecycleRingFull",
1244            self.orig_loc,
1245            self.buf.as_ptr() as usize,
1246        ))
1247    }
1248    pub fn get_recycle_released_refcnt(&self) -> Result<u32, ErrorContext> {
1249        let mut iter = self.clone();
1250        iter.pos = 0;
1251        for attr in iter {
1252            if let PagePoolStats::RecycleReleasedRefcnt(val) = attr? {
1253                return Ok(val);
1254            }
1255        }
1256        Err(ErrorContext::new_missing(
1257            "PagePoolStats",
1258            "RecycleReleasedRefcnt",
1259            self.orig_loc,
1260            self.buf.as_ptr() as usize,
1261        ))
1262    }
1263}
1264impl PagePoolStats<'_> {
1265    pub fn new<'a>(buf: &'a [u8]) -> IterablePagePoolStats<'a> {
1266        IterablePagePoolStats::with_loc(buf, buf.as_ptr() as usize)
1267    }
1268    fn attr_from_type(r#type: u16) -> Option<&'static str> {
1269        let res = match r#type {
1270            1u16 => "Info",
1271            8u16 => "AllocFast",
1272            9u16 => "AllocSlow",
1273            10u16 => "AllocSlowHighOrder",
1274            11u16 => "AllocEmpty",
1275            12u16 => "AllocRefill",
1276            13u16 => "AllocWaive",
1277            14u16 => "RecycleCached",
1278            15u16 => "RecycleCacheFull",
1279            16u16 => "RecycleRing",
1280            17u16 => "RecycleRingFull",
1281            18u16 => "RecycleReleasedRefcnt",
1282            _ => return None,
1283        };
1284        Some(res)
1285    }
1286}
1287#[derive(Clone, Copy, Default)]
1288pub struct IterablePagePoolStats<'a> {
1289    buf: &'a [u8],
1290    pos: usize,
1291    orig_loc: usize,
1292}
1293impl<'a> IterablePagePoolStats<'a> {
1294    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
1295        Self {
1296            buf,
1297            pos: 0,
1298            orig_loc,
1299        }
1300    }
1301    pub fn get_buf(&self) -> &'a [u8] {
1302        self.buf
1303    }
1304}
1305impl<'a> Iterator for IterablePagePoolStats<'a> {
1306    type Item = Result<PagePoolStats<'a>, ErrorContext>;
1307    fn next(&mut self) -> Option<Self::Item> {
1308        let pos = self.pos;
1309        let mut r#type;
1310        loop {
1311            r#type = None;
1312            if self.buf.len() == self.pos {
1313                return None;
1314            }
1315            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
1316                break;
1317            };
1318            r#type = Some(header.r#type);
1319            let res = match header.r#type {
1320                1u16 => PagePoolStats::Info({
1321                    let res = Some(IterablePagePoolInfo::with_loc(next, self.orig_loc));
1322                    let Some(val) = res else { break };
1323                    val
1324                }),
1325                8u16 => PagePoolStats::AllocFast({
1326                    let res = parse_u32(next);
1327                    let Some(val) = res else { break };
1328                    val
1329                }),
1330                9u16 => PagePoolStats::AllocSlow({
1331                    let res = parse_u32(next);
1332                    let Some(val) = res else { break };
1333                    val
1334                }),
1335                10u16 => PagePoolStats::AllocSlowHighOrder({
1336                    let res = parse_u32(next);
1337                    let Some(val) = res else { break };
1338                    val
1339                }),
1340                11u16 => PagePoolStats::AllocEmpty({
1341                    let res = parse_u32(next);
1342                    let Some(val) = res else { break };
1343                    val
1344                }),
1345                12u16 => PagePoolStats::AllocRefill({
1346                    let res = parse_u32(next);
1347                    let Some(val) = res else { break };
1348                    val
1349                }),
1350                13u16 => PagePoolStats::AllocWaive({
1351                    let res = parse_u32(next);
1352                    let Some(val) = res else { break };
1353                    val
1354                }),
1355                14u16 => PagePoolStats::RecycleCached({
1356                    let res = parse_u32(next);
1357                    let Some(val) = res else { break };
1358                    val
1359                }),
1360                15u16 => PagePoolStats::RecycleCacheFull({
1361                    let res = parse_u32(next);
1362                    let Some(val) = res else { break };
1363                    val
1364                }),
1365                16u16 => PagePoolStats::RecycleRing({
1366                    let res = parse_u32(next);
1367                    let Some(val) = res else { break };
1368                    val
1369                }),
1370                17u16 => PagePoolStats::RecycleRingFull({
1371                    let res = parse_u32(next);
1372                    let Some(val) = res else { break };
1373                    val
1374                }),
1375                18u16 => PagePoolStats::RecycleReleasedRefcnt({
1376                    let res = parse_u32(next);
1377                    let Some(val) = res else { break };
1378                    val
1379                }),
1380                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
1381                n => continue,
1382            };
1383            return Some(Ok(res));
1384        }
1385        Some(Err(ErrorContext::new(
1386            "PagePoolStats",
1387            r#type.and_then(|t| PagePoolStats::attr_from_type(t)),
1388            self.orig_loc,
1389            self.buf.as_ptr().wrapping_add(pos) as usize,
1390        )))
1391    }
1392}
1393impl<'a> std::fmt::Debug for IterablePagePoolStats<'_> {
1394    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1395        let mut fmt = f.debug_struct("PagePoolStats");
1396        for attr in self.clone() {
1397            let attr = match attr {
1398                Ok(a) => a,
1399                Err(err) => {
1400                    fmt.finish()?;
1401                    f.write_str("Err(")?;
1402                    err.fmt(f)?;
1403                    return f.write_str(")");
1404                }
1405            };
1406            match attr {
1407                PagePoolStats::Info(val) => fmt.field("Info", &val),
1408                PagePoolStats::AllocFast(val) => fmt.field("AllocFast", &val),
1409                PagePoolStats::AllocSlow(val) => fmt.field("AllocSlow", &val),
1410                PagePoolStats::AllocSlowHighOrder(val) => fmt.field("AllocSlowHighOrder", &val),
1411                PagePoolStats::AllocEmpty(val) => fmt.field("AllocEmpty", &val),
1412                PagePoolStats::AllocRefill(val) => fmt.field("AllocRefill", &val),
1413                PagePoolStats::AllocWaive(val) => fmt.field("AllocWaive", &val),
1414                PagePoolStats::RecycleCached(val) => fmt.field("RecycleCached", &val),
1415                PagePoolStats::RecycleCacheFull(val) => fmt.field("RecycleCacheFull", &val),
1416                PagePoolStats::RecycleRing(val) => fmt.field("RecycleRing", &val),
1417                PagePoolStats::RecycleRingFull(val) => fmt.field("RecycleRingFull", &val),
1418                PagePoolStats::RecycleReleasedRefcnt(val) => {
1419                    fmt.field("RecycleReleasedRefcnt", &val)
1420                }
1421            };
1422        }
1423        fmt.finish()
1424    }
1425}
1426impl IterablePagePoolStats<'_> {
1427    pub fn lookup_attr(
1428        &self,
1429        offset: usize,
1430        missing_type: Option<u16>,
1431    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
1432        let mut stack = Vec::new();
1433        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
1434        if missing_type.is_some() && cur == offset {
1435            stack.push(("PagePoolStats", offset));
1436            return (
1437                stack,
1438                missing_type.and_then(|t| PagePoolStats::attr_from_type(t)),
1439            );
1440        }
1441        if cur > offset || cur + self.buf.len() < offset {
1442            return (stack, None);
1443        }
1444        let mut attrs = self.clone();
1445        let mut last_off = cur + attrs.pos;
1446        let mut missing = None;
1447        while let Some(attr) = attrs.next() {
1448            let Ok(attr) = attr else { break };
1449            match attr {
1450                PagePoolStats::Info(val) => {
1451                    (stack, missing) = val.lookup_attr(offset, missing_type);
1452                    if !stack.is_empty() {
1453                        break;
1454                    }
1455                }
1456                PagePoolStats::AllocFast(val) => {
1457                    if last_off == offset {
1458                        stack.push(("AllocFast", last_off));
1459                        break;
1460                    }
1461                }
1462                PagePoolStats::AllocSlow(val) => {
1463                    if last_off == offset {
1464                        stack.push(("AllocSlow", last_off));
1465                        break;
1466                    }
1467                }
1468                PagePoolStats::AllocSlowHighOrder(val) => {
1469                    if last_off == offset {
1470                        stack.push(("AllocSlowHighOrder", last_off));
1471                        break;
1472                    }
1473                }
1474                PagePoolStats::AllocEmpty(val) => {
1475                    if last_off == offset {
1476                        stack.push(("AllocEmpty", last_off));
1477                        break;
1478                    }
1479                }
1480                PagePoolStats::AllocRefill(val) => {
1481                    if last_off == offset {
1482                        stack.push(("AllocRefill", last_off));
1483                        break;
1484                    }
1485                }
1486                PagePoolStats::AllocWaive(val) => {
1487                    if last_off == offset {
1488                        stack.push(("AllocWaive", last_off));
1489                        break;
1490                    }
1491                }
1492                PagePoolStats::RecycleCached(val) => {
1493                    if last_off == offset {
1494                        stack.push(("RecycleCached", last_off));
1495                        break;
1496                    }
1497                }
1498                PagePoolStats::RecycleCacheFull(val) => {
1499                    if last_off == offset {
1500                        stack.push(("RecycleCacheFull", last_off));
1501                        break;
1502                    }
1503                }
1504                PagePoolStats::RecycleRing(val) => {
1505                    if last_off == offset {
1506                        stack.push(("RecycleRing", last_off));
1507                        break;
1508                    }
1509                }
1510                PagePoolStats::RecycleRingFull(val) => {
1511                    if last_off == offset {
1512                        stack.push(("RecycleRingFull", last_off));
1513                        break;
1514                    }
1515                }
1516                PagePoolStats::RecycleReleasedRefcnt(val) => {
1517                    if last_off == offset {
1518                        stack.push(("RecycleReleasedRefcnt", last_off));
1519                        break;
1520                    }
1521                }
1522                _ => {}
1523            };
1524            last_off = cur + attrs.pos;
1525        }
1526        if !stack.is_empty() {
1527            stack.push(("PagePoolStats", cur));
1528        }
1529        (stack, missing)
1530    }
1531}
1532#[derive(Clone)]
1533pub enum Napi {
1534    #[doc = "ifindex of the netdevice to which NAPI instance belongs\\."]
1535    Ifindex(u32),
1536    #[doc = "ID of the NAPI instance\\."]
1537    Id(u32),
1538    #[doc = "The associated interrupt vector number for the napi"]
1539    Irq(u32),
1540    #[doc = "PID of the napi thread, if NAPI is configured to operate in threaded mode\\. If NAPI is not in threaded mode (i\\.e\\. uses normal softirq context), the attribute will be absent\\."]
1541    Pid(u32),
1542    #[doc = "The number of consecutive empty polls before IRQ deferral ends and hardware IRQs are re\\-enabled\\."]
1543    DeferHardIrqs(u32),
1544    #[doc = "The timeout, in nanoseconds, of when to trigger the NAPI watchdog timer which schedules NAPI processing\\. Additionally, a non\\-zero value will also prevent GRO from flushing recent super\\-frames at the end of a NAPI cycle\\. This may add receive latency in exchange for reducing the number of frames processed by the network stack\\."]
1545    GroFlushTimeout(u32),
1546    #[doc = "The timeout, in nanoseconds, of how long to suspend irq processing, if event polling finds events"]
1547    IrqSuspendTimeout(u32),
1548    #[doc = "Whether the NAPI is configured to operate in threaded polling mode\\. If this is set to enabled then the NAPI context operates in threaded polling mode\\. If this is set to busy\\-poll, then the threaded polling mode also busy polls\\.\nAssociated type: [`NapiThreaded`] (enum)"]
1549    Threaded(u32),
1550}
1551impl<'a> IterableNapi<'a> {
1552    #[doc = "ifindex of the netdevice to which NAPI instance belongs\\."]
1553    pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
1554        let mut iter = self.clone();
1555        iter.pos = 0;
1556        for attr in iter {
1557            if let Napi::Ifindex(val) = attr? {
1558                return Ok(val);
1559            }
1560        }
1561        Err(ErrorContext::new_missing(
1562            "Napi",
1563            "Ifindex",
1564            self.orig_loc,
1565            self.buf.as_ptr() as usize,
1566        ))
1567    }
1568    #[doc = "ID of the NAPI instance\\."]
1569    pub fn get_id(&self) -> Result<u32, ErrorContext> {
1570        let mut iter = self.clone();
1571        iter.pos = 0;
1572        for attr in iter {
1573            if let Napi::Id(val) = attr? {
1574                return Ok(val);
1575            }
1576        }
1577        Err(ErrorContext::new_missing(
1578            "Napi",
1579            "Id",
1580            self.orig_loc,
1581            self.buf.as_ptr() as usize,
1582        ))
1583    }
1584    #[doc = "The associated interrupt vector number for the napi"]
1585    pub fn get_irq(&self) -> Result<u32, ErrorContext> {
1586        let mut iter = self.clone();
1587        iter.pos = 0;
1588        for attr in iter {
1589            if let Napi::Irq(val) = attr? {
1590                return Ok(val);
1591            }
1592        }
1593        Err(ErrorContext::new_missing(
1594            "Napi",
1595            "Irq",
1596            self.orig_loc,
1597            self.buf.as_ptr() as usize,
1598        ))
1599    }
1600    #[doc = "PID of the napi thread, if NAPI is configured to operate in threaded mode\\. If NAPI is not in threaded mode (i\\.e\\. uses normal softirq context), the attribute will be absent\\."]
1601    pub fn get_pid(&self) -> Result<u32, ErrorContext> {
1602        let mut iter = self.clone();
1603        iter.pos = 0;
1604        for attr in iter {
1605            if let Napi::Pid(val) = attr? {
1606                return Ok(val);
1607            }
1608        }
1609        Err(ErrorContext::new_missing(
1610            "Napi",
1611            "Pid",
1612            self.orig_loc,
1613            self.buf.as_ptr() as usize,
1614        ))
1615    }
1616    #[doc = "The number of consecutive empty polls before IRQ deferral ends and hardware IRQs are re\\-enabled\\."]
1617    pub fn get_defer_hard_irqs(&self) -> Result<u32, ErrorContext> {
1618        let mut iter = self.clone();
1619        iter.pos = 0;
1620        for attr in iter {
1621            if let Napi::DeferHardIrqs(val) = attr? {
1622                return Ok(val);
1623            }
1624        }
1625        Err(ErrorContext::new_missing(
1626            "Napi",
1627            "DeferHardIrqs",
1628            self.orig_loc,
1629            self.buf.as_ptr() as usize,
1630        ))
1631    }
1632    #[doc = "The timeout, in nanoseconds, of when to trigger the NAPI watchdog timer which schedules NAPI processing\\. Additionally, a non\\-zero value will also prevent GRO from flushing recent super\\-frames at the end of a NAPI cycle\\. This may add receive latency in exchange for reducing the number of frames processed by the network stack\\."]
1633    pub fn get_gro_flush_timeout(&self) -> Result<u32, ErrorContext> {
1634        let mut iter = self.clone();
1635        iter.pos = 0;
1636        for attr in iter {
1637            if let Napi::GroFlushTimeout(val) = attr? {
1638                return Ok(val);
1639            }
1640        }
1641        Err(ErrorContext::new_missing(
1642            "Napi",
1643            "GroFlushTimeout",
1644            self.orig_loc,
1645            self.buf.as_ptr() as usize,
1646        ))
1647    }
1648    #[doc = "The timeout, in nanoseconds, of how long to suspend irq processing, if event polling finds events"]
1649    pub fn get_irq_suspend_timeout(&self) -> Result<u32, ErrorContext> {
1650        let mut iter = self.clone();
1651        iter.pos = 0;
1652        for attr in iter {
1653            if let Napi::IrqSuspendTimeout(val) = attr? {
1654                return Ok(val);
1655            }
1656        }
1657        Err(ErrorContext::new_missing(
1658            "Napi",
1659            "IrqSuspendTimeout",
1660            self.orig_loc,
1661            self.buf.as_ptr() as usize,
1662        ))
1663    }
1664    #[doc = "Whether the NAPI is configured to operate in threaded polling mode\\. If this is set to enabled then the NAPI context operates in threaded polling mode\\. If this is set to busy\\-poll, then the threaded polling mode also busy polls\\.\nAssociated type: [`NapiThreaded`] (enum)"]
1665    pub fn get_threaded(&self) -> Result<u32, ErrorContext> {
1666        let mut iter = self.clone();
1667        iter.pos = 0;
1668        for attr in iter {
1669            if let Napi::Threaded(val) = attr? {
1670                return Ok(val);
1671            }
1672        }
1673        Err(ErrorContext::new_missing(
1674            "Napi",
1675            "Threaded",
1676            self.orig_loc,
1677            self.buf.as_ptr() as usize,
1678        ))
1679    }
1680}
1681impl Napi {
1682    pub fn new<'a>(buf: &'a [u8]) -> IterableNapi<'a> {
1683        IterableNapi::with_loc(buf, buf.as_ptr() as usize)
1684    }
1685    fn attr_from_type(r#type: u16) -> Option<&'static str> {
1686        let res = match r#type {
1687            1u16 => "Ifindex",
1688            2u16 => "Id",
1689            3u16 => "Irq",
1690            4u16 => "Pid",
1691            5u16 => "DeferHardIrqs",
1692            6u16 => "GroFlushTimeout",
1693            7u16 => "IrqSuspendTimeout",
1694            8u16 => "Threaded",
1695            _ => return None,
1696        };
1697        Some(res)
1698    }
1699}
1700#[derive(Clone, Copy, Default)]
1701pub struct IterableNapi<'a> {
1702    buf: &'a [u8],
1703    pos: usize,
1704    orig_loc: usize,
1705}
1706impl<'a> IterableNapi<'a> {
1707    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
1708        Self {
1709            buf,
1710            pos: 0,
1711            orig_loc,
1712        }
1713    }
1714    pub fn get_buf(&self) -> &'a [u8] {
1715        self.buf
1716    }
1717}
1718impl<'a> Iterator for IterableNapi<'a> {
1719    type Item = Result<Napi, ErrorContext>;
1720    fn next(&mut self) -> Option<Self::Item> {
1721        let pos = self.pos;
1722        let mut r#type;
1723        loop {
1724            r#type = None;
1725            if self.buf.len() == self.pos {
1726                return None;
1727            }
1728            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
1729                break;
1730            };
1731            r#type = Some(header.r#type);
1732            let res = match header.r#type {
1733                1u16 => Napi::Ifindex({
1734                    let res = parse_u32(next);
1735                    let Some(val) = res else { break };
1736                    val
1737                }),
1738                2u16 => Napi::Id({
1739                    let res = parse_u32(next);
1740                    let Some(val) = res else { break };
1741                    val
1742                }),
1743                3u16 => Napi::Irq({
1744                    let res = parse_u32(next);
1745                    let Some(val) = res else { break };
1746                    val
1747                }),
1748                4u16 => Napi::Pid({
1749                    let res = parse_u32(next);
1750                    let Some(val) = res else { break };
1751                    val
1752                }),
1753                5u16 => Napi::DeferHardIrqs({
1754                    let res = parse_u32(next);
1755                    let Some(val) = res else { break };
1756                    val
1757                }),
1758                6u16 => Napi::GroFlushTimeout({
1759                    let res = parse_u32(next);
1760                    let Some(val) = res else { break };
1761                    val
1762                }),
1763                7u16 => Napi::IrqSuspendTimeout({
1764                    let res = parse_u32(next);
1765                    let Some(val) = res else { break };
1766                    val
1767                }),
1768                8u16 => Napi::Threaded({
1769                    let res = parse_u32(next);
1770                    let Some(val) = res else { break };
1771                    val
1772                }),
1773                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
1774                n => continue,
1775            };
1776            return Some(Ok(res));
1777        }
1778        Some(Err(ErrorContext::new(
1779            "Napi",
1780            r#type.and_then(|t| Napi::attr_from_type(t)),
1781            self.orig_loc,
1782            self.buf.as_ptr().wrapping_add(pos) as usize,
1783        )))
1784    }
1785}
1786impl std::fmt::Debug for IterableNapi<'_> {
1787    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1788        let mut fmt = f.debug_struct("Napi");
1789        for attr in self.clone() {
1790            let attr = match attr {
1791                Ok(a) => a,
1792                Err(err) => {
1793                    fmt.finish()?;
1794                    f.write_str("Err(")?;
1795                    err.fmt(f)?;
1796                    return f.write_str(")");
1797                }
1798            };
1799            match attr {
1800                Napi::Ifindex(val) => fmt.field("Ifindex", &val),
1801                Napi::Id(val) => fmt.field("Id", &val),
1802                Napi::Irq(val) => fmt.field("Irq", &val),
1803                Napi::Pid(val) => fmt.field("Pid", &val),
1804                Napi::DeferHardIrqs(val) => fmt.field("DeferHardIrqs", &val),
1805                Napi::GroFlushTimeout(val) => fmt.field("GroFlushTimeout", &val),
1806                Napi::IrqSuspendTimeout(val) => fmt.field("IrqSuspendTimeout", &val),
1807                Napi::Threaded(val) => fmt.field(
1808                    "Threaded",
1809                    &FormatEnum(val.into(), NapiThreaded::from_value),
1810                ),
1811            };
1812        }
1813        fmt.finish()
1814    }
1815}
1816impl IterableNapi<'_> {
1817    pub fn lookup_attr(
1818        &self,
1819        offset: usize,
1820        missing_type: Option<u16>,
1821    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
1822        let mut stack = Vec::new();
1823        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
1824        if missing_type.is_some() && cur == offset {
1825            stack.push(("Napi", offset));
1826            return (stack, missing_type.and_then(|t| Napi::attr_from_type(t)));
1827        }
1828        if cur > offset || cur + self.buf.len() < offset {
1829            return (stack, None);
1830        }
1831        let mut attrs = self.clone();
1832        let mut last_off = cur + attrs.pos;
1833        while let Some(attr) = attrs.next() {
1834            let Ok(attr) = attr else { break };
1835            match attr {
1836                Napi::Ifindex(val) => {
1837                    if last_off == offset {
1838                        stack.push(("Ifindex", last_off));
1839                        break;
1840                    }
1841                }
1842                Napi::Id(val) => {
1843                    if last_off == offset {
1844                        stack.push(("Id", last_off));
1845                        break;
1846                    }
1847                }
1848                Napi::Irq(val) => {
1849                    if last_off == offset {
1850                        stack.push(("Irq", last_off));
1851                        break;
1852                    }
1853                }
1854                Napi::Pid(val) => {
1855                    if last_off == offset {
1856                        stack.push(("Pid", last_off));
1857                        break;
1858                    }
1859                }
1860                Napi::DeferHardIrqs(val) => {
1861                    if last_off == offset {
1862                        stack.push(("DeferHardIrqs", last_off));
1863                        break;
1864                    }
1865                }
1866                Napi::GroFlushTimeout(val) => {
1867                    if last_off == offset {
1868                        stack.push(("GroFlushTimeout", last_off));
1869                        break;
1870                    }
1871                }
1872                Napi::IrqSuspendTimeout(val) => {
1873                    if last_off == offset {
1874                        stack.push(("IrqSuspendTimeout", last_off));
1875                        break;
1876                    }
1877                }
1878                Napi::Threaded(val) => {
1879                    if last_off == offset {
1880                        stack.push(("Threaded", last_off));
1881                        break;
1882                    }
1883                }
1884                _ => {}
1885            };
1886            last_off = cur + attrs.pos;
1887        }
1888        if !stack.is_empty() {
1889            stack.push(("Napi", cur));
1890        }
1891        (stack, None)
1892    }
1893}
1894#[derive(Clone)]
1895pub enum XskInfo {}
1896impl<'a> IterableXskInfo<'a> {}
1897impl XskInfo {
1898    pub fn new<'a>(buf: &'a [u8]) -> IterableXskInfo<'a> {
1899        IterableXskInfo::with_loc(buf, buf.as_ptr() as usize)
1900    }
1901    fn attr_from_type(r#type: u16) -> Option<&'static str> {
1902        None
1903    }
1904}
1905#[derive(Clone, Copy, Default)]
1906pub struct IterableXskInfo<'a> {
1907    buf: &'a [u8],
1908    pos: usize,
1909    orig_loc: usize,
1910}
1911impl<'a> IterableXskInfo<'a> {
1912    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
1913        Self {
1914            buf,
1915            pos: 0,
1916            orig_loc,
1917        }
1918    }
1919    pub fn get_buf(&self) -> &'a [u8] {
1920        self.buf
1921    }
1922}
1923impl<'a> Iterator for IterableXskInfo<'a> {
1924    type Item = Result<XskInfo, ErrorContext>;
1925    fn next(&mut self) -> Option<Self::Item> {
1926        let pos = self.pos;
1927        let mut r#type;
1928        loop {
1929            r#type = None;
1930            if self.buf.len() == self.pos {
1931                return None;
1932            }
1933            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
1934                break;
1935            };
1936            r#type = Some(header.r#type);
1937            let res = match header.r#type {
1938                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
1939                n => continue,
1940            };
1941            return Some(Ok(res));
1942        }
1943        Some(Err(ErrorContext::new(
1944            "XskInfo",
1945            r#type.and_then(|t| XskInfo::attr_from_type(t)),
1946            self.orig_loc,
1947            self.buf.as_ptr().wrapping_add(pos) as usize,
1948        )))
1949    }
1950}
1951impl std::fmt::Debug for IterableXskInfo<'_> {
1952    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1953        let mut fmt = f.debug_struct("XskInfo");
1954        for attr in self.clone() {
1955            let attr = match attr {
1956                Ok(a) => a,
1957                Err(err) => {
1958                    fmt.finish()?;
1959                    f.write_str("Err(")?;
1960                    err.fmt(f)?;
1961                    return f.write_str(")");
1962                }
1963            };
1964            match attr {};
1965        }
1966        fmt.finish()
1967    }
1968}
1969impl IterableXskInfo<'_> {
1970    pub fn lookup_attr(
1971        &self,
1972        offset: usize,
1973        missing_type: Option<u16>,
1974    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
1975        let mut stack = Vec::new();
1976        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
1977        if missing_type.is_some() && cur == offset {
1978            stack.push(("XskInfo", offset));
1979            return (stack, missing_type.and_then(|t| XskInfo::attr_from_type(t)));
1980        }
1981        (stack, None)
1982    }
1983}
1984#[derive(Clone)]
1985pub enum Queue<'a> {
1986    #[doc = "Queue index; most queue types are indexed like a C array, with indexes starting at 0 and ending at queue count \\- 1\\. Queue indexes are scoped to an interface and queue type\\."]
1987    Id(u32),
1988    #[doc = "ifindex of the netdevice to which the queue belongs\\."]
1989    Ifindex(u32),
1990    #[doc = "Queue type as rx, tx\\. Each queue type defines a separate ID space\\. XDP TX queues allocated in the kernel are not linked to NAPIs and thus not listed\\. AF\\_XDP queues will have more information set in the xsk attribute\\.\nAssociated type: [`QueueType`] (enum)"]
1991    Type(u32),
1992    #[doc = "ID of the NAPI instance which services this queue\\."]
1993    NapiId(u32),
1994    #[doc = "ID of the dmabuf attached to this queue, if any\\."]
1995    Dmabuf(u32),
1996    #[doc = "io\\_uring memory provider information\\."]
1997    IoUring(IterableIoUringProviderInfo<'a>),
1998    #[doc = "XSK information for this queue, if any\\."]
1999    Xsk(IterableXskInfo<'a>),
2000}
2001impl<'a> IterableQueue<'a> {
2002    #[doc = "Queue index; most queue types are indexed like a C array, with indexes starting at 0 and ending at queue count \\- 1\\. Queue indexes are scoped to an interface and queue type\\."]
2003    pub fn get_id(&self) -> Result<u32, ErrorContext> {
2004        let mut iter = self.clone();
2005        iter.pos = 0;
2006        for attr in iter {
2007            if let Queue::Id(val) = attr? {
2008                return Ok(val);
2009            }
2010        }
2011        Err(ErrorContext::new_missing(
2012            "Queue",
2013            "Id",
2014            self.orig_loc,
2015            self.buf.as_ptr() as usize,
2016        ))
2017    }
2018    #[doc = "ifindex of the netdevice to which the queue belongs\\."]
2019    pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
2020        let mut iter = self.clone();
2021        iter.pos = 0;
2022        for attr in iter {
2023            if let Queue::Ifindex(val) = attr? {
2024                return Ok(val);
2025            }
2026        }
2027        Err(ErrorContext::new_missing(
2028            "Queue",
2029            "Ifindex",
2030            self.orig_loc,
2031            self.buf.as_ptr() as usize,
2032        ))
2033    }
2034    #[doc = "Queue type as rx, tx\\. Each queue type defines a separate ID space\\. XDP TX queues allocated in the kernel are not linked to NAPIs and thus not listed\\. AF\\_XDP queues will have more information set in the xsk attribute\\.\nAssociated type: [`QueueType`] (enum)"]
2035    pub fn get_type(&self) -> Result<u32, ErrorContext> {
2036        let mut iter = self.clone();
2037        iter.pos = 0;
2038        for attr in iter {
2039            if let Queue::Type(val) = attr? {
2040                return Ok(val);
2041            }
2042        }
2043        Err(ErrorContext::new_missing(
2044            "Queue",
2045            "Type",
2046            self.orig_loc,
2047            self.buf.as_ptr() as usize,
2048        ))
2049    }
2050    #[doc = "ID of the NAPI instance which services this queue\\."]
2051    pub fn get_napi_id(&self) -> Result<u32, ErrorContext> {
2052        let mut iter = self.clone();
2053        iter.pos = 0;
2054        for attr in iter {
2055            if let Queue::NapiId(val) = attr? {
2056                return Ok(val);
2057            }
2058        }
2059        Err(ErrorContext::new_missing(
2060            "Queue",
2061            "NapiId",
2062            self.orig_loc,
2063            self.buf.as_ptr() as usize,
2064        ))
2065    }
2066    #[doc = "ID of the dmabuf attached to this queue, if any\\."]
2067    pub fn get_dmabuf(&self) -> Result<u32, ErrorContext> {
2068        let mut iter = self.clone();
2069        iter.pos = 0;
2070        for attr in iter {
2071            if let Queue::Dmabuf(val) = attr? {
2072                return Ok(val);
2073            }
2074        }
2075        Err(ErrorContext::new_missing(
2076            "Queue",
2077            "Dmabuf",
2078            self.orig_loc,
2079            self.buf.as_ptr() as usize,
2080        ))
2081    }
2082    #[doc = "io\\_uring memory provider information\\."]
2083    pub fn get_io_uring(&self) -> Result<IterableIoUringProviderInfo<'a>, ErrorContext> {
2084        let mut iter = self.clone();
2085        iter.pos = 0;
2086        for attr in iter {
2087            if let Queue::IoUring(val) = attr? {
2088                return Ok(val);
2089            }
2090        }
2091        Err(ErrorContext::new_missing(
2092            "Queue",
2093            "IoUring",
2094            self.orig_loc,
2095            self.buf.as_ptr() as usize,
2096        ))
2097    }
2098    #[doc = "XSK information for this queue, if any\\."]
2099    pub fn get_xsk(&self) -> Result<IterableXskInfo<'a>, ErrorContext> {
2100        let mut iter = self.clone();
2101        iter.pos = 0;
2102        for attr in iter {
2103            if let Queue::Xsk(val) = attr? {
2104                return Ok(val);
2105            }
2106        }
2107        Err(ErrorContext::new_missing(
2108            "Queue",
2109            "Xsk",
2110            self.orig_loc,
2111            self.buf.as_ptr() as usize,
2112        ))
2113    }
2114}
2115impl Queue<'_> {
2116    pub fn new<'a>(buf: &'a [u8]) -> IterableQueue<'a> {
2117        IterableQueue::with_loc(buf, buf.as_ptr() as usize)
2118    }
2119    fn attr_from_type(r#type: u16) -> Option<&'static str> {
2120        let res = match r#type {
2121            1u16 => "Id",
2122            2u16 => "Ifindex",
2123            3u16 => "Type",
2124            4u16 => "NapiId",
2125            5u16 => "Dmabuf",
2126            6u16 => "IoUring",
2127            7u16 => "Xsk",
2128            _ => return None,
2129        };
2130        Some(res)
2131    }
2132}
2133#[derive(Clone, Copy, Default)]
2134pub struct IterableQueue<'a> {
2135    buf: &'a [u8],
2136    pos: usize,
2137    orig_loc: usize,
2138}
2139impl<'a> IterableQueue<'a> {
2140    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
2141        Self {
2142            buf,
2143            pos: 0,
2144            orig_loc,
2145        }
2146    }
2147    pub fn get_buf(&self) -> &'a [u8] {
2148        self.buf
2149    }
2150}
2151impl<'a> Iterator for IterableQueue<'a> {
2152    type Item = Result<Queue<'a>, ErrorContext>;
2153    fn next(&mut self) -> Option<Self::Item> {
2154        let pos = self.pos;
2155        let mut r#type;
2156        loop {
2157            r#type = None;
2158            if self.buf.len() == self.pos {
2159                return None;
2160            }
2161            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
2162                break;
2163            };
2164            r#type = Some(header.r#type);
2165            let res = match header.r#type {
2166                1u16 => Queue::Id({
2167                    let res = parse_u32(next);
2168                    let Some(val) = res else { break };
2169                    val
2170                }),
2171                2u16 => Queue::Ifindex({
2172                    let res = parse_u32(next);
2173                    let Some(val) = res else { break };
2174                    val
2175                }),
2176                3u16 => Queue::Type({
2177                    let res = parse_u32(next);
2178                    let Some(val) = res else { break };
2179                    val
2180                }),
2181                4u16 => Queue::NapiId({
2182                    let res = parse_u32(next);
2183                    let Some(val) = res else { break };
2184                    val
2185                }),
2186                5u16 => Queue::Dmabuf({
2187                    let res = parse_u32(next);
2188                    let Some(val) = res else { break };
2189                    val
2190                }),
2191                6u16 => Queue::IoUring({
2192                    let res = Some(IterableIoUringProviderInfo::with_loc(next, self.orig_loc));
2193                    let Some(val) = res else { break };
2194                    val
2195                }),
2196                7u16 => Queue::Xsk({
2197                    let res = Some(IterableXskInfo::with_loc(next, self.orig_loc));
2198                    let Some(val) = res else { break };
2199                    val
2200                }),
2201                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
2202                n => continue,
2203            };
2204            return Some(Ok(res));
2205        }
2206        Some(Err(ErrorContext::new(
2207            "Queue",
2208            r#type.and_then(|t| Queue::attr_from_type(t)),
2209            self.orig_loc,
2210            self.buf.as_ptr().wrapping_add(pos) as usize,
2211        )))
2212    }
2213}
2214impl<'a> std::fmt::Debug for IterableQueue<'_> {
2215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2216        let mut fmt = f.debug_struct("Queue");
2217        for attr in self.clone() {
2218            let attr = match attr {
2219                Ok(a) => a,
2220                Err(err) => {
2221                    fmt.finish()?;
2222                    f.write_str("Err(")?;
2223                    err.fmt(f)?;
2224                    return f.write_str(")");
2225                }
2226            };
2227            match attr {
2228                Queue::Id(val) => fmt.field("Id", &val),
2229                Queue::Ifindex(val) => fmt.field("Ifindex", &val),
2230                Queue::Type(val) => {
2231                    fmt.field("Type", &FormatEnum(val.into(), QueueType::from_value))
2232                }
2233                Queue::NapiId(val) => fmt.field("NapiId", &val),
2234                Queue::Dmabuf(val) => fmt.field("Dmabuf", &val),
2235                Queue::IoUring(val) => fmt.field("IoUring", &val),
2236                Queue::Xsk(val) => fmt.field("Xsk", &val),
2237            };
2238        }
2239        fmt.finish()
2240    }
2241}
2242impl IterableQueue<'_> {
2243    pub fn lookup_attr(
2244        &self,
2245        offset: usize,
2246        missing_type: Option<u16>,
2247    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
2248        let mut stack = Vec::new();
2249        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
2250        if missing_type.is_some() && cur == offset {
2251            stack.push(("Queue", offset));
2252            return (stack, missing_type.and_then(|t| Queue::attr_from_type(t)));
2253        }
2254        if cur > offset || cur + self.buf.len() < offset {
2255            return (stack, None);
2256        }
2257        let mut attrs = self.clone();
2258        let mut last_off = cur + attrs.pos;
2259        let mut missing = None;
2260        while let Some(attr) = attrs.next() {
2261            let Ok(attr) = attr else { break };
2262            match attr {
2263                Queue::Id(val) => {
2264                    if last_off == offset {
2265                        stack.push(("Id", last_off));
2266                        break;
2267                    }
2268                }
2269                Queue::Ifindex(val) => {
2270                    if last_off == offset {
2271                        stack.push(("Ifindex", last_off));
2272                        break;
2273                    }
2274                }
2275                Queue::Type(val) => {
2276                    if last_off == offset {
2277                        stack.push(("Type", last_off));
2278                        break;
2279                    }
2280                }
2281                Queue::NapiId(val) => {
2282                    if last_off == offset {
2283                        stack.push(("NapiId", last_off));
2284                        break;
2285                    }
2286                }
2287                Queue::Dmabuf(val) => {
2288                    if last_off == offset {
2289                        stack.push(("Dmabuf", last_off));
2290                        break;
2291                    }
2292                }
2293                Queue::IoUring(val) => {
2294                    (stack, missing) = val.lookup_attr(offset, missing_type);
2295                    if !stack.is_empty() {
2296                        break;
2297                    }
2298                }
2299                Queue::Xsk(val) => {
2300                    (stack, missing) = val.lookup_attr(offset, missing_type);
2301                    if !stack.is_empty() {
2302                        break;
2303                    }
2304                }
2305                _ => {}
2306            };
2307            last_off = cur + attrs.pos;
2308        }
2309        if !stack.is_empty() {
2310            stack.push(("Queue", cur));
2311        }
2312        (stack, missing)
2313    }
2314}
2315#[derive(Clone)]
2316pub enum Qstats {
2317    #[doc = "ifindex of the netdevice to which stats belong\\."]
2318    Ifindex(u32),
2319    #[doc = "Queue type as rx, tx, for queue\\-id\\.\nAssociated type: [`QueueType`] (enum)"]
2320    QueueType(u32),
2321    #[doc = "Queue ID, if stats are scoped to a single queue instance\\."]
2322    QueueId(u32),
2323    #[doc = "What object type should be used to iterate over the stats\\.\n\nAssociated type: [`QstatsScope`] (enum)"]
2324    Scope(u32),
2325    #[doc = "Number of wire packets successfully received and passed to the stack\\.\nFor drivers supporting XDP, XDP is considered the first layer\nof the stack, so packets consumed by XDP are still counted here\\.\n"]
2326    RxPackets(u32),
2327    #[doc = "Successfully received bytes, see \\`rx\\-packets\\`\\."]
2328    RxBytes(u32),
2329    #[doc = "Number of wire packets successfully sent\\. Packet is considered to be\nsuccessfully sent once it is in device memory (usually this means\nthe device has issued a DMA completion for the packet)\\.\n"]
2330    TxPackets(u32),
2331    #[doc = "Successfully sent bytes, see \\`tx\\-packets\\`\\."]
2332    TxBytes(u32),
2333    #[doc = "Number of times skb or buffer allocation failed on the Rx datapath\\.\nAllocation failure may, or may not result in a packet drop, depending\non driver implementation and whether system recovers quickly\\.\n"]
2334    RxAllocFail(u32),
2335    #[doc = "Number of all packets which entered the device, but never left it,\nincluding but not limited to: packets dropped due to lack of buffer\nspace, processing errors, explicit or implicit policies and packet\nfilters\\.\n"]
2336    RxHwDrops(u32),
2337    #[doc = "Number of packets dropped due to transient lack of resources, such as\nbuffer space, host descriptors etc\\.\n"]
2338    RxHwDropOverruns(u32),
2339    #[doc = "Number of packets that were marked as CHECKSUM\\_COMPLETE\\."]
2340    RxCsumComplete(u32),
2341    #[doc = "Number of packets that were marked as CHECKSUM\\_UNNECESSARY\\."]
2342    RxCsumUnnecessary(u32),
2343    #[doc = "Number of packets that were not checksummed by device\\."]
2344    RxCsumNone(u32),
2345    #[doc = "Number of packets with bad checksum\\. The packets are not discarded,\nbut still delivered to the stack\\.\n"]
2346    RxCsumBad(u32),
2347    #[doc = "Number of packets that were coalesced from smaller packets by the\ndevice\\. Counts only packets coalesced with the HW\\-GRO netdevice\nfeature, LRO\\-coalesced packets are not counted\\.\n"]
2348    RxHwGroPackets(u32),
2349    #[doc = "See \\`rx\\-hw\\-gro\\-packets\\`\\."]
2350    RxHwGroBytes(u32),
2351    #[doc = "Number of packets that were coalesced to bigger packetss with the\nHW\\-GRO netdevice feature\\. LRO\\-coalesced packets are not counted\\.\n"]
2352    RxHwGroWirePackets(u32),
2353    #[doc = "See \\`rx\\-hw\\-gro\\-wire\\-packets\\`\\."]
2354    RxHwGroWireBytes(u32),
2355    #[doc = "Number of the packets dropped by the device due to the received\npackets bitrate exceeding the device rate limit\\.\n"]
2356    RxHwDropRatelimits(u32),
2357    #[doc = "Number of packets that arrived at the device but never left it,\nencompassing packets dropped for reasons such as processing errors, as\nwell as those affected by explicitly defined policies and packet\nfiltering criteria\\.\n"]
2358    TxHwDrops(u32),
2359    #[doc = "Number of packets dropped because they were invalid or malformed\\."]
2360    TxHwDropErrors(u32),
2361    #[doc = "Number of packets that did not require the device to calculate the\nchecksum\\.\n"]
2362    TxCsumNone(u32),
2363    #[doc = "Number of packets that required the device to calculate the checksum\\.\nThis counter includes the number of GSO wire packets for which device\ncalculated the L4 checksum\\.\n"]
2364    TxNeedsCsum(u32),
2365    #[doc = "Number of packets that necessitated segmentation into smaller packets\nby the device\\.\n"]
2366    TxHwGsoPackets(u32),
2367    #[doc = "See \\`tx\\-hw\\-gso\\-packets\\`\\."]
2368    TxHwGsoBytes(u32),
2369    #[doc = "Number of wire\\-sized packets generated by processing\n\\`tx\\-hw\\-gso\\-packets\\`\n"]
2370    TxHwGsoWirePackets(u32),
2371    #[doc = "See \\`tx\\-hw\\-gso\\-wire\\-packets\\`\\."]
2372    TxHwGsoWireBytes(u32),
2373    #[doc = "Number of the packets dropped by the device due to the transmit\npackets bitrate exceeding the device rate limit\\.\n"]
2374    TxHwDropRatelimits(u32),
2375    #[doc = "Number of times driver paused accepting new tx packets\nfrom the stack to this queue, because the queue was full\\.\nNote that if BQL is supported and enabled on the device\nthe networking stack will avoid queuing a lot of data at once\\.\n"]
2376    TxStop(u32),
2377    #[doc = "Number of times driver re\\-started accepting send\nrequests to this queue from the stack\\.\n"]
2378    TxWake(u32),
2379}
2380impl<'a> IterableQstats<'a> {
2381    #[doc = "ifindex of the netdevice to which stats belong\\."]
2382    pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
2383        let mut iter = self.clone();
2384        iter.pos = 0;
2385        for attr in iter {
2386            if let Qstats::Ifindex(val) = attr? {
2387                return Ok(val);
2388            }
2389        }
2390        Err(ErrorContext::new_missing(
2391            "Qstats",
2392            "Ifindex",
2393            self.orig_loc,
2394            self.buf.as_ptr() as usize,
2395        ))
2396    }
2397    #[doc = "Queue type as rx, tx, for queue\\-id\\.\nAssociated type: [`QueueType`] (enum)"]
2398    pub fn get_queue_type(&self) -> Result<u32, ErrorContext> {
2399        let mut iter = self.clone();
2400        iter.pos = 0;
2401        for attr in iter {
2402            if let Qstats::QueueType(val) = attr? {
2403                return Ok(val);
2404            }
2405        }
2406        Err(ErrorContext::new_missing(
2407            "Qstats",
2408            "QueueType",
2409            self.orig_loc,
2410            self.buf.as_ptr() as usize,
2411        ))
2412    }
2413    #[doc = "Queue ID, if stats are scoped to a single queue instance\\."]
2414    pub fn get_queue_id(&self) -> Result<u32, ErrorContext> {
2415        let mut iter = self.clone();
2416        iter.pos = 0;
2417        for attr in iter {
2418            if let Qstats::QueueId(val) = attr? {
2419                return Ok(val);
2420            }
2421        }
2422        Err(ErrorContext::new_missing(
2423            "Qstats",
2424            "QueueId",
2425            self.orig_loc,
2426            self.buf.as_ptr() as usize,
2427        ))
2428    }
2429    #[doc = "What object type should be used to iterate over the stats\\.\n\nAssociated type: [`QstatsScope`] (enum)"]
2430    pub fn get_scope(&self) -> Result<u32, ErrorContext> {
2431        let mut iter = self.clone();
2432        iter.pos = 0;
2433        for attr in iter {
2434            if let Qstats::Scope(val) = attr? {
2435                return Ok(val);
2436            }
2437        }
2438        Err(ErrorContext::new_missing(
2439            "Qstats",
2440            "Scope",
2441            self.orig_loc,
2442            self.buf.as_ptr() as usize,
2443        ))
2444    }
2445    #[doc = "Number of wire packets successfully received and passed to the stack\\.\nFor drivers supporting XDP, XDP is considered the first layer\nof the stack, so packets consumed by XDP are still counted here\\.\n"]
2446    pub fn get_rx_packets(&self) -> Result<u32, ErrorContext> {
2447        let mut iter = self.clone();
2448        iter.pos = 0;
2449        for attr in iter {
2450            if let Qstats::RxPackets(val) = attr? {
2451                return Ok(val);
2452            }
2453        }
2454        Err(ErrorContext::new_missing(
2455            "Qstats",
2456            "RxPackets",
2457            self.orig_loc,
2458            self.buf.as_ptr() as usize,
2459        ))
2460    }
2461    #[doc = "Successfully received bytes, see \\`rx\\-packets\\`\\."]
2462    pub fn get_rx_bytes(&self) -> Result<u32, ErrorContext> {
2463        let mut iter = self.clone();
2464        iter.pos = 0;
2465        for attr in iter {
2466            if let Qstats::RxBytes(val) = attr? {
2467                return Ok(val);
2468            }
2469        }
2470        Err(ErrorContext::new_missing(
2471            "Qstats",
2472            "RxBytes",
2473            self.orig_loc,
2474            self.buf.as_ptr() as usize,
2475        ))
2476    }
2477    #[doc = "Number of wire packets successfully sent\\. Packet is considered to be\nsuccessfully sent once it is in device memory (usually this means\nthe device has issued a DMA completion for the packet)\\.\n"]
2478    pub fn get_tx_packets(&self) -> Result<u32, ErrorContext> {
2479        let mut iter = self.clone();
2480        iter.pos = 0;
2481        for attr in iter {
2482            if let Qstats::TxPackets(val) = attr? {
2483                return Ok(val);
2484            }
2485        }
2486        Err(ErrorContext::new_missing(
2487            "Qstats",
2488            "TxPackets",
2489            self.orig_loc,
2490            self.buf.as_ptr() as usize,
2491        ))
2492    }
2493    #[doc = "Successfully sent bytes, see \\`tx\\-packets\\`\\."]
2494    pub fn get_tx_bytes(&self) -> Result<u32, ErrorContext> {
2495        let mut iter = self.clone();
2496        iter.pos = 0;
2497        for attr in iter {
2498            if let Qstats::TxBytes(val) = attr? {
2499                return Ok(val);
2500            }
2501        }
2502        Err(ErrorContext::new_missing(
2503            "Qstats",
2504            "TxBytes",
2505            self.orig_loc,
2506            self.buf.as_ptr() as usize,
2507        ))
2508    }
2509    #[doc = "Number of times skb or buffer allocation failed on the Rx datapath\\.\nAllocation failure may, or may not result in a packet drop, depending\non driver implementation and whether system recovers quickly\\.\n"]
2510    pub fn get_rx_alloc_fail(&self) -> Result<u32, ErrorContext> {
2511        let mut iter = self.clone();
2512        iter.pos = 0;
2513        for attr in iter {
2514            if let Qstats::RxAllocFail(val) = attr? {
2515                return Ok(val);
2516            }
2517        }
2518        Err(ErrorContext::new_missing(
2519            "Qstats",
2520            "RxAllocFail",
2521            self.orig_loc,
2522            self.buf.as_ptr() as usize,
2523        ))
2524    }
2525    #[doc = "Number of all packets which entered the device, but never left it,\nincluding but not limited to: packets dropped due to lack of buffer\nspace, processing errors, explicit or implicit policies and packet\nfilters\\.\n"]
2526    pub fn get_rx_hw_drops(&self) -> Result<u32, ErrorContext> {
2527        let mut iter = self.clone();
2528        iter.pos = 0;
2529        for attr in iter {
2530            if let Qstats::RxHwDrops(val) = attr? {
2531                return Ok(val);
2532            }
2533        }
2534        Err(ErrorContext::new_missing(
2535            "Qstats",
2536            "RxHwDrops",
2537            self.orig_loc,
2538            self.buf.as_ptr() as usize,
2539        ))
2540    }
2541    #[doc = "Number of packets dropped due to transient lack of resources, such as\nbuffer space, host descriptors etc\\.\n"]
2542    pub fn get_rx_hw_drop_overruns(&self) -> Result<u32, ErrorContext> {
2543        let mut iter = self.clone();
2544        iter.pos = 0;
2545        for attr in iter {
2546            if let Qstats::RxHwDropOverruns(val) = attr? {
2547                return Ok(val);
2548            }
2549        }
2550        Err(ErrorContext::new_missing(
2551            "Qstats",
2552            "RxHwDropOverruns",
2553            self.orig_loc,
2554            self.buf.as_ptr() as usize,
2555        ))
2556    }
2557    #[doc = "Number of packets that were marked as CHECKSUM\\_COMPLETE\\."]
2558    pub fn get_rx_csum_complete(&self) -> Result<u32, ErrorContext> {
2559        let mut iter = self.clone();
2560        iter.pos = 0;
2561        for attr in iter {
2562            if let Qstats::RxCsumComplete(val) = attr? {
2563                return Ok(val);
2564            }
2565        }
2566        Err(ErrorContext::new_missing(
2567            "Qstats",
2568            "RxCsumComplete",
2569            self.orig_loc,
2570            self.buf.as_ptr() as usize,
2571        ))
2572    }
2573    #[doc = "Number of packets that were marked as CHECKSUM\\_UNNECESSARY\\."]
2574    pub fn get_rx_csum_unnecessary(&self) -> Result<u32, ErrorContext> {
2575        let mut iter = self.clone();
2576        iter.pos = 0;
2577        for attr in iter {
2578            if let Qstats::RxCsumUnnecessary(val) = attr? {
2579                return Ok(val);
2580            }
2581        }
2582        Err(ErrorContext::new_missing(
2583            "Qstats",
2584            "RxCsumUnnecessary",
2585            self.orig_loc,
2586            self.buf.as_ptr() as usize,
2587        ))
2588    }
2589    #[doc = "Number of packets that were not checksummed by device\\."]
2590    pub fn get_rx_csum_none(&self) -> Result<u32, ErrorContext> {
2591        let mut iter = self.clone();
2592        iter.pos = 0;
2593        for attr in iter {
2594            if let Qstats::RxCsumNone(val) = attr? {
2595                return Ok(val);
2596            }
2597        }
2598        Err(ErrorContext::new_missing(
2599            "Qstats",
2600            "RxCsumNone",
2601            self.orig_loc,
2602            self.buf.as_ptr() as usize,
2603        ))
2604    }
2605    #[doc = "Number of packets with bad checksum\\. The packets are not discarded,\nbut still delivered to the stack\\.\n"]
2606    pub fn get_rx_csum_bad(&self) -> Result<u32, ErrorContext> {
2607        let mut iter = self.clone();
2608        iter.pos = 0;
2609        for attr in iter {
2610            if let Qstats::RxCsumBad(val) = attr? {
2611                return Ok(val);
2612            }
2613        }
2614        Err(ErrorContext::new_missing(
2615            "Qstats",
2616            "RxCsumBad",
2617            self.orig_loc,
2618            self.buf.as_ptr() as usize,
2619        ))
2620    }
2621    #[doc = "Number of packets that were coalesced from smaller packets by the\ndevice\\. Counts only packets coalesced with the HW\\-GRO netdevice\nfeature, LRO\\-coalesced packets are not counted\\.\n"]
2622    pub fn get_rx_hw_gro_packets(&self) -> Result<u32, ErrorContext> {
2623        let mut iter = self.clone();
2624        iter.pos = 0;
2625        for attr in iter {
2626            if let Qstats::RxHwGroPackets(val) = attr? {
2627                return Ok(val);
2628            }
2629        }
2630        Err(ErrorContext::new_missing(
2631            "Qstats",
2632            "RxHwGroPackets",
2633            self.orig_loc,
2634            self.buf.as_ptr() as usize,
2635        ))
2636    }
2637    #[doc = "See \\`rx\\-hw\\-gro\\-packets\\`\\."]
2638    pub fn get_rx_hw_gro_bytes(&self) -> Result<u32, ErrorContext> {
2639        let mut iter = self.clone();
2640        iter.pos = 0;
2641        for attr in iter {
2642            if let Qstats::RxHwGroBytes(val) = attr? {
2643                return Ok(val);
2644            }
2645        }
2646        Err(ErrorContext::new_missing(
2647            "Qstats",
2648            "RxHwGroBytes",
2649            self.orig_loc,
2650            self.buf.as_ptr() as usize,
2651        ))
2652    }
2653    #[doc = "Number of packets that were coalesced to bigger packetss with the\nHW\\-GRO netdevice feature\\. LRO\\-coalesced packets are not counted\\.\n"]
2654    pub fn get_rx_hw_gro_wire_packets(&self) -> Result<u32, ErrorContext> {
2655        let mut iter = self.clone();
2656        iter.pos = 0;
2657        for attr in iter {
2658            if let Qstats::RxHwGroWirePackets(val) = attr? {
2659                return Ok(val);
2660            }
2661        }
2662        Err(ErrorContext::new_missing(
2663            "Qstats",
2664            "RxHwGroWirePackets",
2665            self.orig_loc,
2666            self.buf.as_ptr() as usize,
2667        ))
2668    }
2669    #[doc = "See \\`rx\\-hw\\-gro\\-wire\\-packets\\`\\."]
2670    pub fn get_rx_hw_gro_wire_bytes(&self) -> Result<u32, ErrorContext> {
2671        let mut iter = self.clone();
2672        iter.pos = 0;
2673        for attr in iter {
2674            if let Qstats::RxHwGroWireBytes(val) = attr? {
2675                return Ok(val);
2676            }
2677        }
2678        Err(ErrorContext::new_missing(
2679            "Qstats",
2680            "RxHwGroWireBytes",
2681            self.orig_loc,
2682            self.buf.as_ptr() as usize,
2683        ))
2684    }
2685    #[doc = "Number of the packets dropped by the device due to the received\npackets bitrate exceeding the device rate limit\\.\n"]
2686    pub fn get_rx_hw_drop_ratelimits(&self) -> Result<u32, ErrorContext> {
2687        let mut iter = self.clone();
2688        iter.pos = 0;
2689        for attr in iter {
2690            if let Qstats::RxHwDropRatelimits(val) = attr? {
2691                return Ok(val);
2692            }
2693        }
2694        Err(ErrorContext::new_missing(
2695            "Qstats",
2696            "RxHwDropRatelimits",
2697            self.orig_loc,
2698            self.buf.as_ptr() as usize,
2699        ))
2700    }
2701    #[doc = "Number of packets that arrived at the device but never left it,\nencompassing packets dropped for reasons such as processing errors, as\nwell as those affected by explicitly defined policies and packet\nfiltering criteria\\.\n"]
2702    pub fn get_tx_hw_drops(&self) -> Result<u32, ErrorContext> {
2703        let mut iter = self.clone();
2704        iter.pos = 0;
2705        for attr in iter {
2706            if let Qstats::TxHwDrops(val) = attr? {
2707                return Ok(val);
2708            }
2709        }
2710        Err(ErrorContext::new_missing(
2711            "Qstats",
2712            "TxHwDrops",
2713            self.orig_loc,
2714            self.buf.as_ptr() as usize,
2715        ))
2716    }
2717    #[doc = "Number of packets dropped because they were invalid or malformed\\."]
2718    pub fn get_tx_hw_drop_errors(&self) -> Result<u32, ErrorContext> {
2719        let mut iter = self.clone();
2720        iter.pos = 0;
2721        for attr in iter {
2722            if let Qstats::TxHwDropErrors(val) = attr? {
2723                return Ok(val);
2724            }
2725        }
2726        Err(ErrorContext::new_missing(
2727            "Qstats",
2728            "TxHwDropErrors",
2729            self.orig_loc,
2730            self.buf.as_ptr() as usize,
2731        ))
2732    }
2733    #[doc = "Number of packets that did not require the device to calculate the\nchecksum\\.\n"]
2734    pub fn get_tx_csum_none(&self) -> Result<u32, ErrorContext> {
2735        let mut iter = self.clone();
2736        iter.pos = 0;
2737        for attr in iter {
2738            if let Qstats::TxCsumNone(val) = attr? {
2739                return Ok(val);
2740            }
2741        }
2742        Err(ErrorContext::new_missing(
2743            "Qstats",
2744            "TxCsumNone",
2745            self.orig_loc,
2746            self.buf.as_ptr() as usize,
2747        ))
2748    }
2749    #[doc = "Number of packets that required the device to calculate the checksum\\.\nThis counter includes the number of GSO wire packets for which device\ncalculated the L4 checksum\\.\n"]
2750    pub fn get_tx_needs_csum(&self) -> Result<u32, ErrorContext> {
2751        let mut iter = self.clone();
2752        iter.pos = 0;
2753        for attr in iter {
2754            if let Qstats::TxNeedsCsum(val) = attr? {
2755                return Ok(val);
2756            }
2757        }
2758        Err(ErrorContext::new_missing(
2759            "Qstats",
2760            "TxNeedsCsum",
2761            self.orig_loc,
2762            self.buf.as_ptr() as usize,
2763        ))
2764    }
2765    #[doc = "Number of packets that necessitated segmentation into smaller packets\nby the device\\.\n"]
2766    pub fn get_tx_hw_gso_packets(&self) -> Result<u32, ErrorContext> {
2767        let mut iter = self.clone();
2768        iter.pos = 0;
2769        for attr in iter {
2770            if let Qstats::TxHwGsoPackets(val) = attr? {
2771                return Ok(val);
2772            }
2773        }
2774        Err(ErrorContext::new_missing(
2775            "Qstats",
2776            "TxHwGsoPackets",
2777            self.orig_loc,
2778            self.buf.as_ptr() as usize,
2779        ))
2780    }
2781    #[doc = "See \\`tx\\-hw\\-gso\\-packets\\`\\."]
2782    pub fn get_tx_hw_gso_bytes(&self) -> Result<u32, ErrorContext> {
2783        let mut iter = self.clone();
2784        iter.pos = 0;
2785        for attr in iter {
2786            if let Qstats::TxHwGsoBytes(val) = attr? {
2787                return Ok(val);
2788            }
2789        }
2790        Err(ErrorContext::new_missing(
2791            "Qstats",
2792            "TxHwGsoBytes",
2793            self.orig_loc,
2794            self.buf.as_ptr() as usize,
2795        ))
2796    }
2797    #[doc = "Number of wire\\-sized packets generated by processing\n\\`tx\\-hw\\-gso\\-packets\\`\n"]
2798    pub fn get_tx_hw_gso_wire_packets(&self) -> Result<u32, ErrorContext> {
2799        let mut iter = self.clone();
2800        iter.pos = 0;
2801        for attr in iter {
2802            if let Qstats::TxHwGsoWirePackets(val) = attr? {
2803                return Ok(val);
2804            }
2805        }
2806        Err(ErrorContext::new_missing(
2807            "Qstats",
2808            "TxHwGsoWirePackets",
2809            self.orig_loc,
2810            self.buf.as_ptr() as usize,
2811        ))
2812    }
2813    #[doc = "See \\`tx\\-hw\\-gso\\-wire\\-packets\\`\\."]
2814    pub fn get_tx_hw_gso_wire_bytes(&self) -> Result<u32, ErrorContext> {
2815        let mut iter = self.clone();
2816        iter.pos = 0;
2817        for attr in iter {
2818            if let Qstats::TxHwGsoWireBytes(val) = attr? {
2819                return Ok(val);
2820            }
2821        }
2822        Err(ErrorContext::new_missing(
2823            "Qstats",
2824            "TxHwGsoWireBytes",
2825            self.orig_loc,
2826            self.buf.as_ptr() as usize,
2827        ))
2828    }
2829    #[doc = "Number of the packets dropped by the device due to the transmit\npackets bitrate exceeding the device rate limit\\.\n"]
2830    pub fn get_tx_hw_drop_ratelimits(&self) -> Result<u32, ErrorContext> {
2831        let mut iter = self.clone();
2832        iter.pos = 0;
2833        for attr in iter {
2834            if let Qstats::TxHwDropRatelimits(val) = attr? {
2835                return Ok(val);
2836            }
2837        }
2838        Err(ErrorContext::new_missing(
2839            "Qstats",
2840            "TxHwDropRatelimits",
2841            self.orig_loc,
2842            self.buf.as_ptr() as usize,
2843        ))
2844    }
2845    #[doc = "Number of times driver paused accepting new tx packets\nfrom the stack to this queue, because the queue was full\\.\nNote that if BQL is supported and enabled on the device\nthe networking stack will avoid queuing a lot of data at once\\.\n"]
2846    pub fn get_tx_stop(&self) -> Result<u32, ErrorContext> {
2847        let mut iter = self.clone();
2848        iter.pos = 0;
2849        for attr in iter {
2850            if let Qstats::TxStop(val) = attr? {
2851                return Ok(val);
2852            }
2853        }
2854        Err(ErrorContext::new_missing(
2855            "Qstats",
2856            "TxStop",
2857            self.orig_loc,
2858            self.buf.as_ptr() as usize,
2859        ))
2860    }
2861    #[doc = "Number of times driver re\\-started accepting send\nrequests to this queue from the stack\\.\n"]
2862    pub fn get_tx_wake(&self) -> Result<u32, ErrorContext> {
2863        let mut iter = self.clone();
2864        iter.pos = 0;
2865        for attr in iter {
2866            if let Qstats::TxWake(val) = attr? {
2867                return Ok(val);
2868            }
2869        }
2870        Err(ErrorContext::new_missing(
2871            "Qstats",
2872            "TxWake",
2873            self.orig_loc,
2874            self.buf.as_ptr() as usize,
2875        ))
2876    }
2877}
2878impl Qstats {
2879    pub fn new<'a>(buf: &'a [u8]) -> IterableQstats<'a> {
2880        IterableQstats::with_loc(buf, buf.as_ptr() as usize)
2881    }
2882    fn attr_from_type(r#type: u16) -> Option<&'static str> {
2883        let res = match r#type {
2884            1u16 => "Ifindex",
2885            2u16 => "QueueType",
2886            3u16 => "QueueId",
2887            4u16 => "Scope",
2888            8u16 => "RxPackets",
2889            9u16 => "RxBytes",
2890            10u16 => "TxPackets",
2891            11u16 => "TxBytes",
2892            12u16 => "RxAllocFail",
2893            13u16 => "RxHwDrops",
2894            14u16 => "RxHwDropOverruns",
2895            15u16 => "RxCsumComplete",
2896            16u16 => "RxCsumUnnecessary",
2897            17u16 => "RxCsumNone",
2898            18u16 => "RxCsumBad",
2899            19u16 => "RxHwGroPackets",
2900            20u16 => "RxHwGroBytes",
2901            21u16 => "RxHwGroWirePackets",
2902            22u16 => "RxHwGroWireBytes",
2903            23u16 => "RxHwDropRatelimits",
2904            24u16 => "TxHwDrops",
2905            25u16 => "TxHwDropErrors",
2906            26u16 => "TxCsumNone",
2907            27u16 => "TxNeedsCsum",
2908            28u16 => "TxHwGsoPackets",
2909            29u16 => "TxHwGsoBytes",
2910            30u16 => "TxHwGsoWirePackets",
2911            31u16 => "TxHwGsoWireBytes",
2912            32u16 => "TxHwDropRatelimits",
2913            33u16 => "TxStop",
2914            34u16 => "TxWake",
2915            _ => return None,
2916        };
2917        Some(res)
2918    }
2919}
2920#[derive(Clone, Copy, Default)]
2921pub struct IterableQstats<'a> {
2922    buf: &'a [u8],
2923    pos: usize,
2924    orig_loc: usize,
2925}
2926impl<'a> IterableQstats<'a> {
2927    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
2928        Self {
2929            buf,
2930            pos: 0,
2931            orig_loc,
2932        }
2933    }
2934    pub fn get_buf(&self) -> &'a [u8] {
2935        self.buf
2936    }
2937}
2938impl<'a> Iterator for IterableQstats<'a> {
2939    type Item = Result<Qstats, ErrorContext>;
2940    fn next(&mut self) -> Option<Self::Item> {
2941        let pos = self.pos;
2942        let mut r#type;
2943        loop {
2944            r#type = None;
2945            if self.buf.len() == self.pos {
2946                return None;
2947            }
2948            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
2949                break;
2950            };
2951            r#type = Some(header.r#type);
2952            let res = match header.r#type {
2953                1u16 => Qstats::Ifindex({
2954                    let res = parse_u32(next);
2955                    let Some(val) = res else { break };
2956                    val
2957                }),
2958                2u16 => Qstats::QueueType({
2959                    let res = parse_u32(next);
2960                    let Some(val) = res else { break };
2961                    val
2962                }),
2963                3u16 => Qstats::QueueId({
2964                    let res = parse_u32(next);
2965                    let Some(val) = res else { break };
2966                    val
2967                }),
2968                4u16 => Qstats::Scope({
2969                    let res = parse_u32(next);
2970                    let Some(val) = res else { break };
2971                    val
2972                }),
2973                8u16 => Qstats::RxPackets({
2974                    let res = parse_u32(next);
2975                    let Some(val) = res else { break };
2976                    val
2977                }),
2978                9u16 => Qstats::RxBytes({
2979                    let res = parse_u32(next);
2980                    let Some(val) = res else { break };
2981                    val
2982                }),
2983                10u16 => Qstats::TxPackets({
2984                    let res = parse_u32(next);
2985                    let Some(val) = res else { break };
2986                    val
2987                }),
2988                11u16 => Qstats::TxBytes({
2989                    let res = parse_u32(next);
2990                    let Some(val) = res else { break };
2991                    val
2992                }),
2993                12u16 => Qstats::RxAllocFail({
2994                    let res = parse_u32(next);
2995                    let Some(val) = res else { break };
2996                    val
2997                }),
2998                13u16 => Qstats::RxHwDrops({
2999                    let res = parse_u32(next);
3000                    let Some(val) = res else { break };
3001                    val
3002                }),
3003                14u16 => Qstats::RxHwDropOverruns({
3004                    let res = parse_u32(next);
3005                    let Some(val) = res else { break };
3006                    val
3007                }),
3008                15u16 => Qstats::RxCsumComplete({
3009                    let res = parse_u32(next);
3010                    let Some(val) = res else { break };
3011                    val
3012                }),
3013                16u16 => Qstats::RxCsumUnnecessary({
3014                    let res = parse_u32(next);
3015                    let Some(val) = res else { break };
3016                    val
3017                }),
3018                17u16 => Qstats::RxCsumNone({
3019                    let res = parse_u32(next);
3020                    let Some(val) = res else { break };
3021                    val
3022                }),
3023                18u16 => Qstats::RxCsumBad({
3024                    let res = parse_u32(next);
3025                    let Some(val) = res else { break };
3026                    val
3027                }),
3028                19u16 => Qstats::RxHwGroPackets({
3029                    let res = parse_u32(next);
3030                    let Some(val) = res else { break };
3031                    val
3032                }),
3033                20u16 => Qstats::RxHwGroBytes({
3034                    let res = parse_u32(next);
3035                    let Some(val) = res else { break };
3036                    val
3037                }),
3038                21u16 => Qstats::RxHwGroWirePackets({
3039                    let res = parse_u32(next);
3040                    let Some(val) = res else { break };
3041                    val
3042                }),
3043                22u16 => Qstats::RxHwGroWireBytes({
3044                    let res = parse_u32(next);
3045                    let Some(val) = res else { break };
3046                    val
3047                }),
3048                23u16 => Qstats::RxHwDropRatelimits({
3049                    let res = parse_u32(next);
3050                    let Some(val) = res else { break };
3051                    val
3052                }),
3053                24u16 => Qstats::TxHwDrops({
3054                    let res = parse_u32(next);
3055                    let Some(val) = res else { break };
3056                    val
3057                }),
3058                25u16 => Qstats::TxHwDropErrors({
3059                    let res = parse_u32(next);
3060                    let Some(val) = res else { break };
3061                    val
3062                }),
3063                26u16 => Qstats::TxCsumNone({
3064                    let res = parse_u32(next);
3065                    let Some(val) = res else { break };
3066                    val
3067                }),
3068                27u16 => Qstats::TxNeedsCsum({
3069                    let res = parse_u32(next);
3070                    let Some(val) = res else { break };
3071                    val
3072                }),
3073                28u16 => Qstats::TxHwGsoPackets({
3074                    let res = parse_u32(next);
3075                    let Some(val) = res else { break };
3076                    val
3077                }),
3078                29u16 => Qstats::TxHwGsoBytes({
3079                    let res = parse_u32(next);
3080                    let Some(val) = res else { break };
3081                    val
3082                }),
3083                30u16 => Qstats::TxHwGsoWirePackets({
3084                    let res = parse_u32(next);
3085                    let Some(val) = res else { break };
3086                    val
3087                }),
3088                31u16 => Qstats::TxHwGsoWireBytes({
3089                    let res = parse_u32(next);
3090                    let Some(val) = res else { break };
3091                    val
3092                }),
3093                32u16 => Qstats::TxHwDropRatelimits({
3094                    let res = parse_u32(next);
3095                    let Some(val) = res else { break };
3096                    val
3097                }),
3098                33u16 => Qstats::TxStop({
3099                    let res = parse_u32(next);
3100                    let Some(val) = res else { break };
3101                    val
3102                }),
3103                34u16 => Qstats::TxWake({
3104                    let res = parse_u32(next);
3105                    let Some(val) = res else { break };
3106                    val
3107                }),
3108                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
3109                n => continue,
3110            };
3111            return Some(Ok(res));
3112        }
3113        Some(Err(ErrorContext::new(
3114            "Qstats",
3115            r#type.and_then(|t| Qstats::attr_from_type(t)),
3116            self.orig_loc,
3117            self.buf.as_ptr().wrapping_add(pos) as usize,
3118        )))
3119    }
3120}
3121impl std::fmt::Debug for IterableQstats<'_> {
3122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3123        let mut fmt = f.debug_struct("Qstats");
3124        for attr in self.clone() {
3125            let attr = match attr {
3126                Ok(a) => a,
3127                Err(err) => {
3128                    fmt.finish()?;
3129                    f.write_str("Err(")?;
3130                    err.fmt(f)?;
3131                    return f.write_str(")");
3132                }
3133            };
3134            match attr {
3135                Qstats::Ifindex(val) => fmt.field("Ifindex", &val),
3136                Qstats::QueueType(val) => {
3137                    fmt.field("QueueType", &FormatEnum(val.into(), QueueType::from_value))
3138                }
3139                Qstats::QueueId(val) => fmt.field("QueueId", &val),
3140                Qstats::Scope(val) => {
3141                    fmt.field("Scope", &FormatFlags(val.into(), QstatsScope::from_value))
3142                }
3143                Qstats::RxPackets(val) => fmt.field("RxPackets", &val),
3144                Qstats::RxBytes(val) => fmt.field("RxBytes", &val),
3145                Qstats::TxPackets(val) => fmt.field("TxPackets", &val),
3146                Qstats::TxBytes(val) => fmt.field("TxBytes", &val),
3147                Qstats::RxAllocFail(val) => fmt.field("RxAllocFail", &val),
3148                Qstats::RxHwDrops(val) => fmt.field("RxHwDrops", &val),
3149                Qstats::RxHwDropOverruns(val) => fmt.field("RxHwDropOverruns", &val),
3150                Qstats::RxCsumComplete(val) => fmt.field("RxCsumComplete", &val),
3151                Qstats::RxCsumUnnecessary(val) => fmt.field("RxCsumUnnecessary", &val),
3152                Qstats::RxCsumNone(val) => fmt.field("RxCsumNone", &val),
3153                Qstats::RxCsumBad(val) => fmt.field("RxCsumBad", &val),
3154                Qstats::RxHwGroPackets(val) => fmt.field("RxHwGroPackets", &val),
3155                Qstats::RxHwGroBytes(val) => fmt.field("RxHwGroBytes", &val),
3156                Qstats::RxHwGroWirePackets(val) => fmt.field("RxHwGroWirePackets", &val),
3157                Qstats::RxHwGroWireBytes(val) => fmt.field("RxHwGroWireBytes", &val),
3158                Qstats::RxHwDropRatelimits(val) => fmt.field("RxHwDropRatelimits", &val),
3159                Qstats::TxHwDrops(val) => fmt.field("TxHwDrops", &val),
3160                Qstats::TxHwDropErrors(val) => fmt.field("TxHwDropErrors", &val),
3161                Qstats::TxCsumNone(val) => fmt.field("TxCsumNone", &val),
3162                Qstats::TxNeedsCsum(val) => fmt.field("TxNeedsCsum", &val),
3163                Qstats::TxHwGsoPackets(val) => fmt.field("TxHwGsoPackets", &val),
3164                Qstats::TxHwGsoBytes(val) => fmt.field("TxHwGsoBytes", &val),
3165                Qstats::TxHwGsoWirePackets(val) => fmt.field("TxHwGsoWirePackets", &val),
3166                Qstats::TxHwGsoWireBytes(val) => fmt.field("TxHwGsoWireBytes", &val),
3167                Qstats::TxHwDropRatelimits(val) => fmt.field("TxHwDropRatelimits", &val),
3168                Qstats::TxStop(val) => fmt.field("TxStop", &val),
3169                Qstats::TxWake(val) => fmt.field("TxWake", &val),
3170            };
3171        }
3172        fmt.finish()
3173    }
3174}
3175impl IterableQstats<'_> {
3176    pub fn lookup_attr(
3177        &self,
3178        offset: usize,
3179        missing_type: Option<u16>,
3180    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
3181        let mut stack = Vec::new();
3182        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
3183        if missing_type.is_some() && cur == offset {
3184            stack.push(("Qstats", offset));
3185            return (stack, missing_type.and_then(|t| Qstats::attr_from_type(t)));
3186        }
3187        if cur > offset || cur + self.buf.len() < offset {
3188            return (stack, None);
3189        }
3190        let mut attrs = self.clone();
3191        let mut last_off = cur + attrs.pos;
3192        while let Some(attr) = attrs.next() {
3193            let Ok(attr) = attr else { break };
3194            match attr {
3195                Qstats::Ifindex(val) => {
3196                    if last_off == offset {
3197                        stack.push(("Ifindex", last_off));
3198                        break;
3199                    }
3200                }
3201                Qstats::QueueType(val) => {
3202                    if last_off == offset {
3203                        stack.push(("QueueType", last_off));
3204                        break;
3205                    }
3206                }
3207                Qstats::QueueId(val) => {
3208                    if last_off == offset {
3209                        stack.push(("QueueId", last_off));
3210                        break;
3211                    }
3212                }
3213                Qstats::Scope(val) => {
3214                    if last_off == offset {
3215                        stack.push(("Scope", last_off));
3216                        break;
3217                    }
3218                }
3219                Qstats::RxPackets(val) => {
3220                    if last_off == offset {
3221                        stack.push(("RxPackets", last_off));
3222                        break;
3223                    }
3224                }
3225                Qstats::RxBytes(val) => {
3226                    if last_off == offset {
3227                        stack.push(("RxBytes", last_off));
3228                        break;
3229                    }
3230                }
3231                Qstats::TxPackets(val) => {
3232                    if last_off == offset {
3233                        stack.push(("TxPackets", last_off));
3234                        break;
3235                    }
3236                }
3237                Qstats::TxBytes(val) => {
3238                    if last_off == offset {
3239                        stack.push(("TxBytes", last_off));
3240                        break;
3241                    }
3242                }
3243                Qstats::RxAllocFail(val) => {
3244                    if last_off == offset {
3245                        stack.push(("RxAllocFail", last_off));
3246                        break;
3247                    }
3248                }
3249                Qstats::RxHwDrops(val) => {
3250                    if last_off == offset {
3251                        stack.push(("RxHwDrops", last_off));
3252                        break;
3253                    }
3254                }
3255                Qstats::RxHwDropOverruns(val) => {
3256                    if last_off == offset {
3257                        stack.push(("RxHwDropOverruns", last_off));
3258                        break;
3259                    }
3260                }
3261                Qstats::RxCsumComplete(val) => {
3262                    if last_off == offset {
3263                        stack.push(("RxCsumComplete", last_off));
3264                        break;
3265                    }
3266                }
3267                Qstats::RxCsumUnnecessary(val) => {
3268                    if last_off == offset {
3269                        stack.push(("RxCsumUnnecessary", last_off));
3270                        break;
3271                    }
3272                }
3273                Qstats::RxCsumNone(val) => {
3274                    if last_off == offset {
3275                        stack.push(("RxCsumNone", last_off));
3276                        break;
3277                    }
3278                }
3279                Qstats::RxCsumBad(val) => {
3280                    if last_off == offset {
3281                        stack.push(("RxCsumBad", last_off));
3282                        break;
3283                    }
3284                }
3285                Qstats::RxHwGroPackets(val) => {
3286                    if last_off == offset {
3287                        stack.push(("RxHwGroPackets", last_off));
3288                        break;
3289                    }
3290                }
3291                Qstats::RxHwGroBytes(val) => {
3292                    if last_off == offset {
3293                        stack.push(("RxHwGroBytes", last_off));
3294                        break;
3295                    }
3296                }
3297                Qstats::RxHwGroWirePackets(val) => {
3298                    if last_off == offset {
3299                        stack.push(("RxHwGroWirePackets", last_off));
3300                        break;
3301                    }
3302                }
3303                Qstats::RxHwGroWireBytes(val) => {
3304                    if last_off == offset {
3305                        stack.push(("RxHwGroWireBytes", last_off));
3306                        break;
3307                    }
3308                }
3309                Qstats::RxHwDropRatelimits(val) => {
3310                    if last_off == offset {
3311                        stack.push(("RxHwDropRatelimits", last_off));
3312                        break;
3313                    }
3314                }
3315                Qstats::TxHwDrops(val) => {
3316                    if last_off == offset {
3317                        stack.push(("TxHwDrops", last_off));
3318                        break;
3319                    }
3320                }
3321                Qstats::TxHwDropErrors(val) => {
3322                    if last_off == offset {
3323                        stack.push(("TxHwDropErrors", last_off));
3324                        break;
3325                    }
3326                }
3327                Qstats::TxCsumNone(val) => {
3328                    if last_off == offset {
3329                        stack.push(("TxCsumNone", last_off));
3330                        break;
3331                    }
3332                }
3333                Qstats::TxNeedsCsum(val) => {
3334                    if last_off == offset {
3335                        stack.push(("TxNeedsCsum", last_off));
3336                        break;
3337                    }
3338                }
3339                Qstats::TxHwGsoPackets(val) => {
3340                    if last_off == offset {
3341                        stack.push(("TxHwGsoPackets", last_off));
3342                        break;
3343                    }
3344                }
3345                Qstats::TxHwGsoBytes(val) => {
3346                    if last_off == offset {
3347                        stack.push(("TxHwGsoBytes", last_off));
3348                        break;
3349                    }
3350                }
3351                Qstats::TxHwGsoWirePackets(val) => {
3352                    if last_off == offset {
3353                        stack.push(("TxHwGsoWirePackets", last_off));
3354                        break;
3355                    }
3356                }
3357                Qstats::TxHwGsoWireBytes(val) => {
3358                    if last_off == offset {
3359                        stack.push(("TxHwGsoWireBytes", last_off));
3360                        break;
3361                    }
3362                }
3363                Qstats::TxHwDropRatelimits(val) => {
3364                    if last_off == offset {
3365                        stack.push(("TxHwDropRatelimits", last_off));
3366                        break;
3367                    }
3368                }
3369                Qstats::TxStop(val) => {
3370                    if last_off == offset {
3371                        stack.push(("TxStop", last_off));
3372                        break;
3373                    }
3374                }
3375                Qstats::TxWake(val) => {
3376                    if last_off == offset {
3377                        stack.push(("TxWake", last_off));
3378                        break;
3379                    }
3380                }
3381                _ => {}
3382            };
3383            last_off = cur + attrs.pos;
3384        }
3385        if !stack.is_empty() {
3386            stack.push(("Qstats", cur));
3387        }
3388        (stack, None)
3389    }
3390}
3391#[derive(Clone)]
3392pub enum QueueId {
3393    #[doc = "Queue index; most queue types are indexed like a C array, with indexes starting at 0 and ending at queue count \\- 1\\. Queue indexes are scoped to an interface and queue type\\."]
3394    Id(u32),
3395    #[doc = "Queue type as rx, tx\\. Each queue type defines a separate ID space\\. XDP TX queues allocated in the kernel are not linked to NAPIs and thus not listed\\. AF\\_XDP queues will have more information set in the xsk attribute\\.\nAssociated type: [`QueueType`] (enum)"]
3396    Type(u32),
3397}
3398impl<'a> IterableQueueId<'a> {
3399    #[doc = "Queue index; most queue types are indexed like a C array, with indexes starting at 0 and ending at queue count \\- 1\\. Queue indexes are scoped to an interface and queue type\\."]
3400    pub fn get_id(&self) -> Result<u32, ErrorContext> {
3401        let mut iter = self.clone();
3402        iter.pos = 0;
3403        for attr in iter {
3404            if let QueueId::Id(val) = attr? {
3405                return Ok(val);
3406            }
3407        }
3408        Err(ErrorContext::new_missing(
3409            "QueueId",
3410            "Id",
3411            self.orig_loc,
3412            self.buf.as_ptr() as usize,
3413        ))
3414    }
3415    #[doc = "Queue type as rx, tx\\. Each queue type defines a separate ID space\\. XDP TX queues allocated in the kernel are not linked to NAPIs and thus not listed\\. AF\\_XDP queues will have more information set in the xsk attribute\\.\nAssociated type: [`QueueType`] (enum)"]
3416    pub fn get_type(&self) -> Result<u32, ErrorContext> {
3417        let mut iter = self.clone();
3418        iter.pos = 0;
3419        for attr in iter {
3420            if let QueueId::Type(val) = attr? {
3421                return Ok(val);
3422            }
3423        }
3424        Err(ErrorContext::new_missing(
3425            "QueueId",
3426            "Type",
3427            self.orig_loc,
3428            self.buf.as_ptr() as usize,
3429        ))
3430    }
3431}
3432impl QueueId {
3433    pub fn new<'a>(buf: &'a [u8]) -> IterableQueueId<'a> {
3434        IterableQueueId::with_loc(buf, buf.as_ptr() as usize)
3435    }
3436    fn attr_from_type(r#type: u16) -> Option<&'static str> {
3437        Queue::attr_from_type(r#type)
3438    }
3439}
3440#[derive(Clone, Copy, Default)]
3441pub struct IterableQueueId<'a> {
3442    buf: &'a [u8],
3443    pos: usize,
3444    orig_loc: usize,
3445}
3446impl<'a> IterableQueueId<'a> {
3447    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
3448        Self {
3449            buf,
3450            pos: 0,
3451            orig_loc,
3452        }
3453    }
3454    pub fn get_buf(&self) -> &'a [u8] {
3455        self.buf
3456    }
3457}
3458impl<'a> Iterator for IterableQueueId<'a> {
3459    type Item = Result<QueueId, ErrorContext>;
3460    fn next(&mut self) -> Option<Self::Item> {
3461        let pos = self.pos;
3462        let mut r#type;
3463        loop {
3464            r#type = None;
3465            if self.buf.len() == self.pos {
3466                return None;
3467            }
3468            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
3469                break;
3470            };
3471            r#type = Some(header.r#type);
3472            let res = match header.r#type {
3473                1u16 => QueueId::Id({
3474                    let res = parse_u32(next);
3475                    let Some(val) = res else { break };
3476                    val
3477                }),
3478                3u16 => QueueId::Type({
3479                    let res = parse_u32(next);
3480                    let Some(val) = res else { break };
3481                    val
3482                }),
3483                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
3484                n => continue,
3485            };
3486            return Some(Ok(res));
3487        }
3488        Some(Err(ErrorContext::new(
3489            "QueueId",
3490            r#type.and_then(|t| QueueId::attr_from_type(t)),
3491            self.orig_loc,
3492            self.buf.as_ptr().wrapping_add(pos) as usize,
3493        )))
3494    }
3495}
3496impl std::fmt::Debug for IterableQueueId<'_> {
3497    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3498        let mut fmt = f.debug_struct("QueueId");
3499        for attr in self.clone() {
3500            let attr = match attr {
3501                Ok(a) => a,
3502                Err(err) => {
3503                    fmt.finish()?;
3504                    f.write_str("Err(")?;
3505                    err.fmt(f)?;
3506                    return f.write_str(")");
3507                }
3508            };
3509            match attr {
3510                QueueId::Id(val) => fmt.field("Id", &val),
3511                QueueId::Type(val) => {
3512                    fmt.field("Type", &FormatEnum(val.into(), QueueType::from_value))
3513                }
3514            };
3515        }
3516        fmt.finish()
3517    }
3518}
3519impl IterableQueueId<'_> {
3520    pub fn lookup_attr(
3521        &self,
3522        offset: usize,
3523        missing_type: Option<u16>,
3524    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
3525        let mut stack = Vec::new();
3526        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
3527        if missing_type.is_some() && cur == offset {
3528            stack.push(("QueueId", offset));
3529            return (stack, missing_type.and_then(|t| QueueId::attr_from_type(t)));
3530        }
3531        if cur > offset || cur + self.buf.len() < offset {
3532            return (stack, None);
3533        }
3534        let mut attrs = self.clone();
3535        let mut last_off = cur + attrs.pos;
3536        while let Some(attr) = attrs.next() {
3537            let Ok(attr) = attr else { break };
3538            match attr {
3539                QueueId::Id(val) => {
3540                    if last_off == offset {
3541                        stack.push(("Id", last_off));
3542                        break;
3543                    }
3544                }
3545                QueueId::Type(val) => {
3546                    if last_off == offset {
3547                        stack.push(("Type", last_off));
3548                        break;
3549                    }
3550                }
3551                _ => {}
3552            };
3553            last_off = cur + attrs.pos;
3554        }
3555        if !stack.is_empty() {
3556            stack.push(("QueueId", cur));
3557        }
3558        (stack, None)
3559    }
3560}
3561#[derive(Clone)]
3562pub enum Dmabuf<'a> {
3563    #[doc = "netdev ifindex to bind the dmabuf to\\."]
3564    Ifindex(u32),
3565    #[doc = "receive queues to bind the dmabuf to\\.\nAttribute may repeat multiple times (treat it as array)"]
3566    Queues(IterableQueueId<'a>),
3567    #[doc = "dmabuf file descriptor to bind\\."]
3568    Fd(u32),
3569    #[doc = "id of the dmabuf binding"]
3570    Id(u32),
3571}
3572impl<'a> IterableDmabuf<'a> {
3573    #[doc = "netdev ifindex to bind the dmabuf to\\."]
3574    pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
3575        let mut iter = self.clone();
3576        iter.pos = 0;
3577        for attr in iter {
3578            if let Dmabuf::Ifindex(val) = attr? {
3579                return Ok(val);
3580            }
3581        }
3582        Err(ErrorContext::new_missing(
3583            "Dmabuf",
3584            "Ifindex",
3585            self.orig_loc,
3586            self.buf.as_ptr() as usize,
3587        ))
3588    }
3589    #[doc = "receive queues to bind the dmabuf to\\.\nAttribute may repeat multiple times (treat it as array)"]
3590    pub fn get_queues(&self) -> MultiAttrIterable<Self, Dmabuf<'a>, IterableQueueId<'a>> {
3591        MultiAttrIterable::new(self.clone(), |variant| {
3592            if let Dmabuf::Queues(val) = variant {
3593                Some(val)
3594            } else {
3595                None
3596            }
3597        })
3598    }
3599    #[doc = "dmabuf file descriptor to bind\\."]
3600    pub fn get_fd(&self) -> Result<u32, ErrorContext> {
3601        let mut iter = self.clone();
3602        iter.pos = 0;
3603        for attr in iter {
3604            if let Dmabuf::Fd(val) = attr? {
3605                return Ok(val);
3606            }
3607        }
3608        Err(ErrorContext::new_missing(
3609            "Dmabuf",
3610            "Fd",
3611            self.orig_loc,
3612            self.buf.as_ptr() as usize,
3613        ))
3614    }
3615    #[doc = "id of the dmabuf binding"]
3616    pub fn get_id(&self) -> Result<u32, ErrorContext> {
3617        let mut iter = self.clone();
3618        iter.pos = 0;
3619        for attr in iter {
3620            if let Dmabuf::Id(val) = attr? {
3621                return Ok(val);
3622            }
3623        }
3624        Err(ErrorContext::new_missing(
3625            "Dmabuf",
3626            "Id",
3627            self.orig_loc,
3628            self.buf.as_ptr() as usize,
3629        ))
3630    }
3631}
3632impl Dmabuf<'_> {
3633    pub fn new<'a>(buf: &'a [u8]) -> IterableDmabuf<'a> {
3634        IterableDmabuf::with_loc(buf, buf.as_ptr() as usize)
3635    }
3636    fn attr_from_type(r#type: u16) -> Option<&'static str> {
3637        let res = match r#type {
3638            1u16 => "Ifindex",
3639            2u16 => "Queues",
3640            3u16 => "Fd",
3641            4u16 => "Id",
3642            _ => return None,
3643        };
3644        Some(res)
3645    }
3646}
3647#[derive(Clone, Copy, Default)]
3648pub struct IterableDmabuf<'a> {
3649    buf: &'a [u8],
3650    pos: usize,
3651    orig_loc: usize,
3652}
3653impl<'a> IterableDmabuf<'a> {
3654    fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
3655        Self {
3656            buf,
3657            pos: 0,
3658            orig_loc,
3659        }
3660    }
3661    pub fn get_buf(&self) -> &'a [u8] {
3662        self.buf
3663    }
3664}
3665impl<'a> Iterator for IterableDmabuf<'a> {
3666    type Item = Result<Dmabuf<'a>, ErrorContext>;
3667    fn next(&mut self) -> Option<Self::Item> {
3668        let pos = self.pos;
3669        let mut r#type;
3670        loop {
3671            r#type = None;
3672            if self.buf.len() == self.pos {
3673                return None;
3674            }
3675            let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
3676                break;
3677            };
3678            r#type = Some(header.r#type);
3679            let res = match header.r#type {
3680                1u16 => Dmabuf::Ifindex({
3681                    let res = parse_u32(next);
3682                    let Some(val) = res else { break };
3683                    val
3684                }),
3685                2u16 => Dmabuf::Queues({
3686                    let res = Some(IterableQueueId::with_loc(next, self.orig_loc));
3687                    let Some(val) = res else { break };
3688                    val
3689                }),
3690                3u16 => Dmabuf::Fd({
3691                    let res = parse_u32(next);
3692                    let Some(val) = res else { break };
3693                    val
3694                }),
3695                4u16 => Dmabuf::Id({
3696                    let res = parse_u32(next);
3697                    let Some(val) = res else { break };
3698                    val
3699                }),
3700                n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
3701                n => continue,
3702            };
3703            return Some(Ok(res));
3704        }
3705        Some(Err(ErrorContext::new(
3706            "Dmabuf",
3707            r#type.and_then(|t| Dmabuf::attr_from_type(t)),
3708            self.orig_loc,
3709            self.buf.as_ptr().wrapping_add(pos) as usize,
3710        )))
3711    }
3712}
3713impl<'a> std::fmt::Debug for IterableDmabuf<'_> {
3714    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3715        let mut fmt = f.debug_struct("Dmabuf");
3716        for attr in self.clone() {
3717            let attr = match attr {
3718                Ok(a) => a,
3719                Err(err) => {
3720                    fmt.finish()?;
3721                    f.write_str("Err(")?;
3722                    err.fmt(f)?;
3723                    return f.write_str(")");
3724                }
3725            };
3726            match attr {
3727                Dmabuf::Ifindex(val) => fmt.field("Ifindex", &val),
3728                Dmabuf::Queues(val) => fmt.field("Queues", &val),
3729                Dmabuf::Fd(val) => fmt.field("Fd", &val),
3730                Dmabuf::Id(val) => fmt.field("Id", &val),
3731            };
3732        }
3733        fmt.finish()
3734    }
3735}
3736impl IterableDmabuf<'_> {
3737    pub fn lookup_attr(
3738        &self,
3739        offset: usize,
3740        missing_type: Option<u16>,
3741    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
3742        let mut stack = Vec::new();
3743        let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
3744        if missing_type.is_some() && cur == offset {
3745            stack.push(("Dmabuf", offset));
3746            return (stack, missing_type.and_then(|t| Dmabuf::attr_from_type(t)));
3747        }
3748        if cur > offset || cur + self.buf.len() < offset {
3749            return (stack, None);
3750        }
3751        let mut attrs = self.clone();
3752        let mut last_off = cur + attrs.pos;
3753        let mut missing = None;
3754        while let Some(attr) = attrs.next() {
3755            let Ok(attr) = attr else { break };
3756            match attr {
3757                Dmabuf::Ifindex(val) => {
3758                    if last_off == offset {
3759                        stack.push(("Ifindex", last_off));
3760                        break;
3761                    }
3762                }
3763                Dmabuf::Queues(val) => {
3764                    (stack, missing) = val.lookup_attr(offset, missing_type);
3765                    if !stack.is_empty() {
3766                        break;
3767                    }
3768                }
3769                Dmabuf::Fd(val) => {
3770                    if last_off == offset {
3771                        stack.push(("Fd", last_off));
3772                        break;
3773                    }
3774                }
3775                Dmabuf::Id(val) => {
3776                    if last_off == offset {
3777                        stack.push(("Id", last_off));
3778                        break;
3779                    }
3780                }
3781                _ => {}
3782            };
3783            last_off = cur + attrs.pos;
3784        }
3785        if !stack.is_empty() {
3786            stack.push(("Dmabuf", cur));
3787        }
3788        (stack, missing)
3789    }
3790}
3791pub struct PushDev<Prev: Rec> {
3792    pub(crate) prev: Option<Prev>,
3793    pub(crate) header_offset: Option<usize>,
3794}
3795impl<Prev: Rec> Rec for PushDev<Prev> {
3796    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
3797        self.prev.as_mut().unwrap().as_rec_mut()
3798    }
3799    fn as_rec(&self) -> &Vec<u8> {
3800        self.prev.as_ref().unwrap().as_rec()
3801    }
3802}
3803impl<Prev: Rec> PushDev<Prev> {
3804    pub fn new(prev: Prev) -> Self {
3805        Self {
3806            prev: Some(prev),
3807            header_offset: None,
3808        }
3809    }
3810    pub fn end_nested(mut self) -> Prev {
3811        let mut prev = self.prev.take().unwrap();
3812        if let Some(header_offset) = &self.header_offset {
3813            finalize_nested_header(prev.as_rec_mut(), *header_offset);
3814        }
3815        prev
3816    }
3817    #[doc = "netdev ifindex"]
3818    pub fn push_ifindex(mut self, value: u32) -> Self {
3819        push_header(self.as_rec_mut(), 1u16, 4 as u16);
3820        self.as_rec_mut().extend(value.to_ne_bytes());
3821        self
3822    }
3823    pub fn push_pad(mut self, value: &[u8]) -> Self {
3824        push_header(self.as_rec_mut(), 2u16, value.len() as u16);
3825        self.as_rec_mut().extend(value);
3826        self
3827    }
3828    #[doc = "Bitmask of enabled xdp\\-features\\.\nAssociated type: [`XdpAct`] (enum)"]
3829    pub fn push_xdp_features(mut self, value: u64) -> Self {
3830        push_header(self.as_rec_mut(), 3u16, 8 as u16);
3831        self.as_rec_mut().extend(value.to_ne_bytes());
3832        self
3833    }
3834    #[doc = "max fragment count supported by ZC driver"]
3835    pub fn push_xdp_zc_max_segs(mut self, value: u32) -> Self {
3836        push_header(self.as_rec_mut(), 4u16, 4 as u16);
3837        self.as_rec_mut().extend(value.to_ne_bytes());
3838        self
3839    }
3840    #[doc = "Bitmask of supported XDP receive metadata features\\. See Documentation/networking/xdp\\-rx\\-metadata\\.rst for more details\\.\nAssociated type: [`XdpRxMetadata`] (enum)"]
3841    pub fn push_xdp_rx_metadata_features(mut self, value: u64) -> Self {
3842        push_header(self.as_rec_mut(), 5u16, 8 as u16);
3843        self.as_rec_mut().extend(value.to_ne_bytes());
3844        self
3845    }
3846    #[doc = "Bitmask of enabled AF\\_XDP features\\.\nAssociated type: [`XskFlags`] (enum)"]
3847    pub fn push_xsk_features(mut self, value: u64) -> Self {
3848        push_header(self.as_rec_mut(), 6u16, 8 as u16);
3849        self.as_rec_mut().extend(value.to_ne_bytes());
3850        self
3851    }
3852}
3853impl<Prev: Rec> Drop for PushDev<Prev> {
3854    fn drop(&mut self) {
3855        if let Some(prev) = &mut self.prev {
3856            if let Some(header_offset) = &self.header_offset {
3857                finalize_nested_header(prev.as_rec_mut(), *header_offset);
3858            }
3859        }
3860    }
3861}
3862pub struct PushIoUringProviderInfo<Prev: Rec> {
3863    pub(crate) prev: Option<Prev>,
3864    pub(crate) header_offset: Option<usize>,
3865}
3866impl<Prev: Rec> Rec for PushIoUringProviderInfo<Prev> {
3867    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
3868        self.prev.as_mut().unwrap().as_rec_mut()
3869    }
3870    fn as_rec(&self) -> &Vec<u8> {
3871        self.prev.as_ref().unwrap().as_rec()
3872    }
3873}
3874impl<Prev: Rec> PushIoUringProviderInfo<Prev> {
3875    pub fn new(prev: Prev) -> Self {
3876        Self {
3877            prev: Some(prev),
3878            header_offset: None,
3879        }
3880    }
3881    pub fn end_nested(mut self) -> Prev {
3882        let mut prev = self.prev.take().unwrap();
3883        if let Some(header_offset) = &self.header_offset {
3884            finalize_nested_header(prev.as_rec_mut(), *header_offset);
3885        }
3886        prev
3887    }
3888}
3889impl<Prev: Rec> Drop for PushIoUringProviderInfo<Prev> {
3890    fn drop(&mut self) {
3891        if let Some(prev) = &mut self.prev {
3892            if let Some(header_offset) = &self.header_offset {
3893                finalize_nested_header(prev.as_rec_mut(), *header_offset);
3894            }
3895        }
3896    }
3897}
3898pub struct PushPagePool<Prev: Rec> {
3899    pub(crate) prev: Option<Prev>,
3900    pub(crate) header_offset: Option<usize>,
3901}
3902impl<Prev: Rec> Rec for PushPagePool<Prev> {
3903    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
3904        self.prev.as_mut().unwrap().as_rec_mut()
3905    }
3906    fn as_rec(&self) -> &Vec<u8> {
3907        self.prev.as_ref().unwrap().as_rec()
3908    }
3909}
3910impl<Prev: Rec> PushPagePool<Prev> {
3911    pub fn new(prev: Prev) -> Self {
3912        Self {
3913            prev: Some(prev),
3914            header_offset: None,
3915        }
3916    }
3917    pub fn end_nested(mut self) -> Prev {
3918        let mut prev = self.prev.take().unwrap();
3919        if let Some(header_offset) = &self.header_offset {
3920            finalize_nested_header(prev.as_rec_mut(), *header_offset);
3921        }
3922        prev
3923    }
3924    #[doc = "Unique ID of a Page Pool instance\\."]
3925    pub fn push_id(mut self, value: u32) -> Self {
3926        push_header(self.as_rec_mut(), 1u16, 4 as u16);
3927        self.as_rec_mut().extend(value.to_ne_bytes());
3928        self
3929    }
3930    #[doc = "ifindex of the netdev to which the pool belongs\\.\nMay not be reported if the page pool was allocated for a netdev\nwhich got destroyed already (page pools may outlast their netdevs\nbecause they wait for all memory to be returned)\\.\n"]
3931    pub fn push_ifindex(mut self, value: u32) -> Self {
3932        push_header(self.as_rec_mut(), 2u16, 4 as u16);
3933        self.as_rec_mut().extend(value.to_ne_bytes());
3934        self
3935    }
3936    #[doc = "Id of NAPI using this Page Pool instance\\."]
3937    pub fn push_napi_id(mut self, value: u32) -> Self {
3938        push_header(self.as_rec_mut(), 3u16, 4 as u16);
3939        self.as_rec_mut().extend(value.to_ne_bytes());
3940        self
3941    }
3942    #[doc = "Number of outstanding references to this page pool (allocated\nbut yet to be freed pages)\\. Allocated pages may be held in\nsocket receive queues, driver receive ring, page pool recycling\nring, the page pool cache, etc\\.\n"]
3943    pub fn push_inflight(mut self, value: u32) -> Self {
3944        push_header(self.as_rec_mut(), 4u16, 4 as u16);
3945        self.as_rec_mut().extend(value.to_ne_bytes());
3946        self
3947    }
3948    #[doc = "Amount of memory held by inflight pages\\.\n"]
3949    pub fn push_inflight_mem(mut self, value: u32) -> Self {
3950        push_header(self.as_rec_mut(), 5u16, 4 as u16);
3951        self.as_rec_mut().extend(value.to_ne_bytes());
3952        self
3953    }
3954    #[doc = "Seconds in CLOCK\\_BOOTTIME of when Page Pool was detached by\nthe driver\\. Once detached Page Pool can no longer be used to\nallocate memory\\.\nPage Pools wait for all the memory allocated from them to be freed\nbefore truly disappearing\\. \"Detached\" Page Pools cannot be\n\"re\\-attached\", they are just waiting to disappear\\.\nAttribute is absent if Page Pool has not been detached, and\ncan still be used to allocate new memory\\.\n"]
3955    pub fn push_detach_time(mut self, value: u32) -> Self {
3956        push_header(self.as_rec_mut(), 6u16, 4 as u16);
3957        self.as_rec_mut().extend(value.to_ne_bytes());
3958        self
3959    }
3960    #[doc = "ID of the dmabuf this page\\-pool is attached to\\."]
3961    pub fn push_dmabuf(mut self, value: u32) -> Self {
3962        push_header(self.as_rec_mut(), 7u16, 4 as u16);
3963        self.as_rec_mut().extend(value.to_ne_bytes());
3964        self
3965    }
3966    #[doc = "io\\-uring memory provider information\\."]
3967    pub fn nested_io_uring(mut self) -> PushIoUringProviderInfo<Self> {
3968        let header_offset = push_nested_header(self.as_rec_mut(), 8u16);
3969        PushIoUringProviderInfo {
3970            prev: Some(self),
3971            header_offset: Some(header_offset),
3972        }
3973    }
3974}
3975impl<Prev: Rec> Drop for PushPagePool<Prev> {
3976    fn drop(&mut self) {
3977        if let Some(prev) = &mut self.prev {
3978            if let Some(header_offset) = &self.header_offset {
3979                finalize_nested_header(prev.as_rec_mut(), *header_offset);
3980            }
3981        }
3982    }
3983}
3984pub struct PushPagePoolInfo<Prev: Rec> {
3985    pub(crate) prev: Option<Prev>,
3986    pub(crate) header_offset: Option<usize>,
3987}
3988impl<Prev: Rec> Rec for PushPagePoolInfo<Prev> {
3989    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
3990        self.prev.as_mut().unwrap().as_rec_mut()
3991    }
3992    fn as_rec(&self) -> &Vec<u8> {
3993        self.prev.as_ref().unwrap().as_rec()
3994    }
3995}
3996impl<Prev: Rec> PushPagePoolInfo<Prev> {
3997    pub fn new(prev: Prev) -> Self {
3998        Self {
3999            prev: Some(prev),
4000            header_offset: None,
4001        }
4002    }
4003    pub fn end_nested(mut self) -> Prev {
4004        let mut prev = self.prev.take().unwrap();
4005        if let Some(header_offset) = &self.header_offset {
4006            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4007        }
4008        prev
4009    }
4010    #[doc = "Unique ID of a Page Pool instance\\."]
4011    pub fn push_id(mut self, value: u32) -> Self {
4012        push_header(self.as_rec_mut(), 1u16, 4 as u16);
4013        self.as_rec_mut().extend(value.to_ne_bytes());
4014        self
4015    }
4016    #[doc = "ifindex of the netdev to which the pool belongs\\.\nMay not be reported if the page pool was allocated for a netdev\nwhich got destroyed already (page pools may outlast their netdevs\nbecause they wait for all memory to be returned)\\.\n"]
4017    pub fn push_ifindex(mut self, value: u32) -> Self {
4018        push_header(self.as_rec_mut(), 2u16, 4 as u16);
4019        self.as_rec_mut().extend(value.to_ne_bytes());
4020        self
4021    }
4022}
4023impl<Prev: Rec> Drop for PushPagePoolInfo<Prev> {
4024    fn drop(&mut self) {
4025        if let Some(prev) = &mut self.prev {
4026            if let Some(header_offset) = &self.header_offset {
4027                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4028            }
4029        }
4030    }
4031}
4032pub struct PushPagePoolStats<Prev: Rec> {
4033    pub(crate) prev: Option<Prev>,
4034    pub(crate) header_offset: Option<usize>,
4035}
4036impl<Prev: Rec> Rec for PushPagePoolStats<Prev> {
4037    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
4038        self.prev.as_mut().unwrap().as_rec_mut()
4039    }
4040    fn as_rec(&self) -> &Vec<u8> {
4041        self.prev.as_ref().unwrap().as_rec()
4042    }
4043}
4044impl<Prev: Rec> PushPagePoolStats<Prev> {
4045    pub fn new(prev: Prev) -> Self {
4046        Self {
4047            prev: Some(prev),
4048            header_offset: None,
4049        }
4050    }
4051    pub fn end_nested(mut self) -> Prev {
4052        let mut prev = self.prev.take().unwrap();
4053        if let Some(header_offset) = &self.header_offset {
4054            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4055        }
4056        prev
4057    }
4058    #[doc = "Page pool identifying information\\."]
4059    pub fn nested_info(mut self) -> PushPagePoolInfo<Self> {
4060        let header_offset = push_nested_header(self.as_rec_mut(), 1u16);
4061        PushPagePoolInfo {
4062            prev: Some(self),
4063            header_offset: Some(header_offset),
4064        }
4065    }
4066    pub fn push_alloc_fast(mut self, value: u32) -> Self {
4067        push_header(self.as_rec_mut(), 8u16, 4 as u16);
4068        self.as_rec_mut().extend(value.to_ne_bytes());
4069        self
4070    }
4071    pub fn push_alloc_slow(mut self, value: u32) -> Self {
4072        push_header(self.as_rec_mut(), 9u16, 4 as u16);
4073        self.as_rec_mut().extend(value.to_ne_bytes());
4074        self
4075    }
4076    pub fn push_alloc_slow_high_order(mut self, value: u32) -> Self {
4077        push_header(self.as_rec_mut(), 10u16, 4 as u16);
4078        self.as_rec_mut().extend(value.to_ne_bytes());
4079        self
4080    }
4081    pub fn push_alloc_empty(mut self, value: u32) -> Self {
4082        push_header(self.as_rec_mut(), 11u16, 4 as u16);
4083        self.as_rec_mut().extend(value.to_ne_bytes());
4084        self
4085    }
4086    pub fn push_alloc_refill(mut self, value: u32) -> Self {
4087        push_header(self.as_rec_mut(), 12u16, 4 as u16);
4088        self.as_rec_mut().extend(value.to_ne_bytes());
4089        self
4090    }
4091    pub fn push_alloc_waive(mut self, value: u32) -> Self {
4092        push_header(self.as_rec_mut(), 13u16, 4 as u16);
4093        self.as_rec_mut().extend(value.to_ne_bytes());
4094        self
4095    }
4096    pub fn push_recycle_cached(mut self, value: u32) -> Self {
4097        push_header(self.as_rec_mut(), 14u16, 4 as u16);
4098        self.as_rec_mut().extend(value.to_ne_bytes());
4099        self
4100    }
4101    pub fn push_recycle_cache_full(mut self, value: u32) -> Self {
4102        push_header(self.as_rec_mut(), 15u16, 4 as u16);
4103        self.as_rec_mut().extend(value.to_ne_bytes());
4104        self
4105    }
4106    pub fn push_recycle_ring(mut self, value: u32) -> Self {
4107        push_header(self.as_rec_mut(), 16u16, 4 as u16);
4108        self.as_rec_mut().extend(value.to_ne_bytes());
4109        self
4110    }
4111    pub fn push_recycle_ring_full(mut self, value: u32) -> Self {
4112        push_header(self.as_rec_mut(), 17u16, 4 as u16);
4113        self.as_rec_mut().extend(value.to_ne_bytes());
4114        self
4115    }
4116    pub fn push_recycle_released_refcnt(mut self, value: u32) -> Self {
4117        push_header(self.as_rec_mut(), 18u16, 4 as u16);
4118        self.as_rec_mut().extend(value.to_ne_bytes());
4119        self
4120    }
4121}
4122impl<Prev: Rec> Drop for PushPagePoolStats<Prev> {
4123    fn drop(&mut self) {
4124        if let Some(prev) = &mut self.prev {
4125            if let Some(header_offset) = &self.header_offset {
4126                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4127            }
4128        }
4129    }
4130}
4131pub struct PushNapi<Prev: Rec> {
4132    pub(crate) prev: Option<Prev>,
4133    pub(crate) header_offset: Option<usize>,
4134}
4135impl<Prev: Rec> Rec for PushNapi<Prev> {
4136    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
4137        self.prev.as_mut().unwrap().as_rec_mut()
4138    }
4139    fn as_rec(&self) -> &Vec<u8> {
4140        self.prev.as_ref().unwrap().as_rec()
4141    }
4142}
4143impl<Prev: Rec> PushNapi<Prev> {
4144    pub fn new(prev: Prev) -> Self {
4145        Self {
4146            prev: Some(prev),
4147            header_offset: None,
4148        }
4149    }
4150    pub fn end_nested(mut self) -> Prev {
4151        let mut prev = self.prev.take().unwrap();
4152        if let Some(header_offset) = &self.header_offset {
4153            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4154        }
4155        prev
4156    }
4157    #[doc = "ifindex of the netdevice to which NAPI instance belongs\\."]
4158    pub fn push_ifindex(mut self, value: u32) -> Self {
4159        push_header(self.as_rec_mut(), 1u16, 4 as u16);
4160        self.as_rec_mut().extend(value.to_ne_bytes());
4161        self
4162    }
4163    #[doc = "ID of the NAPI instance\\."]
4164    pub fn push_id(mut self, value: u32) -> Self {
4165        push_header(self.as_rec_mut(), 2u16, 4 as u16);
4166        self.as_rec_mut().extend(value.to_ne_bytes());
4167        self
4168    }
4169    #[doc = "The associated interrupt vector number for the napi"]
4170    pub fn push_irq(mut self, value: u32) -> Self {
4171        push_header(self.as_rec_mut(), 3u16, 4 as u16);
4172        self.as_rec_mut().extend(value.to_ne_bytes());
4173        self
4174    }
4175    #[doc = "PID of the napi thread, if NAPI is configured to operate in threaded mode\\. If NAPI is not in threaded mode (i\\.e\\. uses normal softirq context), the attribute will be absent\\."]
4176    pub fn push_pid(mut self, value: u32) -> Self {
4177        push_header(self.as_rec_mut(), 4u16, 4 as u16);
4178        self.as_rec_mut().extend(value.to_ne_bytes());
4179        self
4180    }
4181    #[doc = "The number of consecutive empty polls before IRQ deferral ends and hardware IRQs are re\\-enabled\\."]
4182    pub fn push_defer_hard_irqs(mut self, value: u32) -> Self {
4183        push_header(self.as_rec_mut(), 5u16, 4 as u16);
4184        self.as_rec_mut().extend(value.to_ne_bytes());
4185        self
4186    }
4187    #[doc = "The timeout, in nanoseconds, of when to trigger the NAPI watchdog timer which schedules NAPI processing\\. Additionally, a non\\-zero value will also prevent GRO from flushing recent super\\-frames at the end of a NAPI cycle\\. This may add receive latency in exchange for reducing the number of frames processed by the network stack\\."]
4188    pub fn push_gro_flush_timeout(mut self, value: u32) -> Self {
4189        push_header(self.as_rec_mut(), 6u16, 4 as u16);
4190        self.as_rec_mut().extend(value.to_ne_bytes());
4191        self
4192    }
4193    #[doc = "The timeout, in nanoseconds, of how long to suspend irq processing, if event polling finds events"]
4194    pub fn push_irq_suspend_timeout(mut self, value: u32) -> Self {
4195        push_header(self.as_rec_mut(), 7u16, 4 as u16);
4196        self.as_rec_mut().extend(value.to_ne_bytes());
4197        self
4198    }
4199    #[doc = "Whether the NAPI is configured to operate in threaded polling mode\\. If this is set to enabled then the NAPI context operates in threaded polling mode\\. If this is set to busy\\-poll, then the threaded polling mode also busy polls\\.\nAssociated type: [`NapiThreaded`] (enum)"]
4200    pub fn push_threaded(mut self, value: u32) -> Self {
4201        push_header(self.as_rec_mut(), 8u16, 4 as u16);
4202        self.as_rec_mut().extend(value.to_ne_bytes());
4203        self
4204    }
4205}
4206impl<Prev: Rec> Drop for PushNapi<Prev> {
4207    fn drop(&mut self) {
4208        if let Some(prev) = &mut self.prev {
4209            if let Some(header_offset) = &self.header_offset {
4210                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4211            }
4212        }
4213    }
4214}
4215pub struct PushXskInfo<Prev: Rec> {
4216    pub(crate) prev: Option<Prev>,
4217    pub(crate) header_offset: Option<usize>,
4218}
4219impl<Prev: Rec> Rec for PushXskInfo<Prev> {
4220    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
4221        self.prev.as_mut().unwrap().as_rec_mut()
4222    }
4223    fn as_rec(&self) -> &Vec<u8> {
4224        self.prev.as_ref().unwrap().as_rec()
4225    }
4226}
4227impl<Prev: Rec> PushXskInfo<Prev> {
4228    pub fn new(prev: Prev) -> Self {
4229        Self {
4230            prev: Some(prev),
4231            header_offset: None,
4232        }
4233    }
4234    pub fn end_nested(mut self) -> Prev {
4235        let mut prev = self.prev.take().unwrap();
4236        if let Some(header_offset) = &self.header_offset {
4237            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4238        }
4239        prev
4240    }
4241}
4242impl<Prev: Rec> Drop for PushXskInfo<Prev> {
4243    fn drop(&mut self) {
4244        if let Some(prev) = &mut self.prev {
4245            if let Some(header_offset) = &self.header_offset {
4246                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4247            }
4248        }
4249    }
4250}
4251pub struct PushQueue<Prev: Rec> {
4252    pub(crate) prev: Option<Prev>,
4253    pub(crate) header_offset: Option<usize>,
4254}
4255impl<Prev: Rec> Rec for PushQueue<Prev> {
4256    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
4257        self.prev.as_mut().unwrap().as_rec_mut()
4258    }
4259    fn as_rec(&self) -> &Vec<u8> {
4260        self.prev.as_ref().unwrap().as_rec()
4261    }
4262}
4263impl<Prev: Rec> PushQueue<Prev> {
4264    pub fn new(prev: Prev) -> Self {
4265        Self {
4266            prev: Some(prev),
4267            header_offset: None,
4268        }
4269    }
4270    pub fn end_nested(mut self) -> Prev {
4271        let mut prev = self.prev.take().unwrap();
4272        if let Some(header_offset) = &self.header_offset {
4273            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4274        }
4275        prev
4276    }
4277    #[doc = "Queue index; most queue types are indexed like a C array, with indexes starting at 0 and ending at queue count \\- 1\\. Queue indexes are scoped to an interface and queue type\\."]
4278    pub fn push_id(mut self, value: u32) -> Self {
4279        push_header(self.as_rec_mut(), 1u16, 4 as u16);
4280        self.as_rec_mut().extend(value.to_ne_bytes());
4281        self
4282    }
4283    #[doc = "ifindex of the netdevice to which the queue belongs\\."]
4284    pub fn push_ifindex(mut self, value: u32) -> Self {
4285        push_header(self.as_rec_mut(), 2u16, 4 as u16);
4286        self.as_rec_mut().extend(value.to_ne_bytes());
4287        self
4288    }
4289    #[doc = "Queue type as rx, tx\\. Each queue type defines a separate ID space\\. XDP TX queues allocated in the kernel are not linked to NAPIs and thus not listed\\. AF\\_XDP queues will have more information set in the xsk attribute\\.\nAssociated type: [`QueueType`] (enum)"]
4290    pub fn push_type(mut self, value: u32) -> Self {
4291        push_header(self.as_rec_mut(), 3u16, 4 as u16);
4292        self.as_rec_mut().extend(value.to_ne_bytes());
4293        self
4294    }
4295    #[doc = "ID of the NAPI instance which services this queue\\."]
4296    pub fn push_napi_id(mut self, value: u32) -> Self {
4297        push_header(self.as_rec_mut(), 4u16, 4 as u16);
4298        self.as_rec_mut().extend(value.to_ne_bytes());
4299        self
4300    }
4301    #[doc = "ID of the dmabuf attached to this queue, if any\\."]
4302    pub fn push_dmabuf(mut self, value: u32) -> Self {
4303        push_header(self.as_rec_mut(), 5u16, 4 as u16);
4304        self.as_rec_mut().extend(value.to_ne_bytes());
4305        self
4306    }
4307    #[doc = "io\\_uring memory provider information\\."]
4308    pub fn nested_io_uring(mut self) -> PushIoUringProviderInfo<Self> {
4309        let header_offset = push_nested_header(self.as_rec_mut(), 6u16);
4310        PushIoUringProviderInfo {
4311            prev: Some(self),
4312            header_offset: Some(header_offset),
4313        }
4314    }
4315    #[doc = "XSK information for this queue, if any\\."]
4316    pub fn nested_xsk(mut self) -> PushXskInfo<Self> {
4317        let header_offset = push_nested_header(self.as_rec_mut(), 7u16);
4318        PushXskInfo {
4319            prev: Some(self),
4320            header_offset: Some(header_offset),
4321        }
4322    }
4323}
4324impl<Prev: Rec> Drop for PushQueue<Prev> {
4325    fn drop(&mut self) {
4326        if let Some(prev) = &mut self.prev {
4327            if let Some(header_offset) = &self.header_offset {
4328                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4329            }
4330        }
4331    }
4332}
4333pub struct PushQstats<Prev: Rec> {
4334    pub(crate) prev: Option<Prev>,
4335    pub(crate) header_offset: Option<usize>,
4336}
4337impl<Prev: Rec> Rec for PushQstats<Prev> {
4338    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
4339        self.prev.as_mut().unwrap().as_rec_mut()
4340    }
4341    fn as_rec(&self) -> &Vec<u8> {
4342        self.prev.as_ref().unwrap().as_rec()
4343    }
4344}
4345impl<Prev: Rec> PushQstats<Prev> {
4346    pub fn new(prev: Prev) -> Self {
4347        Self {
4348            prev: Some(prev),
4349            header_offset: None,
4350        }
4351    }
4352    pub fn end_nested(mut self) -> Prev {
4353        let mut prev = self.prev.take().unwrap();
4354        if let Some(header_offset) = &self.header_offset {
4355            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4356        }
4357        prev
4358    }
4359    #[doc = "ifindex of the netdevice to which stats belong\\."]
4360    pub fn push_ifindex(mut self, value: u32) -> Self {
4361        push_header(self.as_rec_mut(), 1u16, 4 as u16);
4362        self.as_rec_mut().extend(value.to_ne_bytes());
4363        self
4364    }
4365    #[doc = "Queue type as rx, tx, for queue\\-id\\.\nAssociated type: [`QueueType`] (enum)"]
4366    pub fn push_queue_type(mut self, value: u32) -> Self {
4367        push_header(self.as_rec_mut(), 2u16, 4 as u16);
4368        self.as_rec_mut().extend(value.to_ne_bytes());
4369        self
4370    }
4371    #[doc = "Queue ID, if stats are scoped to a single queue instance\\."]
4372    pub fn push_queue_id(mut self, value: u32) -> Self {
4373        push_header(self.as_rec_mut(), 3u16, 4 as u16);
4374        self.as_rec_mut().extend(value.to_ne_bytes());
4375        self
4376    }
4377    #[doc = "What object type should be used to iterate over the stats\\.\n\nAssociated type: [`QstatsScope`] (enum)"]
4378    pub fn push_scope(mut self, value: u32) -> Self {
4379        push_header(self.as_rec_mut(), 4u16, 4 as u16);
4380        self.as_rec_mut().extend(value.to_ne_bytes());
4381        self
4382    }
4383    #[doc = "Number of wire packets successfully received and passed to the stack\\.\nFor drivers supporting XDP, XDP is considered the first layer\nof the stack, so packets consumed by XDP are still counted here\\.\n"]
4384    pub fn push_rx_packets(mut self, value: u32) -> Self {
4385        push_header(self.as_rec_mut(), 8u16, 4 as u16);
4386        self.as_rec_mut().extend(value.to_ne_bytes());
4387        self
4388    }
4389    #[doc = "Successfully received bytes, see \\`rx\\-packets\\`\\."]
4390    pub fn push_rx_bytes(mut self, value: u32) -> Self {
4391        push_header(self.as_rec_mut(), 9u16, 4 as u16);
4392        self.as_rec_mut().extend(value.to_ne_bytes());
4393        self
4394    }
4395    #[doc = "Number of wire packets successfully sent\\. Packet is considered to be\nsuccessfully sent once it is in device memory (usually this means\nthe device has issued a DMA completion for the packet)\\.\n"]
4396    pub fn push_tx_packets(mut self, value: u32) -> Self {
4397        push_header(self.as_rec_mut(), 10u16, 4 as u16);
4398        self.as_rec_mut().extend(value.to_ne_bytes());
4399        self
4400    }
4401    #[doc = "Successfully sent bytes, see \\`tx\\-packets\\`\\."]
4402    pub fn push_tx_bytes(mut self, value: u32) -> Self {
4403        push_header(self.as_rec_mut(), 11u16, 4 as u16);
4404        self.as_rec_mut().extend(value.to_ne_bytes());
4405        self
4406    }
4407    #[doc = "Number of times skb or buffer allocation failed on the Rx datapath\\.\nAllocation failure may, or may not result in a packet drop, depending\non driver implementation and whether system recovers quickly\\.\n"]
4408    pub fn push_rx_alloc_fail(mut self, value: u32) -> Self {
4409        push_header(self.as_rec_mut(), 12u16, 4 as u16);
4410        self.as_rec_mut().extend(value.to_ne_bytes());
4411        self
4412    }
4413    #[doc = "Number of all packets which entered the device, but never left it,\nincluding but not limited to: packets dropped due to lack of buffer\nspace, processing errors, explicit or implicit policies and packet\nfilters\\.\n"]
4414    pub fn push_rx_hw_drops(mut self, value: u32) -> Self {
4415        push_header(self.as_rec_mut(), 13u16, 4 as u16);
4416        self.as_rec_mut().extend(value.to_ne_bytes());
4417        self
4418    }
4419    #[doc = "Number of packets dropped due to transient lack of resources, such as\nbuffer space, host descriptors etc\\.\n"]
4420    pub fn push_rx_hw_drop_overruns(mut self, value: u32) -> Self {
4421        push_header(self.as_rec_mut(), 14u16, 4 as u16);
4422        self.as_rec_mut().extend(value.to_ne_bytes());
4423        self
4424    }
4425    #[doc = "Number of packets that were marked as CHECKSUM\\_COMPLETE\\."]
4426    pub fn push_rx_csum_complete(mut self, value: u32) -> Self {
4427        push_header(self.as_rec_mut(), 15u16, 4 as u16);
4428        self.as_rec_mut().extend(value.to_ne_bytes());
4429        self
4430    }
4431    #[doc = "Number of packets that were marked as CHECKSUM\\_UNNECESSARY\\."]
4432    pub fn push_rx_csum_unnecessary(mut self, value: u32) -> Self {
4433        push_header(self.as_rec_mut(), 16u16, 4 as u16);
4434        self.as_rec_mut().extend(value.to_ne_bytes());
4435        self
4436    }
4437    #[doc = "Number of packets that were not checksummed by device\\."]
4438    pub fn push_rx_csum_none(mut self, value: u32) -> Self {
4439        push_header(self.as_rec_mut(), 17u16, 4 as u16);
4440        self.as_rec_mut().extend(value.to_ne_bytes());
4441        self
4442    }
4443    #[doc = "Number of packets with bad checksum\\. The packets are not discarded,\nbut still delivered to the stack\\.\n"]
4444    pub fn push_rx_csum_bad(mut self, value: u32) -> Self {
4445        push_header(self.as_rec_mut(), 18u16, 4 as u16);
4446        self.as_rec_mut().extend(value.to_ne_bytes());
4447        self
4448    }
4449    #[doc = "Number of packets that were coalesced from smaller packets by the\ndevice\\. Counts only packets coalesced with the HW\\-GRO netdevice\nfeature, LRO\\-coalesced packets are not counted\\.\n"]
4450    pub fn push_rx_hw_gro_packets(mut self, value: u32) -> Self {
4451        push_header(self.as_rec_mut(), 19u16, 4 as u16);
4452        self.as_rec_mut().extend(value.to_ne_bytes());
4453        self
4454    }
4455    #[doc = "See \\`rx\\-hw\\-gro\\-packets\\`\\."]
4456    pub fn push_rx_hw_gro_bytes(mut self, value: u32) -> Self {
4457        push_header(self.as_rec_mut(), 20u16, 4 as u16);
4458        self.as_rec_mut().extend(value.to_ne_bytes());
4459        self
4460    }
4461    #[doc = "Number of packets that were coalesced to bigger packetss with the\nHW\\-GRO netdevice feature\\. LRO\\-coalesced packets are not counted\\.\n"]
4462    pub fn push_rx_hw_gro_wire_packets(mut self, value: u32) -> Self {
4463        push_header(self.as_rec_mut(), 21u16, 4 as u16);
4464        self.as_rec_mut().extend(value.to_ne_bytes());
4465        self
4466    }
4467    #[doc = "See \\`rx\\-hw\\-gro\\-wire\\-packets\\`\\."]
4468    pub fn push_rx_hw_gro_wire_bytes(mut self, value: u32) -> Self {
4469        push_header(self.as_rec_mut(), 22u16, 4 as u16);
4470        self.as_rec_mut().extend(value.to_ne_bytes());
4471        self
4472    }
4473    #[doc = "Number of the packets dropped by the device due to the received\npackets bitrate exceeding the device rate limit\\.\n"]
4474    pub fn push_rx_hw_drop_ratelimits(mut self, value: u32) -> Self {
4475        push_header(self.as_rec_mut(), 23u16, 4 as u16);
4476        self.as_rec_mut().extend(value.to_ne_bytes());
4477        self
4478    }
4479    #[doc = "Number of packets that arrived at the device but never left it,\nencompassing packets dropped for reasons such as processing errors, as\nwell as those affected by explicitly defined policies and packet\nfiltering criteria\\.\n"]
4480    pub fn push_tx_hw_drops(mut self, value: u32) -> Self {
4481        push_header(self.as_rec_mut(), 24u16, 4 as u16);
4482        self.as_rec_mut().extend(value.to_ne_bytes());
4483        self
4484    }
4485    #[doc = "Number of packets dropped because they were invalid or malformed\\."]
4486    pub fn push_tx_hw_drop_errors(mut self, value: u32) -> Self {
4487        push_header(self.as_rec_mut(), 25u16, 4 as u16);
4488        self.as_rec_mut().extend(value.to_ne_bytes());
4489        self
4490    }
4491    #[doc = "Number of packets that did not require the device to calculate the\nchecksum\\.\n"]
4492    pub fn push_tx_csum_none(mut self, value: u32) -> Self {
4493        push_header(self.as_rec_mut(), 26u16, 4 as u16);
4494        self.as_rec_mut().extend(value.to_ne_bytes());
4495        self
4496    }
4497    #[doc = "Number of packets that required the device to calculate the checksum\\.\nThis counter includes the number of GSO wire packets for which device\ncalculated the L4 checksum\\.\n"]
4498    pub fn push_tx_needs_csum(mut self, value: u32) -> Self {
4499        push_header(self.as_rec_mut(), 27u16, 4 as u16);
4500        self.as_rec_mut().extend(value.to_ne_bytes());
4501        self
4502    }
4503    #[doc = "Number of packets that necessitated segmentation into smaller packets\nby the device\\.\n"]
4504    pub fn push_tx_hw_gso_packets(mut self, value: u32) -> Self {
4505        push_header(self.as_rec_mut(), 28u16, 4 as u16);
4506        self.as_rec_mut().extend(value.to_ne_bytes());
4507        self
4508    }
4509    #[doc = "See \\`tx\\-hw\\-gso\\-packets\\`\\."]
4510    pub fn push_tx_hw_gso_bytes(mut self, value: u32) -> Self {
4511        push_header(self.as_rec_mut(), 29u16, 4 as u16);
4512        self.as_rec_mut().extend(value.to_ne_bytes());
4513        self
4514    }
4515    #[doc = "Number of wire\\-sized packets generated by processing\n\\`tx\\-hw\\-gso\\-packets\\`\n"]
4516    pub fn push_tx_hw_gso_wire_packets(mut self, value: u32) -> Self {
4517        push_header(self.as_rec_mut(), 30u16, 4 as u16);
4518        self.as_rec_mut().extend(value.to_ne_bytes());
4519        self
4520    }
4521    #[doc = "See \\`tx\\-hw\\-gso\\-wire\\-packets\\`\\."]
4522    pub fn push_tx_hw_gso_wire_bytes(mut self, value: u32) -> Self {
4523        push_header(self.as_rec_mut(), 31u16, 4 as u16);
4524        self.as_rec_mut().extend(value.to_ne_bytes());
4525        self
4526    }
4527    #[doc = "Number of the packets dropped by the device due to the transmit\npackets bitrate exceeding the device rate limit\\.\n"]
4528    pub fn push_tx_hw_drop_ratelimits(mut self, value: u32) -> Self {
4529        push_header(self.as_rec_mut(), 32u16, 4 as u16);
4530        self.as_rec_mut().extend(value.to_ne_bytes());
4531        self
4532    }
4533    #[doc = "Number of times driver paused accepting new tx packets\nfrom the stack to this queue, because the queue was full\\.\nNote that if BQL is supported and enabled on the device\nthe networking stack will avoid queuing a lot of data at once\\.\n"]
4534    pub fn push_tx_stop(mut self, value: u32) -> Self {
4535        push_header(self.as_rec_mut(), 33u16, 4 as u16);
4536        self.as_rec_mut().extend(value.to_ne_bytes());
4537        self
4538    }
4539    #[doc = "Number of times driver re\\-started accepting send\nrequests to this queue from the stack\\.\n"]
4540    pub fn push_tx_wake(mut self, value: u32) -> Self {
4541        push_header(self.as_rec_mut(), 34u16, 4 as u16);
4542        self.as_rec_mut().extend(value.to_ne_bytes());
4543        self
4544    }
4545}
4546impl<Prev: Rec> Drop for PushQstats<Prev> {
4547    fn drop(&mut self) {
4548        if let Some(prev) = &mut self.prev {
4549            if let Some(header_offset) = &self.header_offset {
4550                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4551            }
4552        }
4553    }
4554}
4555pub struct PushQueueId<Prev: Rec> {
4556    pub(crate) prev: Option<Prev>,
4557    pub(crate) header_offset: Option<usize>,
4558}
4559impl<Prev: Rec> Rec for PushQueueId<Prev> {
4560    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
4561        self.prev.as_mut().unwrap().as_rec_mut()
4562    }
4563    fn as_rec(&self) -> &Vec<u8> {
4564        self.prev.as_ref().unwrap().as_rec()
4565    }
4566}
4567impl<Prev: Rec> PushQueueId<Prev> {
4568    pub fn new(prev: Prev) -> Self {
4569        Self {
4570            prev: Some(prev),
4571            header_offset: None,
4572        }
4573    }
4574    pub fn end_nested(mut self) -> Prev {
4575        let mut prev = self.prev.take().unwrap();
4576        if let Some(header_offset) = &self.header_offset {
4577            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4578        }
4579        prev
4580    }
4581    #[doc = "Queue index; most queue types are indexed like a C array, with indexes starting at 0 and ending at queue count \\- 1\\. Queue indexes are scoped to an interface and queue type\\."]
4582    pub fn push_id(mut self, value: u32) -> Self {
4583        push_header(self.as_rec_mut(), 1u16, 4 as u16);
4584        self.as_rec_mut().extend(value.to_ne_bytes());
4585        self
4586    }
4587    #[doc = "Queue type as rx, tx\\. Each queue type defines a separate ID space\\. XDP TX queues allocated in the kernel are not linked to NAPIs and thus not listed\\. AF\\_XDP queues will have more information set in the xsk attribute\\.\nAssociated type: [`QueueType`] (enum)"]
4588    pub fn push_type(mut self, value: u32) -> Self {
4589        push_header(self.as_rec_mut(), 3u16, 4 as u16);
4590        self.as_rec_mut().extend(value.to_ne_bytes());
4591        self
4592    }
4593}
4594impl<Prev: Rec> Drop for PushQueueId<Prev> {
4595    fn drop(&mut self) {
4596        if let Some(prev) = &mut self.prev {
4597            if let Some(header_offset) = &self.header_offset {
4598                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4599            }
4600        }
4601    }
4602}
4603pub struct PushDmabuf<Prev: Rec> {
4604    pub(crate) prev: Option<Prev>,
4605    pub(crate) header_offset: Option<usize>,
4606}
4607impl<Prev: Rec> Rec for PushDmabuf<Prev> {
4608    fn as_rec_mut(&mut self) -> &mut Vec<u8> {
4609        self.prev.as_mut().unwrap().as_rec_mut()
4610    }
4611    fn as_rec(&self) -> &Vec<u8> {
4612        self.prev.as_ref().unwrap().as_rec()
4613    }
4614}
4615impl<Prev: Rec> PushDmabuf<Prev> {
4616    pub fn new(prev: Prev) -> Self {
4617        Self {
4618            prev: Some(prev),
4619            header_offset: None,
4620        }
4621    }
4622    pub fn end_nested(mut self) -> Prev {
4623        let mut prev = self.prev.take().unwrap();
4624        if let Some(header_offset) = &self.header_offset {
4625            finalize_nested_header(prev.as_rec_mut(), *header_offset);
4626        }
4627        prev
4628    }
4629    #[doc = "netdev ifindex to bind the dmabuf to\\."]
4630    pub fn push_ifindex(mut self, value: u32) -> Self {
4631        push_header(self.as_rec_mut(), 1u16, 4 as u16);
4632        self.as_rec_mut().extend(value.to_ne_bytes());
4633        self
4634    }
4635    #[doc = "receive queues to bind the dmabuf to\\.\nAttribute may repeat multiple times (treat it as array)"]
4636    pub fn nested_queues(mut self) -> PushQueueId<Self> {
4637        let header_offset = push_nested_header(self.as_rec_mut(), 2u16);
4638        PushQueueId {
4639            prev: Some(self),
4640            header_offset: Some(header_offset),
4641        }
4642    }
4643    #[doc = "dmabuf file descriptor to bind\\."]
4644    pub fn push_fd(mut self, value: u32) -> Self {
4645        push_header(self.as_rec_mut(), 3u16, 4 as u16);
4646        self.as_rec_mut().extend(value.to_ne_bytes());
4647        self
4648    }
4649    #[doc = "id of the dmabuf binding"]
4650    pub fn push_id(mut self, value: u32) -> Self {
4651        push_header(self.as_rec_mut(), 4u16, 4 as u16);
4652        self.as_rec_mut().extend(value.to_ne_bytes());
4653        self
4654    }
4655}
4656impl<Prev: Rec> Drop for PushDmabuf<Prev> {
4657    fn drop(&mut self) {
4658        if let Some(prev) = &mut self.prev {
4659            if let Some(header_offset) = &self.header_offset {
4660                finalize_nested_header(prev.as_rec_mut(), *header_offset);
4661            }
4662        }
4663    }
4664}
4665#[doc = "Notify attributes:\n- [`.get_ifindex()`](IterableDev::get_ifindex)\n- [`.get_xdp_features()`](IterableDev::get_xdp_features)\n- [`.get_xdp_zc_max_segs()`](IterableDev::get_xdp_zc_max_segs)\n- [`.get_xdp_rx_metadata_features()`](IterableDev::get_xdp_rx_metadata_features)\n- [`.get_xsk_features()`](IterableDev::get_xsk_features)\n"]
4666#[derive(Debug)]
4667pub struct OpDevAddNotif;
4668impl OpDevAddNotif {
4669    pub const CMD: u8 = 2u8;
4670    pub fn decode_notif<'a>(buf: &'a [u8]) -> IterableDev<'a> {
4671        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4672        IterableDev::with_loc(attrs, buf.as_ptr() as usize)
4673    }
4674}
4675#[doc = "Notify attributes:\n- [`.get_ifindex()`](IterableDev::get_ifindex)\n- [`.get_xdp_features()`](IterableDev::get_xdp_features)\n- [`.get_xdp_zc_max_segs()`](IterableDev::get_xdp_zc_max_segs)\n- [`.get_xdp_rx_metadata_features()`](IterableDev::get_xdp_rx_metadata_features)\n- [`.get_xsk_features()`](IterableDev::get_xsk_features)\n"]
4676#[derive(Debug)]
4677pub struct OpDevDelNotif;
4678impl OpDevDelNotif {
4679    pub const CMD: u8 = 3u8;
4680    pub fn decode_notif<'a>(buf: &'a [u8]) -> IterableDev<'a> {
4681        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4682        IterableDev::with_loc(attrs, buf.as_ptr() as usize)
4683    }
4684}
4685#[doc = "Notify attributes:\n- [`.get_ifindex()`](IterableDev::get_ifindex)\n- [`.get_xdp_features()`](IterableDev::get_xdp_features)\n- [`.get_xdp_zc_max_segs()`](IterableDev::get_xdp_zc_max_segs)\n- [`.get_xdp_rx_metadata_features()`](IterableDev::get_xdp_rx_metadata_features)\n- [`.get_xsk_features()`](IterableDev::get_xsk_features)\n"]
4686#[derive(Debug)]
4687pub struct OpDevChangeNotif;
4688impl OpDevChangeNotif {
4689    pub const CMD: u8 = 4u8;
4690    pub fn decode_notif<'a>(buf: &'a [u8]) -> IterableDev<'a> {
4691        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4692        IterableDev::with_loc(attrs, buf.as_ptr() as usize)
4693    }
4694}
4695#[doc = "Notify attributes:\n- [`.get_id()`](IterablePagePool::get_id)\n- [`.get_ifindex()`](IterablePagePool::get_ifindex)\n- [`.get_napi_id()`](IterablePagePool::get_napi_id)\n- [`.get_inflight()`](IterablePagePool::get_inflight)\n- [`.get_inflight_mem()`](IterablePagePool::get_inflight_mem)\n- [`.get_detach_time()`](IterablePagePool::get_detach_time)\n- [`.get_dmabuf()`](IterablePagePool::get_dmabuf)\n- [`.get_io_uring()`](IterablePagePool::get_io_uring)\n"]
4696#[derive(Debug)]
4697pub struct OpPagePoolAddNotif;
4698impl OpPagePoolAddNotif {
4699    pub const CMD: u8 = 6u8;
4700    pub fn decode_notif<'a>(buf: &'a [u8]) -> IterablePagePool<'a> {
4701        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4702        IterablePagePool::with_loc(attrs, buf.as_ptr() as usize)
4703    }
4704}
4705#[doc = "Notify attributes:\n- [`.get_id()`](IterablePagePool::get_id)\n- [`.get_ifindex()`](IterablePagePool::get_ifindex)\n- [`.get_napi_id()`](IterablePagePool::get_napi_id)\n- [`.get_inflight()`](IterablePagePool::get_inflight)\n- [`.get_inflight_mem()`](IterablePagePool::get_inflight_mem)\n- [`.get_detach_time()`](IterablePagePool::get_detach_time)\n- [`.get_dmabuf()`](IterablePagePool::get_dmabuf)\n- [`.get_io_uring()`](IterablePagePool::get_io_uring)\n"]
4706#[derive(Debug)]
4707pub struct OpPagePoolDelNotif;
4708impl OpPagePoolDelNotif {
4709    pub const CMD: u8 = 7u8;
4710    pub fn decode_notif<'a>(buf: &'a [u8]) -> IterablePagePool<'a> {
4711        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4712        IterablePagePool::with_loc(attrs, buf.as_ptr() as usize)
4713    }
4714}
4715#[doc = "Notify attributes:\n- [`.get_id()`](IterablePagePool::get_id)\n- [`.get_ifindex()`](IterablePagePool::get_ifindex)\n- [`.get_napi_id()`](IterablePagePool::get_napi_id)\n- [`.get_inflight()`](IterablePagePool::get_inflight)\n- [`.get_inflight_mem()`](IterablePagePool::get_inflight_mem)\n- [`.get_detach_time()`](IterablePagePool::get_detach_time)\n- [`.get_dmabuf()`](IterablePagePool::get_dmabuf)\n- [`.get_io_uring()`](IterablePagePool::get_io_uring)\n"]
4716#[derive(Debug)]
4717pub struct OpPagePoolChangeNotif;
4718impl OpPagePoolChangeNotif {
4719    pub const CMD: u8 = 8u8;
4720    pub fn decode_notif<'a>(buf: &'a [u8]) -> IterablePagePool<'a> {
4721        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4722        IterablePagePool::with_loc(attrs, buf.as_ptr() as usize)
4723    }
4724}
4725pub struct NotifGroup;
4726impl NotifGroup {
4727    #[doc = "Notifications:\n- [`OpDevAddNotif`]\n- [`OpDevDelNotif`]\n- [`OpDevChangeNotif`]\n"]
4728    pub const MGMT: &str = "mgmt";
4729    #[doc = "Notifications:\n- [`OpDevAddNotif`]\n- [`OpDevDelNotif`]\n- [`OpDevChangeNotif`]\n"]
4730    pub const MGMT_CSTR: &CStr = c"mgmt";
4731    #[doc = "Notifications:\n- [`OpPagePoolAddNotif`]\n- [`OpPagePoolDelNotif`]\n- [`OpPagePoolChangeNotif`]\n"]
4732    pub const PAGE_POOL: &str = "page-pool";
4733    #[doc = "Notifications:\n- [`OpPagePoolAddNotif`]\n- [`OpPagePoolDelNotif`]\n- [`OpPagePoolChangeNotif`]\n"]
4734    pub const PAGE_POOL_CSTR: &CStr = c"page-pool";
4735}
4736#[doc = "Get / dump information about a netdev\\.\n\nReply attributes:\n- [.get_ifindex()](IterableDev::get_ifindex)\n- [.get_xdp_features()](IterableDev::get_xdp_features)\n- [.get_xdp_zc_max_segs()](IterableDev::get_xdp_zc_max_segs)\n- [.get_xdp_rx_metadata_features()](IterableDev::get_xdp_rx_metadata_features)\n- [.get_xsk_features()](IterableDev::get_xsk_features)\n"]
4737#[derive(Debug)]
4738pub struct OpDevGetDump<'r> {
4739    request: Request<'r>,
4740}
4741impl<'r> OpDevGetDump<'r> {
4742    pub fn new(mut request: Request<'r>) -> Self {
4743        Self::write_header(request.buf_mut());
4744        Self {
4745            request: request.set_dump(),
4746        }
4747    }
4748    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushDev<&'buf mut Vec<u8>> {
4749        Self::write_header(buf);
4750        PushDev::new(buf)
4751    }
4752    pub fn encode(&mut self) -> PushDev<&mut Vec<u8>> {
4753        PushDev::new(self.request.buf_mut())
4754    }
4755    pub fn into_encoder(self) -> PushDev<RequestBuf<'r>> {
4756        PushDev::new(self.request.buf)
4757    }
4758    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableDev<'a> {
4759        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4760        IterableDev::with_loc(attrs, buf.as_ptr() as usize)
4761    }
4762    fn write_header<Prev: Rec>(prev: &mut Prev) {
4763        let mut header = BuiltinNfgenmsg::new();
4764        header.cmd = 1u8;
4765        header.version = 1u8;
4766        prev.as_rec_mut().extend(header.as_slice());
4767    }
4768}
4769impl NetlinkRequest for OpDevGetDump<'_> {
4770    fn protocol(&self) -> Protocol {
4771        Protocol::Generic("netdev".as_bytes())
4772    }
4773    fn flags(&self) -> u16 {
4774        self.request.flags
4775    }
4776    fn payload(&self) -> &[u8] {
4777        self.request.buf()
4778    }
4779    type ReplyType<'buf> = IterableDev<'buf>;
4780    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
4781        Self::decode_request(buf)
4782    }
4783    fn lookup(
4784        buf: &[u8],
4785        offset: usize,
4786        missing_type: Option<u16>,
4787    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
4788        Self::decode_request(buf).lookup_attr(offset, missing_type)
4789    }
4790}
4791#[doc = "Get / dump information about a netdev\\.\nRequest attributes:\n- [.push_ifindex()](PushDev::push_ifindex)\n\nReply attributes:\n- [.get_ifindex()](IterableDev::get_ifindex)\n- [.get_xdp_features()](IterableDev::get_xdp_features)\n- [.get_xdp_zc_max_segs()](IterableDev::get_xdp_zc_max_segs)\n- [.get_xdp_rx_metadata_features()](IterableDev::get_xdp_rx_metadata_features)\n- [.get_xsk_features()](IterableDev::get_xsk_features)\n"]
4792#[derive(Debug)]
4793pub struct OpDevGetDo<'r> {
4794    request: Request<'r>,
4795}
4796impl<'r> OpDevGetDo<'r> {
4797    pub fn new(mut request: Request<'r>) -> Self {
4798        Self::write_header(request.buf_mut());
4799        Self { request: request }
4800    }
4801    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushDev<&'buf mut Vec<u8>> {
4802        Self::write_header(buf);
4803        PushDev::new(buf)
4804    }
4805    pub fn encode(&mut self) -> PushDev<&mut Vec<u8>> {
4806        PushDev::new(self.request.buf_mut())
4807    }
4808    pub fn into_encoder(self) -> PushDev<RequestBuf<'r>> {
4809        PushDev::new(self.request.buf)
4810    }
4811    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableDev<'a> {
4812        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4813        IterableDev::with_loc(attrs, buf.as_ptr() as usize)
4814    }
4815    fn write_header<Prev: Rec>(prev: &mut Prev) {
4816        let mut header = BuiltinNfgenmsg::new();
4817        header.cmd = 1u8;
4818        header.version = 1u8;
4819        prev.as_rec_mut().extend(header.as_slice());
4820    }
4821}
4822impl NetlinkRequest for OpDevGetDo<'_> {
4823    fn protocol(&self) -> Protocol {
4824        Protocol::Generic("netdev".as_bytes())
4825    }
4826    fn flags(&self) -> u16 {
4827        self.request.flags
4828    }
4829    fn payload(&self) -> &[u8] {
4830        self.request.buf()
4831    }
4832    type ReplyType<'buf> = IterableDev<'buf>;
4833    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
4834        Self::decode_request(buf)
4835    }
4836    fn lookup(
4837        buf: &[u8],
4838        offset: usize,
4839        missing_type: Option<u16>,
4840    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
4841        Self::decode_request(buf).lookup_attr(offset, missing_type)
4842    }
4843}
4844#[doc = "Get / dump information about Page Pools\\.\nOnly Page Pools associated by the driver with a net\\_device\ncan be listed\\. ifindex will not be reported if the net\\_device\nno longer exists\\.\n\n\nReply attributes:\n- [.get_id()](IterablePagePool::get_id)\n- [.get_ifindex()](IterablePagePool::get_ifindex)\n- [.get_napi_id()](IterablePagePool::get_napi_id)\n- [.get_inflight()](IterablePagePool::get_inflight)\n- [.get_inflight_mem()](IterablePagePool::get_inflight_mem)\n- [.get_detach_time()](IterablePagePool::get_detach_time)\n- [.get_dmabuf()](IterablePagePool::get_dmabuf)\n- [.get_io_uring()](IterablePagePool::get_io_uring)\n"]
4845#[derive(Debug)]
4846pub struct OpPagePoolGetDump<'r> {
4847    request: Request<'r>,
4848}
4849impl<'r> OpPagePoolGetDump<'r> {
4850    pub fn new(mut request: Request<'r>) -> Self {
4851        Self::write_header(request.buf_mut());
4852        Self {
4853            request: request.set_dump(),
4854        }
4855    }
4856    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushPagePool<&'buf mut Vec<u8>> {
4857        Self::write_header(buf);
4858        PushPagePool::new(buf)
4859    }
4860    pub fn encode(&mut self) -> PushPagePool<&mut Vec<u8>> {
4861        PushPagePool::new(self.request.buf_mut())
4862    }
4863    pub fn into_encoder(self) -> PushPagePool<RequestBuf<'r>> {
4864        PushPagePool::new(self.request.buf)
4865    }
4866    pub fn decode_request<'a>(buf: &'a [u8]) -> IterablePagePool<'a> {
4867        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4868        IterablePagePool::with_loc(attrs, buf.as_ptr() as usize)
4869    }
4870    fn write_header<Prev: Rec>(prev: &mut Prev) {
4871        let mut header = BuiltinNfgenmsg::new();
4872        header.cmd = 5u8;
4873        header.version = 1u8;
4874        prev.as_rec_mut().extend(header.as_slice());
4875    }
4876}
4877impl NetlinkRequest for OpPagePoolGetDump<'_> {
4878    fn protocol(&self) -> Protocol {
4879        Protocol::Generic("netdev".as_bytes())
4880    }
4881    fn flags(&self) -> u16 {
4882        self.request.flags
4883    }
4884    fn payload(&self) -> &[u8] {
4885        self.request.buf()
4886    }
4887    type ReplyType<'buf> = IterablePagePool<'buf>;
4888    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
4889        Self::decode_request(buf)
4890    }
4891    fn lookup(
4892        buf: &[u8],
4893        offset: usize,
4894        missing_type: Option<u16>,
4895    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
4896        Self::decode_request(buf).lookup_attr(offset, missing_type)
4897    }
4898}
4899#[doc = "Get / dump information about Page Pools\\.\nOnly Page Pools associated by the driver with a net\\_device\ncan be listed\\. ifindex will not be reported if the net\\_device\nno longer exists\\.\n\nRequest attributes:\n- [.push_id()](PushPagePool::push_id)\n\nReply attributes:\n- [.get_id()](IterablePagePool::get_id)\n- [.get_ifindex()](IterablePagePool::get_ifindex)\n- [.get_napi_id()](IterablePagePool::get_napi_id)\n- [.get_inflight()](IterablePagePool::get_inflight)\n- [.get_inflight_mem()](IterablePagePool::get_inflight_mem)\n- [.get_detach_time()](IterablePagePool::get_detach_time)\n- [.get_dmabuf()](IterablePagePool::get_dmabuf)\n- [.get_io_uring()](IterablePagePool::get_io_uring)\n"]
4900#[derive(Debug)]
4901pub struct OpPagePoolGetDo<'r> {
4902    request: Request<'r>,
4903}
4904impl<'r> OpPagePoolGetDo<'r> {
4905    pub fn new(mut request: Request<'r>) -> Self {
4906        Self::write_header(request.buf_mut());
4907        Self { request: request }
4908    }
4909    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushPagePool<&'buf mut Vec<u8>> {
4910        Self::write_header(buf);
4911        PushPagePool::new(buf)
4912    }
4913    pub fn encode(&mut self) -> PushPagePool<&mut Vec<u8>> {
4914        PushPagePool::new(self.request.buf_mut())
4915    }
4916    pub fn into_encoder(self) -> PushPagePool<RequestBuf<'r>> {
4917        PushPagePool::new(self.request.buf)
4918    }
4919    pub fn decode_request<'a>(buf: &'a [u8]) -> IterablePagePool<'a> {
4920        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4921        IterablePagePool::with_loc(attrs, buf.as_ptr() as usize)
4922    }
4923    fn write_header<Prev: Rec>(prev: &mut Prev) {
4924        let mut header = BuiltinNfgenmsg::new();
4925        header.cmd = 5u8;
4926        header.version = 1u8;
4927        prev.as_rec_mut().extend(header.as_slice());
4928    }
4929}
4930impl NetlinkRequest for OpPagePoolGetDo<'_> {
4931    fn protocol(&self) -> Protocol {
4932        Protocol::Generic("netdev".as_bytes())
4933    }
4934    fn flags(&self) -> u16 {
4935        self.request.flags
4936    }
4937    fn payload(&self) -> &[u8] {
4938        self.request.buf()
4939    }
4940    type ReplyType<'buf> = IterablePagePool<'buf>;
4941    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
4942        Self::decode_request(buf)
4943    }
4944    fn lookup(
4945        buf: &[u8],
4946        offset: usize,
4947        missing_type: Option<u16>,
4948    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
4949        Self::decode_request(buf).lookup_attr(offset, missing_type)
4950    }
4951}
4952#[doc = "Get page pool statistics\\.\n\nReply attributes:\n- [.get_info()](IterablePagePoolStats::get_info)\n- [.get_alloc_fast()](IterablePagePoolStats::get_alloc_fast)\n- [.get_alloc_slow()](IterablePagePoolStats::get_alloc_slow)\n- [.get_alloc_slow_high_order()](IterablePagePoolStats::get_alloc_slow_high_order)\n- [.get_alloc_empty()](IterablePagePoolStats::get_alloc_empty)\n- [.get_alloc_refill()](IterablePagePoolStats::get_alloc_refill)\n- [.get_alloc_waive()](IterablePagePoolStats::get_alloc_waive)\n- [.get_recycle_cached()](IterablePagePoolStats::get_recycle_cached)\n- [.get_recycle_cache_full()](IterablePagePoolStats::get_recycle_cache_full)\n- [.get_recycle_ring()](IterablePagePoolStats::get_recycle_ring)\n- [.get_recycle_ring_full()](IterablePagePoolStats::get_recycle_ring_full)\n- [.get_recycle_released_refcnt()](IterablePagePoolStats::get_recycle_released_refcnt)\n"]
4953#[derive(Debug)]
4954pub struct OpPagePoolStatsGetDump<'r> {
4955    request: Request<'r>,
4956}
4957impl<'r> OpPagePoolStatsGetDump<'r> {
4958    pub fn new(mut request: Request<'r>) -> Self {
4959        Self::write_header(request.buf_mut());
4960        Self {
4961            request: request.set_dump(),
4962        }
4963    }
4964    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushPagePoolStats<&'buf mut Vec<u8>> {
4965        Self::write_header(buf);
4966        PushPagePoolStats::new(buf)
4967    }
4968    pub fn encode(&mut self) -> PushPagePoolStats<&mut Vec<u8>> {
4969        PushPagePoolStats::new(self.request.buf_mut())
4970    }
4971    pub fn into_encoder(self) -> PushPagePoolStats<RequestBuf<'r>> {
4972        PushPagePoolStats::new(self.request.buf)
4973    }
4974    pub fn decode_request<'a>(buf: &'a [u8]) -> IterablePagePoolStats<'a> {
4975        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
4976        IterablePagePoolStats::with_loc(attrs, buf.as_ptr() as usize)
4977    }
4978    fn write_header<Prev: Rec>(prev: &mut Prev) {
4979        let mut header = BuiltinNfgenmsg::new();
4980        header.cmd = 9u8;
4981        header.version = 1u8;
4982        prev.as_rec_mut().extend(header.as_slice());
4983    }
4984}
4985impl NetlinkRequest for OpPagePoolStatsGetDump<'_> {
4986    fn protocol(&self) -> Protocol {
4987        Protocol::Generic("netdev".as_bytes())
4988    }
4989    fn flags(&self) -> u16 {
4990        self.request.flags
4991    }
4992    fn payload(&self) -> &[u8] {
4993        self.request.buf()
4994    }
4995    type ReplyType<'buf> = IterablePagePoolStats<'buf>;
4996    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
4997        Self::decode_request(buf)
4998    }
4999    fn lookup(
5000        buf: &[u8],
5001        offset: usize,
5002        missing_type: Option<u16>,
5003    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5004        Self::decode_request(buf).lookup_attr(offset, missing_type)
5005    }
5006}
5007#[doc = "Get page pool statistics\\.\nRequest attributes:\n- [.nested_info()](PushPagePoolStats::nested_info)\n\nReply attributes:\n- [.get_info()](IterablePagePoolStats::get_info)\n- [.get_alloc_fast()](IterablePagePoolStats::get_alloc_fast)\n- [.get_alloc_slow()](IterablePagePoolStats::get_alloc_slow)\n- [.get_alloc_slow_high_order()](IterablePagePoolStats::get_alloc_slow_high_order)\n- [.get_alloc_empty()](IterablePagePoolStats::get_alloc_empty)\n- [.get_alloc_refill()](IterablePagePoolStats::get_alloc_refill)\n- [.get_alloc_waive()](IterablePagePoolStats::get_alloc_waive)\n- [.get_recycle_cached()](IterablePagePoolStats::get_recycle_cached)\n- [.get_recycle_cache_full()](IterablePagePoolStats::get_recycle_cache_full)\n- [.get_recycle_ring()](IterablePagePoolStats::get_recycle_ring)\n- [.get_recycle_ring_full()](IterablePagePoolStats::get_recycle_ring_full)\n- [.get_recycle_released_refcnt()](IterablePagePoolStats::get_recycle_released_refcnt)\n"]
5008#[derive(Debug)]
5009pub struct OpPagePoolStatsGetDo<'r> {
5010    request: Request<'r>,
5011}
5012impl<'r> OpPagePoolStatsGetDo<'r> {
5013    pub fn new(mut request: Request<'r>) -> Self {
5014        Self::write_header(request.buf_mut());
5015        Self { request: request }
5016    }
5017    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushPagePoolStats<&'buf mut Vec<u8>> {
5018        Self::write_header(buf);
5019        PushPagePoolStats::new(buf)
5020    }
5021    pub fn encode(&mut self) -> PushPagePoolStats<&mut Vec<u8>> {
5022        PushPagePoolStats::new(self.request.buf_mut())
5023    }
5024    pub fn into_encoder(self) -> PushPagePoolStats<RequestBuf<'r>> {
5025        PushPagePoolStats::new(self.request.buf)
5026    }
5027    pub fn decode_request<'a>(buf: &'a [u8]) -> IterablePagePoolStats<'a> {
5028        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5029        IterablePagePoolStats::with_loc(attrs, buf.as_ptr() as usize)
5030    }
5031    fn write_header<Prev: Rec>(prev: &mut Prev) {
5032        let mut header = BuiltinNfgenmsg::new();
5033        header.cmd = 9u8;
5034        header.version = 1u8;
5035        prev.as_rec_mut().extend(header.as_slice());
5036    }
5037}
5038impl NetlinkRequest for OpPagePoolStatsGetDo<'_> {
5039    fn protocol(&self) -> Protocol {
5040        Protocol::Generic("netdev".as_bytes())
5041    }
5042    fn flags(&self) -> u16 {
5043        self.request.flags
5044    }
5045    fn payload(&self) -> &[u8] {
5046        self.request.buf()
5047    }
5048    type ReplyType<'buf> = IterablePagePoolStats<'buf>;
5049    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5050        Self::decode_request(buf)
5051    }
5052    fn lookup(
5053        buf: &[u8],
5054        offset: usize,
5055        missing_type: Option<u16>,
5056    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5057        Self::decode_request(buf).lookup_attr(offset, missing_type)
5058    }
5059}
5060#[doc = "Get queue information from the kernel\\. Only configured queues will be reported (as opposed to all available hardware queues)\\.\nRequest attributes:\n- [.push_ifindex()](PushQueue::push_ifindex)\n\nReply attributes:\n- [.get_id()](IterableQueue::get_id)\n- [.get_ifindex()](IterableQueue::get_ifindex)\n- [.get_type()](IterableQueue::get_type)\n- [.get_napi_id()](IterableQueue::get_napi_id)\n- [.get_dmabuf()](IterableQueue::get_dmabuf)\n- [.get_io_uring()](IterableQueue::get_io_uring)\n- [.get_xsk()](IterableQueue::get_xsk)\n"]
5061#[derive(Debug)]
5062pub struct OpQueueGetDump<'r> {
5063    request: Request<'r>,
5064}
5065impl<'r> OpQueueGetDump<'r> {
5066    pub fn new(mut request: Request<'r>) -> Self {
5067        Self::write_header(request.buf_mut());
5068        Self {
5069            request: request.set_dump(),
5070        }
5071    }
5072    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushQueue<&'buf mut Vec<u8>> {
5073        Self::write_header(buf);
5074        PushQueue::new(buf)
5075    }
5076    pub fn encode(&mut self) -> PushQueue<&mut Vec<u8>> {
5077        PushQueue::new(self.request.buf_mut())
5078    }
5079    pub fn into_encoder(self) -> PushQueue<RequestBuf<'r>> {
5080        PushQueue::new(self.request.buf)
5081    }
5082    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableQueue<'a> {
5083        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5084        IterableQueue::with_loc(attrs, buf.as_ptr() as usize)
5085    }
5086    fn write_header<Prev: Rec>(prev: &mut Prev) {
5087        let mut header = BuiltinNfgenmsg::new();
5088        header.cmd = 10u8;
5089        header.version = 1u8;
5090        prev.as_rec_mut().extend(header.as_slice());
5091    }
5092}
5093impl NetlinkRequest for OpQueueGetDump<'_> {
5094    fn protocol(&self) -> Protocol {
5095        Protocol::Generic("netdev".as_bytes())
5096    }
5097    fn flags(&self) -> u16 {
5098        self.request.flags
5099    }
5100    fn payload(&self) -> &[u8] {
5101        self.request.buf()
5102    }
5103    type ReplyType<'buf> = IterableQueue<'buf>;
5104    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5105        Self::decode_request(buf)
5106    }
5107    fn lookup(
5108        buf: &[u8],
5109        offset: usize,
5110        missing_type: Option<u16>,
5111    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5112        Self::decode_request(buf).lookup_attr(offset, missing_type)
5113    }
5114}
5115#[doc = "Get queue information from the kernel\\. Only configured queues will be reported (as opposed to all available hardware queues)\\.\nRequest attributes:\n- [.push_id()](PushQueue::push_id)\n- [.push_ifindex()](PushQueue::push_ifindex)\n- [.push_type()](PushQueue::push_type)\n\nReply attributes:\n- [.get_id()](IterableQueue::get_id)\n- [.get_ifindex()](IterableQueue::get_ifindex)\n- [.get_type()](IterableQueue::get_type)\n- [.get_napi_id()](IterableQueue::get_napi_id)\n- [.get_dmabuf()](IterableQueue::get_dmabuf)\n- [.get_io_uring()](IterableQueue::get_io_uring)\n- [.get_xsk()](IterableQueue::get_xsk)\n"]
5116#[derive(Debug)]
5117pub struct OpQueueGetDo<'r> {
5118    request: Request<'r>,
5119}
5120impl<'r> OpQueueGetDo<'r> {
5121    pub fn new(mut request: Request<'r>) -> Self {
5122        Self::write_header(request.buf_mut());
5123        Self { request: request }
5124    }
5125    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushQueue<&'buf mut Vec<u8>> {
5126        Self::write_header(buf);
5127        PushQueue::new(buf)
5128    }
5129    pub fn encode(&mut self) -> PushQueue<&mut Vec<u8>> {
5130        PushQueue::new(self.request.buf_mut())
5131    }
5132    pub fn into_encoder(self) -> PushQueue<RequestBuf<'r>> {
5133        PushQueue::new(self.request.buf)
5134    }
5135    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableQueue<'a> {
5136        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5137        IterableQueue::with_loc(attrs, buf.as_ptr() as usize)
5138    }
5139    fn write_header<Prev: Rec>(prev: &mut Prev) {
5140        let mut header = BuiltinNfgenmsg::new();
5141        header.cmd = 10u8;
5142        header.version = 1u8;
5143        prev.as_rec_mut().extend(header.as_slice());
5144    }
5145}
5146impl NetlinkRequest for OpQueueGetDo<'_> {
5147    fn protocol(&self) -> Protocol {
5148        Protocol::Generic("netdev".as_bytes())
5149    }
5150    fn flags(&self) -> u16 {
5151        self.request.flags
5152    }
5153    fn payload(&self) -> &[u8] {
5154        self.request.buf()
5155    }
5156    type ReplyType<'buf> = IterableQueue<'buf>;
5157    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5158        Self::decode_request(buf)
5159    }
5160    fn lookup(
5161        buf: &[u8],
5162        offset: usize,
5163        missing_type: Option<u16>,
5164    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5165        Self::decode_request(buf).lookup_attr(offset, missing_type)
5166    }
5167}
5168#[doc = "Get information about NAPI instances configured on the system\\.\nRequest attributes:\n- [.push_ifindex()](PushNapi::push_ifindex)\n\nReply attributes:\n- [.get_ifindex()](IterableNapi::get_ifindex)\n- [.get_id()](IterableNapi::get_id)\n- [.get_irq()](IterableNapi::get_irq)\n- [.get_pid()](IterableNapi::get_pid)\n- [.get_defer_hard_irqs()](IterableNapi::get_defer_hard_irqs)\n- [.get_gro_flush_timeout()](IterableNapi::get_gro_flush_timeout)\n- [.get_irq_suspend_timeout()](IterableNapi::get_irq_suspend_timeout)\n- [.get_threaded()](IterableNapi::get_threaded)\n"]
5169#[derive(Debug)]
5170pub struct OpNapiGetDump<'r> {
5171    request: Request<'r>,
5172}
5173impl<'r> OpNapiGetDump<'r> {
5174    pub fn new(mut request: Request<'r>) -> Self {
5175        Self::write_header(request.buf_mut());
5176        Self {
5177            request: request.set_dump(),
5178        }
5179    }
5180    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushNapi<&'buf mut Vec<u8>> {
5181        Self::write_header(buf);
5182        PushNapi::new(buf)
5183    }
5184    pub fn encode(&mut self) -> PushNapi<&mut Vec<u8>> {
5185        PushNapi::new(self.request.buf_mut())
5186    }
5187    pub fn into_encoder(self) -> PushNapi<RequestBuf<'r>> {
5188        PushNapi::new(self.request.buf)
5189    }
5190    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableNapi<'a> {
5191        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5192        IterableNapi::with_loc(attrs, buf.as_ptr() as usize)
5193    }
5194    fn write_header<Prev: Rec>(prev: &mut Prev) {
5195        let mut header = BuiltinNfgenmsg::new();
5196        header.cmd = 11u8;
5197        header.version = 1u8;
5198        prev.as_rec_mut().extend(header.as_slice());
5199    }
5200}
5201impl NetlinkRequest for OpNapiGetDump<'_> {
5202    fn protocol(&self) -> Protocol {
5203        Protocol::Generic("netdev".as_bytes())
5204    }
5205    fn flags(&self) -> u16 {
5206        self.request.flags
5207    }
5208    fn payload(&self) -> &[u8] {
5209        self.request.buf()
5210    }
5211    type ReplyType<'buf> = IterableNapi<'buf>;
5212    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5213        Self::decode_request(buf)
5214    }
5215    fn lookup(
5216        buf: &[u8],
5217        offset: usize,
5218        missing_type: Option<u16>,
5219    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5220        Self::decode_request(buf).lookup_attr(offset, missing_type)
5221    }
5222}
5223#[doc = "Get information about NAPI instances configured on the system\\.\nRequest attributes:\n- [.push_id()](PushNapi::push_id)\n\nReply attributes:\n- [.get_ifindex()](IterableNapi::get_ifindex)\n- [.get_id()](IterableNapi::get_id)\n- [.get_irq()](IterableNapi::get_irq)\n- [.get_pid()](IterableNapi::get_pid)\n- [.get_defer_hard_irqs()](IterableNapi::get_defer_hard_irqs)\n- [.get_gro_flush_timeout()](IterableNapi::get_gro_flush_timeout)\n- [.get_irq_suspend_timeout()](IterableNapi::get_irq_suspend_timeout)\n- [.get_threaded()](IterableNapi::get_threaded)\n"]
5224#[derive(Debug)]
5225pub struct OpNapiGetDo<'r> {
5226    request: Request<'r>,
5227}
5228impl<'r> OpNapiGetDo<'r> {
5229    pub fn new(mut request: Request<'r>) -> Self {
5230        Self::write_header(request.buf_mut());
5231        Self { request: request }
5232    }
5233    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushNapi<&'buf mut Vec<u8>> {
5234        Self::write_header(buf);
5235        PushNapi::new(buf)
5236    }
5237    pub fn encode(&mut self) -> PushNapi<&mut Vec<u8>> {
5238        PushNapi::new(self.request.buf_mut())
5239    }
5240    pub fn into_encoder(self) -> PushNapi<RequestBuf<'r>> {
5241        PushNapi::new(self.request.buf)
5242    }
5243    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableNapi<'a> {
5244        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5245        IterableNapi::with_loc(attrs, buf.as_ptr() as usize)
5246    }
5247    fn write_header<Prev: Rec>(prev: &mut Prev) {
5248        let mut header = BuiltinNfgenmsg::new();
5249        header.cmd = 11u8;
5250        header.version = 1u8;
5251        prev.as_rec_mut().extend(header.as_slice());
5252    }
5253}
5254impl NetlinkRequest for OpNapiGetDo<'_> {
5255    fn protocol(&self) -> Protocol {
5256        Protocol::Generic("netdev".as_bytes())
5257    }
5258    fn flags(&self) -> u16 {
5259        self.request.flags
5260    }
5261    fn payload(&self) -> &[u8] {
5262        self.request.buf()
5263    }
5264    type ReplyType<'buf> = IterableNapi<'buf>;
5265    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5266        Self::decode_request(buf)
5267    }
5268    fn lookup(
5269        buf: &[u8],
5270        offset: usize,
5271        missing_type: Option<u16>,
5272    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5273        Self::decode_request(buf).lookup_attr(offset, missing_type)
5274    }
5275}
5276#[doc = "Get / dump fine grained statistics\\. Which statistics are reported\ndepends on the device and the driver, and whether the driver stores\nsoftware counters per\\-queue\\.\n\nRequest attributes:\n- [.push_ifindex()](PushQstats::push_ifindex)\n- [.push_scope()](PushQstats::push_scope)\n\nReply attributes:\n- [.get_ifindex()](IterableQstats::get_ifindex)\n- [.get_queue_type()](IterableQstats::get_queue_type)\n- [.get_queue_id()](IterableQstats::get_queue_id)\n- [.get_rx_packets()](IterableQstats::get_rx_packets)\n- [.get_rx_bytes()](IterableQstats::get_rx_bytes)\n- [.get_tx_packets()](IterableQstats::get_tx_packets)\n- [.get_tx_bytes()](IterableQstats::get_tx_bytes)\n- [.get_rx_alloc_fail()](IterableQstats::get_rx_alloc_fail)\n- [.get_rx_hw_drops()](IterableQstats::get_rx_hw_drops)\n- [.get_rx_hw_drop_overruns()](IterableQstats::get_rx_hw_drop_overruns)\n- [.get_rx_csum_complete()](IterableQstats::get_rx_csum_complete)\n- [.get_rx_csum_unnecessary()](IterableQstats::get_rx_csum_unnecessary)\n- [.get_rx_csum_none()](IterableQstats::get_rx_csum_none)\n- [.get_rx_csum_bad()](IterableQstats::get_rx_csum_bad)\n- [.get_rx_hw_gro_packets()](IterableQstats::get_rx_hw_gro_packets)\n- [.get_rx_hw_gro_bytes()](IterableQstats::get_rx_hw_gro_bytes)\n- [.get_rx_hw_gro_wire_packets()](IterableQstats::get_rx_hw_gro_wire_packets)\n- [.get_rx_hw_gro_wire_bytes()](IterableQstats::get_rx_hw_gro_wire_bytes)\n- [.get_rx_hw_drop_ratelimits()](IterableQstats::get_rx_hw_drop_ratelimits)\n- [.get_tx_hw_drops()](IterableQstats::get_tx_hw_drops)\n- [.get_tx_hw_drop_errors()](IterableQstats::get_tx_hw_drop_errors)\n- [.get_tx_csum_none()](IterableQstats::get_tx_csum_none)\n- [.get_tx_needs_csum()](IterableQstats::get_tx_needs_csum)\n- [.get_tx_hw_gso_packets()](IterableQstats::get_tx_hw_gso_packets)\n- [.get_tx_hw_gso_bytes()](IterableQstats::get_tx_hw_gso_bytes)\n- [.get_tx_hw_gso_wire_packets()](IterableQstats::get_tx_hw_gso_wire_packets)\n- [.get_tx_hw_gso_wire_bytes()](IterableQstats::get_tx_hw_gso_wire_bytes)\n- [.get_tx_hw_drop_ratelimits()](IterableQstats::get_tx_hw_drop_ratelimits)\n- [.get_tx_stop()](IterableQstats::get_tx_stop)\n- [.get_tx_wake()](IterableQstats::get_tx_wake)\n"]
5277#[derive(Debug)]
5278pub struct OpQstatsGetDump<'r> {
5279    request: Request<'r>,
5280}
5281impl<'r> OpQstatsGetDump<'r> {
5282    pub fn new(mut request: Request<'r>) -> Self {
5283        Self::write_header(request.buf_mut());
5284        Self {
5285            request: request.set_dump(),
5286        }
5287    }
5288    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushQstats<&'buf mut Vec<u8>> {
5289        Self::write_header(buf);
5290        PushQstats::new(buf)
5291    }
5292    pub fn encode(&mut self) -> PushQstats<&mut Vec<u8>> {
5293        PushQstats::new(self.request.buf_mut())
5294    }
5295    pub fn into_encoder(self) -> PushQstats<RequestBuf<'r>> {
5296        PushQstats::new(self.request.buf)
5297    }
5298    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableQstats<'a> {
5299        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5300        IterableQstats::with_loc(attrs, buf.as_ptr() as usize)
5301    }
5302    fn write_header<Prev: Rec>(prev: &mut Prev) {
5303        let mut header = BuiltinNfgenmsg::new();
5304        header.cmd = 12u8;
5305        header.version = 1u8;
5306        prev.as_rec_mut().extend(header.as_slice());
5307    }
5308}
5309impl NetlinkRequest for OpQstatsGetDump<'_> {
5310    fn protocol(&self) -> Protocol {
5311        Protocol::Generic("netdev".as_bytes())
5312    }
5313    fn flags(&self) -> u16 {
5314        self.request.flags
5315    }
5316    fn payload(&self) -> &[u8] {
5317        self.request.buf()
5318    }
5319    type ReplyType<'buf> = IterableQstats<'buf>;
5320    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5321        Self::decode_request(buf)
5322    }
5323    fn lookup(
5324        buf: &[u8],
5325        offset: usize,
5326        missing_type: Option<u16>,
5327    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5328        Self::decode_request(buf).lookup_attr(offset, missing_type)
5329    }
5330}
5331#[doc = "Bind dmabuf to netdev\nFlags: admin-perm\nRequest attributes:\n- [.push_ifindex()](PushDmabuf::push_ifindex)\n- [.nested_queues()](PushDmabuf::nested_queues)\n- [.push_fd()](PushDmabuf::push_fd)\n\nReply attributes:\n- [.get_id()](IterableDmabuf::get_id)\n"]
5332#[derive(Debug)]
5333pub struct OpBindRxDo<'r> {
5334    request: Request<'r>,
5335}
5336impl<'r> OpBindRxDo<'r> {
5337    pub fn new(mut request: Request<'r>) -> Self {
5338        Self::write_header(request.buf_mut());
5339        Self { request: request }
5340    }
5341    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushDmabuf<&'buf mut Vec<u8>> {
5342        Self::write_header(buf);
5343        PushDmabuf::new(buf)
5344    }
5345    pub fn encode(&mut self) -> PushDmabuf<&mut Vec<u8>> {
5346        PushDmabuf::new(self.request.buf_mut())
5347    }
5348    pub fn into_encoder(self) -> PushDmabuf<RequestBuf<'r>> {
5349        PushDmabuf::new(self.request.buf)
5350    }
5351    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableDmabuf<'a> {
5352        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5353        IterableDmabuf::with_loc(attrs, buf.as_ptr() as usize)
5354    }
5355    fn write_header<Prev: Rec>(prev: &mut Prev) {
5356        let mut header = BuiltinNfgenmsg::new();
5357        header.cmd = 13u8;
5358        header.version = 1u8;
5359        prev.as_rec_mut().extend(header.as_slice());
5360    }
5361}
5362impl NetlinkRequest for OpBindRxDo<'_> {
5363    fn protocol(&self) -> Protocol {
5364        Protocol::Generic("netdev".as_bytes())
5365    }
5366    fn flags(&self) -> u16 {
5367        self.request.flags
5368    }
5369    fn payload(&self) -> &[u8] {
5370        self.request.buf()
5371    }
5372    type ReplyType<'buf> = IterableDmabuf<'buf>;
5373    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5374        Self::decode_request(buf)
5375    }
5376    fn lookup(
5377        buf: &[u8],
5378        offset: usize,
5379        missing_type: Option<u16>,
5380    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5381        Self::decode_request(buf).lookup_attr(offset, missing_type)
5382    }
5383}
5384#[doc = "Set configurable NAPI instance settings\\.\nFlags: admin-perm\nRequest attributes:\n- [.push_id()](PushNapi::push_id)\n- [.push_defer_hard_irqs()](PushNapi::push_defer_hard_irqs)\n- [.push_gro_flush_timeout()](PushNapi::push_gro_flush_timeout)\n- [.push_irq_suspend_timeout()](PushNapi::push_irq_suspend_timeout)\n- [.push_threaded()](PushNapi::push_threaded)\n"]
5385#[derive(Debug)]
5386pub struct OpNapiSetDo<'r> {
5387    request: Request<'r>,
5388}
5389impl<'r> OpNapiSetDo<'r> {
5390    pub fn new(mut request: Request<'r>) -> Self {
5391        Self::write_header(request.buf_mut());
5392        Self { request: request }
5393    }
5394    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushNapi<&'buf mut Vec<u8>> {
5395        Self::write_header(buf);
5396        PushNapi::new(buf)
5397    }
5398    pub fn encode(&mut self) -> PushNapi<&mut Vec<u8>> {
5399        PushNapi::new(self.request.buf_mut())
5400    }
5401    pub fn into_encoder(self) -> PushNapi<RequestBuf<'r>> {
5402        PushNapi::new(self.request.buf)
5403    }
5404    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableNapi<'a> {
5405        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5406        IterableNapi::with_loc(attrs, buf.as_ptr() as usize)
5407    }
5408    fn write_header<Prev: Rec>(prev: &mut Prev) {
5409        let mut header = BuiltinNfgenmsg::new();
5410        header.cmd = 14u8;
5411        header.version = 1u8;
5412        prev.as_rec_mut().extend(header.as_slice());
5413    }
5414}
5415impl NetlinkRequest for OpNapiSetDo<'_> {
5416    fn protocol(&self) -> Protocol {
5417        Protocol::Generic("netdev".as_bytes())
5418    }
5419    fn flags(&self) -> u16 {
5420        self.request.flags
5421    }
5422    fn payload(&self) -> &[u8] {
5423        self.request.buf()
5424    }
5425    type ReplyType<'buf> = IterableNapi<'buf>;
5426    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5427        Self::decode_request(buf)
5428    }
5429    fn lookup(
5430        buf: &[u8],
5431        offset: usize,
5432        missing_type: Option<u16>,
5433    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5434        Self::decode_request(buf).lookup_attr(offset, missing_type)
5435    }
5436}
5437#[doc = "Bind dmabuf to netdev for TX\nRequest attributes:\n- [.push_ifindex()](PushDmabuf::push_ifindex)\n- [.push_fd()](PushDmabuf::push_fd)\n\nReply attributes:\n- [.get_id()](IterableDmabuf::get_id)\n"]
5438#[derive(Debug)]
5439pub struct OpBindTxDo<'r> {
5440    request: Request<'r>,
5441}
5442impl<'r> OpBindTxDo<'r> {
5443    pub fn new(mut request: Request<'r>) -> Self {
5444        Self::write_header(request.buf_mut());
5445        Self { request: request }
5446    }
5447    pub fn encode_request<'buf>(buf: &'buf mut Vec<u8>) -> PushDmabuf<&'buf mut Vec<u8>> {
5448        Self::write_header(buf);
5449        PushDmabuf::new(buf)
5450    }
5451    pub fn encode(&mut self) -> PushDmabuf<&mut Vec<u8>> {
5452        PushDmabuf::new(self.request.buf_mut())
5453    }
5454    pub fn into_encoder(self) -> PushDmabuf<RequestBuf<'r>> {
5455        PushDmabuf::new(self.request.buf)
5456    }
5457    pub fn decode_request<'a>(buf: &'a [u8]) -> IterableDmabuf<'a> {
5458        let (_header, attrs) = buf.split_at(buf.len().min(BuiltinNfgenmsg::len()));
5459        IterableDmabuf::with_loc(attrs, buf.as_ptr() as usize)
5460    }
5461    fn write_header<Prev: Rec>(prev: &mut Prev) {
5462        let mut header = BuiltinNfgenmsg::new();
5463        header.cmd = 15u8;
5464        header.version = 1u8;
5465        prev.as_rec_mut().extend(header.as_slice());
5466    }
5467}
5468impl NetlinkRequest for OpBindTxDo<'_> {
5469    fn protocol(&self) -> Protocol {
5470        Protocol::Generic("netdev".as_bytes())
5471    }
5472    fn flags(&self) -> u16 {
5473        self.request.flags
5474    }
5475    fn payload(&self) -> &[u8] {
5476        self.request.buf()
5477    }
5478    type ReplyType<'buf> = IterableDmabuf<'buf>;
5479    fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
5480        Self::decode_request(buf)
5481    }
5482    fn lookup(
5483        buf: &[u8],
5484        offset: usize,
5485        missing_type: Option<u16>,
5486    ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
5487        Self::decode_request(buf).lookup_attr(offset, missing_type)
5488    }
5489}
5490use crate::traits::LookupFn;
5491use crate::utils::RequestBuf;
5492#[derive(Debug)]
5493pub struct Request<'buf> {
5494    buf: RequestBuf<'buf>,
5495    flags: u16,
5496    writeback: Option<&'buf mut Option<RequestInfo>>,
5497}
5498#[allow(unused)]
5499#[derive(Debug, Clone)]
5500pub struct RequestInfo {
5501    protocol: Protocol,
5502    flags: u16,
5503    name: &'static str,
5504    lookup: LookupFn,
5505}
5506impl Request<'static> {
5507    pub fn new() -> Self {
5508        Self::new_from_buf(Vec::new())
5509    }
5510    pub fn new_from_buf(buf: Vec<u8>) -> Self {
5511        Self {
5512            flags: 0,
5513            buf: RequestBuf::Own(buf),
5514            writeback: None,
5515        }
5516    }
5517    pub fn into_buf(self) -> Vec<u8> {
5518        match self.buf {
5519            RequestBuf::Own(buf) => buf,
5520            _ => unreachable!(),
5521        }
5522    }
5523}
5524impl<'buf> Request<'buf> {
5525    pub fn new_with_buf(buf: &'buf mut Vec<u8>) -> Self {
5526        buf.clear();
5527        Self::new_extend(buf)
5528    }
5529    pub fn new_extend(buf: &'buf mut Vec<u8>) -> Self {
5530        Self {
5531            flags: 0,
5532            buf: RequestBuf::Ref(buf),
5533            writeback: None,
5534        }
5535    }
5536    fn do_writeback(&mut self, protocol: Protocol, name: &'static str, lookup: LookupFn) {
5537        let Some(writeback) = &mut self.writeback else {
5538            return;
5539        };
5540        **writeback = Some(RequestInfo {
5541            protocol,
5542            flags: self.flags,
5543            name,
5544            lookup,
5545        })
5546    }
5547    pub fn buf(&self) -> &Vec<u8> {
5548        self.buf.buf()
5549    }
5550    pub fn buf_mut(&mut self) -> &mut Vec<u8> {
5551        self.buf.buf_mut()
5552    }
5553    #[doc = "Set `NLM_F_CREATE` flag"]
5554    pub fn set_create(mut self) -> Self {
5555        self.flags |= consts::NLM_F_CREATE as u16;
5556        self
5557    }
5558    #[doc = "Set `NLM_F_EXCL` flag"]
5559    pub fn set_excl(mut self) -> Self {
5560        self.flags |= consts::NLM_F_EXCL as u16;
5561        self
5562    }
5563    #[doc = "Set `NLM_F_REPLACE` flag"]
5564    pub fn set_replace(mut self) -> Self {
5565        self.flags |= consts::NLM_F_REPLACE as u16;
5566        self
5567    }
5568    #[doc = "Set `NLM_F_CREATE` and `NLM_F_REPLACE` flag"]
5569    pub fn set_change(self) -> Self {
5570        self.set_create().set_replace()
5571    }
5572    #[doc = "Set `NLM_F_APPEND` flag"]
5573    pub fn set_append(mut self) -> Self {
5574        self.flags |= consts::NLM_F_APPEND as u16;
5575        self
5576    }
5577    #[doc = "Set `self.flags |= flags`"]
5578    pub fn set_flags(mut self, flags: u16) -> Self {
5579        self.flags |= flags;
5580        self
5581    }
5582    #[doc = "Set `self.flags ^= self.flags & flags`"]
5583    pub fn unset_flags(mut self, flags: u16) -> Self {
5584        self.flags ^= self.flags & flags;
5585        self
5586    }
5587    #[doc = "Set `NLM_F_DUMP` flag"]
5588    fn set_dump(mut self) -> Self {
5589        self.flags |= consts::NLM_F_DUMP as u16;
5590        self
5591    }
5592    #[doc = "Get / dump information about a netdev\\.\n\nReply attributes:\n- [.get_ifindex()](IterableDev::get_ifindex)\n- [.get_xdp_features()](IterableDev::get_xdp_features)\n- [.get_xdp_zc_max_segs()](IterableDev::get_xdp_zc_max_segs)\n- [.get_xdp_rx_metadata_features()](IterableDev::get_xdp_rx_metadata_features)\n- [.get_xsk_features()](IterableDev::get_xsk_features)\n"]
5593    pub fn op_dev_get_dump(self) -> OpDevGetDump<'buf> {
5594        let mut res = OpDevGetDump::new(self);
5595        res.request
5596            .do_writeback(res.protocol(), "op-dev-get-dump", OpDevGetDump::lookup);
5597        res
5598    }
5599    #[doc = "Get / dump information about a netdev\\.\nRequest attributes:\n- [.push_ifindex()](PushDev::push_ifindex)\n\nReply attributes:\n- [.get_ifindex()](IterableDev::get_ifindex)\n- [.get_xdp_features()](IterableDev::get_xdp_features)\n- [.get_xdp_zc_max_segs()](IterableDev::get_xdp_zc_max_segs)\n- [.get_xdp_rx_metadata_features()](IterableDev::get_xdp_rx_metadata_features)\n- [.get_xsk_features()](IterableDev::get_xsk_features)\n"]
5600    pub fn op_dev_get_do(self) -> OpDevGetDo<'buf> {
5601        let mut res = OpDevGetDo::new(self);
5602        res.request
5603            .do_writeback(res.protocol(), "op-dev-get-do", OpDevGetDo::lookup);
5604        res
5605    }
5606    #[doc = "Get / dump information about Page Pools\\.\nOnly Page Pools associated by the driver with a net\\_device\ncan be listed\\. ifindex will not be reported if the net\\_device\nno longer exists\\.\n\n\nReply attributes:\n- [.get_id()](IterablePagePool::get_id)\n- [.get_ifindex()](IterablePagePool::get_ifindex)\n- [.get_napi_id()](IterablePagePool::get_napi_id)\n- [.get_inflight()](IterablePagePool::get_inflight)\n- [.get_inflight_mem()](IterablePagePool::get_inflight_mem)\n- [.get_detach_time()](IterablePagePool::get_detach_time)\n- [.get_dmabuf()](IterablePagePool::get_dmabuf)\n- [.get_io_uring()](IterablePagePool::get_io_uring)\n"]
5607    pub fn op_page_pool_get_dump(self) -> OpPagePoolGetDump<'buf> {
5608        let mut res = OpPagePoolGetDump::new(self);
5609        res.request.do_writeback(
5610            res.protocol(),
5611            "op-page-pool-get-dump",
5612            OpPagePoolGetDump::lookup,
5613        );
5614        res
5615    }
5616    #[doc = "Get / dump information about Page Pools\\.\nOnly Page Pools associated by the driver with a net\\_device\ncan be listed\\. ifindex will not be reported if the net\\_device\nno longer exists\\.\n\nRequest attributes:\n- [.push_id()](PushPagePool::push_id)\n\nReply attributes:\n- [.get_id()](IterablePagePool::get_id)\n- [.get_ifindex()](IterablePagePool::get_ifindex)\n- [.get_napi_id()](IterablePagePool::get_napi_id)\n- [.get_inflight()](IterablePagePool::get_inflight)\n- [.get_inflight_mem()](IterablePagePool::get_inflight_mem)\n- [.get_detach_time()](IterablePagePool::get_detach_time)\n- [.get_dmabuf()](IterablePagePool::get_dmabuf)\n- [.get_io_uring()](IterablePagePool::get_io_uring)\n"]
5617    pub fn op_page_pool_get_do(self) -> OpPagePoolGetDo<'buf> {
5618        let mut res = OpPagePoolGetDo::new(self);
5619        res.request.do_writeback(
5620            res.protocol(),
5621            "op-page-pool-get-do",
5622            OpPagePoolGetDo::lookup,
5623        );
5624        res
5625    }
5626    #[doc = "Get page pool statistics\\.\n\nReply attributes:\n- [.get_info()](IterablePagePoolStats::get_info)\n- [.get_alloc_fast()](IterablePagePoolStats::get_alloc_fast)\n- [.get_alloc_slow()](IterablePagePoolStats::get_alloc_slow)\n- [.get_alloc_slow_high_order()](IterablePagePoolStats::get_alloc_slow_high_order)\n- [.get_alloc_empty()](IterablePagePoolStats::get_alloc_empty)\n- [.get_alloc_refill()](IterablePagePoolStats::get_alloc_refill)\n- [.get_alloc_waive()](IterablePagePoolStats::get_alloc_waive)\n- [.get_recycle_cached()](IterablePagePoolStats::get_recycle_cached)\n- [.get_recycle_cache_full()](IterablePagePoolStats::get_recycle_cache_full)\n- [.get_recycle_ring()](IterablePagePoolStats::get_recycle_ring)\n- [.get_recycle_ring_full()](IterablePagePoolStats::get_recycle_ring_full)\n- [.get_recycle_released_refcnt()](IterablePagePoolStats::get_recycle_released_refcnt)\n"]
5627    pub fn op_page_pool_stats_get_dump(self) -> OpPagePoolStatsGetDump<'buf> {
5628        let mut res = OpPagePoolStatsGetDump::new(self);
5629        res.request.do_writeback(
5630            res.protocol(),
5631            "op-page-pool-stats-get-dump",
5632            OpPagePoolStatsGetDump::lookup,
5633        );
5634        res
5635    }
5636    #[doc = "Get page pool statistics\\.\nRequest attributes:\n- [.nested_info()](PushPagePoolStats::nested_info)\n\nReply attributes:\n- [.get_info()](IterablePagePoolStats::get_info)\n- [.get_alloc_fast()](IterablePagePoolStats::get_alloc_fast)\n- [.get_alloc_slow()](IterablePagePoolStats::get_alloc_slow)\n- [.get_alloc_slow_high_order()](IterablePagePoolStats::get_alloc_slow_high_order)\n- [.get_alloc_empty()](IterablePagePoolStats::get_alloc_empty)\n- [.get_alloc_refill()](IterablePagePoolStats::get_alloc_refill)\n- [.get_alloc_waive()](IterablePagePoolStats::get_alloc_waive)\n- [.get_recycle_cached()](IterablePagePoolStats::get_recycle_cached)\n- [.get_recycle_cache_full()](IterablePagePoolStats::get_recycle_cache_full)\n- [.get_recycle_ring()](IterablePagePoolStats::get_recycle_ring)\n- [.get_recycle_ring_full()](IterablePagePoolStats::get_recycle_ring_full)\n- [.get_recycle_released_refcnt()](IterablePagePoolStats::get_recycle_released_refcnt)\n"]
5637    pub fn op_page_pool_stats_get_do(self) -> OpPagePoolStatsGetDo<'buf> {
5638        let mut res = OpPagePoolStatsGetDo::new(self);
5639        res.request.do_writeback(
5640            res.protocol(),
5641            "op-page-pool-stats-get-do",
5642            OpPagePoolStatsGetDo::lookup,
5643        );
5644        res
5645    }
5646    #[doc = "Get queue information from the kernel\\. Only configured queues will be reported (as opposed to all available hardware queues)\\.\nRequest attributes:\n- [.push_ifindex()](PushQueue::push_ifindex)\n\nReply attributes:\n- [.get_id()](IterableQueue::get_id)\n- [.get_ifindex()](IterableQueue::get_ifindex)\n- [.get_type()](IterableQueue::get_type)\n- [.get_napi_id()](IterableQueue::get_napi_id)\n- [.get_dmabuf()](IterableQueue::get_dmabuf)\n- [.get_io_uring()](IterableQueue::get_io_uring)\n- [.get_xsk()](IterableQueue::get_xsk)\n"]
5647    pub fn op_queue_get_dump(self) -> OpQueueGetDump<'buf> {
5648        let mut res = OpQueueGetDump::new(self);
5649        res.request
5650            .do_writeback(res.protocol(), "op-queue-get-dump", OpQueueGetDump::lookup);
5651        res
5652    }
5653    #[doc = "Get queue information from the kernel\\. Only configured queues will be reported (as opposed to all available hardware queues)\\.\nRequest attributes:\n- [.push_id()](PushQueue::push_id)\n- [.push_ifindex()](PushQueue::push_ifindex)\n- [.push_type()](PushQueue::push_type)\n\nReply attributes:\n- [.get_id()](IterableQueue::get_id)\n- [.get_ifindex()](IterableQueue::get_ifindex)\n- [.get_type()](IterableQueue::get_type)\n- [.get_napi_id()](IterableQueue::get_napi_id)\n- [.get_dmabuf()](IterableQueue::get_dmabuf)\n- [.get_io_uring()](IterableQueue::get_io_uring)\n- [.get_xsk()](IterableQueue::get_xsk)\n"]
5654    pub fn op_queue_get_do(self) -> OpQueueGetDo<'buf> {
5655        let mut res = OpQueueGetDo::new(self);
5656        res.request
5657            .do_writeback(res.protocol(), "op-queue-get-do", OpQueueGetDo::lookup);
5658        res
5659    }
5660    #[doc = "Get information about NAPI instances configured on the system\\.\nRequest attributes:\n- [.push_ifindex()](PushNapi::push_ifindex)\n\nReply attributes:\n- [.get_ifindex()](IterableNapi::get_ifindex)\n- [.get_id()](IterableNapi::get_id)\n- [.get_irq()](IterableNapi::get_irq)\n- [.get_pid()](IterableNapi::get_pid)\n- [.get_defer_hard_irqs()](IterableNapi::get_defer_hard_irqs)\n- [.get_gro_flush_timeout()](IterableNapi::get_gro_flush_timeout)\n- [.get_irq_suspend_timeout()](IterableNapi::get_irq_suspend_timeout)\n- [.get_threaded()](IterableNapi::get_threaded)\n"]
5661    pub fn op_napi_get_dump(self) -> OpNapiGetDump<'buf> {
5662        let mut res = OpNapiGetDump::new(self);
5663        res.request
5664            .do_writeback(res.protocol(), "op-napi-get-dump", OpNapiGetDump::lookup);
5665        res
5666    }
5667    #[doc = "Get information about NAPI instances configured on the system\\.\nRequest attributes:\n- [.push_id()](PushNapi::push_id)\n\nReply attributes:\n- [.get_ifindex()](IterableNapi::get_ifindex)\n- [.get_id()](IterableNapi::get_id)\n- [.get_irq()](IterableNapi::get_irq)\n- [.get_pid()](IterableNapi::get_pid)\n- [.get_defer_hard_irqs()](IterableNapi::get_defer_hard_irqs)\n- [.get_gro_flush_timeout()](IterableNapi::get_gro_flush_timeout)\n- [.get_irq_suspend_timeout()](IterableNapi::get_irq_suspend_timeout)\n- [.get_threaded()](IterableNapi::get_threaded)\n"]
5668    pub fn op_napi_get_do(self) -> OpNapiGetDo<'buf> {
5669        let mut res = OpNapiGetDo::new(self);
5670        res.request
5671            .do_writeback(res.protocol(), "op-napi-get-do", OpNapiGetDo::lookup);
5672        res
5673    }
5674    #[doc = "Get / dump fine grained statistics\\. Which statistics are reported\ndepends on the device and the driver, and whether the driver stores\nsoftware counters per\\-queue\\.\n\nRequest attributes:\n- [.push_ifindex()](PushQstats::push_ifindex)\n- [.push_scope()](PushQstats::push_scope)\n\nReply attributes:\n- [.get_ifindex()](IterableQstats::get_ifindex)\n- [.get_queue_type()](IterableQstats::get_queue_type)\n- [.get_queue_id()](IterableQstats::get_queue_id)\n- [.get_rx_packets()](IterableQstats::get_rx_packets)\n- [.get_rx_bytes()](IterableQstats::get_rx_bytes)\n- [.get_tx_packets()](IterableQstats::get_tx_packets)\n- [.get_tx_bytes()](IterableQstats::get_tx_bytes)\n- [.get_rx_alloc_fail()](IterableQstats::get_rx_alloc_fail)\n- [.get_rx_hw_drops()](IterableQstats::get_rx_hw_drops)\n- [.get_rx_hw_drop_overruns()](IterableQstats::get_rx_hw_drop_overruns)\n- [.get_rx_csum_complete()](IterableQstats::get_rx_csum_complete)\n- [.get_rx_csum_unnecessary()](IterableQstats::get_rx_csum_unnecessary)\n- [.get_rx_csum_none()](IterableQstats::get_rx_csum_none)\n- [.get_rx_csum_bad()](IterableQstats::get_rx_csum_bad)\n- [.get_rx_hw_gro_packets()](IterableQstats::get_rx_hw_gro_packets)\n- [.get_rx_hw_gro_bytes()](IterableQstats::get_rx_hw_gro_bytes)\n- [.get_rx_hw_gro_wire_packets()](IterableQstats::get_rx_hw_gro_wire_packets)\n- [.get_rx_hw_gro_wire_bytes()](IterableQstats::get_rx_hw_gro_wire_bytes)\n- [.get_rx_hw_drop_ratelimits()](IterableQstats::get_rx_hw_drop_ratelimits)\n- [.get_tx_hw_drops()](IterableQstats::get_tx_hw_drops)\n- [.get_tx_hw_drop_errors()](IterableQstats::get_tx_hw_drop_errors)\n- [.get_tx_csum_none()](IterableQstats::get_tx_csum_none)\n- [.get_tx_needs_csum()](IterableQstats::get_tx_needs_csum)\n- [.get_tx_hw_gso_packets()](IterableQstats::get_tx_hw_gso_packets)\n- [.get_tx_hw_gso_bytes()](IterableQstats::get_tx_hw_gso_bytes)\n- [.get_tx_hw_gso_wire_packets()](IterableQstats::get_tx_hw_gso_wire_packets)\n- [.get_tx_hw_gso_wire_bytes()](IterableQstats::get_tx_hw_gso_wire_bytes)\n- [.get_tx_hw_drop_ratelimits()](IterableQstats::get_tx_hw_drop_ratelimits)\n- [.get_tx_stop()](IterableQstats::get_tx_stop)\n- [.get_tx_wake()](IterableQstats::get_tx_wake)\n"]
5675    pub fn op_qstats_get_dump(self) -> OpQstatsGetDump<'buf> {
5676        let mut res = OpQstatsGetDump::new(self);
5677        res.request.do_writeback(
5678            res.protocol(),
5679            "op-qstats-get-dump",
5680            OpQstatsGetDump::lookup,
5681        );
5682        res
5683    }
5684    #[doc = "Bind dmabuf to netdev\nFlags: admin-perm\nRequest attributes:\n- [.push_ifindex()](PushDmabuf::push_ifindex)\n- [.nested_queues()](PushDmabuf::nested_queues)\n- [.push_fd()](PushDmabuf::push_fd)\n\nReply attributes:\n- [.get_id()](IterableDmabuf::get_id)\n"]
5685    pub fn op_bind_rx_do(self) -> OpBindRxDo<'buf> {
5686        let mut res = OpBindRxDo::new(self);
5687        res.request
5688            .do_writeback(res.protocol(), "op-bind-rx-do", OpBindRxDo::lookup);
5689        res
5690    }
5691    #[doc = "Set configurable NAPI instance settings\\.\nFlags: admin-perm\nRequest attributes:\n- [.push_id()](PushNapi::push_id)\n- [.push_defer_hard_irqs()](PushNapi::push_defer_hard_irqs)\n- [.push_gro_flush_timeout()](PushNapi::push_gro_flush_timeout)\n- [.push_irq_suspend_timeout()](PushNapi::push_irq_suspend_timeout)\n- [.push_threaded()](PushNapi::push_threaded)\n"]
5692    pub fn op_napi_set_do(self) -> OpNapiSetDo<'buf> {
5693        let mut res = OpNapiSetDo::new(self);
5694        res.request
5695            .do_writeback(res.protocol(), "op-napi-set-do", OpNapiSetDo::lookup);
5696        res
5697    }
5698    #[doc = "Bind dmabuf to netdev for TX\nRequest attributes:\n- [.push_ifindex()](PushDmabuf::push_ifindex)\n- [.push_fd()](PushDmabuf::push_fd)\n\nReply attributes:\n- [.get_id()](IterableDmabuf::get_id)\n"]
5699    pub fn op_bind_tx_do(self) -> OpBindTxDo<'buf> {
5700        let mut res = OpBindTxDo::new(self);
5701        res.request
5702            .do_writeback(res.protocol(), "op-bind-tx-do", OpBindTxDo::lookup);
5703        res
5704    }
5705}
5706#[cfg(test)]
5707mod generated_tests {
5708    use super::*;
5709    #[test]
5710    fn tests() {
5711        let _ = IterableDev::get_ifindex;
5712        let _ = IterableDev::get_xdp_features;
5713        let _ = IterableDev::get_xdp_rx_metadata_features;
5714        let _ = IterableDev::get_xdp_zc_max_segs;
5715        let _ = IterableDev::get_xsk_features;
5716        let _ = IterableDmabuf::get_id;
5717        let _ = IterableNapi::get_defer_hard_irqs;
5718        let _ = IterableNapi::get_gro_flush_timeout;
5719        let _ = IterableNapi::get_id;
5720        let _ = IterableNapi::get_ifindex;
5721        let _ = IterableNapi::get_irq;
5722        let _ = IterableNapi::get_irq_suspend_timeout;
5723        let _ = IterableNapi::get_pid;
5724        let _ = IterableNapi::get_threaded;
5725        let _ = IterablePagePool::get_detach_time;
5726        let _ = IterablePagePool::get_dmabuf;
5727        let _ = IterablePagePool::get_id;
5728        let _ = IterablePagePool::get_ifindex;
5729        let _ = IterablePagePool::get_inflight;
5730        let _ = IterablePagePool::get_inflight_mem;
5731        let _ = IterablePagePool::get_io_uring;
5732        let _ = IterablePagePool::get_napi_id;
5733        let _ = IterablePagePoolStats::get_alloc_empty;
5734        let _ = IterablePagePoolStats::get_alloc_fast;
5735        let _ = IterablePagePoolStats::get_alloc_refill;
5736        let _ = IterablePagePoolStats::get_alloc_slow;
5737        let _ = IterablePagePoolStats::get_alloc_slow_high_order;
5738        let _ = IterablePagePoolStats::get_alloc_waive;
5739        let _ = IterablePagePoolStats::get_info;
5740        let _ = IterablePagePoolStats::get_recycle_cache_full;
5741        let _ = IterablePagePoolStats::get_recycle_cached;
5742        let _ = IterablePagePoolStats::get_recycle_released_refcnt;
5743        let _ = IterablePagePoolStats::get_recycle_ring;
5744        let _ = IterablePagePoolStats::get_recycle_ring_full;
5745        let _ = IterableQstats::get_ifindex;
5746        let _ = IterableQstats::get_queue_id;
5747        let _ = IterableQstats::get_queue_type;
5748        let _ = IterableQstats::get_rx_alloc_fail;
5749        let _ = IterableQstats::get_rx_bytes;
5750        let _ = IterableQstats::get_rx_csum_bad;
5751        let _ = IterableQstats::get_rx_csum_complete;
5752        let _ = IterableQstats::get_rx_csum_none;
5753        let _ = IterableQstats::get_rx_csum_unnecessary;
5754        let _ = IterableQstats::get_rx_hw_drop_overruns;
5755        let _ = IterableQstats::get_rx_hw_drop_ratelimits;
5756        let _ = IterableQstats::get_rx_hw_drops;
5757        let _ = IterableQstats::get_rx_hw_gro_bytes;
5758        let _ = IterableQstats::get_rx_hw_gro_packets;
5759        let _ = IterableQstats::get_rx_hw_gro_wire_bytes;
5760        let _ = IterableQstats::get_rx_hw_gro_wire_packets;
5761        let _ = IterableQstats::get_rx_packets;
5762        let _ = IterableQstats::get_tx_bytes;
5763        let _ = IterableQstats::get_tx_csum_none;
5764        let _ = IterableQstats::get_tx_hw_drop_errors;
5765        let _ = IterableQstats::get_tx_hw_drop_ratelimits;
5766        let _ = IterableQstats::get_tx_hw_drops;
5767        let _ = IterableQstats::get_tx_hw_gso_bytes;
5768        let _ = IterableQstats::get_tx_hw_gso_packets;
5769        let _ = IterableQstats::get_tx_hw_gso_wire_bytes;
5770        let _ = IterableQstats::get_tx_hw_gso_wire_packets;
5771        let _ = IterableQstats::get_tx_needs_csum;
5772        let _ = IterableQstats::get_tx_packets;
5773        let _ = IterableQstats::get_tx_stop;
5774        let _ = IterableQstats::get_tx_wake;
5775        let _ = IterableQueue::get_dmabuf;
5776        let _ = IterableQueue::get_id;
5777        let _ = IterableQueue::get_ifindex;
5778        let _ = IterableQueue::get_io_uring;
5779        let _ = IterableQueue::get_napi_id;
5780        let _ = IterableQueue::get_type;
5781        let _ = IterableQueue::get_xsk;
5782        let _ = OpDevAddNotif;
5783        let _ = OpDevChangeNotif;
5784        let _ = OpDevDelNotif;
5785        let _ = OpPagePoolAddNotif;
5786        let _ = OpPagePoolChangeNotif;
5787        let _ = OpPagePoolDelNotif;
5788        let _ = PushDev::<&mut Vec<u8>>::push_ifindex;
5789        let _ = PushDmabuf::<&mut Vec<u8>>::nested_queues;
5790        let _ = PushDmabuf::<&mut Vec<u8>>::push_fd;
5791        let _ = PushDmabuf::<&mut Vec<u8>>::push_ifindex;
5792        let _ = PushNapi::<&mut Vec<u8>>::push_defer_hard_irqs;
5793        let _ = PushNapi::<&mut Vec<u8>>::push_gro_flush_timeout;
5794        let _ = PushNapi::<&mut Vec<u8>>::push_id;
5795        let _ = PushNapi::<&mut Vec<u8>>::push_ifindex;
5796        let _ = PushNapi::<&mut Vec<u8>>::push_irq_suspend_timeout;
5797        let _ = PushNapi::<&mut Vec<u8>>::push_threaded;
5798        let _ = PushPagePool::<&mut Vec<u8>>::push_id;
5799        let _ = PushPagePoolStats::<&mut Vec<u8>>::nested_info;
5800        let _ = PushQstats::<&mut Vec<u8>>::push_ifindex;
5801        let _ = PushQstats::<&mut Vec<u8>>::push_scope;
5802        let _ = PushQueue::<&mut Vec<u8>>::push_id;
5803        let _ = PushQueue::<&mut Vec<u8>>::push_ifindex;
5804        let _ = PushQueue::<&mut Vec<u8>>::push_type;
5805    }
5806}