aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_api.c
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 /net/sched/cls_api.c
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>
Diffstat (limited to 'net/sched/cls_api.c')
-rw-r--r--net/sched/cls_api.c51
1 files changed, 36 insertions, 15 deletions
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) {