netlink_packet_route/link/af_spec/
bridge.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    emit_u16, emit_u32, parse_u16, parse_u32, DecodeError, DefaultNla,
5    Emitable, ErrorContext, Nla, NlaBuffer, NlasIterator, Parseable,
6};
7
8const IFLA_BRIDGE_FLAGS: u16 = 0;
9const IFLA_BRIDGE_MODE: u16 = 1;
10const IFLA_BRIDGE_VLAN_INFO: u16 = 2;
11const IFLA_BRIDGE_VLAN_TUNNEL_INFO: u16 = 3;
12// const IFLA_BRIDGE_MRP: u16 = 4;
13// const IFLA_BRIDGE_CFM: u16 = 5;
14// const IFLA_BRIDGE_MST: u16 = 6;
15
16#[derive(Clone, Eq, PartialEq, Debug)]
17#[non_exhaustive]
18pub enum AfSpecBridge {
19    Flags(BridgeFlag),
20    Mode(BridgeMode),
21    VlanInfo(BridgeVlanInfo),
22    VlanTunnelInfo(Vec<BridgeVlanTunnelInfo>),
23    Other(DefaultNla),
24}
25
26impl Nla for AfSpecBridge {
27    fn value_len(&self) -> usize {
28        match self {
29            Self::Flags(_) => BridgeFlag::LENGTH,
30            Self::Mode(_) => BridgeMode::LENGTH,
31            Self::VlanInfo(_) => BridgeVlanInfo::LENGTH,
32            Self::VlanTunnelInfo(s) => s.as_slice().buffer_len(),
33            Self::Other(nla) => nla.value_len(),
34        }
35    }
36
37    fn emit_value(&self, buffer: &mut [u8]) {
38        match self {
39            Self::Flags(value) => emit_u16(buffer, u16::from(*value)).unwrap(),
40            Self::Mode(value) => emit_u16(buffer, u16::from(*value)).unwrap(),
41            Self::VlanInfo(info) => {
42                buffer[..4].copy_from_slice(<[u8; 4]>::from(info).as_slice())
43            }
44            Self::VlanTunnelInfo(s) => s.as_slice().emit(buffer),
45            Self::Other(nla) => nla.emit_value(buffer),
46        }
47    }
48
49    fn kind(&self) -> u16 {
50        match self {
51            Self::Flags(_) => IFLA_BRIDGE_FLAGS,
52            Self::Mode(_) => IFLA_BRIDGE_MODE,
53            Self::VlanInfo(_) => IFLA_BRIDGE_VLAN_INFO,
54            Self::VlanTunnelInfo(_) => IFLA_BRIDGE_VLAN_TUNNEL_INFO,
55            Self::Other(nla) => nla.kind(),
56        }
57    }
58}
59
60impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for AfSpecBridge {
61    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
62        let payload = buf.value();
63        Ok(match buf.kind() {
64            IFLA_BRIDGE_FLAGS => Self::Flags(
65                parse_u16(payload)
66                    .context("Invalid IFLA_BRIDGE_FLAGS value")?
67                    .into(),
68            ),
69            IFLA_BRIDGE_MODE => Self::Mode(
70                parse_u16(payload)
71                    .context("Invalid IFLA_BRIDGE_MODE value")?
72                    .into(),
73            ),
74            IFLA_BRIDGE_VLAN_INFO => Self::VlanInfo(
75                BridgeVlanInfo::try_from(payload)
76                    .context("Invalid IFLA_BRIDGE_VLAN_INFO value")?,
77            ),
78            IFLA_BRIDGE_VLAN_TUNNEL_INFO => {
79                let mut nlas = Vec::new();
80                for nla in NlasIterator::new(payload) {
81                    let nla = &nla.context(format!(
82                        "Invalid IFLA_BRIDGE_VLAN_TUNNEL_INFO for {payload:?}"
83                    ))?;
84                    let parsed = BridgeVlanTunnelInfo::parse(nla)?;
85                    nlas.push(parsed);
86                }
87                Self::VlanTunnelInfo(nlas)
88            }
89            kind => Self::Other(
90                DefaultNla::parse(buf)
91                    .context(format!("Unknown NLA type {kind}"))?,
92            ),
93        })
94    }
95}
96
97#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "android"))]
98pub(crate) struct VecAfSpecBridge(pub(crate) Vec<AfSpecBridge>);
99
100#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "android"))]
101impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
102    for VecAfSpecBridge
103{
104    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
105        let mut nlas = vec![];
106        let err = "Invalid AF_INET NLA for IFLA_AF_SPEC(AF_BRIDGE)";
107        for nla in NlasIterator::new(buf.into_inner()) {
108            let nla = nla.context(err)?;
109            nlas.push(AfSpecBridge::parse(&nla).context(err)?);
110        }
111        Ok(Self(nlas))
112    }
113}
114
115const BRIDGE_VLAN_INFO_CONTROLLER: u16 = 1 << 0;
116const BRIDGE_VLAN_INFO_PVID: u16 = 1 << 1;
117const BRIDGE_VLAN_INFO_UNTAGGED: u16 = 1 << 2;
118const BRIDGE_VLAN_INFO_RANGE_BEGIN: u16 = 1 << 3;
119const BRIDGE_VLAN_INFO_RANGE_END: u16 = 1 << 4;
120const BRIDGE_VLAN_INFO_BRENTRY: u16 = 1 << 5;
121const BRIDGE_VLAN_INFO_ONLY_OPTS: u16 = 1 << 6;
122
123bitflags! {
124    #[non_exhaustive]
125    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126    pub struct BridgeVlanInfoFlags: u16 {
127        /// Operate on Bridge device as well
128        const Controller = BRIDGE_VLAN_INFO_CONTROLLER;
129        /// VLAN is PVID, ingress untagged
130        const Pvid = BRIDGE_VLAN_INFO_PVID;
131        /// VLAN egresses untagged
132        const Untagged= BRIDGE_VLAN_INFO_UNTAGGED;
133        /// VLAN is start of vlan range
134        const RangeBegin = BRIDGE_VLAN_INFO_RANGE_BEGIN;
135        /// VLAN is end of vlan range
136        const RangeEnd = BRIDGE_VLAN_INFO_RANGE_END;
137        /// Global bridge VLAN entry
138        const Brentry = BRIDGE_VLAN_INFO_BRENTRY;
139        /// Skip create/delete/flags
140        const OnlyOpts= BRIDGE_VLAN_INFO_ONLY_OPTS;
141        const _ = !0;
142    }
143}
144
145impl BridgeVlanInfoFlags {
146    pub const LENGTH: usize = 2;
147}
148
149#[derive(Debug, PartialEq, Eq, Clone, Copy)]
150pub struct BridgeVlanInfo {
151    pub flags: BridgeVlanInfoFlags,
152    pub vid: u16,
153}
154
155impl BridgeVlanInfo {
156    pub const LENGTH: usize = 4;
157}
158
159impl From<&BridgeVlanInfo> for [u8; 4] {
160    fn from(d: &BridgeVlanInfo) -> Self {
161        let mut ret = [0u8; 4];
162        emit_u16(&mut ret[0..2], d.flags.bits()).unwrap();
163        emit_u16(&mut ret[2..4], d.vid).unwrap();
164        ret
165    }
166}
167
168impl TryFrom<&[u8]> for BridgeVlanInfo {
169    type Error = DecodeError;
170    fn try_from(raw: &[u8]) -> Result<Self, DecodeError> {
171        if raw.len() == 4 {
172            Ok(Self {
173                flags: BridgeVlanInfoFlags::from_bits_retain(
174                    parse_u16(&raw[0..2]).context(format!(
175                        "Invalid IFLA_BRIDGE_VLAN_INFO value: {raw:?}"
176                    ))?,
177                ),
178                vid: parse_u16(&raw[2..4]).context(format!(
179                    "Invalid IFLA_BRIDGE_VLAN_INFO value: {raw:?}"
180                ))?,
181            })
182        } else {
183            Err(DecodeError::from(format!(
184                "Invalid IFLA_BRIDGE_VLAN_INFO value, expecting [u8;4], but \
185                 got {raw:?}"
186            )))
187        }
188    }
189}
190
191// kernel constant name is BRIDGE_FLAGS_MASTER
192const BRIDGE_FLAGS_CONTROLLER: u16 = 1;
193const BRIDGE_FLAGS_SELF: u16 = 2;
194
195#[derive(Clone, Copy, Eq, PartialEq, Debug)]
196#[non_exhaustive]
197pub enum BridgeFlag {
198    /// Bridge command to/from controller
199    Controller,
200    /// Bridge command to/from lowerdev
201    LowerDev,
202    Other(u16),
203}
204
205impl From<u16> for BridgeFlag {
206    fn from(d: u16) -> Self {
207        match d {
208            BRIDGE_FLAGS_CONTROLLER => Self::Controller,
209            BRIDGE_FLAGS_SELF => Self::LowerDev,
210            _ => Self::Other(d),
211        }
212    }
213}
214
215impl From<BridgeFlag> for u16 {
216    fn from(v: BridgeFlag) -> u16 {
217        match v {
218            BridgeFlag::Controller => BRIDGE_FLAGS_CONTROLLER,
219            BridgeFlag::LowerDev => BRIDGE_FLAGS_SELF,
220            BridgeFlag::Other(d) => d,
221        }
222    }
223}
224
225impl BridgeFlag {
226    pub const LENGTH: usize = 2;
227}
228
229const BRIDGE_MODE_VEB: u16 = 0;
230const BRIDGE_MODE_VEPA: u16 = 1;
231
232#[derive(Clone, Copy, Eq, PartialEq, Debug)]
233#[non_exhaustive]
234pub enum BridgeMode {
235    /// Default loopback mode
236    Veb,
237    /// 802.1Qbg defined VEPA mode
238    Vepa,
239    Other(u16),
240}
241
242impl From<u16> for BridgeMode {
243    fn from(d: u16) -> Self {
244        match d {
245            BRIDGE_MODE_VEB => Self::Veb,
246            BRIDGE_MODE_VEPA => Self::Vepa,
247            _ => Self::Other(d),
248        }
249    }
250}
251
252impl From<BridgeMode> for u16 {
253    fn from(v: BridgeMode) -> u16 {
254        match v {
255            BridgeMode::Veb => BRIDGE_MODE_VEB,
256            BridgeMode::Vepa => BRIDGE_MODE_VEPA,
257            BridgeMode::Other(d) => d,
258        }
259    }
260}
261
262impl BridgeMode {
263    pub const LENGTH: usize = 2;
264}
265
266const IFLA_BRIDGE_VLAN_TUNNEL_ID: u16 = 1;
267const IFLA_BRIDGE_VLAN_TUNNEL_VID: u16 = 2;
268const IFLA_BRIDGE_VLAN_TUNNEL_FLAGS: u16 = 3;
269
270#[derive(Clone, Eq, PartialEq, Debug)]
271#[non_exhaustive]
272pub enum BridgeVlanTunnelInfo {
273    Id(u32),
274    Vid(u16),
275    Flags(BridgeVlanInfoFlags),
276    Other(DefaultNla),
277}
278
279impl Nla for BridgeVlanTunnelInfo {
280    fn value_len(&self) -> usize {
281        match self {
282            Self::Id(_) => 4,
283            Self::Vid(_) => 2,
284            Self::Flags(_) => BridgeVlanInfoFlags::LENGTH,
285            Self::Other(nla) => nla.value_len(),
286        }
287    }
288
289    fn emit_value(&self, buffer: &mut [u8]) {
290        match self {
291            Self::Id(v) => emit_u32(buffer, *v).unwrap(),
292            Self::Vid(v) => emit_u16(buffer, *v).unwrap(),
293            Self::Flags(value) => emit_u16(buffer, value.bits()).unwrap(),
294            Self::Other(nla) => nla.emit_value(buffer),
295        }
296    }
297
298    fn kind(&self) -> u16 {
299        match self {
300            Self::Id(_) => IFLA_BRIDGE_VLAN_TUNNEL_ID,
301            Self::Vid(_) => IFLA_BRIDGE_VLAN_TUNNEL_VID,
302            Self::Flags(_) => IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
303            Self::Other(nla) => nla.kind(),
304        }
305    }
306}
307
308impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
309    for BridgeVlanTunnelInfo
310{
311    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
312        let payload = buf.value();
313        Ok(match buf.kind() {
314            IFLA_BRIDGE_VLAN_TUNNEL_ID => {
315                Self::Id(parse_u32(payload).context(format!(
316                    "Invalid IFLA_BRIDGE_VLAN_TUNNEL_ID {payload:?}"
317                ))?)
318            }
319            IFLA_BRIDGE_VLAN_TUNNEL_VID => {
320                Self::Vid(parse_u16(payload).context(format!(
321                    "Invalid IFLA_BRIDGE_VLAN_TUNNEL_VID {payload:?}"
322                ))?)
323            }
324            IFLA_BRIDGE_VLAN_TUNNEL_FLAGS => {
325                Self::Flags(BridgeVlanInfoFlags::from_bits_retain(
326                    parse_u16(payload).context(format!(
327                        "Invalid IFLA_BRIDGE_VLAN_TUNNEL_VID {payload:?}"
328                    ))?,
329                ))
330            }
331            _ => {
332                Self::Other(DefaultNla::parse(buf).context("Unknown NLA type")?)
333            }
334        })
335    }
336}