netlink_packet_route/link/af_spec/
bridge.rs
1use 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}