aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/Kconfig20
-rw-r--r--net/sched/Makefile2
-rw-r--r--net/sched/act_skbedit.c203
-rw-r--r--net/sched/cls_api.c2
-rw-r--r--net/sched/cls_flow.c28
-rw-r--r--net/sched/cls_route.c2
-rw-r--r--net/sched/em_cmp.c9
-rw-r--r--net/sched/sch_api.c8
-rw-r--r--net/sched/sch_cbq.c2
-rw-r--r--net/sched/sch_dsmark.c8
-rw-r--r--net/sched/sch_generic.c30
-rw-r--r--net/sched/sch_htb.c4
-rw-r--r--net/sched/sch_multiq.c477
-rw-r--r--net/sched/sch_netem.c20
-rw-r--r--net/sched/sch_prio.c6
-rw-r--r--net/sched/sch_sfq.c4
-rw-r--r--net/sched/sch_teql.c2
17 files changed, 772 insertions, 55 deletions
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 9437b27ff84d..6767e54155db 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -106,6 +106,15 @@ config NET_SCH_PRIO
106 To compile this code as a module, choose M here: the 106 To compile this code as a module, choose M here: the
107 module will be called sch_prio. 107 module will be called sch_prio.
108 108
109config NET_SCH_MULTIQ
110 tristate "Hardware Multiqueue-aware Multi Band Queuing (MULTIQ)"
111 ---help---
112 Say Y here if you want to use an n-band queue packet scheduler
113 to support devices that have multiple hardware transmit queues.
114
115 To compile this code as a module, choose M here: the
116 module will be called sch_multiq.
117
109config NET_SCH_RED 118config NET_SCH_RED
110 tristate "Random Early Detection (RED)" 119 tristate "Random Early Detection (RED)"
111 ---help--- 120 ---help---
@@ -476,6 +485,17 @@ config NET_ACT_SIMP
476 To compile this code as a module, choose M here: the 485 To compile this code as a module, choose M here: the
477 module will be called simple. 486 module will be called simple.
478 487
488config NET_ACT_SKBEDIT
489 tristate "SKB Editing"
490 depends on NET_CLS_ACT
491 ---help---
492 Say Y here to change skb priority or queue_mapping settings.
493
494 If unsure, say N.
495
496 To compile this code as a module, choose M here: the
497 module will be called skbedit.
498
479config NET_CLS_IND 499config NET_CLS_IND
480 bool "Incoming device classification" 500 bool "Incoming device classification"
481 depends on NET_CLS_U32 || NET_CLS_FW 501 depends on NET_CLS_U32 || NET_CLS_FW
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 1d2b0f7df848..e60c9925b269 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o
14obj-$(CONFIG_NET_ACT_NAT) += act_nat.o 14obj-$(CONFIG_NET_ACT_NAT) += act_nat.o
15obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o 15obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o
16obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o 16obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o
17obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
17obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o 18obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o
18obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o 19obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o
19obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o 20obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o
26obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o 27obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o
27obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o 28obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o
28obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o 29obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o
30obj-$(CONFIG_NET_SCH_MULTIQ) += sch_multiq.o
29obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o 31obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o
30obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o 32obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o
31obj-$(CONFIG_NET_CLS_U32) += cls_u32.o 33obj-$(CONFIG_NET_CLS_U32) += cls_u32.o
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
new file mode 100644
index 000000000000..fe9777e77f35
--- /dev/null
+++ b/net/sched/act_skbedit.c
@@ -0,0 +1,203 @@
1/*
2 * Copyright (c) 2008, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Author: Alexander Duyck <alexander.h.duyck@intel.com>
18 */
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/skbuff.h>
24#include <linux/rtnetlink.h>
25#include <net/netlink.h>
26#include <net/pkt_sched.h>
27
28#include <linux/tc_act/tc_skbedit.h>
29#include <net/tc_act/tc_skbedit.h>
30
31#define SKBEDIT_TAB_MASK 15
32static struct tcf_common *tcf_skbedit_ht[SKBEDIT_TAB_MASK + 1];
33static u32 skbedit_idx_gen;
34static DEFINE_RWLOCK(skbedit_lock);
35
36static struct tcf_hashinfo skbedit_hash_info = {
37 .htab = tcf_skbedit_ht,
38 .hmask = SKBEDIT_TAB_MASK,
39 .lock = &skbedit_lock,
40};
41
42static int tcf_skbedit(struct sk_buff *skb, struct tc_action *a,
43 struct tcf_result *res)
44{
45 struct tcf_skbedit *d = a->priv;
46
47 spin_lock(&d->tcf_lock);
48 d->tcf_tm.lastuse = jiffies;
49 d->tcf_bstats.bytes += qdisc_pkt_len(skb);
50 d->tcf_bstats.packets++;
51
52 if (d->flags & SKBEDIT_F_PRIORITY)
53 skb->priority = d->priority;
54 if (d->flags & SKBEDIT_F_QUEUE_MAPPING &&
55 skb->dev->real_num_tx_queues > d->queue_mapping)
56 skb_set_queue_mapping(skb, d->queue_mapping);
57
58 spin_unlock(&d->tcf_lock);
59 return d->tcf_action;
60}
61
62static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
63 [TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) },
64 [TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) },
65 [TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) },
66};
67
68static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est,
69 struct tc_action *a, int ovr, int bind)
70{
71 struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
72 struct tc_skbedit *parm;
73 struct tcf_skbedit *d;
74 struct tcf_common *pc;
75 u32 flags = 0, *priority = NULL;
76 u16 *queue_mapping = NULL;
77 int ret = 0, err;
78
79 if (nla == NULL)
80 return -EINVAL;
81
82 err = nla_parse_nested(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy);
83 if (err < 0)
84 return err;
85
86 if (tb[TCA_SKBEDIT_PARMS] == NULL)
87 return -EINVAL;
88
89 if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
90 flags |= SKBEDIT_F_PRIORITY;
91 priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]);
92 }
93
94 if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
95 flags |= SKBEDIT_F_QUEUE_MAPPING;
96 queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
97 }
98 if (!flags)
99 return -EINVAL;
100
101 parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
102
103 pc = tcf_hash_check(parm->index, a, bind, &skbedit_hash_info);
104 if (!pc) {
105 pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
106 &skbedit_idx_gen, &skbedit_hash_info);
107 if (unlikely(!pc))
108 return -ENOMEM;
109
110 d = to_skbedit(pc);
111 ret = ACT_P_CREATED;
112 } else {
113 d = to_skbedit(pc);
114 if (!ovr) {
115 tcf_hash_release(pc, bind, &skbedit_hash_info);
116 return -EEXIST;
117 }
118 }
119
120 spin_lock_bh(&d->tcf_lock);
121
122 d->flags = flags;
123 if (flags & SKBEDIT_F_PRIORITY)
124 d->priority = *priority;
125 if (flags & SKBEDIT_F_QUEUE_MAPPING)
126 d->queue_mapping = *queue_mapping;
127 d->tcf_action = parm->action;
128
129 spin_unlock_bh(&d->tcf_lock);
130
131 if (ret == ACT_P_CREATED)
132 tcf_hash_insert(pc, &skbedit_hash_info);
133 return ret;
134}
135
136static inline int tcf_skbedit_cleanup(struct tc_action *a, int bind)
137{
138 struct tcf_skbedit *d = a->priv;
139
140 if (d)
141 return tcf_hash_release(&d->common, bind, &skbedit_hash_info);
142 return 0;
143}
144
145static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
146 int bind, int ref)
147{
148 unsigned char *b = skb_tail_pointer(skb);
149 struct tcf_skbedit *d = a->priv;
150 struct tc_skbedit opt;
151 struct tcf_t t;
152
153 opt.index = d->tcf_index;
154 opt.refcnt = d->tcf_refcnt - ref;
155 opt.bindcnt = d->tcf_bindcnt - bind;
156 opt.action = d->tcf_action;
157 NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt);
158 if (d->flags & SKBEDIT_F_PRIORITY)
159 NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority),
160 &d->priority);
161 if (d->flags & SKBEDIT_F_QUEUE_MAPPING)
162 NLA_PUT(skb, TCA_SKBEDIT_QUEUE_MAPPING,
163 sizeof(d->queue_mapping), &d->queue_mapping);
164 t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
165 t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
166 t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
167 NLA_PUT(skb, TCA_SKBEDIT_TM, sizeof(t), &t);
168 return skb->len;
169
170nla_put_failure:
171 nlmsg_trim(skb, b);
172 return -1;
173}
174
175static struct tc_action_ops act_skbedit_ops = {
176 .kind = "skbedit",
177 .hinfo = &skbedit_hash_info,
178 .type = TCA_ACT_SKBEDIT,
179 .capab = TCA_CAP_NONE,
180 .owner = THIS_MODULE,
181 .act = tcf_skbedit,
182 .dump = tcf_skbedit_dump,
183 .cleanup = tcf_skbedit_cleanup,
184 .init = tcf_skbedit_init,
185 .walk = tcf_generic_walker,
186};
187
188MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
189MODULE_DESCRIPTION("SKB Editing");
190MODULE_LICENSE("GPL");
191
192static int __init skbedit_init_module(void)
193{
194 return tcf_register_action(&act_skbedit_ops);
195}
196
197static void __exit skbedit_cleanup_module(void)
198{
199 tcf_unregister_action(&act_skbedit_ops);
200}
201
202module_init(skbedit_init_module);
203module_exit(skbedit_cleanup_module);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 5cafdd4c8018..8eb79e92e94c 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -205,7 +205,7 @@ replay:
205 } 205 }
206 } 206 }
207 207
208 root_lock = qdisc_root_lock(q); 208 root_lock = qdisc_root_sleeping_lock(q);
209 209
210 if (tp == NULL) { 210 if (tp == NULL) {
211 /* Proto-tcf does not exist, create new one */ 211 /* Proto-tcf does not exist, create new one */
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 8f63a1a94014..0ebaff637e31 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -67,9 +67,9 @@ static inline u32 addr_fold(void *addr)
67static u32 flow_get_src(const struct sk_buff *skb) 67static u32 flow_get_src(const struct sk_buff *skb)
68{ 68{
69 switch (skb->protocol) { 69 switch (skb->protocol) {
70 case __constant_htons(ETH_P_IP): 70 case htons(ETH_P_IP):
71 return ntohl(ip_hdr(skb)->saddr); 71 return ntohl(ip_hdr(skb)->saddr);
72 case __constant_htons(ETH_P_IPV6): 72 case htons(ETH_P_IPV6):
73 return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); 73 return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]);
74 default: 74 default:
75 return addr_fold(skb->sk); 75 return addr_fold(skb->sk);
@@ -79,9 +79,9 @@ static u32 flow_get_src(const struct sk_buff *skb)
79static u32 flow_get_dst(const struct sk_buff *skb) 79static u32 flow_get_dst(const struct sk_buff *skb)
80{ 80{
81 switch (skb->protocol) { 81 switch (skb->protocol) {
82 case __constant_htons(ETH_P_IP): 82 case htons(ETH_P_IP):
83 return ntohl(ip_hdr(skb)->daddr); 83 return ntohl(ip_hdr(skb)->daddr);
84 case __constant_htons(ETH_P_IPV6): 84 case htons(ETH_P_IPV6):
85 return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); 85 return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]);
86 default: 86 default:
87 return addr_fold(skb->dst) ^ (__force u16)skb->protocol; 87 return addr_fold(skb->dst) ^ (__force u16)skb->protocol;
@@ -91,9 +91,9 @@ static u32 flow_get_dst(const struct sk_buff *skb)
91static u32 flow_get_proto(const struct sk_buff *skb) 91static u32 flow_get_proto(const struct sk_buff *skb)
92{ 92{
93 switch (skb->protocol) { 93 switch (skb->protocol) {
94 case __constant_htons(ETH_P_IP): 94 case htons(ETH_P_IP):
95 return ip_hdr(skb)->protocol; 95 return ip_hdr(skb)->protocol;
96 case __constant_htons(ETH_P_IPV6): 96 case htons(ETH_P_IPV6):
97 return ipv6_hdr(skb)->nexthdr; 97 return ipv6_hdr(skb)->nexthdr;
98 default: 98 default:
99 return 0; 99 return 0;
@@ -120,7 +120,7 @@ static u32 flow_get_proto_src(const struct sk_buff *skb)
120 u32 res = 0; 120 u32 res = 0;
121 121
122 switch (skb->protocol) { 122 switch (skb->protocol) {
123 case __constant_htons(ETH_P_IP): { 123 case htons(ETH_P_IP): {
124 struct iphdr *iph = ip_hdr(skb); 124 struct iphdr *iph = ip_hdr(skb);
125 125
126 if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && 126 if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
@@ -128,7 +128,7 @@ static u32 flow_get_proto_src(const struct sk_buff *skb)
128 res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); 128 res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
129 break; 129 break;
130 } 130 }
131 case __constant_htons(ETH_P_IPV6): { 131 case htons(ETH_P_IPV6): {
132 struct ipv6hdr *iph = ipv6_hdr(skb); 132 struct ipv6hdr *iph = ipv6_hdr(skb);
133 133
134 if (has_ports(iph->nexthdr)) 134 if (has_ports(iph->nexthdr))
@@ -147,7 +147,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb)
147 u32 res = 0; 147 u32 res = 0;
148 148
149 switch (skb->protocol) { 149 switch (skb->protocol) {
150 case __constant_htons(ETH_P_IP): { 150 case htons(ETH_P_IP): {
151 struct iphdr *iph = ip_hdr(skb); 151 struct iphdr *iph = ip_hdr(skb);
152 152
153 if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && 153 if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
@@ -155,7 +155,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb)
155 res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); 155 res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
156 break; 156 break;
157 } 157 }
158 case __constant_htons(ETH_P_IPV6): { 158 case htons(ETH_P_IPV6): {
159 struct ipv6hdr *iph = ipv6_hdr(skb); 159 struct ipv6hdr *iph = ipv6_hdr(skb);
160 160
161 if (has_ports(iph->nexthdr)) 161 if (has_ports(iph->nexthdr))
@@ -213,9 +213,9 @@ static u32 flow_get_nfct(const struct sk_buff *skb)
213static u32 flow_get_nfct_src(const struct sk_buff *skb) 213static u32 flow_get_nfct_src(const struct sk_buff *skb)
214{ 214{
215 switch (skb->protocol) { 215 switch (skb->protocol) {
216 case __constant_htons(ETH_P_IP): 216 case htons(ETH_P_IP):
217 return ntohl(CTTUPLE(skb, src.u3.ip)); 217 return ntohl(CTTUPLE(skb, src.u3.ip));
218 case __constant_htons(ETH_P_IPV6): 218 case htons(ETH_P_IPV6):
219 return ntohl(CTTUPLE(skb, src.u3.ip6[3])); 219 return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
220 } 220 }
221fallback: 221fallback:
@@ -225,9 +225,9 @@ fallback:
225static u32 flow_get_nfct_dst(const struct sk_buff *skb) 225static u32 flow_get_nfct_dst(const struct sk_buff *skb)
226{ 226{
227 switch (skb->protocol) { 227 switch (skb->protocol) {
228 case __constant_htons(ETH_P_IP): 228 case htons(ETH_P_IP):
229 return ntohl(CTTUPLE(skb, dst.u3.ip)); 229 return ntohl(CTTUPLE(skb, dst.u3.ip));
230 case __constant_htons(ETH_P_IPV6): 230 case htons(ETH_P_IPV6):
231 return ntohl(CTTUPLE(skb, dst.u3.ip6[3])); 231 return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
232 } 232 }
233fallback: 233fallback:
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 481260a4f10f..e3d8455eebc2 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -75,7 +75,7 @@ static __inline__ int route4_fastmap_hash(u32 id, int iif)
75static inline 75static inline
76void route4_reset_fastmap(struct Qdisc *q, struct route4_head *head, u32 id) 76void route4_reset_fastmap(struct Qdisc *q, struct route4_head *head, u32 id)
77{ 77{
78 spinlock_t *root_lock = qdisc_root_lock(q); 78 spinlock_t *root_lock = qdisc_root_sleeping_lock(q);
79 79
80 spin_lock_bh(root_lock); 80 spin_lock_bh(root_lock);
81 memset(head->fastmap, 0, sizeof(head->fastmap)); 81 memset(head->fastmap, 0, sizeof(head->fastmap));
diff --git a/net/sched/em_cmp.c b/net/sched/em_cmp.c
index cc49c932641d..bc450397487a 100644
--- a/net/sched/em_cmp.c
+++ b/net/sched/em_cmp.c
@@ -14,6 +14,7 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/skbuff.h> 15#include <linux/skbuff.h>
16#include <linux/tc_ematch/tc_em_cmp.h> 16#include <linux/tc_ematch/tc_em_cmp.h>
17#include <asm/unaligned.h>
17#include <net/pkt_cls.h> 18#include <net/pkt_cls.h>
18 19
19static inline int cmp_needs_transformation(struct tcf_em_cmp *cmp) 20static inline int cmp_needs_transformation(struct tcf_em_cmp *cmp)
@@ -37,8 +38,7 @@ static int em_cmp_match(struct sk_buff *skb, struct tcf_ematch *em,
37 break; 38 break;
38 39
39 case TCF_EM_ALIGN_U16: 40 case TCF_EM_ALIGN_U16:
40 val = *ptr << 8; 41 val = get_unaligned_be16(ptr);
41 val |= *(ptr+1);
42 42
43 if (cmp_needs_transformation(cmp)) 43 if (cmp_needs_transformation(cmp))
44 val = be16_to_cpu(val); 44 val = be16_to_cpu(val);
@@ -47,10 +47,7 @@ static int em_cmp_match(struct sk_buff *skb, struct tcf_ematch *em,
47 case TCF_EM_ALIGN_U32: 47 case TCF_EM_ALIGN_U32:
48 /* Worth checking boundries? The branching seems 48 /* Worth checking boundries? The branching seems
49 * to get worse. Visit again. */ 49 * to get worse. Visit again. */
50 val = *ptr << 24; 50 val = get_unaligned_be32(ptr);
51 val |= *(ptr+1) << 16;
52 val |= *(ptr+2) << 8;
53 val |= *(ptr+3);
54 51
55 if (cmp_needs_transformation(cmp)) 52 if (cmp_needs_transformation(cmp))
56 val = be32_to_cpu(val); 53 val = be32_to_cpu(val);
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 506b709510b6..1122c952aa99 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1169,8 +1169,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
1169 if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) 1169 if (q->stab && qdisc_dump_stab(skb, q->stab) < 0)
1170 goto nla_put_failure; 1170 goto nla_put_failure;
1171 1171
1172 if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, 1172 if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1173 TCA_XSTATS, qdisc_root_lock(q), &d) < 0) 1173 qdisc_root_sleeping_lock(q), &d) < 0)
1174 goto nla_put_failure; 1174 goto nla_put_failure;
1175 1175
1176 if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) 1176 if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
@@ -1461,8 +1461,8 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
1461 if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) 1461 if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0)
1462 goto nla_put_failure; 1462 goto nla_put_failure;
1463 1463
1464 if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, 1464 if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS,
1465 TCA_XSTATS, qdisc_root_lock(q), &d) < 0) 1465 qdisc_root_sleeping_lock(q), &d) < 0)
1466 goto nla_put_failure; 1466 goto nla_put_failure;
1467 1467
1468 if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) 1468 if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0)
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 9b720adedead..8b06fa900482 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1754,7 +1754,7 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg)
1754 1754
1755 if (--cl->refcnt == 0) { 1755 if (--cl->refcnt == 0) {
1756#ifdef CONFIG_NET_CLS_ACT 1756#ifdef CONFIG_NET_CLS_ACT
1757 spinlock_t *root_lock = qdisc_root_lock(sch); 1757 spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
1758 struct cbq_sched_data *q = qdisc_priv(sch); 1758 struct cbq_sched_data *q = qdisc_priv(sch);
1759 1759
1760 spin_lock_bh(root_lock); 1760 spin_lock_bh(root_lock);
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index edd1298f85f6..ba43aab3a851 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -202,7 +202,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
202 202
203 if (p->set_tc_index) { 203 if (p->set_tc_index) {
204 switch (skb->protocol) { 204 switch (skb->protocol) {
205 case __constant_htons(ETH_P_IP): 205 case htons(ETH_P_IP):
206 if (skb_cow_head(skb, sizeof(struct iphdr))) 206 if (skb_cow_head(skb, sizeof(struct iphdr)))
207 goto drop; 207 goto drop;
208 208
@@ -210,7 +210,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
210 & ~INET_ECN_MASK; 210 & ~INET_ECN_MASK;
211 break; 211 break;
212 212
213 case __constant_htons(ETH_P_IPV6): 213 case htons(ETH_P_IPV6):
214 if (skb_cow_head(skb, sizeof(struct ipv6hdr))) 214 if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
215 goto drop; 215 goto drop;
216 216
@@ -289,11 +289,11 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
289 pr_debug("index %d->%d\n", skb->tc_index, index); 289 pr_debug("index %d->%d\n", skb->tc_index, index);
290 290
291 switch (skb->protocol) { 291 switch (skb->protocol) {
292 case __constant_htons(ETH_P_IP): 292 case htons(ETH_P_IP):
293 ipv4_change_dsfield(ip_hdr(skb), p->mask[index], 293 ipv4_change_dsfield(ip_hdr(skb), p->mask[index],
294 p->value[index]); 294 p->value[index]);
295 break; 295 break;
296 case __constant_htons(ETH_P_IPV6): 296 case htons(ETH_P_IPV6):
297 ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index], 297 ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index],
298 p->value[index]); 298 p->value[index]);
299 break; 299 break;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 9634091ee2f0..5e7e0bd38fe8 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -44,10 +44,7 @@ static inline int qdisc_qlen(struct Qdisc *q)
44 44
45static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) 45static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
46{ 46{
47 if (unlikely(skb->next)) 47 __skb_queue_head(&q->requeue, skb);
48 q->gso_skb = skb;
49 else
50 q->ops->requeue(skb, q);
51 48
52 __netif_schedule(q); 49 __netif_schedule(q);
53 return 0; 50 return 0;
@@ -55,12 +52,21 @@ static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
55 52
56static inline struct sk_buff *dequeue_skb(struct Qdisc *q) 53static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
57{ 54{
58 struct sk_buff *skb; 55 struct sk_buff *skb = skb_peek(&q->requeue);
56
57 if (unlikely(skb)) {
58 struct net_device *dev = qdisc_dev(q);
59 struct netdev_queue *txq;
59 60
60 if ((skb = q->gso_skb)) 61 /* check the reason of requeuing without tx lock first */
61 q->gso_skb = NULL; 62 txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
62 else 63 if (!netif_tx_queue_stopped(txq) && !netif_tx_queue_frozen(txq))
64 __skb_unlink(skb, &q->requeue);
65 else
66 skb = NULL;
67 } else {
63 skb = q->dequeue(q); 68 skb = q->dequeue(q);
69 }
64 70
65 return skb; 71 return skb;
66} 72}
@@ -215,10 +221,9 @@ static void dev_watchdog(unsigned long arg)
215 time_after(jiffies, (dev->trans_start + 221 time_after(jiffies, (dev->trans_start +
216 dev->watchdog_timeo))) { 222 dev->watchdog_timeo))) {
217 char drivername[64]; 223 char drivername[64];
218 printk(KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n", 224 WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
219 dev->name, netdev_drivername(dev, drivername, 64)); 225 dev->name, netdev_drivername(dev, drivername, 64));
220 dev->tx_timeout(dev); 226 dev->tx_timeout(dev);
221 WARN_ON_ONCE(1);
222 } 227 }
223 if (!mod_timer(&dev->watchdog_timer, 228 if (!mod_timer(&dev->watchdog_timer,
224 round_jiffies(jiffies + 229 round_jiffies(jiffies +
@@ -328,6 +333,7 @@ struct Qdisc noop_qdisc = {
328 .flags = TCQ_F_BUILTIN, 333 .flags = TCQ_F_BUILTIN,
329 .ops = &noop_qdisc_ops, 334 .ops = &noop_qdisc_ops,
330 .list = LIST_HEAD_INIT(noop_qdisc.list), 335 .list = LIST_HEAD_INIT(noop_qdisc.list),
336 .requeue.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
331 .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), 337 .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock),
332 .dev_queue = &noop_netdev_queue, 338 .dev_queue = &noop_netdev_queue,
333}; 339};
@@ -353,6 +359,7 @@ static struct Qdisc noqueue_qdisc = {
353 .flags = TCQ_F_BUILTIN, 359 .flags = TCQ_F_BUILTIN,
354 .ops = &noqueue_qdisc_ops, 360 .ops = &noqueue_qdisc_ops,
355 .list = LIST_HEAD_INIT(noqueue_qdisc.list), 361 .list = LIST_HEAD_INIT(noqueue_qdisc.list),
362 .requeue.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock),
356 .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), 363 .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock),
357 .dev_queue = &noqueue_netdev_queue, 364 .dev_queue = &noqueue_netdev_queue,
358}; 365};
@@ -473,6 +480,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
473 sch->padded = (char *) sch - (char *) p; 480 sch->padded = (char *) sch - (char *) p;
474 481
475 INIT_LIST_HEAD(&sch->list); 482 INIT_LIST_HEAD(&sch->list);
483 skb_queue_head_init(&sch->requeue);
476 skb_queue_head_init(&sch->q); 484 skb_queue_head_init(&sch->q);
477 sch->ops = ops; 485 sch->ops = ops;
478 sch->enqueue = ops->enqueue; 486 sch->enqueue = ops->enqueue;
@@ -540,7 +548,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
540 module_put(ops->owner); 548 module_put(ops->owner);
541 dev_put(qdisc_dev(qdisc)); 549 dev_put(qdisc_dev(qdisc));
542 550
543 kfree_skb(qdisc->gso_skb); 551 __skb_queue_purge(&qdisc->requeue);
544 552
545 kfree((char *) qdisc - qdisc->padded); 553 kfree((char *) qdisc - qdisc->padded);
546} 554}
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 97d4761cc31e..d14f02056ae6 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1043,7 +1043,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
1043 1043
1044static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) 1044static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
1045{ 1045{
1046 spinlock_t *root_lock = qdisc_root_lock(sch); 1046 spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
1047 struct htb_sched *q = qdisc_priv(sch); 1047 struct htb_sched *q = qdisc_priv(sch);
1048 struct nlattr *nest; 1048 struct nlattr *nest;
1049 struct tc_htb_glob gopt; 1049 struct tc_htb_glob gopt;
@@ -1075,7 +1075,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
1075 struct sk_buff *skb, struct tcmsg *tcm) 1075 struct sk_buff *skb, struct tcmsg *tcm)
1076{ 1076{
1077 struct htb_class *cl = (struct htb_class *)arg; 1077 struct htb_class *cl = (struct htb_class *)arg;
1078 spinlock_t *root_lock = qdisc_root_lock(sch); 1078 spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
1079 struct nlattr *nest; 1079 struct nlattr *nest;
1080 struct tc_htb_opt opt; 1080 struct tc_htb_opt opt;
1081 1081
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
new file mode 100644
index 000000000000..915f3149dde2
--- /dev/null
+++ b/net/sched/sch_multiq.c
@@ -0,0 +1,477 @@
1/*
2 * Copyright (c) 2008, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Author: Alexander Duyck <alexander.h.duyck@intel.com>
18 */
19
20#include <linux/module.h>
21#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/string.h>
24#include <linux/errno.h>
25#include <linux/skbuff.h>
26#include <net/netlink.h>
27#include <net/pkt_sched.h>
28
29
30struct multiq_sched_data {
31 u16 bands;
32 u16 max_bands;
33 u16 curband;
34 struct tcf_proto *filter_list;
35 struct Qdisc **queues;
36};
37
38
39static struct Qdisc *
40multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
41{
42 struct multiq_sched_data *q = qdisc_priv(sch);
43 u32 band;
44 struct tcf_result res;
45 int err;
46
47 *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
48 err = tc_classify(skb, q->filter_list, &res);
49#ifdef CONFIG_NET_CLS_ACT
50 switch (err) {
51 case TC_ACT_STOLEN:
52 case TC_ACT_QUEUED:
53 *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
54 case TC_ACT_SHOT:
55 return NULL;
56 }
57#endif
58 band = skb_get_queue_mapping(skb);
59
60 if (band >= q->bands)
61 return q->queues[0];
62
63 return q->queues[band];
64}
65
66static int
67multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
68{
69 struct Qdisc *qdisc;
70 int ret;
71
72 qdisc = multiq_classify(skb, sch, &ret);
73#ifdef CONFIG_NET_CLS_ACT
74 if (qdisc == NULL) {
75
76 if (ret & __NET_XMIT_BYPASS)
77 sch->qstats.drops++;
78 kfree_skb(skb);
79 return ret;
80 }
81#endif
82
83 ret = qdisc_enqueue(skb, qdisc);
84 if (ret == NET_XMIT_SUCCESS) {
85 sch->bstats.bytes += qdisc_pkt_len(skb);
86 sch->bstats.packets++;
87 sch->q.qlen++;
88 return NET_XMIT_SUCCESS;
89 }
90 if (net_xmit_drop_count(ret))
91 sch->qstats.drops++;
92 return ret;
93}
94
95
96static int
97multiq_requeue(struct sk_buff *skb, struct Qdisc *sch)
98{
99 struct Qdisc *qdisc;
100 struct multiq_sched_data *q = qdisc_priv(sch);
101 int ret;
102
103 qdisc = multiq_classify(skb, sch, &ret);
104#ifdef CONFIG_NET_CLS_ACT
105 if (qdisc == NULL) {
106 if (ret & __NET_XMIT_BYPASS)
107 sch->qstats.drops++;
108 kfree_skb(skb);
109 return ret;
110 }
111#endif
112
113 ret = qdisc->ops->requeue(skb, qdisc);
114 if (ret == NET_XMIT_SUCCESS) {
115 sch->q.qlen++;
116 sch->qstats.requeues++;
117 if (q->curband)
118 q->curband--;
119 else
120 q->curband = q->bands - 1;
121 return NET_XMIT_SUCCESS;
122 }
123 if (net_xmit_drop_count(ret))
124 sch->qstats.drops++;
125 return ret;
126}
127
128
129static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
130{
131 struct multiq_sched_data *q = qdisc_priv(sch);
132 struct Qdisc *qdisc;
133 struct sk_buff *skb;
134 int band;
135
136 for (band = 0; band < q->bands; band++) {
137 /* cycle through bands to ensure fairness */
138 q->curband++;
139 if (q->curband >= q->bands)
140 q->curband = 0;
141
142 /* Check that target subqueue is available before
143 * pulling an skb to avoid excessive requeues
144 */
145 if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) {
146 qdisc = q->queues[q->curband];
147 skb = qdisc->dequeue(qdisc);
148 if (skb) {
149 sch->q.qlen--;
150 return skb;
151 }
152 }
153 }
154 return NULL;
155
156}
157
158static unsigned int multiq_drop(struct Qdisc *sch)
159{
160 struct multiq_sched_data *q = qdisc_priv(sch);
161 int band;
162 unsigned int len;
163 struct Qdisc *qdisc;
164
165 for (band = q->bands-1; band >= 0; band--) {
166 qdisc = q->queues[band];
167 if (qdisc->ops->drop) {
168 len = qdisc->ops->drop(qdisc);
169 if (len != 0) {
170 sch->q.qlen--;
171 return len;
172 }
173 }
174 }
175 return 0;
176}
177
178
179static void
180multiq_reset(struct Qdisc *sch)
181{
182 u16 band;
183 struct multiq_sched_data *q = qdisc_priv(sch);
184
185 for (band = 0; band < q->bands; band++)
186 qdisc_reset(q->queues[band]);
187 sch->q.qlen = 0;
188 q->curband = 0;
189}
190
191static void
192multiq_destroy(struct Qdisc *sch)
193{
194 int band;
195 struct multiq_sched_data *q = qdisc_priv(sch);
196
197 tcf_destroy_chain(&q->filter_list);
198 for (band = 0; band < q->bands; band++)
199 qdisc_destroy(q->queues[band]);
200
201 kfree(q->queues);
202}
203
204static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
205{
206 struct multiq_sched_data *q = qdisc_priv(sch);
207 struct tc_multiq_qopt *qopt;
208 int i;
209
210 if (!netif_is_multiqueue(qdisc_dev(sch)))
211 return -EINVAL;
212 if (nla_len(opt) < sizeof(*qopt))
213 return -EINVAL;
214
215 qopt = nla_data(opt);
216
217 qopt->bands = qdisc_dev(sch)->real_num_tx_queues;
218
219 sch_tree_lock(sch);
220 q->bands = qopt->bands;
221 for (i = q->bands; i < q->max_bands; i++) {
222 if (q->queues[i] != &noop_qdisc) {
223 struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc);
224 qdisc_tree_decrease_qlen(child, child->q.qlen);
225 qdisc_destroy(child);
226 }
227 }
228
229 sch_tree_unlock(sch);
230
231 for (i = 0; i < q->bands; i++) {
232 if (q->queues[i] == &noop_qdisc) {
233 struct Qdisc *child;
234 child = qdisc_create_dflt(qdisc_dev(sch),
235 sch->dev_queue,
236 &pfifo_qdisc_ops,
237 TC_H_MAKE(sch->handle,
238 i + 1));
239 if (child) {
240 sch_tree_lock(sch);
241 child = xchg(&q->queues[i], child);
242
243 if (child != &noop_qdisc) {
244 qdisc_tree_decrease_qlen(child,
245 child->q.qlen);
246 qdisc_destroy(child);
247 }
248 sch_tree_unlock(sch);
249 }
250 }
251 }
252 return 0;
253}
254
255static int multiq_init(struct Qdisc *sch, struct nlattr *opt)
256{
257 struct multiq_sched_data *q = qdisc_priv(sch);
258 int i, err;
259
260 q->queues = NULL;
261
262 if (opt == NULL)
263 return -EINVAL;
264
265 q->max_bands = qdisc_dev(sch)->num_tx_queues;
266
267 q->queues = kcalloc(q->max_bands, sizeof(struct Qdisc *), GFP_KERNEL);
268 if (!q->queues)
269 return -ENOBUFS;
270 for (i = 0; i < q->max_bands; i++)
271 q->queues[i] = &noop_qdisc;
272
273 err = multiq_tune(sch,opt);
274
275 if (err)
276 kfree(q->queues);
277
278 return err;
279}
280
281static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb)
282{
283 struct multiq_sched_data *q = qdisc_priv(sch);
284 unsigned char *b = skb_tail_pointer(skb);
285 struct tc_multiq_qopt opt;
286
287 opt.bands = q->bands;
288 opt.max_bands = q->max_bands;
289
290 NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
291
292 return skb->len;
293
294nla_put_failure:
295 nlmsg_trim(skb, b);
296 return -1;
297}
298
299static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
300 struct Qdisc **old)
301{
302 struct multiq_sched_data *q = qdisc_priv(sch);
303 unsigned long band = arg - 1;
304
305 if (band >= q->bands)
306 return -EINVAL;
307
308 if (new == NULL)
309 new = &noop_qdisc;
310
311 sch_tree_lock(sch);
312 *old = q->queues[band];
313 q->queues[band] = new;
314 qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
315 qdisc_reset(*old);
316 sch_tree_unlock(sch);
317
318 return 0;
319}
320
321static struct Qdisc *
322multiq_leaf(struct Qdisc *sch, unsigned long arg)
323{
324 struct multiq_sched_data *q = qdisc_priv(sch);
325 unsigned long band = arg - 1;
326
327 if (band >= q->bands)
328 return NULL;
329
330 return q->queues[band];
331}
332
333static unsigned long multiq_get(struct Qdisc *sch, u32 classid)
334{
335 struct multiq_sched_data *q = qdisc_priv(sch);
336 unsigned long band = TC_H_MIN(classid);
337
338 if (band - 1 >= q->bands)
339 return 0;
340 return band;
341}
342
343static unsigned long multiq_bind(struct Qdisc *sch, unsigned long parent,
344 u32 classid)
345{
346 return multiq_get(sch, classid);
347}
348
349
350static void multiq_put(struct Qdisc *q, unsigned long cl)
351{
352 return;
353}
354
355static int multiq_change(struct Qdisc *sch, u32 handle, u32 parent,
356 struct nlattr **tca, unsigned long *arg)
357{
358 unsigned long cl = *arg;
359 struct multiq_sched_data *q = qdisc_priv(sch);
360
361 if (cl - 1 > q->bands)
362 return -ENOENT;
363 return 0;
364}
365
366static int multiq_delete(struct Qdisc *sch, unsigned long cl)
367{
368 struct multiq_sched_data *q = qdisc_priv(sch);
369 if (cl - 1 > q->bands)
370 return -ENOENT;
371 return 0;
372}
373
374
375static int multiq_dump_class(struct Qdisc *sch, unsigned long cl,
376 struct sk_buff *skb, struct tcmsg *tcm)
377{
378 struct multiq_sched_data *q = qdisc_priv(sch);
379
380 if (cl - 1 > q->bands)
381 return -ENOENT;
382 tcm->tcm_handle |= TC_H_MIN(cl);
383 if (q->queues[cl-1])
384 tcm->tcm_info = q->queues[cl-1]->handle;
385 return 0;
386}
387
388static int multiq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
389 struct gnet_dump *d)
390{
391 struct multiq_sched_data *q = qdisc_priv(sch);
392 struct Qdisc *cl_q;
393
394 cl_q = q->queues[cl - 1];
395 if (gnet_stats_copy_basic(d, &cl_q->bstats) < 0 ||
396 gnet_stats_copy_queue(d, &cl_q->qstats) < 0)
397 return -1;
398
399 return 0;
400}
401
402static void multiq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
403{
404 struct multiq_sched_data *q = qdisc_priv(sch);
405 int band;
406
407 if (arg->stop)
408 return;
409
410 for (band = 0; band < q->bands; band++) {
411 if (arg->count < arg->skip) {
412 arg->count++;
413 continue;
414 }
415 if (arg->fn(sch, band+1, arg) < 0) {
416 arg->stop = 1;
417 break;
418 }
419 arg->count++;
420 }
421}
422
423static struct tcf_proto **multiq_find_tcf(struct Qdisc *sch, unsigned long cl)
424{
425 struct multiq_sched_data *q = qdisc_priv(sch);
426
427 if (cl)
428 return NULL;
429 return &q->filter_list;
430}
431
432static const struct Qdisc_class_ops multiq_class_ops = {
433 .graft = multiq_graft,
434 .leaf = multiq_leaf,
435 .get = multiq_get,
436 .put = multiq_put,
437 .change = multiq_change,
438 .delete = multiq_delete,
439 .walk = multiq_walk,
440 .tcf_chain = multiq_find_tcf,
441 .bind_tcf = multiq_bind,
442 .unbind_tcf = multiq_put,
443 .dump = multiq_dump_class,
444 .dump_stats = multiq_dump_class_stats,
445};
446
447static struct Qdisc_ops multiq_qdisc_ops __read_mostly = {
448 .next = NULL,
449 .cl_ops = &multiq_class_ops,
450 .id = "multiq",
451 .priv_size = sizeof(struct multiq_sched_data),
452 .enqueue = multiq_enqueue,
453 .dequeue = multiq_dequeue,
454 .requeue = multiq_requeue,
455 .drop = multiq_drop,
456 .init = multiq_init,
457 .reset = multiq_reset,
458 .destroy = multiq_destroy,
459 .change = multiq_tune,
460 .dump = multiq_dump,
461 .owner = THIS_MODULE,
462};
463
464static int __init multiq_module_init(void)
465{
466 return register_qdisc(&multiq_qdisc_ops);
467}
468
469static void __exit multiq_module_exit(void)
470{
471 unregister_qdisc(&multiq_qdisc_ops);
472}
473
474module_init(multiq_module_init)
475module_exit(multiq_module_exit)
476
477MODULE_LICENSE("GPL");
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index fb0294d0b55e..a11959908d9a 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -341,7 +341,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
341 for (i = 0; i < n; i++) 341 for (i = 0; i < n; i++)
342 d->table[i] = data[i]; 342 d->table[i] = data[i];
343 343
344 root_lock = qdisc_root_lock(sch); 344 root_lock = qdisc_root_sleeping_lock(sch);
345 345
346 spin_lock_bh(root_lock); 346 spin_lock_bh(root_lock);
347 d = xchg(&q->delay_dist, d); 347 d = xchg(&q->delay_dist, d);
@@ -388,6 +388,20 @@ static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
388 [TCA_NETEM_CORRUPT] = { .len = sizeof(struct tc_netem_corrupt) }, 388 [TCA_NETEM_CORRUPT] = { .len = sizeof(struct tc_netem_corrupt) },
389}; 389};
390 390
391static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
392 const struct nla_policy *policy, int len)
393{
394 int nested_len = nla_len(nla) - NLA_ALIGN(len);
395
396 if (nested_len < 0)
397 return -EINVAL;
398 if (nested_len >= nla_attr_size(0))
399 return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len),
400 nested_len, policy);
401 memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
402 return 0;
403}
404
391/* Parse netlink message to set options */ 405/* Parse netlink message to set options */
392static int netem_change(struct Qdisc *sch, struct nlattr *opt) 406static int netem_change(struct Qdisc *sch, struct nlattr *opt)
393{ 407{
@@ -399,8 +413,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
399 if (opt == NULL) 413 if (opt == NULL)
400 return -EINVAL; 414 return -EINVAL;
401 415
402 ret = nla_parse_nested_compat(tb, TCA_NETEM_MAX, opt, netem_policy, 416 qopt = nla_data(opt);
403 qopt, sizeof(*qopt)); 417 ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt));
404 if (ret < 0) 418 if (ret < 0)
405 return ret; 419 return ret;
406 420
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index a6697c686c7f..504a78cdb718 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -254,16 +254,12 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
254{ 254{
255 struct prio_sched_data *q = qdisc_priv(sch); 255 struct prio_sched_data *q = qdisc_priv(sch);
256 unsigned char *b = skb_tail_pointer(skb); 256 unsigned char *b = skb_tail_pointer(skb);
257 struct nlattr *nest;
258 struct tc_prio_qopt opt; 257 struct tc_prio_qopt opt;
259 258
260 opt.bands = q->bands; 259 opt.bands = q->bands;
261 memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1); 260 memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1);
262 261
263 nest = nla_nest_compat_start(skb, TCA_OPTIONS, sizeof(opt), &opt); 262 NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
264 if (nest == NULL)
265 goto nla_put_failure;
266 nla_nest_compat_end(skb, nest);
267 263
268 return skb->len; 264 return skb->len;
269 265
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 6e041d10dbdb..fe1508ef0d3d 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -119,7 +119,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
119 u32 h, h2; 119 u32 h, h2;
120 120
121 switch (skb->protocol) { 121 switch (skb->protocol) {
122 case __constant_htons(ETH_P_IP): 122 case htons(ETH_P_IP):
123 { 123 {
124 const struct iphdr *iph = ip_hdr(skb); 124 const struct iphdr *iph = ip_hdr(skb);
125 h = iph->daddr; 125 h = iph->daddr;
@@ -134,7 +134,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
134 h2 ^= *(((u32*)iph) + iph->ihl); 134 h2 ^= *(((u32*)iph) + iph->ihl);
135 break; 135 break;
136 } 136 }
137 case __constant_htons(ETH_P_IPV6): 137 case htons(ETH_P_IPV6):
138 { 138 {
139 struct ipv6hdr *iph = ipv6_hdr(skb); 139 struct ipv6hdr *iph = ipv6_hdr(skb);
140 h = iph->daddr.s6_addr32[3]; 140 h = iph->daddr.s6_addr32[3];
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 2c35c678563b..d35ef059abb1 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -161,7 +161,7 @@ teql_destroy(struct Qdisc* sch)
161 txq = netdev_get_tx_queue(master->dev, 0); 161 txq = netdev_get_tx_queue(master->dev, 0);
162 master->slaves = NULL; 162 master->slaves = NULL;
163 163
164 root_lock = qdisc_root_lock(txq->qdisc); 164 root_lock = qdisc_root_sleeping_lock(txq->qdisc);
165 spin_lock_bh(root_lock); 165 spin_lock_bh(root_lock);
166 qdisc_reset(txq->qdisc); 166 qdisc_reset(txq->qdisc);
167 spin_unlock_bh(root_lock); 167 spin_unlock_bh(root_lock);