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