Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 <liangwen12year@gmail.com>
  • Loading branch information
liangwen12year authored and cathay4t committed Jul 16, 2023
1 parent 9b67c97 commit 7afe563
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 2 deletions.
61 changes: 61 additions & 0 deletions examples/get_bond_port_settings.rs
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use rtnetlink::{new_connection, Error, Handle};
use std::env;

#[tokio::main]
async fn main() -> Result<(), ()> {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
usage();
return Ok(());
}
let link_name = &args[1];

let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

let linkname = link_name.to_string();
println!("dumping bond port settings for link \"{linkname}\"");

if let Err(e) = dump_bond_port_settings(handle, linkname).await {
eprintln!("{e}");
}

Ok(())
}

async fn dump_bond_port_settings(
handle: Handle,
linkname: String,
) -> Result<(), Error> {
let mut links = handle.link().get().match_name(linkname.clone()).execute();
if let Some(_link) = links.try_next().await? {
let mut link_messgage =
handle.link().get().match_name(linkname).execute();
while let Some(msg) = link_messgage.try_next().await? {
println!("{msg:?}");
}
Ok(())
} else {
eprintln!("link {linkname} not found");
Ok(())
}
}

fn usage() {
eprintln!(
"usage:
cargo run --example get_bond_port_settings -- <link name>
Note that you need to run this program as root. Instead of running cargo as root,
build the example normally:
cd netlink-ip ; cargo build --example get_bond_port_settings
Then find the binary in the target directory:
cd ../target/debug/example ; sudo ./get_bond_port_settings <link_name>"
);
}
61 changes: 61 additions & 0 deletions examples/set_bond_port_settings.rs
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use rtnetlink::{new_connection, Error, Handle};
use std::env;

#[tokio::main]
async fn main() -> Result<(), String> {
let args: Vec<String> = env::args().collect();
if args.len() != 2 {
usage();
return Ok(());
}
let link_name = &args[1];

let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

set_bond_port_settings(handle, link_name.to_string())
.await
.map_err(|e| format!("{e}"))
}
// The bond port priority is only supported to set when bonding mode is
// active-backup(1) or balance-tlb (5) or balance-alb (6)
async fn set_bond_port_settings(
handle: Handle,
name: String,
) -> Result<(), Error> {
let mut links = handle.link().get().match_name(name.clone()).execute();
if let Some(link) = links.try_next().await? {
// This is equivalent to `ip link set name NAME type bond_slave queue_id
// 0 prio 1`. The port priority setting is supported in kernel
// since v6.0
handle
.link()
.set_bond_port(link.header.index)
.queue_id(0)
.prio(1)
.execute()
.await?
} else {
println!("no link link {name} found");
}
Ok(())
}

fn usage() {
eprintln!(
"usage:
cargo run --example set_bond_port_settings -- <link name>
Note that you need to run this program as root. Instead of running cargo as root,
build the example normally:
cd netlink-ip ; cargo build --example set_bond_port_settings
Then find the binary in the target directory:
cd ../target/debug/example ; sudo ./set_bond_port_settings <link_name>"
);
}
8 changes: 6 additions & 2 deletions src/link/handle.rs
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT

use super::{
LinkAddRequest, LinkDelPropRequest, LinkDelRequest, LinkGetRequest,
LinkNewPropRequest, LinkSetRequest,
BondPortSetRequest, LinkAddRequest, LinkDelPropRequest, LinkDelRequest,
LinkGetRequest, LinkNewPropRequest, LinkSetRequest,
};
use crate::Handle;

Expand Down Expand Up @@ -37,4 +37,8 @@ impl LinkHandle {
pub fn get(&mut self) -> LinkGetRequest {
LinkGetRequest::new(self.0.clone())
}

pub fn set_bond_port(&mut self, index: u32) -> BondPortSetRequest {
BondPortSetRequest::new(self.0.clone(), index)
}
}
3 changes: 3 additions & 0 deletions src/link/mod.rs
Expand Up @@ -15,6 +15,9 @@ pub use self::get::*;
mod set;
pub use self::set::*;

mod set_bond_port;
pub use self::set_bond_port::*;

mod property_add;
pub use self::property_add::*;

Expand Down
71 changes: 71 additions & 0 deletions src/link/set_bond_port.rs
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT

use futures::stream::StreamExt;
use netlink_packet_core::{NetlinkMessage, NLM_F_ACK, NLM_F_REQUEST};
use netlink_packet_route::{
link::nlas::{Info, InfoBondPort, InfoPortData, InfoPortKind, Nla},
LinkMessage, RtnlMessage,
};

use crate::{try_nl, Error, Handle};

pub struct BondPortSetRequest {
handle: Handle,
index: u32,
port_nlas: Vec<InfoBondPort>,
}

impl BondPortSetRequest {
pub(crate) fn new(handle: Handle, index: u32) -> Self {
BondPortSetRequest {
handle,
index,
port_nlas: Vec::new(),
}
}

/// Execute the request.
pub async fn execute(self) -> Result<(), Error> {
let BondPortSetRequest {
mut handle,
index,
port_nlas,
} = self;

let mut message = LinkMessage::default();
message.header.index = index;
message.nlas.push(Nla::Info(vec![
Info::PortKind(InfoPortKind::Bond),
Info::PortData(InfoPortData::BondPort(port_nlas)),
]));

let mut req = NetlinkMessage::from(RtnlMessage::NewLink(message));
req.header.flags = NLM_F_REQUEST | NLM_F_ACK;

let mut response = handle.request(req)?;
while let Some(message) = response.next().await {
try_nl!(message);
}
Ok(())
}

/// Return a mutable reference to the Vec<InfoBondPort>
pub fn info_port_nlas_mut(&mut self) -> &mut Vec<InfoBondPort> {
&mut self.port_nlas
}

/// Adds the `queue_id` attribute to the bond port
/// This is equivalent to
/// `ip link set name NAME type bond_slave queue_id QUEUE_ID`.
pub fn queue_id(mut self, queue_id: u16) -> Self {
self.port_nlas.push(InfoBondPort::QueueId(queue_id));
self
}

/// Adds the `prio` attribute to the bond port
/// This is equivalent to `ip link set name NAME type bond_slave prio PRIO`.
pub fn prio(mut self, prio: i32) -> Self {
self.port_nlas.push(InfoBondPort::Prio(prio));
self
}
}

0 comments on commit 7afe563

Please sign in to comment.