Skip to content

Commit c71ed0e

Browse files
committed
fec: Support querying FEC
Example code `examples/dump_fec.rs` included. Signed-off-by: Gris Ge <[email protected]>
1 parent 96a97a7 commit c71ed0e

File tree

12 files changed

+452
-24
lines changed

12 files changed

+452
-24
lines changed

examples/dump_fec.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use futures::stream::TryStreamExt;
4+
5+
// Once we find a way to load netsimdev kernel module in CI, we can convert this
6+
// to a test
7+
fn main() {
8+
let rt = tokio::runtime::Builder::new_current_thread()
9+
.enable_io()
10+
.build()
11+
.unwrap();
12+
let iface_name = std::env::args().nth(1);
13+
rt.block_on(get_fec(iface_name.as_deref()));
14+
}
15+
16+
async fn get_fec(iface_name: Option<&str>) {
17+
let (connection, mut handle, _) = ethtool::new_connection().unwrap();
18+
tokio::spawn(connection);
19+
20+
let mut fec_handle = handle.fec().get(iface_name).execute().await;
21+
22+
let mut msgs = Vec::new();
23+
while let Some(msg) = fec_handle.try_next().await.unwrap() {
24+
msgs.push(msg);
25+
}
26+
assert!(!msgs.is_empty());
27+
for msg in msgs {
28+
println!("{:?}", msg);
29+
}
30+
}

src/bitset_util.rs

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
use anyhow::Context;
44
use log::warn;
55
use netlink_packet_utils::{
6-
nla::NlasIterator, parsers::parse_string, DecodeError,
6+
nla::NlasIterator,
7+
parsers::{parse_string, parse_u32},
8+
DecodeError,
79
};
810

911
const ETHTOOL_A_BITSET_BITS: u16 = 3;
@@ -14,9 +16,16 @@ const ETHTOOL_A_BITSET_BIT_INDEX: u16 = 1;
1416
const ETHTOOL_A_BITSET_BIT_NAME: u16 = 2;
1517
const ETHTOOL_A_BITSET_BIT_VALUE: u16 = 3;
1618

