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