netlink_packet_route/rtnl/link/nlas/
af_spec_bridge.rs

1// SPDX-License-Identifier: MIT
2
3use std::convert::TryFrom;
4
5use anyhow::Context;
6use netlink_packet_utils::{
7    nla::{self, DefaultNla, NlaBuffer},
8    parsers::parse_u16,
9    traits::Parseable,
10    DecodeError,
11};
12
13use crate::constants::*;
14
15use byteorder::{ByteOrder, NativeEndian};
16
17#[derive(Clone, Eq, PartialEq, Debug)]
18#[non_exhaustive]
19pub enum AfSpecBridge {
20    Flags(u16),
21    VlanInfo(BridgeVlanInfo),
22    Other(DefaultNla),
23}
24
25impl nla::Nla for AfSpecBridge {
26    fn value_len(&self) -> usize {
27        use self::AfSpecBridge::*;
28        match *self {
29            VlanInfo(_) => 4,
30            Flags(_) => 2,
31            Other(ref nla) => nla.value_len(),
32        }
33    }
34
35    fn emit_value(&self, buffer: &mut [u8]) {
36        use self::AfSpecBridge::*;
37        match *self {
38            Flags(value) => NativeEndian::write_u16(buffer, value),
39            VlanInfo(ref info) => {
40                buffer[..4].copy_from_slice(<[u8; 4]>::from(info).as_slice())
41            }
42            Other(ref nla) => nla.emit_value(buffer),
43        }
44    }
45
46    fn kind(&self) -> u16 {
47        use self::AfSpecBridge::*;
48        match *self {
49            Flags(_) => IFLA_BRIDGE_FLAGS,
50            VlanInfo(_) => IFLA_BRIDGE_VLAN_INFO,
51            Other(ref nla) => nla.kind(),
52        }
53    }
54}
55
56impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for AfSpecBridge {
57    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
58        use self::AfSpecBridge::*;
59
60        let payload = buf.value();
61        Ok(match buf.kind() {
62            IFLA_BRIDGE_VLAN_INFO => VlanInfo(
63                BridgeVlanInfo::try_from(payload)
64                    .context("Invalid IFLA_BRIDGE_VLAN_INFO value")?,
65            ),
66            IFLA_BRIDGE_FLAGS => Flags(
67                parse_u16(payload)
68                    .context("invalid IFLA_BRIDGE_FLAGS value")?,
69            ),
70            kind => Other(
71                DefaultNla::parse(buf)
72                    .context(format!("Unknown NLA type {kind}"))?,
73            ),
74        })
75    }
76}
77
78#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
79#[non_exhaustive]
80pub struct BridgeVlanInfo {
81    pub flags: u16,
82    pub vid: u16,
83}
84
85impl From<&BridgeVlanInfo> for [u8; 4] {
86    fn from(d: &BridgeVlanInfo) -> Self {
87        let mut ret = [0u8; 4];
88        NativeEndian::write_u16(&mut ret[0..2], d.flags);
89        NativeEndian::write_u16(&mut ret[2..4], d.vid);
90        ret
91    }
92}
93
94impl TryFrom<&[u8]> for BridgeVlanInfo {
95    type Error = DecodeError;
96    fn try_from(raw: &[u8]) -> Result<Self, DecodeError> {
97        if raw.len() == 4 {
98            Ok(Self {
99                flags: parse_u16(&raw[0..2]).context(format!(
100                    "Invalid IFLA_BRIDGE_VLAN_INFO value: {raw:?}"
101                ))?,
102                vid: parse_u16(&raw[2..4]).context(format!(
103                    "Invalid IFLA_BRIDGE_VLAN_INFO value: {raw:?}"
104                ))?,
105            })
106        } else {
107            Err(DecodeError::from(format!(
108                "Invalid IFLA_BRIDGE_VLAN_INFO value, expecting [u8;4], but got {raw:?}"
109            )))
110        }
111    }
112}