netlink_packet_route/link/af_spec/
bridge.rs

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