netlink_packet_route/link/link_info/
vlan.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use byteorder::{BigEndian, ByteOrder, NativeEndian};
5use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
6use netlink_packet_utils::parsers::{parse_u16, parse_u16_be, parse_u32};
7use netlink_packet_utils::traits::{Emitable, Parseable};
8use netlink_packet_utils::DecodeError;
9
10use crate::link::VlanProtocol;
11
12const IFLA_VLAN_ID: u16 = 1;
13const IFLA_VLAN_FLAGS: u16 = 2;
14const IFLA_VLAN_EGRESS_QOS: u16 = 3;
15const IFLA_VLAN_INGRESS_QOS: u16 = 4;
16const IFLA_VLAN_PROTOCOL: u16 = 5;
17
18const IFLA_VLAN_QOS_MAPPING: u16 = 1;
19
20#[derive(Debug, PartialEq, Eq, Clone)]
21#[non_exhaustive]
22pub enum InfoVlan {
23    Id(u16),
24    Flags((u32, u32)),
25    EgressQos(Vec<VlanQosMapping>),
26    IngressQos(Vec<VlanQosMapping>),
27    Protocol(VlanProtocol),
28    Other(DefaultNla),
29}
30
31impl Nla for InfoVlan {
32    fn value_len(&self) -> usize {
33        match self {
34            Self::Id(_) | Self::Protocol(_) => 2,
35            Self::Flags(_) => 8,
36            Self::EgressQos(mappings) | Self::IngressQos(mappings) => {
37                mappings.as_slice().buffer_len()
38            }
39            Self::Other(v) => v.value_len(),
40        }
41    }
42
43    fn emit_value(&self, buffer: &mut [u8]) {
44        match self {
45            Self::EgressQos(ref mappings) | Self::IngressQos(ref mappings) => {
46                mappings.as_slice().emit(buffer)
47            }
48            Self::Id(value) => NativeEndian::write_u16(buffer, *value),
49            Self::Protocol(value) => BigEndian::write_u16(buffer, (*value).into()),
50            Self::Flags(flags) => {
51                NativeEndian::write_u32(&mut buffer[0..4], flags.0);
52                NativeEndian::write_u32(&mut buffer[4..8], flags.1)
53            }
54            Self::Other(v) => v.emit_value(buffer),
55        }
56    }
57
58    fn kind(&self) -> u16 {
59        match self {
60            Self::Id(_) => IFLA_VLAN_ID,
61            Self::Flags(_) => IFLA_VLAN_FLAGS,
62            Self::EgressQos(_) => IFLA_VLAN_EGRESS_QOS,
63            Self::IngressQos(_) => IFLA_VLAN_INGRESS_QOS,
64            Self::Protocol(_) => IFLA_VLAN_PROTOCOL,
65            Self::Other(v) => v.kind(),
66        }
67    }
68}
69
70#[derive(Debug, PartialEq, Eq, Clone)]
71#[non_exhaustive]
72pub enum VlanQosMapping {
73    /// Tuple (from, to)
74    Mapping(u32, u32),
75    Other(DefaultNla),
76}
77
78impl Nla for VlanQosMapping {
79    fn value_len(&self) -> usize {
80        match self {
81            VlanQosMapping::Mapping { .. } => 8,
82            VlanQosMapping::Other(nla) => nla.value_len(),
83        }
84    }
85
86    fn kind(&self) -> u16 {
87        match self {
88            VlanQosMapping::Mapping { .. } => IFLA_VLAN_QOS_MAPPING,
89            VlanQosMapping::Other(nla) => nla.kind(),
90        }
91    }
92
93    fn emit_value(&self, buffer: &mut [u8]) {
94        use VlanQosMapping::*;
95        match self {
96            Mapping(from, to) => {
97                NativeEndian::write_u32(buffer, *from);
98                NativeEndian::write_u32(&mut buffer[4..], *to);
99            }
100            Other(nla) => nla.emit_value(buffer),
101        }
102    }
103}
104
105impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VlanQosMapping {
106    type Error = DecodeError;
107    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
108        use VlanQosMapping::*;
109        let payload = buf.value();
110        Ok(match buf.kind() {
111            IFLA_VLAN_QOS_MAPPING => {
112                if payload.len() != 8 {
113                    return Err("invalid IFLA_VLAN_QOS_MAPPING value".into());
114                }
115                Mapping(
116                    parse_u32(&payload[..4]).context("expected u32 from value")?,
117                    parse_u32(&payload[4..]).context("expected u32 to value")?,
118                )
119            }
120            kind => Other(
121                DefaultNla::parse(buf)
122                    .context(format!("unknown NLA type {kind} for VLAN QoS mapping"))?,
123            ),
124        })
125    }
126}
127
128fn parse_mappings(payload: &[u8]) -> Result<Vec<VlanQosMapping>, DecodeError> {
129    let mut mappings = Vec::new();
130    for nla in NlasIterator::new(payload) {
131        let nla = nla?;
132        let parsed = VlanQosMapping::parse(&nla)?;
133        mappings.push(parsed);
134    }
135    Ok(mappings)
136}
137
138impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVlan {
139    type Error = DecodeError;
140    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
141        use self::InfoVlan::*;
142        let payload = buf.value();
143        Ok(match buf.kind() {
144            IFLA_VLAN_ID => Id(parse_u16(payload).context("invalid IFLA_VLAN_ID value")?),
145            IFLA_VLAN_FLAGS => {
146                let err = "invalid IFLA_VLAN_FLAGS value";
147                if payload.len() != 8 {
148                    return Err(err.into());
149                }
150                let flags = parse_u32(&payload[0..4]).context(err)?;
151                let mask = parse_u32(&payload[4..]).context(err)?;
152                Flags((flags, mask))
153            }
154            IFLA_VLAN_EGRESS_QOS => {
155                EgressQos(parse_mappings(payload).context("failed to parse IFLA_VLAN_EGRESS_QOS")?)
156            }
157            IFLA_VLAN_INGRESS_QOS => IngressQos(
158                parse_mappings(payload).context("failed to parse IFLA_VLAN_INGRESS_QOS")?,
159            ),
160            IFLA_VLAN_PROTOCOL => {
161                Protocol(parse_u16_be(payload).context("invalid IFLA_VLAN_PROTOCOL value")?.into())
162            }
163            _ => Self::Other(
164                DefaultNla::parse(buf)
165                    .context(format!("invalid NLA for {}: {payload:?}", buf.kind()))?,
166            ),
167        })
168    }
169}