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