Skip to content

Commit 7f889a7

Browse files
committed
Some test progress
1 parent 097b62c commit 7f889a7

File tree

4 files changed

+378
-88
lines changed

4 files changed

+378
-88
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ name = "dump_packet_links"
3030
pcap-file = "1.1.1"
3131
netlink-sys = { version = "0.8.5" }
3232
pretty_assertions = "0.7.2"
33+
hex = "0.4.3"

src/tc/actions/action.rs

Lines changed: 87 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,29 @@
22

33
use anyhow::Context;
44
use byteorder::{ByteOrder, NativeEndian};
5-
6-
use crate::tc::actions::tunnel_key::{
7-
TcActionTunnelKey, TcActionTunnelKeyOption,
8-
};
95
use netlink_packet_utils::{
106
nla::{DefaultNla, Nla, NlaBuffer, NlasIterator},
117
parsers::{parse_string, parse_u32},
128
traits::{Emitable, Parseable, ParseableParametrized},
139
DecodeError,
1410
};
1511

12+
use crate::tc::actions::tunnel_key::{
13+
TcActionTunnelKey, TcActionTunnelKeyOption,
14+
};
15+
use crate::tc::TcStats2;
16+
1617
use super::{
1718
TcActionMirror, TcActionMirrorOption, TcActionNat, TcActionNatOption,
1819
};
19-
use crate::tc::TcStats2;
2020

2121
const TCA_ACT_TAB: u16 = 1;
2222

