From 03ca6ddac0f2380405cdc6fa2b8cc17778bcdb6d Mon Sep 17 00:00:00 2001 From: Gris Ge Date: Thu, 1 Jan 2026 09:55:19 +0800 Subject: [PATCH] link: Support specifying arbitrary LinkMessage for `RTM_DELLINK` In order to support deleting bridge VLAN information, this patch introduced `LinkHandle::del_with_message()` allowing sending arbitrary LinkMessage for the `RTM_DELLINK` call. Example code updated with bridge VLAN deletion function. Signed-off-by: Gris Ge --- examples/set_bridge_vlan.rs | 78 +++++++++++++++++++++++++++++++------ src/link/del.rs | 4 ++ src/link/handle.rs | 11 +++++- 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/examples/set_bridge_vlan.rs b/examples/set_bridge_vlan.rs index f63e403..2b253bb 100644 --- a/examples/set_bridge_vlan.rs +++ b/examples/set_bridge_vlan.rs @@ -95,17 +95,9 @@ async fn set_bridge_vlan( Ok(()) } -#[tokio::main] -async fn main() -> Result<(), Box> { - let (connection, handle, _) = new_connection().unwrap(); - tokio::spawn(connection); - - let bridge_index = create_bridge_and_get_index(&handle).await?; - - let port_index = - create_dummy_and_attach_to_bridge(&handle, bridge_index).await?; - set_bridge_vlan(&handle, bridge_index, port_index).await?; - +async fn dump_bridge_vlan( + handle: &rtnetlink::Handle, +) -> Result<(), rtnetlink::Error> { let mut dump_link = handle .link() .get() @@ -138,3 +130,67 @@ async fn main() -> Result<(), Box> { } Ok(()) } + +async fn del_bridge_vlan( + handle: &Handle, + bridge_index: u32, + port_index: u32, +) -> Result<(), rtnetlink::Error> { + let message = LinkBridgeVlan::new(port_index) + .vlan(10, BridgeVlanInfoFlags::Pvid) + .vlan_range_start(20, BridgeVlanInfoFlags::empty()) + .vlan_range_end(30, BridgeVlanInfoFlags::empty()) + .build(); + + handle.link().del_with_message(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().del_with_message(message).execute().await?; + + Ok(()) +} + +async fn cleanup( + handle: &Handle, + bridge_index: u32, + port_index: u32, +) -> Result<(), rtnetlink::Error> { + handle.link().del(bridge_index).execute().await?; + handle.link().del(port_index).execute().await?; + + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let (connection, handle, _) = new_connection().unwrap(); + tokio::spawn(connection); + + let bridge_index = create_bridge_and_get_index(&handle).await?; + + let port_index = + create_dummy_and_attach_to_bridge(&handle, bridge_index).await?; + + println!("Setting Bridge VLAN"); + set_bridge_vlan(&handle, bridge_index, port_index).await?; + + dump_bridge_vlan(&handle).await?; + + println!("Removing Bridge VLAN"); + + del_bridge_vlan(&handle, bridge_index, port_index).await?; + + dump_bridge_vlan(&handle).await?; + + println!("Cleaning up"); + + cleanup(&handle, bridge_index, port_index).await?; + + Ok(()) +} diff --git a/src/link/del.rs b/src/link/del.rs index d746cca..e3c4805 100644 --- a/src/link/del.rs +++ b/src/link/del.rs @@ -18,6 +18,10 @@ impl LinkDelRequest { LinkDelRequest { handle, message } } + pub fn new_with_message(handle: Handle, message: LinkMessage) -> Self { + LinkDelRequest { handle, message } + } + /// Execute the request pub async fn execute(self) -> Result<(), Error> { let LinkDelRequest { diff --git a/src/link/handle.rs b/src/link/handle.rs index 43a790d..e60a59a 100644 --- a/src/link/handle.rs +++ b/src/link/handle.rs @@ -43,12 +43,19 @@ impl LinkHandle { LinkDelPropRequest::new(self.0.clone(), index) } - pub fn del(&mut self, index: u32) -> LinkDelRequest { + pub fn del(&self, index: u32) -> LinkDelRequest { LinkDelRequest::new(self.0.clone(), index) } + /// Delete specified information from interface. + /// For example: To delete bridge VLANs, it is required to include + /// LinkMessage of VLAN information to delete. + pub fn del_with_message(&self, message: LinkMessage) -> LinkDelRequest { + LinkDelRequest::new_with_message(self.0.clone(), message) + } + /// Retrieve the list of links (equivalent to `ip link show`) - pub fn get(&mut self) -> LinkGetRequest { + pub fn get(&self) -> LinkGetRequest { LinkGetRequest::new(self.0.clone()) }