Skip to content

Add channel get and set functionality #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions src/channel/attr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// SPDX-License-Identifier: MIT

use anyhow::Context;
use byteorder::{ByteOrder, NativeEndian};
use netlink_packet_utils::{
nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED},
parsers::parse_u32,
DecodeError, Emitable, Parseable,
};

use crate::{EthtoolAttr, EthtoolHeader};

const ETHTOOL_A_CHANNELS_HEADER: u16 = 1;
const ETHTOOL_A_CHANNELS_RX_MAX: u16 = 2;
const ETHTOOL_A_CHANNELS_TX_MAX: u16 = 3;
const ETHTOOL_A_CHANNELS_OTHER_MAX: u16 = 4;
const ETHTOOL_A_CHANNELS_COMBINED_MAX: u16 = 5;
const ETHTOOL_A_CHANNELS_RX_COUNT: u16 = 6;
const ETHTOOL_A_CHANNELS_TX_COUNT: u16 = 7;
const ETHTOOL_A_CHANNELS_OTHER_COUNT: u16 = 8;
const ETHTOOL_A_CHANNELS_COMBINED_COUNT: u16 = 9;

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum EthtoolChannelAttr {
Header(Vec<EthtoolHeader>),
RxMax(u32),
TxMax(u32),
OtherMax(u32),
CombinedMax(u32),
RxCount(u32),
TxCount(u32),
OtherCount(u32),
CombinedCount(u32),
Other(DefaultNla),
}

impl Nla for EthtoolChannelAttr {
fn value_len(&self) -> usize {
match self {
Self::Header(hdrs) => hdrs.as_slice().buffer_len(),
Self::RxMax(_)
| Self::TxMax(_)
| Self::OtherMax(_)
| Self::CombinedMax(_)
| Self::RxCount(_)
| Self::TxCount(_)
| Self::OtherCount(_)
| Self::CombinedCount(_) => 4,
Self::Other(attr) => attr.value_len(),
}
}

fn kind(&self) -> u16 {
match self {
Self::Header(_) => ETHTOOL_A_CHANNELS_HEADER | NLA_F_NESTED,
Self::RxMax(_) => ETHTOOL_A_CHANNELS_RX_MAX,
Self::TxMax(_) => ETHTOOL_A_CHANNELS_TX_MAX,
Self::OtherMax(_) => ETHTOOL_A_CHANNELS_OTHER_MAX,
Self::CombinedMax(_) => ETHTOOL_A_CHANNELS_COMBINED_MAX,
Self::RxCount(_) => ETHTOOL_A_CHANNELS_RX_COUNT,
Self::TxCount(_) => ETHTOOL_A_CHANNELS_TX_COUNT,
Self::OtherCount(_) => ETHTOOL_A_CHANNELS_OTHER_COUNT,
Self::CombinedCount(_) => ETHTOOL_A_CHANNELS_COMBINED_COUNT,
Self::Other(attr) => attr.kind(),
}
}

fn emit_value(&self, buffer: &mut [u8]) {
match self {
Self::Header(ref nlas) => nlas.as_slice().emit(buffer),
Self::RxMax(d)
| Self::TxMax(d)
| Self::OtherMax(d)
| Self::CombinedMax(d)
| Self::RxCount(d)
| Self::TxCount(d)
| Self::OtherCount(d)
| Self::CombinedCount(d) => NativeEndian::write_u32(buffer, *d),
Self::Other(ref attr) => attr.emit(buffer),
}
}
}

impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
for EthtoolChannelAttr
{
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
let payload = buf.value();
Ok(match buf.kind() {
ETHTOOL_A_CHANNELS_HEADER => {
let mut nlas = Vec::new();
let error_msg = "failed to parse channel header attributes";
for nla in NlasIterator::new(payload) {
let nla = &nla.context(error_msg)?;
let parsed =
EthtoolHeader::parse(nla).context(error_msg)?;
nlas.push(parsed);
}
Self::Header(nlas)
}
ETHTOOL_A_CHANNELS_RX_MAX => Self::RxMax(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_MAX value")?,
),
ETHTOOL_A_CHANNELS_TX_MAX => Self::TxMax(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_MAX value")?,
),
ETHTOOL_A_CHANNELS_OTHER_MAX => Self::OtherMax(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_MAX value")?,
),
ETHTOOL_A_CHANNELS_COMBINED_MAX => Self::CombinedMax(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_MAX value")?,
),
ETHTOOL_A_CHANNELS_RX_COUNT => Self::RxCount(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_COUNT value")?,
),
ETHTOOL_A_CHANNELS_TX_COUNT => Self::TxCount(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_COUNT value")?,
),
ETHTOOL_A_CHANNELS_OTHER_COUNT => Self::OtherCount(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_COUNT value")?,
),
ETHTOOL_A_CHANNELS_COMBINED_COUNT => Self::CombinedCount(
parse_u32(payload)
.context("Invalid ETHTOOL_A_CHANNELS_RX_COUNT value")?,
),
kind => {
Self::Other(DefaultNla::parse(buf).context(format!(
"invalid ethtool channel NLA kind {kind}"
))?)
}
})
}
}

pub(crate) fn parse_channel_nlas(
buffer: &[u8],
) -> Result<Vec<EthtoolAttr>, DecodeError> {
let mut nlas = Vec::new();
for nla in NlasIterator::new(buffer) {
let error_msg = format!(
"Failed to parse ethtool channel message attribute {nla:?}"
);
let nla = &nla.context(error_msg.clone())?;
let parsed = EthtoolChannelAttr::parse(nla).context(error_msg)?;
nlas.push(EthtoolAttr::Channel(parsed));
}
Ok(nlas)
}
34 changes: 34 additions & 0 deletions src/channel/get.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT

use futures::TryStream;
use netlink_packet_generic::GenlMessage;

use crate::{ethtool_execute, EthtoolError, EthtoolHandle, EthtoolMessage};

pub struct EthtoolChannelGetRequest {
handle: EthtoolHandle,
iface_name: Option<String>,
}

impl EthtoolChannelGetRequest {
pub(crate) fn new(handle: EthtoolHandle, iface_name: Option<&str>) -> Self {
EthtoolChannelGetRequest {
handle,
iface_name: iface_name.map(|i| i.to_string()),
}
}

pub async fn execute(
self,
) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError>
{
let EthtoolChannelGetRequest {
mut handle,
iface_name,
} = self;

let ethtool_msg =
EthtoolMessage::new_channel_get(iface_name.as_deref());
ethtool_execute(&mut handle, iface_name.is_none(), ethtool_msg).await
}
}
27 changes: 27 additions & 0 deletions src/channel/handle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT

use crate::{
EthtoolChannelGetRequest, EthtoolChannelSetRequest, EthtoolHandle,
};

pub struct EthtoolChannelHandle(EthtoolHandle);

impl EthtoolChannelHandle {
pub fn new(handle: EthtoolHandle) -> Self {
EthtoolChannelHandle(handle)
}

/// Retrieve the ethtool Channels of a interface (equivalent to `ethtool -l
/// eth1`)
pub fn get(
&mut self,
iface_name: Option<&str>,
) -> EthtoolChannelGetRequest {
EthtoolChannelGetRequest::new(self.0.clone(), iface_name)
}

/// Set the ethtool Channels of a interface (equivalent to `ethtool -L eth1`)
pub fn set(&mut self, iface_name: &str) -> EthtoolChannelSetRequest {
EthtoolChannelSetRequest::new(self.0.clone(), iface_name)
}
}
13 changes: 13 additions & 0 deletions src/channel/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT

mod attr;
mod get;
mod handle;
mod set;

pub(crate) use attr::parse_channel_nlas;

