22
33use anyhow:: Context ;
44use byteorder:: { ByteOrder , NativeEndian } ;
5-
6- use crate :: tc:: actions:: tunnel_key:: {
7- TcActionTunnelKey , TcActionTunnelKeyOption ,
8- } ;
95use 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+
1617use super :: {
1718 TcActionMirror , TcActionMirrorOption , TcActionNat , TcActionNatOption ,
1819} ;
19- use crate :: tc:: TcStats2 ;
2020
2121const 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]
2626pub 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
5656impl < ' 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
217210where
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 ) ,
0 commit comments