Skip to content

Commit 8cbfe93

Browse files
zhengbaowendavem330
authored andcommitted
flow_offload: allow user to offload tc action to net device
Use flow_indr_dev_register/flow_indr_dev_setup_offload to offload tc action. We need to call tc_cleanup_flow_action to clean up tc action entry since in tc_setup_action, some actions may hold dev refcnt, especially the mirror action. Signed-off-by: Baowen Zheng <[email protected]> Signed-off-by: Louis Peens <[email protected]> Signed-off-by: Simon Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c54e1d9 commit 8cbfe93

17 files changed

+254
-23
lines changed

include/linux/netdevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@ enum tc_setup_type {
920920
TC_SETUP_QDISC_TBF,
921921
TC_SETUP_QDISC_FIFO,
922922
TC_SETUP_QDISC_HTB,
923+
TC_SETUP_ACT,
923924
};
924925

925926
/* These structures hold the attributes of bpf state that are being passed

include/net/flow_offload.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,23 @@ struct flow_cls_offload {
551551
u32 classid;
552552
};
553553

554+
enum offload_act_command {
555+
FLOW_ACT_REPLACE,
556+
FLOW_ACT_DESTROY,
557+
FLOW_ACT_STATS,
558+
};
559+
560+
struct flow_offload_action {
561+
struct netlink_ext_ack *extack; /* NULL in FLOW_ACT_STATS process*/
562+
enum offload_act_command command;
563+
enum flow_action_id id;
564+
u32 index;
565+
struct flow_stats stats;
566+
struct flow_action action;
567+
};
568+
569+
struct flow_offload_action *offload_action_alloc(unsigned int num_actions);
570+
554571
static inline struct flow_rule *
555572
flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd)
556573
{

include/net/pkt_cls.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ static inline void tcf_exts_put_net(struct tcf_exts *exts)
262262
for (; 0; (void)(i), (void)(a), (void)(exts))
263263
#endif
264264

265+
#define tcf_act_for_each_action(i, a, actions) \
266+
for (i = 0; i < TCA_ACT_MAX_PRIO && ((a) = actions[i]); i++)
267+
265268
static inline void
266269
tcf_exts_stats_update(const struct tcf_exts *exts,
267270
u64 bytes, u64 packets, u64 drops, u64 lastuse,
@@ -539,6 +542,8 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
539542
int tc_setup_offload_action(struct flow_action *flow_action,
540543
const struct tcf_exts *exts);
541544
void tc_cleanup_offload_action(struct flow_action *flow_action);
545+
int tc_setup_action(struct flow_action *flow_action,
546+
struct tc_action *actions[]);
542547

543548
int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
544549
void *type_data, bool err_stop, bool rtnl_held);

net/core/flow_offload.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,26 @@ struct flow_rule *flow_rule_alloc(unsigned int num_actions)
2727
}
2828
EXPORT_SYMBOL(flow_rule_alloc);
2929

30+
struct flow_offload_action *offload_action_alloc(unsigned int num_actions)
31+
{
32+
struct flow_offload_action *fl_action;
33+
int i;
34+
35+
fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions),
36+
GFP_KERNEL);
37+
if (!fl_action)
38+
return NULL;
39+
40+
fl_action->action.num_entries = num_actions;
41+
/* Pre-fill each action hw_stats with DONT_CARE.
42+
* Caller can override this if it wants stats for a given action.
43+
*/
44+
for (i = 0; i < num_actions; i++)
45+
fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
46+
47+
return fl_action;
48+
}
49+
3050
#define FLOW_DISSECTOR_MATCH(__rule, __type, __out) \
3151
const struct flow_match *__m = &(__rule)->match; \
3252
struct flow_dissector *__d = (__m)->dissector; \
@@ -549,19 +569,25 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
549569
void (*cleanup)(struct flow_block_cb *block_cb))
550570
{
551571
struct flow_indr_dev *this;
572+
u32 count = 0;
573+
int err;
552574

553575
mutex_lock(&flow_indr_block_lock);
576+
if (bo) {
577+
if (bo->command == FLOW_BLOCK_BIND)
578+
indir_dev_add(data, dev, sch, type, cleanup, bo);
579+
else if (bo->command == FLOW_BLOCK_UNBIND)
580+
indir_dev_remove(data);
581+
}
554582

555-
if (bo->command == FLOW_BLOCK_BIND)
556-
indir_dev_add(data, dev, sch, type, cleanup, bo);
557-
else if (bo->command == FLOW_BLOCK_UNBIND)
558-
indir_dev_remove(data);
559-
560-
list_for_each_entry(this, &flow_block_indr_dev_list, list)
561-
this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup);
583+
list_for_each_entry(this, &flow_block_indr_dev_list, list) {
584+
err = this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup);
585+
if (!err)
586+
count++;
587+
}
562588

