Skip to content

Commit f3953b8

Browse files
Alexander Chernikovcathay4t
authored andcommitted
actions: convert tm from vec to proper kernel struct tcf.
1 parent 1bab123 commit f3953b8

File tree

9 files changed

+167
-87
lines changed

9 files changed

+167
-87
lines changed

src/tc/actions/action.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,46 @@ impl From<TcActionType> for i32 {
548548
}
549549
}
550550
}
551+
552+
pub const TC_TCF_BUF_LEN: usize = 32;
553+
554+
#[derive(Debug, PartialEq, Eq, Clone, Default)]
555+
pub struct Tcf {
556+
pub install: u64,
557+
pub lastuse: u64,
558+
pub expires: u64,
559+
pub firstuse: u64,
560+
}
561+
562+
// kernel struct `tcf_t`
563+
buffer!(TcfBuffer(TC_TCF_BUF_LEN) {
564+
install: (u64, 0..8),
565+
lastuse: (u64, 8..16),
566+
expires: (u64, 16..24),
567+
firstuse: (u64, 24..32),
568+
});
569+
570+
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<TcfBuffer<&'a T>> for Tcf {
571+
fn parse(buf: &TcfBuffer<&T>) -> Result<Self, DecodeError> {
572+
Ok(Self {
573+
install: buf.install(),
574+
lastuse: buf.lastuse(),
575+
expires: buf.expires(),
576+
firstuse: buf.firstuse(),
577+
})
578+
}
579+
}
580+
581+
impl Emitable for Tcf {
582+
fn buffer_len(&self) -> usize {
583+
TC_TCF_BUF_LEN
584+
}
585+
586+
fn emit(&self, buffer: &mut [u8]) {
587+
let mut packet = TcfBuffer::new(buffer);
588+
packet.set_install(self.install);
589+
packet.set_lastuse(self.lastuse);
590+
packet.set_expires(self.expires);
591+
packet.set_firstuse(self.firstuse);
592+
}
593+
}

src/tc/actions/mirror.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use netlink_packet_utils::{
1212
DecodeError,
1313
};
1414

15-
use super::{TcActionGeneric, TcActionGenericBuffer};
15+
use super::{
16+
TcActionGeneric, TcActionGenericBuffer, Tcf, TcfBuffer, TC_TCF_BUF_LEN,
17+
};
1618

