2
2
3
3
use anyhow:: Context ;
4
4
use byteorder:: { ByteOrder , NativeEndian } ;
5
-
6
- use crate :: tc:: actions:: tunnel_key:: {
7
- TcActionTunnelKey , TcActionTunnelKeyOption ,
8
- } ;
9
5
use netlink_packet_utils:: {
10
6
nla:: { DefaultNla , Nla , NlaBuffer , NlasIterator } ,
11
7
parsers:: { parse_string, parse_u32} ,
12
8
traits:: { Emitable , Parseable , ParseableParametrized } ,
13
9
DecodeError ,
14
10
} ;
15
11
12
+ use crate :: tc:: actions:: tunnel_key:: {
13
+ TcActionTunnelKey , TcActionTunnelKeyOption ,
14
+ } ;
15
+ use crate :: tc:: TcStats2 ;
16
+
16
17
use super :: {
17
18
TcActionMirror , TcActionMirrorOption , TcActionNat , TcActionNatOption ,
18
19
} ;
19
- use crate :: tc:: TcStats2 ;
20
20
21
21
const TCA_ACT_TAB : u16 = 1 ;
22
22
23
23
/// `TcAction` is a netlink message attribute that describes a [tc-action].
24
24
#[ derive( Debug , PartialEq , Eq , Clone ) ]
25
25
#[ non_exhaustive]
26
26
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 .
28
28
pub tab : u16 ,
29
29
/// Attributes of the action.
30
30
pub attributes : Vec < TcActionAttribute > ,
@@ -55,62 +55,53 @@ impl Nla for TcAction {
55
55
56
56
impl < ' a , T : AsRef < [ u8 ] > + ?Sized > Parseable < NlaBuffer < & ' a T > > for TcAction {
57
57
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
+ )
81
75
}
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 ,
83
83
}
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" ) ) ;
102
90
}
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
+
114
105
Ok ( Self {
115
106
tab : buf. kind ( ) ,
116
107
attributes,
@@ -141,6 +132,8 @@ pub enum TcActionAttribute {
141
132
///
142
133
/// This is used to identify the action in the kernel.
143
134
/// Each action `Kind` has a unique table of actions.
135
+ /// That is, each action `Kind` has its own set of `Index`
136
+ /// values.
144
137
///
145
138
/// If `Index` is zero on action creation,
146
139
/// the kernel will assign a unique index to the new action.
@@ -149,14 +142,14 @@ pub enum TcActionAttribute {
149
142
/// future.
150
143
///
151
144
/// 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 .
153
146
/// Such multiply referenced actions will aggregate their statistics.
154
147
///
155
148
/// The kernel will reject attempts to delete an action if it is in use by
156
149
/// a filter.
157
150
/// Remove all referencing filters before deleting the action.
158
151
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
160
153
/// processed).
161
154
Stats ( Vec < TcStats2 > ) ,
162
155
/// An arbitrary identifier which _is not interpreted by the kernel at
@@ -213,11 +206,15 @@ impl Nla for TcActionAttribute {
213
206
}
214
207
}
215
208
216
- impl < ' a , T > Parseable < NlaBuffer < & ' a T > > for TcActionAttribute
209
+ impl < ' a , T , P > ParseableParametrized < NlaBuffer < & ' a T > , P > for TcActionAttribute
217
210
where
218
211
T : AsRef < [ u8 ] > + ?Sized ,
212
+ P : AsRef < str > ,
219
213
{
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 > {
221
218
Ok ( match buf. kind ( ) {
222
219
TCA_ACT_KIND => {
223
220
let buf_value = buf. value ( ) ;
@@ -226,19 +223,33 @@ where
226
223
. context ( "failed to parse TCA_ACT_KIND" ) ?,
227
224
)
228
225
}
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
+ ) ,
242
253
_ => TcActionAttribute :: Other (
243
254
DefaultNla :: parse ( buf) . context ( "failed to parse action nla" ) ?,
244
255
) ,
0 commit comments