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