netlink_packet_route/rtnl/link/nlas/
af_spec_bridge.rs

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