netlink_packet_route/link/link_info/
vlan.rs1use netlink_packet_core::{
4 emit_u16, emit_u16_be, emit_u32, parse_u16, parse_u16_be, parse_u32,
5 DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
6 NlasIterator, Parseable,
7};
8
9use crate::link::VlanProtocol;
10
11const VLAN_FLAG_REORDER_HDR: u32 = 0x1;
12const VLAN_FLAG_GVRP: u32 = 0x2;
13const VLAN_FLAG_LOOSE_BINDING: u32 = 0x4;
14const VLAN_FLAG_MVRP: u32 = 0x8;
15const VLAN_FLAG_BRIDGE_BINDING: u32 = 0x10;
16
17bitflags! {
18 #[non_exhaustive]
19 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20 pub struct VlanFlags: u32 {
21 const ReorderHdr = VLAN_FLAG_REORDER_HDR;
23 const Gvrp = VLAN_FLAG_GVRP;
25 const LooseBinding = VLAN_FLAG_LOOSE_BINDING;
27 const Mvrp = VLAN_FLAG_MVRP;
29 const BridgeBinding = VLAN_FLAG_BRIDGE_BINDING;
32 const _ = !0;
33 }
34}
35
36const IFLA_VLAN_ID: u16 = 1;
37const IFLA_VLAN_FLAGS: u16 = 2;
38const IFLA_VLAN_EGRESS_QOS: u16 = 3;
39const IFLA_VLAN_INGRESS_QOS: u16 = 4;
40const IFLA_VLAN_PROTOCOL: u16 = 5;
41
42const IFLA_VLAN_QOS_MAPPING: u16 = 1;
43
44#[derive(Debug, PartialEq, Eq, Clone)]
45#[non_exhaustive]
46pub enum InfoVlan {
47 Id(u16),
48 Flags((VlanFlags, VlanFlags)),
50 EgressQos(Vec<VlanQosMapping>),
51 IngressQos(Vec<VlanQosMapping>),
52 Protocol(VlanProtocol),
53 Other(DefaultNla),
54}
55
56impl Nla for InfoVlan {
57 fn value_len(&self) -> usize {
58 match self {
59 Self::Id(_) | Self::Protocol(_) => 2,
60 Self::Flags(_) => 8,
61 Self::EgressQos(mappings) | Self::IngressQos(mappings) => {
62 mappings.as_slice().buffer_len()
63 }
64 Self::Other(v) => v.value_len(),
65 }
66 }
67
68 fn emit_value(&self, buffer: &mut [u8]) {
69 match self {
70 Self::EgressQos(ref mappings) | Self::IngressQos(ref mappings) => {
71 mappings.as_slice().emit(buffer)
72 }
73 Self::Id(value) => emit_u16(buffer, *value).unwrap(),
74 Self::Protocol(value) => {
75 emit_u16_be(buffer, (*value).into()).unwrap()
76 }
77 Self::Flags((active, mask)) => {
78 emit_u32(&mut buffer[0..4], active.bits()).unwrap();
79 emit_u32(&mut buffer[4..8], mask.bits()).unwrap()
80 }
81 Self::Other(v) => v.emit_value(buffer),
82 }
83 }
84
85 fn kind(&self) -> u16 {
86 match self {
87 Self::Id(_) => IFLA_VLAN_ID,
88 Self::Flags(_) => IFLA_VLAN_FLAGS,
89 Self::EgressQos(_) => IFLA_VLAN_EGRESS_QOS,
90 Self::IngressQos(_) => IFLA_VLAN_INGRESS_QOS,
91 Self::Protocol(_) => IFLA_VLAN_PROTOCOL,
92 Self::Other(v) => v.kind(),
93 }
94 }
95}
96
97#[derive(Debug, PartialEq, Eq, Clone)]
98#[non_exhaustive]
99pub enum VlanQosMapping {
100 Mapping(u32, u32),
102 Other(DefaultNla),
103}
104
105impl Nla for VlanQosMapping {
106 fn value_len(&self) -> usize {
107 match self {
108 VlanQosMapping::Mapping { .. } => 8,
109 VlanQosMapping::Other(nla) => nla.value_len(),
110 }
111 }
112
113 fn kind(&self) -> u16 {
114 match self {
115 VlanQosMapping::Mapping { .. } => IFLA_VLAN_QOS_MAPPING,
116 VlanQosMapping::Other(nla) => nla.kind(),
117 }
118 }
119
120 fn emit_value(&self, buffer: &mut [u8]) {
121 use VlanQosMapping::*;
122 match self {
123 Mapping(from, to) => {
124 emit_u32(buffer, *from).unwrap();
125 emit_u32(&mut buffer[4..], *to).unwrap();
126 }
127 Other(nla) => nla.emit_value(buffer),
128 }
129 }
130}
131
132impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
133 for VlanQosMapping
134{
135 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
136 use VlanQosMapping::*;
137 let payload = buf.value();
138 Ok(match buf.kind() {
139 IFLA_VLAN_QOS_MAPPING => {
140 if payload.len() != 8 {
141 return Err("invalid IFLA_VLAN_QOS_MAPPING value".into());
142 }
143 Mapping(
144 parse_u32(&payload[..4])
145 .context("expected u32 from value")?,
146 parse_u32(&payload[4..])
147 .context("expected u32 to value")?,
148 )
149 }
150 kind => Other(DefaultNla::parse(buf).context(format!(
151 "unknown NLA type {kind} for VLAN QoS mapping"
152 ))?),
153 })
154 }
155}
156
157fn parse_mappings(payload: &[u8]) -> Result<Vec<VlanQosMapping>, DecodeError> {
158 let mut mappings = Vec::new();
159 for nla in NlasIterator::new(payload) {
160 let nla = nla?;
161 let parsed = VlanQosMapping::parse(&nla)?;
162 mappings.push(parsed);
163 }
164 Ok(mappings)
165}
166
167impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVlan {
168 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
169 use self::InfoVlan::*;
170 let payload = buf.value();
171 Ok(match buf.kind() {
172 IFLA_VLAN_ID => {
173 Id(parse_u16(payload).context("invalid IFLA_VLAN_ID value")?)
174 }
175 IFLA_VLAN_FLAGS => {
176 let err = "invalid IFLA_VLAN_FLAGS value";
177 if payload.len() != 8 {
178 return Err(err.into());
179 }
180 let flags = parse_u32(&payload[0..4]).context(err)?;
181 let mask = parse_u32(&payload[4..]).context(err)?;
182 Flags((
183 VlanFlags::from_bits_retain(flags),
184 VlanFlags::from_bits_retain(mask),
185 ))
186 }
187 IFLA_VLAN_EGRESS_QOS => EgressQos(
188 parse_mappings(payload)
189 .context("failed to parse IFLA_VLAN_EGRESS_QOS")?,
190 ),
191 IFLA_VLAN_INGRESS_QOS => IngressQos(
192 parse_mappings(payload)
193 .context("failed to parse IFLA_VLAN_INGRESS_QOS")?,
194 ),
195 IFLA_VLAN_PROTOCOL => Protocol(
196 parse_u16_be(payload)
197 .context("invalid IFLA_VLAN_PROTOCOL value")?
198 .into(),
199 ),
200 _ => Self::Other(DefaultNla::parse(buf).context(format!(
201 "invalid NLA for {}: {payload:?}",
202 buf.kind()
203 ))?),
204 })
205 }
206}