aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2016-08-14 01:35:00 -0400
committerDavid S. Miller <davem@davemloft.net>2016-08-17 19:27:51 -0400
commit22dc13c837c33207548c8ee5116b64e2930a6e23 (patch)
tree12a58165f757c38f9fe5e85371e84413f2bfe848
parent2734437ef3c2943090d0914bf91caa6b30451615 (diff)
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: a85a970af265 ("net_sched: move tc_action into tcf_common") Reported-by: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c4
-rw-r--r--include/net/act_api.h4
-rw-r--r--include/net/pkt_cls.h40
-rw-r--r--net/sched/act_api.c11
-rw-r--r--net/sched/cls_api.c51
7 files changed, 85 insertions, 41 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index ee57a89252bb..b4f03748adc0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -8396,12 +8396,14 @@ static int parse_tc_actions(struct ixgbe_adapter *adapter,
8396 struct tcf_exts *exts, u64 *action, u8 *queue) 8396 struct tcf_exts *exts, u64 *action, u8 *queue)
8397{ 8397{
8398 const struct tc_action *a; 8398 const struct tc_action *a;
8399 LIST_HEAD(actions);
8399 int err; 8400 int err;
8400 8401
8401 if (tc_no_actions(exts)) 8402 if (tc_no_actions(exts))
8402 return -EINVAL; 8403 return -EINVAL;
8403 8404
8404 tc_for_each_action(a, exts) { 8405 tcf_exts_to_list(exts, &actions);
8406 list_for_each_entry(a, &actions, list) {
8405 8407
8406 /* Drop action */ 8408 /* Drop action */
8407 if (is_tcf_gact_shot(a)) { 8409 if (is_tcf_gact_shot(a)) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 0f19b01e3fff..dc8b1cb0fdc8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -318,6 +318,7 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
318 u32 *action, u32 *flow_tag) 318 u32 *action, u32 *flow_tag)
319{ 319{
320 const struct tc_action *a; 320 const struct tc_action *a;
321 LIST_HEAD(actions);
321 322
322 if (tc_no_actions(exts)) 323 if (tc_no_actions(exts))
323 return -EINVAL; 324 return -EINVAL;
@@ -325,7 +326,8 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
325 *flow_tag = MLX5_FS_DEFAULT_FLOW_TAG; 326 *flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
326 *action = 0; 327 *action = 0;
327 328
328 tc_for_each_action(a, exts) { 329 tcf_exts_to_list(exts, &actions);
330 list_for_each_entry(a, &actions, list) {
329 /* Only support a single action per rule */ 331 /* Only support a single action per rule */
330 if (*action) 332 if (*action)
331 return -EINVAL; 333 return -EINVAL;
@@ -362,13 +364,15 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
362 u32 *action, u32 *dest_vport) 364 u32 *action, u32 *dest_vport)
363{ 365{
364 const struct tc_action *a; 366 const struct tc_action *a;
367 LIST_HEAD(actions);
365 368
366 if (tc_no_actions(exts)) 369 if (tc_no_actions(exts))
367 return -EINVAL; 370 return -EINVAL;
368 371
369 *action = 0; 372 *action = 0;
370 373
371 tc_for_each_action(a, exts) { 374 tcf_exts_to_list(exts, &actions);
375 list_for_each_entry(a, &actions, list) {
372 /* Only support a single action per rule */ 376 /* Only support a single action per rule */
373 if (*action) 377 if (*action)
374 return -EINVAL; 378 return -EINVAL;
@@ -503,6 +507,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
503 struct mlx5e_tc_flow *flow; 507 struct mlx5e_tc_flow *flow;
504 struct tc_action *a; 508 struct tc_action *a;
505 struct mlx5_fc *counter; 509 struct mlx5_fc *counter;
510 LIST_HEAD(actions);
506 u64 bytes; 511 u64 bytes;
507 u64 packets; 512 u64 packets;
508 u64 lastuse; 513 u64 lastuse;
@@ -518,7 +523,8 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
518 523
519 mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); 524 mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
520 525
521 tc_for_each_action(a, f->exts) 526 tcf_exts_to_list(f->exts, &actions);
527 list_for_each_entry(a, &actions, list)
522 tcf_action_stats_update(a, bytes, packets, lastuse); 528 tcf_action_stats_update(a, bytes, packets, lastuse);
523 529
524 return 0; 530 return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 1fe9fbdc9102..1f8168906811 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1121,6 +1121,7 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
1121 bool ingress) 1121 bool ingress)
1122{ 1122{
1123 const struct tc_action *a; 1123 const struct tc_action *a;
1124 LIST_HEAD(actions);
1124 int err; 1125 int err;
1125 1126
1126 if (!tc_single_action(cls->exts)) { 1127 if (!tc_single_action(cls->exts)) {
@@ -1128,7 +1129,8 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
1128 return -ENOTSUPP; 1129 return -ENOTSUPP;
1129 } 1130 }
1130 1131
1131 tc_for_each_action(a, cls->exts) { 1132 tcf_exts_to_list(cls->exts, &actions);
1133 list_for_each_entry(a, &actions, list) {
1132 if (!is_tcf_mirred_mirror(a) || protocol != htons(ETH_P_ALL)) 1134 if (!is_tcf_mirred_mirror(a) || protocol != htons(ETH_P_ALL))
1133 return -ENOTSUPP; 1135 return -ENOTSUPP;
1134 1136
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 870332ff61eb..82f3c912a5b1 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -176,8 +176,8 @@ int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
176int tcf_unregister_action(struct tc_action_ops *a, 176int tcf_unregister_action(struct tc_action_ops *a,
177 struct pernet_operations *ops); 177 struct pernet_operations *ops);
178int tcf_action_destroy(struct list_head *actions, int bind); 178int tcf_action_destroy(struct list_head *actions, int bind);
179int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions, 179int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
180 struct tcf_result *res); 180 int nr_actions, struct tcf_result *res);
181int tcf_action_init(struct net *net, struct nlattr *nla, 181int tcf_action_init(struct net *net, struct nlattr *nla,
182 struct nlattr *est, char *n, int ovr, 182 struct nlattr *est, char *n, int ovr,
183 int bind, struct list_head *); 183 int bind, struct list_head *);
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 00dd5c4c1d0a..c99508d426cc 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -59,7 +59,8 @@ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
59struct tcf_exts { 59struct tcf_exts {
60#ifdef CONFIG_NET_CLS_ACT 60#ifdef CONFIG_NET_CLS_ACT
61 __u32 type; /* for backward compat(TCA_OLD_COMPAT) */ 61 __u32 type; /* for backward compat(TCA_OLD_COMPAT) */
62 struct list_head actions; 62 int nr_actions;
63 struct tc_action **actions;
63#endif 64#endif
64 /* Map to export classifier specific extension TLV types to the 65 /* Map to export classifier specific extension TLV types to the
65 * generic extensions API. Unsupported extensions must be set to 0. 66 * 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)
72{ 73{
73#ifdef CONFIG_NET_CLS_ACT 74#ifdef CONFIG_NET_CLS_ACT
74 exts->type = 0; 75 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 */
76#endif 80#endif
77 exts->action = action; 81 exts->action = action;
78 exts->police = police; 82 exts->police = police;
@@ -89,7 +93,7 @@ static inline int
89tcf_exts_is_predicative(struct tcf_exts *exts) 93tcf_exts_is_predicative(struct tcf_exts *exts)
90{ 94{
91#ifdef CONFIG_NET_CLS_ACT 95#ifdef CONFIG_NET_CLS_ACT
92 return !list_empty(&exts->actions); 96 return exts->nr_actions;
93#else 97#else
94 return 0; 98 return 0;
95#endif 99#endif
@@ -108,6 +112,20 @@ tcf_exts_is_available(struct tcf_exts *exts)
108 return tcf_exts_is_predicative(exts); 112 return tcf_exts_is_predicative(exts);
109} 113}
110 114
115static 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
111/** 129/**
112 * tcf_exts_exec - execute tc filter extensions 130 * tcf_exts_exec - execute tc filter extensions
113 * @skb: socket buffer 131 * @skb: socket buffer
@@ -124,27 +142,21 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
124 struct tcf_result *res) 142 struct tcf_result *res)
125{ 143{
126#ifdef CONFIG_NET_CLS_ACT 144#ifdef CONFIG_NET_CLS_ACT
127 if (!list_empty(&exts->actions)) 145 if (exts->nr_actions)
128 return tcf_action_exec(skb, &exts->actions, res); 146 return tcf_action_exec(skb, exts->actions, exts->nr_actions,
147 res);
129#endif 148#endif
130 return 0; 149 return 0;
131} 150}
132 151
133#ifdef CONFIG_NET_CLS_ACT 152#ifdef CONFIG_NET_CLS_ACT
134 153
135#define tc_no_actions(_exts) \ 154#define tc_no_actions(_exts) ((_exts)->nr_actions == 0)
136 (list_empty(&(_exts)->actions)) 155#define tc_single_action(_exts) ((_exts)->nr_actions == 1)
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))
143 156
144#else /* CONFIG_NET_CLS_ACT */ 157#else /* CONFIG_NET_CLS_ACT */
145 158
146#define tc_no_actions(_exts) true 159#define tc_no_actions(_exts) true
147#define tc_for_each_action(_a, _exts) while ((void)(_a), 0)
148#define tc_single_action(_exts) false 160#define tc_single_action(_exts) false
149 161
150#endif /* CONFIG_NET_CLS_ACT */ 162#endif /* CONFIG_NET_CLS_ACT */
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index b4c7be38b632..d09d0687594b 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -420,18 +420,19 @@ static struct tc_action_ops *tc_lookup_action(struct nlattr *kind)
420 return res; 420 return res;
421} 421}
422 422
423int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions, 423int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
424 struct tcf_result *res) 424 int nr_actions, struct tcf_result *res)
425{ 425{
426 const struct tc_action *a; 426 int ret = -1, i;
427 int ret = -1;
428 427
429 if (skb->tc_verd & TC_NCLS) { 428 if (skb->tc_verd & TC_NCLS) {
430 skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); 429 skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
431 ret = TC_ACT_OK; 430 ret = TC_ACT_OK;
432 goto exec_done; 431 goto exec_done;
433 } 432 }
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
435repeat: 436repeat:
436 ret = a->ops->act(skb, a, res); 437 ret = a->ops->act(skb, a, res);
437 if (ret == TC_ACT_REPEAT) 438 if (ret == TC_ACT_REPEAT)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 843a716a4303..a7c5645373af 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -541,8 +541,12 @@ out:
541void tcf_exts_destroy(struct tcf_exts *exts) 541void tcf_exts_destroy(struct tcf_exts *exts)
542{ 542{
543#ifdef CONFIG_NET_CLS_ACT 543#ifdef CONFIG_NET_CLS_ACT
544 tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND); 544 LIST_HEAD(actions);
545 INIT_LIST_HEAD(&exts->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;
546#endif 550#endif
547} 551}
548EXPORT_SYMBOL(tcf_exts_destroy); 552EXPORT_SYMBOL(tcf_exts_destroy);
@@ -554,7 +558,6 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
554 { 558 {
555 struct tc_action *act; 559 struct tc_action *act;
556 560
557 INIT_LIST_HEAD(&exts->actions);
558 if (exts->police && tb[exts->police]) { 561 if (exts->police && tb[exts->police]) {
559 act = tcf_action_init_1(net, tb[exts->police], rate_tlv, 562 act = tcf_action_init_1(net, tb[exts->police], rate_tlv,
560 "police", ovr, 563 "police", ovr,
@@ -563,14 +566,20 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
563 return PTR_ERR(act); 566 return PTR_ERR(act);
564 567
565 act->type = exts->type = TCA_OLD_COMPAT; 568 act->type = exts->type = TCA_OLD_COMPAT;
566 list_add(&act->list, &exts->actions); 569 exts->actions[0] = act;
570 exts->nr_actions = 1;
567 } else if (exts->action && tb[exts->action]) { 571 } else if (exts->action && tb[exts->action]) {
568 int err; 572 LIST_HEAD(actions);
573 int err, i = 0;
574
569 err = tcf_action_init(net, tb[exts->action], rate_tlv, 575 err = tcf_action_init(net, tb[exts->action], rate_tlv,
570 NULL, ovr, 576 NULL, ovr,
571 TCA_ACT_BIND, &exts->actions); 577 TCA_ACT_BIND, &actions);
572 if (err) 578 if (err)
573 return err; 579 return err;
580 list_for_each_entry(act, &actions, list)
581 exts->actions[i++] = act;
582 exts->nr_actions = i;
574 } 583 }
575 } 584 }
576#else 585#else
@@ -587,37 +596,49 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
587 struct tcf_exts *src) 596 struct tcf_exts *src)
588{ 597{
589#ifdef CONFIG_NET_CLS_ACT 598#ifdef CONFIG_NET_CLS_ACT
590 LIST_HEAD(tmp); 599 struct tcf_exts old = *dst;
600
591 tcf_tree_lock(tp); 601 tcf_tree_lock(tp);
592 list_splice_init(&dst->actions, &tmp); 602 dst->nr_actions = src->nr_actions;
593 list_splice(&src->actions, &dst->actions); 603 dst->actions = src->actions;
594 dst->type = src->type; 604 dst->type = src->type;
595 tcf_tree_unlock(tp); 605 tcf_tree_unlock(tp);
596 tcf_action_destroy(&tmp, TCA_ACT_UNBIND); 606
607 tcf_exts_destroy(&old);
597#endif 608#endif
598} 609}
599EXPORT_SYMBOL(tcf_exts_change); 610EXPORT_SYMBOL(tcf_exts_change);
600 611
601#define tcf_exts_first_act(ext) \ 612#ifdef CONFIG_NET_CLS_ACT
602 list_first_entry_or_null(&(exts)->actions, \ 613static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts)
603 struct tc_action, list) 614{
615 if (exts->nr_actions == 0)
616 return NULL;
617 else
618 return exts->actions[0];
619}
620#endif
604 621
605int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) 622int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
606{ 623{
607#ifdef CONFIG_NET_CLS_ACT 624#ifdef CONFIG_NET_CLS_ACT
608 struct nlattr *nest; 625 struct nlattr *nest;
609 626
610 if (exts->action && !list_empty(&exts->actions)) { 627 if (exts->action && exts->nr_actions) {
611 /* 628 /*
612 * again for backward compatible mode - we want 629 * again for backward compatible mode - we want
613 * to work with both old and new modes of entering 630 * to work with both old and new modes of entering
614 * tc data even if iproute2 was newer - jhs 631 * tc data even if iproute2 was newer - jhs
615 */ 632 */
616 if (exts->type != TCA_OLD_COMPAT) { 633 if (exts->type != TCA_OLD_COMPAT) {
634 LIST_HEAD(actions);
635
617 nest = nla_nest_start(skb, exts->action); 636 nest = nla_nest_start(skb, exts->action);
618 if (nest == NULL) 637 if (nest == NULL)
619 goto nla_put_failure; 638 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)
621 goto nla_put_failure; 642 goto nla_put_failure;
622 nla_nest_end(skb, nest); 643 nla_nest_end(skb, nest);
623 } else if (exts->police) { 644 } else if (exts->police) {