563589
mutex_unlock(&flow_indr_block_lock);
564590

565-
return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
591+
return (bo && list_empty(&bo->cb_list)) ? -EOPNOTSUPP : count;
566592
}
567593
EXPORT_SYMBOL(flow_indr_dev_setup_offload);

net/sched/act_api.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#include <net/sock.h>
2020
#include <net/sch_generic.h>
2121
#include <net/pkt_cls.h>
22+
#include <net/tc_act/tc_pedit.h>
2223
#include <net/act_api.h>
2324
#include <net/netlink.h>
25+
#include <net/flow_offload.h>
2426

2527
#ifdef CONFIG_INET
2628
DEFINE_STATIC_KEY_FALSE(tcf_frag_xmit_count);
@@ -129,8 +131,92 @@ static void free_tcf(struct tc_action *p)
129131
kfree(p);
130132
}
131133

134+
static unsigned int tcf_offload_act_num_actions_single(struct tc_action *act)
135+
{
136+
if (is_tcf_pedit(act))
137+
return tcf_pedit_nkeys(act);
138+
else
139+
return 1;
140+
}
141+
142+
static int offload_action_init(struct flow_offload_action *fl_action,
143+
struct tc_action *act,
144+
enum offload_act_command cmd,
145+
struct netlink_ext_ack *extack)
146+
{
147+
fl_action->extack = extack;
148+
fl_action->command = cmd;
149+
fl_action->index = act->tcfa_index;
150+
151+
if (act->ops->offload_act_setup)
152+
return act->ops->offload_act_setup(act, fl_action, NULL, false);
153+
154+
return -EOPNOTSUPP;
155+
}
156+
157+
static int tcf_action_offload_cmd(struct flow_offload_action *fl_act,
158+
struct netlink_ext_ack *extack)
159+
{
160+
int err;
161+
162+
err = flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT,
163+
fl_act, NULL, NULL);
164+
if (err < 0)
165+
return err;
166+
167+
return 0;
168+
}
169+
170+
/* offload the tc action after it is inserted */
171+
static int tcf_action_offload_add(struct tc_action *action,
172+
struct netlink_ext_ack *extack)
173+
{
174+
struct tc_action *actions[TCA_ACT_MAX_PRIO] = {
175+
[0] = action,
176+
};
177+
struct flow_offload_action *fl_action;
178+
int num, err = 0;
179+
180+
num = tcf_offload_act_num_actions_single(action);
181+
fl_action = offload_action_alloc(num);
182+
if (!fl_action)
183+
return -ENOMEM;
184+
185+
err = offload_action_init(fl_action, action, FLOW_ACT_REPLACE, extack);
186+
if (err)
187+
goto fl_err;
188+
189+
err = tc_setup_action(&fl_action->action, actions);
190+
if (err) {
191+
NL_SET_ERR_MSG_MOD(extack,
192+
"Failed to setup tc actions for offload\n");
193+
goto fl_err;
194+
}
195+
196+
err = tcf_action_offload_cmd(fl_action, extack);
197+
tc_cleanup_offload_action(&fl_action->action);
198+
199+
fl_err:
200+
kfree(fl_action);
201+
202+
return err;
203+
}
204+
205+
static int tcf_action_offload_del(struct tc_action *action)
206+
{
207+
struct flow_offload_action fl_act = {};
208+
int err = 0;
209+
210+
err = offload_action_init(&fl_act, action, FLOW_ACT_DESTROY, NULL);
211+
if (err)
212+
return err;
213+
214+
return tcf_action_offload_cmd(&fl_act, NULL);
215+
}
216+
132217
static void tcf_action_cleanup(struct tc_action *p)
133218
{
219+
tcf_action_offload_del(p);
134220
if (p->ops->cleanup)
135221
p->ops->cleanup(p);
136222

@@ -1061,6 +1147,11 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
10611147
return ERR_PTR(err);
10621148
}
10631149

