1#![doc = "OVS datapath 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 = "ovs_datapath";
17pub const PROTONAME_CSTR: &CStr = c"ovs_datapath";
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 UserFeatures {
21 #[doc = "Allow last Netlink attribute to be unaligned"]
22 Unaligned = 1 << 0,
23 #[doc = "Allow datapath to associate multiple Netlink PIDs to each vport"]
24 VportPids = 1 << 1,
25 #[doc = "Allow tc offload recirc sharing"]
26 TcRecircSharing = 1 << 2,
27 #[doc = "Allow per\\-cpu dispatch of upcalls"]
28 DispatchUpcallPerCpu = 1 << 3,
29}
30impl UserFeatures {
31 pub fn from_value(value: u64) -> Option<Self> {
32 Some(match value {
33 n if n == 1 << 0 => Self::Unaligned,
34 n if n == 1 << 1 => Self::VportPids,
35 n if n == 1 << 2 => Self::TcRecircSharing,
36 n if n == 1 << 3 => Self::DispatchUpcallPerCpu,
37 _ => return None,
38 })
39 }
40}
41#[derive(Debug)]
42#[repr(C, packed(4))]
43pub struct OvsHeader {
44 pub dp_ifindex: u32,
45}
46impl Clone for OvsHeader {
47 fn clone(&self) -> Self {
48 Self::new_from_array(*self.as_array())
49 }
50}
51#[doc = "Create zero-initialized struct"]
52impl Default for OvsHeader {
53 fn default() -> Self {
54 Self::new()
55 }
56}
57impl OvsHeader {
58 #[doc = "Create zero-initialized struct"]
59 pub fn new() -> Self {
60 Self::new_from_array([0u8; Self::len()])
61 }
62 #[doc = "Copy from contents from slice"]
63 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
64 if other.len() != Self::len() {
65 return None;
66 }
67 let mut buf = [0u8; Self::len()];
68 buf.clone_from_slice(other);
69 Some(Self::new_from_array(buf))
70 }
71 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
72 pub fn new_from_zeroed(other: &[u8]) -> Self {
73 let mut buf = [0u8; Self::len()];
74 let len = buf.len().min(other.len());
75 buf[..len].clone_from_slice(&other[..len]);
76 Self::new_from_array(buf)
77 }
78 pub fn new_from_array(buf: [u8; 4usize]) -> Self {
79 unsafe { std::mem::transmute(buf) }
80 }
81 pub fn as_slice(&self) -> &[u8] {
82 unsafe {
83 let ptr: *const u8 = std::mem::transmute(self as *const Self);
84 std::slice::from_raw_parts(ptr, Self::len())
85 }
86 }
87 pub fn from_slice(buf: &[u8]) -> &Self {
88 assert!(buf.len() >= Self::len());
89 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
90 unsafe { std::mem::transmute(buf.as_ptr()) }
91 }
92 pub fn as_array(&self) -> &[u8; 4usize] {
93 unsafe { std::mem::transmute(self) }
94 }
95 pub fn from_array(buf: &[u8; 4usize]) -> &Self {
96 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
97 unsafe { std::mem::transmute(buf) }
98 }
99 pub fn into_array(self) -> [u8; 4usize] {
100 unsafe { std::mem::transmute(self) }
101 }
102 pub const fn len() -> usize {
103 const _: () = assert!(std::mem::size_of::<OvsHeader>() == 4usize);
104 4usize
105 }
106}
107#[repr(C, packed(4))]
108pub struct OvsDpStats {
109 pub n_hit: u64,
110 pub n_missed: u64,
111 pub n_lost: u64,
112 pub n_flows: u64,
113}
114impl Clone for OvsDpStats {
115 fn clone(&self) -> Self {
116 Self::new_from_array(*self.as_array())
117 }
118}
119#[doc = "Create zero-initialized struct"]
120impl Default for OvsDpStats {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125impl OvsDpStats {
126 #[doc = "Create zero-initialized struct"]
127 pub fn new() -> Self {
128 Self::new_from_array([0u8; Self::len()])
129 }
130 #[doc = "Copy from contents from slice"]
131 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
132 if other.len() != Self::len() {
133 return None;
134 }
135 let mut buf = [0u8; Self::len()];
136 buf.clone_from_slice(other);
137 Some(Self::new_from_array(buf))
138 }
139 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
140 pub fn new_from_zeroed(other: &[u8]) -> Self {
141 let mut buf = [0u8; Self::len()];
142 let len = buf.len().min(other.len());
143 buf[..len].clone_from_slice(&other[..len]);
144 Self::new_from_array(buf)
145 }
146 pub fn new_from_array(buf: [u8; 32usize]) -> Self {
147 unsafe { std::mem::transmute(buf) }
148 }
149 pub fn as_slice(&self) -> &[u8] {
150 unsafe {
151 let ptr: *const u8 = std::mem::transmute(self as *const Self);
152 std::slice::from_raw_parts(ptr, Self::len())
153 }
154 }
155 pub fn from_slice(buf: &[u8]) -> &Self {
156 assert!(buf.len() >= Self::len());
157 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
158 unsafe { std::mem::transmute(buf.as_ptr()) }
159 }
160 pub fn as_array(&self) -> &[u8; 32usize] {
161 unsafe { std::mem::transmute(self) }
162 }
163 pub fn from_array(buf: &[u8; 32usize]) -> &Self {
164 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
165 unsafe { std::mem::transmute(buf) }
166 }
167 pub fn into_array(self) -> [u8; 32usize] {
168 unsafe { std::mem::transmute(self) }
169 }
170 pub const fn len() -> usize {
171 const _: () = assert!(std::mem::size_of::<OvsDpStats>() == 32usize);
172 32usize
173 }
174}
175impl std::fmt::Debug for OvsDpStats {
176 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 fmt.debug_struct("OvsDpStats")
178 .field("n_hit", &{ self.n_hit })
179 .field("n_missed", &{ self.n_missed })
180 .field("n_lost", &{ self.n_lost })
181 .field("n_flows", &{ self.n_flows })
182 .finish()
183 }
184}
185#[repr(C, packed(4))]
186pub struct OvsDpMegaflowStats {
187 pub n_mask_hit: u64,
188 pub n_masks: u32,
189 pub padding: u32,
190 pub n_cache_hit: u64,
191 pub pad1: u64,
192}
193impl Clone for OvsDpMegaflowStats {
194 fn clone(&self) -> Self {
195 Self::new_from_array(*self.as_array())
196 }
197}
198#[doc = "Create zero-initialized struct"]
199impl Default for OvsDpMegaflowStats {
200 fn default() -> Self {
201 Self::new()
202 }
203}
204impl OvsDpMegaflowStats {
205 #[doc = "Create zero-initialized struct"]
206 pub fn new() -> Self {
207 Self::new_from_array([0u8; Self::len()])
208 }
209 #[doc = "Copy from contents from slice"]
210 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
211 if other.len() != Self::len() {
212 return None;
213 }
214 let mut buf = [0u8; Self::len()];
215 buf.clone_from_slice(other);
216 Some(Self::new_from_array(buf))
217 }
218 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
219 pub fn new_from_zeroed(other: &[u8]) -> Self {
220 let mut buf = [0u8; Self::len()];
221 let len = buf.len().min(other.len());
222 buf[..len].clone_from_slice(&other[..len]);
223 Self::new_from_array(buf)
224 }
225 pub fn new_from_array(buf: [u8; 32usize]) -> Self {
226 unsafe { std::mem::transmute(buf) }
227 }
228 pub fn as_slice(&self) -> &[u8] {
229 unsafe {
230 let ptr: *const u8 = std::mem::transmute(self as *const Self);
231 std::slice::from_raw_parts(ptr, Self::len())
232 }
233 }
234 pub fn from_slice(buf: &[u8]) -> &Self {
235 assert!(buf.len() >= Self::len());
236 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
237 unsafe { std::mem::transmute(buf.as_ptr()) }
238 }
239 pub fn as_array(&self) -> &[u8; 32usize] {
240 unsafe { std::mem::transmute(self) }
241 }
242 pub fn from_array(buf: &[u8; 32usize]) -> &Self {
243 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
244 unsafe { std::mem::transmute(buf) }
245 }
246 pub fn into_array(self) -> [u8; 32usize] {
247 unsafe { std::mem::transmute(self) }
248 }
249 pub const fn len() -> usize {
250 const _: () = assert!(std::mem::size_of::<OvsDpMegaflowStats>() == 32usize);
251 32usize
252 }
253}
254impl std::fmt::Debug for OvsDpMegaflowStats {
255 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 fmt.debug_struct("OvsDpMegaflowStats")
257 .field("n_mask_hit", &{ self.n_mask_hit })
258 .field("n_masks", &self.n_masks)
259 .field("padding", &self.padding)
260 .field("n_cache_hit", &{ self.n_cache_hit })
261 .field("pad1", &{ self.pad1 })
262 .finish()
263 }
264}
265#[derive(Clone)]
266pub enum Datapath<'a> {
267 Name(&'a CStr),
268 #[doc = "upcall pid"]
269 UpcallPid(u32),
270 Stats(OvsDpStats),
271 MegaflowStats(OvsDpMegaflowStats),
272 #[doc = "Associated type: [`UserFeatures`] (1 bit per enumeration)"]
273 UserFeatures(u32),
274 MasksCacheSize(u32),
275 PerCpuPids(&'a [u8]),
276 Ifindex(u32),
277}
278impl<'a> IterableDatapath<'a> {
279 pub fn get_name(&self) -> Result<&'a CStr, ErrorContext> {
280 let mut iter = self.clone();
281 iter.pos = 0;
282 for attr in iter {
283 if let Datapath::Name(val) = attr? {
284 return Ok(val);
285 }
286 }
287 Err(ErrorContext::new_missing(
288 "Datapath",
289 "Name",
290 self.orig_loc,
291 self.buf.as_ptr() as usize,
292 ))
293 }
294 #[doc = "upcall pid"]
295 pub fn get_upcall_pid(&self) -> Result<u32, ErrorContext> {
296 let mut iter = self.clone();
297 iter.pos = 0;
298 for attr in iter {
299 if let Datapath::UpcallPid(val) = attr? {
300 return Ok(val);
301 }
302 }
303 Err(ErrorContext::new_missing(
304 "Datapath",
305 "UpcallPid",
306 self.orig_loc,
307 self.buf.as_ptr() as usize,
308 ))
309 }
310 pub fn get_stats(&self) -> Result<OvsDpStats, ErrorContext> {
311 let mut iter = self.clone();
312 iter.pos = 0;
313 for attr in iter {
314 if let Datapath::Stats(val) = attr? {
315 return Ok(val);
316 }
317 }
318 Err(ErrorContext::new_missing(
319 "Datapath",
320 "Stats",
321 self.orig_loc,
322 self.buf.as_ptr() as usize,
323 ))
324 }
325 pub fn get_megaflow_stats(&self) -> Result<OvsDpMegaflowStats, ErrorContext> {
326 let mut iter = self.clone();
327 iter.pos = 0;
328 for attr in iter {
329 if let Datapath::MegaflowStats(val) = attr? {
330 return Ok(val);
331 }
332 }
333 Err(ErrorContext::new_missing(
334 "Datapath",
335 "MegaflowStats",
336 self.orig_loc,
337 self.buf.as_ptr() as usize,
338 ))
339 }
340 #[doc = "Associated type: [`UserFeatures`] (1 bit per enumeration)"]
341 pub fn get_user_features(&self) -> Result<u32, ErrorContext> {
342 let mut iter = self.clone();
343 iter.pos = 0;
344 for attr in iter {
345 if let Datapath::UserFeatures(val) = attr? {
346 return Ok(val);
347 }
348 }
349 Err(ErrorContext::new_missing(
350 "Datapath",
351 "UserFeatures",
352 self.orig_loc,
353 self.buf.as_ptr() as usize,
354 ))
355 }
356 pub fn get_masks_cache_size(&self) -> Result<u32, ErrorContext> {
357 let mut iter = self.clone();
358 iter.pos = 0;
359 for attr in iter {
360 if let Datapath::MasksCacheSize(val) = attr? {
361 return Ok(val);
362 }
363 }
364 Err(ErrorContext::new_missing(
365 "Datapath",
366 "MasksCacheSize",
367 self.orig_loc,
368 self.buf.as_ptr() as usize,
369 ))
370 }
371 pub fn get_per_cpu_pids(&self) -> Result<&'a [u8], ErrorContext> {
372 let mut iter = self.clone();
373 iter.pos = 0;
374 for attr in iter {
375 if let Datapath::PerCpuPids(val) = attr? {
376 return Ok(val);
377 }
378 }
379 Err(ErrorContext::new_missing(
380 "Datapath",
381 "PerCpuPids",
382 self.orig_loc,
383 self.buf.as_ptr() as usize,
384 ))
385 }
386 pub fn get_ifindex(&self) -> Result<u32, ErrorContext> {
387 let mut iter = self.clone();
388 iter.pos = 0;
389 for attr in iter {
390 if let Datapath::Ifindex(val) = attr? {
391 return Ok(val);
392 }
393 }
394 Err(ErrorContext::new_missing(
395 "Datapath",
396 "Ifindex",
397 self.orig_loc,
398 self.buf.as_ptr() as usize,
399 ))
400 }
401}
402impl Datapath<'_> {
403 pub fn new<'a>(buf: &'a [u8]) -> IterableDatapath<'a> {
404 IterableDatapath::with_loc(buf, buf.as_ptr() as usize)
405 }
406 fn attr_from_type(r#type: u16) -> Option<&'static str> {
407 let res = match r#type {
408 1u16 => "Name",
409 2u16 => "UpcallPid",
410 3u16 => "Stats",
411 4u16 => "MegaflowStats",
412 5u16 => "UserFeatures",
413 6u16 => "Pad",
414 7u16 => "MasksCacheSize",
415 8u16 => "PerCpuPids",
416 9u16 => "Ifindex",
417 _ => return None,
418 };
419 Some(res)
420 }
421}
422#[derive(Clone, Copy, Default)]
423pub struct IterableDatapath<'a> {
424 buf: &'a [u8],
425 pos: usize,
426 orig_loc: usize,
427}
428impl<'a> IterableDatapath<'a> {
429 fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
430 Self {
431 buf,
432 pos: 0,
433 orig_loc,
434 }
435 }
436 pub fn get_buf(&self) -> &'a [u8] {
437 self.buf
438 }
439}
440impl<'a> Iterator for IterableDatapath<'a> {
441 type Item = Result<Datapath<'a>, ErrorContext>;
442 fn next(&mut self) -> Option<Self::Item> {
443 let pos = self.pos;
444 let mut r#type;
445 loop {
446 r#type = None;
447 if self.buf.len() == self.pos {
448 return None;
449 }
450 let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
451 break;
452 };
453 r#type = Some(header.r#type);
454 let res = match header.r#type {
455 1u16 => Datapath::Name({
456 let res = CStr::from_bytes_with_nul(next).ok();
457 let Some(val) = res else { break };
458 val
459 }),
460 2u16 => Datapath::UpcallPid({
461 let res = parse_u32(next);
462 let Some(val) = res else { break };
463 val
464 }),
465 3u16 => Datapath::Stats({
466 let res = Some(OvsDpStats::new_from_zeroed(next));
467 let Some(val) = res else { break };
468 val
469 }),
470 4u16 => Datapath::MegaflowStats({
471 let res = Some(OvsDpMegaflowStats::new_from_zeroed(next));
472 let Some(val) = res else { break };
473 val
474 }),
475 5u16 => Datapath::UserFeatures({
476 let res = parse_u32(next);
477 let Some(val) = res else { break };
478 val
479 }),
480 7u16 => Datapath::MasksCacheSize({
481 let res = parse_u32(next);
482 let Some(val) = res else { break };
483 val
484 }),
485 8u16 => Datapath::PerCpuPids({
486 let res = Some(next);
487 let Some(val) = res else { break };
488 val
489 }),
490 9u16 => Datapath::Ifindex({
491 let res = parse_u32(next);
492 let Some(val) = res else { break };
493 val
494 }),
495 n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
496 n => continue,
497 };
498 return Some(Ok(res));
499 }
500 Some(Err(ErrorContext::new(
501 "Datapath",
502 r#type.and_then(|t| Datapath::attr_from_type(t)),
503 self.orig_loc,
504 self.buf.as_ptr().wrapping_add(pos) as usize,
505 )))
506 }
507}
508impl<'a> std::fmt::Debug for IterableDatapath<'_> {
509 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
510 let mut fmt = f.debug_struct("Datapath");
511 for attr in self.clone() {
512 let attr = match attr {
513 Ok(a) => a,
514 Err(err) => {
515 fmt.finish()?;
516 f.write_str("Err(")?;
517 err.fmt(f)?;
518 return f.write_str(")");
519 }
520 };
521 match attr {
522 Datapath::Name(val) => fmt.field("Name", &val),
523 Datapath::UpcallPid(val) => fmt.field("UpcallPid", &val),
524 Datapath::Stats(val) => fmt.field("Stats", &val),
525 Datapath::MegaflowStats(val) => fmt.field("MegaflowStats", &val),
526 Datapath::UserFeatures(val) => fmt.field(
527 "UserFeatures",
528 &FormatFlags(val.into(), UserFeatures::from_value),
529 ),
530 Datapath::MasksCacheSize(val) => fmt.field("MasksCacheSize", &val),
531 Datapath::PerCpuPids(val) => fmt.field("PerCpuPids", &val),
532 Datapath::Ifindex(val) => fmt.field("Ifindex", &val),
533 };
534 }
535 fmt.finish()
536 }
537}
538impl IterableDatapath<'_> {
539 pub fn lookup_attr(
540 &self,
541 offset: usize,
542 missing_type: Option<u16>,
543 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
544 let mut stack = Vec::new();
545 let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
546 if missing_type.is_some() && cur == offset {
547 stack.push(("Datapath", offset));
548 return (
549 stack,
550 missing_type.and_then(|t| Datapath::attr_from_type(t)),
551 );
552 }
553 if cur > offset || cur + self.buf.len() < offset {
554 return (stack, None);
555 }
556 let mut attrs = self.clone();
557 let mut last_off = cur + attrs.pos;
558 while let Some(attr) = attrs.next() {
559 let Ok(attr) = attr else { break };
560 match attr {
561 Datapath::Name(val) => {
562 if last_off == offset {
563 stack.push(("Name", last_off));
564 break;
565 }
566 }
567 Datapath::UpcallPid(val) => {
568 if last_off == offset {
569 stack.push(("UpcallPid", last_off));
570 break;
571 }
572 }
573 Datapath::Stats(val) => {
574 if last_off == offset {
575 stack.push(("Stats", last_off));
576 break;
577 }
578 }
579 Datapath::MegaflowStats(val) => {
580 if last_off == offset {
581 stack.push(("MegaflowStats", last_off));
582 break;
583 }
584 }
585 Datapath::UserFeatures(val) => {
586 if last_off == offset {
587 stack.push(("UserFeatures", last_off));
588 break;
589 }
590 }
591 Datapath::MasksCacheSize(val) => {
592 if last_off == offset {
593 stack.push(("MasksCacheSize", last_off));
594 break;
595 }
596 }
597 Datapath::PerCpuPids(val) => {
598 if last_off == offset {
599 stack.push(("PerCpuPids", last_off));
600 break;
601 }
602 }
603 Datapath::Ifindex(val) => {
604 if last_off == offset {
605 stack.push(("Ifindex", last_off));
606 break;
607 }
608 }
609 _ => {}
610 };
611 last_off = cur + attrs.pos;
612 }
613 if !stack.is_empty() {
614 stack.push(("Datapath", cur));
615 }
616 (stack, None)
617 }
618}
619pub struct PushDatapath<Prev: Rec> {
620 pub(crate) prev: Option<Prev>,
621 pub(crate) header_offset: Option<usize>,
622}
623impl<Prev: Rec> Rec for PushDatapath<Prev> {
624 fn as_rec_mut(&mut self) -> &mut Vec<u8> {
625 self.prev.as_mut().unwrap().as_rec_mut()
626 }
627 fn as_rec(&self) -> &Vec<u8> {
628 self.prev.as_ref().unwrap().as_rec()
629 }
630}
631impl<Prev: Rec> PushDatapath<Prev> {
632 pub fn new(prev: Prev) -> Self {
633 Self {
634 prev: Some(prev),
635 header_offset: None,
636 }
637 }
638 pub fn end_nested(mut self) -> Prev {
639 let mut prev = self.prev.take().unwrap();
640 if let Some(header_offset) = &self.header_offset {
641 finalize_nested_header(prev.as_rec_mut(), *header_offset);
642 }
643 prev
644 }
645 pub fn push_name(mut self, value: &CStr) -> Self {
646 push_header(
647 self.as_rec_mut(),
648 1u16,
649 value.to_bytes_with_nul().len() as u16,
650 );
651 self.as_rec_mut().extend(value.to_bytes_with_nul());
652 self
653 }
654 pub fn push_name_bytes(mut self, value: &[u8]) -> Self {
655 push_header(self.as_rec_mut(), 1u16, (value.len() + 1) as u16);
656 self.as_rec_mut().extend(value);
657 self.as_rec_mut().push(0);
658 self
659 }
660 #[doc = "upcall pid"]
661 pub fn push_upcall_pid(mut self, value: u32) -> Self {
662 push_header(self.as_rec_mut(), 2u16, 4 as u16);
663 self.as_rec_mut().extend(value.to_ne_bytes());
664 self
665 }
666 pub fn push_stats(mut self, value: OvsDpStats) -> Self {
667 push_header(self.as_rec_mut(), 3u16, value.as_slice().len() as u16);
668 self.as_rec_mut().extend(value.as_slice());
669 self
670 }
671 pub fn push_megaflow_stats(mut self, value: OvsDpMegaflowStats) -> Self {
672 push_header(self.as_rec_mut(), 4u16, value.as_slice().len() as u16);
673 self.as_rec_mut().extend(value.as_slice());
674 self
675 }
676 #[doc = "Associated type: [`UserFeatures`] (1 bit per enumeration)"]
677 pub fn push_user_features(mut self, value: u32) -> Self {
678 push_header(self.as_rec_mut(), 5u16, 4 as u16);
679 self.as_rec_mut().extend(value.to_ne_bytes());
680 self
681 }
682 pub fn push_masks_cache_size(mut self, value: u32) -> Self {
683 push_header(self.as_rec_mut(), 7u16, 4 as u16);
684 self.as_rec_mut().extend(value.to_ne_bytes());
685 self
686 }
687 pub fn push_per_cpu_pids(mut self, value: &[u8]) -> Self {
688 push_header(self.as_rec_mut(), 8u16, value.len() as u16);
689 self.as_rec_mut().extend(value);
690 self
691 }
692 pub fn push_ifindex(mut self, value: u32) -> Self {
693 push_header(self.as_rec_mut(), 9u16, 4 as u16);
694 self.as_rec_mut().extend(value.to_ne_bytes());
695 self
696 }
697}
698impl<Prev: Rec> Drop for PushDatapath<Prev> {
699 fn drop(&mut self) {
700 if let Some(prev) = &mut self.prev {
701 if let Some(header_offset) = &self.header_offset {
702 finalize_nested_header(prev.as_rec_mut(), *header_offset);
703 }
704 }
705 }
706}
707pub struct NotifGroup;
708impl NotifGroup {
709 pub const OVS_DATAPATH: &str = "ovs_datapath";
710 pub const OVS_DATAPATH_CSTR: &CStr = c"ovs_datapath";
711}
712#[doc = "Get / dump OVS data path configuration and state\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n\nReply attributes:\n- [.get_name()](IterableDatapath::get_name)\n- [.get_upcall_pid()](IterableDatapath::get_upcall_pid)\n- [.get_stats()](IterableDatapath::get_stats)\n- [.get_megaflow_stats()](IterableDatapath::get_megaflow_stats)\n- [.get_user_features()](IterableDatapath::get_user_features)\n- [.get_masks_cache_size()](IterableDatapath::get_masks_cache_size)\n- [.get_per_cpu_pids()](IterableDatapath::get_per_cpu_pids)\n"]
713#[derive(Debug)]
714pub struct OpGetDump<'r> {
715 request: Request<'r>,
716}
717impl<'r> OpGetDump<'r> {
718 pub fn new(mut request: Request<'r>, header: &OvsHeader) -> Self {
719 Self::write_header(request.buf_mut(), header);
720 Self {
721 request: request.set_dump(),
722 }
723 }
724 pub fn encode_request<'buf>(
725 buf: &'buf mut Vec<u8>,
726 header: &OvsHeader,
727 ) -> PushDatapath<&'buf mut Vec<u8>> {
728 Self::write_header(buf, header);
729 PushDatapath::new(buf)
730 }
731 pub fn encode(&mut self) -> PushDatapath<&mut Vec<u8>> {
732 PushDatapath::new(self.request.buf_mut())
733 }
734 pub fn into_encoder(self) -> PushDatapath<RequestBuf<'r>> {
735 PushDatapath::new(self.request.buf)
736 }
737 pub fn decode_request<'a>(buf: &'a [u8]) -> (OvsHeader, IterableDatapath<'a>) {
738 let (header, attrs) = buf.split_at(buf.len().min(OvsHeader::len()));
739 (
740 OvsHeader::new_from_slice(header).unwrap_or_default(),
741 IterableDatapath::with_loc(attrs, buf.as_ptr() as usize),
742 )
743 }
744 fn write_header<Prev: Rec>(prev: &mut Prev, header: &OvsHeader) {
745 prev.as_rec_mut().extend(header.as_slice());
746 }
747}
748impl NetlinkRequest for OpGetDump<'_> {
749 fn protocol(&self) -> Protocol {
750 Protocol::Generic("ovs_datapath".as_bytes())
751 }
752 fn flags(&self) -> u16 {
753 self.request.flags
754 }
755 fn payload(&self) -> &[u8] {
756 self.request.buf()
757 }
758 type ReplyType<'buf> = (OvsHeader, IterableDatapath<'buf>);
759 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
760 Self::decode_request(buf)
761 }
762 fn lookup(
763 buf: &[u8],
764 offset: usize,
765 missing_type: Option<u16>,
766 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
767 Self::decode_request(buf)
768 .1
769 .lookup_attr(offset, missing_type)
770 }
771}
772#[doc = "Get / dump OVS data path configuration and state\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n\nReply attributes:\n- [.get_name()](IterableDatapath::get_name)\n- [.get_upcall_pid()](IterableDatapath::get_upcall_pid)\n- [.get_stats()](IterableDatapath::get_stats)\n- [.get_megaflow_stats()](IterableDatapath::get_megaflow_stats)\n- [.get_user_features()](IterableDatapath::get_user_features)\n- [.get_masks_cache_size()](IterableDatapath::get_masks_cache_size)\n- [.get_per_cpu_pids()](IterableDatapath::get_per_cpu_pids)\n"]
773#[derive(Debug)]
774pub struct OpGetDo<'r> {
775 request: Request<'r>,
776}
777impl<'r> OpGetDo<'r> {
778 pub fn new(mut request: Request<'r>, header: &OvsHeader) -> Self {
779 Self::write_header(request.buf_mut(), header);
780 Self { request: request }
781 }
782 pub fn encode_request<'buf>(
783 buf: &'buf mut Vec<u8>,
784 header: &OvsHeader,
785 ) -> PushDatapath<&'buf mut Vec<u8>> {
786 Self::write_header(buf, header);
787 PushDatapath::new(buf)
788 }
789 pub fn encode(&mut self) -> PushDatapath<&mut Vec<u8>> {
790 PushDatapath::new(self.request.buf_mut())
791 }
792 pub fn into_encoder(self) -> PushDatapath<RequestBuf<'r>> {
793 PushDatapath::new(self.request.buf)
794 }
795 pub fn decode_request<'a>(buf: &'a [u8]) -> (OvsHeader, IterableDatapath<'a>) {
796 let (header, attrs) = buf.split_at(buf.len().min(OvsHeader::len()));
797 (
798 OvsHeader::new_from_slice(header).unwrap_or_default(),
799 IterableDatapath::with_loc(attrs, buf.as_ptr() as usize),
800 )
801 }
802 fn write_header<Prev: Rec>(prev: &mut Prev, header: &OvsHeader) {
803 prev.as_rec_mut().extend(header.as_slice());
804 }
805}
806impl NetlinkRequest for OpGetDo<'_> {
807 fn protocol(&self) -> Protocol {
808 Protocol::Generic("ovs_datapath".as_bytes())
809 }
810 fn flags(&self) -> u16 {
811 self.request.flags
812 }
813 fn payload(&self) -> &[u8] {
814 self.request.buf()
815 }
816 type ReplyType<'buf> = (OvsHeader, IterableDatapath<'buf>);
817 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
818 Self::decode_request(buf)
819 }
820 fn lookup(
821 buf: &[u8],
822 offset: usize,
823 missing_type: Option<u16>,
824 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
825 Self::decode_request(buf)
826 .1
827 .lookup_attr(offset, missing_type)
828 }
829}
830#[doc = "Create new OVS data path\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n- [.push_upcall_pid()](PushDatapath::push_upcall_pid)\n- [.push_user_features()](PushDatapath::push_user_features)\n"]
831#[derive(Debug)]
832pub struct OpNewDo<'r> {
833 request: Request<'r>,
834}
835impl<'r> OpNewDo<'r> {
836 pub fn new(mut request: Request<'r>, header: &OvsHeader) -> Self {
837 Self::write_header(request.buf_mut(), header);
838 Self { request: request }
839 }
840 pub fn encode_request<'buf>(
841 buf: &'buf mut Vec<u8>,
842 header: &OvsHeader,
843 ) -> PushDatapath<&'buf mut Vec<u8>> {
844 Self::write_header(buf, header);
845 PushDatapath::new(buf)
846 }
847 pub fn encode(&mut self) -> PushDatapath<&mut Vec<u8>> {
848 PushDatapath::new(self.request.buf_mut())
849 }
850 pub fn into_encoder(self) -> PushDatapath<RequestBuf<'r>> {
851 PushDatapath::new(self.request.buf)
852 }
853 pub fn decode_request<'a>(buf: &'a [u8]) -> (OvsHeader, IterableDatapath<'a>) {
854 let (header, attrs) = buf.split_at(buf.len().min(OvsHeader::len()));
855 (
856 OvsHeader::new_from_slice(header).unwrap_or_default(),
857 IterableDatapath::with_loc(attrs, buf.as_ptr() as usize),
858 )
859 }
860 fn write_header<Prev: Rec>(prev: &mut Prev, header: &OvsHeader) {
861 prev.as_rec_mut().extend(header.as_slice());
862 }
863}
864impl NetlinkRequest for OpNewDo<'_> {
865 fn protocol(&self) -> Protocol {
866 Protocol::Generic("ovs_datapath".as_bytes())
867 }
868 fn flags(&self) -> u16 {
869 self.request.flags
870 }
871 fn payload(&self) -> &[u8] {
872 self.request.buf()
873 }
874 type ReplyType<'buf> = (OvsHeader, IterableDatapath<'buf>);
875 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
876 Self::decode_request(buf)
877 }
878 fn lookup(
879 buf: &[u8],
880 offset: usize,
881 missing_type: Option<u16>,
882 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
883 Self::decode_request(buf)
884 .1
885 .lookup_attr(offset, missing_type)
886 }
887}
888#[doc = "Delete existing OVS data path\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n"]
889#[derive(Debug)]
890pub struct OpDelDo<'r> {
891 request: Request<'r>,
892}
893impl<'r> OpDelDo<'r> {
894 pub fn new(mut request: Request<'r>, header: &OvsHeader) -> Self {
895 Self::write_header(request.buf_mut(), header);
896 Self { request: request }
897 }
898 pub fn encode_request<'buf>(
899 buf: &'buf mut Vec<u8>,
900 header: &OvsHeader,
901 ) -> PushDatapath<&'buf mut Vec<u8>> {
902 Self::write_header(buf, header);
903 PushDatapath::new(buf)
904 }
905 pub fn encode(&mut self) -> PushDatapath<&mut Vec<u8>> {
906 PushDatapath::new(self.request.buf_mut())
907 }
908 pub fn into_encoder(self) -> PushDatapath<RequestBuf<'r>> {
909 PushDatapath::new(self.request.buf)
910 }
911 pub fn decode_request<'a>(buf: &'a [u8]) -> (OvsHeader, IterableDatapath<'a>) {
912 let (header, attrs) = buf.split_at(buf.len().min(OvsHeader::len()));
913 (
914 OvsHeader::new_from_slice(header).unwrap_or_default(),
915 IterableDatapath::with_loc(attrs, buf.as_ptr() as usize),
916 )
917 }
918 fn write_header<Prev: Rec>(prev: &mut Prev, header: &OvsHeader) {
919 prev.as_rec_mut().extend(header.as_slice());
920 }
921}
922impl NetlinkRequest for OpDelDo<'_> {
923 fn protocol(&self) -> Protocol {
924 Protocol::Generic("ovs_datapath".as_bytes())
925 }
926 fn flags(&self) -> u16 {
927 self.request.flags
928 }
929 fn payload(&self) -> &[u8] {
930 self.request.buf()
931 }
932 type ReplyType<'buf> = (OvsHeader, IterableDatapath<'buf>);
933 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
934 Self::decode_request(buf)
935 }
936 fn lookup(
937 buf: &[u8],
938 offset: usize,
939 missing_type: Option<u16>,
940 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
941 Self::decode_request(buf)
942 .1
943 .lookup_attr(offset, missing_type)
944 }
945}
946use crate::traits::LookupFn;
947use crate::utils::RequestBuf;
948#[derive(Debug)]
949pub struct Request<'buf> {
950 buf: RequestBuf<'buf>,
951 flags: u16,
952 writeback: Option<&'buf mut Option<RequestInfo>>,
953}
954#[allow(unused)]
955#[derive(Debug, Clone)]
956pub struct RequestInfo {
957 protocol: Protocol,
958 flags: u16,
959 name: &'static str,
960 lookup: LookupFn,
961}
962impl Request<'static> {
963 pub fn new() -> Self {
964 Self::new_from_buf(Vec::new())
965 }
966 pub fn new_from_buf(buf: Vec<u8>) -> Self {
967 Self {
968 flags: 0,
969 buf: RequestBuf::Own(buf),
970 writeback: None,
971 }
972 }
973 pub fn into_buf(self) -> Vec<u8> {
974 match self.buf {
975 RequestBuf::Own(buf) => buf,
976 _ => unreachable!(),
977 }
978 }
979}
980impl<'buf> Request<'buf> {
981 pub fn new_with_buf(buf: &'buf mut Vec<u8>) -> Self {
982 buf.clear();
983 Self::new_extend(buf)
984 }
985 pub fn new_extend(buf: &'buf mut Vec<u8>) -> Self {
986 Self {
987 flags: 0,
988 buf: RequestBuf::Ref(buf),
989 writeback: None,
990 }
991 }
992 fn do_writeback(&mut self, protocol: Protocol, name: &'static str, lookup: LookupFn) {
993 let Some(writeback) = &mut self.writeback else {
994 return;
995 };
996 **writeback = Some(RequestInfo {
997 protocol,
998 flags: self.flags,
999 name,
1000 lookup,
1001 })
1002 }
1003 pub fn buf(&self) -> &Vec<u8> {
1004 self.buf.buf()
1005 }
1006 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
1007 self.buf.buf_mut()
1008 }
1009 #[doc = "Set `NLM_F_CREATE` flag"]
1010 pub fn set_create(mut self) -> Self {
1011 self.flags |= consts::NLM_F_CREATE as u16;
1012 self
1013 }
1014 #[doc = "Set `NLM_F_EXCL` flag"]
1015 pub fn set_excl(mut self) -> Self {
1016 self.flags |= consts::NLM_F_EXCL as u16;
1017 self
1018 }
1019 #[doc = "Set `NLM_F_REPLACE` flag"]
1020 pub fn set_replace(mut self) -> Self {
1021 self.flags |= consts::NLM_F_REPLACE as u16;
1022 self
1023 }
1024 #[doc = "Set `NLM_F_CREATE` and `NLM_F_REPLACE` flag"]
1025 pub fn set_change(self) -> Self {
1026 self.set_create().set_replace()
1027 }
1028 #[doc = "Set `NLM_F_APPEND` flag"]
1029 pub fn set_append(mut self) -> Self {
1030 self.flags |= consts::NLM_F_APPEND as u16;
1031 self
1032 }
1033 #[doc = "Set `self.flags |= flags`"]
1034 pub fn set_flags(mut self, flags: u16) -> Self {
1035 self.flags |= flags;
1036 self
1037 }
1038 #[doc = "Set `self.flags ^= self.flags & flags`"]
1039 pub fn unset_flags(mut self, flags: u16) -> Self {
1040 self.flags ^= self.flags & flags;
1041 self
1042 }
1043 #[doc = "Set `NLM_F_DUMP` flag"]
1044 fn set_dump(mut self) -> Self {
1045 self.flags |= consts::NLM_F_DUMP as u16;
1046 self
1047 }
1048 #[doc = "Get / dump OVS data path configuration and state\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n\nReply attributes:\n- [.get_name()](IterableDatapath::get_name)\n- [.get_upcall_pid()](IterableDatapath::get_upcall_pid)\n- [.get_stats()](IterableDatapath::get_stats)\n- [.get_megaflow_stats()](IterableDatapath::get_megaflow_stats)\n- [.get_user_features()](IterableDatapath::get_user_features)\n- [.get_masks_cache_size()](IterableDatapath::get_masks_cache_size)\n- [.get_per_cpu_pids()](IterableDatapath::get_per_cpu_pids)\n"]
1049 pub fn op_get_dump(self, header: &OvsHeader) -> OpGetDump<'buf> {
1050 let mut res = OpGetDump::new(self, header);
1051 res.request
1052 .do_writeback(res.protocol(), "op-get-dump", OpGetDump::lookup);
1053 res
1054 }
1055 #[doc = "Get / dump OVS data path configuration and state\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n\nReply attributes:\n- [.get_name()](IterableDatapath::get_name)\n- [.get_upcall_pid()](IterableDatapath::get_upcall_pid)\n- [.get_stats()](IterableDatapath::get_stats)\n- [.get_megaflow_stats()](IterableDatapath::get_megaflow_stats)\n- [.get_user_features()](IterableDatapath::get_user_features)\n- [.get_masks_cache_size()](IterableDatapath::get_masks_cache_size)\n- [.get_per_cpu_pids()](IterableDatapath::get_per_cpu_pids)\n"]
1056 pub fn op_get_do(self, header: &OvsHeader) -> OpGetDo<'buf> {
1057 let mut res = OpGetDo::new(self, header);
1058 res.request
1059 .do_writeback(res.protocol(), "op-get-do", OpGetDo::lookup);
1060 res
1061 }
1062 #[doc = "Create new OVS data path\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n- [.push_upcall_pid()](PushDatapath::push_upcall_pid)\n- [.push_user_features()](PushDatapath::push_user_features)\n"]
1063 pub fn op_new_do(self, header: &OvsHeader) -> OpNewDo<'buf> {
1064 let mut res = OpNewDo::new(self, header);
1065 res.request
1066 .do_writeback(res.protocol(), "op-new-do", OpNewDo::lookup);
1067 res
1068 }
1069 #[doc = "Delete existing OVS data path\nRequest attributes:\n- [.push_name()](PushDatapath::push_name)\n"]
1070 pub fn op_del_do(self, header: &OvsHeader) -> OpDelDo<'buf> {
1071 let mut res = OpDelDo::new(self, header);
1072 res.request
1073 .do_writeback(res.protocol(), "op-del-do", OpDelDo::lookup);
1074 res
1075 }
1076}
1077#[cfg(test)]
1078mod generated_tests {
1079 use super::*;
1080 #[test]
1081 fn tests() {
1082 let _ = IterableDatapath::get_masks_cache_size;
1083 let _ = IterableDatapath::get_megaflow_stats;
1084 let _ = IterableDatapath::get_name;
1085 let _ = IterableDatapath::get_per_cpu_pids;
1086 let _ = IterableDatapath::get_stats;
1087 let _ = IterableDatapath::get_upcall_pid;
1088 let _ = IterableDatapath::get_user_features;
1089 let _ = PushDatapath::<&mut Vec<u8>>::push_name;
1090 let _ = PushDatapath::<&mut Vec<u8>>::push_upcall_pid;
1091 let _ = PushDatapath::<&mut Vec<u8>>::push_user_features;
1092 }
1093}