Skip to content

Commit f5535f3

Browse files
Alexander Chernikovcathay4t
authored andcommitted
Add tunnel_key action.
1 parent f3953b8 commit f5535f3

File tree

6 files changed

+428
-2
lines changed

6 files changed

+428
-2
lines changed

src/tc/actions/action.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::tc::TcStats2;
1414

1515
use super::{
1616
TcActionMirror, TcActionMirrorOption, TcActionNat, TcActionNatOption,
17+
TcActionTunnelKey, TcActionTunnelKeyOption,
1718
};
1819

1920
/// TODO: determine when and why to use this as opposed to the buffer's `kind`.
@@ -287,6 +288,10 @@ pub enum TcActionOption {
287288
///
288289
/// These options type can be used to perform network address translation.
289290
Nat(TcActionNatOption),
291+
/// Tunnel key options.
292+
///
293+
/// These options type can be used to assign encapsulation properties to the packet.
294+
TunnelKey(TcActionTunnelKeyOption),
290295
/// Other action types not yet supported by this library.
291296
Other(DefaultNla),
292297
}
@@ -296,6 +301,7 @@ impl Nla for TcActionOption {
296301
match self {
297302
Self::Mirror(nla) => nla.value_len(),
298303
Self::Nat(nla) => nla.value_len(),
304+
Self::TunnelKey(nla) => nla.value_len(),
299305
Self::Other(nla) => nla.value_len(),
300306
}
301307
}
@@ -304,6 +310,7 @@ impl Nla for TcActionOption {
304310
match self {
305311
Self::Mirror(nla) => nla.emit_value(buffer),
306312
Self::Nat(nla) => nla.emit_value(buffer),
313+
Self::TunnelKey(nla) => nla.emit_value(buffer),
307314
Self::Other(nla) => nla.emit_value(buffer),
308315
}
309316
}
@@ -312,6 +319,7 @@ impl Nla for TcActionOption {
312319
match self {
313320
Self::Mirror(nla) => nla.kind(),
314321
Self::Nat(nla) => nla.kind(),
322+
Self::TunnelKey(nla) => nla.kind(),
315323
Self::Other(nla) => nla.kind(),
316324
}
317325
}
@@ -335,6 +343,10 @@ where
335343
TcActionNatOption::parse(buf)
336344
.context("failed to parse nat action")?,
337345
),
346+
TcActionTunnelKey::KIND => Self::TunnelKey(
347+
TcActionTunnelKeyOption::parse(buf)
348+
.context("failed to parse tunnel_key action")?,
349+
),
338350
_ => Self::Other(
339351
DefaultNla::parse(buf)
340352
.context("failed to parse action options")?,

src/tc/actions/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ pub use self::mirror::{
1616
TcMirrorBuffer,
1717
};
1818
pub use self::nat::{TcActionNat, TcActionNatOption, TcNat, TcNatBuffer};
19+
pub use self::tunnel_key::{
20+
TcActionTunnelKey, TcActionTunnelKeyOption, TcTunnelKey,
21+
};
1922

2023
mod action;
2124
mod header;
2225
mod message;
2326
mod mirror;
2427
mod nat;
2528
mod nat_flag;
29+
mod tunnel_key;
2630

2731
#[cfg(test)]
2832
pub mod tests;

src/tc/actions/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ pub mod header;
55
pub mod message;
66
pub mod mirror;
77
pub mod nat;
8+
pub mod tunnel_key;

src/tc/actions/tests/tunnel_key.rs

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use netlink_packet_utils::nla::NlaBuffer;
4+
use netlink_packet_utils::{Emitable, Parseable};
5+
6+
use crate::tc::{
7+
TcAction, TcActionAttribute, TcActionGeneric, TcActionOption,
8+
TcActionTunnelKeyOption, TcActionType, TcStats2, TcStatsBasic,
9+
TcStatsQueue, TcTunnelKey, Tcf,
10+
};
11+
use std::net::{Ipv4Addr, Ipv6Addr};
12+
13+
// > tc actions add action tunnel_key set id 33 src_ip 1.2.3.4 dst_ip 2.3.4.5 dst_port 4789 tos 1 ttl 2
14+
// > tools/nl_dump.py dump_actions tunnel_key
15+
// Note: 5.15 and 6.8 kernels do NOT set NLA_F_NESTED for TCA_ACT_OPTIONS
16+
#[test]
17+
fn get_tunnel_key_vxlan_action_ipv4() {
18+
let raw = vec![
19+
0xD4, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x74, 0x75, 0x6E, 0x6E,
20+
0x65, 0x6C, 0x5F, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x44, 0x00, 0x04, 0x00,
21+
0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x07, 0x00,
23+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24+
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
25+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26+
0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x02, 0x80, 0x1C, 0x00, 0x02, 0x00,
27+
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
28+
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
29+
0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x03, 0x00,
30+
0x01, 0x02, 0x03, 0x04, 0x08, 0x00, 0x04, 0x00, 0x02, 0x03, 0x04, 0x05,
31+
0x06, 0x00, 0x09, 0x00, 0x12, 0xB5, 0x00, 0x00, 0x05, 0x00, 0x0A, 0x00,
32+
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x00,
33+
0x05, 0x00, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00,
34+
0xB0, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x23, 0x00, 0x00,
35+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37+
];
38+
39+
let expected = TcAction {
40+
tab: 1,
41+
attributes: vec![
42+
TcActionAttribute::Kind("tunnel_key".to_string()),
43+
TcActionAttribute::Stats(vec![
44+
TcStats2::Basic(TcStatsBasic {
45+
bytes: 0,
46+
packets: 0,
47+
}),
48+
TcStats2::BasicHw(TcStatsBasic {
49+
bytes: 0,
50+
packets: 0,
51+
}),
52+
TcStats2::Queue(TcStatsQueue {
53+
qlen: 0,
54+
backlog: 0,
55+
drops: 0,
56+
requeues: 0,
57+
overlimits: 0,
58+
}),
59+
]),
60+
TcActionAttribute::Options(vec![
61+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::Parms(
62+
TcTunnelKey {
63+
generic: TcActionGeneric {
64+
index: 2,
65+
capab: 0,
66+
action: TcActionType::Pipe,
67+
refcnt: 1,
68+
bindcnt: 0,
69+
},
70+
t_action: 1,
71+
},
72+
)),
73+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncKeyId(
74+
33,
75+
)),
76+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncIpv4Src(
77+
"1.2.3.4".parse::<Ipv4Addr>().unwrap(),
78+
)),
79+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncIpv4Dst(
80+
"2.3.4.5".parse::<Ipv4Addr>().unwrap(),
81+
)),
82+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncDstPort(
83+
4789,
84+
)),
85+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::NoCsum(
86+
false,
87+
)),
88+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncTos(1)),
89+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncTtl(2)),
90+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::Tm(Tcf {
91+
install: 9136,
92+
lastuse: 9136,
93+
expires: 0,
94+
firstuse: 0,
95+
})),
96+
]),
97+
],
98+
};
99+
100+
assert_eq!(expected, TcAction::parse(&NlaBuffer::new(&raw)).unwrap());
101+
102+
let mut buf = vec![0; expected.buffer_len()];
103+
104+
expected.emit(&mut buf);
105+
106+
assert_eq!(buf, raw);
107+
}
108+
109+
// > tc actions add action tunnel_key set id 33 src_ip 2a00:1:: dst_ip 2a01:2:: dst_port 4789 tos 1 ttl 2
110+
// > tools/nl_dump.py dump_actions tunnel_key
111+
// Note: 5.15 and 6.8 kernels do NOT set NLA_F_NESTED for TCA_ACT_OPTIONS
112+
#[test]
113+
fn test_action_tunnel_key_vxlan_ipv6() {
114+
let raw = vec![
115+
0xEC, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x74, 0x75, 0x6E, 0x6E,
116+
0x65, 0x6C, 0x5F, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x44, 0x00, 0x04, 0x00,
117+
0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x07, 0x00,
119+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120+
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
121+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122+
0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x02, 0x80, 0x1C, 0x00, 0x02, 0x00,
123+
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
124+
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
125+
0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x21, 0x14, 0x00, 0x05, 0x00,
126+
0x2A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127+
0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00, 0x2A, 0x01, 0x00, 0x02,
128+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129+
0x06, 0x00, 0x09, 0x00, 0x12, 0xB5, 0x00, 0x00, 0x05, 0x00, 0x0A, 0x00,
130+
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x00,
131+
0x05, 0x00, 0x0D, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00,
132+
0xFB, 0x71, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0x71, 0x3A, 0x00,
133+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135+
];
136+
137+
let expected = TcAction {
138+
tab: 0,
139+
attributes: vec![
140+
TcActionAttribute::Kind("tunnel_key".to_string()),
141+
TcActionAttribute::Stats(vec![
142+
TcStats2::Basic(TcStatsBasic {
143+
bytes: 0,
144+
packets: 0,
145+
}),
146+
TcStats2::BasicHw(TcStatsBasic {
147+
bytes: 0,
148+
packets: 0,
149+
}),
150+
TcStats2::Queue(TcStatsQueue {
151+
qlen: 0,
152+
backlog: 0,
153+
drops: 0,
154+
requeues: 0,
155+
overlimits: 0,
156+
}),
157+
]),
158+
TcActionAttribute::Options(vec![
159+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::Parms(
160+
TcTunnelKey {
161+
generic: TcActionGeneric {
162+
index: 1,
163+
capab: 0,
164+
action: TcActionType::Pipe,
165+
refcnt: 1,
166+
bindcnt: 1,
167+
},
168+
t_action: 1,
169+
},
170+
)),
171+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncKeyId(
172+
33,
173+
)),
174+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncIpv6Src(
175+
"2a00:1::".parse::<Ipv6Addr>().unwrap(),
176+
)),
177+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncIpv6Dst(
178+
"2a01:2::".parse::<Ipv6Addr>().unwrap(),
179+
)),
180+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncDstPort(
181+
4789,
182+
)),
183+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::NoCsum(
184+
false,
185+
)),
186+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncTos(1)),
187+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::EncTtl(2)),
188+
TcActionOption::TunnelKey(TcActionTunnelKeyOption::Tm(Tcf {
189+
install: 3830267,
190+
lastuse: 3830267,
191+
expires: 0,
192+
firstuse: 0,
193+
})),
194+
]),
195+
],
196+
};
197+
198+
assert_eq!(expected, TcAction::parse(&NlaBuffer::new(&raw)).unwrap());
199+
200+
let mut buf = vec![0; expected.buffer_len()];
201+
202+
expected.emit(&mut buf);
203+
204+
assert_eq!(buf, raw);
205+
}

0 commit comments

Comments
 (0)