2323
/// `TcAction` is a netlink message attribute that describes a [tc-action].
2424
#[derive(Debug, PartialEq, Eq, Clone)]
2525
#[non_exhaustive]
2626
pub struct TcAction {
27-
/// Table id. Should always be `TCA_ACT_TAB` (which equals 1).
27+
/// Table id. Corresponds to the `Kind` of the action.
2828
pub tab: u16,
2929
/// Attributes of the action.
3030
pub attributes: Vec<TcActionAttribute>,
@@ -55,62 +55,53 @@ impl Nla for TcAction {
5555

5656
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for TcAction {
5757
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
58-
let mut attributes = vec![];
59-
let mut kind = String::new();
60-
61-
for iter in NlasIterator::new(buf.value()) {
62-
let buf = iter.context("invalid action nla")?;
63-
let payload = buf.value();
64-
attributes.push(match buf.kind() {
65-
TCA_ACT_KIND => {
66-
kind = parse_string(payload)
67-
.context("failed to parse TCA_ACT_KIND")?;
68-
TcActionAttribute::Kind(kind.clone())
69-
}
70-
TCA_ACT_OPTIONS => {
71-
let mut nlas = vec![];
72-
for nla in NlasIterator::new(payload) {
73-
let nla = nla.context("invalid TCA_ACT_OPTIONS")?;
74-
nlas.push(
75-
TcActionOption::parse_with_param(&nla, &kind)
76-
.context(format!(
77-
"failed to parse TCA_ACT_OPTIONS \
78-
for kind {kind}"
79-
))?,
80-
);
58+
// We need to find the `Kind` attribute before we can parse the others,
59+
// as kind is used in calls to parse_with_param for the other
60+
// attributes.
61+
// Messages of this type which do not specify `Kind`, or which specify
62+
// `Kind` more than once are malformed and should be rejected.
63+
// We cannot ensure that `Kind` will be the first attribute in the
64+
// `attributes` `Vec` (although it usually is).
65+
// As a result, we need to determine `Kind` first, then parse the rest
66+
// of the attributes.
67+
let kind = match NlasIterator::new(buf.value())
68+
.filter_map(|nla| {
69+
let nla = match nla {
70+
Ok(nla) => nla,
71+
Err(e) => {
72+
return Some(
73+
Err(e).context("failed to parse action nla"),
74+
)
8175
}
82-
TcActionAttribute::Options(nlas)
76+
};
77+
match nla.kind() {
78+
TCA_ACT_KIND => Some(
79+
parse_string(nla.value())
80+
.context("failed to parse TCA_ACT_KIND"),
81+
),
82+
_ => None,
8383
}
84-
TCA_ACT_INDEX => TcActionAttribute::Index(
85-
parse_u32(payload)
86-
.context("failed to parse TCA_ACT_INDEX")?,
87-
),
88-
TCA_ACT_STATS => {
89-
let mut nlas = vec![];
90-
for nla in NlasIterator::new(payload) {
91-
let nla = nla.context("invalid TCA_ACT_STATS")?;
92-
nlas.push(
93-
TcStats2::parse_with_param(&nla, &kind).context(
94-
format!(
95-
"failed to parse TCA_ACT_STATS for \
96-
kind {kind}",
97-
),
98-
)?,
99-
);
100-
}
101-
TcActionAttribute::Stats(nlas)
84+
})
85+
.collect::<Result<Vec<_>, _>>()
86+
{
87+
Ok(kinds) => {
88+
if kinds.is_empty() {
89+
return Err(DecodeError::from("Missing TCA_ACT_KIND"));
10290
}
103-
TCA_ACT_COOKIE => TcActionAttribute::Cookie(payload.to_vec()),
104-
TCA_ACT_IN_HW_COUNT => TcActionAttribute::InHwCount(
105-
parse_u32(payload)
106-
.context("failed to parse TCA_ACT_IN_HW_COUNT")?,
107-
),
108-
_ => TcActionAttribute::Other(
109-
DefaultNla::parse(&buf)
110-
.context("failed to parse action nla")?,
111-
),
112-
});
113-
}
91+
if kinds.len() > 1 {
92+
return Err(DecodeError::from("Duplicate TCA_ACT_KIND"));
93+
}
94+
kinds[0].clone()
95+
}
96+
Err(e) => return Err(DecodeError::from(e.to_string())),
97+
};
98+
99+
let attributes = NlasIterator::new(buf.value())
100+
.map(|nla| {
101+
TcActionAttribute::parse_with_param(&nla?, kind.as_str())
102+
})
103+
.collect::<Result<Vec<_>, _>>()?;
104+
114105
Ok(Self {
115106
tab: buf.kind(),
116107
attributes,
@@ -141,6 +132,8 @@ pub enum TcActionAttribute {
141132
///
142133
/// This is used to identify the action in the kernel.
143134
/// Each action `Kind` has a unique table of actions.
135+
/// That is, each action `Kind` has its own set of `Index`
136+
/// values.
144137
///
145138
/// If `Index` is zero on action creation,
146139
/// the kernel will assign a unique index to the new action.
@@ -149,14 +142,14 @@ pub enum TcActionAttribute {
149142
/// future.
150143
///
151144
/// For example, one action can be used by multiple different filters by
152-
/// referencing the action's `Index`.
145+
/// referencing the action's `Index` when creating that filter.
153146
/// Such multiply referenced actions will aggregate their statistics.
154147
///
155148
/// The kernel will reject attempts to delete an action if it is in use by
156149
/// a filter.
157150
/// Remove all referencing filters before deleting the action.
158151
Index(u32),
159-
/// Statistics about the action (e.g. number of bytes and or packets
152+
/// Statistics about the action (e.g., number of bytes and or packets
160153
/// processed).
161154
Stats(Vec<TcStats2>),
162155
/// An arbitrary identifier which _is not interpreted by the kernel at
@@ -213,11 +206,15 @@ impl Nla for TcActionAttribute {
213206
}
214207
}
215208

216-
impl<'a, T> Parseable<NlaBuffer<&'a T>> for TcActionAttribute
209+
impl<'a, T, P> ParseableParametrized<NlaBuffer<&'a T>, P> for TcActionAttribute
217210
where
218211
T: AsRef<[u8]> + ?Sized,
212+
P: AsRef<str>,
219213
{
220-
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
214+
fn parse_with_param(
215+
buf: &NlaBuffer<&'a T>,
216+
kind: P,
217+
) -> Result<Self, DecodeError> {
221218
Ok(match buf.kind() {
222219
TCA_ACT_KIND => {
223220
let buf_value = buf.value();
@@ -226,19 +223,33 @@ where
226223
.context("failed to parse TCA_ACT_KIND")?,
227224
)
228225
}
229-
// TCA_ACT_OPTIONS => {
230-
// let mut nlas = vec![];
231-
// for nla in NlasIterator::new(payload) {
232-
// let nla = nla.context("invalid TCA_ACT_OPTIONS")?;
233-
// nlas.push(
234-
// TcActionOption::parse_with_param(&nla, kind)
235-
// .context(format!(
236-
// "failed to parse TCA_ACT_OPTIONS for kind
237-
// {kind}" ))?,
238-
// )
239-
// }
240-
// TcActionAttribute::Options(nlas)
241-
// }
226+
TCA_ACT_OPTIONS => TcActionAttribute::Options(
227+
NlasIterator::new(buf.value())
228+
.map(|nla| {
229+
let nla = nla.context("invalid TCA_ACT_OPTIONS")?;
230+
TcActionOption::parse_with_param(&nla, kind.as_ref())
231+
.context("failed to parse TCA_ACT_OPTIONS")
232+
})
233+
.collect::<Result<Vec<_>, _>>()?,
234+
),
235+
TCA_ACT_INDEX => TcActionAttribute::Index(
236+
parse_u32(buf.value())
237+
.context("failed to parse TCA_ACT_INDEX")?,
238+
),
239+
TCA_ACT_STATS => TcActionAttribute::Stats(
240+
NlasIterator::new(buf.value())
241+
.map(|nla| {
242+
let nla = nla.context("invalid TCA_ACT_STATS")?;
243+
TcStats2::parse_with_param(&nla, kind.as_ref())
244+
.context("failed to parse TCA_ACT_STATS")
245+
})
246+
.collect::<Result<Vec<_>, _>>()?,
247+
),
248+
TCA_ACT_COOKIE => TcActionAttribute::Cookie(buf.value().to_vec()),
249+
TCA_ACT_IN_HW_COUNT => TcActionAttribute::InHwCount(
250+
parse_u32(buf.value())
251+
.context("failed to parse TCA_ACT_IN_HW_COUNT")?,
252+
),
242253
_ => TcActionAttribute::Other(
243254
DefaultNla::parse(buf).context("failed to parse action nla")?,
244255
),

src/tc/actions/message.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ bitflags! {
5858
/// `selector` field will be ignored.
5959
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, PartialOrd, Ord, Hash)]
6060
pub struct TcActionMessageFlagsWithSelector {
61-
flags: TcActionMessageFlags,
62-
selector: TcActionMessageFlags,
61+
pub flags: TcActionMessageFlags,
62+
pub selector: TcActionMessageFlags,
6363
}
6464

6565
impl Nla for TcActionMessageFlagsWithSelector {

0 commit comments

Comments
 (0)