netlink_packet_route/link/link_info/
bridge.rs

1// SPDX-License-Identifier: MIT
2
3use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4
5use anyhow::Context;
6use byteorder::{BigEndian, ByteOrder, NativeEndian};
7use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED};
8use netlink_packet_utils::parsers::{
9    parse_ip, parse_mac, parse_u16, parse_u16_be, parse_u32, parse_u64, parse_u8,
10};
11use netlink_packet_utils::traits::{Emitable, Parseable};
12use netlink_packet_utils::DecodeError;
13
14const IFLA_BR_FORWARD_DELAY: u16 = 1;
15const IFLA_BR_HELLO_TIME: u16 = 2;
16const IFLA_BR_MAX_AGE: u16 = 3;
17const IFLA_BR_AGEING_TIME: u16 = 4;
18const IFLA_BR_STP_STATE: u16 = 5;
19const IFLA_BR_PRIORITY: u16 = 6;
20const IFLA_BR_VLAN_FILTERING: u16 = 7;
21const IFLA_BR_VLAN_PROTOCOL: u16 = 8;
22const IFLA_BR_GROUP_FWD_MASK: u16 = 9;
23const IFLA_BR_ROOT_ID: u16 = 10;
24const IFLA_BR_BRIDGE_ID: u16 = 11;
25const IFLA_BR_ROOT_PORT: u16 = 12;
26const IFLA_BR_ROOT_PATH_COST: u16 = 13;
27const IFLA_BR_TOPOLOGY_CHANGE: u16 = 14;
28const IFLA_BR_TOPOLOGY_CHANGE_DETECTED: u16 = 15;
29const IFLA_BR_HELLO_TIMER: u16 = 16;
30const IFLA_BR_TCN_TIMER: u16 = 17;
31const IFLA_BR_TOPOLOGY_CHANGE_TIMER: u16 = 18;
32const IFLA_BR_GC_TIMER: u16 = 19;
33const IFLA_BR_GROUP_ADDR: u16 = 20;
34const IFLA_BR_FDB_FLUSH: u16 = 21;
35const IFLA_BR_MCAST_ROUTER: u16 = 22;
36const IFLA_BR_MCAST_SNOOPING: u16 = 23;
37const IFLA_BR_MCAST_QUERY_USE_IFADDR: u16 = 24;
38const IFLA_BR_MCAST_QUERIER: u16 = 25;
39const IFLA_BR_MCAST_HASH_ELASTICITY: u16 = 26;
40const IFLA_BR_MCAST_HASH_MAX: u16 = 27;
41const IFLA_BR_MCAST_LAST_MEMBER_CNT: u16 = 28;
42const IFLA_BR_MCAST_STARTUP_QUERY_CNT: u16 = 29;
43const IFLA_BR_MCAST_LAST_MEMBER_INTVL: u16 = 30;
44const IFLA_BR_MCAST_MEMBERSHIP_INTVL: u16 = 31;
45const IFLA_BR_MCAST_QUERIER_INTVL: u16 = 32;
46const IFLA_BR_MCAST_QUERY_INTVL: u16 = 33;
47const IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: u16 = 34;
48const IFLA_BR_MCAST_STARTUP_QUERY_INTVL: u16 = 35;
49const IFLA_BR_NF_CALL_IPTABLES: u16 = 36;
50const IFLA_BR_NF_CALL_IP6TABLES: u16 = 37;
51const IFLA_BR_NF_CALL_ARPTABLES: u16 = 38;
52const IFLA_BR_VLAN_DEFAULT_PVID: u16 = 39;
53// const IFLA_BR_PAD: u16 = 40;
54const IFLA_BR_VLAN_STATS_ENABLED: u16 = 41;
55const IFLA_BR_MCAST_STATS_ENABLED: u16 = 42;
56const IFLA_BR_MCAST_IGMP_VERSION: u16 = 43;
57const IFLA_BR_MCAST_MLD_VERSION: u16 = 44;
58const IFLA_BR_VLAN_STATS_PER_PORT: u16 = 45;
59const IFLA_BR_MULTI_BOOLOPT: u16 = 46;
60const IFLA_BR_MCAST_QUERIER_STATE: u16 = 47;
61
62#[derive(Debug, PartialEq, Eq, Clone)]
63#[non_exhaustive]
64pub enum InfoBridge {
65    GroupAddr([u8; 6]),
66    FdbFlush,
67    HelloTimer(u64),
68    TcnTimer(u64),
69    TopologyChangeTimer(u64),
70    GcTimer(u64),
71    MulticastMembershipInterval(u64),
72    MulticastQuerierInterval(u64),
73    MulticastQueryInterval(u64),
74    MulticastQueryResponseInterval(u64),
75    MulticastLastMemberInterval(u64),
76    MulticastStartupQueryInterval(u64),
77    ForwardDelay(u32),
78    HelloTime(u32),
79    MaxAge(u32),
80    AgeingTime(u32),
81    StpState(u32),
82    MulticastHashElasticity(u32),
83    MulticastHashMax(u32),
84    MulticastLastMemberCount(u32),
85    MulticastStartupQueryCount(u32),
86    RootPathCost(u32),
87    Priority(u16),
88    VlanProtocol(u16),
89    GroupFwdMask(u16),
90    RootId(BridgeId),
91    BridgeId(BridgeId),
92    RootPort(u16),
93    VlanDefaultPvid(u16),
94    VlanFiltering(bool),
95    TopologyChange(u8),
96    TopologyChangeDetected(u8),
97    MulticastRouter(u8),
98    MulticastSnooping(u8),
99    MulticastQueryUseIfaddr(u8),
100    MulticastQuerier(u8),
101    NfCallIpTables(u8),
102    NfCallIp6Tables(u8),
103    NfCallArpTables(u8),
104    VlanStatsEnabled(u8),
105    MulticastStatsEnabled(u8),
106    MulticastIgmpVersion(u8),
107    MulticastMldVersion(u8),
108    VlanStatsPerHost(u8),
109    MultiBoolOpt(u64),
110    MulticastQuerierState(Vec<BridgeQuerierState>),
111    Other(DefaultNla),
112}
113
114impl Nla for InfoBridge {
115    fn value_len(&self) -> usize {
116        match self {
117            // The existance of FdbFlush means true
118            Self::FdbFlush => 0,
119            Self::HelloTimer(_)
120            | Self::TcnTimer(_)
121            | Self::TopologyChangeTimer(_)
122            | Self::GcTimer(_)
123            | Self::MulticastMembershipInterval(_)
124            | Self::MulticastQuerierInterval(_)
125            | Self::MulticastQueryInterval(_)
126            | Self::MulticastQueryResponseInterval(_)
127            | Self::MulticastLastMemberInterval(_)
128            | Self::MulticastStartupQueryInterval(_) => 8,
129            Self::ForwardDelay(_)
130            | Self::HelloTime(_)
131            | Self::MaxAge(_)
132            | Self::AgeingTime(_)
133            | Self::StpState(_)
134            | Self::MulticastHashElasticity(_)
135            | Self::MulticastHashMax(_)
136            | Self::MulticastLastMemberCount(_)
137            | Self::MulticastStartupQueryCount(_)
138            | Self::RootPathCost(_) => 4,
139            Self::Priority(_)
140            | Self::VlanProtocol(_)
141            | Self::GroupFwdMask(_)
142            | Self::RootPort(_)
143            | Self::VlanDefaultPvid(_) => 2,
144
145            Self::RootId(_) | Self::BridgeId(_) | Self::MultiBoolOpt(_) => 8,
146
147            Self::GroupAddr(_) => 6,
148
149            Self::VlanFiltering(_) => 1,
150            Self::TopologyChange(_)
151            | Self::TopologyChangeDetected(_)
152            | Self::MulticastRouter(_)
153            | Self::MulticastSnooping(_)
154            | Self::MulticastQueryUseIfaddr(_)
155            | Self::MulticastQuerier(_)
156            | Self::NfCallIpTables(_)
157            | Self::NfCallIp6Tables(_)
158            | Self::NfCallArpTables(_)
159            | Self::VlanStatsEnabled(_)
160            | Self::MulticastStatsEnabled(_)
161            | Self::MulticastIgmpVersion(_)
162            | Self::MulticastMldVersion(_)
163            | Self::VlanStatsPerHost(_) => 1,
164
165            Self::MulticastQuerierState(nlas) => nlas.as_slice().buffer_len(),
166
167            Self::Other(nla) => nla.value_len(),
168        }
169    }
170
171    fn emit_value(&self, buffer: &mut [u8]) {
172        match self {
173            Self::FdbFlush => (),
174
175            Self::HelloTimer(value)
176            | Self::TcnTimer(value)
177            | Self::TopologyChangeTimer(value)
178            | Self::GcTimer(value)
179            | Self::MulticastMembershipInterval(value)
180            | Self::MulticastQuerierInterval(value)
181            | Self::MulticastQueryInterval(value)
182            | Self::MulticastQueryResponseInterval(value)
183            | Self::MulticastLastMemberInterval(value)
184            | Self::MulticastStartupQueryInterval(value)
185            | Self::MultiBoolOpt(value) => NativeEndian::write_u64(buffer, *value),
186
187            Self::ForwardDelay(value)
188            | Self::HelloTime(value)
189            | Self::MaxAge(value)
190            | Self::AgeingTime(value)
191            | Self::StpState(value)
192            | Self::MulticastHashElasticity(value)
193            | Self::MulticastHashMax(value)
194            | Self::MulticastLastMemberCount(value)
195            | Self::MulticastStartupQueryCount(value)
196            | Self::RootPathCost(value) => NativeEndian::write_u32(buffer, *value),
197
198            Self::Priority(value)
199            | Self::GroupFwdMask(value)
200            | Self::RootPort(value)
201            | Self::VlanDefaultPvid(value) => NativeEndian::write_u16(buffer, *value),
202
203            Self::VlanProtocol(value) => BigEndian::write_u16(buffer, *value),
204
205            Self::RootId(bridge_id) | Self::BridgeId(bridge_id) => bridge_id.emit(buffer),
206
207            Self::GroupAddr(value) => buffer.copy_from_slice(&value[..]),
208
209            Self::VlanFiltering(value) => buffer[0] = (*value).into(),
210            Self::TopologyChange(value)
211            | Self::TopologyChangeDetected(value)
212            | Self::MulticastRouter(value)
213            | Self::MulticastSnooping(value)
214            | Self::MulticastQueryUseIfaddr(value)
215            | Self::MulticastQuerier(value)
216            | Self::NfCallIpTables(value)
217            | Self::NfCallIp6Tables(value)
218            | Self::NfCallArpTables(value)
219            | Self::VlanStatsEnabled(value)
220            | Self::MulticastStatsEnabled(value)
221            | Self::MulticastIgmpVersion(value)
222            | Self::MulticastMldVersion(value)
223            | Self::VlanStatsPerHost(value) => buffer[0] = *value,
224
225            Self::MulticastQuerierState(nlas) => nlas.as_slice().emit(buffer),
226
227            Self::Other(nla) => nla.emit_value(buffer),
228        }
229    }
230
231    fn kind(&self) -> u16 {
232        match self {
233            Self::GroupAddr(_) => IFLA_BR_GROUP_ADDR,
234            Self::FdbFlush => IFLA_BR_FDB_FLUSH,
235            Self::HelloTimer(_) => IFLA_BR_HELLO_TIMER,
236            Self::TcnTimer(_) => IFLA_BR_TCN_TIMER,
237            Self::TopologyChangeTimer(_) => IFLA_BR_TOPOLOGY_CHANGE_TIMER,
238            Self::GcTimer(_) => IFLA_BR_GC_TIMER,
239            Self::MulticastMembershipInterval(_) => IFLA_BR_MCAST_MEMBERSHIP_INTVL,
240            Self::MulticastQuerierInterval(_) => IFLA_BR_MCAST_QUERIER_INTVL,
241            Self::MulticastQueryInterval(_) => IFLA_BR_MCAST_QUERY_INTVL,
242            Self::MulticastQueryResponseInterval(_) => IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
243            Self::ForwardDelay(_) => IFLA_BR_FORWARD_DELAY,
244            Self::HelloTime(_) => IFLA_BR_HELLO_TIME,
245            Self::MaxAge(_) => IFLA_BR_MAX_AGE,
246            Self::AgeingTime(_) => IFLA_BR_AGEING_TIME,
247            Self::StpState(_) => IFLA_BR_STP_STATE,
248            Self::MulticastHashElasticity(_) => IFLA_BR_MCAST_HASH_ELASTICITY,
249            Self::MulticastHashMax(_) => IFLA_BR_MCAST_HASH_MAX,
250            Self::MulticastLastMemberCount(_) => IFLA_BR_MCAST_LAST_MEMBER_CNT,
251            Self::MulticastStartupQueryCount(_) => IFLA_BR_MCAST_STARTUP_QUERY_CNT,
252            Self::MulticastLastMemberInterval(_) => IFLA_BR_MCAST_LAST_MEMBER_INTVL,
253            Self::MulticastStartupQueryInterval(_) => IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
254            Self::RootPathCost(_) => IFLA_BR_ROOT_PATH_COST,
255            Self::Priority(_) => IFLA_BR_PRIORITY,
256            Self::VlanProtocol(_) => IFLA_BR_VLAN_PROTOCOL,
257            Self::GroupFwdMask(_) => IFLA_BR_GROUP_FWD_MASK,
258            Self::RootId(_) => IFLA_BR_ROOT_ID,
259            Self::BridgeId(_) => IFLA_BR_BRIDGE_ID,
260            Self::RootPort(_) => IFLA_BR_ROOT_PORT,
261            Self::VlanDefaultPvid(_) => IFLA_BR_VLAN_DEFAULT_PVID,
262            Self::VlanFiltering(_) => IFLA_BR_VLAN_FILTERING,
263            Self::TopologyChange(_) => IFLA_BR_TOPOLOGY_CHANGE,
264            Self::TopologyChangeDetected(_) => IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
265            Self::MulticastRouter(_) => IFLA_BR_MCAST_ROUTER,
266            Self::MulticastSnooping(_) => IFLA_BR_MCAST_SNOOPING,
267            Self::MulticastQueryUseIfaddr(_) => IFLA_BR_MCAST_QUERY_USE_IFADDR,
268            Self::MulticastQuerier(_) => IFLA_BR_MCAST_QUERIER,
269            Self::NfCallIpTables(_) => IFLA_BR_NF_CALL_IPTABLES,
270            Self::NfCallIp6Tables(_) => IFLA_BR_NF_CALL_IP6TABLES,
271            Self::NfCallArpTables(_) => IFLA_BR_NF_CALL_ARPTABLES,
272            Self::VlanStatsEnabled(_) => IFLA_BR_VLAN_STATS_ENABLED,
273            Self::MulticastStatsEnabled(_) => IFLA_BR_MCAST_STATS_ENABLED,
274            Self::MulticastIgmpVersion(_) => IFLA_BR_MCAST_IGMP_VERSION,
275            Self::MulticastMldVersion(_) => IFLA_BR_MCAST_MLD_VERSION,
276            Self::VlanStatsPerHost(_) => IFLA_BR_VLAN_STATS_PER_PORT,
277            Self::MultiBoolOpt(_) => IFLA_BR_MULTI_BOOLOPT,
278            Self::MulticastQuerierState(_) => IFLA_BR_MCAST_QUERIER_STATE | NLA_F_NESTED,
279            Self::Other(nla) => nla.kind(),
280        }
281    }
282}
283
284impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBridge {
285    type Error = DecodeError;
286    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
287        let payload = buf.value();
288        Ok(match buf.kind() {
289            IFLA_BR_FDB_FLUSH => Self::FdbFlush,
290            IFLA_BR_HELLO_TIMER => {
291                Self::HelloTimer(parse_u64(payload).context("invalid IFLA_BR_HELLO_TIMER value")?)
292            }
293            IFLA_BR_TCN_TIMER => {
294                Self::TcnTimer(parse_u64(payload).context("invalid IFLA_BR_TCN_TIMER value")?)
295            }
296            IFLA_BR_TOPOLOGY_CHANGE_TIMER => Self::TopologyChangeTimer(
297                parse_u64(payload).context("invalid IFLA_BR_TOPOLOGY_CHANGE_TIMER value")?,
298            ),
299            IFLA_BR_GC_TIMER => {
300                Self::GcTimer(parse_u64(payload).context("invalid IFLA_BR_GC_TIMER value")?)
301            }
302            IFLA_BR_MCAST_LAST_MEMBER_INTVL => Self::MulticastLastMemberInterval(
303                parse_u64(payload).context("invalid IFLA_BR_MCAST_LAST_MEMBER_INTVL value")?,
304            ),
305            IFLA_BR_MCAST_MEMBERSHIP_INTVL => Self::MulticastMembershipInterval(
306                parse_u64(payload).context("invalid IFLA_BR_MCAST_MEMBERSHIP_INTVL value")?,
307            ),
308            IFLA_BR_MCAST_QUERIER_INTVL => Self::MulticastQuerierInterval(
309                parse_u64(payload).context("invalid IFLA_BR_MCAST_QUERIER_INTVL value")?,
310            ),
311            IFLA_BR_MCAST_QUERY_INTVL => Self::MulticastQueryInterval(
312                parse_u64(payload).context("invalid IFLA_BR_MCAST_QUERY_INTVL value")?,
313            ),
314            IFLA_BR_MCAST_QUERY_RESPONSE_INTVL => Self::MulticastQueryResponseInterval(
315                parse_u64(payload).context("invalid IFLA_BR_MCAST_QUERY_RESPONSE_INTVL value")?,
316            ),
317            IFLA_BR_MCAST_STARTUP_QUERY_INTVL => Self::MulticastStartupQueryInterval(
318                parse_u64(payload).context("invalid IFLA_BR_MCAST_STARTUP_QUERY_INTVL value")?,
319            ),
320            IFLA_BR_FORWARD_DELAY => Self::ForwardDelay(
321                parse_u32(payload).context("invalid IFLA_BR_FORWARD_DELAY value")?,
322            ),
323            IFLA_BR_HELLO_TIME => {
324                Self::HelloTime(parse_u32(payload).context("invalid IFLA_BR_HELLO_TIME value")?)
325            }
326            IFLA_BR_MAX_AGE => {
327                Self::MaxAge(parse_u32(payload).context("invalid IFLA_BR_MAX_AGE value")?)
328            }
329            IFLA_BR_AGEING_TIME => {
330                Self::AgeingTime(parse_u32(payload).context("invalid IFLA_BR_AGEING_TIME value")?)
331            }
332            IFLA_BR_STP_STATE => {
333                Self::StpState(parse_u32(payload).context("invalid IFLA_BR_STP_STATE value")?)
334            }
335            IFLA_BR_MCAST_HASH_ELASTICITY => Self::MulticastHashElasticity(
336                parse_u32(payload).context("invalid IFLA_BR_MCAST_HASH_ELASTICITY value")?,
337            ),
338            IFLA_BR_MCAST_HASH_MAX => Self::MulticastHashMax(
339                parse_u32(payload).context("invalid IFLA_BR_MCAST_HASH_MAX value")?,
340            ),
341            IFLA_BR_MCAST_LAST_MEMBER_CNT => Self::MulticastLastMemberCount(
342                parse_u32(payload).context("invalid IFLA_BR_MCAST_LAST_MEMBER_CNT value")?,
343            ),
344            IFLA_BR_MCAST_STARTUP_QUERY_CNT => Self::MulticastStartupQueryCount(
345                parse_u32(payload).context("invalid IFLA_BR_MCAST_STARTUP_QUERY_CNT value")?,
346            ),
347            IFLA_BR_ROOT_PATH_COST => Self::RootPathCost(
348                parse_u32(payload).context("invalid IFLA_BR_ROOT_PATH_COST value")?,
349            ),
350            IFLA_BR_PRIORITY => {
351                Self::Priority(parse_u16(payload).context("invalid IFLA_BR_PRIORITY value")?)
352            }
353            IFLA_BR_VLAN_PROTOCOL => Self::VlanProtocol(
354                parse_u16_be(payload).context("invalid IFLA_BR_VLAN_PROTOCOL value")?,
355            ),
356            IFLA_BR_GROUP_FWD_MASK => Self::GroupFwdMask(
357                parse_u16(payload).context("invalid IFLA_BR_GROUP_FWD_MASK value")?,
358            ),
359            IFLA_BR_ROOT_ID => Self::RootId(
360                BridgeId::parse(&BridgeIdBuffer::new(payload))
361                    .context("invalid IFLA_BR_ROOT_ID value")?,
362            ),
363            IFLA_BR_BRIDGE_ID => Self::BridgeId(
364                BridgeId::parse(&BridgeIdBuffer::new(payload))
365                    .context("invalid IFLA_BR_BRIDGE_ID value")?,
366            ),
367            IFLA_BR_GROUP_ADDR => {
368                Self::GroupAddr(parse_mac(payload).context("invalid IFLA_BR_GROUP_ADDR value")?)
369            }
370            IFLA_BR_ROOT_PORT => {
371                Self::RootPort(parse_u16(payload).context("invalid IFLA_BR_ROOT_PORT value")?)
372            }
373            IFLA_BR_VLAN_DEFAULT_PVID => Self::VlanDefaultPvid(
374                parse_u16(payload).context("invalid IFLA_BR_VLAN_DEFAULT_PVID value")?,
375            ),
376            IFLA_BR_VLAN_FILTERING => Self::VlanFiltering(
377                parse_u8(payload).context("invalid IFLA_BR_VLAN_FILTERING value")? > 0,
378            ),
379            IFLA_BR_TOPOLOGY_CHANGE => Self::TopologyChange(
380                parse_u8(payload).context("invalid IFLA_BR_TOPOLOGY_CHANGE value")?,
381            ),
382            IFLA_BR_TOPOLOGY_CHANGE_DETECTED => Self::TopologyChangeDetected(
383                parse_u8(payload).context("invalid IFLA_BR_TOPOLOGY_CHANGE_DETECTED value")?,
384            ),
385            IFLA_BR_MCAST_ROUTER => Self::MulticastRouter(
386                parse_u8(payload).context("invalid IFLA_BR_MCAST_ROUTER value")?,
387            ),
388            IFLA_BR_MCAST_SNOOPING => Self::MulticastSnooping(
389                parse_u8(payload).context("invalid IFLA_BR_MCAST_SNOOPING value")?,
390            ),
391            IFLA_BR_MCAST_QUERY_USE_IFADDR => Self::MulticastQueryUseIfaddr(
392                parse_u8(payload).context("invalid IFLA_BR_MCAST_QUERY_USE_IFADDR value")?,
393            ),
394            IFLA_BR_MCAST_QUERIER => Self::MulticastQuerier(
395                parse_u8(payload).context("invalid IFLA_BR_MCAST_QUERIER value")?,
396            ),
397            IFLA_BR_NF_CALL_IPTABLES => Self::NfCallIpTables(
398                parse_u8(payload).context("invalid IFLA_BR_NF_CALL_IPTABLES value")?,
399            ),
400            IFLA_BR_NF_CALL_IP6TABLES => Self::NfCallIp6Tables(
401                parse_u8(payload).context("invalid IFLA_BR_NF_CALL_IP6TABLES value")?,
402            ),
403            IFLA_BR_NF_CALL_ARPTABLES => Self::NfCallArpTables(
404                parse_u8(payload).context("invalid IFLA_BR_NF_CALL_ARPTABLES value")?,
405            ),
406            IFLA_BR_VLAN_STATS_ENABLED => Self::VlanStatsEnabled(
407                parse_u8(payload).context("invalid IFLA_BR_VLAN_STATS_ENABLED value")?,
408            ),
409            IFLA_BR_MCAST_STATS_ENABLED => Self::MulticastStatsEnabled(
410                parse_u8(payload).context("invalid IFLA_BR_MCAST_STATS_ENABLED value")?,
411            ),
412            IFLA_BR_MCAST_IGMP_VERSION => Self::MulticastIgmpVersion(
413                parse_u8(payload).context("invalid IFLA_BR_MCAST_IGMP_VERSION value")?,
414            ),
415            IFLA_BR_MCAST_MLD_VERSION => Self::MulticastMldVersion(
416                parse_u8(payload).context("invalid IFLA_BR_MCAST_MLD_VERSION value")?,
417            ),
418            IFLA_BR_VLAN_STATS_PER_PORT => Self::VlanStatsPerHost(
419                parse_u8(payload).context("invalid IFLA_BR_VLAN_STATS_PER_PORT value")?,
420            ),
421            IFLA_BR_MULTI_BOOLOPT => Self::MultiBoolOpt(
422                parse_u64(payload).context("invalid IFLA_BR_MULTI_BOOLOPT value")?,
423            ),
424            IFLA_BR_MCAST_QUERIER_STATE => {
425                let mut v = Vec::new();
426                let err = "failed to parse IFLA_BR_MCAST_QUERIER_STATE";
427                for nla in NlasIterator::new(payload) {
428                    let nla = &nla.context(err)?;
429                    let parsed = BridgeQuerierState::parse(nla).context(err)?;
430                    v.push(parsed);
431                }
432                Self::MulticastQuerierState(v)
433            }
434            _ => Self::Other(
435                DefaultNla::parse(buf)
436                    .context("invalid link info bridge NLA value (unknown type)")?,
437            ),
438        })
439    }
440}
441
442const BRIDGE_ID_LEN: usize = 8;
443
444#[derive(Debug, PartialEq, Eq, Clone)]
445pub struct BridgeId {
446    pub priority: u16,
447    pub address: [u8; 6],
448}
449
450buffer!(BridgeIdBuffer(BRIDGE_ID_LEN) {
451    priority: (u16, 0..2),
452    address: (slice, 2..BRIDGE_ID_LEN)
453});
454
455impl<T: AsRef<[u8]> + ?Sized> Parseable<BridgeIdBuffer<&T>> for BridgeId {
456    type Error = DecodeError;
457    fn parse(buf: &BridgeIdBuffer<&T>) -> Result<Self, DecodeError> {
458        // Priority is encoded in big endian. From kernel's
459        // net/bridge/br_netlink.c br_fill_info():
460        // u16 priority = (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1];
461        Ok(Self {
462            priority: u16::from_be(buf.priority()),
463            address: parse_mac(buf.address()).context("invalid MAC address in BridgeId buffer")?,
464        })
465    }
466}
467
468impl Emitable for BridgeId {
469    fn buffer_len(&self) -> usize {
470        BRIDGE_ID_LEN
471    }
472
473    fn emit(&self, buffer: &mut [u8]) {
474        let mut buffer = BridgeIdBuffer::new(buffer);
475        buffer.set_priority(self.priority.to_be());
476        buffer.address_mut().copy_from_slice(&self.address[..]);
477    }
478}
479
480const BRIDGE_QUERIER_IP_ADDRESS: u16 = 1;
481const BRIDGE_QUERIER_IP_PORT: u16 = 2;
482const BRIDGE_QUERIER_IP_OTHER_TIMER: u16 = 3;
483// const BRIDGE_QUERIER_PAD: u16 = 4;
484const BRIDGE_QUERIER_IPV6_ADDRESS: u16 = 5;
485const BRIDGE_QUERIER_IPV6_PORT: u16 = 6;
486const BRIDGE_QUERIER_IPV6_OTHER_TIMER: u16 = 7;
487
488#[derive(Debug, Clone, Eq, PartialEq)]
489#[non_exhaustive]
490pub enum BridgeQuerierState {
491    Ipv4Address(Ipv4Addr),
492    Ipv4Port(u32),
493    Ipv4OtherTimer(u64),
494    Ipv6Address(Ipv6Addr),
495    Ipv6Port(u32),
496    Ipv6OtherTimer(u64),
497    Other(DefaultNla),
498}
499
500impl Nla for BridgeQuerierState {
501    fn value_len(&self) -> usize {
502        use self::BridgeQuerierState::*;
503        match self {
504            Ipv4Address(_) => 4,
505            Ipv6Address(_) => 16,
506            Ipv4Port(_) | Ipv6Port(_) => 4,
507            Ipv4OtherTimer(_) | Ipv6OtherTimer(_) => 8,
508            Other(nla) => nla.value_len(),
509        }
510    }
511
512    fn kind(&self) -> u16 {
513        use self::BridgeQuerierState::*;
514        match self {
515            Ipv4Address(_) => BRIDGE_QUERIER_IP_ADDRESS,
516            Ipv4Port(_) => BRIDGE_QUERIER_IP_PORT,
517            Ipv4OtherTimer(_) => BRIDGE_QUERIER_IP_OTHER_TIMER,
518            Ipv6Address(_) => BRIDGE_QUERIER_IPV6_ADDRESS,
519            Ipv6Port(_) => BRIDGE_QUERIER_IPV6_PORT,
520            Ipv6OtherTimer(_) => BRIDGE_QUERIER_IPV6_OTHER_TIMER,
521            Other(nla) => nla.kind(),
522        }
523    }
524
525    fn emit_value(&self, buffer: &mut [u8]) {
526        use self::BridgeQuerierState::*;
527        match self {
528            Ipv4Port(d) | Ipv6Port(d) => NativeEndian::write_u32(buffer, *d),
529            Ipv4OtherTimer(d) | Ipv6OtherTimer(d) => NativeEndian::write_u64(buffer, *d),
530            Ipv4Address(addr) => buffer.copy_from_slice(&addr.octets()),
531            Ipv6Address(addr) => buffer.copy_from_slice(&addr.octets()),
532            Other(nla) => nla.emit_value(buffer),
533        }
534    }
535}
536
537impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for BridgeQuerierState {
538    type Error = DecodeError;
539    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
540        use self::BridgeQuerierState::*;
541        let payload = buf.value();
542        Ok(match buf.kind() {
543            BRIDGE_QUERIER_IP_ADDRESS => match parse_ip(payload) {
544                Ok(IpAddr::V4(addr)) => Ipv4Address(addr),
545                Ok(v) => {
546                    return Err(DecodeError::from(format!(
547                        "Invalid BRIDGE_QUERIER_IP_ADDRESS, \
548                        expecting IPv4 address, but got {v}"
549                    )))
550                }
551                Err(e) => {
552                    return Err(DecodeError::from(format!("Invalid BRIDGE_QUERIER_IP_ADDRESS {e}")))
553                }
554            },
555            BRIDGE_QUERIER_IPV6_ADDRESS => match parse_ip(payload) {
556                Ok(IpAddr::V6(addr)) => Ipv6Address(addr),
557                Ok(v) => {
558                    return Err(DecodeError::from(format!(
559                        "Invalid BRIDGE_QUERIER_IPV6_ADDRESS, \
560                        expecting IPv6 address, but got {v}"
561                    )));
562                }
563                Err(e) => {
564                    return Err(DecodeError::from(format!(
565                        "Invalid BRIDGE_QUERIER_IPV6_ADDRESS {e}"
566                    )));
567                }
568            },
569            BRIDGE_QUERIER_IP_PORT => {
570                Ipv4Port(parse_u32(payload).context("invalid BRIDGE_QUERIER_IP_PORT value")?)
571            }
572            BRIDGE_QUERIER_IPV6_PORT => {
573                Ipv6Port(parse_u32(payload).context("invalid BRIDGE_QUERIER_IPV6_PORT value")?)
574            }
575            BRIDGE_QUERIER_IP_OTHER_TIMER => Ipv4OtherTimer(
576                parse_u64(payload).context("invalid BRIDGE_QUERIER_IP_OTHER_TIMER value")?,
577            ),
578            BRIDGE_QUERIER_IPV6_OTHER_TIMER => Ipv6OtherTimer(
579                parse_u64(payload).context("invalid BRIDGE_QUERIER_IPV6_OTHER_TIMER value")?,
580            ),
581
582            kind => Other(DefaultNla::parse(buf).context(format!("unknown NLA type {kind}"))?),
583        })
584    }
585}