From 68d3011592a2d011a3a29c438713f6ab4269c9a5 Mon Sep 17 00:00:00 2001 From: Gris Ge Date: Wed, 31 Dec 2025 22:35:54 +0800 Subject: [PATCH] link: Support changing VLAN filter of bridge itself Mimicking command `bridge vlan add dev br0 vid 11 self` by introducing `LinkBridgeVlan::bridge_self()`. Example code updated and manually tested. Signed-off-by: Gris Ge --- examples/set_bridge_vlan.rs | 36 +++++++++++++++++++++++++++--------- src/link/bridge_vlan.rs | 9 ++++++++- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/examples/set_bridge_vlan.rs b/examples/set_bridge_vlan.rs index c5d520e..f63e403 100644 --- a/examples/set_bridge_vlan.rs +++ b/examples/set_bridge_vlan.rs @@ -72,6 +72,7 @@ async fn create_dummy_and_attach_to_bridge( async fn set_bridge_vlan( handle: &Handle, + bridge_index: u32, port_index: u32, ) -> Result<(), rtnetlink::Error> { let message = LinkBridgeVlan::new(port_index) @@ -81,6 +82,16 @@ async fn set_bridge_vlan( .build(); handle.link().set(message).execute().await?; + + let message = LinkBridgeVlan::new(bridge_index) + .bridge_self() + .vlan(40, BridgeVlanInfoFlags::Pvid) + .vlan_range_start(50, BridgeVlanInfoFlags::empty()) + .vlan_range_end(60, BridgeVlanInfoFlags::empty()) + .build(); + + handle.link().set(message).execute().await?; + Ok(()) } @@ -93,7 +104,7 @@ async fn main() -> Result<(), Box> { let port_index = create_dummy_and_attach_to_bridge(&handle, bridge_index).await?; - set_bridge_vlan(&handle, port_index).await?; + set_bridge_vlan(&handle, bridge_index, port_index).await?; let mut dump_link = handle .link() @@ -106,17 +117,24 @@ async fn main() -> Result<(), Box> { while let Some(link_msg) = dump_link.try_next().await? { // With set_filter_mask(), we cannot use match_name to filter due to // linux kernel limitation. - if !link_msg.attributes.as_slice().iter().any( - |a| matches!(a, LinkAttribute::IfName(name) if name == "my-dummy0"), - ) { + let iface_name = if let Some(name) = + link_msg.attributes.iter().find_map(|attr| match attr { + LinkAttribute::IfName(name) + if name == "my-dummy0" || name == "my-bridge0" => + { + Some(name) + } + _ => None, + }) { + name + } else { continue; - } - for nla in link_msg.attributes { + }; + for nla in &link_msg.attributes { if let LinkAttribute::AfSpecBridge(i) = &nla { - println!("{:?}", i); - return Ok(()); + println!("Interface {iface_name}: {i:?}"); } } } - Err("failed to find bridge vlan info for my-dummy0".into()) + Ok(()) } diff --git a/src/link/bridge_vlan.rs b/src/link/bridge_vlan.rs index a278dab..ba3a6df 100644 --- a/src/link/bridge_vlan.rs +++ b/src/link/bridge_vlan.rs @@ -3,7 +3,8 @@ use crate::{ packet_route::{ link::{ - AfSpecBridge, BridgeVlanInfo, BridgeVlanInfoFlags, LinkAttribute, + AfSpecBridge, BridgeFlag, BridgeVlanInfo, BridgeVlanInfoFlags, + LinkAttribute, }, AddressFamily, }, @@ -58,4 +59,10 @@ impl LinkMessageBuilder { pub fn vlan_range_end(self, vid: u16, flags: BridgeVlanInfoFlags) -> Self { self.vlan(vid, flags | BridgeVlanInfoFlags::RangeEnd) } + + /// Change VLAN of bridge itself + /// Equal to the `self` argument in `bridge vlan add dev br0 vid 11 self` + pub fn bridge_self(self) -> Self { + self.append_af_spec(AfSpecBridge::Flags(BridgeFlag::LowerDev)) + } }