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