1150+
static bool tc_act_bind(u32 flags)
1151+
{
1152+
return !!(flags & TCA_ACT_FLAGS_BIND);
1153+
}
1154+
10641155
/* Returns numbers of initialized actions or negative error. */
10651156

10661157
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1103,6 +1194,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
11031194
sz += tcf_action_fill_size(act);
11041195
/* Start from index 0 */
11051196
actions[i - 1] = act;
1197+
if (!tc_act_bind(flags))
1198+
tcf_action_offload_add(act, extack);
11061199
}
11071200

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

net/sched/act_csum.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,9 @@ static int tcf_csum_offload_act_setup(struct tc_action *act, void *entry_data,
705705
entry->csum_flags = tcf_csum_update_flags(act);
706706
*index_inc = 1;
707707
} else {
708-
return -EOPNOTSUPP;
708+
struct flow_offload_action *fl_action = entry_data;
709+
710+
fl_action->id = FLOW_ACTION_CSUM;
709711
}
710712

711713
return 0;

net/sched/act_ct.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1505,7 +1505,9 @@ static int tcf_ct_offload_act_setup(struct tc_action *act, void *entry_data,
15051505
entry->ct.flow_table = tcf_ct_ft(act);
15061506
*index_inc = 1;
15071507
} else {
1508-
return -EOPNOTSUPP;
1508+
struct flow_offload_action *fl_action = entry_data;
1509+
1510+
fl_action->id = FLOW_ACTION_CT;
15091511
}
15101512

15111513
return 0;

net/sched/act_gact.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,18 @@ static int tcf_gact_offload_act_setup(struct tc_action *act, void *entry_data,
272272
}
273273
*index_inc = 1;
274274
} else {
275-
return -EOPNOTSUPP;
275+
struct flow_offload_action *fl_action = entry_data;
276+
277+
if (is_tcf_gact_ok(act))
278+
fl_action->id = FLOW_ACTION_ACCEPT;
279+
else if (is_tcf_gact_shot(act))
280+
fl_action->id = FLOW_ACTION_DROP;
281+
else if (is_tcf_gact_trap(act))
282+
fl_action->id = FLOW_ACTION_TRAP;
283+
else if (is_tcf_gact_goto_chain(act))
284+
fl_action->id = FLOW_ACTION_GOTO;
285+
else
286+
return -EOPNOTSUPP;
276287
}
277288

278289
return 0;

net/sched/act_gate.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,9 @@ static int tcf_gate_offload_act_setup(struct tc_action *act, void *entry_data,
637637
return err;
638638
*index_inc = 1;
639639
} else {
640-
return -EOPNOTSUPP;
640+
struct flow_offload_action *fl_action = entry_data;
641+
642+
fl_action->id = FLOW_ACTION_GATE;
641643
}
642644

643645
return 0;

