Skip to content

Commit 7adc576

Browse files
zhengbaowendavem330
authored andcommitted
flow_offload: add skip_hw and skip_sw to control if offload the action
We add skip_hw and skip_sw for user to control if offload the action to hardware. We also add in_hw_count for user to indicate if the action is offloaded to any hardware. Signed-off-by: Baowen Zheng <[email protected]> Signed-off-by: Simon Horman <[email protected]> Acked-by: Jamal Hadi Salim <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8cbfe93 commit 7adc576

File tree

3 files changed

+84
-9
lines changed

3 files changed

+84
-9
lines changed

include/net/act_api.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct tc_action {
4444
u8 hw_stats;
4545
u8 used_hw_stats;
4646
bool used_hw_stats_valid;
47+
u32 in_hw_count;
4748
};
4849
#define tcf_index common.tcfa_index
4950
#define tcf_refcnt common.tcfa_refcnt

include/uapi/linux/pkt_cls.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ enum {
1919
TCA_ACT_FLAGS,
2020
TCA_ACT_HW_STATS,
2121
TCA_ACT_USED_HW_STATS,
22+
TCA_ACT_IN_HW_COUNT,
2223
__TCA_ACT_MAX
2324
};
2425

2526
/* See other TCA_ACT_FLAGS_ * flags in include/net/act_api.h. */
26-
#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for
27-
* actions stats.
28-
*/
27+
#define TCA_ACT_FLAGS_NO_PERCPU_STATS (1 << 0) /* Don't use percpu allocator for
28+
* actions stats.
29+
*/
30+
#define TCA_ACT_FLAGS_SKIP_HW (1 << 1) /* don't offload action to HW */
31+
#define TCA_ACT_FLAGS_SKIP_SW (1 << 2) /* don't use action in SW */
2932

3033
/* tca HW stats type
3134
* When user does not pass the attribute, he does not care.

net/sched/act_api.c

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ static void free_tcf(struct tc_action *p)
131131
kfree(p);
132132
}
133133

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+
134140
static unsigned int tcf_offload_act_num_actions_single(struct tc_action *act)
135141
{
136142
if (is_tcf_pedit(act))
@@ -139,6 +145,29 @@ static unsigned int tcf_offload_act_num_actions_single(struct tc_action *act)
139145
return 1;
140146
}
141147

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+
142171
static int offload_action_init(struct flow_offload_action *fl_action,
143172
struct tc_action *act,
144173
enum offload_act_command cmd,
@@ -155,6 +184,7 @@ static int offload_action_init(struct flow_offload_action *fl_action,
155184
}
156185

157186
static int tcf_action_offload_cmd(struct flow_offload_action *fl_act,
187+
u32 *hw_count,
158188
struct netlink_ext_ack *extack)
159189
{
160190
int err;
@@ -164,19 +194,27 @@ static int tcf_action_offload_cmd(struct flow_offload_action *fl_act,
164194
if (err < 0)
165195
return err;
166196

197+
if (hw_count)
198+
*hw_count = err;
199+
167200
return 0;
168201
}
169202

170203
/* offload the tc action after it is inserted */
171204
static int tcf_action_offload_add(struct tc_action *action,
172205
struct netlink_ext_ack *extack)
173206
{
207+
bool skip_sw = tc_act_skip_sw(action->tcfa_flags);
174208
struct tc_action *actions[TCA_ACT_MAX_PRIO] = {
175209
[0] = action,
176210
};
177211
struct flow_offload_action *fl_action;
212+
u32 in_hw_count = 0;
178213
int num, err = 0;
179214

215+
if (tc_act_skip_hw(action->tcfa_flags))
216+
return 0;
217+
180218
num = tcf_offload_act_num_actions_single(action);
181219
fl_action = offload_action_alloc(num);
182220
if (!fl_action)
@@ -193,7 +231,13 @@ static int tcf_action_offload_add(struct tc_action *action,
193231
goto fl_err;
194232
}
195233

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+
197241
tc_cleanup_offload_action(&fl_action->action);
198242

199243
fl_err:
@@ -205,13 +249,24 @@ static int tcf_action_offload_add(struct tc_action *action,
205249
static int tcf_action_offload_del(struct tc_action *action)
206250
{
207251
struct flow_offload_action fl_act = {};
252+
u32 in_hw_count = 0;
208253
int err = 0;
209254

255+
if (!tc_act_in_hw(action))
256+
return 0;
257+
210258
err = offload_action_init(&fl_act, action, FLOW_ACT_DESTROY, NULL);
211259
if (err)
212260
return err;
213261

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;
215270
}
216271

217272
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,
821876
jmp_prgcnt -= 1;
822877
continue;
823878
}
879+
880+
if (tc_act_skip_sw(a->tcfa_flags))
881+
continue;
824882
repeat:
825883
ret = a->ops->act(skb, a, res);
826884
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)
926984
a->tcfa_flags, a->tcfa_flags))
927985
goto nla_put_failure;
928986

987+
if (nla_put_u32(skb, TCA_ACT_IN_HW_COUNT, a->in_hw_count))
988+
goto nla_put_failure;
989+
929990
nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
930991
if (nest == NULL)
931992
goto nla_put_failure;
@@ -1005,7 +1066,9 @@ static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
10051066
[TCA_ACT_COOKIE] = { .type = NLA_BINARY,
10061067
.len = TC_COOKIE_MAX_SIZE },
10071068
[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),
10091072
[TCA_ACT_HW_STATS] = NLA_POLICY_BITFIELD32(TCA_ACT_HW_STATS_ANY),
10101073
};
10111074

@@ -1118,8 +1181,13 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
11181181
}
11191182
}
11201183
hw_stats = tcf_action_hw_stats_get(tb[TCA_ACT_HW_STATS]);
1121-
if (tb[TCA_ACT_FLAGS])
1184+
if (tb[TCA_ACT_FLAGS]) {
11221185
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+
}
11231191

11241192
err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, &a, tp,
11251193
userflags.value | flags, extack);
@@ -1194,8 +1262,11 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
11941262
sz += tcf_action_fill_size(act);
11951263
/* Start from index 0 */
11961264
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+
}
11991270
}
12001271

12011272
/* We have to commit them all together, because if any error happened in

0 commit comments

Comments
 (0)