@@ -131,6 +131,12 @@ static void free_tcf(struct tc_action *p)
131
131
kfree (p );
132
132
}
133
133
134
+ static void offload_action_hw_count_set (struct tc_action * act ,
135
+ u32 hw_count )
136
+ {
137
+ act -> in_hw_count = hw_count ;
138
+ }
139
+
134
140
static unsigned int tcf_offload_act_num_actions_single (struct tc_action * act )
135
141
{
136
142
if (is_tcf_pedit (act ))
@@ -139,6 +145,29 @@ static unsigned int tcf_offload_act_num_actions_single(struct tc_action *act)
139
145
return 1 ;
140
146
}
141
147
148
+ static bool tc_act_skip_hw (u32 flags )
149
+ {
150
+ return (flags & TCA_ACT_FLAGS_SKIP_HW ) ? true : false;
151
+ }
152
+
153
+ static bool tc_act_skip_sw (u32 flags )
154
+ {
155
+ return (flags & TCA_ACT_FLAGS_SKIP_SW ) ? true : false;
156
+ }
157
+
158
+ static bool tc_act_in_hw (struct tc_action * act )
159
+ {
160
+ return !!act -> in_hw_count ;
161
+ }
162
+
163
+ /* SKIP_HW and SKIP_SW are mutually exclusive flags. */
164
+ static bool tc_act_flags_valid (u32 flags )
165
+ {
166
+ flags &= TCA_ACT_FLAGS_SKIP_HW | TCA_ACT_FLAGS_SKIP_SW ;
167
+
168
+ return flags ^ (TCA_ACT_FLAGS_SKIP_HW | TCA_ACT_FLAGS_SKIP_SW );
169
+ }
170
+
142
171
static int offload_action_init (struct flow_offload_action * fl_action ,
143
172
struct tc_action * act ,
144
173
enum offload_act_command cmd ,
@@ -155,6 +184,7 @@ static int offload_action_init(struct flow_offload_action *fl_action,
155
184
}
156
185
157
186
static int tcf_action_offload_cmd (struct flow_offload_action * fl_act ,
187
+ u32 * hw_count ,
158
188
struct netlink_ext_ack * extack )
159
189
{
160
190
int err ;
@@ -164,19 +194,27 @@ static int tcf_action_offload_cmd(struct flow_offload_action *fl_act,
164
194
if (err < 0 )
165
195
return err ;
166
196
197
+ if (hw_count )
198
+ * hw_count = err ;
199
+
167
200
return 0 ;
168
201
}
169
202
170
203
/* offload the tc action after it is inserted */
171
204
static int tcf_action_offload_add (struct tc_action * action ,
172
205
struct netlink_ext_ack * extack )
173
206
{
207
+ bool skip_sw = tc_act_skip_sw (action -> tcfa_flags );
174
208
struct tc_action * actions [TCA_ACT_MAX_PRIO ] = {
175
209
[0 ] = action ,
176
210
};
177
211
struct flow_offload_action * fl_action ;
212
+ u32 in_hw_count = 0 ;
178
213
int num , err = 0 ;
179
214
215
+ if (tc_act_skip_hw (action -> tcfa_flags ))
216
+ return 0 ;
217
+
180
218
num = tcf_offload_act_num_actions_single (action );
181
219
fl_action = offload_action_alloc (num );
182
220
if (!fl_action )
@@ -193,7 +231,13 @@ static int tcf_action_offload_add(struct tc_action *action,
193
231
goto fl_err ;
194
232
}
195
233
196
- err = tcf_action_offload_cmd (fl_action , extack );
234
+ err = tcf_action_offload_cmd (fl_action , & in_hw_count , extack );
235
+ if (!err )
236
+ offload_action_hw_count_set (action , in_hw_count );
237
+
238
+ if (skip_sw && !tc_act_in_hw (action ))
239
+ err = - EINVAL ;
240
+
197
241
tc_cleanup_offload_action (& fl_action -> action );
198
242
199
243
fl_err :
@@ -205,13 +249,24 @@ static int tcf_action_offload_add(struct tc_action *action,
205
249
static int tcf_action_offload_del (struct tc_action * action )
206
250
{
207
251
struct flow_offload_action fl_act = {};
252
+ u32 in_hw_count = 0 ;
208
253
int err = 0 ;
209
254
255
+ if (!tc_act_in_hw (action ))
256
+ return 0 ;
257
+
210
258
err = offload_action_init (& fl_act , action , FLOW_ACT_DESTROY , NULL );
211
259
if (err )
212
260
return err ;
213
261
214
- return tcf_action_offload_cmd (& fl_act , NULL );
262
+ err = tcf_action_offload_cmd (& fl_act , & in_hw_count , NULL );
263
+ if (err )
264
+ return err ;
265
+
266
+ if (action -> in_hw_count != in_hw_count )
267
+ return - EINVAL ;
268
+
269
+ return 0 ;
215
270
}
216
271
217
272
static void tcf_action_cleanup (struct tc_action * p )
@@ -821,6 +876,9 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
821
876
jmp_prgcnt -= 1 ;
822
877
continue ;
823
878
}
879
+
880
+ if (tc_act_skip_sw (a -> tcfa_flags ))
881
+ continue ;
824
882
repeat :
825
883
ret = a -> ops -> act (skb , a , res );
826
884
if (ret == TC_ACT_REPEAT )
@@ -926,6 +984,9 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
926
984
a -> tcfa_flags , a -> tcfa_flags ))
927
985
goto nla_put_failure ;
928
986
987
+ if (nla_put_u32 (skb , TCA_ACT_IN_HW_COUNT , a -> in_hw_count ))
988
+ goto nla_put_failure ;
989
+
929
990
nest = nla_nest_start_noflag (skb , TCA_OPTIONS );
930
991
if (nest == NULL )
931
992
goto nla_put_failure ;
@@ -1005,7 +1066,9 @@ static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
1005
1066
[TCA_ACT_COOKIE ] = { .type = NLA_BINARY ,
1006
1067
.len = TC_COOKIE_MAX_SIZE },
1007
1068
[TCA_ACT_OPTIONS ] = { .type = NLA_NESTED },
1008
- [TCA_ACT_FLAGS ] = NLA_POLICY_BITFIELD32 (TCA_ACT_FLAGS_NO_PERCPU_STATS ),
1069
+ [TCA_ACT_FLAGS ] = NLA_POLICY_BITFIELD32 (TCA_ACT_FLAGS_NO_PERCPU_STATS |
1070
+ TCA_ACT_FLAGS_SKIP_HW |
1071
+ TCA_ACT_FLAGS_SKIP_SW ),
1009
1072
[TCA_ACT_HW_STATS ] = NLA_POLICY_BITFIELD32 (TCA_ACT_HW_STATS_ANY ),
1010
1073
};
1011
1074
@@ -1118,8 +1181,13 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
1118
1181
}
1119
1182
}
1120
1183
hw_stats = tcf_action_hw_stats_get (tb [TCA_ACT_HW_STATS ]);
1121
- if (tb [TCA_ACT_FLAGS ])
1184
+ if (tb [TCA_ACT_FLAGS ]) {
1122
1185
userflags = nla_get_bitfield32 (tb [TCA_ACT_FLAGS ]);
1186
+ if (!tc_act_flags_valid (userflags .value )) {
1187
+ err = - EINVAL ;
1188
+ goto err_out ;
1189
+ }
1190
+ }
1123
1191
1124
1192
err = a_o -> init (net , tb [TCA_ACT_OPTIONS ], est , & a , tp ,
1125
1193
userflags .value | flags , extack );
@@ -1194,8 +1262,11 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
1194
1262
sz += tcf_action_fill_size (act );
1195
1263
/* Start from index 0 */
1196
1264
actions [i - 1 ] = act ;
1197
- if (!tc_act_bind (flags ))
1198
- tcf_action_offload_add (act , extack );
1265
+ if (!tc_act_bind (flags )) {
1266
+ err = tcf_action_offload_add (act , extack );
1267
+ if (tc_act_skip_sw (act -> tcfa_flags ) && err )
1268
+ goto err ;
1269
+ }
1199
1270
}
1200
1271
1201
1272
/* We have to commit them all together, because if any error happened in
0 commit comments