net/sched/act_mirred.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,18 @@ static int tcf_mirred_offload_act_setup(struct tc_action *act, void *entry_data,
482482
}
483483
*index_inc = 1;
484484
} else {
485-
return -EOPNOTSUPP;
485+
struct flow_offload_action *fl_action = entry_data;
486+
487+
if (is_tcf_mirred_egress_redirect(act))
488+
fl_action->id = FLOW_ACTION_REDIRECT;
489+
else if (is_tcf_mirred_egress_mirror(act))
490+
fl_action->id = FLOW_ACTION_MIRRED;
491+
else if (is_tcf_mirred_ingress_redirect(act))
492+
fl_action->id = FLOW_ACTION_REDIRECT_INGRESS;
493+
else if (is_tcf_mirred_ingress_mirror(act))
494+
fl_action->id = FLOW_ACTION_MIRRED_INGRESS;
495+
else
496+
return -EOPNOTSUPP;
486497
}
487498

488499
return 0;

net/sched/act_mpls.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,21 @@ static int tcf_mpls_offload_act_setup(struct tc_action *act, void *entry_data,
415415
}
416416
*index_inc = 1;
417417
} else {
418-
return -EOPNOTSUPP;
418+
struct flow_offload_action *fl_action = entry_data;
419+
420+
switch (tcf_mpls_action(act)) {
421+
case TCA_MPLS_ACT_PUSH:
422+
fl_action->id = FLOW_ACTION_MPLS_PUSH;
423+
break;
424+
case TCA_MPLS_ACT_POP:
425+
fl_action->id = FLOW_ACTION_MPLS_POP;
426+
break;
427+
case TCA_MPLS_ACT_MODIFY:
428+
fl_action->id = FLOW_ACTION_MPLS_MANGLE;
429+
break;
430+
default:
431+
return -EOPNOTSUPP;
432+
}
419433
}
420434

421435
return 0;

net/sched/act_police.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,9 @@ static int tcf_police_offload_act_setup(struct tc_action *act, void *entry_data,
421421
entry->police.mtu = tcf_police_tcfp_mtu(act);
422422
*index_inc = 1;
423423
} else {
424-
return -EOPNOTSUPP;
424+
struct flow_offload_action *fl_action = entry_data;
425+
426+
fl_action->id = FLOW_ACTION_POLICE;
425427
}
426428

427429
return 0;

net/sched/act_sample.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,9 @@ static int tcf_sample_offload_act_setup(struct tc_action *act, void *entry_data,
303303
tcf_offload_sample_get_group(entry, act);
304304
*index_inc = 1;
305305
} else {
306-
return -EOPNOTSUPP;
306+
struct flow_offload_action *fl_action = entry_data;
307+
308+
fl_action->id = FLOW_ACTION_SAMPLE;
307309
}
308310

309311
return 0;

net/sched/act_skbedit.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,16 @@ static int tcf_skbedit_offload_act_setup(struct tc_action *act, void *entry_data
347347
}
348348
*index_inc = 1;
349349
} else {
350-
return -EOPNOTSUPP;
350+
struct flow_offload_action *fl_action = entry_data;
351+
352+
if (is_tcf_skbedit_mark(act))
353+
fl_action->id = FLOW_ACTION_MARK;
354+
else if (is_tcf_skbedit_ptype(act))
355+
fl_action->id = FLOW_ACTION_PTYPE;
356+
else if (is_tcf_skbedit_priority(act))
357+
fl_action->id = FLOW_ACTION_PRIORITY;
358+
else
359+
return -EOPNOTSUPP;
351360
}
352361

353362
return 0;

net/sched/act_tunnel_key.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,14 @@ static int tcf_tunnel_key_offload_act_setup(struct tc_action *act,
827827
}
828828
*index_inc = 1;
829829
} else {
830-
return -EOPNOTSUPP;
830+
struct flow_offload_action *fl_action = entry_data;
831+
832+
if (is_tcf_tunnel_set(act))
833+
fl_action->id = FLOW_ACTION_TUNNEL_ENCAP;
834+
else if (is_tcf_tunnel_release(act))
835+
fl_action->id = FLOW_ACTION_TUNNEL_DECAP;
836+
else
837+
return -EOPNOTSUPP;
831838
}
832839

833840
return 0;

0 commit comments

Comments
 (0)