pub use attr::EthtoolChannelAttr;
pub use get::EthtoolChannelGetRequest;
pub use handle::EthtoolChannelHandle;
pub use set::EthtoolChannelSetRequest;
88 changes: 88 additions & 0 deletions src/channel/set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: MIT

use futures::TryStream;
use netlink_packet_generic::GenlMessage;

use crate::{
ethtool_execute, EthtoolAttr, EthtoolChannelAttr, EthtoolError,
EthtoolHandle, EthtoolMessage,
};

pub struct EthtoolChannelSetRequest {
handle: EthtoolHandle,
message: EthtoolMessage,
rx_count: Option<u32>,
tx_count: Option<u32>,
other_count: Option<u32>,
combined_count: Option<u32>,
}

impl EthtoolChannelSetRequest {
pub(crate) fn new(handle: EthtoolHandle, iface_name: &str) -> Self {
EthtoolChannelSetRequest {
handle,
message: EthtoolMessage::new_channel_set(iface_name),
rx_count: None,
tx_count: None,
other_count: None,
combined_count: None,
}
}

pub fn rx_count(mut self, count: u32) -> Self {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of every function pushing a NLA, could you try builder way like rust-netlink/rtnetlink#57

self.rx_count = Some(count);
self
}

pub fn tx_count(mut self, count: u32) -> Self {
self.tx_count = Some(count);
self
}

pub fn other_count(mut self, count: u32) -> Self {
self.other_count = Some(count);
self
}

pub fn combined_count(mut self, count: u32) -> Self {
self.combined_count = Some(count);
self
}

pub async fn execute(
self,
) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError>
{
let EthtoolChannelSetRequest {
mut handle,
mut message,
rx_count,
tx_count,
other_count,
combined_count,
} = self;

if let Some(count) = rx_count {
message
.nlas
.push(EthtoolAttr::Channel(EthtoolChannelAttr::RxCount(count)));
}
if let Some(count) = tx_count {
message
.nlas
.push(EthtoolAttr::Channel(EthtoolChannelAttr::TxCount(count)));
}
if let Some(count) = other_count {
message.nlas.push(EthtoolAttr::Channel(
EthtoolChannelAttr::OtherCount(count),
));
}
if let Some(count) = combined_count {
message.nlas.push(EthtoolAttr::Channel(
EthtoolChannelAttr::CombinedCount(count),
));
}

ethtool_execute(&mut handle, false, message).await
}
}
10 changes: 7 additions & 3 deletions src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use netlink_packet_generic::GenlMessage;
use netlink_packet_utils::DecodeError;

use crate::{
try_ethtool, EthtoolCoalesceHandle, EthtoolError, EthtoolFeatureHandle,
EthtoolLinkModeHandle, EthtoolMessage, EthtoolPauseHandle,
EthtoolRingHandle, EthtoolTsInfoHandle,
try_ethtool, EthtoolChannelHandle, EthtoolCoalesceHandle, EthtoolError,
EthtoolFeatureHandle, EthtoolLinkModeHandle, EthtoolMessage,
EthtoolPauseHandle, EthtoolRingHandle, EthtoolTsInfoHandle,
};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -48,6 +48,10 @@ impl EthtoolHandle {
EthtoolTsInfoHandle::new(self.clone())
}

pub fn channel(&mut self) -> EthtoolChannelHandle {
EthtoolChannelHandle::new(self.clone())
}

pub async fn request(
&mut self,
message: NetlinkMessage<GenlMessage<EthtoolMessage>>,
Expand Down
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT

mod bitset_util;
mod channel;
mod coalesce;
mod connection;
mod error;
Expand All @@ -14,6 +15,10 @@ mod pause;
mod ring;
mod tsinfo;

pub use channel::{
EthtoolChannelAttr, EthtoolChannelGetRequest, EthtoolChannelHandle,
EthtoolChannelSetRequest,
};
pub use coalesce::{
EthtoolCoalesceAttr, EthtoolCoalesceGetRequest, EthtoolCoalesceHandle,
};
Expand Down
Loading