netlink_packet_generic/ctrl/nlas/
mod.rs

1// SPDX-License-Identifier: MIT
2
3use crate::constants::*;
4use anyhow::Context;
5use byteorder::{ByteOrder, NativeEndian};
6use netlink_packet_utils::{
7    nla::{Nla, NlaBuffer, NlasIterator},
8    parsers::*,
9    traits::*,
10    DecodeError,
11};
12use std::mem::size_of_val;
13
14mod mcast;
15mod oppolicy;
16mod ops;
17mod policy;
18
19pub use mcast::*;
20pub use oppolicy::*;
21pub use ops::*;
22pub use policy::*;
23
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub enum GenlCtrlAttrs {
26    FamilyId(u16),
27    FamilyName(String),
28    Version(u32),
29    HdrSize(u32),
30    MaxAttr(u32),
31    Ops(Vec<Vec<OpAttrs>>),
32    McastGroups(Vec<Vec<McastGrpAttrs>>),
33    Policy(PolicyAttr),
34    OpPolicy(OppolicyAttr),
35    Op(u32),
36}
37
38impl Nla for GenlCtrlAttrs {
39    fn value_len(&self) -> usize {
40        use GenlCtrlAttrs::*;
41        match self {
42            FamilyId(v) => size_of_val(v),
43            FamilyName(s) => s.len() + 1,
44            Version(v) => size_of_val(v),
45            HdrSize(v) => size_of_val(v),
46            MaxAttr(v) => size_of_val(v),
47            Ops(nlas) => OpList::from(nlas).as_slice().buffer_len(),
48            McastGroups(nlas) => {
49                McastGroupList::from(nlas).as_slice().buffer_len()
50            }
51            Policy(nla) => nla.buffer_len(),
52            OpPolicy(nla) => nla.buffer_len(),
53            Op(v) => size_of_val(v),
54        }
55    }
56
57    fn kind(&self) -> u16 {
58        use GenlCtrlAttrs::*;
59        match self {
60            FamilyId(_) => CTRL_ATTR_FAMILY_ID,
61            FamilyName(_) => CTRL_ATTR_FAMILY_NAME,
62            Version(_) => CTRL_ATTR_VERSION,
63            HdrSize(_) => CTRL_ATTR_HDRSIZE,
64            MaxAttr(_) => CTRL_ATTR_MAXATTR,
65            Ops(_) => CTRL_ATTR_OPS,
66            McastGroups(_) => CTRL_ATTR_MCAST_GROUPS,
67            Policy(_) => CTRL_ATTR_POLICY,
68            OpPolicy(_) => CTRL_ATTR_OP_POLICY,
69            Op(_) => CTRL_ATTR_OP,
70        }
71    }
72
73    fn emit_value(&self, buffer: &mut [u8]) {
74        use GenlCtrlAttrs::*;
75        match self {
76            FamilyId(v) => NativeEndian::write_u16(buffer, *v),
77            FamilyName(s) => {
78                buffer[..s.len()].copy_from_slice(s.as_bytes());
79                buffer[s.len()] = 0;
80            }
81            Version(v) => NativeEndian::write_u32(buffer, *v),
82            HdrSize(v) => NativeEndian::write_u32(buffer, *v),
83            MaxAttr(v) => NativeEndian::write_u32(buffer, *v),
84            Ops(nlas) => {
85                OpList::from(nlas).as_slice().emit(buffer);
86            }
87            McastGroups(nlas) => {
88                McastGroupList::from(nlas).as_slice().emit(buffer);
89            }
90            Policy(nla) => nla.emit_value(buffer),
91            OpPolicy(nla) => nla.emit_value(buffer),
92            Op(v) => NativeEndian::write_u32(buffer, *v),
93        }
94    }
95}
96
97impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
98    for GenlCtrlAttrs
99{
100    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
101        let payload = buf.value();
102        Ok(match buf.kind() {
103            CTRL_ATTR_FAMILY_ID => Self::FamilyId(
104                parse_u16(payload)
105                    .context("invalid CTRL_ATTR_FAMILY_ID value")?,
106            ),
107            CTRL_ATTR_FAMILY_NAME => Self::FamilyName(
108                parse_string(payload)
109                    .context("invalid CTRL_ATTR_FAMILY_NAME value")?,
110            ),
111            CTRL_ATTR_VERSION => Self::Version(
112                parse_u32(payload)
113                    .context("invalid CTRL_ATTR_VERSION value")?,
114            ),
115            CTRL_ATTR_HDRSIZE => Self::HdrSize(
116                parse_u32(payload)
117                    .context("invalid CTRL_ATTR_HDRSIZE value")?,
118            ),
119            CTRL_ATTR_MAXATTR => Self::MaxAttr(
120                parse_u32(payload)
121                    .context("invalid CTRL_ATTR_MAXATTR value")?,
122            ),
123            CTRL_ATTR_OPS => {
124                let ops = NlasIterator::new(payload)
125                    .map(|nlas| {
126                        nlas.and_then(|nlas| {
127                            NlasIterator::new(nlas.value())
128                                .map(|nla| {
129                                    nla.and_then(|nla| OpAttrs::parse(&nla))
130                                })
131                                .collect::<Result<Vec<_>, _>>()
132                        })
133                    })
134                    .collect::<Result<Vec<Vec<_>>, _>>()
135                    .context("failed to parse CTRL_ATTR_OPS")?;
136                Self::Ops(ops)
137            }
138            CTRL_ATTR_MCAST_GROUPS => {
139                let groups = NlasIterator::new(payload)
140                    .map(|nlas| {
141                        nlas.and_then(|nlas| {
142                            NlasIterator::new(nlas.value())
143                                .map(|nla| {
144                                    nla.and_then(|nla| {
145                                        McastGrpAttrs::parse(&nla)
146                                    })
147                                })
148                                .collect::<Result<Vec<_>, _>>()
149                        })
150                    })
151                    .collect::<Result<Vec<Vec<_>>, _>>()
152                    .context("failed to parse CTRL_ATTR_MCAST_GROUPS")?;
153                Self::McastGroups(groups)
154            }
155            CTRL_ATTR_POLICY => Self::Policy(
156                PolicyAttr::parse(&NlaBuffer::new(payload))
157                    .context("failed to parse CTRL_ATTR_POLICY")?,
158            ),
159            CTRL_ATTR_OP_POLICY => Self::OpPolicy(
160                OppolicyAttr::parse(&NlaBuffer::new(payload))
161                    .context("failed to parse CTRL_ATTR_OP_POLICY")?,
162            ),
163            CTRL_ATTR_OP => Self::Op(parse_u32(payload)?),
164            kind => {
165                return Err(DecodeError::from(format!(
166                    "Unknown NLA type: {kind}"
167                )))
168            }
169        })
170    }
171}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn mcast_groups_parse() {
179        let mcast_bytes: [u8; 24] = [
180            24, 0, // Netlink header length
181            7, 0, // Netlink header kind (Mcast groups)
182            20, 0, // Mcast group nested NLA length
183            1, 0, // Mcast group kind
184            8, 0, // Id length
185            2, 0, // Id kind
186            1, 0, 0, 0, // Id
187            8, 0, // Name length
188            1, 0, // Name kind
189            b't', b'e', b's', b't', // Name
190        ];
191        let nla_buffer = NlaBuffer::new_checked(&mcast_bytes[..])
192            .expect("Failed to create NlaBuffer");
193        let result_attr = GenlCtrlAttrs::parse(&nla_buffer)
194            .expect("Failed to parse encoded McastGroups");
195        let expected_attr = GenlCtrlAttrs::McastGroups(vec![vec![
196            McastGrpAttrs::Id(1),
197            McastGrpAttrs::Name("test".to_string()),
198        ]]);
199        assert_eq!(expected_attr, result_attr);
200    }
201
202    #[test]
203    fn mcast_groups_emit() {
204        let mcast_attr = GenlCtrlAttrs::McastGroups(vec![
205            vec![
206                McastGrpAttrs::Id(7),
207                McastGrpAttrs::Name("group1".to_string()),
208            ],
209            vec![
210                McastGrpAttrs::Id(8),
211                McastGrpAttrs::Name("group2".to_string()),
212            ],
213        ]);
214        let expected_bytes: [u8; 52] = [
215            52, 0, // Netlink header length
216            7, 0, // Netlink header kind (Mcast groups)
217            24, 0, // Mcast group nested NLA length
218            1, 0, // Mcast group kind (index 1)
219            8, 0, // Id length
220            2, 0, // Id kind
221            7, 0, 0, 0, // Id
222            11, 0, // Name length
223            1, 0, // Name kind
224            b'g', b'r', b'o', b'u', b'p', b'1', 0, // Name
225            0, // mcast group padding
226            24, 0, // Mcast group nested NLA length
227            2, 0, // Mcast group kind (index 2)
228            8, 0, // Id length
229            2, 0, // Id kind
230            8, 0, 0, 0, // Id
231            11, 0, // Name length
232            1, 0, // Name kind
233            b'g', b'r', b'o', b'u', b'p', b'2', 0, // Name
234            0, // padding
235        ];
236        let mut buf = vec![0u8; 100];
237        mcast_attr.emit(&mut buf);
238
239        assert_eq!(&expected_bytes[..], &buf[..expected_bytes.len()]);
240    }
241
242    #[test]
243    fn ops_parse() {
244        let ops_bytes: [u8; 24] = [
245            24, 0, // Netlink header length
246            6, 0, // Netlink header kind (Ops)
247            20, 0, // Op nested NLA length
248            0, 0, // Op kind
249            8, 0, // Id length
250            1, 0, // Id kind
251            1, 0, 0, 0, // Id
252            8, 0, // Flags length
253            2, 0, // Flags kind
254            123, 0, 0, 0, // Flags
255        ];
256        let nla_buffer = NlaBuffer::new_checked(&ops_bytes[..])
257            .expect("Failed to create NlaBuffer");
258        let result_attr = GenlCtrlAttrs::parse(&nla_buffer)
259            .expect("Failed to parse encoded McastGroups");
260        let expected_attr =
261            GenlCtrlAttrs::Ops(vec![vec![OpAttrs::Id(1), OpAttrs::Flags(123)]]);
262        assert_eq!(expected_attr, result_attr);
263    }
264
265    #[test]
266    fn ops_emit() {
267        let ops = GenlCtrlAttrs::Ops(vec![
268            vec![OpAttrs::Id(1), OpAttrs::Flags(11)],
269            vec![OpAttrs::Id(3), OpAttrs::Flags(33)],
270        ]);
271        let expected_bytes: [u8; 44] = [
272            44, 0, // Netlink header length
273            6, 0, // Netlink header kind (Ops)
274            20, 0, // Op nested NLA length
275            1, 0, // Op kind
276            8, 0, // Id length
277            1, 0, // Id kind
278            1, 0, 0, 0, // Id
279            8, 0, // Flags length
280            2, 0, // Flags kind
281            11, 0, 0, 0, // Flags
282            20, 0, // Op nested NLA length
283            2, 0, // Op kind
284            8, 0, // Id length
285            1, 0, // Id kind
286            3, 0, 0, 0, // Id
287            8, 0, // Flags length
288            2, 0, // Flags kind
289            33, 0, 0, 0, // Flags
290        ];
291        let mut buf = vec![0u8; 100];
292        ops.emit(&mut buf);
293
294        assert_eq!(&expected_bytes[..], &buf[..expected_bytes.len()]);
295    }
296}