netlink_packet_route/link/link_info/
bridge_port.rs

1// SPDX-License-Identifier: MIT
2use 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;
20// only used in one driver, we don't know if its type is stable:
21// const IFLA_BRPORT_LEARNING_SYNC: u16 = 11;
22const 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;
36// const IFLA_BRPORT_PAD: u16 = 26;
37const 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}