1use 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;
56const 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 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 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;
560const 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}