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