Skip to content

Commit 7afe563

Browse files
liangwen12yearcathay4t
authored andcommitted
Support setting the bond port settings of the device
Add support for setting device's bond port settings and also provide the example for validating the support. Notice that the port priority setting is supported in kernel since v6.0. Signed-off-by: Wen Liang <[email protected]>
1 parent 9b67c97 commit 7afe563

File tree

5 files changed

+202
-2
lines changed

5 files changed

+202
-2
lines changed

examples/get_bond_port_settings.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use futures::stream::TryStreamExt;
4+
use rtnetlink::{new_connection, Error, Handle};
5+
use std::env;
6+
7+
#[tokio::main]
8+
async fn main() -> Result<(), ()> {
9+
let args: Vec<String> = env::args().collect();
10+
if args.len() != 2 {
11+
usage();
12+
return Ok(());
13+
}
14+
let link_name = &args[1];
15+
16+
let (connection, handle, _) = new_connection().unwrap();
17+
tokio::spawn(connection);
18+
19+
let linkname = link_name.to_string();
20+
println!("dumping bond port settings for link \"{linkname}\"");
21+
22+
if let Err(e) = dump_bond_port_settings(handle, linkname).await {
23+
eprintln!("{e}");
24+
}
25+
26+
Ok(())
27+
}
28+
29+
async fn dump_bond_port_settings(
30+
handle: Handle,
31+
linkname: String,
32+
) -> Result<(), Error> {
33+
let mut links = handle.link().get().match_name(linkname.clone()).execute();
34+
if let Some(_link) = links.try_next().await? {
35+
let mut link_messgage =
36+
handle.link().get().match_name(linkname).execute();
37+
while let Some(msg) = link_messgage.try_next().await? {
38+
println!("{msg:?}");
39+
}
40+
Ok(())
41+
} else {
42+
eprintln!("link {linkname} not found");
43+
Ok(())
44+
}
45+
}
46+
47+
fn usage() {
48+
eprintln!(
49+
"usage:
50+
cargo run --example get_bond_port_settings -- <link name>
51+
52+
Note that you need to run this program as root. Instead of running cargo as root,
53+
build the example normally:
54+
55+
cd netlink-ip ; cargo build --example get_bond_port_settings
56+
57+
Then find the binary in the target directory:
58+
59+
cd ../target/debug/example ; sudo ./get_bond_port_settings <link_name>"
60+
);
61+
}

examples/set_bond_port_settings.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use futures::stream::TryStreamExt;
4+
use rtnetlink::{new_connection, Error, Handle};
5+
use std::env;
6+
7+
#[tokio::main]
8+
async fn main() -> Result<(), String> {
9+
let args: Vec<String> = env::args().collect();
10+
if args.len() != 2 {
11+
usage();
12+
return Ok(());
13+
}
14+
let link_name = &args[1];
15+
16+
let (connection, handle, _) = new_connection().unwrap();
17+
tokio::spawn(connection);
18+
19+
set_bond_port_settings(handle, link_name.to_string())
20+
.await
21+
.map_err(|e| format!("{e}"))
22+
}
23+
// The bond port priority is only supported to set when bonding mode is
24+
// active-backup(1) or balance-tlb (5) or balance-alb (6)
25+
async fn set_bond_port_settings(
26+
handle: Handle,
27+
name: String,
28+
) -> Result<(), Error> {
29+
let mut links = handle.link().get().match_name(name.clone()).execute();
30+
if let Some(link) = links.try_next().await? {
31+
// This is equivalent to `ip link set name NAME type bond_slave queue_id
32+
// 0 prio 1`. The port priority setting is supported in kernel
33+
// since v6.0
34+
handle
35+
.link()
36+
.set_bond_port(link.header.index)
37+
.queue_id(0)
38+
.prio(1)
39+
.execute()
40+
.await?
41+
} else {
42+
println!("no link link {name} found");
43+
}
44+
Ok(())
45+
}
46+
47+
fn usage() {
48+
eprintln!(
49+
"usage:
50+
cargo run --example set_bond_port_settings -- <link name>
51+
52+
Note that you need to run this program as root. Instead of running cargo as root,
53+
build the example normally:
54+
55+
cd netlink-ip ; cargo build --example set_bond_port_settings
56+
57+
Then find the binary in the target directory:
58+
59+
cd ../target/debug/example ; sudo ./set_bond_port_settings <link_name>"
60+
);
61+
}

