diff options
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/act_api.c | 34 | ||||
-rw-r--r-- | net/sched/act_police.c | 62 | ||||
-rw-r--r-- | net/sched/cls_api.c | 51 |
3 files changed, 56 insertions, 91 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index e4a5f2607ffa..d09d0687594b 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
@@ -64,7 +64,6 @@ int __tcf_hash_release(struct tc_action *p, bool bind, bool strict) | |||
64 | if (p->tcfa_bindcnt <= 0 && p->tcfa_refcnt <= 0) { | 64 | if (p->tcfa_bindcnt <= 0 && p->tcfa_refcnt <= 0) { |
65 | if (p->ops->cleanup) | 65 | if (p->ops->cleanup) |
66 | p->ops->cleanup(p, bind); | 66 | p->ops->cleanup(p, bind); |
67 | list_del(&p->list); | ||
68 | tcf_hash_destroy(p->hinfo, p); | 67 | tcf_hash_destroy(p->hinfo, p); |
69 | ret = ACT_P_DELETED; | 68 | ret = ACT_P_DELETED; |
70 | } | 69 | } |
@@ -421,18 +420,19 @@ static struct tc_action_ops *tc_lookup_action(struct nlattr *kind) | |||
421 | return res; | 420 | return res; |
422 | } | 421 | } |
423 | 422 | ||
424 | int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions, | 423 | int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, |
425 | struct tcf_result *res) | 424 | int nr_actions, struct tcf_result *res) |
426 | { | 425 | { |
427 | const struct tc_action *a; | 426 | int ret = -1, i; |
428 | int ret = -1; | ||
429 | 427 | ||
430 | if (skb->tc_verd & TC_NCLS) { | 428 | if (skb->tc_verd & TC_NCLS) { |
431 | skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); | 429 | skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); |
432 | ret = TC_ACT_OK; | 430 | ret = TC_ACT_OK; |
433 | goto exec_done; | 431 | goto exec_done; |
434 | } | 432 | } |
435 | list_for_each_entry(a, actions, list) { | 433 | for (i = 0; i < nr_actions; i++) { |
434 | const struct tc_action *a = actions[i]; | ||
435 | |||
436 | repeat: | 436 | repeat: |
437 | ret = a->ops->act(skb, a, res); | 437 | ret = a->ops->act(skb, a, res); |
438 | if (ret == TC_ACT_REPEAT) | 438 | if (ret == TC_ACT_REPEAT) |
@@ -754,16 +754,6 @@ err_out: | |||
754 | return ERR_PTR(err); | 754 | return ERR_PTR(err); |
755 | } | 755 | } |
756 | 756 | ||
757 | static void cleanup_a(struct list_head *actions) | ||
758 | { | ||
759 | struct tc_action *a, *tmp; | ||
760 | |||
761 | list_for_each_entry_safe(a, tmp, actions, list) { | ||
762 | list_del(&a->list); | ||
763 | kfree(a); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | static int tca_action_flush(struct net *net, struct nlattr *nla, | 757 | static int tca_action_flush(struct net *net, struct nlattr *nla, |
768 | struct nlmsghdr *n, u32 portid) | 758 | struct nlmsghdr *n, u32 portid) |
769 | { | 759 | { |
@@ -905,7 +895,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, | |||
905 | return ret; | 895 | return ret; |
906 | } | 896 | } |
907 | err: | 897 | err: |
908 | cleanup_a(&actions); | 898 | tcf_action_destroy(&actions, 0); |
909 | return ret; | 899 | return ret; |
910 | } | 900 | } |
911 | 901 | ||
@@ -942,15 +932,9 @@ tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n, | |||
942 | 932 | ||
943 | ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions); | 933 | ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions); |
944 | if (ret) | 934 | if (ret) |
945 | goto done; | 935 | return ret; |
946 | 936 | ||
947 | /* dump then free all the actions after update; inserted policy | 937 | return tcf_add_notify(net, n, &actions, portid); |
948 | * stays intact | ||
949 | */ | ||
950 | ret = tcf_add_notify(net, n, &actions, portid); | ||
951 | cleanup_a(&actions); | ||
952 | done: | ||
953 | return ret; | ||
954 | } | 938 | } |
955 | 939 | ||
956 | static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n) | 940 | static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n) |
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index b3c7e975fc9e..8a3be1d99775 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
@@ -63,49 +63,8 @@ static int tcf_act_police_walker(struct net *net, struct sk_buff *skb, | |||
63 | const struct tc_action_ops *ops) | 63 | const struct tc_action_ops *ops) |
64 | { | 64 | { |
65 | struct tc_action_net *tn = net_generic(net, police_net_id); | 65 | struct tc_action_net *tn = net_generic(net, police_net_id); |
66 | struct tcf_hashinfo *hinfo = tn->hinfo; | ||
67 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; | ||
68 | struct nlattr *nest; | ||
69 | |||
70 | spin_lock_bh(&hinfo->lock); | ||
71 | |||
72 | s_i = cb->args[0]; | ||
73 | |||
74 | for (i = 0; i < (POL_TAB_MASK + 1); i++) { | ||
75 | struct hlist_head *head; | ||
76 | struct tc_action *p; | ||
77 | |||
78 | head = &hinfo->htab[tcf_hash(i, POL_TAB_MASK)]; | ||
79 | |||
80 | hlist_for_each_entry_rcu(p, head, tcfa_head) { | ||
81 | index++; | ||
82 | if (index < s_i) | ||
83 | continue; | ||
84 | nest = nla_nest_start(skb, index); | ||
85 | if (nest == NULL) | ||
86 | goto nla_put_failure; | ||
87 | if (type == RTM_DELACTION) | ||
88 | err = tcf_action_dump_1(skb, p, 0, 1); | ||
89 | else | ||
90 | err = tcf_action_dump_1(skb, p, 0, 0); | ||
91 | if (err < 0) { | ||
92 | index--; | ||
93 | nla_nest_cancel(skb, nest); | ||
94 | goto done; | ||
95 | } | ||
96 | nla_nest_end(skb, nest); | ||
97 | n_i++; | ||
98 | } | ||
99 | } | ||
100 | done: | ||
101 | spin_unlock_bh(&hinfo->lock); | ||
102 | if (n_i) | ||
103 | cb->args[0] += n_i; | ||
104 | return n_i; | ||
105 | 66 | ||
106 | nla_put_failure: | 67 | return tcf_generic_walker(tn, skb, cb, type, ops); |
107 | nla_nest_cancel(skb, nest); | ||
108 | goto done; | ||
109 | } | 68 | } |
110 | 69 | ||
111 | static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = { | 70 | static const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = { |
@@ -125,6 +84,7 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, | |||
125 | struct tcf_police *police; | 84 | struct tcf_police *police; |
126 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; | 85 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; |
127 | struct tc_action_net *tn = net_generic(net, police_net_id); | 86 | struct tc_action_net *tn = net_generic(net, police_net_id); |
87 | bool exists = false; | ||
128 | int size; | 88 | int size; |
129 | 89 | ||
130 | if (nla == NULL) | 90 | if (nla == NULL) |
@@ -139,24 +99,24 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, | |||
139 | size = nla_len(tb[TCA_POLICE_TBF]); | 99 | size = nla_len(tb[TCA_POLICE_TBF]); |
140 | if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat)) | 100 | if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat)) |
141 | return -EINVAL; | 101 | return -EINVAL; |
102 | |||
142 | parm = nla_data(tb[TCA_POLICE_TBF]); | 103 | parm = nla_data(tb[TCA_POLICE_TBF]); |
104 | exists = tcf_hash_check(tn, parm->index, a, bind); | ||
105 | if (exists && bind) | ||
106 | return 0; | ||
143 | 107 | ||
144 | if (parm->index) { | 108 | if (!exists) { |
145 | if (tcf_hash_check(tn, parm->index, a, bind)) { | ||
146 | if (ovr) | ||
147 | goto override; | ||
148 | /* not replacing */ | ||
149 | return -EEXIST; | ||
150 | } | ||
151 | } else { | ||
152 | ret = tcf_hash_create(tn, parm->index, NULL, a, | 109 | ret = tcf_hash_create(tn, parm->index, NULL, a, |
153 | &act_police_ops, bind, false); | 110 | &act_police_ops, bind, false); |
154 | if (ret) | 111 | if (ret) |
155 | return ret; | 112 | return ret; |
156 | ret = ACT_P_CREATED; | 113 | ret = ACT_P_CREATED; |
114 | } else { | ||
115 | tcf_hash_release(*a, bind); | ||
116 | if (!ovr) | ||
117 | return -EEXIST; | ||
157 | } | 118 | } |
158 | 119 | ||
159 | override: | ||
160 | police = to_police(*a); | 120 | police = to_police(*a); |
161 | if (parm->rate.rate) { | 121 | if (parm->rate.rate) { |
162 | err = -ENOMEM; | 122 | err = -ENOMEM; |
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: | |||
541 | void tcf_exts_destroy(struct tcf_exts *exts) | 541 | void 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 | } |
548 | EXPORT_SYMBOL(tcf_exts_destroy); | 552 | EXPORT_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 | } |
599 | EXPORT_SYMBOL(tcf_exts_change); | 610 | EXPORT_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, \ | 613 | static 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 | ||
605 | int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts) | 622 | int 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) { |