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