src/link/handle.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// SPDX-License-Identifier: MIT
22

33
use super::{
4-
LinkAddRequest, LinkDelPropRequest, LinkDelRequest, LinkGetRequest,
5-
LinkNewPropRequest, LinkSetRequest,
4+
BondPortSetRequest, LinkAddRequest, LinkDelPropRequest, LinkDelRequest,
5+
LinkGetRequest, LinkNewPropRequest, LinkSetRequest,
66
};
77
use crate::Handle;
88

@@ -37,4 +37,8 @@ impl LinkHandle {
3737
pub fn get(&mut self) -> LinkGetRequest {
3838
LinkGetRequest::new(self.0.clone())
3939
}
40+
41+
pub fn set_bond_port(&mut self, index: u32) -> BondPortSetRequest {
42+
BondPortSetRequest::new(self.0.clone(), index)
43+
}
4044
}

src/link/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ pub use self::get::*;
1515
mod set;
1616
pub use self::set::*;
1717

18+
mod set_bond_port;
19+
pub use self::set_bond_port::*;
20+
1821
mod property_add;
1922
pub use self::property_add::*;
2023

src/link/set_bond_port.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use futures::stream::StreamExt;
4+
use netlink_packet_core::{NetlinkMessage, NLM_F_ACK, NLM_F_REQUEST};
5+
use netlink_packet_route::{
6+
link::nlas::{Info, InfoBondPort, InfoPortData, InfoPortKind, Nla},
7+
LinkMessage, RtnlMessage,
8+
};
9+
10+
use crate::{try_nl, Error, Handle};
11+
12+
pub struct BondPortSetRequest {
13+
handle: Handle,
14+
index: u32,
15+
port_nlas: Vec<InfoBondPort>,
16+
}
17+
18+
impl BondPortSetRequest {
19+
pub(crate) fn new(handle: Handle, index: u32) -> Self {
20+
BondPortSetRequest {
21+
handle,
22+
index,
23+
port_nlas: Vec::new(),
24+
}
25+
}
26+
27+
/// Execute the request.
28+
pub async fn execute(self) -> Result<(), Error> {
29+
let BondPortSetRequest {
30+
mut handle,
31+
index,
32+
port_nlas,
33+
} = self;
34+
35+
let mut message = LinkMessage::default();
36+
message.header.index = index;
37+
message.nlas.push(Nla::Info(vec![
38+
Info::PortKind(InfoPortKind::Bond),
39+
Info::PortData(InfoPortData::BondPort(port_nlas)),
40+
]));
41+
42+
let mut req = NetlinkMessage::from(RtnlMessage::NewLink(message));
43+
req.header.flags = NLM_F_REQUEST | NLM_F_ACK;
44+
45+
let mut response = handle.request(req)?;
46+
while let Some(message) = response.next().await {
47+
try_nl!(message);
48+
}
49+
Ok(())
50+
}
51+
52+
/// Return a mutable reference to the Vec<InfoBondPort>
53+
pub fn info_port_nlas_mut(&mut self) -> &mut Vec<InfoBondPort> {
54+
&mut self.port_nlas
55+
}
56+
57+
/// Adds the `queue_id` attribute to the bond port
58+
/// This is equivalent to
59+
/// `ip link set name NAME type bond_slave queue_id QUEUE_ID`.
60+
pub fn queue_id(mut self, queue_id: u16) -> Self {
61+
self.port_nlas.push(InfoBondPort::QueueId(queue_id));
62+
self
63+
}
64+
65+
/// Adds the `prio` attribute to the bond port
66+
/// This is equivalent to `ip link set name NAME type bond_slave prio PRIO`.
67+
pub fn prio(mut self, prio: i32) -> Self {
68+
self.port_nlas.push(InfoBondPort::Prio(prio));
69+
self
70+
}
71+
}

0 commit comments

Comments
 (0)