1719
/// Traffic control action used to mirror or redirect packets.
1820
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -30,8 +32,8 @@ const TCA_MIRRED_PARMS: u16 = 2;
3032
#[derive(Debug, PartialEq, Eq, Clone)]
3133
#[non_exhaustive]
3234
pub enum TcActionMirrorOption {
33-
/// TODO: document this after we make it something better than `Vec<u8>`
34-
Tm(Vec<u8>),
35+
/// Rule installation and usage time
36+
Tm(Tcf),
3537
/// Parameters for the mirred action.
3638
Parms(TcMirror),
3739
/// Other attributes unknown at the time of writing.
@@ -41,15 +43,15 @@ pub enum TcActionMirrorOption {
4143
impl Nla for TcActionMirrorOption {
4244
fn value_len(&self) -> usize {
4345
match self {
44-
Self::Tm(bytes) => bytes.len(),
46+
Self::Tm(_) => TC_TCF_BUF_LEN,
4547
Self::Parms(_) => TC_MIRRED_BUF_LEN,
4648
Self::Other(attr) => attr.value_len(),
4749
}
4850
}
4951

5052
fn emit_value(&self, buffer: &mut [u8]) {
5153
match self {
52-
Self::Tm(bytes) => buffer.copy_from_slice(bytes.as_slice()),
54+
Self::Tm(p) => p.emit(buffer),
5355
Self::Parms(p) => p.emit(buffer),
5456
Self::Other(attr) => attr.emit_value(buffer),
5557
}
@@ -69,7 +71,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
6971
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
7072
let payload = buf.value();
7173
Ok(match buf.kind() {
72-
TCA_MIRRED_TM => Self::Tm(payload.to_vec()),
74+
TCA_MIRRED_TM => {
75+
Self::Tm(Tcf::parse(&TcfBuffer::new_checked(payload)?)?)
76+
}
7377
TCA_MIRRED_PARMS => Self::Parms(TcMirror::parse(
7478
&TcMirrorBuffer::new_checked(payload)?,
7579
)?),

src/tc/actions/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub use nat_flag::TcNatFlags;
44

55
pub use self::action::{
66
TcAction, TcActionAttribute, TcActionGeneric, TcActionGenericBuffer,
7-
TcActionOption, TcActionType,
7+
TcActionOption, TcActionType, Tcf, TcfBuffer, TC_TCF_BUF_LEN,
88
};
99
pub use self::header::{TcActionMessageBuffer, TcActionMessageHeader};
1010
pub use self::message::{

src/tc/actions/nat.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use netlink_packet_utils::{
1111
DecodeError,
1212
};
1313

14-
use super::{nat_flag::TcNatFlags, TcActionGeneric, TcActionGenericBuffer};
14+
use super::{
15+
nat_flag::TcNatFlags, TcActionGeneric, TcActionGenericBuffer, Tcf,
16+
TcfBuffer, TC_TCF_BUF_LEN,
17+
};
1518

1619
const TCA_NAT_PARMS: u16 = 1;
1720
const TCA_NAT_TM: u16 = 2;
@@ -29,8 +32,8 @@ impl TcActionNat {
2932
#[derive(Debug, PartialEq, Eq, Clone)]
3033
#[non_exhaustive]
3134
pub enum TcActionNatOption {
32-
/// TODO: document this after we make it something better than `Vec<u8>`
33-
Tm(Vec<u8>),
35+
/// Rule installation and usage time
36+
Tm(Tcf),
3437
/// Parameters for the nat action.
3538
Parms(TcNat),
3639
/// Other attributes unknown at the time of writing.
@@ -40,15 +43,15 @@ pub enum TcActionNatOption {
4043
impl Nla for TcActionNatOption {
4144
fn value_len(&self) -> usize {
4245
match self {
43-
Self::Tm(bytes) => bytes.len(),
46+
Self::Tm(_) => TC_TCF_BUF_LEN,
4447
Self::Parms(v) => v.buffer_len(),
4548
Self::Other(attr) => attr.value_len(),
4649
}
4750
}
4851

4952
fn emit_value(&self, buffer: &mut [u8]) {
5053
match self {
51-
Self::Tm(bytes) => buffer.copy_from_slice(bytes.as_slice()),
54+
Self::Tm(p) => p.emit(buffer),
5255
Self::Parms(p) => p.emit(buffer),
5356
Self::Other(attr) => attr.emit_value(buffer),
5457
}
@@ -68,7 +71,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
6871
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
6972
let payload = buf.value();
7073
Ok(match buf.kind() {
71-
TCA_NAT_TM => Self::Tm(payload.to_vec()),
74+
TCA_NAT_TM => {
75+
Self::Tm(Tcf::parse(&TcfBuffer::new_checked(payload)?)?)
76+
}
7277
TCA_NAT_PARMS => {
7378
Self::Parms(TcNat::parse(&TcNatBuffer::new_checked(payload)?)?)
7479
}

src/tc/actions/tests/message.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ mod mirror {
3333
use crate::tc::TcMirrorActionType::{EgressRedir, IngressMirror};
3434
use crate::tc::TcStats2::{Basic, BasicHw, Queue};
3535
use crate::tc::{
36-
TcAction, TcActionGeneric, TcMirror, TcStatsBasic, TcStatsQueue,
36+
TcAction, TcActionGeneric, TcMirror, TcStatsBasic, TcStatsQueue, Tcf,
3737
};
3838
use crate::AddressFamily;
3939

@@ -223,11 +223,12 @@ mod mirror {
223223
eaction: EgressRedir,
224224
ifindex: 1,
225225
})),
226-
Mirror(Tm(vec![
227-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
228-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
229-
0, 0, 0, 0,
230-
])),
226+
Mirror(Tm(Tcf {
227+
install: 0,
228+
lastuse: 0,
229+
expires: 0,
230+
firstuse: 0,
231+
})),
231232
]),
232233
],
233234
},
@@ -269,11 +270,12 @@ mod mirror {
269270
eaction: IngressMirror,
270271
ifindex: 1,
271272
})),
272-
Mirror(Tm(vec![
273-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
275-
0, 0, 0, 0,
276-
])),
273+
Mirror(Tm(Tcf {
274+
install: 0,
275+
lastuse: 0,
276+
expires: 0,
277+
firstuse: 0,
278+
})),
277279
]),
278280
],
279281
},

src/tc/actions/tests/mirror.rs

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ use netlink_packet_utils::nla::NlaBuffer;
44
use netlink_packet_utils::{Emitable, Parseable};
55

66
use crate::tc::{
7-
TcActionGeneric, TcActionGenericBuffer, TcActionMirrorOption, TcActionType,
8-
TcMirror, TcMirrorActionType, TcMirrorBuffer,
7+
TcAction, TcActionAttribute, TcActionGeneric, TcActionGenericBuffer,
8+
TcActionMirrorOption, TcActionOption, TcActionType, TcMirror,
9+
TcMirrorActionType, TcMirrorBuffer, TcStats2, TcStatsBasic, TcStatsQueue,
10+
Tcf,
911
};
1012

1113
#[test]
@@ -64,22 +66,76 @@ fn tc_mirror_example_parse_back() {
6466
assert_eq!(orig, parsed);
6567
}
6668

69+
// > act actions add action mirred egress redirect dev veth1
70+
// > tools/nl_dump.py dump_actions mirred
71+
// Note: 5.15 and 6.8 kernels do NOT set NLA_F_NESTED for TCA_ACT_OPTIONS
72+
//
6773
#[test]
68-
fn tc_mirror_tm_default_parse_back() {
69-
let mirror_option = TcActionMirrorOption::Tm(vec![]);
70-
let mut buffer = vec![0; mirror_option.buffer_len()];
71-
mirror_option.emit(&mut buffer);
72-
let nla_buf = NlaBuffer::new_checked(&buffer).unwrap();
73-
let parsed = TcActionMirrorOption::parse(&nla_buf).unwrap();
74-
assert_eq!(mirror_option, parsed);
75-
}
74+
fn get_mirred_eggress_redirect_action() {
75+
let raw = vec![
76+
0x9C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x6D, 0x69, 0x72, 0x72,
77+
0x65, 0x64, 0x00, 0x00, 0x44, 0x00, 0x04, 0x00, 0x14, 0x00, 0x01, 0x00,
78+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79+
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
80+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81+
0x18, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83+
0x48, 0x00, 0x02, 0x80, 0x20, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
84+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
85+
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
86+
0x24, 0x00, 0x01, 0x00, 0x68, 0x3D, 0xB6, 0x02, 0x00, 0x00, 0x00, 0x00,
87+
0x68, 0x3D, 0xB6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89+
];
7690

77-
#[test]
78-
fn tc_mirror_tm_example_parse_back() {
79-
let mirror_option = TcActionMirrorOption::Tm(vec![1, 2, 3]);
80-
let mut buffer = vec![0; mirror_option.buffer_len()];
81-
mirror_option.emit(&mut buffer);
82-
let nla_buf = NlaBuffer::new_checked(&buffer).unwrap();
83-
let parsed = TcActionMirrorOption::parse(&nla_buf).unwrap();
84-
assert_eq!(mirror_option, parsed);
91+
let expected = TcAction {
92+
tab: 0,
93+
attributes: vec![
94+
TcActionAttribute::Kind("mirred".to_string()),
95+
TcActionAttribute::Stats(vec![
96+
TcStats2::Basic(TcStatsBasic {
97+
bytes: 0,
98+
packets: 0,
99+
}),
100+
TcStats2::BasicHw(TcStatsBasic {
101+
bytes: 0,
102+
packets: 0,
103+
}),
104+
TcStats2::Queue(TcStatsQueue {
105+
qlen: 0,
106+
backlog: 0,
107+
drops: 0,
108+
requeues: 0,
109+
overlimits: 0,
110+
}),
111+
]),
112+
TcActionAttribute::Options(vec![
113+
TcActionOption::Mirror(TcActionMirrorOption::Parms(TcMirror {
114+
generic: TcActionGeneric {
115+
index: 1,
116+
capab: 0,
117+
action: TcActionType::Ok,
118+
refcnt: 2,
119+
bindcnt: 2,
120+
},
121+
eaction: TcMirrorActionType::EgressRedir,
122+
ifindex: 3,
123+
})),
124+
TcActionOption::Mirror(TcActionMirrorOption::Tm(Tcf {
125+
install: 45497704,
126+
lastuse: 45497704,
127+
expires: 0,
128+
firstuse: 0,
129+
})),
130+
]),
131+
],
132+
};
133+
134+
assert_eq!(expected, TcAction::parse(&NlaBuffer::new(&raw)).unwrap());
135+
136+
let mut buf = vec![0; expected.buffer_len()];
137+
138+
expected.emit(&mut buf);
139+
140+
assert_eq!(buf, raw);
85141
}

src/tc/actions/tests/nat.rs

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::tc::TcActionOption::Nat;
1414
use crate::tc::TcStats2::{Basic, BasicHw, Queue};
1515
use crate::tc::{
1616
TcAction, TcActionGeneric, TcActionNatOption, TcActionType, TcNat,
17-
TcNatFlags, TcStatsBasic, TcStatsQueue,
17+
TcNatFlags, TcStatsBasic, TcStatsQueue, Tcf,
1818
};
1919
use crate::AddressFamily;
2020

@@ -248,39 +248,6 @@ fn tc_action_nat_option_emit_uses_whole_buffer() {
248248
}
249249
}
250250

251-
fn tc_action_nat_option_tm_examples() -> [TcActionNatOption; 4] {
252-
[
253-
Tm(vec![]),
254-
Tm(vec![1]),
255-
Tm(vec![1, 2, 3, 4]),
256-
Tm(vec![99; 10]),
257-
]
258-
}
259-
260-
#[test]
261-
fn tc_action_nat_option_parse_back_example_tm() {
262-
for example in &tc_action_nat_option_tm_examples() {
263-
let mut buffer = vec![0; example.buffer_len()];
264-
example.emit(&mut buffer);
265-
let parsed = TcActionNatOption::parse(
266-
&NlaBuffer::new_checked(buffer.as_slice()).unwrap(),
267-
)
268-
.unwrap();
269-
assert_eq!(example, &parsed);
270-
}
271-
}
272-
273-
#[test]
274-
fn tc_action_nat_option_emit_tm_uses_whole_buffer() {
275-
for example in &tc_action_nat_option_tm_examples() {
276-
let mut buffer1 = vec![0x00; example.buffer_len()];
277-
let mut buffer2 = vec![0xff; example.buffer_len()];
278-
example.emit(&mut buffer1);
279-
example.emit(&mut buffer2);
280-
assert_eq!(buffer1, buffer2);
281-
}
282-
}
283-
284251
/// Setup:
285252
///
286253
/// ```bash
@@ -357,10 +324,12 @@ fn test_get_filter_nat() {
357324
mask: Ipv4Addr::BROADCAST,
358325
flags: TcNatFlags::empty(),
359326
})),
360-
Nat(Tm(vec![
361-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
362-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
363-
])),
327+
Nat(Tm(Tcf {
328+
install: 0,
329+
lastuse: 0,
330+
expires: 0,
331+
firstuse: 0,
332+
})),
364333
]),
365334
],
366335
}])],

src/tc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub use self::actions::{
1515
TcActionMessageFlags, TcActionMessageFlagsWithSelector, TcActionMirror,
1616
TcActionMirrorOption, TcActionNat, TcActionNatOption, TcActionOption,
1717
TcActionType, TcMirror, TcMirrorActionType, TcMirrorBuffer, TcNat,
18-
TcNatBuffer, TcNatFlags,
18+
TcNatBuffer, TcNatFlags, Tcf,
1919
};
2020
pub use self::attribute::TcAttribute;
2121
pub use self::filters::{

0 commit comments

Comments
 (0)