1use crate::link::{BridgeId, BridgeIdBuffer};
3use anyhow::Context;
4use byteorder::{ByteOrder, NativeEndian};
5use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer};
6use netlink_packet_utils::parsers::{parse_u16, parse_u32, parse_u64, parse_u8};
7use netlink_packet_utils::traits::{Emitable, Parseable};
8use netlink_packet_utils::DecodeError;
9
10const IFLA_BRPORT_STATE: u16 = 1;
11const IFLA_BRPORT_PRIORITY: u16 = 2;
12const IFLA_BRPORT_COST: u16 = 3;
13const IFLA_BRPORT_MODE: u16 = 4;
14const IFLA_BRPORT_GUARD: u16 = 5;
15const IFLA_BRPORT_PROTECT: u16 = 6;
16const IFLA_BRPORT_FAST_LEAVE: u16 = 7;
17const IFLA_BRPORT_LEARNING: u16 = 8;
18const IFLA_BRPORT_UNICAST_FLOOD: u16 = 9;
19const IFLA_BRPORT_PROXYARP: u16 = 10;
20const IFLA_BRPORT_PROXYARP_WIFI: u16 = 12;
23const IFLA_BRPORT_ROOT_ID: u16 = 13;
24const IFLA_BRPORT_BRIDGE_ID: u16 = 14;
25const IFLA_BRPORT_DESIGNATED_PORT: u16 = 15;
26const IFLA_BRPORT_DESIGNATED_COST: u16 = 16;
27const IFLA_BRPORT_ID: u16 = 17;
28const IFLA_BRPORT_NO: u16 = 18;
29const IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: u16 = 19;
30const IFLA_BRPORT_CONFIG_PENDING: u16 = 20;
31const IFLA_BRPORT_MESSAGE_AGE_TIMER: u16 = 21;
32const IFLA_BRPORT_FORWARD_DELAY_TIMER: u16 = 22;
33const IFLA_BRPORT_HOLD_TIMER: u16 = 23;
34const IFLA_BRPORT_FLUSH: u16 = 24;
35const IFLA_BRPORT_MULTICAST_ROUTER: u16 = 25;
36const IFLA_BRPORT_MCAST_FLOOD: u16 = 27;
38const IFLA_BRPORT_MCAST_TO_UCAST: u16 = 28;
39const IFLA_BRPORT_VLAN_TUNNEL: u16 = 29;
40const IFLA_BRPORT_BCAST_FLOOD: u16 = 30;
41const IFLA_BRPORT_GROUP_FWD_MASK: u16 = 31;
42const IFLA_BRPORT_NEIGH_SUPPRESS: u16 = 32;
43const IFLA_BRPORT_ISOLATED: u16 = 33;
44const IFLA_BRPORT_BACKUP_PORT: u16 = 34;
45const IFLA_BRPORT_MRP_RING_OPEN: u16 = 35;
46const IFLA_BRPORT_MRP_IN_OPEN: u16 = 36;
47const IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT: u16 = 37;
48const IFLA_BRPORT_MCAST_EHT_HOSTS_CNT: u16 = 38;
49const IFLA_BRPORT_LOCKED: u16 = 39;
50const IFLA_BRPORT_MAB: u16 = 40;
51const IFLA_BRPORT_MCAST_N_GROUPS: u16 = 41;
52const IFLA_BRPORT_MCAST_MAX_GROUPS: u16 = 42;
53const IFLA_BRPORT_NEIGH_VLAN_SUPPRESS: u16 = 43;
54const IFLA_BRPORT_BACKUP_NHID: u16 = 44;
55
56#[derive(Debug, PartialEq, Eq, Clone)]
57#[non_exhaustive]
58pub enum InfoBridgePort {
59 State(BridgePortState),
60 Priority(u16),
61 Cost(u32),
62 HairpinMode(bool),
63 Guard(bool),
64 Protect(bool),
65 FastLeave(bool),
66 Learning(bool),
67 UnicastFlood(bool),
68 ProxyARP(bool),
69 ProxyARPWifi(bool),
70 RootId(BridgeId),
71 BridgeId(BridgeId),
72 DesignatedPort(u16),
73 DesignatedCost(u16),
74 PortId(u16),
75 PortNumber(u16),
76 TopologyChangeAck(bool),
77 ConfigPending(bool),
78 MessageAgeTimer(u64),
79 ForwardDelayTimer(u64),
80 HoldTimer(u64),
81 Flush,
82 MulticastRouter(BridgePortMulticastRouter),
83 MulticastFlood(bool),
84 MulticastToUnicast(bool),
85 VlanTunnel(bool),
86 BroadcastFlood(bool),
87 GroupFwdMask(u16),
88 NeighSupress(bool),
89 Isolated(bool),
90 BackupPort(u32),
91 MrpRingOpen(bool),
92 MrpInOpen(bool),
93 MulticastEhtHostsLimit(u32),
94 MulticastEhtHostsCnt(u32),
95 Locked(bool),
96 Mab(bool),
97 MulticastNGroups(u32),
98 MulticastMaxGroups(u32),
99 NeighVlanSupress(bool),
100 BackupNextHopId(u32),
101 Other(DefaultNla),
102}
103
104impl Nla for InfoBridgePort {
105 fn value_len(&self) -> usize {
106 match self {
107 InfoBridgePort::Flush => 0,
108 InfoBridgePort::State(_)
109 | InfoBridgePort::HairpinMode(_)
110 | InfoBridgePort::Guard(_)
111 | InfoBridgePort::Protect(_)
112 | InfoBridgePort::FastLeave(_)
113 | InfoBridgePort::Learning(_)
114 | InfoBridgePort::UnicastFlood(_)
115 | InfoBridgePort::ProxyARP(_)
116 | InfoBridgePort::ProxyARPWifi(_)
117 | InfoBridgePort::TopologyChangeAck(_)
118 | InfoBridgePort::ConfigPending(_)
119 | InfoBridgePort::MulticastRouter(_)
120 | InfoBridgePort::MulticastFlood(_)
121 | InfoBridgePort::MulticastToUnicast(_)
122 | InfoBridgePort::VlanTunnel(_)
123 | InfoBridgePort::BroadcastFlood(_)
124 | InfoBridgePort::NeighSupress(_)
125 | InfoBridgePort::Isolated(_)
126 | InfoBridgePort::MrpRingOpen(_)
127 | InfoBridgePort::MrpInOpen(_)
128 | InfoBridgePort::Locked(_)
129 | InfoBridgePort::Mab(_)
130 | InfoBridgePort::NeighVlanSupress(_) => 1,
131 InfoBridgePort::Priority(_)
132 | InfoBridgePort::DesignatedPort(_)
133 | InfoBridgePort::DesignatedCost(_)
134 | InfoBridgePort::PortId(_)
135 | InfoBridgePort::PortNumber(_)
136 | InfoBridgePort::GroupFwdMask(_) => 2,
137 InfoBridgePort::Cost(_)
138 | InfoBridgePort::BackupPort(_)
139 | InfoBridgePort::MulticastEhtHostsLimit(_)
140 | InfoBridgePort::MulticastEhtHostsCnt(_)
141 | InfoBridgePort::MulticastNGroups(_)
142 | InfoBridgePort::MulticastMaxGroups(_)
143 | InfoBridgePort::BackupNextHopId(_) => 4,
144 InfoBridgePort::RootId(_)
145 | InfoBridgePort::BridgeId(_)
146 | InfoBridgePort::MessageAgeTimer(_)
147 | InfoBridgePort::ForwardDelayTimer(_)
148 | InfoBridgePort::HoldTimer(_) => 8,
149 InfoBridgePort::Other(nla) => nla.value_len(),
150 }
151 }
152
153 fn emit_value(&self, buffer: &mut [u8]) {
154 match self {
155 InfoBridgePort::Flush => (),
156 InfoBridgePort::HairpinMode(value)
157 | InfoBridgePort::Guard(value)
158 | InfoBridgePort::Protect(value)
159 | InfoBridgePort::FastLeave(value)
160 | InfoBridgePort::Learning(value)
161 | InfoBridgePort::UnicastFlood(value)
162 | InfoBridgePort::ProxyARP(value)
163 | InfoBridgePort::TopologyChangeAck(value)
164 | InfoBridgePort::ConfigPending(value)
165 | InfoBridgePort::ProxyARPWifi(value)
166 | InfoBridgePort::MulticastFlood(value)
167 | InfoBridgePort::MulticastToUnicast(value)
168 | InfoBridgePort::VlanTunnel(value)
169 | InfoBridgePort::BroadcastFlood(value)
170 | InfoBridgePort::NeighSupress(value)
171 | InfoBridgePort::Isolated(value)
172 | InfoBridgePort::MrpRingOpen(value)
173 | InfoBridgePort::MrpInOpen(value)
174 | InfoBridgePort::Locked(value)
175 | InfoBridgePort::Mab(value)
176 | InfoBridgePort::NeighVlanSupress(value) => buffer[0] = if *value { 1 } else { 0 },
177 InfoBridgePort::Priority(value)
178 | InfoBridgePort::DesignatedPort(value)
179 | InfoBridgePort::DesignatedCost(value)
180 | InfoBridgePort::PortId(value)
181 | InfoBridgePort::PortNumber(value)
182 | InfoBridgePort::GroupFwdMask(value) => NativeEndian::write_u16(buffer, *value),
183 InfoBridgePort::Cost(value)
184 | InfoBridgePort::BackupPort(value)
185 | InfoBridgePort::MulticastEhtHostsLimit(value)
186 | InfoBridgePort::MulticastEhtHostsCnt(value)
187 | InfoBridgePort::MulticastNGroups(value)
188 | InfoBridgePort::MulticastMaxGroups(value)
189 | InfoBridgePort::BackupNextHopId(value) => NativeEndian::write_u32(buffer, *value),
190 InfoBridgePort::MessageAgeTimer(value)
191 | InfoBridgePort::ForwardDelayTimer(value)
192 | InfoBridgePort::HoldTimer(value) => NativeEndian::write_u64(buffer, *value),
193 InfoBridgePort::RootId(bridge_id) | InfoBridgePort::BridgeId(bridge_id) => {
194 bridge_id.emit(buffer)
195 }
196 InfoBridgePort::State(state) => buffer[0] = (*state).into(),
197 InfoBridgePort::MulticastRouter(mcast_router) => buffer[0] = (*mcast_router).into(),
198 InfoBridgePort::Other(nla) => nla.emit_value(buffer),
199 }
200 }
201
202 fn kind(&self) -> u16 {
203 match self {
204 InfoBridgePort::State(_) => IFLA_BRPORT_STATE,
205 InfoBridgePort::Priority(_) => IFLA_BRPORT_PRIORITY,
206 InfoBridgePort::Cost(_) => IFLA_BRPORT_COST,
207 InfoBridgePort::HairpinMode(_) => IFLA_BRPORT_MODE,
208 InfoBridgePort::Guard(_) => IFLA_BRPORT_GUARD,
209 InfoBridgePort::Protect(_) => IFLA_BRPORT_PROTECT,
210 InfoBridgePort::FastLeave(_) => IFLA_BRPORT_FAST_LEAVE,
211 InfoBridgePort::Learning(_) => IFLA_BRPORT_LEARNING,
212 InfoBridgePort::UnicastFlood(_) => IFLA_BRPORT_UNICAST_FLOOD,
213 InfoBridgePort::ProxyARP(_) => IFLA_BRPORT_PROXYARP,
214 InfoBridgePort::ProxyARPWifi(_) => IFLA_BRPORT_PROXYARP_WIFI,
215 InfoBridgePort::RootId(_) => IFLA_BRPORT_ROOT_ID,
216 InfoBridgePort::BridgeId(_) => IFLA_BRPORT_BRIDGE_ID,
217 InfoBridgePort::DesignatedPort(_) => IFLA_BRPORT_DESIGNATED_PORT,
218 InfoBridgePort::DesignatedCost(_) => IFLA_BRPORT_DESIGNATED_COST,
219 InfoBridgePort::PortId(_) => IFLA_BRPORT_ID,
220 InfoBridgePort::PortNumber(_) => IFLA_BRPORT_NO,
221 InfoBridgePort::TopologyChangeAck(_) => IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
222 InfoBridgePort::ConfigPending(_) => IFLA_BRPORT_CONFIG_PENDING,
223 InfoBridgePort::MessageAgeTimer(_) => IFLA_BRPORT_MESSAGE_AGE_TIMER,
224 InfoBridgePort::ForwardDelayTimer(_) => IFLA_BRPORT_FORWARD_DELAY_TIMER,
225 InfoBridgePort::HoldTimer(_) => IFLA_BRPORT_HOLD_TIMER,
226 InfoBridgePort::Flush => IFLA_BRPORT_FLUSH,
227 InfoBridgePort::MulticastRouter(_) => IFLA_BRPORT_MULTICAST_ROUTER,
228 InfoBridgePort::MulticastFlood(_) => IFLA_BRPORT_MCAST_FLOOD,
229 InfoBridgePort::MulticastToUnicast(_) => IFLA_BRPORT_MCAST_TO_UCAST,
230 InfoBridgePort::VlanTunnel(_) => IFLA_BRPORT_VLAN_TUNNEL,
231 InfoBridgePort::BroadcastFlood(_) => IFLA_BRPORT_BCAST_FLOOD,
232 InfoBridgePort::GroupFwdMask(_) => IFLA_BRPORT_GROUP_FWD_MASK,
233 InfoBridgePort::NeighSupress(_) => IFLA_BRPORT_NEIGH_SUPPRESS,
234 InfoBridgePort::Isolated(_) => IFLA_BRPORT_ISOLATED,
235 InfoBridgePort::BackupPort(_) => IFLA_BRPORT_BACKUP_PORT,
236 InfoBridgePort::MrpRingOpen(_) => IFLA_BRPORT_MRP_RING_OPEN,
237 InfoBridgePort::MrpInOpen(_) => IFLA_BRPORT_MRP_IN_OPEN,
238 InfoBridgePort::MulticastEhtHostsLimit(_) => IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT,
239 InfoBridgePort::MulticastEhtHostsCnt(_) => IFLA_BRPORT_MCAST_EHT_HOSTS_CNT,
240 InfoBridgePort::Locked(_) => IFLA_BRPORT_LOCKED,
241 InfoBridgePort::Mab(_) => IFLA_BRPORT_MAB,
242 InfoBridgePort::MulticastNGroups(_) => IFLA_BRPORT_MCAST_N_GROUPS,
243 InfoBridgePort::MulticastMaxGroups(_) => IFLA_BRPORT_MCAST_MAX_GROUPS,
244 InfoBridgePort::NeighVlanSupress(_) => IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
245 InfoBridgePort::BackupNextHopId(_) => IFLA_BRPORT_BACKUP_NHID,
246 InfoBridgePort::Other(nla) => nla.kind(),
247 }
248 }
249}
250
251impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBridgePort {
252 type Error = DecodeError;
253 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
254 let payload = buf.value();
255
256 Ok(match buf.kind() {
257 IFLA_BRPORT_STATE => InfoBridgePort::State(
258 parse_u8(payload)
259 .with_context(|| format!("invalid IFLA_BRPORT_STATE {payload:?}"))?
260 .into(),
261 ),
262 IFLA_BRPORT_PRIORITY => InfoBridgePort::Priority(
263 parse_u16(payload)
264 .with_context(|| format!("invalid IFLA_BRPORT_PRIORITY {payload:?}"))?,
265 ),
266 IFLA_BRPORT_COST => InfoBridgePort::Cost(
267 parse_u32(payload)
268 .with_context(|| format!("invalid IFLA_BRPORT_COST {payload:?}"))?,
269 ),
270 IFLA_BRPORT_MODE => InfoBridgePort::HairpinMode(
271 parse_u8(payload)
272 .with_context(|| format!("invalid IFLA_BRPORT_MODE {payload:?}"))?
273 > 0,
274 ),
275 IFLA_BRPORT_GUARD => InfoBridgePort::Guard(
276 parse_u8(payload)
277 .with_context(|| format!("invalid IFLA_BRPORT_GUARD {payload:?}"))?
278 > 0,
279 ),
280 IFLA_BRPORT_PROTECT => InfoBridgePort::Protect(
281 parse_u8(payload)
282 .with_context(|| format!("invalid IFLA_BRPORT_PROTECT {payload:?}"))?
283 > 0,
284 ),
285 IFLA_BRPORT_FAST_LEAVE => InfoBridgePort::FastLeave(
286 parse_u8(payload)
287 .with_context(|| format!("invalid IFLA_BRPORT_FAST_LEAVE {payload:?}"))?
288 > 0,
289 ),
290 IFLA_BRPORT_LEARNING => InfoBridgePort::Learning(
291 parse_u8(payload)
292 .with_context(|| format!("invalid IFLA_BRPORT_LEARNING {payload:?}"))?
293 > 0,
294 ),
295 IFLA_BRPORT_UNICAST_FLOOD => InfoBridgePort::UnicastFlood(
296 parse_u8(payload)
297 .with_context(|| format!("invalid IFLA_BRPORT_UNICAST_FLOOD {payload:?}"))?
298 > 0,
299 ),
300 IFLA_BRPORT_PROXYARP => InfoBridgePort::ProxyARP(
301 parse_u8(payload)
302 .with_context(|| format!("invalid IFLA_BRPORT_PROXYARP {payload:?}"))?
303 > 0,
304 ),
305 IFLA_BRPORT_PROXYARP_WIFI => InfoBridgePort::ProxyARPWifi(
306 parse_u8(payload)
307 .with_context(|| format!("invalid IFLA_BRPORT_PROXYARP_WIFI {payload:?}"))?
308 > 0,
309 ),
310 IFLA_BRPORT_ROOT_ID => Self::RootId(
311 BridgeId::parse(&BridgeIdBuffer::new(payload))
312 .with_context(|| format!("invalid IFLA_BRPORT_ROOT_ID {payload:?}"))?,
313 ),
314 IFLA_BRPORT_BRIDGE_ID => Self::BridgeId(
315 BridgeId::parse(&BridgeIdBuffer::new(payload))
316 .with_context(|| format!("invalid IFLA_BRPORT_BRIDGE_ID {payload:?}"))?,
317 ),
318 IFLA_BRPORT_DESIGNATED_PORT => InfoBridgePort::DesignatedPort(
319 parse_u16(payload)
320 .with_context(|| format!("invalid IFLA_BRPORT_DESIGNATED_PORT {payload:?}"))?,
321 ),
322 IFLA_BRPORT_DESIGNATED_COST => InfoBridgePort::DesignatedCost(
323 parse_u16(payload)
324 .with_context(|| format!("invalid IFLA_BRPORT_DESIGNATED_COST {payload:?}"))?,
325 ),
326 IFLA_BRPORT_ID => InfoBridgePort::PortId(
327 parse_u16(payload)
328 .with_context(|| format!("invalid IFLA_BRPORT_ID {payload:?}"))?,
329 ),
330 IFLA_BRPORT_NO => InfoBridgePort::PortNumber(
331 parse_u16(payload)
332 .with_context(|| format!("invalid IFLA_BRPORT_NO {payload:?}"))?,
333 ),
334 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK => InfoBridgePort::TopologyChangeAck(
335 parse_u8(payload).with_context(|| {
336 format!("invalid IFLA_BRPORT_TOPOLOGY_CHANGE_ACK {payload:?}")
337 })? > 0,
338 ),
339 IFLA_BRPORT_CONFIG_PENDING => InfoBridgePort::ConfigPending(
340 parse_u8(payload)
341 .with_context(|| format!("invalid IFLA_BRPORT_CONFIG_PENDING {payload:?}"))?
342 > 0,
343 ),
344 IFLA_BRPORT_MESSAGE_AGE_TIMER => {
345 InfoBridgePort::MessageAgeTimer(parse_u64(payload).with_context(|| {
346 format!("invalid IFLA_BRPORT_MESSAGE_AGE_TIMER {payload:?}")
347 })?)
348 }
349 IFLA_BRPORT_FORWARD_DELAY_TIMER => {
350 InfoBridgePort::ForwardDelayTimer(parse_u64(payload).with_context(|| {
351 format!("invalid IFLA_BRPORT_FORWARD_DELAY_TIMER {payload:?}")
352 })?)
353 }
354 IFLA_BRPORT_HOLD_TIMER => InfoBridgePort::HoldTimer(
355 parse_u64(payload)
356 .with_context(|| format!("invalid IFLA_BRPORT_HOLD_TIMER {payload:?}"))?,
357 ),
358 IFLA_BRPORT_FLUSH => InfoBridgePort::Flush,
359 IFLA_BRPORT_MULTICAST_ROUTER => InfoBridgePort::MulticastRouter(
360 parse_u8(payload)
361 .with_context(|| format!("invalid IFLA_BRPORT_MULTICAST_ROUTER {payload:?}"))?
362 .into(),
363 ),
364 IFLA_BRPORT_MCAST_FLOOD => InfoBridgePort::MulticastFlood(
365 parse_u8(payload)
366 .with_context(|| format!("invalid IFLA_BRPORT_MCAST_FLOOD {payload:?}"))?
367 > 0,
368 ),
369 IFLA_BRPORT_MCAST_TO_UCAST => InfoBridgePort::MulticastToUnicast(
370 parse_u8(payload)
371 .with_context(|| format!("invalid IFLA_BRPORT_MCAST_TO_UCAST {payload:?}"))?
372 > 0,
373 ),
374 IFLA_BRPORT_VLAN_TUNNEL => InfoBridgePort::VlanTunnel(
375 parse_u8(payload)
376 .with_context(|| format!("invalid IFLA_BRPORT_VLAN_TUNNEL {payload:?}"))?
377 > 0,
378 ),
379 IFLA_BRPORT_BCAST_FLOOD => InfoBridgePort::BroadcastFlood(
380 parse_u8(payload)
381 .with_context(|| format!("invalid IFLA_BRPORT_BCAST_FLOOD {payload:?}"))?
382 > 0,
383 ),
384 IFLA_BRPORT_GROUP_FWD_MASK => InfoBridgePort::GroupFwdMask(
385 parse_u16(payload)
386 .with_context(|| format!("invalid IFLA_BRPORT_GROUP_FWD_MASK {payload:?}"))?,
387 ),
388 IFLA_BRPORT_NEIGH_SUPPRESS => InfoBridgePort::NeighSupress(
389 parse_u8(payload)
390 .with_context(|| format!("invalid IFLA_BRPORT_NEIGH_SUPPRESS {payload:?}"))?
391 > 0,
392 ),
393 IFLA_BRPORT_ISOLATED => InfoBridgePort::Isolated(
394 parse_u8(payload)
395 .with_context(|| format!("invalid IFLA_BRPORT_ISOLATED {payload:?}"))?
396 > 0,
397 ),
398 IFLA_BRPORT_BACKUP_PORT => InfoBridgePort::BackupPort(
399 parse_u32(payload)
400 .with_context(|| format!("invalid IFLA_BRPORT_BACKUP_PORT {payload:?}"))?,
401 ),
402 IFLA_BRPORT_MRP_RING_OPEN => InfoBridgePort::MrpRingOpen(
403 parse_u8(payload)
404 .with_context(|| format!("invalid IFLA_BRPORT_MRP_RING_OPEN {payload:?}"))?
405 > 0,
406 ),
407 IFLA_BRPORT_MRP_IN_OPEN => InfoBridgePort::MrpInOpen(
408 parse_u8(payload)
409 .with_context(|| format!("invalid IFLA_BRPORT_MRP_IN_OPEN {payload:?}"))?
410 > 0,
411 ),
412 IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT => {
413 InfoBridgePort::MulticastEhtHostsLimit(parse_u32(payload).with_context(|| {
414 format!("invalid IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT {payload:?}")
415 })?)
416 }
417 IFLA_BRPORT_MCAST_EHT_HOSTS_CNT => {
418 InfoBridgePort::MulticastEhtHostsCnt(parse_u32(payload).with_context(|| {
419 format!("invalid IFLA_BRPORT_MCAST_EHT_HOSTS_CNT {payload:?}")
420 })?)
421 }
422 IFLA_BRPORT_LOCKED => InfoBridgePort::Locked(
423 parse_u8(payload)
424 .with_context(|| format!("invalid IFLA_BRPORT_LOCKED {payload:?}"))?
425 > 0,
426 ),
427 IFLA_BRPORT_MAB => InfoBridgePort::Mab(
428 parse_u8(payload)
429 .with_context(|| format!("invalid IFLA_BRPORT_MAB {payload:?}"))?
430 > 0,
431 ),
432 IFLA_BRPORT_MCAST_N_GROUPS => InfoBridgePort::MulticastNGroups(
433 parse_u32(payload)
434 .with_context(|| format!("invalid IFLA_BRPORT_MCAST_N_GROUPS {payload:?}"))?,
435 ),
436 IFLA_BRPORT_MCAST_MAX_GROUPS => InfoBridgePort::MulticastMaxGroups(
437 parse_u32(payload)
438 .with_context(|| format!("invalid IFLA_BRPORT_MCAST_MAX_GROUPS {payload:?}"))?,
439 ),
440 IFLA_BRPORT_NEIGH_VLAN_SUPPRESS => InfoBridgePort::NeighVlanSupress(
441 parse_u8(payload).with_context(|| {
442 format!("invalid IFLA_BRPORT_NEIGH_VLAN_SUPPRESS {payload:?}")
443 })? > 0,
444 ),
445 IFLA_BRPORT_BACKUP_NHID => InfoBridgePort::BackupNextHopId(
446 parse_u32(payload)
447 .with_context(|| format!("invalid IFLA_BRPORT_BACKUP_NHID {payload:?}"))?,
448 ),
449 kind => InfoBridgePort::Other(DefaultNla::parse(buf).with_context(|| {
450 format!("failed to parse bridge port NLA of type '{kind}' into DefaultNla")
451 })?),
452 })
453 }
454}
455
456const BR_STATE_DISABLED: u8 = 0;
457const BR_STATE_LISTENING: u8 = 1;
458const BR_STATE_LEARNING: u8 = 2;
459const BR_STATE_FORWARDING: u8 = 3;
460const BR_STATE_BLOCKING: u8 = 4;
461
462#[derive(Debug, Clone, Copy, Eq, PartialEq)]
463#[non_exhaustive]
464pub enum BridgePortState {
465 Disabled,
466 Listening,
467 Learning,
468 Forwarding,
469 Blocking,
470 Other(u8),
471}
472
473impl From<u8> for BridgePortState {
474 fn from(value: u8) -> Self {
475 match value {
476 BR_STATE_DISABLED => BridgePortState::Disabled,
477 BR_STATE_LISTENING => BridgePortState::Listening,
478 BR_STATE_LEARNING => BridgePortState::Learning,
479 BR_STATE_FORWARDING => BridgePortState::Forwarding,
480 BR_STATE_BLOCKING => BridgePortState::Blocking,
481 _ => BridgePortState::Other(value),
482 }
483 }
484}
485
486impl From<BridgePortState> for u8 {
487 fn from(value: BridgePortState) -> Self {
488 match value {
489 BridgePortState::Disabled => BR_STATE_DISABLED,
490 BridgePortState::Listening => BR_STATE_LISTENING,
491 BridgePortState::Learning => BR_STATE_LEARNING,
492 BridgePortState::Forwarding => BR_STATE_FORWARDING,
493 BridgePortState::Blocking => BR_STATE_BLOCKING,
494 BridgePortState::Other(v) => v,
495 }
496 }
497}
498
499const MDB_RTR_TYPE_DISABLED: u8 = 0;
500const MDB_RTR_TYPE_TEMP_QUERY: u8 = 1;
501const MDB_RTR_TYPE_PERM: u8 = 2;
502const MDB_RTR_TYPE_TEMP: u8 = 3;
503
504#[derive(Debug, Clone, Copy, Eq, PartialEq)]
505#[non_exhaustive]
506pub enum BridgePortMulticastRouter {
507 Disabled,
508 TempQuery,
509 Perm,
510 Temp,
511 Other(u8),
512}
513
514impl From<u8> for BridgePortMulticastRouter {
515 fn from(value: u8) -> Self {
516 match value {
517 MDB_RTR_TYPE_DISABLED => BridgePortMulticastRouter::Disabled,
518 MDB_RTR_TYPE_TEMP_QUERY => BridgePortMulticastRouter::TempQuery,
519 MDB_RTR_TYPE_PERM => BridgePortMulticastRouter::Perm,
520 MDB_RTR_TYPE_TEMP => BridgePortMulticastRouter::Temp,
521 _ => BridgePortMulticastRouter::Other(value),
522 }
523 }
524}
525
526impl From<BridgePortMulticastRouter> for u8 {
527 fn from(value: BridgePortMulticastRouter) -> Self {
528 match value {
529 BridgePortMulticastRouter::Disabled => MDB_RTR_TYPE_DISABLED,
530 BridgePortMulticastRouter::TempQuery => MDB_RTR_TYPE_TEMP_QUERY,
531 BridgePortMulticastRouter::Perm => MDB_RTR_TYPE_PERM,
532 BridgePortMulticastRouter::Temp => MDB_RTR_TYPE_TEMP,
533 BridgePortMulticastRouter::Other(v) => v,
534 }
535 }
536}