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