diff options
Diffstat (limited to 'net/sched/act_api.c')
| -rw-r--r-- | net/sched/act_api.c | 77 |
1 files changed, 44 insertions, 33 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 64f5e328cee9..23b25f89e7e0 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
| 17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
| 18 | #include <linux/slab.h> | ||
| 18 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
| 19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 20 | #include <linux/kmod.h> | 21 | #include <linux/kmod.h> |
| @@ -25,6 +26,11 @@ | |||
| 25 | #include <net/act_api.h> | 26 | #include <net/act_api.h> |
| 26 | #include <net/netlink.h> | 27 | #include <net/netlink.h> |
| 27 | 28 | ||
| 29 | static void tcf_common_free_rcu(struct rcu_head *head) | ||
| 30 | { | ||
| 31 | kfree(container_of(head, struct tcf_common, tcfc_rcu)); | ||
| 32 | } | ||
| 33 | |||
| 28 | void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) | 34 | void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) |
| 29 | { | 35 | { |
| 30 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); | 36 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); |
| @@ -37,7 +43,11 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) | |||
| 37 | write_unlock_bh(hinfo->lock); | 43 | write_unlock_bh(hinfo->lock); |
| 38 | gen_kill_estimator(&p->tcfc_bstats, | 44 | gen_kill_estimator(&p->tcfc_bstats, |
| 39 | &p->tcfc_rate_est); | 45 | &p->tcfc_rate_est); |
| 40 | kfree(p); | 46 | /* |
| 47 | * gen_estimator est_timer() might access p->tcfc_lock | ||
| 48 | * or bstats, wait a RCU grace period before freeing p | ||
| 49 | */ | ||
| 50 | call_rcu(&p->tcfc_rcu, tcf_common_free_rcu); | ||
| 41 | return; | 51 | return; |
| 42 | } | 52 | } |
| 43 | } | 53 | } |
| @@ -152,7 +162,7 @@ int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, | |||
| 152 | } else if (type == RTM_GETACTION) { | 162 | } else if (type == RTM_GETACTION) { |
| 153 | return tcf_dump_walker(skb, cb, a, hinfo); | 163 | return tcf_dump_walker(skb, cb, a, hinfo); |
| 154 | } else { | 164 | } else { |
| 155 | printk("tcf_generic_walker: unknown action %d\n", type); | 165 | WARN(1, "tcf_generic_walker: unknown action %d\n", type); |
| 156 | return -EINVAL; | 166 | return -EINVAL; |
| 157 | } | 167 | } |
| 158 | } | 168 | } |
| @@ -402,8 +412,9 @@ void tcf_action_destroy(struct tc_action *act, int bind) | |||
| 402 | module_put(a->ops->owner); | 412 | module_put(a->ops->owner); |
| 403 | act = act->next; | 413 | act = act->next; |
| 404 | kfree(a); | 414 | kfree(a); |
| 405 | } else { /*FIXME: Remove later - catch insertion bugs*/ | 415 | } else { |
| 406 | printk("tcf_action_destroy: BUG? destroying NULL ops\n"); | 416 | /*FIXME: Remove later - catch insertion bugs*/ |
| 417 | WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n"); | ||
| 407 | act = act->next; | 418 | act = act->next; |
| 408 | kfree(a); | 419 | kfree(a); |
| 409 | } | 420 | } |
| @@ -667,7 +678,8 @@ nlmsg_failure: | |||
| 667 | } | 678 | } |
| 668 | 679 | ||
| 669 | static int | 680 | static int |
| 670 | act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) | 681 | act_get_notify(struct net *net, u32 pid, struct nlmsghdr *n, |
| 682 | struct tc_action *a, int event) | ||
| 671 | { | 683 | { |
| 672 | struct sk_buff *skb; | 684 | struct sk_buff *skb; |
| 673 | 685 | ||
| @@ -679,7 +691,7 @@ act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) | |||
| 679 | return -EINVAL; | 691 | return -EINVAL; |
| 680 | } | 692 | } |
| 681 | 693 | ||
| 682 | return rtnl_unicast(skb, &init_net, pid); | 694 | return rtnl_unicast(skb, net, pid); |
| 683 | } | 695 | } |
| 684 | 696 | ||
| 685 | static struct tc_action * | 697 | static struct tc_action * |
| @@ -742,14 +754,15 @@ static struct tc_action *create_a(int i) | |||
| 742 | 754 | ||
| 743 | act = kzalloc(sizeof(*act), GFP_KERNEL); | 755 | act = kzalloc(sizeof(*act), GFP_KERNEL); |
| 744 | if (act == NULL) { | 756 | if (act == NULL) { |
| 745 | printk("create_a: failed to alloc!\n"); | 757 | pr_debug("create_a: failed to alloc!\n"); |
| 746 | return NULL; | 758 | return NULL; |
| 747 | } | 759 | } |
| 748 | act->order = i; | 760 | act->order = i; |
| 749 | return act; | 761 | return act; |
| 750 | } | 762 | } |
| 751 | 763 | ||
| 752 | static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid) | 764 | static int tca_action_flush(struct net *net, struct nlattr *nla, |
| 765 | struct nlmsghdr *n, u32 pid) | ||
| 753 | { | 766 | { |
| 754 | struct sk_buff *skb; | 767 | struct sk_buff *skb; |
| 755 | unsigned char *b; | 768 | unsigned char *b; |
| @@ -763,13 +776,13 @@ static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid) | |||
| 763 | int err = -ENOMEM; | 776 | int err = -ENOMEM; |
| 764 | 777 | ||
| 765 | if (a == NULL) { | 778 | if (a == NULL) { |
| 766 | printk("tca_action_flush: couldnt create tc_action\n"); | 779 | pr_debug("tca_action_flush: couldnt create tc_action\n"); |
| 767 | return err; | 780 | return err; |
| 768 | } | 781 | } |
| 769 | 782 | ||
| 770 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 783 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
| 771 | if (!skb) { | 784 | if (!skb) { |
| 772 | printk("tca_action_flush: failed skb alloc\n"); | 785 | pr_debug("tca_action_flush: failed skb alloc\n"); |
| 773 | kfree(a); | 786 | kfree(a); |
| 774 | return err; | 787 | return err; |
| 775 | } | 788 | } |
| @@ -808,7 +821,7 @@ static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid) | |||
| 808 | nlh->nlmsg_flags |= NLM_F_ROOT; | 821 | nlh->nlmsg_flags |= NLM_F_ROOT; |
| 809 | module_put(a->ops->owner); | 822 | module_put(a->ops->owner); |
| 810 | kfree(a); | 823 | kfree(a); |
| 811 | err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); | 824 | err = rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); |
| 812 | if (err > 0) | 825 | if (err > 0) |
| 813 | return 0; | 826 | return 0; |
| 814 | 827 | ||
| @@ -825,7 +838,8 @@ noflush_out: | |||
| 825 | } | 838 | } |
| 826 | 839 | ||
| 827 | static int | 840 | static int |
| 828 | tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event) | 841 | tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, |
| 842 | u32 pid, int event) | ||
| 829 | { | 843 | { |
| 830 | int i, ret; | 844 | int i, ret; |
| 831 | struct nlattr *tb[TCA_ACT_MAX_PRIO+1]; | 845 | struct nlattr *tb[TCA_ACT_MAX_PRIO+1]; |
| @@ -837,7 +851,7 @@ tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event) | |||
| 837 | 851 | ||
| 838 | if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) { | 852 | if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) { |
| 839 | if (tb[1] != NULL) | 853 | if (tb[1] != NULL) |
| 840 | return tca_action_flush(tb[1], n, pid); | 854 | return tca_action_flush(net, tb[1], n, pid); |
| 841 | else | 855 | else |
| 842 | return -EINVAL; | 856 | return -EINVAL; |
| 843 | } | 857 | } |
| @@ -858,7 +872,7 @@ tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event) | |||
| 858 | } | 872 | } |
| 859 | 873 | ||
| 860 | if (event == RTM_GETACTION) | 874 | if (event == RTM_GETACTION) |
| 861 | ret = act_get_notify(pid, n, head, event); | 875 | ret = act_get_notify(net, pid, n, head, event); |
| 862 | else { /* delete */ | 876 | else { /* delete */ |
| 863 | struct sk_buff *skb; | 877 | struct sk_buff *skb; |
| 864 | 878 | ||
| @@ -877,7 +891,7 @@ tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event) | |||
| 877 | 891 | ||
| 878 | /* now do the delete */ | 892 | /* now do the delete */ |
| 879 | tcf_action_destroy(head, 0); | 893 | tcf_action_destroy(head, 0); |
| 880 | ret = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, | 894 | ret = rtnetlink_send(skb, net, pid, RTNLGRP_TC, |
| 881 | n->nlmsg_flags&NLM_F_ECHO); | 895 | n->nlmsg_flags&NLM_F_ECHO); |
| 882 | if (ret > 0) | 896 | if (ret > 0) |
| 883 | return 0; | 897 | return 0; |
| @@ -888,8 +902,8 @@ err: | |||
| 888 | return ret; | 902 | return ret; |
| 889 | } | 903 | } |
| 890 | 904 | ||
| 891 | static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, | 905 | static int tcf_add_notify(struct net *net, struct tc_action *a, |
| 892 | u16 flags) | 906 | u32 pid, u32 seq, int event, u16 flags) |
| 893 | { | 907 | { |
| 894 | struct tcamsg *t; | 908 | struct tcamsg *t; |
| 895 | struct nlmsghdr *nlh; | 909 | struct nlmsghdr *nlh; |
| @@ -922,7 +936,7 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, | |||
| 922 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; | 936 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
| 923 | NETLINK_CB(skb).dst_group = RTNLGRP_TC; | 937 | NETLINK_CB(skb).dst_group = RTNLGRP_TC; |
| 924 | 938 | ||
| 925 | err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, flags&NLM_F_ECHO); | 939 | err = rtnetlink_send(skb, net, pid, RTNLGRP_TC, flags&NLM_F_ECHO); |
| 926 | if (err > 0) | 940 | if (err > 0) |
| 927 | err = 0; | 941 | err = 0; |
| 928 | return err; | 942 | return err; |
| @@ -935,7 +949,8 @@ nlmsg_failure: | |||
| 935 | 949 | ||
| 936 | 950 | ||
| 937 | static int | 951 | static int |
| 938 | tcf_action_add(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int ovr) | 952 | tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n, |
| 953 | u32 pid, int ovr) | ||
| 939 | { | 954 | { |
| 940 | int ret = 0; | 955 | int ret = 0; |
| 941 | struct tc_action *act; | 956 | struct tc_action *act; |
| @@ -953,7 +968,7 @@ tcf_action_add(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int ovr) | |||
| 953 | /* dump then free all the actions after update; inserted policy | 968 | /* dump then free all the actions after update; inserted policy |
| 954 | * stays intact | 969 | * stays intact |
| 955 | * */ | 970 | * */ |
| 956 | ret = tcf_add_notify(act, pid, seq, RTM_NEWACTION, n->nlmsg_flags); | 971 | ret = tcf_add_notify(net, act, pid, seq, RTM_NEWACTION, n->nlmsg_flags); |
| 957 | for (a = act; a; a = act) { | 972 | for (a = act; a; a = act) { |
| 958 | act = a->next; | 973 | act = a->next; |
| 959 | kfree(a); | 974 | kfree(a); |
| @@ -969,15 +984,12 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 969 | u32 pid = skb ? NETLINK_CB(skb).pid : 0; | 984 | u32 pid = skb ? NETLINK_CB(skb).pid : 0; |
| 970 | int ret = 0, ovr = 0; | 985 | int ret = 0, ovr = 0; |
| 971 | 986 | ||
| 972 | if (!net_eq(net, &init_net)) | ||
| 973 | return -EINVAL; | ||
| 974 | |||
| 975 | ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL); | 987 | ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL); |
| 976 | if (ret < 0) | 988 | if (ret < 0) |
| 977 | return ret; | 989 | return ret; |
| 978 | 990 | ||
| 979 | if (tca[TCA_ACT_TAB] == NULL) { | 991 | if (tca[TCA_ACT_TAB] == NULL) { |
| 980 | printk("tc_ctl_action: received NO action attribs\n"); | 992 | pr_notice("tc_ctl_action: received NO action attribs\n"); |
| 981 | return -EINVAL; | 993 | return -EINVAL; |
| 982 | } | 994 | } |
| 983 | 995 | ||
| @@ -994,15 +1006,17 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 994 | if (n->nlmsg_flags&NLM_F_REPLACE) | 1006 | if (n->nlmsg_flags&NLM_F_REPLACE) |
| 995 | ovr = 1; | 1007 | ovr = 1; |
| 996 | replay: | 1008 | replay: |
| 997 | ret = tcf_action_add(tca[TCA_ACT_TAB], n, pid, ovr); | 1009 | ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, pid, ovr); |
| 998 | if (ret == -EAGAIN) | 1010 | if (ret == -EAGAIN) |
| 999 | goto replay; | 1011 | goto replay; |
| 1000 | break; | 1012 | break; |
| 1001 | case RTM_DELACTION: | 1013 | case RTM_DELACTION: |
| 1002 | ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_DELACTION); | 1014 | ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, |
| 1015 | pid, RTM_DELACTION); | ||
| 1003 | break; | 1016 | break; |
| 1004 | case RTM_GETACTION: | 1017 | case RTM_GETACTION: |
| 1005 | ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_GETACTION); | 1018 | ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, |
| 1019 | pid, RTM_GETACTION); | ||
| 1006 | break; | 1020 | break; |
| 1007 | default: | 1021 | default: |
| 1008 | BUG(); | 1022 | BUG(); |
| @@ -1042,7 +1056,6 @@ find_dump_kind(const struct nlmsghdr *n) | |||
| 1042 | static int | 1056 | static int |
| 1043 | tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) | 1057 | tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) |
| 1044 | { | 1058 | { |
| 1045 | struct net *net = sock_net(skb->sk); | ||
| 1046 | struct nlmsghdr *nlh; | 1059 | struct nlmsghdr *nlh; |
| 1047 | unsigned char *b = skb_tail_pointer(skb); | 1060 | unsigned char *b = skb_tail_pointer(skb); |
| 1048 | struct nlattr *nest; | 1061 | struct nlattr *nest; |
| @@ -1052,11 +1065,8 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1052 | struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh); | 1065 | struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh); |
| 1053 | struct nlattr *kind = find_dump_kind(cb->nlh); | 1066 | struct nlattr *kind = find_dump_kind(cb->nlh); |
| 1054 | 1067 | ||
| 1055 | if (!net_eq(net, &init_net)) | ||
| 1056 | return 0; | ||
| 1057 | |||
| 1058 | if (kind == NULL) { | 1068 | if (kind == NULL) { |
| 1059 | printk("tc_dump_action: action bad kind\n"); | 1069 | pr_info("tc_dump_action: action bad kind\n"); |
| 1060 | return 0; | 1070 | return 0; |
| 1061 | } | 1071 | } |
| 1062 | 1072 | ||
| @@ -1069,7 +1079,8 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1069 | a.ops = a_o; | 1079 | a.ops = a_o; |
| 1070 | 1080 | ||
| 1071 | if (a_o->walk == NULL) { | 1081 | if (a_o->walk == NULL) { |
| 1072 | printk("tc_dump_action: %s !capable of dumping table\n", a_o->kind); | 1082 | WARN(1, "tc_dump_action: %s !capable of dumping table\n", |
| 1083 | a_o->kind); | ||
| 1073 | goto nla_put_failure; | 1084 | goto nla_put_failure; |
| 1074 | } | 1085 | } |
| 1075 | 1086 | ||
