diff options
Diffstat (limited to 'net/sched')
42 files changed, 706 insertions, 403 deletions
diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 929218a47620..2f691fb180d1 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig | |||
| @@ -328,13 +328,16 @@ config NET_CLS_FLOW | |||
| 328 | module will be called cls_flow. | 328 | module will be called cls_flow. |
| 329 | 329 | ||
| 330 | config NET_CLS_CGROUP | 330 | config NET_CLS_CGROUP |
| 331 | bool "Control Group Classifier" | 331 | tristate "Control Group Classifier" |
| 332 | select NET_CLS | 332 | select NET_CLS |
| 333 | depends on CGROUPS | 333 | depends on CGROUPS |
| 334 | ---help--- | 334 | ---help--- |
| 335 | Say Y here if you want to classify packets based on the control | 335 | Say Y here if you want to classify packets based on the control |
| 336 | cgroup of their process. | 336 | cgroup of their process. |
| 337 | 337 | ||
| 338 | To compile this code as a module, choose M here: the | ||
| 339 | module will be called cls_cgroup. | ||
| 340 | |||
| 338 | config NET_EMATCH | 341 | config NET_EMATCH |
| 339 | bool "Extended Matches" | 342 | bool "Extended Matches" |
| 340 | select NET_CLS | 343 | select NET_CLS |
| @@ -433,7 +436,7 @@ config NET_ACT_POLICE | |||
| 433 | module. | 436 | module. |
| 434 | 437 | ||
| 435 | To compile this code as a module, choose M here: the | 438 | To compile this code as a module, choose M here: the |
| 436 | module will be called police. | 439 | module will be called act_police. |
| 437 | 440 | ||
| 438 | config NET_ACT_GACT | 441 | config NET_ACT_GACT |
| 439 | tristate "Generic actions" | 442 | tristate "Generic actions" |
| @@ -443,7 +446,7 @@ config NET_ACT_GACT | |||
| 443 | accepting packets. | 446 | accepting packets. |
| 444 | 447 | ||
| 445 | To compile this code as a module, choose M here: the | 448 | To compile this code as a module, choose M here: the |
| 446 | module will be called gact. | 449 | module will be called act_gact. |
| 447 | 450 | ||
| 448 | config GACT_PROB | 451 | config GACT_PROB |
| 449 | bool "Probability support" | 452 | bool "Probability support" |
| @@ -459,7 +462,7 @@ config NET_ACT_MIRRED | |||
| 459 | other devices. | 462 | other devices. |
| 460 | 463 | ||
| 461 | To compile this code as a module, choose M here: the | 464 | To compile this code as a module, choose M here: the |
| 462 | module will be called mirred. | 465 | module will be called act_mirred. |
| 463 | 466 | ||
| 464 | config NET_ACT_IPT | 467 | config NET_ACT_IPT |
| 465 | tristate "IPtables targets" | 468 | tristate "IPtables targets" |
| @@ -469,7 +472,7 @@ config NET_ACT_IPT | |||
| 469 | classification. | 472 | classification. |
| 470 | 473 | ||
| 471 | To compile this code as a module, choose M here: the | 474 | To compile this code as a module, choose M here: the |
| 472 | module will be called ipt. | 475 | module will be called act_ipt. |
| 473 | 476 | ||
| 474 | config NET_ACT_NAT | 477 | config NET_ACT_NAT |
| 475 | tristate "Stateless NAT" | 478 | tristate "Stateless NAT" |
| @@ -479,7 +482,7 @@ config NET_ACT_NAT | |||
| 479 | netfilter for NAT unless you know what you are doing. | 482 | netfilter for NAT unless you know what you are doing. |
| 480 | 483 | ||
| 481 | To compile this code as a module, choose M here: the | 484 | To compile this code as a module, choose M here: the |
| 482 | module will be called nat. | 485 | module will be called act_nat. |
| 483 | 486 | ||
| 484 | config NET_ACT_PEDIT | 487 | config NET_ACT_PEDIT |
| 485 | tristate "Packet Editing" | 488 | tristate "Packet Editing" |
| @@ -488,7 +491,7 @@ config NET_ACT_PEDIT | |||
| 488 | Say Y here if you want to mangle the content of packets. | 491 | Say Y here if you want to mangle the content of packets. |
| 489 | 492 | ||
| 490 | To compile this code as a module, choose M here: the | 493 | To compile this code as a module, choose M here: the |
| 491 | module will be called pedit. | 494 | module will be called act_pedit. |
| 492 | 495 | ||
| 493 | config NET_ACT_SIMP | 496 | config NET_ACT_SIMP |
| 494 | tristate "Simple Example (Debug)" | 497 | tristate "Simple Example (Debug)" |
| @@ -502,7 +505,7 @@ config NET_ACT_SIMP | |||
| 502 | If unsure, say N. | 505 | If unsure, say N. |
| 503 | 506 | ||
| 504 | To compile this code as a module, choose M here: the | 507 | To compile this code as a module, choose M here: the |
| 505 | module will be called simple. | 508 | module will be called act_simple. |
| 506 | 509 | ||
| 507 | config NET_ACT_SKBEDIT | 510 | config NET_ACT_SKBEDIT |
| 508 | tristate "SKB Editing" | 511 | tristate "SKB Editing" |
| @@ -513,7 +516,7 @@ config NET_ACT_SKBEDIT | |||
| 513 | If unsure, say N. | 516 | If unsure, say N. |
| 514 | 517 | ||
| 515 | To compile this code as a module, choose M here: the | 518 | To compile this code as a module, choose M here: the |
| 516 | module will be called skbedit. | 519 | module will be called act_skbedit. |
| 517 | 520 | ||
| 518 | config NET_CLS_IND | 521 | config NET_CLS_IND |
| 519 | bool "Incoming device classification" | 522 | bool "Incoming device classification" |
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 | ||
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index e7f796aec657..c2ed90a4c0b4 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c | |||
| @@ -152,21 +152,24 @@ static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result | |||
| 152 | static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | 152 | static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
| 153 | { | 153 | { |
| 154 | unsigned char *b = skb_tail_pointer(skb); | 154 | unsigned char *b = skb_tail_pointer(skb); |
| 155 | struct tc_gact opt; | ||
| 156 | struct tcf_gact *gact = a->priv; | 155 | struct tcf_gact *gact = a->priv; |
| 156 | struct tc_gact opt = { | ||
| 157 | .index = gact->tcf_index, | ||
| 158 | .refcnt = gact->tcf_refcnt - ref, | ||
| 159 | .bindcnt = gact->tcf_bindcnt - bind, | ||
| 160 | .action = gact->tcf_action, | ||
| 161 | }; | ||
| 157 | struct tcf_t t; | 162 | struct tcf_t t; |
| 158 | 163 | ||
| 159 | opt.index = gact->tcf_index; | ||
| 160 | opt.refcnt = gact->tcf_refcnt - ref; | ||
| 161 | opt.bindcnt = gact->tcf_bindcnt - bind; | ||
| 162 | opt.action = gact->tcf_action; | ||
| 163 | NLA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); | 164 | NLA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); |
| 164 | #ifdef CONFIG_GACT_PROB | 165 | #ifdef CONFIG_GACT_PROB |
| 165 | if (gact->tcfg_ptype) { | 166 | if (gact->tcfg_ptype) { |
| 166 | struct tc_gact_p p_opt; | 167 | struct tc_gact_p p_opt = { |
| 167 | p_opt.paction = gact->tcfg_paction; | 168 | .paction = gact->tcfg_paction, |
| 168 | p_opt.pval = gact->tcfg_pval; | 169 | .pval = gact->tcfg_pval, |
| 169 | p_opt.ptype = gact->tcfg_ptype; | 170 | .ptype = gact->tcfg_ptype, |
| 171 | }; | ||
| 172 | |||
| 170 | NLA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); | 173 | NLA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); |
| 171 | } | 174 | } |
| 172 | #endif | 175 | #endif |
| @@ -202,9 +205,9 @@ MODULE_LICENSE("GPL"); | |||
| 202 | static int __init gact_init_module(void) | 205 | static int __init gact_init_module(void) |
| 203 | { | 206 | { |
| 204 | #ifdef CONFIG_GACT_PROB | 207 | #ifdef CONFIG_GACT_PROB |
| 205 | printk("GACT probability on\n"); | 208 | printk(KERN_INFO "GACT probability on\n"); |
| 206 | #else | 209 | #else |
| 207 | printk("GACT probability NOT on\n"); | 210 | printk(KERN_INFO "GACT probability NOT on\n"); |
| 208 | #endif | 211 | #endif |
| 209 | return tcf_register_action(&act_gact_ops); | 212 | return tcf_register_action(&act_gact_ops); |
| 210 | } | 213 | } |
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 082c520b0def..c7e59e6ec349 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | #include <linux/slab.h> | ||
| 22 | #include <net/netlink.h> | 23 | #include <net/netlink.h> |
| 23 | #include <net/pkt_sched.h> | 24 | #include <net/pkt_sched.h> |
| 24 | #include <linux/tc_act/tc_ipt.h> | 25 | #include <linux/tc_act/tc_ipt.h> |
| @@ -46,8 +47,8 @@ static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int | |||
| 46 | 47 | ||
| 47 | target = xt_request_find_target(AF_INET, t->u.user.name, | 48 | target = xt_request_find_target(AF_INET, t->u.user.name, |
| 48 | t->u.user.revision); | 49 | t->u.user.revision); |
| 49 | if (!target) | 50 | if (IS_ERR(target)) |
| 50 | return -ENOENT; | 51 | return PTR_ERR(target); |
| 51 | 52 | ||
| 52 | t->u.kernel.target = target; | 53 | t->u.kernel.target = target; |
| 53 | par.table = table; | 54 | par.table = table; |
| @@ -198,7 +199,7 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a, | |||
| 198 | { | 199 | { |
| 199 | int ret = 0, result = 0; | 200 | int ret = 0, result = 0; |
| 200 | struct tcf_ipt *ipt = a->priv; | 201 | struct tcf_ipt *ipt = a->priv; |
| 201 | struct xt_target_param par; | 202 | struct xt_action_param par; |
| 202 | 203 | ||
| 203 | if (skb_cloned(skb)) { | 204 | if (skb_cloned(skb)) { |
| 204 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | 205 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) |
| @@ -234,7 +235,8 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a, | |||
| 234 | break; | 235 | break; |
| 235 | default: | 236 | default: |
| 236 | if (net_ratelimit()) | 237 | if (net_ratelimit()) |
| 237 | printk("Bogus netfilter code %d assume ACCEPT\n", ret); | 238 | pr_notice("tc filter: Bogus netfilter code" |
| 239 | " %d assume ACCEPT\n", ret); | ||
| 238 | result = TC_POLICE_OK; | 240 | result = TC_POLICE_OK; |
| 239 | break; | 241 | break; |
| 240 | } | 242 | } |
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index d329170243cb..0c311be92827 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 23 | #include <linux/gfp.h> | ||
| 23 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
| 24 | #include <net/netlink.h> | 25 | #include <net/netlink.h> |
| 25 | #include <net/pkt_sched.h> | 26 | #include <net/pkt_sched.h> |
| @@ -32,6 +33,7 @@ | |||
| 32 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; | 33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; |
| 33 | static u32 mirred_idx_gen; | 34 | static u32 mirred_idx_gen; |
| 34 | static DEFINE_RWLOCK(mirred_lock); | 35 | static DEFINE_RWLOCK(mirred_lock); |
| 36 | static LIST_HEAD(mirred_list); | ||
| 35 | 37 | ||
| 36 | static struct tcf_hashinfo mirred_hash_info = { | 38 | static struct tcf_hashinfo mirred_hash_info = { |
| 37 | .htab = tcf_mirred_ht, | 39 | .htab = tcf_mirred_ht, |
| @@ -46,7 +48,9 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind) | |||
| 46 | m->tcf_bindcnt--; | 48 | m->tcf_bindcnt--; |
| 47 | m->tcf_refcnt--; | 49 | m->tcf_refcnt--; |
| 48 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { | 50 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { |
| 49 | dev_put(m->tcfm_dev); | 51 | list_del(&m->tcfm_list); |
| 52 | if (m->tcfm_dev) | ||
| 53 | dev_put(m->tcfm_dev); | ||
| 50 | tcf_hash_destroy(&m->common, &mirred_hash_info); | 54 | tcf_hash_destroy(&m->common, &mirred_hash_info); |
| 51 | return 1; | 55 | return 1; |
| 52 | } | 56 | } |
| @@ -133,8 +137,10 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, | |||
| 133 | m->tcfm_ok_push = ok_push; | 137 | m->tcfm_ok_push = ok_push; |
| 134 | } | 138 | } |
| 135 | spin_unlock_bh(&m->tcf_lock); | 139 | spin_unlock_bh(&m->tcf_lock); |
| 136 | if (ret == ACT_P_CREATED) | 140 | if (ret == ACT_P_CREATED) { |
| 141 | list_add(&m->tcfm_list, &mirred_list); | ||
| 137 | tcf_hash_insert(pc, &mirred_hash_info); | 142 | tcf_hash_insert(pc, &mirred_hash_info); |
| 143 | } | ||
| 138 | 144 | ||
| 139 | return ret; | 145 | return ret; |
| 140 | } | 146 | } |
| @@ -159,22 +165,27 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
| 159 | 165 | ||
| 160 | spin_lock(&m->tcf_lock); | 166 | spin_lock(&m->tcf_lock); |
| 161 | m->tcf_tm.lastuse = jiffies; | 167 | m->tcf_tm.lastuse = jiffies; |
| 168 | m->tcf_bstats.bytes += qdisc_pkt_len(skb); | ||
| 169 | m->tcf_bstats.packets++; | ||
| 162 | 170 | ||
| 163 | dev = m->tcfm_dev; | 171 | dev = m->tcfm_dev; |
| 172 | if (!dev) { | ||
| 173 | printk_once(KERN_NOTICE "tc mirred: target device is gone\n"); | ||
| 174 | goto out; | ||
| 175 | } | ||
| 176 | |||
| 164 | if (!(dev->flags & IFF_UP)) { | 177 | if (!(dev->flags & IFF_UP)) { |
| 165 | if (net_ratelimit()) | 178 | if (net_ratelimit()) |
| 166 | printk("mirred to Houston: device %s is gone!\n", | 179 | pr_notice("tc mirred to Houston: device %s is down\n", |
| 167 | dev->name); | 180 | dev->name); |
| 168 | goto out; | 181 | goto out; |
| 169 | } | 182 | } |
| 170 | 183 | ||
| 171 | skb2 = skb_act_clone(skb, GFP_ATOMIC); | 184 | at = G_TC_AT(skb->tc_verd); |
| 185 | skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action); | ||
| 172 | if (skb2 == NULL) | 186 | if (skb2 == NULL) |
| 173 | goto out; | 187 | goto out; |
| 174 | 188 | ||
| 175 | m->tcf_bstats.bytes += qdisc_pkt_len(skb2); | ||
| 176 | m->tcf_bstats.packets++; | ||
| 177 | at = G_TC_AT(skb->tc_verd); | ||
| 178 | if (!(at & AT_EGRESS)) { | 189 | if (!(at & AT_EGRESS)) { |
| 179 | if (m->tcfm_ok_push) | 190 | if (m->tcfm_ok_push) |
| 180 | skb_push(skb2, skb2->dev->hard_header_len); | 191 | skb_push(skb2, skb2->dev->hard_header_len); |
| @@ -184,16 +195,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
| 184 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR) | 195 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR) |
| 185 | skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); | 196 | skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); |
| 186 | 197 | ||
| 187 | skb2->dev = dev; | ||
| 188 | skb2->skb_iif = skb->dev->ifindex; | 198 | skb2->skb_iif = skb->dev->ifindex; |
| 199 | skb2->dev = dev; | ||
| 189 | dev_queue_xmit(skb2); | 200 | dev_queue_xmit(skb2); |
| 190 | err = 0; | 201 | err = 0; |
| 191 | 202 | ||
| 192 | out: | 203 | out: |
| 193 | if (err) { | 204 | if (err) { |
| 194 | m->tcf_qstats.overlimits++; | 205 | m->tcf_qstats.overlimits++; |
| 195 | m->tcf_bstats.bytes += qdisc_pkt_len(skb); | ||
| 196 | m->tcf_bstats.packets++; | ||
| 197 | /* should we be asking for packet to be dropped? | 206 | /* should we be asking for packet to be dropped? |
| 198 | * may make sense for redirect case only | 207 | * may make sense for redirect case only |
| 199 | */ | 208 | */ |
| @@ -210,15 +219,16 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i | |||
| 210 | { | 219 | { |
| 211 | unsigned char *b = skb_tail_pointer(skb); | 220 | unsigned char *b = skb_tail_pointer(skb); |
| 212 | struct tcf_mirred *m = a->priv; | 221 | struct tcf_mirred *m = a->priv; |
| 213 | struct tc_mirred opt; | 222 | struct tc_mirred opt = { |
| 223 | .index = m->tcf_index, | ||
| 224 | .action = m->tcf_action, | ||
| 225 | .refcnt = m->tcf_refcnt - ref, | ||
| 226 | .bindcnt = m->tcf_bindcnt - bind, | ||
| 227 | .eaction = m->tcfm_eaction, | ||
| 228 | .ifindex = m->tcfm_ifindex, | ||
| 229 | }; | ||
| 214 | struct tcf_t t; | 230 | struct tcf_t t; |
| 215 | 231 | ||
| 216 | opt.index = m->tcf_index; | ||
| 217 | opt.action = m->tcf_action; | ||
| 218 | opt.refcnt = m->tcf_refcnt - ref; | ||
| 219 | opt.bindcnt = m->tcf_bindcnt - bind; | ||
| 220 | opt.eaction = m->tcfm_eaction; | ||
| 221 | opt.ifindex = m->tcfm_ifindex; | ||
| 222 | NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); | 232 | NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); |
| 223 | t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); | 233 | t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); |
| 224 | t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); | 234 | t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); |
| @@ -231,6 +241,28 @@ nla_put_failure: | |||
| 231 | return -1; | 241 | return -1; |
| 232 | } | 242 | } |
| 233 | 243 | ||
| 244 | static int mirred_device_event(struct notifier_block *unused, | ||
| 245 | unsigned long event, void *ptr) | ||
| 246 | { | ||
| 247 | struct net_device *dev = ptr; | ||
| 248 | struct tcf_mirred *m; | ||
| 249 | |||
| 250 | if (event == NETDEV_UNREGISTER) | ||
| 251 | list_for_each_entry(m, &mirred_list, tcfm_list) { | ||
| 252 | if (m->tcfm_dev == dev) { | ||
| 253 | dev_put(dev); | ||
| 254 | m->tcfm_dev = NULL; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | return NOTIFY_DONE; | ||
| 259 | } | ||
| 260 | |||
| 261 | static struct notifier_block mirred_device_notifier = { | ||
| 262 | .notifier_call = mirred_device_event, | ||
| 263 | }; | ||
| 264 | |||
| 265 | |||
| 234 | static struct tc_action_ops act_mirred_ops = { | 266 | static struct tc_action_ops act_mirred_ops = { |
| 235 | .kind = "mirred", | 267 | .kind = "mirred", |
| 236 | .hinfo = &mirred_hash_info, | 268 | .hinfo = &mirred_hash_info, |
| @@ -251,12 +283,17 @@ MODULE_LICENSE("GPL"); | |||
| 251 | 283 | ||
| 252 | static int __init mirred_init_module(void) | 284 | static int __init mirred_init_module(void) |
| 253 | { | 285 | { |
| 254 | printk("Mirror/redirect action on\n"); | 286 | int err = register_netdevice_notifier(&mirred_device_notifier); |
| 287 | if (err) | ||
| 288 | return err; | ||
| 289 | |||
| 290 | pr_info("Mirror/redirect action on\n"); | ||
| 255 | return tcf_register_action(&act_mirred_ops); | 291 | return tcf_register_action(&act_mirred_ops); |
| 256 | } | 292 | } |
| 257 | 293 | ||
| 258 | static void __exit mirred_cleanup_module(void) | 294 | static void __exit mirred_cleanup_module(void) |
| 259 | { | 295 | { |
| 296 | unregister_netdevice_notifier(&mirred_device_notifier); | ||
| 260 | tcf_unregister_action(&act_mirred_ops); | 297 | tcf_unregister_action(&act_mirred_ops); |
| 261 | } | 298 | } |
| 262 | 299 | ||
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index d885ba311564..186eb837e600 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c | |||
| @@ -114,6 +114,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 114 | int egress; | 114 | int egress; |
| 115 | int action; | 115 | int action; |
| 116 | int ihl; | 116 | int ihl; |
| 117 | int noff; | ||
| 117 | 118 | ||
| 118 | spin_lock(&p->tcf_lock); | 119 | spin_lock(&p->tcf_lock); |
| 119 | 120 | ||
| @@ -132,7 +133,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 132 | if (unlikely(action == TC_ACT_SHOT)) | 133 | if (unlikely(action == TC_ACT_SHOT)) |
| 133 | goto drop; | 134 | goto drop; |
| 134 | 135 | ||
| 135 | if (!pskb_may_pull(skb, sizeof(*iph))) | 136 | noff = skb_network_offset(skb); |
| 137 | if (!pskb_may_pull(skb, sizeof(*iph) + noff)) | ||
| 136 | goto drop; | 138 | goto drop; |
| 137 | 139 | ||
| 138 | iph = ip_hdr(skb); | 140 | iph = ip_hdr(skb); |
| @@ -144,7 +146,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 144 | 146 | ||
| 145 | if (!((old_addr ^ addr) & mask)) { | 147 | if (!((old_addr ^ addr) & mask)) { |
| 146 | if (skb_cloned(skb) && | 148 | if (skb_cloned(skb) && |
| 147 | !skb_clone_writable(skb, sizeof(*iph)) && | 149 | !skb_clone_writable(skb, sizeof(*iph) + noff) && |
| 148 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | 150 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) |
| 149 | goto drop; | 151 | goto drop; |
| 150 | 152 | ||
| @@ -159,6 +161,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 159 | iph->daddr = new_addr; | 161 | iph->daddr = new_addr; |
| 160 | 162 | ||
| 161 | csum_replace4(&iph->check, addr, new_addr); | 163 | csum_replace4(&iph->check, addr, new_addr); |
| 164 | } else if ((iph->frag_off & htons(IP_OFFSET)) || | ||
| 165 | iph->protocol != IPPROTO_ICMP) { | ||
| 166 | goto out; | ||
| 162 | } | 167 | } |
| 163 | 168 | ||
| 164 | ihl = iph->ihl * 4; | 169 | ihl = iph->ihl * 4; |
| @@ -169,9 +174,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 169 | { | 174 | { |
| 170 | struct tcphdr *tcph; | 175 | struct tcphdr *tcph; |
| 171 | 176 | ||
| 172 | if (!pskb_may_pull(skb, ihl + sizeof(*tcph)) || | 177 | if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) || |
| 173 | (skb_cloned(skb) && | 178 | (skb_cloned(skb) && |
| 174 | !skb_clone_writable(skb, ihl + sizeof(*tcph)) && | 179 | !skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) && |
| 175 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 180 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) |
| 176 | goto drop; | 181 | goto drop; |
| 177 | 182 | ||
| @@ -183,9 +188,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 183 | { | 188 | { |
| 184 | struct udphdr *udph; | 189 | struct udphdr *udph; |
| 185 | 190 | ||
| 186 | if (!pskb_may_pull(skb, ihl + sizeof(*udph)) || | 191 | if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) || |
| 187 | (skb_cloned(skb) && | 192 | (skb_cloned(skb) && |
| 188 | !skb_clone_writable(skb, ihl + sizeof(*udph)) && | 193 | !skb_clone_writable(skb, ihl + sizeof(*udph) + noff) && |
| 189 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 194 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) |
| 190 | goto drop; | 195 | goto drop; |
| 191 | 196 | ||
| @@ -202,7 +207,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 202 | { | 207 | { |
| 203 | struct icmphdr *icmph; | 208 | struct icmphdr *icmph; |
| 204 | 209 | ||
| 205 | if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph))) | 210 | if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + noff)) |
| 206 | goto drop; | 211 | goto drop; |
| 207 | 212 | ||
| 208 | icmph = (void *)(skb_network_header(skb) + ihl); | 213 | icmph = (void *)(skb_network_header(skb) + ihl); |
| @@ -212,6 +217,11 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 212 | (icmph->type != ICMP_PARAMETERPROB)) | 217 | (icmph->type != ICMP_PARAMETERPROB)) |
| 213 | break; | 218 | break; |
| 214 | 219 | ||
| 220 | if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph) + | ||
| 221 | noff)) | ||
| 222 | goto drop; | ||
| 223 | |||
| 224 | icmph = (void *)(skb_network_header(skb) + ihl); | ||
| 215 | iph = (void *)(icmph + 1); | 225 | iph = (void *)(icmph + 1); |
| 216 | if (egress) | 226 | if (egress) |
| 217 | addr = iph->daddr; | 227 | addr = iph->daddr; |
| @@ -222,8 +232,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 222 | break; | 232 | break; |
| 223 | 233 | ||
| 224 | if (skb_cloned(skb) && | 234 | if (skb_cloned(skb) && |
| 225 | !skb_clone_writable(skb, | 235 | !skb_clone_writable(skb, ihl + sizeof(*icmph) + |
| 226 | ihl + sizeof(*icmph) + sizeof(*iph)) && | 236 | sizeof(*iph) + noff) && |
| 227 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | 237 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) |
| 228 | goto drop; | 238 | goto drop; |
| 229 | 239 | ||
| @@ -240,13 +250,14 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
| 240 | iph->saddr = new_addr; | 250 | iph->saddr = new_addr; |
| 241 | 251 | ||
| 242 | inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, | 252 | inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, |
| 243 | 1); | 253 | 0); |
| 244 | break; | 254 | break; |
| 245 | } | 255 | } |
| 246 | default: | 256 | default: |
| 247 | break; | 257 | break; |
| 248 | } | 258 | } |
| 249 | 259 | ||
| 260 | out: | ||
| 250 | return action; | 261 | return action; |
| 251 | 262 | ||
| 252 | drop: | 263 | drop: |
| @@ -261,40 +272,29 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, | |||
| 261 | { | 272 | { |
| 262 | unsigned char *b = skb_tail_pointer(skb); | 273 | unsigned char *b = skb_tail_pointer(skb); |
| 263 | struct tcf_nat *p = a->priv; | 274 | struct tcf_nat *p = a->priv; |
| 264 | struct tc_nat *opt; | 275 | struct tc_nat opt = { |
| 276 | .old_addr = p->old_addr, | ||
| 277 | .new_addr = p->new_addr, | ||
| 278 | .mask = p->mask, | ||
| 279 | .flags = p->flags, | ||
| 280 | |||
| 281 | .index = p->tcf_index, | ||
| 282 | .action = p->tcf_action, | ||
| 283 | .refcnt = p->tcf_refcnt - ref, | ||
| 284 | .bindcnt = p->tcf_bindcnt - bind, | ||
| 285 | }; | ||
| 265 | struct tcf_t t; | 286 | struct tcf_t t; |
| 266 | int s; | ||
| 267 | |||
| 268 | s = sizeof(*opt); | ||
| 269 | 287 | ||
| 270 | /* netlink spinlocks held above us - must use ATOMIC */ | 288 | NLA_PUT(skb, TCA_NAT_PARMS, sizeof(opt), &opt); |
| 271 | opt = kzalloc(s, GFP_ATOMIC); | ||
| 272 | if (unlikely(!opt)) | ||
| 273 | return -ENOBUFS; | ||
| 274 | |||
| 275 | opt->old_addr = p->old_addr; | ||
| 276 | opt->new_addr = p->new_addr; | ||
| 277 | opt->mask = p->mask; | ||
| 278 | opt->flags = p->flags; | ||
| 279 | |||
| 280 | opt->index = p->tcf_index; | ||
| 281 | opt->action = p->tcf_action; | ||
| 282 | opt->refcnt = p->tcf_refcnt - ref; | ||
| 283 | opt->bindcnt = p->tcf_bindcnt - bind; | ||
| 284 | |||
| 285 | NLA_PUT(skb, TCA_NAT_PARMS, s, opt); | ||
| 286 | t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); | 289 | t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); |
| 287 | t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); | 290 | t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); |
| 288 | t.expires = jiffies_to_clock_t(p->tcf_tm.expires); | 291 | t.expires = jiffies_to_clock_t(p->tcf_tm.expires); |
| 289 | NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t); | 292 | NLA_PUT(skb, TCA_NAT_TM, sizeof(t), &t); |
| 290 | 293 | ||
| 291 | kfree(opt); | ||
| 292 | |||
| 293 | return skb->len; | 294 | return skb->len; |
| 294 | 295 | ||
| 295 | nla_put_failure: | 296 | nla_put_failure: |
| 296 | nlmsg_trim(skb, b); | 297 | nlmsg_trim(skb, b); |
| 297 | kfree(opt); | ||
| 298 | return -1; | 298 | return -1; |
| 299 | } | 299 | } |
| 300 | 300 | ||
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 6b0359a500e6..a0593c9640db 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/rtnetlink.h> | 17 | #include <linux/rtnetlink.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/slab.h> | ||
| 20 | #include <net/netlink.h> | 21 | #include <net/netlink.h> |
| 21 | #include <net/pkt_sched.h> | 22 | #include <net/pkt_sched.h> |
| 22 | #include <linux/tc_act/tc_pedit.h> | 23 | #include <linux/tc_act/tc_pedit.h> |
| @@ -124,16 +125,15 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, | |||
| 124 | { | 125 | { |
| 125 | struct tcf_pedit *p = a->priv; | 126 | struct tcf_pedit *p = a->priv; |
| 126 | int i, munged = 0; | 127 | int i, munged = 0; |
| 127 | u8 *pptr; | 128 | unsigned int off; |
| 128 | 129 | ||
| 129 | if (!(skb->tc_verd & TC_OK2MUNGE)) { | 130 | if (skb_cloned(skb)) { |
| 130 | /* should we set skb->cloned? */ | ||
| 131 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { | 131 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { |
| 132 | return p->tcf_action; | 132 | return p->tcf_action; |
| 133 | } | 133 | } |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | pptr = skb_network_header(skb); | 136 | off = skb_network_offset(skb); |
| 137 | 137 | ||
| 138 | spin_lock(&p->tcf_lock); | 138 | spin_lock(&p->tcf_lock); |
| 139 | 139 | ||
| @@ -143,41 +143,46 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, | |||
| 143 | struct tc_pedit_key *tkey = p->tcfp_keys; | 143 | struct tc_pedit_key *tkey = p->tcfp_keys; |
| 144 | 144 | ||
| 145 | for (i = p->tcfp_nkeys; i > 0; i--, tkey++) { | 145 | for (i = p->tcfp_nkeys; i > 0; i--, tkey++) { |
| 146 | u32 *ptr; | 146 | u32 *ptr, _data; |
| 147 | int offset = tkey->off; | 147 | int offset = tkey->off; |
| 148 | 148 | ||
| 149 | if (tkey->offmask) { | 149 | if (tkey->offmask) { |
| 150 | if (skb->len > tkey->at) { | 150 | char *d, _d; |
| 151 | char *j = pptr + tkey->at; | 151 | |
| 152 | offset += ((*j & tkey->offmask) >> | 152 | d = skb_header_pointer(skb, off + tkey->at, 1, |
| 153 | tkey->shift); | 153 | &_d); |
| 154 | } else { | 154 | if (!d) |
| 155 | goto bad; | 155 | goto bad; |
| 156 | } | 156 | offset += (*d & tkey->offmask) >> tkey->shift; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | if (offset % 4) { | 159 | if (offset % 4) { |
| 160 | printk("offset must be on 32 bit boundaries\n"); | 160 | pr_info("tc filter pedit" |
| 161 | " offset must be on 32 bit boundaries\n"); | ||
| 161 | goto bad; | 162 | goto bad; |
| 162 | } | 163 | } |
| 163 | if (offset > 0 && offset > skb->len) { | 164 | if (offset > 0 && offset > skb->len) { |
| 164 | printk("offset %d cant exceed pkt length %d\n", | 165 | pr_info("tc filter pedit" |
| 166 | " offset %d cant exceed pkt length %d\n", | ||
| 165 | offset, skb->len); | 167 | offset, skb->len); |
| 166 | goto bad; | 168 | goto bad; |
| 167 | } | 169 | } |
| 168 | 170 | ||
| 169 | ptr = (u32 *)(pptr+offset); | 171 | ptr = skb_header_pointer(skb, off + offset, 4, &_data); |
| 172 | if (!ptr) | ||
| 173 | goto bad; | ||
| 170 | /* just do it, baby */ | 174 | /* just do it, baby */ |
| 171 | *ptr = ((*ptr & tkey->mask) ^ tkey->val); | 175 | *ptr = ((*ptr & tkey->mask) ^ tkey->val); |
| 176 | if (ptr == &_data) | ||
| 177 | skb_store_bits(skb, off + offset, ptr, 4); | ||
| 172 | munged++; | 178 | munged++; |
| 173 | } | 179 | } |
| 174 | 180 | ||
| 175 | if (munged) | 181 | if (munged) |
| 176 | skb->tc_verd = SET_TC_MUNGED(skb->tc_verd); | 182 | skb->tc_verd = SET_TC_MUNGED(skb->tc_verd); |
| 177 | goto done; | 183 | goto done; |
| 178 | } else { | 184 | } else |
| 179 | printk("pedit BUG: index %d\n", p->tcf_index); | 185 | WARN(1, "pedit BUG: index %d\n", p->tcf_index); |
| 180 | } | ||
| 181 | 186 | ||
| 182 | bad: | 187 | bad: |
| 183 | p->tcf_qstats.overlimits++; | 188 | p->tcf_qstats.overlimits++; |
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 723964c3ee4f..7ebf7439b478 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
| 19 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/slab.h> | ||
| 21 | #include <net/act_api.h> | 22 | #include <net/act_api.h> |
| 22 | #include <net/netlink.h> | 23 | #include <net/netlink.h> |
| 23 | 24 | ||
| @@ -96,6 +97,11 @@ nla_put_failure: | |||
| 96 | goto done; | 97 | goto done; |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 100 | static void tcf_police_free_rcu(struct rcu_head *head) | ||
| 101 | { | ||
| 102 | kfree(container_of(head, struct tcf_police, tcf_rcu)); | ||
| 103 | } | ||
| 104 | |||
| 99 | static void tcf_police_destroy(struct tcf_police *p) | 105 | static void tcf_police_destroy(struct tcf_police *p) |
| 100 | { | 106 | { |
| 101 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); | 107 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); |
| @@ -112,7 +118,11 @@ static void tcf_police_destroy(struct tcf_police *p) | |||
| 112 | qdisc_put_rtab(p->tcfp_R_tab); | 118 | qdisc_put_rtab(p->tcfp_R_tab); |
| 113 | if (p->tcfp_P_tab) | 119 | if (p->tcfp_P_tab) |
| 114 | qdisc_put_rtab(p->tcfp_P_tab); | 120 | qdisc_put_rtab(p->tcfp_P_tab); |
| 115 | kfree(p); | 121 | /* |
| 122 | * gen_estimator est_timer() might access p->tcf_lock | ||
| 123 | * or bstats, wait a RCU grace period before freeing p | ||
| 124 | */ | ||
| 125 | call_rcu(&p->tcf_rcu, tcf_police_free_rcu); | ||
| 116 | return; | 126 | return; |
| 117 | } | 127 | } |
| 118 | } | 128 | } |
| @@ -340,22 +350,19 @@ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | |||
| 340 | { | 350 | { |
| 341 | unsigned char *b = skb_tail_pointer(skb); | 351 | unsigned char *b = skb_tail_pointer(skb); |
| 342 | struct tcf_police *police = a->priv; | 352 | struct tcf_police *police = a->priv; |
| 343 | struct tc_police opt; | 353 | struct tc_police opt = { |
| 344 | 354 | .index = police->tcf_index, | |
| 345 | opt.index = police->tcf_index; | 355 | .action = police->tcf_action, |
| 346 | opt.action = police->tcf_action; | 356 | .mtu = police->tcfp_mtu, |
| 347 | opt.mtu = police->tcfp_mtu; | 357 | .burst = police->tcfp_burst, |
| 348 | opt.burst = police->tcfp_burst; | 358 | .refcnt = police->tcf_refcnt - ref, |
| 349 | opt.refcnt = police->tcf_refcnt - ref; | 359 | .bindcnt = police->tcf_bindcnt - bind, |
| 350 | opt.bindcnt = police->tcf_bindcnt - bind; | 360 | }; |
| 361 | |||
| 351 | if (police->tcfp_R_tab) | 362 | if (police->tcfp_R_tab) |
| 352 | opt.rate = police->tcfp_R_tab->rate; | 363 | opt.rate = police->tcfp_R_tab->rate; |
| 353 | else | ||
| 354 | memset(&opt.rate, 0, sizeof(opt.rate)); | ||
| 355 | if (police->tcfp_P_tab) | 364 | if (police->tcfp_P_tab) |
| 356 | opt.peakrate = police->tcfp_P_tab->rate; | 365 | opt.peakrate = police->tcfp_P_tab->rate; |
| 357 | else | ||
| 358 | memset(&opt.peakrate, 0, sizeof(opt.peakrate)); | ||
| 359 | NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); | 366 | NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); |
| 360 | if (police->tcfp_result) | 367 | if (police->tcfp_result) |
| 361 | NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result); | 368 | NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result); |
| @@ -396,6 +403,7 @@ static void __exit | |||
| 396 | police_cleanup_module(void) | 403 | police_cleanup_module(void) |
| 397 | { | 404 | { |
| 398 | tcf_unregister_action(&act_police_ops); | 405 | tcf_unregister_action(&act_police_ops); |
| 406 | rcu_barrier(); /* Wait for completion of call_rcu()'s (tcf_police_free_rcu) */ | ||
| 399 | } | 407 | } |
| 400 | 408 | ||
| 401 | module_init(police_init_module); | 409 | module_init(police_init_module); |
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 8daa1ebc7413..97e84f3ee775 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/slab.h> | ||
| 14 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 15 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 16 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
| @@ -48,7 +49,7 @@ static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result | |||
| 48 | * Example if this was the 3rd packet and the string was "hello" | 49 | * Example if this was the 3rd packet and the string was "hello" |
| 49 | * then it would look like "hello_3" (without quotes) | 50 | * then it would look like "hello_3" (without quotes) |
| 50 | **/ | 51 | **/ |
| 51 | printk("simple: %s_%d\n", | 52 | pr_info("simple: %s_%d\n", |
| 52 | (char *)d->tcfd_defdata, d->tcf_bstats.packets); | 53 | (char *)d->tcfd_defdata, d->tcf_bstats.packets); |
| 53 | spin_unlock(&d->tcf_lock); | 54 | spin_unlock(&d->tcf_lock); |
| 54 | return d->tcf_action; | 55 | return d->tcf_action; |
| @@ -72,10 +73,10 @@ static int tcf_simp_release(struct tcf_defact *d, int bind) | |||
| 72 | 73 | ||
| 73 | static int alloc_defdata(struct tcf_defact *d, char *defdata) | 74 | static int alloc_defdata(struct tcf_defact *d, char *defdata) |
| 74 | { | 75 | { |
| 75 | d->tcfd_defdata = kstrndup(defdata, SIMP_MAX_DATA, GFP_KERNEL); | 76 | d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); |
| 76 | if (unlikely(!d->tcfd_defdata)) | 77 | if (unlikely(!d->tcfd_defdata)) |
| 77 | return -ENOMEM; | 78 | return -ENOMEM; |
| 78 | 79 | strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); | |
| 79 | return 0; | 80 | return 0; |
| 80 | } | 81 | } |
| 81 | 82 | ||
| @@ -163,13 +164,14 @@ static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, | |||
| 163 | { | 164 | { |
| 164 | unsigned char *b = skb_tail_pointer(skb); | 165 | unsigned char *b = skb_tail_pointer(skb); |
| 165 | struct tcf_defact *d = a->priv; | 166 | struct tcf_defact *d = a->priv; |
| 166 | struct tc_defact opt; | 167 | struct tc_defact opt = { |
| 168 | .index = d->tcf_index, | ||
| 169 | .refcnt = d->tcf_refcnt - ref, | ||
| 170 | .bindcnt = d->tcf_bindcnt - bind, | ||
| 171 | .action = d->tcf_action, | ||
| 172 | }; | ||
| 167 | struct tcf_t t; | 173 | struct tcf_t t; |
| 168 | 174 | ||
| 169 | opt.index = d->tcf_index; | ||
| 170 | opt.refcnt = d->tcf_refcnt - ref; | ||
| 171 | opt.bindcnt = d->tcf_bindcnt - bind; | ||
| 172 | opt.action = d->tcf_action; | ||
| 173 | NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); | 175 | NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); |
| 174 | NLA_PUT_STRING(skb, TCA_DEF_DATA, d->tcfd_defdata); | 176 | NLA_PUT_STRING(skb, TCA_DEF_DATA, d->tcfd_defdata); |
| 175 | t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); | 177 | t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); |
| @@ -204,7 +206,7 @@ static int __init simp_init_module(void) | |||
| 204 | { | 206 | { |
| 205 | int ret = tcf_register_action(&act_simp_ops); | 207 | int ret = tcf_register_action(&act_simp_ops); |
| 206 | if (!ret) | 208 | if (!ret) |
| 207 | printk("Simple TC action Loaded\n"); | 209 | pr_info("Simple TC action Loaded\n"); |
| 208 | return ret; | 210 | return ret; |
| 209 | } | 211 | } |
| 210 | 212 | ||
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index e9607fe55b58..66cbf4eb8855 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c | |||
| @@ -159,13 +159,14 @@ static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, | |||
| 159 | { | 159 | { |
| 160 | unsigned char *b = skb_tail_pointer(skb); | 160 | unsigned char *b = skb_tail_pointer(skb); |
| 161 | struct tcf_skbedit *d = a->priv; | 161 | struct tcf_skbedit *d = a->priv; |
| 162 | struct tc_skbedit opt; | 162 | struct tc_skbedit opt = { |
| 163 | .index = d->tcf_index, | ||
| 164 | .refcnt = d->tcf_refcnt - ref, | ||
| 165 | .bindcnt = d->tcf_bindcnt - bind, | ||
| 166 | .action = d->tcf_action, | ||
| 167 | }; | ||
| 163 | struct tcf_t t; | 168 | struct tcf_t t; |
| 164 | 169 | ||
| 165 | opt.index = d->tcf_index; | ||
| 166 | opt.refcnt = d->tcf_refcnt - ref; | ||
| 167 | opt.bindcnt = d->tcf_bindcnt - bind; | ||
| 168 | opt.action = d->tcf_action; | ||
| 169 | NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt); | 170 | NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt); |
| 170 | if (d->flags & SKBEDIT_F_PRIORITY) | 171 | if (d->flags & SKBEDIT_F_PRIORITY) |
| 171 | NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority), | 172 | NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority), |
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 3725d8fa29db..5fd0c28ef79a 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/kmod.h> | 24 | #include <linux/kmod.h> |
| 25 | #include <linux/netlink.h> | 25 | #include <linux/netlink.h> |
| 26 | #include <linux/err.h> | 26 | #include <linux/err.h> |
| 27 | #include <linux/slab.h> | ||
| 27 | #include <net/net_namespace.h> | 28 | #include <net/net_namespace.h> |
| 28 | #include <net/sock.h> | 29 | #include <net/sock.h> |
| 29 | #include <net/netlink.h> | 30 | #include <net/netlink.h> |
| @@ -98,8 +99,9 @@ out: | |||
| 98 | } | 99 | } |
| 99 | EXPORT_SYMBOL(unregister_tcf_proto_ops); | 100 | EXPORT_SYMBOL(unregister_tcf_proto_ops); |
| 100 | 101 | ||
| 101 | static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, | 102 | static int tfilter_notify(struct net *net, struct sk_buff *oskb, |
| 102 | struct tcf_proto *tp, unsigned long fh, int event); | 103 | struct nlmsghdr *n, struct tcf_proto *tp, |
| 104 | unsigned long fh, int event); | ||
| 103 | 105 | ||
| 104 | 106 | ||
| 105 | /* Select new prio value from the range, managed by kernel. */ | 107 | /* Select new prio value from the range, managed by kernel. */ |
| @@ -137,9 +139,6 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 137 | int err; | 139 | int err; |
| 138 | int tp_created = 0; | 140 | int tp_created = 0; |
| 139 | 141 | ||
| 140 | if (!net_eq(net, &init_net)) | ||
| 141 | return -EINVAL; | ||
| 142 | |||
| 143 | replay: | 142 | replay: |
| 144 | t = NLMSG_DATA(n); | 143 | t = NLMSG_DATA(n); |
| 145 | protocol = TC_H_MIN(t->tcm_info); | 144 | protocol = TC_H_MIN(t->tcm_info); |
| @@ -158,7 +157,7 @@ replay: | |||
| 158 | /* Find head of filter chain. */ | 157 | /* Find head of filter chain. */ |
| 159 | 158 | ||
| 160 | /* Find link */ | 159 | /* Find link */ |
| 161 | dev = __dev_get_by_index(&init_net, t->tcm_ifindex); | 160 | dev = __dev_get_by_index(net, t->tcm_ifindex); |
| 162 | if (dev == NULL) | 161 | if (dev == NULL) |
| 163 | return -ENODEV; | 162 | return -ENODEV; |
| 164 | 163 | ||
| @@ -282,7 +281,7 @@ replay: | |||
| 282 | *back = tp->next; | 281 | *back = tp->next; |
| 283 | spin_unlock_bh(root_lock); | 282 | spin_unlock_bh(root_lock); |
| 284 | 283 | ||
| 285 | tfilter_notify(skb, n, tp, fh, RTM_DELTFILTER); | 284 | tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); |
| 286 | tcf_destroy(tp); | 285 | tcf_destroy(tp); |
| 287 | err = 0; | 286 | err = 0; |
| 288 | goto errout; | 287 | goto errout; |
| @@ -305,10 +304,10 @@ replay: | |||
| 305 | case RTM_DELTFILTER: | 304 | case RTM_DELTFILTER: |
| 306 | err = tp->ops->delete(tp, fh); | 305 | err = tp->ops->delete(tp, fh); |
| 307 | if (err == 0) | 306 | if (err == 0) |
| 308 | tfilter_notify(skb, n, tp, fh, RTM_DELTFILTER); | 307 | tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); |
| 309 | goto errout; | 308 | goto errout; |
| 310 | case RTM_GETTFILTER: | 309 | case RTM_GETTFILTER: |
| 311 | err = tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER); | 310 | err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); |
| 312 | goto errout; | 311 | goto errout; |
| 313 | default: | 312 | default: |
| 314 | err = -EINVAL; | 313 | err = -EINVAL; |
| @@ -324,7 +323,7 @@ replay: | |||
| 324 | *back = tp; | 323 | *back = tp; |
| 325 | spin_unlock_bh(root_lock); | 324 | spin_unlock_bh(root_lock); |
| 326 | } | 325 | } |
| 327 | tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER); | 326 | tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); |
| 328 | } else { | 327 | } else { |
| 329 | if (tp_created) | 328 | if (tp_created) |
| 330 | tcf_destroy(tp); | 329 | tcf_destroy(tp); |
| @@ -370,8 +369,9 @@ nla_put_failure: | |||
| 370 | return -1; | 369 | return -1; |
| 371 | } | 370 | } |
| 372 | 371 | ||
| 373 | static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, | 372 | static int tfilter_notify(struct net *net, struct sk_buff *oskb, |
| 374 | struct tcf_proto *tp, unsigned long fh, int event) | 373 | struct nlmsghdr *n, struct tcf_proto *tp, |
| 374 | unsigned long fh, int event) | ||
| 375 | { | 375 | { |
| 376 | struct sk_buff *skb; | 376 | struct sk_buff *skb; |
| 377 | u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; | 377 | u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; |
| @@ -385,7 +385,7 @@ static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n, | |||
| 385 | return -EINVAL; | 385 | return -EINVAL; |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, | 388 | return rtnetlink_send(skb, net, pid, RTNLGRP_TC, |
| 389 | n->nlmsg_flags & NLM_F_ECHO); | 389 | n->nlmsg_flags & NLM_F_ECHO); |
| 390 | } | 390 | } |
| 391 | 391 | ||
| @@ -418,12 +418,9 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 418 | const struct Qdisc_class_ops *cops; | 418 | const struct Qdisc_class_ops *cops; |
| 419 | struct tcf_dump_args arg; | 419 | struct tcf_dump_args arg; |
| 420 | 420 | ||
| 421 | if (!net_eq(net, &init_net)) | ||
| 422 | return 0; | ||
| 423 | |||
| 424 | if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) | 421 | if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) |
| 425 | return skb->len; | 422 | return skb->len; |
| 426 | if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) | 423 | if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) |
| 427 | return skb->len; | 424 | return skb->len; |
| 428 | 425 | ||
| 429 | if (!tcm->tcm_parent) | 426 | if (!tcm->tcm_parent) |
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index 4e2bda854119..efd4f95fd050 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | ||
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/string.h> | 16 | #include <linux/string.h> |
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index e4877ca6727c..78ef2c5e130b 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c | |||
| @@ -10,20 +10,37 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | ||
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
| 15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 16 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
| 17 | #include <linux/cgroup.h> | 18 | #include <linux/cgroup.h> |
| 19 | #include <linux/rcupdate.h> | ||
| 18 | #include <net/rtnetlink.h> | 20 | #include <net/rtnetlink.h> |
| 19 | #include <net/pkt_cls.h> | 21 | #include <net/pkt_cls.h> |
| 22 | #include <net/sock.h> | ||
| 23 | #include <net/cls_cgroup.h> | ||
| 20 | 24 | ||
| 21 | struct cgroup_cls_state | 25 | static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, |
| 22 | { | 26 | struct cgroup *cgrp); |
| 23 | struct cgroup_subsys_state css; | 27 | static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); |
| 24 | u32 classid; | 28 | static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp); |
| 29 | |||
| 30 | struct cgroup_subsys net_cls_subsys = { | ||
| 31 | .name = "net_cls", | ||
| 32 | .create = cgrp_create, | ||
| 33 | .destroy = cgrp_destroy, | ||
| 34 | .populate = cgrp_populate, | ||
| 35 | #ifdef CONFIG_NET_CLS_CGROUP | ||
| 36 | .subsys_id = net_cls_subsys_id, | ||
| 37 | #else | ||
| 38 | #define net_cls_subsys_id net_cls_subsys.subsys_id | ||
| 39 | #endif | ||
| 40 | .module = THIS_MODULE, | ||
| 25 | }; | 41 | }; |
| 26 | 42 | ||
| 43 | |||
| 27 | static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) | 44 | static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) |
| 28 | { | 45 | { |
| 29 | return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), | 46 | return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), |
| @@ -79,14 +96,6 @@ static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) | |||
| 79 | return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); | 96 | return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); |
| 80 | } | 97 | } |
| 81 | 98 | ||
| 82 | struct cgroup_subsys net_cls_subsys = { | ||
| 83 | .name = "net_cls", | ||
| 84 | .create = cgrp_create, | ||
| 85 | .destroy = cgrp_destroy, | ||
| 86 | .populate = cgrp_populate, | ||
| 87 | .subsys_id = net_cls_subsys_id, | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct cls_cgroup_head | 99 | struct cls_cgroup_head |
| 91 | { | 100 | { |
| 92 | u32 handle; | 101 | u32 handle; |
| @@ -100,6 +109,10 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
| 100 | struct cls_cgroup_head *head = tp->root; | 109 | struct cls_cgroup_head *head = tp->root; |
| 101 | u32 classid; | 110 | u32 classid; |
| 102 | 111 | ||
| 112 | rcu_read_lock(); | ||
| 113 | classid = task_cls_state(current)->classid; | ||
| 114 | rcu_read_unlock(); | ||
| 115 | |||
| 103 | /* | 116 | /* |
| 104 | * Due to the nature of the classifier it is required to ignore all | 117 | * Due to the nature of the classifier it is required to ignore all |
| 105 | * packets originating from softirq context as accessing `current' | 118 | * packets originating from softirq context as accessing `current' |
| @@ -110,12 +123,12 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
| 110 | * calls by looking at the number of nested bh disable calls because | 123 | * calls by looking at the number of nested bh disable calls because |
| 111 | * softirqs always disables bh. | 124 | * softirqs always disables bh. |
| 112 | */ | 125 | */ |
| 113 | if (softirq_count() != SOFTIRQ_OFFSET) | 126 | if (softirq_count() != SOFTIRQ_OFFSET) { |
| 114 | return -1; | 127 | /* If there is an sk_classid we'll use that. */ |
| 115 | 128 | if (!skb->sk) | |
| 116 | rcu_read_lock(); | 129 | return -1; |
| 117 | classid = task_cls_state(current)->classid; | 130 | classid = skb->sk->sk_classid; |
| 118 | rcu_read_unlock(); | 131 | } |
| 119 | 132 | ||
| 120 | if (!classid) | 133 | if (!classid) |
| 121 | return -1; | 134 | return -1; |
| @@ -277,12 +290,36 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { | |||
| 277 | 290 | ||
| 278 | static int __init init_cgroup_cls(void) | 291 | static int __init init_cgroup_cls(void) |
| 279 | { | 292 | { |
| 280 | return register_tcf_proto_ops(&cls_cgroup_ops); | 293 | int ret; |
| 294 | |||
| 295 | ret = cgroup_load_subsys(&net_cls_subsys); | ||
| 296 | if (ret) | ||
| 297 | goto out; | ||
| 298 | |||
| 299 | #ifndef CONFIG_NET_CLS_CGROUP | ||
| 300 | /* We can't use rcu_assign_pointer because this is an int. */ | ||
| 301 | smp_wmb(); | ||
| 302 | net_cls_subsys_id = net_cls_subsys.subsys_id; | ||
| 303 | #endif | ||
| 304 | |||
| 305 | ret = register_tcf_proto_ops(&cls_cgroup_ops); | ||
| 306 | if (ret) | ||
| 307 | cgroup_unload_subsys(&net_cls_subsys); | ||
| 308 | |||
| 309 | out: | ||
| 310 | return ret; | ||
| 281 | } | 311 | } |
| 282 | 312 | ||
| 283 | static void __exit exit_cgroup_cls(void) | 313 | static void __exit exit_cgroup_cls(void) |
| 284 | { | 314 | { |
| 285 | unregister_tcf_proto_ops(&cls_cgroup_ops); | 315 | unregister_tcf_proto_ops(&cls_cgroup_ops); |
| 316 | |||
| 317 | #ifndef CONFIG_NET_CLS_CGROUP | ||
| 318 | net_cls_subsys_id = -1; | ||
| 319 | synchronize_rcu(); | ||
| 320 | #endif | ||
| 321 | |||
| 322 | cgroup_unload_subsys(&net_cls_subsys); | ||
| 286 | } | 323 | } |
| 287 | 324 | ||
| 288 | module_init(init_cgroup_cls); | 325 | module_init(init_cgroup_cls); |
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index e054c62857e1..e17096e3913c 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/ip.h> | 20 | #include <linux/ip.h> |
| 21 | #include <linux/ipv6.h> | 21 | #include <linux/ipv6.h> |
| 22 | #include <linux/if_vlan.h> | 22 | #include <linux/if_vlan.h> |
| 23 | #include <linux/slab.h> | ||
| 23 | 24 | ||
| 24 | #include <net/pkt_cls.h> | 25 | #include <net/pkt_cls.h> |
| 25 | #include <net/ip.h> | 26 | #include <net/ip.h> |
| @@ -64,37 +65,47 @@ static inline u32 addr_fold(void *addr) | |||
| 64 | return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); | 65 | return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | static u32 flow_get_src(const struct sk_buff *skb) | 68 | static u32 flow_get_src(struct sk_buff *skb) |
| 68 | { | 69 | { |
| 69 | switch (skb->protocol) { | 70 | switch (skb->protocol) { |
| 70 | case htons(ETH_P_IP): | 71 | case htons(ETH_P_IP): |
| 71 | return ntohl(ip_hdr(skb)->saddr); | 72 | if (pskb_network_may_pull(skb, sizeof(struct iphdr))) |
| 73 | return ntohl(ip_hdr(skb)->saddr); | ||
| 74 | break; | ||
| 72 | case htons(ETH_P_IPV6): | 75 | case htons(ETH_P_IPV6): |
| 73 | return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); | 76 | if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) |
| 74 | default: | 77 | return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); |
| 75 | return addr_fold(skb->sk); | 78 | break; |
| 76 | } | 79 | } |
| 80 | |||
| 81 | return addr_fold(skb->sk); | ||
| 77 | } | 82 | } |
| 78 | 83 | ||
| 79 | static u32 flow_get_dst(const struct sk_buff *skb) | 84 | static u32 flow_get_dst(struct sk_buff *skb) |
| 80 | { | 85 | { |
| 81 | switch (skb->protocol) { | 86 | switch (skb->protocol) { |
| 82 | case htons(ETH_P_IP): | 87 | case htons(ETH_P_IP): |
| 83 | return ntohl(ip_hdr(skb)->daddr); | 88 | if (pskb_network_may_pull(skb, sizeof(struct iphdr))) |
| 89 | return ntohl(ip_hdr(skb)->daddr); | ||
| 90 | break; | ||
| 84 | case htons(ETH_P_IPV6): | 91 | case htons(ETH_P_IPV6): |
| 85 | return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); | 92 | if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) |
| 86 | default: | 93 | return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); |
| 87 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | 94 | break; |
| 88 | } | 95 | } |
| 96 | |||
| 97 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | ||
| 89 | } | 98 | } |
| 90 | 99 | ||
| 91 | static u32 flow_get_proto(const struct sk_buff *skb) | 100 | static u32 flow_get_proto(struct sk_buff *skb) |
| 92 | { | 101 | { |
| 93 | switch (skb->protocol) { | 102 | switch (skb->protocol) { |
| 94 | case htons(ETH_P_IP): | 103 | case htons(ETH_P_IP): |
| 95 | return ip_hdr(skb)->protocol; | 104 | return pskb_network_may_pull(skb, sizeof(struct iphdr)) ? |
| 105 | ip_hdr(skb)->protocol : 0; | ||
| 96 | case htons(ETH_P_IPV6): | 106 | case htons(ETH_P_IPV6): |
| 97 | return ipv6_hdr(skb)->nexthdr; | 107 | return pskb_network_may_pull(skb, sizeof(struct ipv6hdr)) ? |
| 108 | ipv6_hdr(skb)->nexthdr : 0; | ||
| 98 | default: | 109 | default: |
| 99 | return 0; | 110 | return 0; |
| 100 | } | 111 | } |
| @@ -115,58 +126,64 @@ static int has_ports(u8 protocol) | |||
| 115 | } | 126 | } |
| 116 | } | 127 | } |
| 117 | 128 | ||
| 118 | static u32 flow_get_proto_src(const struct sk_buff *skb) | 129 | static u32 flow_get_proto_src(struct sk_buff *skb) |
| 119 | { | 130 | { |
| 120 | u32 res = 0; | ||
| 121 | |||
| 122 | switch (skb->protocol) { | 131 | switch (skb->protocol) { |
| 123 | case htons(ETH_P_IP): { | 132 | case htons(ETH_P_IP): { |
| 124 | struct iphdr *iph = ip_hdr(skb); | 133 | struct iphdr *iph; |
| 125 | 134 | ||
| 135 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | ||
| 136 | break; | ||
| 137 | iph = ip_hdr(skb); | ||
| 126 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 138 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && |
| 127 | has_ports(iph->protocol)) | 139 | has_ports(iph->protocol) && |
| 128 | res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); | 140 | pskb_network_may_pull(skb, iph->ihl * 4 + 2)) |
| 141 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); | ||
| 129 | break; | 142 | break; |
| 130 | } | 143 | } |
| 131 | case htons(ETH_P_IPV6): { | 144 | case htons(ETH_P_IPV6): { |
| 132 | struct ipv6hdr *iph = ipv6_hdr(skb); | 145 | struct ipv6hdr *iph; |
| 133 | 146 | ||
| 147 | if (!pskb_network_may_pull(skb, sizeof(*iph) + 2)) | ||
| 148 | break; | ||
| 149 | iph = ipv6_hdr(skb); | ||
| 134 | if (has_ports(iph->nexthdr)) | 150 | if (has_ports(iph->nexthdr)) |
| 135 | res = ntohs(*(__be16 *)&iph[1]); | 151 | return ntohs(*(__be16 *)&iph[1]); |
| 136 | break; | 152 | break; |
| 137 | } | 153 | } |
| 138 | default: | ||
| 139 | res = addr_fold(skb->sk); | ||
| 140 | } | 154 | } |
| 141 | 155 | ||
| 142 | return res; | 156 | return addr_fold(skb->sk); |
| 143 | } | 157 | } |
| 144 | 158 | ||
| 145 | static u32 flow_get_proto_dst(const struct sk_buff *skb) | 159 | static u32 flow_get_proto_dst(struct sk_buff *skb) |
| 146 | { | 160 | { |
| 147 | u32 res = 0; | ||
| 148 | |||
| 149 | switch (skb->protocol) { | 161 | switch (skb->protocol) { |
| 150 | case htons(ETH_P_IP): { | 162 | case htons(ETH_P_IP): { |
| 151 | struct iphdr *iph = ip_hdr(skb); | 163 | struct iphdr *iph; |
| 152 | 164 | ||
| 165 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | ||
| 166 | break; | ||
| 167 | iph = ip_hdr(skb); | ||
| 153 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 168 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && |
| 154 | has_ports(iph->protocol)) | 169 | has_ports(iph->protocol) && |
| 155 | res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); | 170 | pskb_network_may_pull(skb, iph->ihl * 4 + 4)) |
| 171 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); | ||
| 156 | break; | 172 | break; |
| 157 | } | 173 | } |
| 158 | case htons(ETH_P_IPV6): { | 174 | case htons(ETH_P_IPV6): { |
| 159 | struct ipv6hdr *iph = ipv6_hdr(skb); | 175 | struct ipv6hdr *iph; |
| 160 | 176 | ||
| 177 | if (!pskb_network_may_pull(skb, sizeof(*iph) + 4)) | ||
| 178 | break; | ||
| 179 | iph = ipv6_hdr(skb); | ||
| 161 | if (has_ports(iph->nexthdr)) | 180 | if (has_ports(iph->nexthdr)) |
| 162 | res = ntohs(*(__be16 *)((void *)&iph[1] + 2)); | 181 | return ntohs(*(__be16 *)((void *)&iph[1] + 2)); |
| 163 | break; | 182 | break; |
| 164 | } | 183 | } |
| 165 | default: | ||
| 166 | res = addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; | ||
| 167 | } | 184 | } |
| 168 | 185 | ||
| 169 | return res; | 186 | return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; |
| 170 | } | 187 | } |
| 171 | 188 | ||
| 172 | static u32 flow_get_iif(const struct sk_buff *skb) | 189 | static u32 flow_get_iif(const struct sk_buff *skb) |
| @@ -210,7 +227,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb) | |||
| 210 | }) | 227 | }) |
| 211 | #endif | 228 | #endif |
| 212 | 229 | ||
| 213 | static u32 flow_get_nfct_src(const struct sk_buff *skb) | 230 | static u32 flow_get_nfct_src(struct sk_buff *skb) |
| 214 | { | 231 | { |
| 215 | switch (skb->protocol) { | 232 | switch (skb->protocol) { |
| 216 | case htons(ETH_P_IP): | 233 | case htons(ETH_P_IP): |
| @@ -222,7 +239,7 @@ fallback: | |||
| 222 | return flow_get_src(skb); | 239 | return flow_get_src(skb); |
| 223 | } | 240 | } |
| 224 | 241 | ||
| 225 | static u32 flow_get_nfct_dst(const struct sk_buff *skb) | 242 | static u32 flow_get_nfct_dst(struct sk_buff *skb) |
| 226 | { | 243 | { |
| 227 | switch (skb->protocol) { | 244 | switch (skb->protocol) { |
| 228 | case htons(ETH_P_IP): | 245 | case htons(ETH_P_IP): |
| @@ -234,14 +251,14 @@ fallback: | |||
| 234 | return flow_get_dst(skb); | 251 | return flow_get_dst(skb); |
| 235 | } | 252 | } |
| 236 | 253 | ||
| 237 | static u32 flow_get_nfct_proto_src(const struct sk_buff *skb) | 254 | static u32 flow_get_nfct_proto_src(struct sk_buff *skb) |
| 238 | { | 255 | { |
| 239 | return ntohs(CTTUPLE(skb, src.u.all)); | 256 | return ntohs(CTTUPLE(skb, src.u.all)); |
| 240 | fallback: | 257 | fallback: |
| 241 | return flow_get_proto_src(skb); | 258 | return flow_get_proto_src(skb); |
| 242 | } | 259 | } |
| 243 | 260 | ||
| 244 | static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb) | 261 | static u32 flow_get_nfct_proto_dst(struct sk_buff *skb) |
| 245 | { | 262 | { |
| 246 | return ntohs(CTTUPLE(skb, dst.u.all)); | 263 | return ntohs(CTTUPLE(skb, dst.u.all)); |
| 247 | fallback: | 264 | fallback: |
| @@ -280,7 +297,7 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb) | |||
| 280 | return tag & VLAN_VID_MASK; | 297 | return tag & VLAN_VID_MASK; |
| 281 | } | 298 | } |
| 282 | 299 | ||
| 283 | static u32 flow_key_get(const struct sk_buff *skb, int key) | 300 | static u32 flow_key_get(struct sk_buff *skb, int key) |
| 284 | { | 301 | { |
| 285 | switch (key) { | 302 | switch (key) { |
| 286 | case FLOW_KEY_SRC: | 303 | case FLOW_KEY_SRC: |
| @@ -601,7 +618,6 @@ static unsigned long flow_get(struct tcf_proto *tp, u32 handle) | |||
| 601 | 618 | ||
| 602 | static void flow_put(struct tcf_proto *tp, unsigned long f) | 619 | static void flow_put(struct tcf_proto *tp, unsigned long f) |
| 603 | { | 620 | { |
| 604 | return; | ||
| 605 | } | 621 | } |
| 606 | 622 | ||
| 607 | static int flow_dump(struct tcf_proto *tp, unsigned long fh, | 623 | static int flow_dump(struct tcf_proto *tp, unsigned long fh, |
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 6d6e87585fb1..93b0a7b6f9b4 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/slab.h> | ||
| 22 | #include <linux/types.h> | 23 | #include <linux/types.h> |
| 23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
| 24 | #include <linux/string.h> | 25 | #include <linux/string.h> |
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index dd872d5383ef..694dcd85dec8 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | ||
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/string.h> | 16 | #include <linux/string.h> |
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index dd9414e44200..425a1790b048 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h | |||
| @@ -143,9 +143,17 @@ static int rsvp_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
| 143 | u8 tunnelid = 0; | 143 | u8 tunnelid = 0; |
| 144 | u8 *xprt; | 144 | u8 *xprt; |
| 145 | #if RSVP_DST_LEN == 4 | 145 | #if RSVP_DST_LEN == 4 |
| 146 | struct ipv6hdr *nhptr = ipv6_hdr(skb); | 146 | struct ipv6hdr *nhptr; |
| 147 | |||
| 148 | if (!pskb_network_may_pull(skb, sizeof(*nhptr))) | ||
| 149 | return -1; | ||
| 150 | nhptr = ipv6_hdr(skb); | ||
| 147 | #else | 151 | #else |
| 148 | struct iphdr *nhptr = ip_hdr(skb); | 152 | struct iphdr *nhptr; |
| 153 | |||
| 154 | if (!pskb_network_may_pull(skb, sizeof(*nhptr))) | ||
| 155 | return -1; | ||
| 156 | nhptr = ip_hdr(skb); | ||
| 149 | #endif | 157 | #endif |
| 150 | 158 | ||
| 151 | restart: | 159 | restart: |
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index e806f2314b5e..20ef330bb918 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
| 10 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
| 11 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
| 12 | #include <linux/slab.h> | ||
| 12 | #include <net/act_api.h> | 13 | #include <net/act_api.h> |
| 13 | #include <net/netlink.h> | 14 | #include <net/netlink.h> |
| 14 | #include <net/pkt_cls.h> | 15 | #include <net/pkt_cls.h> |
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 07372f60bee3..b0c2a82178af 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | */ | 31 | */ |
| 32 | 32 | ||
| 33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 34 | #include <linux/slab.h> | ||
| 34 | #include <linux/types.h> | 35 | #include <linux/types.h> |
| 35 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
| 36 | #include <linux/string.h> | 37 | #include <linux/string.h> |
| @@ -97,11 +98,11 @@ static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_re | |||
| 97 | { | 98 | { |
| 98 | struct { | 99 | struct { |
| 99 | struct tc_u_knode *knode; | 100 | struct tc_u_knode *knode; |
| 100 | u8 *ptr; | 101 | unsigned int off; |
| 101 | } stack[TC_U32_MAXDEPTH]; | 102 | } stack[TC_U32_MAXDEPTH]; |
| 102 | 103 | ||
| 103 | struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root; | 104 | struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root; |
| 104 | u8 *ptr = skb_network_header(skb); | 105 | unsigned int off = skb_network_offset(skb); |
| 105 | struct tc_u_knode *n; | 106 | struct tc_u_knode *n; |
| 106 | int sdepth = 0; | 107 | int sdepth = 0; |
| 107 | int off2 = 0; | 108 | int off2 = 0; |
| @@ -133,8 +134,16 @@ next_knode: | |||
| 133 | #endif | 134 | #endif |
| 134 | 135 | ||
| 135 | for (i = n->sel.nkeys; i>0; i--, key++) { | 136 | for (i = n->sel.nkeys; i>0; i--, key++) { |
| 137 | int toff = off + key->off + (off2 & key->offmask); | ||
| 138 | __be32 *data, _data; | ||
| 136 | 139 | ||
| 137 | if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { | 140 | if (skb_headroom(skb) + toff > INT_MAX) |
| 141 | goto out; | ||
| 142 | |||
| 143 | data = skb_header_pointer(skb, toff, 4, &_data); | ||
| 144 | if (!data) | ||
| 145 | goto out; | ||
| 146 | if ((*data ^ key->val) & key->mask) { | ||
| 138 | n = n->next; | 147 | n = n->next; |
| 139 | goto next_knode; | 148 | goto next_knode; |
| 140 | } | 149 | } |
| @@ -173,29 +182,45 @@ check_terminal: | |||
| 173 | if (sdepth >= TC_U32_MAXDEPTH) | 182 | if (sdepth >= TC_U32_MAXDEPTH) |
| 174 | goto deadloop; | 183 | goto deadloop; |
| 175 | stack[sdepth].knode = n; | 184 | stack[sdepth].knode = n; |
| 176 | stack[sdepth].ptr = ptr; | 185 | stack[sdepth].off = off; |
| 177 | sdepth++; | 186 | sdepth++; |
| 178 | 187 | ||
| 179 | ht = n->ht_down; | 188 | ht = n->ht_down; |
| 180 | sel = 0; | 189 | sel = 0; |
| 181 | if (ht->divisor) | 190 | if (ht->divisor) { |
| 182 | sel = ht->divisor&u32_hash_fold(*(__be32*)(ptr+n->sel.hoff), &n->sel,n->fshift); | 191 | __be32 *data, _data; |
| 183 | 192 | ||
| 193 | data = skb_header_pointer(skb, off + n->sel.hoff, 4, | ||
| 194 | &_data); | ||
| 195 | if (!data) | ||
| 196 | goto out; | ||
| 197 | sel = ht->divisor & u32_hash_fold(*data, &n->sel, | ||
| 198 | n->fshift); | ||
| 199 | } | ||
| 184 | if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) | 200 | if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) |
| 185 | goto next_ht; | 201 | goto next_ht; |
| 186 | 202 | ||
| 187 | if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { | 203 | if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) { |
| 188 | off2 = n->sel.off + 3; | 204 | off2 = n->sel.off + 3; |
| 189 | if (n->sel.flags&TC_U32_VAROFFSET) | 205 | if (n->sel.flags & TC_U32_VAROFFSET) { |
| 190 | off2 += ntohs(n->sel.offmask & *(__be16*)(ptr+n->sel.offoff)) >>n->sel.offshift; | 206 | __be16 *data, _data; |
| 207 | |||
| 208 | data = skb_header_pointer(skb, | ||
| 209 | off + n->sel.offoff, | ||
| 210 | 2, &_data); | ||
| 211 | if (!data) | ||
| 212 | goto out; | ||
| 213 | off2 += ntohs(n->sel.offmask & *data) >> | ||
| 214 | n->sel.offshift; | ||
| 215 | } | ||
| 191 | off2 &= ~3; | 216 | off2 &= ~3; |
| 192 | } | 217 | } |
| 193 | if (n->sel.flags&TC_U32_EAT) { | 218 | if (n->sel.flags&TC_U32_EAT) { |
| 194 | ptr += off2; | 219 | off += off2; |
| 195 | off2 = 0; | 220 | off2 = 0; |
| 196 | } | 221 | } |
| 197 | 222 | ||
| 198 | if (ptr < skb_tail_pointer(skb)) | 223 | if (off < skb->len) |
| 199 | goto next_ht; | 224 | goto next_ht; |
| 200 | } | 225 | } |
| 201 | 226 | ||
| @@ -203,14 +228,15 @@ check_terminal: | |||
| 203 | if (sdepth--) { | 228 | if (sdepth--) { |
| 204 | n = stack[sdepth].knode; | 229 | n = stack[sdepth].knode; |
| 205 | ht = n->ht_up; | 230 | ht = n->ht_up; |
| 206 | ptr = stack[sdepth].ptr; | 231 | off = stack[sdepth].off; |
| 207 | goto check_terminal; | 232 | goto check_terminal; |
| 208 | } | 233 | } |
| 234 | out: | ||
| 209 | return -1; | 235 | return -1; |
| 210 | 236 | ||
| 211 | deadloop: | 237 | deadloop: |
| 212 | if (net_ratelimit()) | 238 | if (net_ratelimit()) |
| 213 | printk("cls_u32: dead loop\n"); | 239 | printk(KERN_WARNING "cls_u32: dead loop\n"); |
| 214 | return -1; | 240 | return -1; |
| 215 | } | 241 | } |
| 216 | 242 | ||
| @@ -767,15 +793,15 @@ static struct tcf_proto_ops cls_u32_ops __read_mostly = { | |||
| 767 | 793 | ||
| 768 | static int __init init_u32(void) | 794 | static int __init init_u32(void) |
| 769 | { | 795 | { |
| 770 | printk("u32 classifier\n"); | 796 | pr_info("u32 classifier\n"); |
| 771 | #ifdef CONFIG_CLS_U32_PERF | 797 | #ifdef CONFIG_CLS_U32_PERF |
| 772 | printk(" Performance counters on\n"); | 798 | pr_info(" Performance counters on\n"); |
| 773 | #endif | 799 | #endif |
| 774 | #ifdef CONFIG_NET_CLS_IND | 800 | #ifdef CONFIG_NET_CLS_IND |
| 775 | printk(" input device check on \n"); | 801 | pr_info(" input device check on\n"); |
| 776 | #endif | 802 | #endif |
| 777 | #ifdef CONFIG_NET_CLS_ACT | 803 | #ifdef CONFIG_NET_CLS_ACT |
| 778 | printk(" Actions configured \n"); | 804 | pr_info(" Actions configured\n"); |
| 779 | #endif | 805 | #endif |
| 780 | return register_tcf_proto_ops(&cls_u32_ops); | 806 | return register_tcf_proto_ops(&cls_u32_ops); |
| 781 | } | 807 | } |
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 24dce8b648a4..3bcac8aa333c 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c | |||
| @@ -58,6 +58,7 @@ | |||
| 58 | * only available if that subsystem is enabled in the kernel. | 58 | * only available if that subsystem is enabled in the kernel. |
| 59 | */ | 59 | */ |
| 60 | 60 | ||
| 61 | #include <linux/slab.h> | ||
| 61 | #include <linux/module.h> | 62 | #include <linux/module.h> |
| 62 | #include <linux/types.h> | 63 | #include <linux/types.h> |
| 63 | #include <linux/kernel.h> | 64 | #include <linux/kernel.h> |
diff --git a/net/sched/em_nbyte.c b/net/sched/em_nbyte.c index 370a1b2ea317..1a4176aee6e5 100644 --- a/net/sched/em_nbyte.c +++ b/net/sched/em_nbyte.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | * Authors: Thomas Graf <tgraf@suug.ch> | 9 | * Authors: Thomas Graf <tgraf@suug.ch> |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/gfp.h> | ||
| 12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
diff --git a/net/sched/em_text.c b/net/sched/em_text.c index 853c5ead87fd..763253257411 100644 --- a/net/sched/em_text.c +++ b/net/sched/em_text.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | * Authors: Thomas Graf <tgraf@suug.ch> | 9 | * Authors: Thomas Graf <tgraf@suug.ch> |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/slab.h> | ||
| 12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
diff --git a/net/sched/ematch.c b/net/sched/ematch.c index aab59409728b..5e37da961f80 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c | |||
| @@ -82,6 +82,7 @@ | |||
| 82 | */ | 82 | */ |
| 83 | 83 | ||
| 84 | #include <linux/module.h> | 84 | #include <linux/module.h> |
| 85 | #include <linux/slab.h> | ||
| 85 | #include <linux/types.h> | 86 | #include <linux/types.h> |
| 86 | #include <linux/kernel.h> | 87 | #include <linux/kernel.h> |
| 87 | #include <linux/errno.h> | 88 | #include <linux/errno.h> |
| @@ -526,7 +527,8 @@ pop_stack: | |||
| 526 | 527 | ||
| 527 | stack_overflow: | 528 | stack_overflow: |
| 528 | if (net_ratelimit()) | 529 | if (net_ratelimit()) |
| 529 | printk("Local stack overflow, increase NET_EMATCH_STACK\n"); | 530 | printk(KERN_WARNING "tc ematch: local stack overflow," |
| 531 | " increase NET_EMATCH_STACK\n"); | ||
| 530 | return -1; | 532 | return -1; |
| 531 | } | 533 | } |
| 532 | EXPORT_SYMBOL(__tcf_em_tree_match); | 534 | EXPORT_SYMBOL(__tcf_em_tree_match); |
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 75fd1c672c61..408eea7086aa 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
| @@ -28,16 +28,19 @@ | |||
| 28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
| 29 | #include <linux/hrtimer.h> | 29 | #include <linux/hrtimer.h> |
| 30 | #include <linux/lockdep.h> | 30 | #include <linux/lockdep.h> |
| 31 | #include <linux/slab.h> | ||
| 31 | 32 | ||
| 32 | #include <net/net_namespace.h> | 33 | #include <net/net_namespace.h> |
| 33 | #include <net/sock.h> | 34 | #include <net/sock.h> |
| 34 | #include <net/netlink.h> | 35 | #include <net/netlink.h> |
| 35 | #include <net/pkt_sched.h> | 36 | #include <net/pkt_sched.h> |
| 36 | 37 | ||
| 37 | static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, | 38 | static int qdisc_notify(struct net *net, struct sk_buff *oskb, |
| 39 | struct nlmsghdr *n, u32 clid, | ||
| 38 | struct Qdisc *old, struct Qdisc *new); | 40 | struct Qdisc *old, struct Qdisc *new); |
| 39 | static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, | 41 | static int tclass_notify(struct net *net, struct sk_buff *oskb, |
| 40 | struct Qdisc *q, unsigned long cl, int event); | 42 | struct nlmsghdr *n, struct Qdisc *q, |
| 43 | unsigned long cl, int event); | ||
| 41 | 44 | ||
| 42 | /* | 45 | /* |
| 43 | 46 | ||
| @@ -147,22 +150,34 @@ int register_qdisc(struct Qdisc_ops *qops) | |||
| 147 | if (qops->enqueue == NULL) | 150 | if (qops->enqueue == NULL) |
| 148 | qops->enqueue = noop_qdisc_ops.enqueue; | 151 | qops->enqueue = noop_qdisc_ops.enqueue; |
| 149 | if (qops->peek == NULL) { | 152 | if (qops->peek == NULL) { |
| 150 | if (qops->dequeue == NULL) { | 153 | if (qops->dequeue == NULL) |
| 151 | qops->peek = noop_qdisc_ops.peek; | 154 | qops->peek = noop_qdisc_ops.peek; |
| 152 | } else { | 155 | else |
| 153 | rc = -EINVAL; | 156 | goto out_einval; |
| 154 | goto out; | ||
| 155 | } | ||
| 156 | } | 157 | } |
| 157 | if (qops->dequeue == NULL) | 158 | if (qops->dequeue == NULL) |
| 158 | qops->dequeue = noop_qdisc_ops.dequeue; | 159 | qops->dequeue = noop_qdisc_ops.dequeue; |
| 159 | 160 | ||
| 161 | if (qops->cl_ops) { | ||
| 162 | const struct Qdisc_class_ops *cops = qops->cl_ops; | ||
| 163 | |||
| 164 | if (!(cops->get && cops->put && cops->walk && cops->leaf)) | ||
| 165 | goto out_einval; | ||
| 166 | |||
| 167 | if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf)) | ||
| 168 | goto out_einval; | ||
| 169 | } | ||
| 170 | |||
| 160 | qops->next = NULL; | 171 | qops->next = NULL; |
| 161 | *qp = qops; | 172 | *qp = qops; |
| 162 | rc = 0; | 173 | rc = 0; |
| 163 | out: | 174 | out: |
| 164 | write_unlock(&qdisc_mod_lock); | 175 | write_unlock(&qdisc_mod_lock); |
| 165 | return rc; | 176 | return rc; |
| 177 | |||
| 178 | out_einval: | ||
| 179 | rc = -EINVAL; | ||
| 180 | goto out; | ||
| 166 | } | 181 | } |
| 167 | EXPORT_SYMBOL(register_qdisc); | 182 | EXPORT_SYMBOL(register_qdisc); |
| 168 | 183 | ||
| @@ -638,11 +653,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) | |||
| 638 | } | 653 | } |
| 639 | EXPORT_SYMBOL(qdisc_tree_decrease_qlen); | 654 | EXPORT_SYMBOL(qdisc_tree_decrease_qlen); |
| 640 | 655 | ||
| 641 | static void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid, | 656 | static void notify_and_destroy(struct net *net, struct sk_buff *skb, |
| 657 | struct nlmsghdr *n, u32 clid, | ||
| 642 | struct Qdisc *old, struct Qdisc *new) | 658 | struct Qdisc *old, struct Qdisc *new) |
| 643 | { | 659 | { |
| 644 | if (new || old) | 660 | if (new || old) |
| 645 | qdisc_notify(skb, n, clid, old, new); | 661 | qdisc_notify(net, skb, n, clid, old, new); |
| 646 | 662 | ||
| 647 | if (old) | 663 | if (old) |
| 648 | qdisc_destroy(old); | 664 | qdisc_destroy(old); |
| @@ -662,6 +678,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
| 662 | struct Qdisc *new, struct Qdisc *old) | 678 | struct Qdisc *new, struct Qdisc *old) |
| 663 | { | 679 | { |
| 664 | struct Qdisc *q = old; | 680 | struct Qdisc *q = old; |
| 681 | struct net *net = dev_net(dev); | ||
| 665 | int err = 0; | 682 | int err = 0; |
| 666 | 683 | ||
| 667 | if (parent == NULL) { | 684 | if (parent == NULL) { |
| @@ -698,12 +715,13 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
| 698 | } | 715 | } |
| 699 | 716 | ||
| 700 | if (!ingress) { | 717 | if (!ingress) { |
| 701 | notify_and_destroy(skb, n, classid, dev->qdisc, new); | 718 | notify_and_destroy(net, skb, n, classid, |
| 719 | dev->qdisc, new); | ||
| 702 | if (new && !new->ops->attach) | 720 | if (new && !new->ops->attach) |
| 703 | atomic_inc(&new->refcnt); | 721 | atomic_inc(&new->refcnt); |
| 704 | dev->qdisc = new ? : &noop_qdisc; | 722 | dev->qdisc = new ? : &noop_qdisc; |
| 705 | } else { | 723 | } else { |
| 706 | notify_and_destroy(skb, n, classid, old, new); | 724 | notify_and_destroy(net, skb, n, classid, old, new); |
| 707 | } | 725 | } |
| 708 | 726 | ||
| 709 | if (dev->flags & IFF_UP) | 727 | if (dev->flags & IFF_UP) |
| @@ -721,7 +739,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
| 721 | err = -ENOENT; | 739 | err = -ENOENT; |
| 722 | } | 740 | } |
| 723 | if (!err) | 741 | if (!err) |
| 724 | notify_and_destroy(skb, n, classid, old, new); | 742 | notify_and_destroy(net, skb, n, classid, old, new); |
| 725 | } | 743 | } |
| 726 | return err; | 744 | return err; |
| 727 | } | 745 | } |
| @@ -947,10 +965,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 947 | struct Qdisc *p = NULL; | 965 | struct Qdisc *p = NULL; |
| 948 | int err; | 966 | int err; |
| 949 | 967 | ||
| 950 | if (!net_eq(net, &init_net)) | 968 | if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) |
| 951 | return -EINVAL; | ||
| 952 | |||
| 953 | if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) | ||
| 954 | return -ENODEV; | 969 | return -ENODEV; |
| 955 | 970 | ||
| 956 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); | 971 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); |
| @@ -990,7 +1005,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 990 | if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0) | 1005 | if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0) |
| 991 | return err; | 1006 | return err; |
| 992 | } else { | 1007 | } else { |
| 993 | qdisc_notify(skb, n, clid, NULL, q); | 1008 | qdisc_notify(net, skb, n, clid, NULL, q); |
| 994 | } | 1009 | } |
| 995 | return 0; | 1010 | return 0; |
| 996 | } | 1011 | } |
| @@ -1009,16 +1024,13 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 1009 | struct Qdisc *q, *p; | 1024 | struct Qdisc *q, *p; |
| 1010 | int err; | 1025 | int err; |
| 1011 | 1026 | ||
| 1012 | if (!net_eq(net, &init_net)) | ||
| 1013 | return -EINVAL; | ||
| 1014 | |||
| 1015 | replay: | 1027 | replay: |
| 1016 | /* Reinit, just in case something touches this. */ | 1028 | /* Reinit, just in case something touches this. */ |
| 1017 | tcm = NLMSG_DATA(n); | 1029 | tcm = NLMSG_DATA(n); |
| 1018 | clid = tcm->tcm_parent; | 1030 | clid = tcm->tcm_parent; |
| 1019 | q = p = NULL; | 1031 | q = p = NULL; |
| 1020 | 1032 | ||
| 1021 | if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) | 1033 | if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) |
| 1022 | return -ENODEV; | 1034 | return -ENODEV; |
| 1023 | 1035 | ||
| 1024 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); | 1036 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); |
| @@ -1105,7 +1117,7 @@ replay: | |||
| 1105 | return -EINVAL; | 1117 | return -EINVAL; |
| 1106 | err = qdisc_change(q, tca); | 1118 | err = qdisc_change(q, tca); |
| 1107 | if (err == 0) | 1119 | if (err == 0) |
| 1108 | qdisc_notify(skb, n, clid, NULL, q); | 1120 | qdisc_notify(net, skb, n, clid, NULL, q); |
| 1109 | return err; | 1121 | return err; |
| 1110 | 1122 | ||
| 1111 | create_n_graft: | 1123 | create_n_graft: |
| @@ -1195,8 +1207,14 @@ nla_put_failure: | |||
| 1195 | return -1; | 1207 | return -1; |
| 1196 | } | 1208 | } |
| 1197 | 1209 | ||
| 1198 | static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, | 1210 | static bool tc_qdisc_dump_ignore(struct Qdisc *q) |
| 1199 | u32 clid, struct Qdisc *old, struct Qdisc *new) | 1211 | { |
| 1212 | return (q->flags & TCQ_F_BUILTIN) ? true : false; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | static int qdisc_notify(struct net *net, struct sk_buff *oskb, | ||
| 1216 | struct nlmsghdr *n, u32 clid, | ||
| 1217 | struct Qdisc *old, struct Qdisc *new) | ||
| 1200 | { | 1218 | { |
| 1201 | struct sk_buff *skb; | 1219 | struct sk_buff *skb; |
| 1202 | u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; | 1220 | u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; |
| @@ -1205,28 +1223,23 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, | |||
| 1205 | if (!skb) | 1223 | if (!skb) |
| 1206 | return -ENOBUFS; | 1224 | return -ENOBUFS; |
| 1207 | 1225 | ||
| 1208 | if (old && old->handle) { | 1226 | if (old && !tc_qdisc_dump_ignore(old)) { |
| 1209 | if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0) | 1227 | if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0) |
| 1210 | goto err_out; | 1228 | goto err_out; |
| 1211 | } | 1229 | } |
| 1212 | if (new) { | 1230 | if (new && !tc_qdisc_dump_ignore(new)) { |
| 1213 | if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) | 1231 | if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) |
| 1214 | goto err_out; | 1232 | goto err_out; |
| 1215 | } | 1233 | } |
| 1216 | 1234 | ||
| 1217 | if (skb->len) | 1235 | if (skb->len) |
| 1218 | return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); | 1236 | return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); |
| 1219 | 1237 | ||
| 1220 | err_out: | 1238 | err_out: |
| 1221 | kfree_skb(skb); | 1239 | kfree_skb(skb); |
| 1222 | return -EINVAL; | 1240 | return -EINVAL; |
| 1223 | } | 1241 | } |
| 1224 | 1242 | ||
| 1225 | static bool tc_qdisc_dump_ignore(struct Qdisc *q) | ||
| 1226 | { | ||
| 1227 | return (q->flags & TCQ_F_BUILTIN) ? true : false; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, | 1243 | static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, |
| 1231 | struct netlink_callback *cb, | 1244 | struct netlink_callback *cb, |
| 1232 | int *q_idx_p, int s_q_idx) | 1245 | int *q_idx_p, int s_q_idx) |
| @@ -1274,15 +1287,12 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1274 | int s_idx, s_q_idx; | 1287 | int s_idx, s_q_idx; |
| 1275 | struct net_device *dev; | 1288 | struct net_device *dev; |
| 1276 | 1289 | ||
| 1277 | if (!net_eq(net, &init_net)) | ||
| 1278 | return 0; | ||
| 1279 | |||
| 1280 | s_idx = cb->args[0]; | 1290 | s_idx = cb->args[0]; |
| 1281 | s_q_idx = q_idx = cb->args[1]; | 1291 | s_q_idx = q_idx = cb->args[1]; |
| 1282 | 1292 | ||
| 1283 | rcu_read_lock(); | 1293 | rcu_read_lock(); |
| 1284 | idx = 0; | 1294 | idx = 0; |
| 1285 | for_each_netdev_rcu(&init_net, dev) { | 1295 | for_each_netdev_rcu(net, dev) { |
| 1286 | struct netdev_queue *dev_queue; | 1296 | struct netdev_queue *dev_queue; |
| 1287 | 1297 | ||
| 1288 | if (idx < s_idx) | 1298 | if (idx < s_idx) |
| @@ -1334,10 +1344,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 1334 | u32 qid = TC_H_MAJ(clid); | 1344 | u32 qid = TC_H_MAJ(clid); |
| 1335 | int err; | 1345 | int err; |
| 1336 | 1346 | ||
| 1337 | if (!net_eq(net, &init_net)) | 1347 | if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) |
| 1338 | return -EINVAL; | ||
| 1339 | |||
| 1340 | if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) | ||
| 1341 | return -ENODEV; | 1348 | return -ENODEV; |
| 1342 | 1349 | ||
| 1343 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); | 1350 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); |
| @@ -1418,10 +1425,10 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 1418 | if (cops->delete) | 1425 | if (cops->delete) |
| 1419 | err = cops->delete(q, cl); | 1426 | err = cops->delete(q, cl); |
| 1420 | if (err == 0) | 1427 | if (err == 0) |
| 1421 | tclass_notify(skb, n, q, cl, RTM_DELTCLASS); | 1428 | tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS); |
| 1422 | goto out; | 1429 | goto out; |
| 1423 | case RTM_GETTCLASS: | 1430 | case RTM_GETTCLASS: |
| 1424 | err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS); | 1431 | err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS); |
| 1425 | goto out; | 1432 | goto out; |
| 1426 | default: | 1433 | default: |
| 1427 | err = -EINVAL; | 1434 | err = -EINVAL; |
| @@ -1434,7 +1441,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
| 1434 | if (cops->change) | 1441 | if (cops->change) |
| 1435 | err = cops->change(q, clid, pid, tca, &new_cl); | 1442 | err = cops->change(q, clid, pid, tca, &new_cl); |
| 1436 | if (err == 0) | 1443 | if (err == 0) |
| 1437 | tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS); | 1444 | tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS); |
| 1438 | 1445 | ||
| 1439 | out: | 1446 | out: |
| 1440 | if (cl) | 1447 | if (cl) |
| @@ -1486,8 +1493,9 @@ nla_put_failure: | |||
| 1486 | return -1; | 1493 | return -1; |
| 1487 | } | 1494 | } |
| 1488 | 1495 | ||
| 1489 | static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, | 1496 | static int tclass_notify(struct net *net, struct sk_buff *oskb, |
| 1490 | struct Qdisc *q, unsigned long cl, int event) | 1497 | struct nlmsghdr *n, struct Qdisc *q, |
| 1498 | unsigned long cl, int event) | ||
| 1491 | { | 1499 | { |
| 1492 | struct sk_buff *skb; | 1500 | struct sk_buff *skb; |
| 1493 | u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; | 1501 | u32 pid = oskb ? NETLINK_CB(oskb).pid : 0; |
| @@ -1501,7 +1509,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, | |||
| 1501 | return -EINVAL; | 1509 | return -EINVAL; |
| 1502 | } | 1510 | } |
| 1503 | 1511 | ||
| 1504 | return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); | 1512 | return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); |
| 1505 | } | 1513 | } |
| 1506 | 1514 | ||
| 1507 | struct qdisc_dump_args | 1515 | struct qdisc_dump_args |
| @@ -1576,12 +1584,9 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1576 | struct net_device *dev; | 1584 | struct net_device *dev; |
| 1577 | int t, s_t; | 1585 | int t, s_t; |
| 1578 | 1586 | ||
| 1579 | if (!net_eq(net, &init_net)) | ||
| 1580 | return 0; | ||
| 1581 | |||
| 1582 | if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) | 1587 | if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) |
| 1583 | return 0; | 1588 | return 0; |
| 1584 | if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) | 1589 | if ((dev = dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) |
| 1585 | return 0; | 1590 | return 0; |
| 1586 | 1591 | ||
| 1587 | s_t = cb->args[0]; | 1592 | s_t = cb->args[0]; |
| @@ -1644,9 +1649,12 @@ reclassify: | |||
| 1644 | tp = otp; | 1649 | tp = otp; |
| 1645 | 1650 | ||
| 1646 | if (verd++ >= MAX_REC_LOOP) { | 1651 | if (verd++ >= MAX_REC_LOOP) { |
| 1647 | printk("rule prio %u protocol %02x reclassify loop, " | 1652 | if (net_ratelimit()) |
| 1648 | "packet dropped\n", | 1653 | printk(KERN_NOTICE |
| 1649 | tp->prio&0xffff, ntohs(tp->protocol)); | 1654 | "%s: packet reclassify loop" |
| 1655 | " rule prio %u protocol %02x\n", | ||
| 1656 | tp->q->ops->id, | ||
| 1657 | tp->prio & 0xffff, ntohs(tp->protocol)); | ||
| 1650 | return TC_ACT_SHOT; | 1658 | return TC_ACT_SHOT; |
| 1651 | } | 1659 | } |
| 1652 | skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); | 1660 | skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); |
| @@ -1691,7 +1699,7 @@ static int psched_show(struct seq_file *seq, void *v) | |||
| 1691 | 1699 | ||
| 1692 | static int psched_open(struct inode *inode, struct file *file) | 1700 | static int psched_open(struct inode *inode, struct file *file) |
| 1693 | { | 1701 | { |
| 1694 | return single_open(file, psched_show, PDE(inode)->data); | 1702 | return single_open(file, psched_show, NULL); |
| 1695 | } | 1703 | } |
| 1696 | 1704 | ||
| 1697 | static const struct file_operations psched_fops = { | 1705 | static const struct file_operations psched_fops = { |
| @@ -1701,14 +1709,53 @@ static const struct file_operations psched_fops = { | |||
| 1701 | .llseek = seq_lseek, | 1709 | .llseek = seq_lseek, |
| 1702 | .release = single_release, | 1710 | .release = single_release, |
| 1703 | }; | 1711 | }; |
| 1712 | |||
| 1713 | static int __net_init psched_net_init(struct net *net) | ||
| 1714 | { | ||
| 1715 | struct proc_dir_entry *e; | ||
| 1716 | |||
| 1717 | e = proc_net_fops_create(net, "psched", 0, &psched_fops); | ||
| 1718 | if (e == NULL) | ||
| 1719 | return -ENOMEM; | ||
| 1720 | |||
| 1721 | return 0; | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | static void __net_exit psched_net_exit(struct net *net) | ||
| 1725 | { | ||
| 1726 | proc_net_remove(net, "psched"); | ||
| 1727 | } | ||
| 1728 | #else | ||
| 1729 | static int __net_init psched_net_init(struct net *net) | ||
| 1730 | { | ||
| 1731 | return 0; | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | static void __net_exit psched_net_exit(struct net *net) | ||
| 1735 | { | ||
| 1736 | } | ||
| 1704 | #endif | 1737 | #endif |
| 1705 | 1738 | ||
| 1739 | static struct pernet_operations psched_net_ops = { | ||
| 1740 | .init = psched_net_init, | ||
| 1741 | .exit = psched_net_exit, | ||
| 1742 | }; | ||
| 1743 | |||
| 1706 | static int __init pktsched_init(void) | 1744 | static int __init pktsched_init(void) |
| 1707 | { | 1745 | { |
| 1746 | int err; | ||
| 1747 | |||
| 1748 | err = register_pernet_subsys(&psched_net_ops); | ||
| 1749 | if (err) { | ||
| 1750 | printk(KERN_ERR "pktsched_init: " | ||
| 1751 | "cannot initialize per netns operations\n"); | ||
| 1752 | return err; | ||
| 1753 | } | ||
| 1754 | |||
| 1708 | register_qdisc(&pfifo_qdisc_ops); | 1755 | register_qdisc(&pfifo_qdisc_ops); |
| 1709 | register_qdisc(&bfifo_qdisc_ops); | 1756 | register_qdisc(&bfifo_qdisc_ops); |
| 1757 | register_qdisc(&pfifo_head_drop_qdisc_ops); | ||
| 1710 | register_qdisc(&mq_qdisc_ops); | 1758 | register_qdisc(&mq_qdisc_ops); |
| 1711 | proc_net_fops_create(&init_net, "psched", 0, &psched_fops); | ||
| 1712 | 1759 | ||
| 1713 | rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); | 1760 | rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); |
| 1714 | rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL); | 1761 | rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL); |
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index ab82f145f689..6318e1136b83 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | /* Written 1998-2000 by Werner Almesberger, EPFL ICA */ | 3 | /* Written 1998-2000 by Werner Almesberger, EPFL ICA */ |
| 4 | 4 | ||
| 5 | #include <linux/module.h> | 5 | #include <linux/module.h> |
| 6 | #include <linux/slab.h> | ||
| 6 | #include <linux/init.h> | 7 | #include <linux/init.h> |
| 7 | #include <linux/string.h> | 8 | #include <linux/string.h> |
| 8 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
| @@ -51,7 +52,7 @@ struct atm_flow_data { | |||
| 51 | int ref; /* reference count */ | 52 | int ref; /* reference count */ |
| 52 | struct gnet_stats_basic_packed bstats; | 53 | struct gnet_stats_basic_packed bstats; |
| 53 | struct gnet_stats_queue qstats; | 54 | struct gnet_stats_queue qstats; |
| 54 | struct atm_flow_data *next; | 55 | struct list_head list; |
| 55 | struct atm_flow_data *excess; /* flow for excess traffic; | 56 | struct atm_flow_data *excess; /* flow for excess traffic; |
| 56 | NULL to set CLP instead */ | 57 | NULL to set CLP instead */ |
| 57 | int hdr_len; | 58 | int hdr_len; |
| @@ -60,34 +61,23 @@ struct atm_flow_data { | |||
| 60 | 61 | ||
| 61 | struct atm_qdisc_data { | 62 | struct atm_qdisc_data { |
| 62 | struct atm_flow_data link; /* unclassified skbs go here */ | 63 | struct atm_flow_data link; /* unclassified skbs go here */ |
| 63 | struct atm_flow_data *flows; /* NB: "link" is also on this | 64 | struct list_head flows; /* NB: "link" is also on this |
| 64 | list */ | 65 | list */ |
| 65 | struct tasklet_struct task; /* dequeue tasklet */ | 66 | struct tasklet_struct task; /* dequeue tasklet */ |
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | /* ------------------------- Class/flow operations ------------------------- */ | 69 | /* ------------------------- Class/flow operations ------------------------- */ |
| 69 | 70 | ||
| 70 | static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow) | ||
| 71 | { | ||
| 72 | struct atm_flow_data *walk; | ||
| 73 | |||
| 74 | pr_debug("find_flow(qdisc %p,flow %p)\n", qdisc, flow); | ||
| 75 | for (walk = qdisc->flows; walk; walk = walk->next) | ||
| 76 | if (walk == flow) | ||
| 77 | return 1; | ||
| 78 | pr_debug("find_flow: not found\n"); | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) | 71 | static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) |
| 83 | { | 72 | { |
| 84 | struct atm_qdisc_data *p = qdisc_priv(sch); | 73 | struct atm_qdisc_data *p = qdisc_priv(sch); |
| 85 | struct atm_flow_data *flow; | 74 | struct atm_flow_data *flow; |
| 86 | 75 | ||
| 87 | for (flow = p->flows; flow; flow = flow->next) | 76 | list_for_each_entry(flow, &p->flows, list) { |
| 88 | if (flow->classid == classid) | 77 | if (flow->classid == classid) |
| 89 | break; | 78 | return flow; |
| 90 | return flow; | 79 | } |
| 80 | return NULL; | ||
| 91 | } | 81 | } |
| 92 | 82 | ||
| 93 | static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, | 83 | static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, |
| @@ -98,7 +88,7 @@ static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, | |||
| 98 | 88 | ||
| 99 | pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", | 89 | pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n", |
| 100 | sch, p, flow, new, old); | 90 | sch, p, flow, new, old); |
| 101 | if (!find_flow(p, flow)) | 91 | if (list_empty(&flow->list)) |
| 102 | return -EINVAL; | 92 | return -EINVAL; |
| 103 | if (!new) | 93 | if (!new) |
| 104 | new = &noop_qdisc; | 94 | new = &noop_qdisc; |
| @@ -145,20 +135,12 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl) | |||
| 145 | { | 135 | { |
| 146 | struct atm_qdisc_data *p = qdisc_priv(sch); | 136 | struct atm_qdisc_data *p = qdisc_priv(sch); |
| 147 | struct atm_flow_data *flow = (struct atm_flow_data *)cl; | 137 | struct atm_flow_data *flow = (struct atm_flow_data *)cl; |
| 148 | struct atm_flow_data **prev; | ||
| 149 | 138 | ||
| 150 | pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); | 139 | pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); |
| 151 | if (--flow->ref) | 140 | if (--flow->ref) |
| 152 | return; | 141 | return; |
| 153 | pr_debug("atm_tc_put: destroying\n"); | 142 | pr_debug("atm_tc_put: destroying\n"); |
| 154 | for (prev = &p->flows; *prev; prev = &(*prev)->next) | 143 | list_del_init(&flow->list); |
| 155 | if (*prev == flow) | ||
| 156 | break; | ||
| 157 | if (!*prev) { | ||
| 158 | printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow); | ||
| 159 | return; | ||
| 160 | } | ||
| 161 | *prev = flow->next; | ||
| 162 | pr_debug("atm_tc_put: qdisc %p\n", flow->q); | 144 | pr_debug("atm_tc_put: qdisc %p\n", flow->q); |
| 163 | qdisc_destroy(flow->q); | 145 | qdisc_destroy(flow->q); |
| 164 | tcf_destroy_chain(&flow->filter_list); | 146 | tcf_destroy_chain(&flow->filter_list); |
| @@ -273,10 +255,6 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, | |||
| 273 | error = -EINVAL; | 255 | error = -EINVAL; |
| 274 | goto err_out; | 256 | goto err_out; |
| 275 | } | 257 | } |
| 276 | if (find_flow(p, flow)) { | ||
| 277 | error = -EEXIST; | ||
| 278 | goto err_out; | ||
| 279 | } | ||
| 280 | } else { | 258 | } else { |
| 281 | int i; | 259 | int i; |
| 282 | unsigned long cl; | 260 | unsigned long cl; |
| @@ -312,8 +290,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, | |||
| 312 | flow->classid = classid; | 290 | flow->classid = classid; |
| 313 | flow->ref = 1; | 291 | flow->ref = 1; |
| 314 | flow->excess = excess; | 292 | flow->excess = excess; |
| 315 | flow->next = p->link.next; | 293 | list_add(&flow->list, &p->link.list); |
| 316 | p->link.next = flow; | ||
| 317 | flow->hdr_len = hdr_len; | 294 | flow->hdr_len = hdr_len; |
| 318 | if (hdr) | 295 | if (hdr) |
| 319 | memcpy(flow->hdr, hdr, hdr_len); | 296 | memcpy(flow->hdr, hdr, hdr_len); |
| @@ -334,7 +311,7 @@ static int atm_tc_delete(struct Qdisc *sch, unsigned long arg) | |||
| 334 | struct atm_flow_data *flow = (struct atm_flow_data *)arg; | 311 | struct atm_flow_data *flow = (struct atm_flow_data *)arg; |
| 335 | 312 | ||
| 336 | pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); | 313 | pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow); |
| 337 | if (!find_flow(qdisc_priv(sch), flow)) | 314 | if (list_empty(&flow->list)) |
| 338 | return -EINVAL; | 315 | return -EINVAL; |
| 339 | if (flow->filter_list || flow == &p->link) | 316 | if (flow->filter_list || flow == &p->link) |
| 340 | return -EBUSY; | 317 | return -EBUSY; |
| @@ -360,12 +337,12 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker) | |||
| 360 | pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); | 337 | pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker); |
| 361 | if (walker->stop) | 338 | if (walker->stop) |
| 362 | return; | 339 | return; |
| 363 | for (flow = p->flows; flow; flow = flow->next) { | 340 | list_for_each_entry(flow, &p->flows, list) { |
| 364 | if (walker->count >= walker->skip) | 341 | if (walker->count >= walker->skip && |
| 365 | if (walker->fn(sch, (unsigned long)flow, walker) < 0) { | 342 | walker->fn(sch, (unsigned long)flow, walker) < 0) { |
| 366 | walker->stop = 1; | 343 | walker->stop = 1; |
| 367 | break; | 344 | break; |
| 368 | } | 345 | } |
| 369 | walker->count++; | 346 | walker->count++; |
| 370 | } | 347 | } |
| 371 | } | 348 | } |
| @@ -384,16 +361,17 @@ static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl) | |||
| 384 | static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) | 361 | static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
| 385 | { | 362 | { |
| 386 | struct atm_qdisc_data *p = qdisc_priv(sch); | 363 | struct atm_qdisc_data *p = qdisc_priv(sch); |
| 387 | struct atm_flow_data *flow = NULL; /* @@@ */ | 364 | struct atm_flow_data *flow; |
| 388 | struct tcf_result res; | 365 | struct tcf_result res; |
| 389 | int result; | 366 | int result; |
| 390 | int ret = NET_XMIT_POLICED; | 367 | int ret = NET_XMIT_POLICED; |
| 391 | 368 | ||
| 392 | pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); | 369 | pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); |
| 393 | result = TC_POLICE_OK; /* be nice to gcc */ | 370 | result = TC_POLICE_OK; /* be nice to gcc */ |
| 371 | flow = NULL; | ||
| 394 | if (TC_H_MAJ(skb->priority) != sch->handle || | 372 | if (TC_H_MAJ(skb->priority) != sch->handle || |
| 395 | !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) | 373 | !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority))) { |
| 396 | for (flow = p->flows; flow; flow = flow->next) | 374 | list_for_each_entry(flow, &p->flows, list) { |
| 397 | if (flow->filter_list) { | 375 | if (flow->filter_list) { |
| 398 | result = tc_classify_compat(skb, | 376 | result = tc_classify_compat(skb, |
| 399 | flow->filter_list, | 377 | flow->filter_list, |
| @@ -403,8 +381,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 403 | flow = (struct atm_flow_data *)res.class; | 381 | flow = (struct atm_flow_data *)res.class; |
| 404 | if (!flow) | 382 | if (!flow) |
| 405 | flow = lookup_flow(sch, res.classid); | 383 | flow = lookup_flow(sch, res.classid); |
| 406 | break; | 384 | goto done; |
| 407 | } | 385 | } |
| 386 | } | ||
| 387 | flow = NULL; | ||
| 388 | done: | ||
| 389 | ; | ||
| 390 | } | ||
| 408 | if (!flow) | 391 | if (!flow) |
| 409 | flow = &p->link; | 392 | flow = &p->link; |
| 410 | else { | 393 | else { |
| @@ -431,7 +414,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 431 | } | 414 | } |
| 432 | 415 | ||
| 433 | ret = qdisc_enqueue(skb, flow->q); | 416 | ret = qdisc_enqueue(skb, flow->q); |
| 434 | if (ret != 0) { | 417 | if (ret != NET_XMIT_SUCCESS) { |
| 435 | drop: __maybe_unused | 418 | drop: __maybe_unused |
| 436 | if (net_xmit_drop_count(ret)) { | 419 | if (net_xmit_drop_count(ret)) { |
| 437 | sch->qstats.drops++; | 420 | sch->qstats.drops++; |
| @@ -455,7 +438,7 @@ drop: __maybe_unused | |||
| 455 | */ | 438 | */ |
| 456 | if (flow == &p->link) { | 439 | if (flow == &p->link) { |
| 457 | sch->q.qlen++; | 440 | sch->q.qlen++; |
| 458 | return 0; | 441 | return NET_XMIT_SUCCESS; |
| 459 | } | 442 | } |
| 460 | tasklet_schedule(&p->task); | 443 | tasklet_schedule(&p->task); |
| 461 | return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; | 444 | return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; |
| @@ -476,7 +459,9 @@ static void sch_atm_dequeue(unsigned long data) | |||
| 476 | struct sk_buff *skb; | 459 | struct sk_buff *skb; |
| 477 | 460 | ||
| 478 | pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); | 461 | pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p); |
| 479 | for (flow = p->link.next; flow; flow = flow->next) | 462 | list_for_each_entry(flow, &p->flows, list) { |
| 463 | if (flow == &p->link) | ||
| 464 | continue; | ||
| 480 | /* | 465 | /* |
| 481 | * If traffic is properly shaped, this won't generate nasty | 466 | * If traffic is properly shaped, this won't generate nasty |
| 482 | * little bursts. Otherwise, it may ... (but that's okay) | 467 | * little bursts. Otherwise, it may ... (but that's okay) |
| @@ -511,6 +496,7 @@ static void sch_atm_dequeue(unsigned long data) | |||
| 511 | /* atm.atm_options are already set by atm_tc_enqueue */ | 496 | /* atm.atm_options are already set by atm_tc_enqueue */ |
| 512 | flow->vcc->send(flow->vcc, skb); | 497 | flow->vcc->send(flow->vcc, skb); |
| 513 | } | 498 | } |
| 499 | } | ||
| 514 | } | 500 | } |
| 515 | 501 | ||
| 516 | static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) | 502 | static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) |
| @@ -542,9 +528,10 @@ static unsigned int atm_tc_drop(struct Qdisc *sch) | |||
| 542 | unsigned int len; | 528 | unsigned int len; |
| 543 | 529 | ||
| 544 | pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p); | 530 | pr_debug("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p); |
| 545 | for (flow = p->flows; flow; flow = flow->next) | 531 | list_for_each_entry(flow, &p->flows, list) { |
| 546 | if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q))) | 532 | if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q))) |
| 547 | return len; | 533 | return len; |
| 534 | } | ||
| 548 | return 0; | 535 | return 0; |
| 549 | } | 536 | } |
| 550 | 537 | ||
| @@ -553,7 +540,9 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 553 | struct atm_qdisc_data *p = qdisc_priv(sch); | 540 | struct atm_qdisc_data *p = qdisc_priv(sch); |
| 554 | 541 | ||
| 555 | pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); | 542 | pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); |
| 556 | p->flows = &p->link; | 543 | INIT_LIST_HEAD(&p->flows); |
| 544 | INIT_LIST_HEAD(&p->link.list); | ||
| 545 | list_add(&p->link.list, &p->flows); | ||
| 557 | p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 546 | p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, |
| 558 | &pfifo_qdisc_ops, sch->handle); | 547 | &pfifo_qdisc_ops, sch->handle); |
| 559 | if (!p->link.q) | 548 | if (!p->link.q) |
| @@ -564,7 +553,6 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) | |||
| 564 | p->link.sock = NULL; | 553 | p->link.sock = NULL; |
| 565 | p->link.classid = sch->handle; | 554 | p->link.classid = sch->handle; |
| 566 | p->link.ref = 1; | 555 | p->link.ref = 1; |
| 567 | p->link.next = NULL; | ||
| 568 | tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch); | 556 | tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch); |
| 569 | return 0; | 557 | return 0; |
| 570 | } | 558 | } |
| @@ -575,7 +563,7 @@ static void atm_tc_reset(struct Qdisc *sch) | |||
| 575 | struct atm_flow_data *flow; | 563 | struct atm_flow_data *flow; |
| 576 | 564 | ||
| 577 | pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); | 565 | pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p); |
| 578 | for (flow = p->flows; flow; flow = flow->next) | 566 | list_for_each_entry(flow, &p->flows, list) |
| 579 | qdisc_reset(flow->q); | 567 | qdisc_reset(flow->q); |
| 580 | sch->q.qlen = 0; | 568 | sch->q.qlen = 0; |
| 581 | } | 569 | } |
| @@ -583,24 +571,17 @@ static void atm_tc_reset(struct Qdisc *sch) | |||
| 583 | static void atm_tc_destroy(struct Qdisc *sch) | 571 | static void atm_tc_destroy(struct Qdisc *sch) |
| 584 | { | 572 | { |
| 585 | struct atm_qdisc_data *p = qdisc_priv(sch); | 573 | struct atm_qdisc_data *p = qdisc_priv(sch); |
| 586 | struct atm_flow_data *flow; | 574 | struct atm_flow_data *flow, *tmp; |
| 587 | 575 | ||
| 588 | pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); | 576 | pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p); |
| 589 | for (flow = p->flows; flow; flow = flow->next) | 577 | list_for_each_entry(flow, &p->flows, list) |
| 590 | tcf_destroy_chain(&flow->filter_list); | 578 | tcf_destroy_chain(&flow->filter_list); |
| 591 | 579 | ||
| 592 | /* races ? */ | 580 | list_for_each_entry_safe(flow, tmp, &p->flows, list) { |
| 593 | while ((flow = p->flows)) { | ||
| 594 | if (flow->ref > 1) | 581 | if (flow->ref > 1) |
| 595 | printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow, | 582 | printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow, |
| 596 | flow->ref); | 583 | flow->ref); |
| 597 | atm_tc_put(sch, (unsigned long)flow); | 584 | atm_tc_put(sch, (unsigned long)flow); |
| 598 | if (p->flows == flow) { | ||
| 599 | printk(KERN_ERR "atm_destroy: putting flow %p didn't " | ||
| 600 | "kill it\n", flow); | ||
| 601 | p->flows = flow->next; /* brute force */ | ||
| 602 | break; | ||
| 603 | } | ||
| 604 | } | 585 | } |
| 605 | tasklet_kill(&p->task); | 586 | tasklet_kill(&p->task); |
| 606 | } | 587 | } |
| @@ -614,7 +595,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, | |||
| 614 | 595 | ||
| 615 | pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", | 596 | pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", |
| 616 | sch, p, flow, skb, tcm); | 597 | sch, p, flow, skb, tcm); |
| 617 | if (!find_flow(p, flow)) | 598 | if (list_empty(&flow->list)) |
| 618 | return -EINVAL; | 599 | return -EINVAL; |
| 619 | tcm->tcm_handle = flow->classid; | 600 | tcm->tcm_handle = flow->classid; |
| 620 | tcm->tcm_info = flow->q->handle; | 601 | tcm->tcm_info = flow->q->handle; |
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 3846d65bc03e..28c01ef5abc8 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/slab.h> | ||
| 14 | #include <linux/types.h> | 15 | #include <linux/types.h> |
| 15 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 16 | #include <linux/string.h> | 17 | #include <linux/string.h> |
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index a65604f8f2b8..b74046a95397 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/slab.h> | ||
| 12 | #include <linux/init.h> | 13 | #include <linux/init.h> |
| 13 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
| 14 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index d303daa45d49..63d41f86679c 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
| 7 | #include <linux/init.h> | 7 | #include <linux/init.h> |
| 8 | #include <linux/slab.h> | ||
| 8 | #include <linux/types.h> | 9 | #include <linux/types.h> |
| 9 | #include <linux/string.h> | 10 | #include <linux/string.h> |
| 10 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index 69188e8358b4..5948bafa8ce2 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | ||
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| @@ -43,6 +44,26 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch) | |||
| 43 | return qdisc_reshape_fail(skb, sch); | 44 | return qdisc_reshape_fail(skb, sch); |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 47 | static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc* sch) | ||
| 48 | { | ||
| 49 | struct sk_buff *skb_head; | ||
| 50 | struct fifo_sched_data *q = qdisc_priv(sch); | ||
| 51 | |||
| 52 | if (likely(skb_queue_len(&sch->q) < q->limit)) | ||
| 53 | return qdisc_enqueue_tail(skb, sch); | ||
| 54 | |||
| 55 | /* queue full, remove one skb to fulfill the limit */ | ||
| 56 | skb_head = qdisc_dequeue_head(sch); | ||
| 57 | sch->bstats.bytes -= qdisc_pkt_len(skb_head); | ||
| 58 | sch->bstats.packets--; | ||
| 59 | sch->qstats.drops++; | ||
| 60 | kfree_skb(skb_head); | ||
| 61 | |||
| 62 | qdisc_enqueue_tail(skb, sch); | ||
| 63 | |||
| 64 | return NET_XMIT_CN; | ||
| 65 | } | ||
| 66 | |||
| 46 | static int fifo_init(struct Qdisc *sch, struct nlattr *opt) | 67 | static int fifo_init(struct Qdisc *sch, struct nlattr *opt) |
| 47 | { | 68 | { |
| 48 | struct fifo_sched_data *q = qdisc_priv(sch); | 69 | struct fifo_sched_data *q = qdisc_priv(sch); |
| @@ -108,6 +129,20 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = { | |||
| 108 | }; | 129 | }; |
| 109 | EXPORT_SYMBOL(bfifo_qdisc_ops); | 130 | EXPORT_SYMBOL(bfifo_qdisc_ops); |
| 110 | 131 | ||
| 132 | struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = { | ||
| 133 | .id = "pfifo_head_drop", | ||
| 134 | .priv_size = sizeof(struct fifo_sched_data), | ||
| 135 | .enqueue = pfifo_tail_enqueue, | ||
| 136 | .dequeue = qdisc_dequeue_head, | ||
| 137 | .peek = qdisc_peek_head, | ||
| 138 | .drop = qdisc_queue_drop_head, | ||
| 139 | .init = fifo_init, | ||
| 140 | .reset = qdisc_reset_queue, | ||
| 141 | .change = fifo_init, | ||
| 142 | .dump = fifo_dump, | ||
| 143 | .owner = THIS_MODULE, | ||
| 144 | }; | ||
| 145 | |||
| 111 | /* Pass size change message down to embedded FIFO */ | 146 | /* Pass size change message down to embedded FIFO */ |
| 112 | int fifo_set_limit(struct Qdisc *q, unsigned int limit) | 147 | int fifo_set_limit(struct Qdisc *q, unsigned int limit) |
| 113 | { | 148 | { |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 5173c1e1b19c..2aeb3a4386a1 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
| @@ -24,7 +24,9 @@ | |||
| 24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
| 25 | #include <linux/rcupdate.h> | 25 | #include <linux/rcupdate.h> |
| 26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
| 27 | #include <linux/slab.h> | ||
| 27 | #include <net/pkt_sched.h> | 28 | #include <net/pkt_sched.h> |
| 29 | #include <net/dst.h> | ||
| 28 | 30 | ||
| 29 | /* Main transmission queue. */ | 31 | /* Main transmission queue. */ |
| 30 | 32 | ||
| @@ -39,6 +41,7 @@ | |||
| 39 | 41 | ||
| 40 | static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) | 42 | static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) |
| 41 | { | 43 | { |
| 44 | skb_dst_force(skb); | ||
| 42 | q->gso_skb = skb; | 45 | q->gso_skb = skb; |
| 43 | q->qstats.requeues++; | 46 | q->qstats.requeues++; |
| 44 | q->q.qlen++; /* it's still part of the queue */ | 47 | q->q.qlen++; /* it's still part of the queue */ |
| @@ -93,7 +96,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb, | |||
| 93 | * Another cpu is holding lock, requeue & delay xmits for | 96 | * Another cpu is holding lock, requeue & delay xmits for |
| 94 | * some time. | 97 | * some time. |
| 95 | */ | 98 | */ |
| 96 | __get_cpu_var(netdev_rx_stat).cpu_collision++; | 99 | __this_cpu_inc(softnet_data.cpu_collision); |
| 97 | ret = dev_requeue_skb(skb, q); | 100 | ret = dev_requeue_skb(skb, q); |
| 98 | } | 101 | } |
| 99 | 102 | ||
| @@ -178,7 +181,7 @@ static inline int qdisc_restart(struct Qdisc *q) | |||
| 178 | skb = dequeue_skb(q); | 181 | skb = dequeue_skb(q); |
| 179 | if (unlikely(!skb)) | 182 | if (unlikely(!skb)) |
| 180 | return 0; | 183 | return 0; |
| 181 | 184 | WARN_ON_ONCE(skb_dst_is_noref(skb)); | |
| 182 | root_lock = qdisc_lock(q); | 185 | root_lock = qdisc_lock(q); |
| 183 | dev = qdisc_dev(q); | 186 | dev = qdisc_dev(q); |
| 184 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); | 187 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); |
| @@ -202,7 +205,7 @@ void __qdisc_run(struct Qdisc *q) | |||
| 202 | } | 205 | } |
| 203 | } | 206 | } |
| 204 | 207 | ||
| 205 | clear_bit(__QDISC_STATE_RUNNING, &q->state); | 208 | qdisc_run_end(q); |
| 206 | } | 209 | } |
| 207 | 210 | ||
| 208 | unsigned long dev_trans_start(struct net_device *dev) | 211 | unsigned long dev_trans_start(struct net_device *dev) |
| @@ -324,6 +327,24 @@ void netif_carrier_off(struct net_device *dev) | |||
| 324 | } | 327 | } |
| 325 | EXPORT_SYMBOL(netif_carrier_off); | 328 | EXPORT_SYMBOL(netif_carrier_off); |
| 326 | 329 | ||
| 330 | /** | ||
| 331 | * netif_notify_peers - notify network peers about existence of @dev | ||
| 332 | * @dev: network device | ||
| 333 | * | ||
| 334 | * Generate traffic such that interested network peers are aware of | ||
| 335 | * @dev, such as by generating a gratuitous ARP. This may be used when | ||
| 336 | * a device wants to inform the rest of the network about some sort of | ||
| 337 | * reconfiguration such as a failover event or virtual machine | ||
| 338 | * migration. | ||
| 339 | */ | ||
| 340 | void netif_notify_peers(struct net_device *dev) | ||
| 341 | { | ||
| 342 | rtnl_lock(); | ||
| 343 | call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev); | ||
| 344 | rtnl_unlock(); | ||
| 345 | } | ||
| 346 | EXPORT_SYMBOL(netif_notify_peers); | ||
| 347 | |||
| 327 | /* "NOOP" scheduler: the best scheduler, recommended for all interfaces | 348 | /* "NOOP" scheduler: the best scheduler, recommended for all interfaces |
| 328 | under all circumstances. It is difficult to invent anything faster or | 349 | under all circumstances. It is difficult to invent anything faster or |
| 329 | cheaper. | 350 | cheaper. |
| @@ -528,7 +549,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, | |||
| 528 | unsigned int size; | 549 | unsigned int size; |
| 529 | int err = -ENOBUFS; | 550 | int err = -ENOBUFS; |
| 530 | 551 | ||
| 531 | /* ensure that the Qdisc and the private data are 32-byte aligned */ | 552 | /* ensure that the Qdisc and the private data are 64-byte aligned */ |
| 532 | size = QDISC_ALIGN(sizeof(*sch)); | 553 | size = QDISC_ALIGN(sizeof(*sch)); |
| 533 | size += ops->priv_size + (QDISC_ALIGNTO - 1); | 554 | size += ops->priv_size + (QDISC_ALIGNTO - 1); |
| 534 | 555 | ||
| @@ -540,6 +561,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, | |||
| 540 | 561 | ||
| 541 | INIT_LIST_HEAD(&sch->list); | 562 | INIT_LIST_HEAD(&sch->list); |
| 542 | skb_queue_head_init(&sch->q); | 563 | skb_queue_head_init(&sch->q); |
| 564 | spin_lock_init(&sch->busylock); | ||
| 543 | sch->ops = ops; | 565 | sch->ops = ops; |
| 544 | sch->enqueue = ops->enqueue; | 566 | sch->enqueue = ops->enqueue; |
| 545 | sch->dequeue = ops->dequeue; | 567 | sch->dequeue = ops->dequeue; |
| @@ -590,6 +612,13 @@ void qdisc_reset(struct Qdisc *qdisc) | |||
| 590 | } | 612 | } |
| 591 | EXPORT_SYMBOL(qdisc_reset); | 613 | EXPORT_SYMBOL(qdisc_reset); |
| 592 | 614 | ||
| 615 | static void qdisc_rcu_free(struct rcu_head *head) | ||
| 616 | { | ||
| 617 | struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head); | ||
| 618 | |||
| 619 | kfree((char *) qdisc - qdisc->padded); | ||
| 620 | } | ||
| 621 | |||
| 593 | void qdisc_destroy(struct Qdisc *qdisc) | 622 | void qdisc_destroy(struct Qdisc *qdisc) |
| 594 | { | 623 | { |
| 595 | const struct Qdisc_ops *ops = qdisc->ops; | 624 | const struct Qdisc_ops *ops = qdisc->ops; |
| @@ -613,7 +642,11 @@ void qdisc_destroy(struct Qdisc *qdisc) | |||
| 613 | dev_put(qdisc_dev(qdisc)); | 642 | dev_put(qdisc_dev(qdisc)); |
| 614 | 643 | ||
| 615 | kfree_skb(qdisc->gso_skb); | 644 | kfree_skb(qdisc->gso_skb); |
| 616 | kfree((char *) qdisc - qdisc->padded); | 645 | /* |
| 646 | * gen_estimator est_timer() might access qdisc->q.lock, | ||
| 647 | * wait a RCU grace period before freeing qdisc. | ||
| 648 | */ | ||
| 649 | call_rcu(&qdisc->rcu_head, qdisc_rcu_free); | ||
| 617 | } | 650 | } |
| 618 | EXPORT_SYMBOL(qdisc_destroy); | 651 | EXPORT_SYMBOL(qdisc_destroy); |
| 619 | 652 | ||
| @@ -765,7 +798,7 @@ static bool some_qdisc_is_busy(struct net_device *dev) | |||
| 765 | 798 | ||
| 766 | spin_lock_bh(root_lock); | 799 | spin_lock_bh(root_lock); |
| 767 | 800 | ||
| 768 | val = (test_bit(__QDISC_STATE_RUNNING, &q->state) || | 801 | val = (qdisc_is_running(q) || |
| 769 | test_bit(__QDISC_STATE_SCHED, &q->state)); | 802 | test_bit(__QDISC_STATE_SCHED, &q->state)); |
| 770 | 803 | ||
| 771 | spin_unlock_bh(root_lock); | 804 | spin_unlock_bh(root_lock); |
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index 40408d595c08..51dcc2aa5c92 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | * For all the glorious comments look at include/net/red.h | 18 | * For all the glorious comments look at include/net/red.h |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/slab.h> | ||
| 21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 22 | #include <linux/types.h> | 23 | #include <linux/types.h> |
| 23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index b38b39c60752..47496098d35c 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c | |||
| @@ -617,7 +617,6 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) | |||
| 617 | rtsc->y = y; | 617 | rtsc->y = y; |
| 618 | rtsc->dx = dx; | 618 | rtsc->dx = dx; |
| 619 | rtsc->dy = dy; | 619 | rtsc->dy = dy; |
| 620 | return; | ||
| 621 | } | 620 | } |
| 622 | 621 | ||
| 623 | static void | 622 | static void |
| @@ -762,8 +761,8 @@ init_vf(struct hfsc_class *cl, unsigned int len) | |||
| 762 | if (f != cl->cl_f) { | 761 | if (f != cl->cl_f) { |
| 763 | cl->cl_f = f; | 762 | cl->cl_f = f; |
| 764 | cftree_update(cl); | 763 | cftree_update(cl); |
| 765 | update_cfmin(cl->cl_parent); | ||
| 766 | } | 764 | } |
| 765 | update_cfmin(cl->cl_parent); | ||
| 767 | } | 766 | } |
| 768 | } | 767 | } |
| 769 | 768 | ||
| @@ -1155,7 +1154,7 @@ static struct hfsc_class * | |||
| 1155 | hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) | 1154 | hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) |
| 1156 | { | 1155 | { |
| 1157 | struct hfsc_sched *q = qdisc_priv(sch); | 1156 | struct hfsc_sched *q = qdisc_priv(sch); |
| 1158 | struct hfsc_class *cl; | 1157 | struct hfsc_class *head, *cl; |
| 1159 | struct tcf_result res; | 1158 | struct tcf_result res; |
| 1160 | struct tcf_proto *tcf; | 1159 | struct tcf_proto *tcf; |
| 1161 | int result; | 1160 | int result; |
| @@ -1166,6 +1165,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) | |||
| 1166 | return cl; | 1165 | return cl; |
| 1167 | 1166 | ||
| 1168 | *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; | 1167 | *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; |
| 1168 | head = &q->root; | ||
| 1169 | tcf = q->root.filter_list; | 1169 | tcf = q->root.filter_list; |
| 1170 | while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { | 1170 | while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { |
| 1171 | #ifdef CONFIG_NET_CLS_ACT | 1171 | #ifdef CONFIG_NET_CLS_ACT |
| @@ -1180,6 +1180,8 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) | |||
| 1180 | if ((cl = (struct hfsc_class *)res.class) == NULL) { | 1180 | if ((cl = (struct hfsc_class *)res.class) == NULL) { |
| 1181 | if ((cl = hfsc_find_class(res.classid, sch)) == NULL) | 1181 | if ((cl = hfsc_find_class(res.classid, sch)) == NULL) |
| 1182 | break; /* filter selected invalid classid */ | 1182 | break; /* filter selected invalid classid */ |
| 1183 | if (cl->level >= head->level) | ||
| 1184 | break; /* filter may only point downwards */ | ||
| 1183 | } | 1185 | } |
| 1184 | 1186 | ||
| 1185 | if (cl->level == 0) | 1187 | if (cl->level == 0) |
| @@ -1187,6 +1189,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) | |||
| 1187 | 1189 | ||
| 1188 | /* apply inner filter chain */ | 1190 | /* apply inner filter chain */ |
| 1189 | tcf = cl->filter_list; | 1191 | tcf = cl->filter_list; |
| 1192 | head = cl; | ||
| 1190 | } | 1193 | } |
| 1191 | 1194 | ||
| 1192 | /* classification failed, try default class */ | 1195 | /* classification failed, try default class */ |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 508cf5f3a6d5..4be8d04b262d 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/compiler.h> | 36 | #include <linux/compiler.h> |
| 37 | #include <linux/rbtree.h> | 37 | #include <linux/rbtree.h> |
| 38 | #include <linux/workqueue.h> | 38 | #include <linux/workqueue.h> |
| 39 | #include <linux/slab.h> | ||
| 39 | #include <net/netlink.h> | 40 | #include <net/netlink.h> |
| 40 | #include <net/pkt_sched.h> | 41 | #include <net/pkt_sched.h> |
| 41 | 42 | ||
| @@ -1549,7 +1550,6 @@ static const struct Qdisc_class_ops htb_class_ops = { | |||
| 1549 | }; | 1550 | }; |
| 1550 | 1551 | ||
| 1551 | static struct Qdisc_ops htb_qdisc_ops __read_mostly = { | 1552 | static struct Qdisc_ops htb_qdisc_ops __read_mostly = { |
| 1552 | .next = NULL, | ||
| 1553 | .cl_ops = &htb_class_ops, | 1553 | .cl_ops = &htb_class_ops, |
| 1554 | .id = "htb", | 1554 | .id = "htb", |
| 1555 | .priv_size = sizeof(struct htb_sched), | 1555 | .priv_size = sizeof(struct htb_sched), |
| @@ -1560,7 +1560,6 @@ static struct Qdisc_ops htb_qdisc_ops __read_mostly = { | |||
| 1560 | .init = htb_init, | 1560 | .init = htb_init, |
| 1561 | .reset = htb_reset, | 1561 | .reset = htb_reset, |
| 1562 | .destroy = htb_destroy, | 1562 | .destroy = htb_destroy, |
| 1563 | .change = NULL /* htb_change */, | ||
| 1564 | .dump = htb_dump, | 1563 | .dump = htb_dump, |
| 1565 | .owner = THIS_MODULE, | 1564 | .owner = THIS_MODULE, |
| 1566 | }; | 1565 | }; |
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index a9e646bdb605..f10e34a68445 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c | |||
| @@ -44,7 +44,6 @@ static void ingress_put(struct Qdisc *sch, unsigned long cl) | |||
| 44 | 44 | ||
| 45 | static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) | 45 | static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) |
| 46 | { | 46 | { |
| 47 | return; | ||
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch, unsigned long cl) | 49 | static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch, unsigned long cl) |
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index d1dea3d5dc92..fe91e50f9d98 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <linux/slab.h> | ||
| 12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 13 | #include <linux/string.h> | 14 | #include <linux/string.h> |
| 14 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
| @@ -173,7 +174,6 @@ static unsigned long mq_get(struct Qdisc *sch, u32 classid) | |||
| 173 | 174 | ||
| 174 | static void mq_put(struct Qdisc *sch, unsigned long cl) | 175 | static void mq_put(struct Qdisc *sch, unsigned long cl) |
| 175 | { | 176 | { |
| 176 | return; | ||
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static int mq_dump_class(struct Qdisc *sch, unsigned long cl, | 179 | static int mq_dump_class(struct Qdisc *sch, unsigned long cl, |
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 7db2c88ce585..6ae251279fc2 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/slab.h> | ||
| 21 | #include <linux/types.h> | 22 | #include <linux/types.h> |
| 22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 23 | #include <linux/string.h> | 24 | #include <linux/string.h> |
| @@ -339,7 +340,6 @@ static unsigned long multiq_bind(struct Qdisc *sch, unsigned long parent, | |||
| 339 | 340 | ||
| 340 | static void multiq_put(struct Qdisc *q, unsigned long cl) | 341 | static void multiq_put(struct Qdisc *q, unsigned long cl) |
| 341 | { | 342 | { |
| 342 | return; | ||
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | static int multiq_dump_class(struct Qdisc *sch, unsigned long cl, | 345 | static int multiq_dump_class(struct Qdisc *sch, unsigned long cl, |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index d8b10e054627..4714ff162bbd 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/slab.h> | ||
| 17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 18 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
| 19 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 93285cecb246..0748fb1e3a49 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/slab.h> | ||
| 15 | #include <linux/types.h> | 16 | #include <linux/types.h> |
| 16 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 17 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| @@ -302,7 +303,6 @@ static unsigned long prio_bind(struct Qdisc *sch, unsigned long parent, u32 clas | |||
| 302 | 303 | ||
| 303 | static void prio_put(struct Qdisc *q, unsigned long cl) | 304 | static void prio_put(struct Qdisc *q, unsigned long cl) |
| 304 | { | 305 | { |
| 305 | return; | ||
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, | 308 | static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, |
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 072cdf442f8e..8d42bb3ba540 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c | |||
| @@ -303,7 +303,6 @@ static unsigned long red_get(struct Qdisc *sch, u32 classid) | |||
| 303 | 303 | ||
| 304 | static void red_put(struct Qdisc *sch, unsigned long arg) | 304 | static void red_put(struct Qdisc *sch, unsigned long arg) |
| 305 | { | 305 | { |
| 306 | return; | ||
| 307 | } | 306 | } |
| 308 | 307 | ||
| 309 | static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) | 308 | static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) |
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index cb21380c0605..201cbac2b32c 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/ipv6.h> | 20 | #include <linux/ipv6.h> |
| 21 | #include <linux/skbuff.h> | 21 | #include <linux/skbuff.h> |
| 22 | #include <linux/jhash.h> | 22 | #include <linux/jhash.h> |
| 23 | #include <linux/slab.h> | ||
| 23 | #include <net/ip.h> | 24 | #include <net/ip.h> |
| 24 | #include <net/netlink.h> | 25 | #include <net/netlink.h> |
| 25 | #include <net/pkt_sched.h> | 26 | #include <net/pkt_sched.h> |
| @@ -121,35 +122,46 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) | |||
| 121 | switch (skb->protocol) { | 122 | switch (skb->protocol) { |
| 122 | case htons(ETH_P_IP): | 123 | case htons(ETH_P_IP): |
| 123 | { | 124 | { |
| 124 | const struct iphdr *iph = ip_hdr(skb); | 125 | const struct iphdr *iph; |
| 125 | h = iph->daddr; | 126 | |
| 126 | h2 = iph->saddr ^ iph->protocol; | 127 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
| 128 | goto err; | ||
| 129 | iph = ip_hdr(skb); | ||
| 130 | h = (__force u32)iph->daddr; | ||
| 131 | h2 = (__force u32)iph->saddr ^ iph->protocol; | ||
| 127 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 132 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && |
| 128 | (iph->protocol == IPPROTO_TCP || | 133 | (iph->protocol == IPPROTO_TCP || |
| 129 | iph->protocol == IPPROTO_UDP || | 134 | iph->protocol == IPPROTO_UDP || |
| 130 | iph->protocol == IPPROTO_UDPLITE || | 135 | iph->protocol == IPPROTO_UDPLITE || |
| 131 | iph->protocol == IPPROTO_SCTP || | 136 | iph->protocol == IPPROTO_SCTP || |
| 132 | iph->protocol == IPPROTO_DCCP || | 137 | iph->protocol == IPPROTO_DCCP || |
| 133 | iph->protocol == IPPROTO_ESP)) | 138 | iph->protocol == IPPROTO_ESP) && |
| 139 | pskb_network_may_pull(skb, iph->ihl * 4 + 4)) | ||
| 134 | h2 ^= *(((u32*)iph) + iph->ihl); | 140 | h2 ^= *(((u32*)iph) + iph->ihl); |
| 135 | break; | 141 | break; |
| 136 | } | 142 | } |
| 137 | case htons(ETH_P_IPV6): | 143 | case htons(ETH_P_IPV6): |
| 138 | { | 144 | { |
| 139 | struct ipv6hdr *iph = ipv6_hdr(skb); | 145 | struct ipv6hdr *iph; |
| 140 | h = iph->daddr.s6_addr32[3]; | 146 | |
| 141 | h2 = iph->saddr.s6_addr32[3] ^ iph->nexthdr; | 147 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
| 142 | if (iph->nexthdr == IPPROTO_TCP || | 148 | goto err; |
| 143 | iph->nexthdr == IPPROTO_UDP || | 149 | iph = ipv6_hdr(skb); |
| 144 | iph->nexthdr == IPPROTO_UDPLITE || | 150 | h = (__force u32)iph->daddr.s6_addr32[3]; |
| 145 | iph->nexthdr == IPPROTO_SCTP || | 151 | h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr; |
| 146 | iph->nexthdr == IPPROTO_DCCP || | 152 | if ((iph->nexthdr == IPPROTO_TCP || |
| 147 | iph->nexthdr == IPPROTO_ESP) | 153 | iph->nexthdr == IPPROTO_UDP || |
| 154 | iph->nexthdr == IPPROTO_UDPLITE || | ||
| 155 | iph->nexthdr == IPPROTO_SCTP || | ||
| 156 | iph->nexthdr == IPPROTO_DCCP || | ||
| 157 | iph->nexthdr == IPPROTO_ESP) && | ||
| 158 | pskb_network_may_pull(skb, sizeof(*iph) + 4)) | ||
| 148 | h2 ^= *(u32*)&iph[1]; | 159 | h2 ^= *(u32*)&iph[1]; |
| 149 | break; | 160 | break; |
| 150 | } | 161 | } |
| 151 | default: | 162 | default: |
| 152 | h = (unsigned long)skb_dst(skb) ^ skb->protocol; | 163 | err: |
| 164 | h = (unsigned long)skb_dst(skb) ^ (__force u32)skb->protocol; | ||
| 153 | h2 = (unsigned long)skb->sk; | 165 | h2 = (unsigned long)skb->sk; |
| 154 | } | 166 | } |
| 155 | 167 | ||
| @@ -322,7 +334,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
| 322 | if (++sch->q.qlen <= q->limit) { | 334 | if (++sch->q.qlen <= q->limit) { |
| 323 | sch->bstats.bytes += qdisc_pkt_len(skb); | 335 | sch->bstats.bytes += qdisc_pkt_len(skb); |
| 324 | sch->bstats.packets++; | 336 | sch->bstats.packets++; |
| 325 | return 0; | 337 | return NET_XMIT_SUCCESS; |
| 326 | } | 338 | } |
| 327 | 339 | ||
| 328 | sfq_drop(sch); | 340 | sfq_drop(sch); |
| @@ -496,11 +508,26 @@ nla_put_failure: | |||
| 496 | return -1; | 508 | return -1; |
| 497 | } | 509 | } |
| 498 | 510 | ||
| 511 | static struct Qdisc *sfq_leaf(struct Qdisc *sch, unsigned long arg) | ||
| 512 | { | ||
| 513 | return NULL; | ||
| 514 | } | ||
| 515 | |||
| 499 | static unsigned long sfq_get(struct Qdisc *sch, u32 classid) | 516 | static unsigned long sfq_get(struct Qdisc *sch, u32 classid) |
| 500 | { | 517 | { |
| 501 | return 0; | 518 | return 0; |
| 502 | } | 519 | } |
| 503 | 520 | ||
| 521 | static unsigned long sfq_bind(struct Qdisc *sch, unsigned long parent, | ||
| 522 | u32 classid) | ||
| 523 | { | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | static void sfq_put(struct Qdisc *q, unsigned long cl) | ||
| 528 | { | ||
| 529 | } | ||
| 530 | |||
| 504 | static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl) | 531 | static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl) |
| 505 | { | 532 | { |
| 506 | struct sfq_sched_data *q = qdisc_priv(sch); | 533 | struct sfq_sched_data *q = qdisc_priv(sch); |
| @@ -553,8 +580,12 @@ static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg) | |||
| 553 | } | 580 | } |
| 554 | 581 | ||
| 555 | static const struct Qdisc_class_ops sfq_class_ops = { | 582 | static const struct Qdisc_class_ops sfq_class_ops = { |
| 583 | .leaf = sfq_leaf, | ||
| 556 | .get = sfq_get, | 584 | .get = sfq_get, |
| 585 | .put = sfq_put, | ||
| 557 | .tcf_chain = sfq_find_tcf, | 586 | .tcf_chain = sfq_find_tcf, |
| 587 | .bind_tcf = sfq_bind, | ||
| 588 | .unbind_tcf = sfq_put, | ||
| 558 | .dump = sfq_dump_class, | 589 | .dump = sfq_dump_class, |
| 559 | .dump_stats = sfq_dump_class_stats, | 590 | .dump_stats = sfq_dump_class_stats, |
| 560 | .walk = sfq_walk, | 591 | .walk = sfq_walk, |
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 8fb8107ab188..641a30d64635 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c | |||
| @@ -127,7 +127,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) | |||
| 127 | return qdisc_reshape_fail(skb, sch); | 127 | return qdisc_reshape_fail(skb, sch); |
| 128 | 128 | ||
| 129 | ret = qdisc_enqueue(skb, q->qdisc); | 129 | ret = qdisc_enqueue(skb, q->qdisc); |
| 130 | if (ret != 0) { | 130 | if (ret != NET_XMIT_SUCCESS) { |
| 131 | if (net_xmit_drop_count(ret)) | 131 | if (net_xmit_drop_count(ret)) |
| 132 | sch->qstats.drops++; | 132 | sch->qstats.drops++; |
| 133 | return ret; | 133 | return ret; |
| @@ -136,7 +136,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) | |||
| 136 | sch->q.qlen++; | 136 | sch->q.qlen++; |
| 137 | sch->bstats.bytes += qdisc_pkt_len(skb); | 137 | sch->bstats.bytes += qdisc_pkt_len(skb); |
| 138 | sch->bstats.packets++; | 138 | sch->bstats.packets++; |
| 139 | return 0; | 139 | return NET_XMIT_SUCCESS; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | static unsigned int tbf_drop(struct Qdisc* sch) | 142 | static unsigned int tbf_drop(struct Qdisc* sch) |
| @@ -273,7 +273,11 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt) | |||
| 273 | if (max_size < 0) | 273 | if (max_size < 0) |
| 274 | goto done; | 274 | goto done; |
| 275 | 275 | ||
| 276 | if (qopt->limit > 0) { | 276 | if (q->qdisc != &noop_qdisc) { |
| 277 | err = fifo_set_limit(q->qdisc, qopt->limit); | ||
| 278 | if (err) | ||
| 279 | goto done; | ||
| 280 | } else if (qopt->limit > 0) { | ||
| 277 | child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit); | 281 | child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit); |
| 278 | if (IS_ERR(child)) { | 282 | if (IS_ERR(child)) { |
| 279 | err = PTR_ERR(child); | 283 | err = PTR_ERR(child); |
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index db69637069c4..feaabc103ce6 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/slab.h> | ||
| 14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
| 15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 16 | #include <linux/if_arp.h> | 17 | #include <linux/if_arp.h> |
| @@ -84,7 +85,7 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch) | |||
| 84 | __skb_queue_tail(&q->q, skb); | 85 | __skb_queue_tail(&q->q, skb); |
| 85 | sch->bstats.bytes += qdisc_pkt_len(skb); | 86 | sch->bstats.bytes += qdisc_pkt_len(skb); |
| 86 | sch->bstats.packets++; | 87 | sch->bstats.packets++; |
| 87 | return 0; | 88 | return NET_XMIT_SUCCESS; |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | kfree_skb(skb); | 91 | kfree_skb(skb); |
| @@ -448,6 +449,7 @@ static __init void teql_master_setup(struct net_device *dev) | |||
| 448 | dev->tx_queue_len = 100; | 449 | dev->tx_queue_len = 100; |
| 449 | dev->flags = IFF_NOARP; | 450 | dev->flags = IFF_NOARP; |
| 450 | dev->hard_header_len = LL_MAX_HEADER; | 451 | dev->hard_header_len = LL_MAX_HEADER; |
| 452 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
| 451 | } | 453 | } |
| 452 | 454 | ||
| 453 | static LIST_HEAD(master_dev_list); | 455 | static LIST_HEAD(master_dev_list); |
