Skip to content

Commit fb497b3

Browse files
ihuguetcathay4t
authored andcommitted
link: use struct BridgeId instead of tuple and fix its endianess
The bridge ID defined by attributes BRIDGE_ID and ROOT_ID, both in bridge and bridge_port, contains a priority field and the MAC address. Use a named struct to show the meaning of these fields instead of using a tuple. Also, fix the endianess of the priority field. The kernel uses a `u8 prio[2]` field instead of `u16`, with the first byte being the highest order byte. See: https://elixir.bootlin.com/linux/v6.6.9/source/net/bridge/br_netlink.c#L1633 Note: to make the file bridge.rs to be well organized, moved the definition of BRIDGE_QUERIER_* close to BridgeQuerierState where it's used. Signed-off-by: Íñigo Huguet <[email protected]>
1 parent faffa52 commit fb497b3

File tree

5 files changed

+105
-94
lines changed

5 files changed

+105
-94
lines changed

src/link/link_info/bridge.rs

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@ use netlink_packet_utils::{
1414
DecodeError,
1515
};
1616

17-
const BRIDGE_QUERIER_IP_ADDRESS: u16 = 1;
18-
const BRIDGE_QUERIER_IP_PORT: u16 = 2;
19-
const BRIDGE_QUERIER_IP_OTHER_TIMER: u16 = 3;
20-
// const BRIDGE_QUERIER_PAD: u16 = 4;
21-
const BRIDGE_QUERIER_IPV6_ADDRESS: u16 = 5;
22-
const BRIDGE_QUERIER_IPV6_PORT: u16 = 6;
23-
const BRIDGE_QUERIER_IPV6_OTHER_TIMER: u16 = 7;
24-
2517
const IFLA_BR_FORWARD_DELAY: u16 = 1;
2618
const IFLA_BR_HELLO_TIME: u16 = 2;
2719
const IFLA_BR_MAX_AGE: u16 = 3;
@@ -98,8 +90,8 @@ pub enum InfoBridge {
9890
Priority(u16),
9991
VlanProtocol(u16),
10092
GroupFwdMask(u16),
101-
RootId((u16, [u8; 6])),
102-
BridgeId((u16, [u8; 6])),
93+
RootId(BridgeId),
94+
BridgeId(BridgeId),
10395
RootPort(u16),
10496
VlanDefaultPvid(u16),
10597
VlanFiltering(u8),
@@ -219,10 +211,8 @@ impl Nla for InfoBridge {
219211

220212
Self::VlanProtocol(value) => BigEndian::write_u16(buffer, *value),
221213

222-
Self::RootId((priority, ref address))
223-
| Self::BridgeId((priority, ref address)) => {
224-
NativeEndian::write_u16(buffer, *priority);
225-
buffer[2..].copy_from_slice(&address[..]);
214+
Self::RootId(bridge_id) | Self::BridgeId(bridge_id) => {
215+
bridge_id.emit(buffer)
226216
}
227217

228218
Self::GroupAddr(value) => buffer.copy_from_slice(&value[..]),
@@ -423,25 +413,14 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBridge {
423413
parse_u16(payload)
424414
.context("invalid IFLA_BR_GROUP_FWD_MASK value")?,
425415
),
426-
IFLA_BR_ROOT_ID | IFLA_BR_BRIDGE_ID => {
427-
if payload.len() != 8 {
428-
return Err(
429-
"invalid IFLA_BR_ROOT_ID or IFLA_BR_BRIDGE_ID value"
430-
.into(),
431-
);
432-
}
433-
434-
let priority = NativeEndian::read_u16(&payload[..2]);
435-
let address = parse_mac(&payload[2..]).context(
436-
"invalid IFLA_BR_ROOT_ID or IFLA_BR_BRIDGE_ID value",
437-
)?;
438-
439-
match buf.kind() {
440-
IFLA_BR_ROOT_ID => Self::RootId((priority, address)),
441-
IFLA_BR_BRIDGE_ID => Self::BridgeId((priority, address)),
442-
_ => unreachable!(),
443-
}
444-
}
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+
),
445424
IFLA_BR_GROUP_ADDR => Self::GroupAddr(
446425
parse_mac(payload)
447426
.context("invalid IFLA_BR_GROUP_ADDR value")?,
@@ -536,6 +515,52 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBridge {
536515
}
537516
}
538517

518+
const BRIDGE_ID_LEN: usize = 8;
519+
520+
#[derive(Debug, PartialEq, Eq, Clone)]
521+
pub struct BridgeId {
522+
pub priority: u16,
523+
pub address: [u8; 6],
524+
}
525+
526+
buffer!(BridgeIdBuffer(BRIDGE_ID_LEN) {
527+
priority: (u16, 0..2),
528+
address: (slice, 2..BRIDGE_ID_LEN)
529+
});
530+
531+
impl<T: AsRef<[u8]> + ?Sized> Parseable<BridgeIdBuffer<&T>> for BridgeId {
532+
fn parse(buf: &BridgeIdBuffer<&T>) -> Result<Self, DecodeError> {
533+
// Priority is encoded in big endian. From kernel's
534+
// net/bridge/br_netlink.c br_fill_info():
535+
// u16 priority = (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1];
536+
Ok(Self {
537+
priority: u16::from_be(buf.priority()),
538+
address: parse_mac(buf.address())
539+
.context("invalid MAC address in BridgeId buffer")?,
540+
})
541+
}
542+
}
543+
544+
impl Emitable for BridgeId {
545+
fn buffer_len(&self) -> usize {
546+
BRIDGE_ID_LEN
547+
}
548+
549+
fn emit(&self, buffer: &mut [u8]) {
550+
let mut buffer = BridgeIdBuffer::new(buffer);
551+
buffer.set_priority(self.priority.to_be());
552+
buffer.address_mut().copy_from_slice(&self.address[..]);
553+
}
554+
}
555+
556+
const BRIDGE_QUERIER_IP_ADDRESS: u16 = 1;
557+
const BRIDGE_QUERIER_IP_PORT: u16 = 2;
558+
const BRIDGE_QUERIER_IP_OTHER_TIMER: u16 = 3;
559+
// const BRIDGE_QUERIER_PAD: u16 = 4;
560+
const BRIDGE_QUERIER_IPV6_ADDRESS: u16 = 5;
561+
const BRIDGE_QUERIER_IPV6_PORT: u16 = 6;
562+
const BRIDGE_QUERIER_IPV6_OTHER_TIMER: u16 = 7;
563+
539564
#[derive(Debug, Clone, Eq, PartialEq)]
540565
#[non_exhaustive]
541566
pub enum BridgeQuerierState {

src/link/link_info/bridge_port.rs

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// SPDX-License-Identifier: MIT
2+
use crate::link::{BridgeId, BridgeIdBuffer};
23
use anyhow::Context;
34
use byteorder::{ByteOrder, NativeEndian};
45
use netlink_packet_utils::{
56
nla::{DefaultNla, Nla, NlaBuffer},
6-
parsers::{parse_mac, parse_u16, parse_u32, parse_u64, parse_u8},
7-
traits::Parseable,
7+
parsers::{parse_u16, parse_u32, parse_u64, parse_u8},
8+
traits::{Emitable, Parseable},
89
DecodeError,
910
};
1011

@@ -68,8 +69,8 @@ pub enum InfoBridgePort {
6869
UnicastFlood(bool),
6970
ProxyARP(bool),
7071
ProxyARPWifi(bool),
71-
RootId((u16, [u8; 6])),
72-
BridgeId((u16, [u8; 6])),
72+
RootId(BridgeId),
73+
BridgeId(BridgeId),
7374
DesignatedPort(u16),
7475
DesignatedCost(u16),
7576
PortId(u16),
@@ -199,11 +200,8 @@ impl Nla for InfoBridgePort {
199200
| InfoBridgePort::HoldTimer(value) => {
200201
NativeEndian::write_u64(buffer, *value)
201202
}
202-
InfoBridgePort::RootId((prio, addr))
203-
| InfoBridgePort::BridgeId((prio, addr)) => {
204-
NativeEndian::write_u16(buffer, *prio);
205-
buffer[2..].copy_from_slice(&addr[..]);
206-
}
203+
InfoBridgePort::RootId(bridge_id)
204+
| InfoBridgePort::BridgeId(bridge_id) => bridge_id.emit(buffer),
207205
InfoBridgePort::State(state) => buffer[0] = (*state).into(),
208206
InfoBridgePort::MulticastRouter(mcast_router) => {
209207
buffer[0] = (*mcast_router).into()
@@ -339,32 +337,16 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
339337
format!("invalid IFLA_BRPORT_PROXYARP_WIFI {payload:?}")
340338
})? > 0,
341339
),
342-
IFLA_BRPORT_ROOT_ID => {
343-
if payload.len() != 8 {
344-
return Err(format!(
345-
"invalid IFLA_BRPORT_ROOT_ID {payload:?}"
346-
)
347-
.into());
348-
}
349-
let prio = NativeEndian::read_u16(&payload[0..2]);
350-
let addr = parse_mac(&payload[2..]).with_context(|| {
340+
IFLA_BRPORT_ROOT_ID => Self::RootId(
341+
BridgeId::parse(&BridgeIdBuffer::new(payload)).with_context(|| {
351342
format!("invalid IFLA_BRPORT_ROOT_ID {payload:?}")
352-
})?;
353-
InfoBridgePort::RootId((prio, addr))
354-
}
355-
IFLA_BRPORT_BRIDGE_ID => {
356-
if payload.len() != 8 {
357-
return Err(format!(
358-
"invalid IFLA_BRPORT_BRIDGE_ID {payload:?}"
359-
)
360-
.into());
361-
}
362-
let prio = NativeEndian::read_u16(&payload[0..2]);
363-
let addr = parse_mac(&payload[2..]).with_context(|| {
343+
})?,
344+
),
345+
IFLA_BRPORT_BRIDGE_ID => Self::BridgeId(
346+
BridgeId::parse(&BridgeIdBuffer::new(payload)).with_context(|| {
364347
format!("invalid IFLA_BRPORT_BRIDGE_ID {payload:?}")
365-
})?;
366-
InfoBridgePort::BridgeId((prio, addr))
367-
}
348+
})?,
349+
),
368350
IFLA_BRPORT_DESIGNATED_PORT => InfoBridgePort::DesignatedPort(
369351
parse_u16(payload).with_context(|| {
370352
format!("invalid IFLA_BRPORT_DESIGNATED_PORT {payload:?}")

src/link/link_info/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ mod xstats;
2929

3030
pub use self::bond::{BondAdInfo, InfoBond};
3131
pub use self::bond_port::{BondPortState, InfoBondPort, MiiStatus};
32-
pub use self::bridge::{BridgeQuerierState, InfoBridge};
32+
pub use self::bridge::{
33+
BridgeId, BridgeIdBuffer, BridgeQuerierState, InfoBridge,
34+
};
3335
pub use self::bridge_port::{
3436
BridgePortMulticastRouter, BridgePortState, InfoBridgePort,
3537
};

src/link/mod.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ pub use self::ext_mask::LinkExtentMask;
3838
pub use self::header::{LinkHeader, LinkMessageBuffer};
3939
pub use self::link_flag::LinkFlag;
4040
pub use self::link_info::{
41-
BondAdInfo, BondPortState, BridgePortMulticastRouter, BridgePortState,
42-
BridgeQuerierState, HsrProtocol, InfoBond, InfoBondPort, InfoBridge,
43-
InfoBridgePort, InfoData, InfoGreTap, InfoGreTap6, InfoGreTun, InfoGreTun6,
44-
InfoGtp, InfoHsr, InfoIpVlan, InfoIpoib, InfoKind, InfoMacSec, InfoMacVlan,
45-
InfoMacVtap, InfoPortData, InfoPortKind, InfoSitTun, InfoTun, InfoVeth,
46-
InfoVlan, InfoVrf, InfoVti, InfoVxlan, InfoXfrm, LinkInfo, LinkXstats,
41+
BondAdInfo, BondPortState, BridgeId, BridgeIdBuffer,
42+
BridgePortMulticastRouter, BridgePortState, BridgeQuerierState,
43+
HsrProtocol, InfoBond, InfoBondPort, InfoBridge, InfoBridgePort, InfoData,
44+
InfoGreTap, InfoGreTap6, InfoGreTun, InfoGreTun6, InfoGtp, InfoHsr,
45+
InfoIpVlan, InfoIpoib, InfoKind, InfoMacSec, InfoMacVlan, InfoMacVtap,
46+
InfoPortData, InfoPortKind, InfoSitTun, InfoTun, InfoVeth, InfoVlan,
47+
InfoVrf, InfoVti, InfoVxlan, InfoXfrm, LinkInfo, LinkXstats,
4748
MacSecCipherId, MacSecOffload, MacSecValidate, MiiStatus, VlanQosMapping,
4849
};
4950
pub use self::link_layer_type::LinkLayerType;

src/link/tests/bridge.rs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ use netlink_packet_utils::{
77

88
use crate::link::{
99
af_spec::VecAfSpecBridge, AfSpecBridge, AfSpecInet, AfSpecInet6,
10-
AfSpecUnspec, BridgePortMulticastRouter, BridgePortState, BridgeVlanInfo,
11-
Inet6CacheInfo, Inet6DevConf, Inet6IfaceFlag, Inet6IfaceFlags, InetDevConf,
12-
InfoBridge, InfoBridgePort, InfoData, InfoKind, InfoPortData, InfoPortKind,
13-
LinkAttribute, LinkFlag, LinkHeader, LinkInfo, LinkLayerType, LinkMessage,
14-
LinkMessageBuffer, LinkXdp, Map, State, Stats, Stats64, XdpAttached,
10+
AfSpecUnspec, BridgeId, BridgePortMulticastRouter, BridgePortState,
11+
BridgeVlanInfo, Inet6CacheInfo, Inet6DevConf, Inet6IfaceFlag,
12+
Inet6IfaceFlags, InetDevConf, InfoBridge, InfoBridgePort, InfoData,
13+
InfoKind, InfoPortData, InfoPortKind, LinkAttribute, LinkFlag, LinkHeader,
14+
LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, LinkXdp, Map,
15+
State, Stats, Stats64, XdpAttached,
1516
};
1617
use crate::AddressFamily;
1718

@@ -260,14 +261,14 @@ fn test_parse_link_bridge_no_extention_mask() {
260261
InfoBridge::Priority(32768),
261262
InfoBridge::VlanFiltering(0),
262263
InfoBridge::GroupFwdMask(0),
263-
InfoBridge::BridgeId((
264-
0x0080, // iproute is showing it as 0x8000
265-
[0x00, 0x23, 0x45, 0x67, 0x89, 0x1c],
266-
)),
267-
InfoBridge::RootId((
268-
0x0080, // iproute is showing it as 0x8000
269-
[0x00, 0x23, 0x45, 0x67, 0x89, 0x1c],
270-
)),
264+
InfoBridge::BridgeId(BridgeId {
265+
priority: 0x8000,
266+
address: [0x00, 0x23, 0x45, 0x67, 0x89, 0x1c],
267+
}),
268+
InfoBridge::RootId(BridgeId {
269+
priority: 0x8000,
270+
address: [0x00, 0x23, 0x45, 0x67, 0x89, 0x1c],
271+
}),
271272
InfoBridge::RootPort(0),
272273
InfoBridge::RootPathCost(0),
273274
InfoBridge::TopologyChange(0),
@@ -513,14 +514,14 @@ fn test_bridge_port_link_info() {
513514
InfoBridgePort::BroadcastFlood(true),
514515
InfoBridgePort::ProxyARP(false),
515516
InfoBridgePort::ProxyARPWifi(false),
516-
InfoBridgePort::RootId((
517-
0x0080,
518-
[0x52, 0x54, 0x00, 0xde, 0x0d, 0x2e],
519-
)),
520-
InfoBridgePort::BridgeId((
521-
0x0080,
522-
[0x52, 0x54, 0x00, 0xde, 0x0d, 0x2e],
523-
)),
517+
InfoBridgePort::RootId(BridgeId {
518+
priority: 0x8000,
519+
address: [0x52, 0x54, 0x00, 0xde, 0x0d, 0x2e],
520+
}),
521+
InfoBridgePort::BridgeId(BridgeId {
522+
priority: 0x8000,
523+
address: [0x52, 0x54, 0x00, 0xde, 0x0d, 0x2e],
524+
}),
524525
InfoBridgePort::DesignatedPort(32769),
525526
InfoBridgePort::DesignatedCost(0),
526527
InfoBridgePort::PortId(32769),

0 commit comments

Comments
 (0)