Skip to content

Commit 22dc13c

Browse files
congwangdavem330
authored andcommitted
net_sched: convert tcf_exts from list to pointer array
As pointed out by Jamal, an action could be shared by multiple filters, so we can't use list to chain them any more after we get rid of the original tc_action. Instead, we could just save pointers to these actions in tcf_exts, since they are refcount'ed, so convert the list to an array of pointers. The "ugly" part is the action API still accepts list as a parameter, I just introduce a helper function to convert the array of pointers to a list, instead of relying on the C99 feature to iterate the array. Fixes: a85a970 ("net_sched: move tc_action into tcf_common") Reported-by: Jamal Hadi Salim <[email protected]> Cc: Jamal Hadi Salim <[email protected]> Signed-off-by: Cong Wang <[email protected]> Acked-by: Jamal Hadi Salim <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2734437 commit 22dc13c

File tree

7 files changed

+85
-41
lines changed

7 files changed

+85
-41
lines changed

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8396,12 +8396,14 @@ static int parse_tc_actions(struct ixgbe_adapter *adapter,
83968396
struct tcf_exts *exts, u64 *action, u8 *queue)
83978397
{
83988398
const struct tc_action *a;
8399+
LIST_HEAD(actions);
83998400
int err;
84008401

84018402
if (tc_no_actions(exts))
84028403
return -EINVAL;
84038404

8404-
tc_for_each_action(a, exts) {
8405+
tcf_exts_to_list(exts, &actions);
8406+
list_for_each_entry(a, &actions, list) {
84058407

84068408
/* Drop action */
84078409
if (is_tcf_gact_shot(a)) {

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,14 +318,16 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
318318
u32 *action, u32 *flow_tag)
319319
{
320320
const struct tc_action *a;
321+
LIST_HEAD(actions);
321322

322323
if (tc_no_actions(exts))
323324
return -EINVAL;
324325

325326
*flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
326327
*action = 0;
327328

328-
tc_for_each_action(a, exts) {
329+
tcf_exts_to_list(exts, &actions);
330+
list_for_each_entry(a, &actions, list) {
329331
/* Only support a single action per rule */
330332
if (*action)
331333
return -EINVAL;
@@ -362,13 +364,15 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
362364
u32 *action, u32 *dest_vport)
363365
{
364366
const struct tc_action *a;
367+
LIST_HEAD(actions);
365368

366369
if (tc_no_actions(exts))
367370
return -EINVAL;
368371

369372
*action = 0;
370373

371-
tc_for_each_action(a, exts) {
374+
tcf_exts_to_list(exts, &actions);
375+
list_for_each_entry(a, &actions, list) {
372376
/* Only support a single action per rule */
373377
if (*action)
374378
return -EINVAL;
@@ -503,6 +507,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
503507
struct mlx5e_tc_flow *flow;
504508
struct tc_action *a;
505509
struct mlx5_fc *counter;
510+
LIST_HEAD(actions);
506511
u64 bytes;
507512
u64 packets;
508513
u64 lastuse;
@@ -518,7 +523,8 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
518523

519524
mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
520525

521-
tc_for_each_action(a, f->exts)
526+
tcf_exts_to_list(f->exts, &actions);
527+
list_for_each_entry(a, &actions, list)
522528
tcf_action_stats_update(a, bytes, packets, lastuse);
523529

524530
return 0;

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1121,14 +1121,16 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
11211121
bool ingress)
11221122
{
11231123
const struct tc_action *a;
1124+
LIST_HEAD(actions);
11241125
int err;
11251126

11261127
if (!tc_single_action(cls->exts)) {
11271128
netdev_err(mlxsw_sp_port->dev, "only singular actions are supported\n");
11281129
return -ENOTSUPP;
11291130
}
11301131

1131-
tc_for_each_action(a, cls->exts) {
1132+
tcf_exts_to_list(cls->exts, &actions);
1133+
list_for_each_entry(a, &actions, list) {
11321134
if (!is_tcf_mirred_mirror(a) || protocol != htons(ETH_P_ALL))
11331135
return -ENOTSUPP;
11341136

include/net/act_api.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
176176
int tcf_unregister_action(struct tc_action_ops *a,
177177
struct pernet_operations *ops);
178178
int tcf_action_destroy(struct list_head *actions, int bind);
179-
int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
180-
struct tcf_result *res);
179+
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
180+
int nr_actions, struct tcf_result *res);
181181
int tcf_action_init(struct net *net, struct nlattr *nla,
182182
struct nlattr *est, char *n, int ovr,
183183
int bind, struct list_head *);

include/net/pkt_cls.h

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
5959
struct tcf_exts {
6060
#ifdef CONFIG_NET_CLS_ACT
6161
__u32 type; /* for backward compat(TCA_OLD_COMPAT) */
62-
struct list_head actions;
62+
int nr_actions;
63+
struct tc_action **actions;
6364
#endif
6465
/* Map to export classifier specific extension TLV types to the
6566
* generic extensions API. Unsupported extensions must be set to 0.
@@ -72,7 +73,10 @@ static inline void tcf_exts_init(struct tcf_exts *exts, int action, int police)
7273
{
7374
#ifdef CONFIG_NET_CLS_ACT
7475
exts->type = 0;
75-
INIT_LIST_HEAD(&exts->actions);
76+
exts->nr_actions = 0;
77+
exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
78+
GFP_KERNEL);
79+
WARN_ON(!exts->actions); /* TODO: propagate the error to callers */
7680
#endif
7781
exts->action = action;
7882
exts->police = police;
@@ -89,7 +93,7 @@ static inline int
8993
tcf_exts_is_predicative(struct tcf_exts *exts)
9094
{
9195
#ifdef CONFIG_NET_CLS_ACT
92-
return !list_empty(&exts->actions);
96+
return exts->nr_actions;
9397
#else
9498
return 0;
9599
#endif
@@ -108,6 +112,20 @@ tcf_exts_is_available(struct tcf_exts *exts)
108112
return tcf_exts_is_predicative(exts);
109113
}
110114

115+
static inline void tcf_exts_to_list(const struct tcf_exts *exts,
116+
struct list_head *actions)
117+
{
118+
#ifdef CONFIG_NET_CLS_ACT
119+
int i;
120+
121+
for (i = 0; i < exts->nr_actions; i++) {
122+
struct tc_action *a = exts->actions[i];
123+
124+
list_add(&a->list, actions);
125+
}
126+
#endif
127+
}
128+
111129
/**
112130
* tcf_exts_exec - execute tc filter extensions
113131
* @skb: socket buffer
@@ -124,27 +142,21 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
124142
struct tcf_result *res)
125143
{
126144
#ifdef CONFIG_NET_CLS_ACT
127-
if (!list_empty(&exts->actions))
128-
return tcf_action_exec(skb, &exts->actions, res);
145+
if (exts->nr_actions)
146+
return tcf_action_exec(skb, exts->actions, exts->nr_actions,
147+
res);
129148
#endif
130149
return 0;
131150
}
132151

133152
#ifdef CONFIG_NET_CLS_ACT
134153

135-
#define tc_no_actions(_exts) \
136-
(list_empty(&(_exts)->actions))
137-
138-
#define tc_for_each_action(_a, _exts) \
139-
list_for_each_entry(_a, &(_exts)->actions, list)
140-
141-
#define tc_single_action(_exts) \
142-
(list_is_singular(&(_exts)->actions))
154+
#define tc_no_actions(_exts) ((_exts)->nr_actions == 0)
155+
#define tc_single_action(_exts) ((_exts)->nr_actions == 1)
143156

144157
#else /* CONFIG_NET_CLS_ACT */
145158

146159
#define tc_no_actions(_exts) true
147-
#define tc_for_each_action(_a, _exts) while ((void)(_a), 0)
148160
#define tc_single_action(_exts) false
149161

150162
#endif /* CONFIG_NET_CLS_ACT */

net/sched/act_api.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,18 +420,19 @@ static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
420420
return res;
421421
}
422422

423-
int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
424-
struct tcf_result *res)
423+
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
424+
int nr_actions, struct tcf_result *res)
425425
{
426-
const struct tc_action *a;
427-
int ret = -1;
426+
int ret = -1, i;
428427

429428
if (skb->tc_verd & TC_NCLS) {
430429
skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
431430
ret = TC_ACT_OK;
432431
goto exec_done;
433432
}
434-
list_for_each_entry(a, actions, list) {
433+
for (i = 0; i < nr_actions; i++) {
434+
const struct tc_action *a = actions[i];
435+
435436
repeat:
436437
ret = a->ops->act(skb, a, res);
437438
if (ret == TC_ACT_REPEAT)

net/sched/cls_api.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,12 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
541541
void tcf_exts_destroy(struct tcf_exts *exts)
542542
{
543543
#ifdef CONFIG_NET_CLS_ACT
544-
tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND);
545-
INIT_LIST_HEAD(&exts->actions);
544+
LIST_HEAD(actions);
545+
546+
tcf_exts_to_list(exts, &actions);
547+
tcf_action_destroy(&actions, TCA_ACT_UNBIND);
548+
kfree(exts->actions);
549+
exts->nr_actions = 0;
546550
#endif
547551
}
548552
EXPORT_SYMBOL(tcf_exts_destroy);
@@ -554,7 +558,6 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
554558
{
555559
struct tc_action *act;
556560

557-
INIT_LIST_HEAD(&exts->actions);
558561
if (exts->police && tb[exts->police]) {
559562
act = tcf_action_init_1(net, tb[exts->police], rate_tlv,
560563
"police", ovr,
@@ -563,14 +566,20 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
563566
return PTR_ERR(act);
564567

565568
act->type = exts->type = TCA_OLD_COMPAT;
566-
list_add(&act->list, &exts->actions);
569+
exts->actions[0] = act;
570+
exts->nr_actions = 1;
567571
} else if (exts->action && tb[exts->action]) {
568-
int err;
572+
LIST_HEAD(actions);
573+
int err, i = 0;
574+
569575
err = tcf_action_init(net, tb[exts->action], rate_tlv,
570576
NULL, ovr,
571-
TCA_ACT_BIND, &exts->actions);
577+
TCA_ACT_BIND, &actions);
572578
if (err)
573579
return err;
580+
list_for_each_entry(act, &actions, list)
581+
exts->actions[i++] = act;
582+
exts->nr_actions = i;
574583
}
575584
}
576585
#else
@@ -587,37 +596,49 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
587596
struct tcf_exts *src)
588597
{
589598
#ifdef CONFIG_NET_CLS_ACT
590-
LIST_HEAD(tmp);
599+
struct tcf_exts old = *dst;
600+
591601
tcf_tree_lock(tp);
592-
list_splice_init(&dst->actions, &tmp);
593-
list_splice(&src->actions, &dst->actions);
602+
dst->nr_actions = src->nr_actions;
603+
dst->actions = src->actions;
594604
dst->type = src->type;
595605
tcf_tree_unlock(tp);
596-
tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
606+
607+
tcf_exts_destroy(&old);
597608
#endif
598609
}
599610
EXPORT_SYMBOL(tcf_exts_change);
600611

601-
#define tcf_exts_first_act(ext) \
602-
list_first_entry_or_null(&(exts)->actions, \
603-
struct tc_action, list)
612+
#ifdef CONFIG_NET_CLS_ACT
613+
static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts)
614+
{
615+
if (exts->nr_actions == 0)
616+
return NULL;
617+
else
618+
return exts->actions[0];
619+
}
620+
#endif
604621

605622
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
606623
{
607624
#ifdef CONFIG_NET_CLS_ACT
608625
struct nlattr *nest;
609626

610-
if (exts->action && !list_empty(&exts->actions)) {
627+
if (exts->action && exts->nr_actions) {
611628
/*
612629
* again for backward compatible mode - we want
613630
* to work with both old and new modes of entering
614631
* tc data even if iproute2 was newer - jhs
615632
*/
616633
if (exts->type != TCA_OLD_COMPAT) {
634+
LIST_HEAD(actions);
635+
617636
nest = nla_nest_start(skb, exts->action);
618637
if (nest == NULL)
619638
goto nla_put_failure;
620-
if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0)
639+
640+
tcf_exts_to_list(exts, &actions);
641+
if (tcf_action_dump(skb, &actions, 0, 0) < 0)
621642
goto nla_put_failure;
622643
nla_nest_end(skb, nest);
623644
} else if (exts->police) {

0 commit comments

Comments
 (0)