19+
#[derive(Debug, PartialEq, Eq, Clone, Default)]
20+
pub(crate) struct EthtoolBitSet {
21+
pub(crate) index: u32,
22+
pub(crate) name: String,
23+
pub(crate) value: bool,
24+
}
25+
1726
pub(crate) fn parse_bitset_bits_nlas(
1827
raw: &[u8],
19-
) -> Result<Vec<String>, DecodeError> {
28+
) -> Result<Vec<EthtoolBitSet>, DecodeError> {
2029
let error_msg = "failed to parse mode bit sets";
2130
for nla in NlasIterator::new(raw) {
2231
let nla = &nla.context(error_msg)?;
@@ -27,28 +36,55 @@ pub(crate) fn parse_bitset_bits_nlas(
2736
Err("No ETHTOOL_A_BITSET_BITS NLA found".into())
2837
}
2938

30-
fn parse_bitset_bits_nla(raw: &[u8]) -> Result<Vec<String>, DecodeError> {
31-
let mut modes = Vec::new();
39+
pub(crate) fn parse_bitset_bits_string_nlas(
40+
raw: &[u8],
41+
) -> Result<Vec<String>, DecodeError> {
42+
let error_msg = "failed to parse mode bit sets";
43+
for nla in NlasIterator::new(raw) {
44+
let nla = &nla.context(error_msg)?;
45+
if nla.kind() == ETHTOOL_A_BITSET_BITS {
46+
let bits = parse_bitset_bits_nla(nla.value())?;
47+
48+
return Ok(bits
49+
.into_iter()
50+
.filter_map(|b| if b.value { Some(b.name) } else { None })
51+
.collect::<Vec<String>>());
52+
}
53+
}
54+
Err("No ETHTOOL_A_BITSET_BITS NLA found".into())
55+
}
56+
57+
fn parse_bitset_bits_nla(
58+
raw: &[u8],
59+
) -> Result<Vec<EthtoolBitSet>, DecodeError> {
60+
let mut bit_sets = Vec::new();
3261
let error_msg = "Failed to parse ETHTOOL_A_BITSET_BITS attributes";
3362
for bit_nla in NlasIterator::new(raw) {
3463
let bit_nla = &bit_nla.context(error_msg)?;
3564
match bit_nla.kind() {
3665
ETHTOOL_A_BITSET_BITS_BIT => {
3766
let error_msg =
3867
"Failed to parse ETHTOOL_A_BITSET_BITS_BIT attributes";
68+
let mut bit_set = EthtoolBitSet::default();
3969
let nlas = NlasIterator::new(bit_nla.value());
4070
for nla in nlas {
4171
let nla = &nla.context(error_msg)?;
4272
let payload = nla.value();
4373
match nla.kind() {
44-
ETHTOOL_A_BITSET_BIT_INDEX
45-
| ETHTOOL_A_BITSET_BIT_VALUE => {
46-
// ignored
74+
ETHTOOL_A_BITSET_BIT_INDEX => {
75+
bit_set.index =
76+
parse_u32(payload).context(format!(
77+
"Invalid ETHTOOL_A_BITSET_BIT_INDEX \
78+
value {payload:?}"
79+
))?;
80+
}
81+
ETHTOOL_A_BITSET_BIT_VALUE => {
82+
bit_set.value = true;
4783
}
4884
ETHTOOL_A_BITSET_BIT_NAME => {
49-
modes.push(parse_string(payload).context(
85+
bit_set.name = parse_string(payload).context(
5086
"Invald ETHTOOL_A_BITSET_BIT_NAME value",
51-
)?);
87+
)?;
5288
}
5389
_ => {
5490
warn!(
@@ -59,6 +95,7 @@ fn parse_bitset_bits_nla(raw: &[u8]) -> Result<Vec<String>, DecodeError> {
5995
}
6096
}
6197
}
98+
bit_sets.push(bit_set);
6299
}
63100
_ => {
64101
warn!(
@@ -69,5 +106,5 @@ fn parse_bitset_bits_nla(raw: &[u8]) -> Result<Vec<String>, DecodeError> {
69106
}
70107
};
71108
}
72-
Ok(modes)
109+
Ok(bit_sets)
73110
}

src/feature/attr.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,25 +116,25 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
116116
Self::Header(nlas)
117117
}
118118
ETHTOOL_A_FEATURES_HW => {
119-
Self::Hw(parse_bitset_bits_nlas(
119+
Self::Hw(parse_bitset_bits_string_nlas(
120120
payload,
121121
true, /* ETHTOOL_A_FEATURES_HW is using mask */
122122
)?)
123123
}
124124
ETHTOOL_A_FEATURES_WANTED => {
125-
Self::Wanted(parse_bitset_bits_nlas(
125+
Self::Wanted(parse_bitset_bits_string_nlas(
126126
payload,
127127
false, /* ETHTOOL_A_FEATURES_WANTED does not use mask */
128128
)?)
129129
}
130130
ETHTOOL_A_FEATURES_ACTIVE => {
131-
Self::Active(parse_bitset_bits_nlas(
131+
Self::Active(parse_bitset_bits_string_nlas(
132132
payload,
133133
false, /* ETHTOOL_A_FEATURES_ACTIVE does not use mask */
134134
)?)
135135
}
136136
ETHTOOL_A_FEATURES_NOCHANGE => {
137-
Self::NoChange(parse_bitset_bits_nlas(
137+
Self::NoChange(parse_bitset_bits_string_nlas(
138138
payload,
139139
false, /* ETHTOOL_A_FEATURES_NOCHANGE does not use mask */
140140
)?)
@@ -146,7 +146,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
146146
}
147147
}
148148

149-
fn parse_bitset_bits_nlas(
149+
fn parse_bitset_bits_string_nlas(
150150
raw: &[u8],
151151
has_mask: bool,
152152
) -> Result<Vec<EthtoolFeatureBit>, DecodeError> {

0 commit comments

Comments
 (0)