Skip to content

Commit 467b1c6

Browse files
committed
tc: Fix DecodeError on sfq scheduler
When running `GetQueueDiscipline` against `sfq` scheduler, we will get DecodeError. This is because different scheduler has different layout of `TCA_OPTIONS`. For `fq_codel`, it is a list of netlink attribute. For kernel code, `fq_codel_dump()` has `nla_nest_start_noflag(skb, TCA_OPTIONS)` For `sfq`, it is a single netlink attribute, trying to decode it as `NlasIterator` will generate DecodeError as expected. For kernel code: `sfq_dump()` only has `nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)`. This patch created `pub(crate) struct VecTcOpt` to handle this difference correctly. Signed-off-by: Gris Ge <[email protected]>
1 parent 2457bdf commit 467b1c6

File tree

4 files changed

+49
-15
lines changed

4 files changed

+49
-15
lines changed

src/rtnl/tc/message.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ use netlink_packet_utils::{
88
DecodeError,
99
};
1010

11+
use super::nlas::VecTcOpt;
1112
use crate::{
1213
constants::*,
13-
nlas::tc::{Nla, Stats, Stats2, StatsBuffer, TcOpt},
14+
nlas::tc::{Nla, Stats, Stats2, StatsBuffer},
1415
TcMessageBuffer, TC_HEADER_LEN,
1516
};
1617

@@ -119,17 +120,11 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable<TcMessageBuffer<&'a T>> for Vec<Nla> {
119120
kind = parse_string(payload).context("invalid TCA_KIND")?;
120121
Nla::Kind(kind.clone())
121122
}
122-
TCA_OPTIONS => {
123-
let mut nlas = vec![];
124-
for nla in NlasIterator::new(payload) {
125-
let nla = nla.context("invalid TCA_OPTIONS")?;
126-
nlas.push(
127-
TcOpt::parse_with_param(&nla, &kind)
128-
.context("failed to parse TCA_OPTIONS")?,
129-
)
130-
}
131-
Nla::Options(nlas)
132-
}
123+
TCA_OPTIONS => Nla::Options(
124+
VecTcOpt::parse_with_param(&buf, &kind)
125+
.context(format!("Invalid TCA_OPTIONS for {kind}"))?
126+
.0,
127+
),
133128
TCA_STATS => Nla::Stats(
134129
Stats::parse(
135130
&StatsBuffer::new_checked(payload)

src/rtnl/tc/nlas/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub use self::stats_basic::*;
1111

1212
mod options;
1313
pub use self::options::*;
14+
pub(crate) use self::options::VecTcOpt;
1415

1516
mod qdisc;
1617
pub use self::qdisc::*;

src/rtnl/tc/nlas/options.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use anyhow::Context;
44
use netlink_packet_utils::{
5-
nla::{self, DefaultNla, NlaBuffer},
5+
nla::{self, DefaultNla, NlaBuffer, NlasIterator},
66
traits::{Parseable, ParseableParametrized},
77
DecodeError,
88
};
@@ -73,3 +73,41 @@ where
7373
})
7474
}
7575
}
76+
77+
pub(crate) struct VecTcOpt(pub(crate) Vec<TcOpt>);
78+
79+
impl<'a, T, S> ParseableParametrized<NlaBuffer<&'a T>, S> for VecTcOpt
80+
where
81+
T: AsRef<[u8]> + ?Sized,
82+
S: AsRef<str>,
83+
{
84+
fn parse_with_param(
85+
buf: &NlaBuffer<&'a T>,
86+
kind: S,
87+
) -> Result<VecTcOpt, DecodeError> {
88+
Ok(match kind.as_ref() {
89+
ingress::KIND => {
90+
Self(vec![TcOpt::parse_with_param(&buf, &kind).context(
91+
format!("Failed to pase TCA_OPTIONS for {}", ingress::KIND),
92+
)?])
93+
}
94+
u32::KIND | matchall::KIND => {
95+
let mut nlas = vec![];
96+
for nla in NlasIterator::new(buf.value()) {
97+
let nla = nla.context(format!(
98+
"invalid TCA_OPTIONS for {}",
99+
kind.as_ref()
100+
))?;
101+
nlas.push(TcOpt::parse_with_param(&nla, &kind).context(
102+
format!(
103+
"failed to parse TCA_OPTIONS for {}",
104+
kind.as_ref()
105+
),
106+
)?)
107+
}
108+
Self(nlas)
109+
}
110+
_ => Self(vec![TcOpt::Other(DefaultNla::parse(buf)?)]),
111+
})
112+
}
113+
}

src/rtnl/tc/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use crate::{
66
constants::*,
7-
tc::{ingress, Nla, Stats, Stats2, StatsBuffer, TC_HEADER_LEN},
7+
tc::{ingress, Nla, Stats, Stats2, StatsBuffer, TcOpt, TC_HEADER_LEN},
88
TcHeader, TcMessage, TcMessageBuffer,
99
};
1010

@@ -167,7 +167,7 @@ fn tc_qdisc_ingress_read() {
167167
assert_eq!(nla, &Nla::Kind(String::from(ingress::KIND)));
168168

169169
let nla = iter.next().unwrap();
170-
assert_eq!(nla, &Nla::Options(vec![]));
170+
assert_eq!(nla, &Nla::Options(vec![TcOpt::Ingress]));
171171

172172
let nla = iter.next().unwrap();
173173
assert_eq!(nla, &Nla::HwOffload(0));

0 commit comments

Comments
 (0)