netlink_packet_generic/ctrl/nlas/
mcast.rs1use crate::constants::*;
4use anyhow::Context;
5use byteorder::{ByteOrder, NativeEndian};
6use netlink_packet_utils::{
7 nla::{Nla, NlaBuffer},
8 parsers::*,
9 traits::*,
10 DecodeError,
11};
12use std::{mem::size_of_val, ops::Deref};
13
14pub(crate) struct McastGroupList(Vec<McastGroup>);
15
16impl Deref for McastGroupList {
17 type Target = Vec<McastGroup>;
18
19 fn deref(&self) -> &Self::Target {
20 &self.0
21 }
22}
23
24impl From<&Vec<Vec<McastGrpAttrs>>> for McastGroupList {
25 fn from(groups: &Vec<Vec<McastGrpAttrs>>) -> Self {
26 Self(
27 groups
28 .iter()
29 .cloned()
30 .enumerate()
31 .map(|(index, nlas)| McastGroup {
32 index: index as u16,
33 nlas,
34 })
35 .collect(),
36 )
37 }
38}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
41pub struct McastGroup {
42 pub index: u16,
43 pub nlas: Vec<McastGrpAttrs>,
44}
45
46impl Nla for McastGroup {
47 fn value_len(&self) -> usize {
48 self.nlas.as_slice().buffer_len()
49 }
50
51 fn kind(&self) -> u16 {
52 self.index + 1
53 }
54
55 fn emit_value(&self, buffer: &mut [u8]) {
56 self.nlas.as_slice().emit(buffer);
57 }
58}
59
60#[derive(Clone, Debug, PartialEq, Eq)]
61pub enum McastGrpAttrs {
62 Name(String),
63 Id(u32),
64}
65
66impl Nla for McastGrpAttrs {
67 fn value_len(&self) -> usize {
68 use McastGrpAttrs::*;
69 match self {
70 Name(s) => s.as_bytes().len() + 1,
71 Id(v) => size_of_val(v),
72 }
73 }
74
75 fn kind(&self) -> u16 {
76 use McastGrpAttrs::*;
77 match self {
78 Name(_) => CTRL_ATTR_MCAST_GRP_NAME,
79 Id(_) => CTRL_ATTR_MCAST_GRP_ID,
80 }
81 }
82
83 fn emit_value(&self, buffer: &mut [u8]) {
84 use McastGrpAttrs::*;
85 match self {
86 Name(s) => {
87 buffer[..s.len()].copy_from_slice(s.as_bytes());
88 buffer[s.len()] = 0;
89 }
90 Id(v) => NativeEndian::write_u32(buffer, *v),
91 }
92 }
93}
94
95impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
96 for McastGrpAttrs
97{
98 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
99 let payload = buf.value();
100 Ok(match buf.kind() {
101 CTRL_ATTR_MCAST_GRP_NAME => Self::Name(
102 parse_string(payload)
103 .context("invalid CTRL_ATTR_MCAST_GRP_NAME value")?,
104 ),
105 CTRL_ATTR_MCAST_GRP_ID => Self::Id(
106 parse_u32(payload)
107 .context("invalid CTRL_ATTR_MCAST_GRP_ID value")?,
108 ),
109 kind => {
110 return Err(DecodeError::from(format!(
111 "Unknown NLA type: {kind}"
112 )))
113 }
114 })
115 }
116}