1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4
5use netlink_packet_core::{
6 emit_u16, emit_u16_be, emit_u32, emit_u64, parse_ip, parse_mac, parse_u16,
7 parse_u16_be, parse_u32, parse_u64, parse_u8, DecodeError, DefaultNla,
8 Emitable, ErrorContext, Nla, NlaBuffer, NlasIterator, Parseable,
9 NLA_F_NESTED,
10};
11
12use crate::link::{BridgeBooleanOptions, VlanProtocol};
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;
53const 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;
61const IFLA_BR_FDB_N_LEARNED: u16 = 48;
62const IFLA_BR_FDB_MAX_LEARNED: u16 = 49;
63
64#[derive(Debug, PartialEq, Eq, Clone)]
65#[non_exhaustive]
66pub enum InfoBridge {
67 GroupAddr([u8; 6]),
68 FdbFlush,
69 HelloTimer(u64),
70 TcnTimer(u64),
71 TopologyChangeTimer(u64),
72 GcTimer(u64),
73 MulticastMembershipInterval(u64),
74 MulticastQuerierInterval(u64),
75 MulticastQueryInterval(u64),
76 MulticastQueryResponseInterval(u64),
77 MulticastLastMemberInterval(u64),
78 MulticastStartupQueryInterval(u64),
79 ForwardDelay(u32),
80 HelloTime(u32),
81 MaxAge(u32),
82 AgeingTime(u32),
83 StpState(BridgeStpState),
84 MulticastHashElasticity(u32),
85 MulticastHashMax(u32),
86 MulticastLastMemberCount(u32),
87 MulticastStartupQueryCount(u32),
88 RootPathCost(u32),
89 Priority(u16),
90 VlanProtocol(VlanProtocol),
91 GroupFwdMask(u16),
92 RootId(BridgeId),
93 BridgeId(BridgeId),
94 RootPort(u16),
95 VlanDefaultPvid(u16),
96 VlanFiltering(bool),
97 TopologyChange(u8),
98 TopologyChangeDetected(u8),
99 MulticastRouter(BridgeMulticastRouterType),
100 MulticastSnooping(bool),
101 MulticastQueryUseIfaddr(bool),
102 MulticastQuerier(bool),
103 NfCallIpTables(bool),
104 NfCallIp6Tables(bool),
105 NfCallArpTables(bool),
106 VlanStatsEnabled(bool),
107 MulticastStatsEnabled(bool),
108 MulticastIgmpVersion(u8),
109 MulticastMldVersion(u8),
110 VlanStatsPerPort(bool),
111 MultiBoolOpt(BridgeBooleanOptions),
112 MulticastQuerierState(Vec<BridgeQuerierState>),
113 FdbNLearned(u32),
114 FdbMaxLearned(u32),
115 Other(DefaultNla),
116}
117
118impl Nla for InfoBridge {
119 fn value_len(&self) -> usize {
120 match self {
121 Self::FdbFlush => 0,
123 Self::HelloTimer(_)
124 | Self::TcnTimer(_)
125 | Self::TopologyChangeTimer(_)
126 | Self::GcTimer(_)
127 | Self::MulticastMembershipInterval(_)
128 | Self::MulticastQuerierInterval(_)
129 | Self::MulticastQueryInterval(_)
130 | Self::MulticastQueryResponseInterval(_)
131 | Self::MulticastLastMemberInterval(_)
132 | Self::MulticastStartupQueryInterval(_) => 8,
133 Self::ForwardDelay(_)
134 | Self::HelloTime(_)
135 | Self::MaxAge(_)
136 | Self::AgeingTime(_)
137 | Self::MulticastHashElasticity(_)
138 | Self::MulticastHashMax(_)
139 | Self::MulticastLastMemberCount(_)
140 | Self::MulticastStartupQueryCount(_)
141 | Self::RootPathCost(_)
142 | Self::FdbNLearned(_)
143 | Self::FdbMaxLearned(_) => 4,
144 Self::Priority(_)
145 | Self::GroupFwdMask(_)
146 | Self::RootPort(_)
147 | Self::VlanDefaultPvid(_) => 2,
148
149 Self::VlanProtocol(_) => 2,
150
151 Self::StpState(_) => 4,
152
153 Self::RootId(_) | Self::BridgeId(_) => 8,
154
155 Self::MultiBoolOpt(v) => v.buffer_len(),
156
157 Self::GroupAddr(_) => 6,
158
159 Self::VlanFiltering(_) => 1,
160 Self::MulticastRouter(_) => 1,
161 Self::TopologyChange(_)
162 | Self::TopologyChangeDetected(_)
163 | Self::MulticastIgmpVersion(_)
164 | Self::MulticastMldVersion(_) => 1,
165
166 Self::MulticastSnooping(_)
167 | Self::NfCallIpTables(_)
168 | Self::NfCallIp6Tables(_)
169 | Self::NfCallArpTables(_)
170 | Self::MulticastStatsEnabled(_)
171 | Self::MulticastQuerier(_)
172 | Self::MulticastQueryUseIfaddr(_)
173 | Self::VlanStatsPerPort(_)
174 | Self::VlanStatsEnabled(_) => 1,
175
176 Self::MulticastQuerierState(nlas) => nlas.as_slice().buffer_len(),
177
178 Self::Other(nla) => nla.value_len(),
179 }
180 }
181
182 fn emit_value(&self, buffer: &mut [u8]) {
183 match self {
184 Self::FdbFlush => (),
185
186 Self::HelloTimer(value)
187 | Self::TcnTimer(value)
188 | Self::TopologyChangeTimer(value)
189 | Self::GcTimer(value)
190 | Self::MulticastMembershipInterval(value)
191 | Self::MulticastQuerierInterval(value)
192 | Self::MulticastQueryInterval(value)
193 | Self::MulticastQueryResponseInterval(value)
194 | Self::MulticastLastMemberInterval(value)
195 | Self::MulticastStartupQueryInterval(value) => {
196 emit_u64(buffer, *value).unwrap()
197 }
198
199 Self::MultiBoolOpt(value) => value.emit(buffer),
200
201 Self::ForwardDelay(value)
202 | Self::HelloTime(value)
203 | Self::MaxAge(value)
204 | Self::AgeingTime(value)
205 | Self::MulticastHashElasticity(value)
206 | Self::MulticastHashMax(value)
207 | Self::MulticastLastMemberCount(value)
208 | Self::MulticastStartupQueryCount(value)
209 | Self::FdbNLearned(value)
210 | Self::FdbMaxLearned(value)
211 | Self::RootPathCost(value) => emit_u32(buffer, *value).unwrap(),
212
213 Self::StpState(value) => {
214 emit_u32(buffer, u32::from(*value)).unwrap()
215 }
216
217 Self::Priority(value)
218 | Self::GroupFwdMask(value)
219 | Self::RootPort(value)
220 | Self::VlanDefaultPvid(value) => emit_u16(buffer, *value).unwrap(),
221
222 Self::VlanProtocol(value) => {
223 emit_u16_be(buffer, (*value).into()).unwrap()
224 }
225
226 Self::RootId(bridge_id) | Self::BridgeId(bridge_id) => {
227 bridge_id.emit(buffer)
228 }
229
230 Self::GroupAddr(value) => buffer.copy_from_slice(&value[..]),
231
232 Self::VlanFiltering(value) => buffer[0] = (*value).into(),
233 Self::TopologyChange(value)
234 | Self::TopologyChangeDetected(value)
235 | Self::MulticastIgmpVersion(value)
236 | Self::MulticastMldVersion(value) => buffer[0] = *value,
237
238 Self::MulticastRouter(value) => buffer[0] = (*value).into(),
239
240 Self::MulticastSnooping(value)
241 | Self::NfCallIpTables(value)
242 | Self::NfCallIp6Tables(value)
243 | Self::NfCallArpTables(value)
244 | Self::MulticastStatsEnabled(value)
245 | Self::MulticastQuerier(value)
246 | Self::MulticastQueryUseIfaddr(value)
247 | Self::VlanStatsPerPort(value)
248 | Self::VlanStatsEnabled(value) => buffer[0] = (*value).into(),
249
250 Self::MulticastQuerierState(nlas) => nlas.as_slice().emit(buffer),
251
252 Self::Other(nla) => nla.emit_value(buffer),
253 }
254 }
255
256 fn kind(&self) -> u16 {
257 match self {
258 Self::GroupAddr(_) => IFLA_BR_GROUP_ADDR,
259 Self::FdbFlush => IFLA_BR_FDB_FLUSH,
260 Self::HelloTimer(_) => IFLA_BR_HELLO_TIMER,
261 Self::TcnTimer(_) => IFLA_BR_TCN_TIMER,
262 Self::TopologyChangeTimer(_) => IFLA_BR_TOPOLOGY_CHANGE_TIMER,
263 Self::GcTimer(_) => IFLA_BR_GC_TIMER,
264 Self::MulticastMembershipInterval(_) => {
265 IFLA_BR_MCAST_MEMBERSHIP_INTVL
266 }
267 Self::MulticastQuerierInterval(_) => IFLA_BR_MCAST_QUERIER_INTVL,
268 Self::MulticastQueryInterval(_) => IFLA_BR_MCAST_QUERY_INTVL,
269 Self::MulticastQueryResponseInterval(_) => {
270 IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
271 }
272 Self::ForwardDelay(_) => IFLA_BR_FORWARD_DELAY,
273 Self::HelloTime(_) => IFLA_BR_HELLO_TIME,
274 Self::MaxAge(_) => IFLA_BR_MAX_AGE,
275 Self::AgeingTime(_) => IFLA_BR_AGEING_TIME,
276 Self::StpState(_) => IFLA_BR_STP_STATE,
277 Self::MulticastHashElasticity(_) => IFLA_BR_MCAST_HASH_ELASTICITY,
278 Self::MulticastHashMax(_) => IFLA_BR_MCAST_HASH_MAX,
279 Self::MulticastLastMemberCount(_) => IFLA_BR_MCAST_LAST_MEMBER_CNT,
280 Self::MulticastStartupQueryCount(_) => {
281 IFLA_BR_MCAST_STARTUP_QUERY_CNT
282 }
283 Self::MulticastLastMemberInterval(_) => {
284 IFLA_BR_MCAST_LAST_MEMBER_INTVL
285 }
286 Self::MulticastStartupQueryInterval(_) => {
287 IFLA_BR_MCAST_STARTUP_QUERY_INTVL
288 }
289 Self::RootPathCost(_) => IFLA_BR_ROOT_PATH_COST,
290 Self::Priority(_) => IFLA_BR_PRIORITY,
291 Self::VlanProtocol(_) => IFLA_BR_VLAN_PROTOCOL,
292 Self::GroupFwdMask(_) => IFLA_BR_GROUP_FWD_MASK,
293 Self::RootId(_) => IFLA_BR_ROOT_ID,
294 Self::BridgeId(_) => IFLA_BR_BRIDGE_ID,
295 Self::RootPort(_) => IFLA_BR_ROOT_PORT,
296 Self::VlanDefaultPvid(_) => IFLA_BR_VLAN_DEFAULT_PVID,
297 Self::VlanFiltering(_) => IFLA_BR_VLAN_FILTERING,
298 Self::TopologyChange(_) => IFLA_BR_TOPOLOGY_CHANGE,
299 Self::TopologyChangeDetected(_) => IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
300 Self::MulticastRouter(_) => IFLA_BR_MCAST_ROUTER,
301 Self::MulticastSnooping(_) => IFLA_BR_MCAST_SNOOPING,
302 Self::MulticastQueryUseIfaddr(_) => IFLA_BR_MCAST_QUERY_USE_IFADDR,
303 Self::MulticastQuerier(_) => IFLA_BR_MCAST_QUERIER,
304 Self::NfCallIpTables(_) => IFLA_BR_NF_CALL_IPTABLES,
305 Self::NfCallIp6Tables(_) => IFLA_BR_NF_CALL_IP6TABLES,
306 Self::NfCallArpTables(_) => IFLA_BR_NF_CALL_ARPTABLES,
307 Self::VlanStatsEnabled(_) => IFLA_BR_VLAN_STATS_ENABLED,
308 Self::MulticastStatsEnabled(_) => IFLA_BR_MCAST_STATS_ENABLED,
309 Self::MulticastIgmpVersion(_) => IFLA_BR_MCAST_IGMP_VERSION,
310 Self::MulticastMldVersion(_) => IFLA_BR_MCAST_MLD_VERSION,
311 Self::VlanStatsPerPort(_) => IFLA_BR_VLAN_STATS_PER_PORT,
312 Self::MultiBoolOpt(_) => IFLA_BR_MULTI_BOOLOPT,
313 Self::MulticastQuerierState(_) => {
314 IFLA_BR_MCAST_QUERIER_STATE | NLA_F_NESTED
315 }
316 Self::FdbNLearned(_) => IFLA_BR_FDB_N_LEARNED,
317 Self::FdbMaxLearned(_) => IFLA_BR_FDB_MAX_LEARNED,
318 Self::Other(nla) => nla.kind(),
319 }
320 }
321}
322
323impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBridge {
324 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
325 let payload = buf.value();
326 Ok(match buf.kind() {
327 IFLA_BR_FDB_FLUSH => Self::FdbFlush,
328 IFLA_BR_HELLO_TIMER => Self::HelloTimer(
329 parse_u64(payload)
330 .context("invalid IFLA_BR_HELLO_TIMER value")?,
331 ),
332 IFLA_BR_TCN_TIMER => Self::TcnTimer(
333 parse_u64(payload)
334 .context("invalid IFLA_BR_TCN_TIMER value")?,
335 ),
336 IFLA_BR_TOPOLOGY_CHANGE_TIMER => Self::TopologyChangeTimer(
337 parse_u64(payload)
338 .context("invalid IFLA_BR_TOPOLOGY_CHANGE_TIMER value")?,
339 ),
340 IFLA_BR_GC_TIMER => Self::GcTimer(
341 parse_u64(payload).context("invalid IFLA_BR_GC_TIMER value")?,
342 ),
343 IFLA_BR_MCAST_LAST_MEMBER_INTVL => {
344 Self::MulticastLastMemberInterval(
345 parse_u64(payload).context(
346 "invalid IFLA_BR_MCAST_LAST_MEMBER_INTVL value",
347 )?,
348 )
349 }
350 IFLA_BR_MCAST_MEMBERSHIP_INTVL => {
351 Self::MulticastMembershipInterval(
352 parse_u64(payload).context(
353 "invalid IFLA_BR_MCAST_MEMBERSHIP_INTVL value",
354 )?,
355 )
356 }
357 IFLA_BR_MCAST_QUERIER_INTVL => Self::MulticastQuerierInterval(
358 parse_u64(payload)
359 .context("invalid IFLA_BR_MCAST_QUERIER_INTVL value")?,
360 ),
361 IFLA_BR_MCAST_QUERY_INTVL => Self::MulticastQueryInterval(
362 parse_u64(payload)
363 .context("invalid IFLA_BR_MCAST_QUERY_INTVL value")?,
364 ),
365 IFLA_BR_MCAST_QUERY_RESPONSE_INTVL => {
366 Self::MulticastQueryResponseInterval(
367 parse_u64(payload).context(
368 "invalid IFLA_BR_MCAST_QUERY_RESPONSE_INTVL value",
369 )?,
370 )
371 }
372 IFLA_BR_MCAST_STARTUP_QUERY_INTVL => {
373 Self::MulticastStartupQueryInterval(
374 parse_u64(payload).context(
375 "invalid IFLA_BR_MCAST_STARTUP_QUERY_INTVL value",
376 )?,
377 )
378 }
379 IFLA_BR_FORWARD_DELAY => Self::ForwardDelay(
380 parse_u32(payload)
381 .context("invalid IFLA_BR_FORWARD_DELAY value")?,
382 ),
383 IFLA_BR_HELLO_TIME => Self::HelloTime(
384 parse_u32(payload)
385 .context("invalid IFLA_BR_HELLO_TIME value")?,
386 ),
387 IFLA_BR_MAX_AGE => Self::MaxAge(
388 parse_u32(payload).context("invalid IFLA_BR_MAX_AGE value")?,
389 ),
390 IFLA_BR_AGEING_TIME => Self::AgeingTime(
391 parse_u32(payload)
392 .context("invalid IFLA_BR_AGEING_TIME value")?,
393 ),
394 IFLA_BR_STP_STATE => Self::StpState(
395 parse_u32(payload)
396 .context("invalid IFLA_BR_STP_STATE value")?
397 .into(),
398 ),
399 IFLA_BR_MCAST_HASH_ELASTICITY => Self::MulticastHashElasticity(
400 parse_u32(payload)
401 .context("invalid IFLA_BR_MCAST_HASH_ELASTICITY value")?,
402 ),
403 IFLA_BR_MCAST_HASH_MAX => Self::MulticastHashMax(
404 parse_u32(payload)
405 .context("invalid IFLA_BR_MCAST_HASH_MAX value")?,
406 ),
407 IFLA_BR_MCAST_LAST_MEMBER_CNT => Self::MulticastLastMemberCount(
408 parse_u32(payload)
409 .context("invalid IFLA_BR_MCAST_LAST_MEMBER_CNT value")?,
410 ),
411 IFLA_BR_MCAST_STARTUP_QUERY_CNT => {
412 Self::MulticastStartupQueryCount(
413 parse_u32(payload).context(
414 "invalid IFLA_BR_MCAST_STARTUP_QUERY_CNT value",
415 )?,
416 )
417 }
418 IFLA_BR_ROOT_PATH_COST => Self::RootPathCost(
419 parse_u32(payload)
420 .context("invalid IFLA_BR_ROOT_PATH_COST value")?,
421 ),
422 IFLA_BR_PRIORITY => Self::Priority(
423 parse_u16(payload).context("invalid IFLA_BR_PRIORITY value")?,
424 ),
425 IFLA_BR_VLAN_PROTOCOL => Self::VlanProtocol(
426 parse_u16_be(payload)
427 .context("invalid IFLA_BR_VLAN_PROTOCOL value")?
428 .into(),
429 ),
430 IFLA_BR_GROUP_FWD_MASK => Self::GroupFwdMask(
431 parse_u16(payload)
432 .context("invalid IFLA_BR_GROUP_FWD_MASK value")?,
433 ),
434 IFLA_BR_ROOT_ID => Self::RootId(
435 BridgeId::parse(&BridgeIdBuffer::new(payload))
436 .context("invalid IFLA_BR_ROOT_ID value")?,
437 ),
438 IFLA_BR_BRIDGE_ID => Self::BridgeId(
439 BridgeId::parse(&BridgeIdBuffer::new(payload))
440 .context("invalid IFLA_BR_BRIDGE_ID value")?,
441 ),
442 IFLA_BR_GROUP_ADDR => Self::GroupAddr(
443 parse_mac(payload)
444 .context("invalid IFLA_BR_GROUP_ADDR value")?,
445 ),
446 IFLA_BR_ROOT_PORT => Self::RootPort(
447 parse_u16(payload)
448 .context("invalid IFLA_BR_ROOT_PORT value")?,
449 ),
450 IFLA_BR_VLAN_DEFAULT_PVID => Self::VlanDefaultPvid(
451 parse_u16(payload)
452 .context("invalid IFLA_BR_VLAN_DEFAULT_PVID value")?,
453 ),
454 IFLA_BR_VLAN_FILTERING => Self::VlanFiltering(
455 parse_u8(payload)
456 .context("invalid IFLA_BR_VLAN_FILTERING value")?
457 > 0,
458 ),
459 IFLA_BR_TOPOLOGY_CHANGE => Self::TopologyChange(
460 parse_u8(payload)
461 .context("invalid IFLA_BR_TOPOLOGY_CHANGE value")?,
462 ),
463 IFLA_BR_TOPOLOGY_CHANGE_DETECTED => {
464 Self::TopologyChangeDetected(parse_u8(payload).context(
465 "invalid IFLA_BR_TOPOLOGY_CHANGE_DETECTED value",
466 )?)
467 }
468 IFLA_BR_MCAST_ROUTER => Self::MulticastRouter(
469 parse_u8(payload)
470 .context("invalid IFLA_BR_MCAST_ROUTER value")?
471 .into(),
472 ),
473 IFLA_BR_MCAST_SNOOPING => Self::MulticastSnooping(
474 parse_u8(payload)
475 .context("invalid IFLA_BR_MCAST_SNOOPING value")?
476 > 0,
477 ),
478 IFLA_BR_MCAST_QUERY_USE_IFADDR => Self::MulticastQueryUseIfaddr(
479 parse_u8(payload)
480 .context("invalid IFLA_BR_MCAST_QUERY_USE_IFADDR value")?
481 > 0,
482 ),
483 IFLA_BR_MCAST_QUERIER => Self::MulticastQuerier(
484 parse_u8(payload)
485 .context("invalid IFLA_BR_MCAST_QUERIER value")?
486 > 0,
487 ),
488 IFLA_BR_NF_CALL_IPTABLES => Self::NfCallIpTables(
489 parse_u8(payload)
490 .context("invalid IFLA_BR_NF_CALL_IPTABLES value")?
491 > 0,
492 ),
493 IFLA_BR_NF_CALL_IP6TABLES => Self::NfCallIp6Tables(
494 parse_u8(payload)
495 .context("invalid IFLA_BR_NF_CALL_IP6TABLES value")?
496 > 0,
497 ),
498 IFLA_BR_NF_CALL_ARPTABLES => Self::NfCallArpTables(
499 parse_u8(payload)
500 .context("invalid IFLA_BR_NF_CALL_ARPTABLES value")?
501 > 0,
502 ),
503 IFLA_BR_VLAN_STATS_ENABLED => Self::VlanStatsEnabled(
504 parse_u8(payload)
505 .context("invalid IFLA_BR_VLAN_STATS_ENABLED value")?
506 > 0,
507 ),
508 IFLA_BR_MCAST_STATS_ENABLED => Self::MulticastStatsEnabled(
509 parse_u8(payload)
510 .context("invalid IFLA_BR_MCAST_STATS_ENABLED value")?
511 > 0,
512 ),
513 IFLA_BR_MCAST_IGMP_VERSION => Self::MulticastIgmpVersion(
514 parse_u8(payload)
515 .context("invalid IFLA_BR_MCAST_IGMP_VERSION value")?,
516 ),
517 IFLA_BR_MCAST_MLD_VERSION => Self::MulticastMldVersion(
518 parse_u8(payload)
519 .context("invalid IFLA_BR_MCAST_MLD_VERSION value")?,
520 ),
521 IFLA_BR_VLAN_STATS_PER_PORT => Self::VlanStatsPerPort(
522 parse_u8(payload)
523 .context("invalid IFLA_BR_VLAN_STATS_PER_PORT value")?
524 > 0,
525 ),
526 IFLA_BR_MULTI_BOOLOPT => {
527 Self::MultiBoolOpt(BridgeBooleanOptions::parse(payload)?)
528 }
529 IFLA_BR_MCAST_QUERIER_STATE => {
530 let mut v = Vec::new();
531 let err = "failed to parse IFLA_BR_MCAST_QUERIER_STATE";
532 for nla in NlasIterator::new(payload) {
533 let nla = &nla.context(err)?;
534 let parsed = BridgeQuerierState::parse(nla).context(err)?;
535 v.push(parsed);
536 }
537 Self::MulticastQuerierState(v)
538 }
539 IFLA_BR_FDB_N_LEARNED => Self::FdbNLearned(
540 parse_u32(payload)
541 .context("invalid IFLA_BR_FDB_N_LEARNED value")?,
542 ),
543 IFLA_BR_FDB_MAX_LEARNED => Self::FdbMaxLearned(
544 parse_u32(payload)
545 .context("invalid IFLA_BR_FDB_MAX_LEARNED value")?,
546 ),
547 _ => Self::Other(DefaultNla::parse(buf).context(
548 "invalid link info bridge NLA value (unknown type)",
549 )?),
550 })
551 }
552}
553
554const BRIDGE_ID_LEN: usize = 8;
555
556#[derive(Debug, PartialEq, Eq, Clone)]
557pub struct BridgeId {
558 pub priority: u16,
559 pub address: [u8; 6],
560}
561
562buffer!(BridgeIdBuffer(BRIDGE_ID_LEN) {
563 priority: (u16, 0..2),
564 address: (slice, 2..BRIDGE_ID_LEN)
565});
566
567impl<T: AsRef<[u8]> + ?Sized> Parseable<BridgeIdBuffer<&T>> for BridgeId {
568 fn parse(buf: &BridgeIdBuffer<&T>) -> Result<Self, DecodeError> {
569 Ok(Self {
573 priority: u16::from_be(buf.priority()),
574 address: parse_mac(buf.address())
575 .context("invalid MAC address in BridgeId buffer")?,
576 })
577 }
578}
579
580impl Emitable for BridgeId {
581 fn buffer_len(&self) -> usize {
582 BRIDGE_ID_LEN
583 }
584
585 fn emit(&self, buffer: &mut [u8]) {
586 let mut buffer = BridgeIdBuffer::new(buffer);
587 buffer.set_priority(self.priority.to_be());
588 buffer.address_mut().copy_from_slice(&self.address[..]);
589 }
590}
591
592const BRIDGE_QUERIER_IP_ADDRESS: u16 = 1;
593const BRIDGE_QUERIER_IP_PORT: u16 = 2;
594const BRIDGE_QUERIER_IP_OTHER_TIMER: u16 = 3;
595const BRIDGE_QUERIER_IPV6_ADDRESS: u16 = 5;
597const BRIDGE_QUERIER_IPV6_PORT: u16 = 6;
598const BRIDGE_QUERIER_IPV6_OTHER_TIMER: u16 = 7;
599
600#[derive(Debug, Clone, Eq, PartialEq)]
601#[non_exhaustive]
602pub enum BridgeQuerierState {
603 Ipv4Address(Ipv4Addr),
604 Ipv4Port(u32),
605 Ipv4OtherTimer(u64),
606 Ipv6Address(Ipv6Addr),
607 Ipv6Port(u32),
608 Ipv6OtherTimer(u64),
609 Other(DefaultNla),
610}
611
612impl Nla for BridgeQuerierState {
613 fn value_len(&self) -> usize {
614 use self::BridgeQuerierState::*;
615 match self {
616 Ipv4Address(_) => 4,
617 Ipv6Address(_) => 16,
618 Ipv4Port(_) | Ipv6Port(_) => 4,
619 Ipv4OtherTimer(_) | Ipv6OtherTimer(_) => 8,
620 Other(nla) => nla.value_len(),
621 }
622 }
623
624 fn kind(&self) -> u16 {
625 use self::BridgeQuerierState::*;
626 match self {
627 Ipv4Address(_) => BRIDGE_QUERIER_IP_ADDRESS,
628 Ipv4Port(_) => BRIDGE_QUERIER_IP_PORT,
629 Ipv4OtherTimer(_) => BRIDGE_QUERIER_IP_OTHER_TIMER,
630 Ipv6Address(_) => BRIDGE_QUERIER_IPV6_ADDRESS,
631 Ipv6Port(_) => BRIDGE_QUERIER_IPV6_PORT,
632 Ipv6OtherTimer(_) => BRIDGE_QUERIER_IPV6_OTHER_TIMER,
633 Other(nla) => nla.kind(),
634 }
635 }
636
637 fn emit_value(&self, buffer: &mut [u8]) {
638 use self::BridgeQuerierState::*;
639 match self {
640 Ipv4Port(d) | Ipv6Port(d) => emit_u32(buffer, *d).unwrap(),
641 Ipv4OtherTimer(d) | Ipv6OtherTimer(d) => {
642 emit_u64(buffer, *d).unwrap()
643 }
644 Ipv4Address(addr) => buffer.copy_from_slice(&addr.octets()),
645 Ipv6Address(addr) => buffer.copy_from_slice(&addr.octets()),
646 Other(nla) => nla.emit_value(buffer),
647 }
648 }
649}
650
651impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
652 for BridgeQuerierState
653{
654 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
655 use self::BridgeQuerierState::*;
656 let payload = buf.value();
657 Ok(match buf.kind() {
658 BRIDGE_QUERIER_IP_ADDRESS => match parse_ip(payload) {
659 Ok(IpAddr::V4(addr)) => Ipv4Address(addr),
660 Ok(v) => {
661 return Err(DecodeError::from(format!(
662 "Invalid BRIDGE_QUERIER_IP_ADDRESS, expecting IPv4 \
663 address, but got {v}"
664 )))
665 }
666 Err(e) => {
667 return Err(DecodeError::from(format!(
668 "Invalid BRIDGE_QUERIER_IP_ADDRESS {e}"
669 )))
670 }
671 },
672 BRIDGE_QUERIER_IPV6_ADDRESS => match parse_ip(payload) {
673 Ok(IpAddr::V6(addr)) => Ipv6Address(addr),
674 Ok(v) => {
675 return Err(DecodeError::from(format!(
676 "Invalid BRIDGE_QUERIER_IPV6_ADDRESS, expecting IPv6 \
677 address, but got {v}"
678 )));
679 }
680 Err(e) => {
681 return Err(DecodeError::from(format!(
682 "Invalid BRIDGE_QUERIER_IPV6_ADDRESS {e}"
683 )));
684 }
685 },
686 BRIDGE_QUERIER_IP_PORT => Ipv4Port(
687 parse_u32(payload)
688 .context("invalid BRIDGE_QUERIER_IP_PORT value")?,
689 ),
690 BRIDGE_QUERIER_IPV6_PORT => Ipv6Port(
691 parse_u32(payload)
692 .context("invalid BRIDGE_QUERIER_IPV6_PORT value")?,
693 ),
694 BRIDGE_QUERIER_IP_OTHER_TIMER => Ipv4OtherTimer(
695 parse_u64(payload)
696 .context("invalid BRIDGE_QUERIER_IP_OTHER_TIMER value")?,
697 ),
698 BRIDGE_QUERIER_IPV6_OTHER_TIMER => Ipv6OtherTimer(
699 parse_u64(payload)
700 .context("invalid BRIDGE_QUERIER_IPV6_OTHER_TIMER value")?,
701 ),
702
703 kind => Other(
704 DefaultNla::parse(buf)
705 .context(format!("unknown NLA type {kind}"))?,
706 ),
707 })
708 }
709}
710
711const BR_NO_STP: u32 = 0;
712const BR_KERNEL_STP: u32 = 1;
713const BR_USER_STP: u32 = 2;
714
715#[derive(Debug, PartialEq, Eq, Clone, Copy)]
716#[non_exhaustive]
717pub enum BridgeStpState {
718 Disabled,
719 KernelStp,
720 UserStp,
721 Other(u32),
722}
723
724impl From<u32> for BridgeStpState {
725 fn from(d: u32) -> Self {
726 match d {
727 BR_NO_STP => Self::Disabled,
728 BR_KERNEL_STP => Self::KernelStp,
729 BR_USER_STP => Self::UserStp,
730 _ => Self::Other(d),
731 }
732 }
733}
734
735impl From<BridgeStpState> for u32 {
736 fn from(v: BridgeStpState) -> u32 {
737 match v {
738 BridgeStpState::Disabled => BR_NO_STP,
739 BridgeStpState::KernelStp => BR_KERNEL_STP,
740 BridgeStpState::UserStp => BR_USER_STP,
741 BridgeStpState::Other(d) => d,
742 }
743 }
744}
745
746const MDB_RTR_TYPE_DISABLED: u8 = 0;
747const MDB_RTR_TYPE_TEMP_QUERY: u8 = 1;
748const MDB_RTR_TYPE_PERM: u8 = 2;
749const MDB_RTR_TYPE_TEMP: u8 = 3;
750
751#[derive(Debug, PartialEq, Eq, Clone, Copy)]
752#[non_exhaustive]
753pub enum BridgeMulticastRouterType {
754 Disabled,
755 TempQuery,
756 Permanent,
757 Temp,
758 Other(u8),
759}
760
761impl BridgeMulticastRouterType {
762 #[allow(non_upper_case_globals)]
764 pub const Auto: Self = Self::TempQuery;
765}
766
767impl From<u8> for BridgeMulticastRouterType {
768 fn from(d: u8) -> Self {
769 match d {
770 MDB_RTR_TYPE_DISABLED => Self::Disabled,
771 MDB_RTR_TYPE_TEMP_QUERY => Self::TempQuery,
772 MDB_RTR_TYPE_PERM => Self::Permanent,
773 MDB_RTR_TYPE_TEMP => Self::Temp,
774 _ => Self::Other(d),
775 }
776 }
777}
778
779impl From<BridgeMulticastRouterType> for u8 {
780 fn from(v: BridgeMulticastRouterType) -> u8 {
781 match v {
782 BridgeMulticastRouterType::Disabled => MDB_RTR_TYPE_DISABLED,
783 BridgeMulticastRouterType::TempQuery => MDB_RTR_TYPE_TEMP_QUERY,
784 BridgeMulticastRouterType::Permanent => MDB_RTR_TYPE_PERM,
785 BridgeMulticastRouterType::Temp => MDB_RTR_TYPE_TEMP,
786 BridgeMulticastRouterType::Other(d) => d,
787 }
788 }
789}