diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 14:47:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 14:47:02 -0400 |
commit | 5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0 (patch) | |
tree | 7851ef1c93aa1aba7ef327ca4b75fd35e6d10f29 /net/sched | |
parent | 02f36038c568111ad4fc433f6fa760ff5e38fab4 (diff) | |
parent | ec37a48d1d16c30b655ac5280209edf52a6775d4 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits)
bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL.
vlan: Calling vlan_hwaccel_do_receive() is always valid.
tproxy: use the interface primary IP address as a default value for --on-ip
tproxy: added IPv6 support to the socket match
cxgb3: function namespace cleanup
tproxy: added IPv6 support to the TPROXY target
tproxy: added IPv6 socket lookup function to nf_tproxy_core
be2net: Changes to use only priority codes allowed by f/w
tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled
tproxy: added tproxy sockopt interface in the IPV6 layer
tproxy: added udp6_lib_lookup function
tproxy: added const specifiers to udp lookup functions
tproxy: split off ipv6 defragmentation to a separate module
l2tp: small cleanup
nf_nat: restrict ICMP translation for embedded header
can: mcp251x: fix generation of error frames
can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set
can-raw: add msg_flags to distinguish local traffic
9p: client code cleanup
rds: make local functions/variables static
...
Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and
drivers/net/wireless/ath/ath9k/debug.c as per David
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/Kconfig | 10 | ||||
-rw-r--r-- | net/sched/Makefile | 1 | ||||
-rw-r--r-- | net/sched/act_csum.c | 595 | ||||
-rw-r--r-- | net/sched/act_ipt.c | 14 | ||||
-rw-r--r-- | net/sched/cls_flow.c | 74 | ||||
-rw-r--r-- | net/sched/em_meta.c | 6 | ||||
-rw-r--r-- | net/sched/sch_api.c | 44 | ||||
-rw-r--r-- | net/sched/sch_atm.c | 5 | ||||
-rw-r--r-- | net/sched/sch_cbq.c | 12 | ||||
-rw-r--r-- | net/sched/sch_drr.c | 4 | ||||
-rw-r--r-- | net/sched/sch_dsmark.c | 6 | ||||
-rw-r--r-- | net/sched/sch_fifo.c | 3 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 24 | ||||
-rw-r--r-- | net/sched/sch_hfsc.c | 8 | ||||
-rw-r--r-- | net/sched/sch_htb.c | 12 | ||||
-rw-r--r-- | net/sched/sch_mq.c | 2 | ||||
-rw-r--r-- | net/sched/sch_multiq.c | 3 | ||||
-rw-r--r-- | net/sched/sch_netem.c | 3 | ||||
-rw-r--r-- | net/sched/sch_prio.c | 2 | ||||
-rw-r--r-- | net/sched/sch_sfq.c | 33 | ||||
-rw-r--r-- | net/sched/sch_teql.c | 8 |
21 files changed, 752 insertions, 117 deletions
diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 2f691fb180d1..a36270a994d7 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig | |||
@@ -518,6 +518,16 @@ config NET_ACT_SKBEDIT | |||
518 | To compile this code as a module, choose M here: the | 518 | To compile this code as a module, choose M here: the |
519 | module will be called act_skbedit. | 519 | module will be called act_skbedit. |
520 | 520 | ||
521 | config NET_ACT_CSUM | ||
522 | tristate "Checksum Updating" | ||
523 | depends on NET_CLS_ACT && INET | ||
524 | ---help--- | ||
525 | Say Y here to update some common checksum after some direct | ||
526 | packet alterations. | ||
527 | |||
528 | To compile this code as a module, choose M here: the | ||
529 | module will be called act_csum. | ||
530 | |||
521 | config NET_CLS_IND | 531 | config NET_CLS_IND |
522 | bool "Incoming device classification" | 532 | bool "Incoming device classification" |
523 | depends on NET_CLS_U32 || NET_CLS_FW | 533 | depends on NET_CLS_U32 || NET_CLS_FW |
diff --git a/net/sched/Makefile b/net/sched/Makefile index f14e71bfa58f..960f5dba6304 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_ACT_NAT) += act_nat.o | |||
15 | obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o | 15 | obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o |
16 | obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o | 16 | obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o |
17 | obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o | 17 | obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o |
18 | obj-$(CONFIG_NET_ACT_CSUM) += act_csum.o | ||
18 | obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o | 19 | obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o |
19 | obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o | 20 | obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o |
20 | obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o | 21 | obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o |
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c new file mode 100644 index 000000000000..67dc7ce9b63a --- /dev/null +++ b/net/sched/act_csum.c | |||
@@ -0,0 +1,595 @@ | |||
1 | /* | ||
2 | * Checksum updating actions | ||
3 | * | ||
4 | * Copyright (c) 2010 Gregoire Baron <baronchon@n7mm.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the Free | ||
8 | * Software Foundation; either version 2 of the License, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | |||
19 | #include <linux/netlink.h> | ||
20 | #include <net/netlink.h> | ||
21 | #include <linux/rtnetlink.h> | ||
22 | |||
23 | #include <linux/skbuff.h> | ||
24 | |||
25 | #include <net/ip.h> | ||
26 | #include <net/ipv6.h> | ||
27 | #include <net/icmp.h> | ||
28 | #include <linux/icmpv6.h> | ||
29 | #include <linux/igmp.h> | ||
30 | #include <net/tcp.h> | ||
31 | #include <net/udp.h> | ||
32 | #include <net/ip6_checksum.h> | ||
33 | |||
34 | #include <net/act_api.h> | ||
35 | |||
36 | #include <linux/tc_act/tc_csum.h> | ||
37 | #include <net/tc_act/tc_csum.h> | ||
38 | |||
39 | #define CSUM_TAB_MASK 15 | ||
40 | static struct tcf_common *tcf_csum_ht[CSUM_TAB_MASK + 1]; | ||
41 | static u32 csum_idx_gen; | ||
42 | static DEFINE_RWLOCK(csum_lock); | ||
43 | |||
44 | static struct tcf_hashinfo csum_hash_info = { | ||
45 | .htab = tcf_csum_ht, | ||
46 | .hmask = CSUM_TAB_MASK, | ||
47 | .lock = &csum_lock, | ||
48 | }; | ||
49 | |||
50 | static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = { | ||
51 | [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), }, | ||
52 | }; | ||
53 | |||
54 | static int tcf_csum_init(struct nlattr *nla, struct nlattr *est, | ||
55 | struct tc_action *a, int ovr, int bind) | ||
56 | { | ||
57 | struct nlattr *tb[TCA_CSUM_MAX + 1]; | ||
58 | struct tc_csum *parm; | ||
59 | struct tcf_common *pc; | ||
60 | struct tcf_csum *p; | ||
61 | int ret = 0, err; | ||
62 | |||
63 | if (nla == NULL) | ||
64 | return -EINVAL; | ||
65 | |||
66 | err = nla_parse_nested(tb, TCA_CSUM_MAX, nla,csum_policy); | ||
67 | if (err < 0) | ||
68 | return err; | ||
69 | |||
70 | if (tb[TCA_CSUM_PARMS] == NULL) | ||
71 | return -EINVAL; | ||
72 | parm = nla_data(tb[TCA_CSUM_PARMS]); | ||
73 | |||
74 | pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info); | ||
75 | if (!pc) { | ||
76 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, | ||
77 | &csum_idx_gen, &csum_hash_info); | ||
78 | if (IS_ERR(pc)) | ||
79 | return PTR_ERR(pc); | ||
80 | p = to_tcf_csum(pc); | ||
81 | ret = ACT_P_CREATED; | ||
82 | } else { | ||
83 | p = to_tcf_csum(pc); | ||
84 | if (!ovr) { | ||
85 | tcf_hash_release(pc, bind, &csum_hash_info); | ||
86 | return -EEXIST; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | spin_lock_bh(&p->tcf_lock); | ||
91 | p->tcf_action = parm->action; | ||
92 | p->update_flags = parm->update_flags; | ||
93 | spin_unlock_bh(&p->tcf_lock); | ||
94 | |||
95 | if (ret == ACT_P_CREATED) | ||
96 | tcf_hash_insert(pc, &csum_hash_info); | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | static int tcf_csum_cleanup(struct tc_action *a, int bind) | ||
102 | { | ||
103 | struct tcf_csum *p = a->priv; | ||
104 | return tcf_hash_release(&p->common, bind, &csum_hash_info); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * tcf_csum_skb_nextlayer - Get next layer pointer | ||
109 | * @skb: sk_buff to use | ||
110 | * @ihl: previous summed headers length | ||
111 | * @ipl: complete packet length | ||
112 | * @jhl: next header length | ||
113 | * | ||
114 | * Check the expected next layer availability in the specified sk_buff. | ||
115 | * Return the next layer pointer if pass, NULL otherwise. | ||
116 | */ | ||
117 | static void *tcf_csum_skb_nextlayer(struct sk_buff *skb, | ||
118 | unsigned int ihl, unsigned int ipl, | ||
119 | unsigned int jhl) | ||
120 | { | ||
121 | int ntkoff = skb_network_offset(skb); | ||
122 | int hl = ihl + jhl; | ||
123 | |||
124 | if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) || | ||
125 | (skb_cloned(skb) && | ||
126 | !skb_clone_writable(skb, hl + ntkoff) && | ||
127 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | ||
128 | return NULL; | ||
129 | else | ||
130 | return (void *)(skb_network_header(skb) + ihl); | ||
131 | } | ||
132 | |||
133 | static int tcf_csum_ipv4_icmp(struct sk_buff *skb, | ||
134 | unsigned int ihl, unsigned int ipl) | ||
135 | { | ||
136 | struct icmphdr *icmph; | ||
137 | |||
138 | icmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmph)); | ||
139 | if (icmph == NULL) | ||
140 | return 0; | ||
141 | |||
142 | icmph->checksum = 0; | ||
143 | skb->csum = csum_partial(icmph, ipl - ihl, 0); | ||
144 | icmph->checksum = csum_fold(skb->csum); | ||
145 | |||
146 | skb->ip_summed = CHECKSUM_NONE; | ||
147 | |||
148 | return 1; | ||
149 | } | ||
150 | |||
151 | static int tcf_csum_ipv4_igmp(struct sk_buff *skb, | ||
152 | unsigned int ihl, unsigned int ipl) | ||
153 | { | ||
154 | struct igmphdr *igmph; | ||
155 | |||
156 | igmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*igmph)); | ||
157 | if (igmph == NULL) | ||
158 | return 0; | ||
159 | |||
160 | igmph->csum = 0; | ||
161 | skb->csum = csum_partial(igmph, ipl - ihl, 0); | ||
162 | igmph->csum = csum_fold(skb->csum); | ||
163 | |||
164 | skb->ip_summed = CHECKSUM_NONE; | ||
165 | |||
166 | return 1; | ||
167 | } | ||
168 | |||
169 | static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h, | ||
170 | unsigned int ihl, unsigned int ipl) | ||
171 | { | ||
172 | struct icmp6hdr *icmp6h; | ||
173 | |||
174 | icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h)); | ||
175 | if (icmp6h == NULL) | ||
176 | return 0; | ||
177 | |||
178 | icmp6h->icmp6_cksum = 0; | ||
179 | skb->csum = csum_partial(icmp6h, ipl - ihl, 0); | ||
180 | icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, | ||
181 | ipl - ihl, IPPROTO_ICMPV6, | ||
182 | skb->csum); | ||
183 | |||
184 | skb->ip_summed = CHECKSUM_NONE; | ||
185 | |||
186 | return 1; | ||
187 | } | ||
188 | |||
189 | static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph, | ||
190 | unsigned int ihl, unsigned int ipl) | ||
191 | { | ||
192 | struct tcphdr *tcph; | ||
193 | |||
194 | tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); | ||
195 | if (tcph == NULL) | ||
196 | return 0; | ||
197 | |||
198 | tcph->check = 0; | ||
199 | skb->csum = csum_partial(tcph, ipl - ihl, 0); | ||
200 | tcph->check = tcp_v4_check(ipl - ihl, | ||
201 | iph->saddr, iph->daddr, skb->csum); | ||
202 | |||
203 | skb->ip_summed = CHECKSUM_NONE; | ||
204 | |||
205 | return 1; | ||
206 | } | ||
207 | |||
208 | static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h, | ||
209 | unsigned int ihl, unsigned int ipl) | ||
210 | { | ||
211 | struct tcphdr *tcph; | ||
212 | |||
213 | tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); | ||
214 | if (tcph == NULL) | ||
215 | return 0; | ||
216 | |||
217 | tcph->check = 0; | ||
218 | skb->csum = csum_partial(tcph, ipl - ihl, 0); | ||
219 | tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, | ||
220 | ipl - ihl, IPPROTO_TCP, | ||
221 | skb->csum); | ||
222 | |||
223 | skb->ip_summed = CHECKSUM_NONE; | ||
224 | |||
225 | return 1; | ||
226 | } | ||
227 | |||
228 | static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph, | ||
229 | unsigned int ihl, unsigned int ipl, int udplite) | ||
230 | { | ||
231 | struct udphdr *udph; | ||
232 | u16 ul; | ||
233 | |||
234 | /* | ||
235 | * Support both UDP and UDPLITE checksum algorithms, Don't use | ||
236 | * udph->len to get the real length without any protocol check, | ||
237 | * UDPLITE uses udph->len for another thing, | ||
238 | * Use iph->tot_len, or just ipl. | ||
239 | */ | ||
240 | |||
241 | udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph)); | ||
242 | if (udph == NULL) | ||
243 | return 0; | ||
244 | |||
245 | ul = ntohs(udph->len); | ||
246 | |||
247 | if (udplite || udph->check) { | ||
248 | |||
249 | udph->check = 0; | ||
250 | |||
251 | if (udplite) { | ||
252 | if (ul == 0) | ||
253 | skb->csum = csum_partial(udph, ipl - ihl, 0); | ||
254 | else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl)) | ||
255 | skb->csum = csum_partial(udph, ul, 0); | ||
256 | else | ||
257 | goto ignore_obscure_skb; | ||
258 | } else { | ||
259 | if (ul != ipl - ihl) | ||
260 | goto ignore_obscure_skb; | ||
261 | |||
262 | skb->csum = csum_partial(udph, ul, 0); | ||
263 | } | ||
264 | |||
265 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
266 | ul, iph->protocol, | ||
267 | skb->csum); | ||
268 | |||
269 | if (!udph->check) | ||
270 | udph->check = CSUM_MANGLED_0; | ||
271 | } | ||
272 | |||
273 | skb->ip_summed = CHECKSUM_NONE; | ||
274 | |||
275 | ignore_obscure_skb: | ||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h, | ||
280 | unsigned int ihl, unsigned int ipl, int udplite) | ||
281 | { | ||
282 | struct udphdr *udph; | ||
283 | u16 ul; | ||
284 | |||
285 | /* | ||
286 | * Support both UDP and UDPLITE checksum algorithms, Don't use | ||
287 | * udph->len to get the real length without any protocol check, | ||
288 | * UDPLITE uses udph->len for another thing, | ||
289 | * Use ip6h->payload_len + sizeof(*ip6h) ... , or just ipl. | ||
290 | */ | ||
291 | |||
292 | udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph)); | ||
293 | if (udph == NULL) | ||
294 | return 0; | ||
295 | |||
296 | ul = ntohs(udph->len); | ||
297 | |||
298 | udph->check = 0; | ||
299 | |||
300 | if (udplite) { | ||
301 | if (ul == 0) | ||
302 | skb->csum = csum_partial(udph, ipl - ihl, 0); | ||
303 | |||
304 | else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl)) | ||
305 | skb->csum = csum_partial(udph, ul, 0); | ||
306 | |||
307 | else | ||
308 | goto ignore_obscure_skb; | ||
309 | } else { | ||
310 | if (ul != ipl - ihl) | ||
311 | goto ignore_obscure_skb; | ||
312 | |||
313 | skb->csum = csum_partial(udph, ul, 0); | ||
314 | } | ||
315 | |||
316 | udph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ul, | ||
317 | udplite ? IPPROTO_UDPLITE : IPPROTO_UDP, | ||
318 | skb->csum); | ||
319 | |||
320 | if (!udph->check) | ||
321 | udph->check = CSUM_MANGLED_0; | ||
322 | |||
323 | skb->ip_summed = CHECKSUM_NONE; | ||
324 | |||
325 | ignore_obscure_skb: | ||
326 | return 1; | ||
327 | } | ||
328 | |||
329 | static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags) | ||
330 | { | ||
331 | struct iphdr *iph; | ||
332 | int ntkoff; | ||
333 | |||
334 | ntkoff = skb_network_offset(skb); | ||
335 | |||
336 | if (!pskb_may_pull(skb, sizeof(*iph) + ntkoff)) | ||
337 | goto fail; | ||
338 | |||
339 | iph = ip_hdr(skb); | ||
340 | |||
341 | switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) { | ||
342 | case IPPROTO_ICMP: | ||
343 | if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP) | ||
344 | if (!tcf_csum_ipv4_icmp(skb, iph->ihl * 4, | ||
345 | ntohs(iph->tot_len))) | ||
346 | goto fail; | ||
347 | break; | ||
348 | case IPPROTO_IGMP: | ||
349 | if (update_flags & TCA_CSUM_UPDATE_FLAG_IGMP) | ||
350 | if (!tcf_csum_ipv4_igmp(skb, iph->ihl * 4, | ||
351 | ntohs(iph->tot_len))) | ||
352 | goto fail; | ||
353 | break; | ||
354 | case IPPROTO_TCP: | ||
355 | if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP) | ||
356 | if (!tcf_csum_ipv4_tcp(skb, iph, iph->ihl * 4, | ||
357 | ntohs(iph->tot_len))) | ||
358 | goto fail; | ||
359 | break; | ||
360 | case IPPROTO_UDP: | ||
361 | if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP) | ||
362 | if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4, | ||
363 | ntohs(iph->tot_len), 0)) | ||
364 | goto fail; | ||
365 | break; | ||
366 | case IPPROTO_UDPLITE: | ||
367 | if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE) | ||
368 | if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4, | ||
369 | ntohs(iph->tot_len), 1)) | ||
370 | goto fail; | ||
371 | break; | ||
372 | } | ||
373 | |||
374 | if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) { | ||
375 | if (skb_cloned(skb) && | ||
376 | !skb_clone_writable(skb, sizeof(*iph) + ntkoff) && | ||
377 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | ||
378 | goto fail; | ||
379 | |||
380 | ip_send_check(iph); | ||
381 | } | ||
382 | |||
383 | return 1; | ||
384 | |||
385 | fail: | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int tcf_csum_ipv6_hopopts(struct ipv6_opt_hdr *ip6xh, | ||
390 | unsigned int ixhl, unsigned int *pl) | ||
391 | { | ||
392 | int off, len, optlen; | ||
393 | unsigned char *xh = (void *)ip6xh; | ||
394 | |||
395 | off = sizeof(*ip6xh); | ||
396 | len = ixhl - off; | ||
397 | |||
398 | while (len > 1) { | ||
399 | switch (xh[off]) { | ||
400 | case IPV6_TLV_PAD0: | ||
401 | optlen = 1; | ||
402 | break; | ||
403 | case IPV6_TLV_JUMBO: | ||
404 | optlen = xh[off + 1] + 2; | ||
405 | if (optlen != 6 || len < 6 || (off & 3) != 2) | ||
406 | /* wrong jumbo option length/alignment */ | ||
407 | return 0; | ||
408 | *pl = ntohl(*(__be32 *)(xh + off + 2)); | ||
409 | goto done; | ||
410 | default: | ||
411 | optlen = xh[off + 1] + 2; | ||
412 | if (optlen > len) | ||
413 | /* ignore obscure options */ | ||
414 | goto done; | ||
415 | break; | ||
416 | } | ||
417 | off += optlen; | ||
418 | len -= optlen; | ||
419 | } | ||
420 | |||
421 | done: | ||
422 | return 1; | ||
423 | } | ||
424 | |||
425 | static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags) | ||
426 | { | ||
427 | struct ipv6hdr *ip6h; | ||
428 | struct ipv6_opt_hdr *ip6xh; | ||
429 | unsigned int hl, ixhl; | ||
430 | unsigned int pl; | ||
431 | int ntkoff; | ||
432 | u8 nexthdr; | ||
433 | |||
434 | ntkoff = skb_network_offset(skb); | ||
435 | |||
436 | hl = sizeof(*ip6h); | ||
437 | |||
438 | if (!pskb_may_pull(skb, hl + ntkoff)) | ||
439 | goto fail; | ||
440 | |||
441 | ip6h = ipv6_hdr(skb); | ||
442 | |||
443 | pl = ntohs(ip6h->payload_len); | ||
444 | nexthdr = ip6h->nexthdr; | ||
445 | |||
446 | do { | ||
447 | switch (nexthdr) { | ||
448 | case NEXTHDR_FRAGMENT: | ||
449 | goto ignore_skb; | ||
450 | case NEXTHDR_ROUTING: | ||
451 | case NEXTHDR_HOP: | ||
452 | case NEXTHDR_DEST: | ||
453 | if (!pskb_may_pull(skb, hl + sizeof(*ip6xh) + ntkoff)) | ||
454 | goto fail; | ||
455 | ip6xh = (void *)(skb_network_header(skb) + hl); | ||
456 | ixhl = ipv6_optlen(ip6xh); | ||
457 | if (!pskb_may_pull(skb, hl + ixhl + ntkoff)) | ||
458 | goto fail; | ||
459 | if ((nexthdr == NEXTHDR_HOP) && | ||
460 | !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl))) | ||
461 | goto fail; | ||
462 | nexthdr = ip6xh->nexthdr; | ||
463 | hl += ixhl; | ||
464 | break; | ||
465 | case IPPROTO_ICMPV6: | ||
466 | if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP) | ||
467 | if (!tcf_csum_ipv6_icmp(skb, ip6h, | ||
468 | hl, pl + sizeof(*ip6h))) | ||
469 | goto fail; | ||
470 | goto done; | ||
471 | case IPPROTO_TCP: | ||
472 | if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP) | ||
473 | if (!tcf_csum_ipv6_tcp(skb, ip6h, | ||
474 | hl, pl + sizeof(*ip6h))) | ||
475 | goto fail; | ||
476 | goto done; | ||
477 | case IPPROTO_UDP: | ||
478 | if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP) | ||
479 | if (!tcf_csum_ipv6_udp(skb, ip6h, hl, | ||
480 | pl + sizeof(*ip6h), 0)) | ||
481 | goto fail; | ||
482 | goto done; | ||
483 | case IPPROTO_UDPLITE: | ||
484 | if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE) | ||
485 | if (!tcf_csum_ipv6_udp(skb, ip6h, hl, | ||
486 | pl + sizeof(*ip6h), 1)) | ||
487 | goto fail; | ||
488 | goto done; | ||
489 | default: | ||
490 | goto ignore_skb; | ||
491 | } | ||
492 | } while (pskb_may_pull(skb, hl + 1 + ntkoff)); | ||
493 | |||
494 | done: | ||
495 | ignore_skb: | ||
496 | return 1; | ||
497 | |||
498 | fail: | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int tcf_csum(struct sk_buff *skb, | ||
503 | struct tc_action *a, struct tcf_result *res) | ||
504 | { | ||
505 | struct tcf_csum *p = a->priv; | ||
506 | int action; | ||
507 | u32 update_flags; | ||
508 | |||
509 | spin_lock(&p->tcf_lock); | ||
510 | p->tcf_tm.lastuse = jiffies; | ||
511 | p->tcf_bstats.bytes += qdisc_pkt_len(skb); | ||
512 | p->tcf_bstats.packets++; | ||
513 | action = p->tcf_action; | ||
514 | update_flags = p->update_flags; | ||
515 | spin_unlock(&p->tcf_lock); | ||
516 | |||
517 | if (unlikely(action == TC_ACT_SHOT)) | ||
518 | goto drop; | ||
519 | |||
520 | switch (skb->protocol) { | ||
521 | case cpu_to_be16(ETH_P_IP): | ||
522 | if (!tcf_csum_ipv4(skb, update_flags)) | ||
523 | goto drop; | ||
524 | break; | ||
525 | case cpu_to_be16(ETH_P_IPV6): | ||
526 | if (!tcf_csum_ipv6(skb, update_flags)) | ||
527 | goto drop; | ||
528 | break; | ||
529 | } | ||
530 | |||
531 | return action; | ||
532 | |||
533 | drop: | ||
534 | spin_lock(&p->tcf_lock); | ||
535 | p->tcf_qstats.drops++; | ||
536 | spin_unlock(&p->tcf_lock); | ||
537 | return TC_ACT_SHOT; | ||
538 | } | ||
539 | |||
540 | static int tcf_csum_dump(struct sk_buff *skb, | ||
541 | struct tc_action *a, int bind, int ref) | ||
542 | { | ||
543 | unsigned char *b = skb_tail_pointer(skb); | ||
544 | struct tcf_csum *p = a->priv; | ||
545 | struct tc_csum opt = { | ||
546 | .update_flags = p->update_flags, | ||
547 | .index = p->tcf_index, | ||
548 | .action = p->tcf_action, | ||
549 | .refcnt = p->tcf_refcnt - ref, | ||
550 | .bindcnt = p->tcf_bindcnt - bind, | ||
551 | }; | ||
552 | struct tcf_t t; | ||
553 | |||
554 | NLA_PUT(skb, TCA_CSUM_PARMS, sizeof(opt), &opt); | ||
555 | t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); | ||
556 | t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); | ||
557 | t.expires = jiffies_to_clock_t(p->tcf_tm.expires); | ||
558 | NLA_PUT(skb, TCA_CSUM_TM, sizeof(t), &t); | ||
559 | |||
560 | return skb->len; | ||
561 | |||
562 | nla_put_failure: | ||
563 | nlmsg_trim(skb, b); | ||
564 | return -1; | ||
565 | } | ||
566 | |||
567 | static struct tc_action_ops act_csum_ops = { | ||
568 | .kind = "csum", | ||
569 | .hinfo = &csum_hash_info, | ||
570 | .type = TCA_ACT_CSUM, | ||
571 | .capab = TCA_CAP_NONE, | ||
572 | .owner = THIS_MODULE, | ||
573 | .act = tcf_csum, | ||
574 | .dump = tcf_csum_dump, | ||
575 | .cleanup = tcf_csum_cleanup, | ||
576 | .lookup = tcf_hash_search, | ||
577 | .init = tcf_csum_init, | ||
578 | .walk = tcf_generic_walker | ||
579 | }; | ||
580 | |||
581 | MODULE_DESCRIPTION("Checksum updating actions"); | ||
582 | MODULE_LICENSE("GPL"); | ||
583 | |||
584 | static int __init csum_init_module(void) | ||
585 | { | ||
586 | return tcf_register_action(&act_csum_ops); | ||
587 | } | ||
588 | |||
589 | static void __exit csum_cleanup_module(void) | ||
590 | { | ||
591 | tcf_unregister_action(&act_csum_ops); | ||
592 | } | ||
593 | |||
594 | module_init(csum_init_module); | ||
595 | module_exit(csum_cleanup_module); | ||
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index c7e59e6ec349..8daef9632255 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c | |||
@@ -39,7 +39,7 @@ static struct tcf_hashinfo ipt_hash_info = { | |||
39 | .lock = &ipt_lock, | 39 | .lock = &ipt_lock, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) | 42 | static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook) |
43 | { | 43 | { |
44 | struct xt_tgchk_param par; | 44 | struct xt_tgchk_param par; |
45 | struct xt_target *target; | 45 | struct xt_target *target; |
@@ -66,7 +66,7 @@ static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | static void ipt_destroy_target(struct ipt_entry_target *t) | 69 | static void ipt_destroy_target(struct xt_entry_target *t) |
70 | { | 70 | { |
71 | struct xt_tgdtor_param par = { | 71 | struct xt_tgdtor_param par = { |
72 | .target = t->u.kernel.target, | 72 | .target = t->u.kernel.target, |
@@ -99,7 +99,7 @@ static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { | |||
99 | [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ }, | 99 | [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ }, |
100 | [TCA_IPT_HOOK] = { .type = NLA_U32 }, | 100 | [TCA_IPT_HOOK] = { .type = NLA_U32 }, |
101 | [TCA_IPT_INDEX] = { .type = NLA_U32 }, | 101 | [TCA_IPT_INDEX] = { .type = NLA_U32 }, |
102 | [TCA_IPT_TARG] = { .len = sizeof(struct ipt_entry_target) }, | 102 | [TCA_IPT_TARG] = { .len = sizeof(struct xt_entry_target) }, |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est, | 105 | static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est, |
@@ -108,7 +108,7 @@ static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est, | |||
108 | struct nlattr *tb[TCA_IPT_MAX + 1]; | 108 | struct nlattr *tb[TCA_IPT_MAX + 1]; |
109 | struct tcf_ipt *ipt; | 109 | struct tcf_ipt *ipt; |
110 | struct tcf_common *pc; | 110 | struct tcf_common *pc; |
111 | struct ipt_entry_target *td, *t; | 111 | struct xt_entry_target *td, *t; |
112 | char *tname; | 112 | char *tname; |
113 | int ret = 0, err; | 113 | int ret = 0, err; |
114 | u32 hook = 0; | 114 | u32 hook = 0; |
@@ -126,7 +126,7 @@ static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est, | |||
126 | if (tb[TCA_IPT_TARG] == NULL) | 126 | if (tb[TCA_IPT_TARG] == NULL) |
127 | return -EINVAL; | 127 | return -EINVAL; |
128 | 128 | ||
129 | td = (struct ipt_entry_target *)nla_data(tb[TCA_IPT_TARG]); | 129 | td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); |
130 | if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) | 130 | if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) |
131 | return -EINVAL; | 131 | return -EINVAL; |
132 | 132 | ||
@@ -230,7 +230,7 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a, | |||
230 | result = TC_ACT_SHOT; | 230 | result = TC_ACT_SHOT; |
231 | ipt->tcf_qstats.drops++; | 231 | ipt->tcf_qstats.drops++; |
232 | break; | 232 | break; |
233 | case IPT_CONTINUE: | 233 | case XT_CONTINUE: |
234 | result = TC_ACT_PIPE; | 234 | result = TC_ACT_PIPE; |
235 | break; | 235 | break; |
236 | default: | 236 | default: |
@@ -249,7 +249,7 @@ static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int | |||
249 | { | 249 | { |
250 | unsigned char *b = skb_tail_pointer(skb); | 250 | unsigned char *b = skb_tail_pointer(skb); |
251 | struct tcf_ipt *ipt = a->priv; | 251 | struct tcf_ipt *ipt = a->priv; |
252 | struct ipt_entry_target *t; | 252 | struct xt_entry_target *t; |
253 | struct tcf_t tm; | 253 | struct tcf_t tm; |
254 | struct tc_cnt c; | 254 | struct tc_cnt c; |
255 | 255 | ||
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index e17096e3913c..5b271a18bc3a 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c | |||
@@ -111,44 +111,41 @@ static u32 flow_get_proto(struct sk_buff *skb) | |||
111 | } | 111 | } |
112 | } | 112 | } |
113 | 113 | ||
114 | static int has_ports(u8 protocol) | ||
115 | { | ||
116 | switch (protocol) { | ||
117 | case IPPROTO_TCP: | ||
118 | case IPPROTO_UDP: | ||
119 | case IPPROTO_UDPLITE: | ||
120 | case IPPROTO_SCTP: | ||
121 | case IPPROTO_DCCP: | ||
122 | case IPPROTO_ESP: | ||
123 | return 1; | ||
124 | default: | ||
125 | return 0; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static u32 flow_get_proto_src(struct sk_buff *skb) | 114 | static u32 flow_get_proto_src(struct sk_buff *skb) |
130 | { | 115 | { |
131 | switch (skb->protocol) { | 116 | switch (skb->protocol) { |
132 | case htons(ETH_P_IP): { | 117 | case htons(ETH_P_IP): { |
133 | struct iphdr *iph; | 118 | struct iphdr *iph; |
119 | int poff; | ||
134 | 120 | ||
135 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 121 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
136 | break; | 122 | break; |
137 | iph = ip_hdr(skb); | 123 | iph = ip_hdr(skb); |
138 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 124 | if (iph->frag_off & htons(IP_MF|IP_OFFSET)) |
139 | has_ports(iph->protocol) && | 125 | break; |
140 | pskb_network_may_pull(skb, iph->ihl * 4 + 2)) | 126 | poff = proto_ports_offset(iph->protocol); |
141 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); | 127 | if (poff >= 0 && |
128 | pskb_network_may_pull(skb, iph->ihl * 4 + 2 + poff)) { | ||
129 | iph = ip_hdr(skb); | ||
130 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + | ||
131 | poff)); | ||
132 | } | ||
142 | break; | 133 | break; |
143 | } | 134 | } |
144 | case htons(ETH_P_IPV6): { | 135 | case htons(ETH_P_IPV6): { |
145 | struct ipv6hdr *iph; | 136 | struct ipv6hdr *iph; |
137 | int poff; | ||
146 | 138 | ||
147 | if (!pskb_network_may_pull(skb, sizeof(*iph) + 2)) | 139 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
148 | break; | 140 | break; |
149 | iph = ipv6_hdr(skb); | 141 | iph = ipv6_hdr(skb); |
150 | if (has_ports(iph->nexthdr)) | 142 | poff = proto_ports_offset(iph->nexthdr); |
151 | return ntohs(*(__be16 *)&iph[1]); | 143 | if (poff >= 0 && |
144 | pskb_network_may_pull(skb, sizeof(*iph) + poff + 2)) { | ||
145 | iph = ipv6_hdr(skb); | ||
146 | return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) + | ||
147 | poff)); | ||
148 | } | ||
152 | break; | 149 | break; |
153 | } | 150 | } |
154 | } | 151 | } |
@@ -161,24 +158,36 @@ static u32 flow_get_proto_dst(struct sk_buff *skb) | |||
161 | switch (skb->protocol) { | 158 | switch (skb->protocol) { |
162 | case htons(ETH_P_IP): { | 159 | case htons(ETH_P_IP): { |
163 | struct iphdr *iph; | 160 | struct iphdr *iph; |
161 | int poff; | ||
164 | 162 | ||
165 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 163 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
166 | break; | 164 | break; |
167 | iph = ip_hdr(skb); | 165 | iph = ip_hdr(skb); |
168 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 166 | if (iph->frag_off & htons(IP_MF|IP_OFFSET)) |
169 | has_ports(iph->protocol) && | 167 | break; |
170 | pskb_network_may_pull(skb, iph->ihl * 4 + 4)) | 168 | poff = proto_ports_offset(iph->protocol); |
171 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); | 169 | if (poff >= 0 && |
170 | pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) { | ||
171 | iph = ip_hdr(skb); | ||
172 | return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + | ||
173 | 2 + poff)); | ||
174 | } | ||
172 | break; | 175 | break; |
173 | } | 176 | } |
174 | case htons(ETH_P_IPV6): { | 177 | case htons(ETH_P_IPV6): { |
175 | struct ipv6hdr *iph; | 178 | struct ipv6hdr *iph; |
179 | int poff; | ||
176 | 180 | ||
177 | if (!pskb_network_may_pull(skb, sizeof(*iph) + 4)) | 181 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
178 | break; | 182 | break; |
179 | iph = ipv6_hdr(skb); | 183 | iph = ipv6_hdr(skb); |
180 | if (has_ports(iph->nexthdr)) | 184 | poff = proto_ports_offset(iph->nexthdr); |
181 | return ntohs(*(__be16 *)((void *)&iph[1] + 2)); | 185 | if (poff >= 0 && |
186 | pskb_network_may_pull(skb, sizeof(*iph) + poff + 4)) { | ||
187 | iph = ipv6_hdr(skb); | ||
188 | return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) + | ||
189 | poff + 2)); | ||
190 | } | ||
182 | break; | 191 | break; |
183 | } | 192 | } |
184 | } | 193 | } |
@@ -297,6 +306,11 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb) | |||
297 | return tag & VLAN_VID_MASK; | 306 | return tag & VLAN_VID_MASK; |
298 | } | 307 | } |
299 | 308 | ||
309 | static u32 flow_get_rxhash(struct sk_buff *skb) | ||
310 | { | ||
311 | return skb_get_rxhash(skb); | ||
312 | } | ||
313 | |||
300 | static u32 flow_key_get(struct sk_buff *skb, int key) | 314 | static u32 flow_key_get(struct sk_buff *skb, int key) |
301 | { | 315 | { |
302 | switch (key) { | 316 | switch (key) { |
@@ -334,6 +348,8 @@ static u32 flow_key_get(struct sk_buff *skb, int key) | |||
334 | return flow_get_skgid(skb); | 348 | return flow_get_skgid(skb); |
335 | case FLOW_KEY_VLAN_TAG: | 349 | case FLOW_KEY_VLAN_TAG: |
336 | return flow_get_vlan_tag(skb); | 350 | return flow_get_vlan_tag(skb); |
351 | case FLOW_KEY_RXHASH: | ||
352 | return flow_get_rxhash(skb); | ||
337 | default: | 353 | default: |
338 | WARN_ON(1); | 354 | WARN_ON(1); |
339 | return 0; | 355 | return 0; |
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 3bcac8aa333c..34da5e29ea1a 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c | |||
@@ -223,6 +223,11 @@ META_COLLECTOR(int_maclen) | |||
223 | dst->value = skb->mac_len; | 223 | dst->value = skb->mac_len; |
224 | } | 224 | } |
225 | 225 | ||
226 | META_COLLECTOR(int_rxhash) | ||
227 | { | ||
228 | dst->value = skb_get_rxhash(skb); | ||
229 | } | ||
230 | |||
226 | /************************************************************************** | 231 | /************************************************************************** |
227 | * Netfilter | 232 | * Netfilter |
228 | **************************************************************************/ | 233 | **************************************************************************/ |
@@ -541,6 +546,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = { | |||
541 | [META_ID(SK_SENDMSG_OFF)] = META_FUNC(int_sk_sendmsg_off), | 546 | [META_ID(SK_SENDMSG_OFF)] = META_FUNC(int_sk_sendmsg_off), |
542 | [META_ID(SK_WRITE_PENDING)] = META_FUNC(int_sk_write_pend), | 547 | [META_ID(SK_WRITE_PENDING)] = META_FUNC(int_sk_write_pend), |
543 | [META_ID(VLAN_TAG)] = META_FUNC(int_vlan_tag), | 548 | [META_ID(VLAN_TAG)] = META_FUNC(int_vlan_tag), |
549 | [META_ID(RXHASH)] = META_FUNC(int_rxhash), | ||
544 | } | 550 | } |
545 | }; | 551 | }; |
546 | 552 | ||
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 408eea7086aa..b22ca2d1cebc 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -240,7 +240,10 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) | |||
240 | if (q) | 240 | if (q) |
241 | goto out; | 241 | goto out; |
242 | 242 | ||
243 | q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); | 243 | if (dev_ingress_queue(dev)) |
244 | q = qdisc_match_from_root( | ||
245 | dev_ingress_queue(dev)->qdisc_sleeping, | ||
246 | handle); | ||
244 | out: | 247 | out: |
245 | return q; | 248 | return q; |
246 | } | 249 | } |
@@ -360,7 +363,7 @@ static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) | |||
360 | tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); | 363 | tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); |
361 | } | 364 | } |
362 | 365 | ||
363 | if (!s || tsize != s->tsize || (!tab && tsize > 0)) | 366 | if (tsize != s->tsize || (!tab && tsize > 0)) |
364 | return ERR_PTR(-EINVAL); | 367 | return ERR_PTR(-EINVAL); |
365 | 368 | ||
366 | spin_lock(&qdisc_stab_lock); | 369 | spin_lock(&qdisc_stab_lock); |
@@ -690,6 +693,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
690 | (new && new->flags & TCQ_F_INGRESS)) { | 693 | (new && new->flags & TCQ_F_INGRESS)) { |
691 | num_q = 1; | 694 | num_q = 1; |
692 | ingress = 1; | 695 | ingress = 1; |
696 | if (!dev_ingress_queue(dev)) | ||
697 | return -ENOENT; | ||
693 | } | 698 | } |
694 | 699 | ||
695 | if (dev->flags & IFF_UP) | 700 | if (dev->flags & IFF_UP) |
@@ -701,7 +706,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
701 | } | 706 | } |
702 | 707 | ||
703 | for (i = 0; i < num_q; i++) { | 708 | for (i = 0; i < num_q; i++) { |
704 | struct netdev_queue *dev_queue = &dev->rx_queue; | 709 | struct netdev_queue *dev_queue = dev_ingress_queue(dev); |
705 | 710 | ||
706 | if (!ingress) | 711 | if (!ingress) |
707 | dev_queue = netdev_get_tx_queue(dev, i); | 712 | dev_queue = netdev_get_tx_queue(dev, i); |
@@ -979,7 +984,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
979 | return -ENOENT; | 984 | return -ENOENT; |
980 | q = qdisc_leaf(p, clid); | 985 | q = qdisc_leaf(p, clid); |
981 | } else { /* ingress */ | 986 | } else { /* ingress */ |
982 | q = dev->rx_queue.qdisc_sleeping; | 987 | if (dev_ingress_queue(dev)) |
988 | q = dev_ingress_queue(dev)->qdisc_sleeping; | ||
983 | } | 989 | } |
984 | } else { | 990 | } else { |
985 | q = dev->qdisc; | 991 | q = dev->qdisc; |
@@ -1043,8 +1049,9 @@ replay: | |||
1043 | if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) | 1049 | if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) |
1044 | return -ENOENT; | 1050 | return -ENOENT; |
1045 | q = qdisc_leaf(p, clid); | 1051 | q = qdisc_leaf(p, clid); |
1046 | } else { /*ingress */ | 1052 | } else { /* ingress */ |
1047 | q = dev->rx_queue.qdisc_sleeping; | 1053 | if (dev_ingress_queue_create(dev)) |
1054 | q = dev_ingress_queue(dev)->qdisc_sleeping; | ||
1048 | } | 1055 | } |
1049 | } else { | 1056 | } else { |
1050 | q = dev->qdisc; | 1057 | q = dev->qdisc; |
@@ -1123,11 +1130,14 @@ replay: | |||
1123 | create_n_graft: | 1130 | create_n_graft: |
1124 | if (!(n->nlmsg_flags&NLM_F_CREATE)) | 1131 | if (!(n->nlmsg_flags&NLM_F_CREATE)) |
1125 | return -ENOENT; | 1132 | return -ENOENT; |
1126 | if (clid == TC_H_INGRESS) | 1133 | if (clid == TC_H_INGRESS) { |
1127 | q = qdisc_create(dev, &dev->rx_queue, p, | 1134 | if (dev_ingress_queue(dev)) |
1128 | tcm->tcm_parent, tcm->tcm_parent, | 1135 | q = qdisc_create(dev, dev_ingress_queue(dev), p, |
1129 | tca, &err); | 1136 | tcm->tcm_parent, tcm->tcm_parent, |
1130 | else { | 1137 | tca, &err); |
1138 | else | ||
1139 | err = -ENOENT; | ||
1140 | } else { | ||
1131 | struct netdev_queue *dev_queue; | 1141 | struct netdev_queue *dev_queue; |
1132 | 1142 | ||
1133 | if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) | 1143 | if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) |
@@ -1304,8 +1314,10 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) | |||
1304 | if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) | 1314 | if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) |
1305 | goto done; | 1315 | goto done; |
1306 | 1316 | ||
1307 | dev_queue = &dev->rx_queue; | 1317 | dev_queue = dev_ingress_queue(dev); |
1308 | if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0) | 1318 | if (dev_queue && |
1319 | tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, | ||
1320 | &q_idx, s_q_idx) < 0) | ||
1309 | goto done; | 1321 | goto done; |
1310 | 1322 | ||
1311 | cont: | 1323 | cont: |
@@ -1595,8 +1607,10 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) | |||
1595 | if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) | 1607 | if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) |
1596 | goto done; | 1608 | goto done; |
1597 | 1609 | ||
1598 | dev_queue = &dev->rx_queue; | 1610 | dev_queue = dev_ingress_queue(dev); |
1599 | if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0) | 1611 | if (dev_queue && |
1612 | tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, | ||
1613 | &t, s_t) < 0) | ||
1600 | goto done; | 1614 | goto done; |
1601 | 1615 | ||
1602 | done: | 1616 | done: |
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 6318e1136b83..282540778aa8 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c | |||
@@ -275,8 +275,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, | |||
275 | goto err_out; | 275 | goto err_out; |
276 | } | 276 | } |
277 | flow->filter_list = NULL; | 277 | flow->filter_list = NULL; |
278 | flow->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 278 | flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid); |
279 | &pfifo_qdisc_ops, classid); | ||
280 | if (!flow->q) | 279 | if (!flow->q) |
281 | flow->q = &noop_qdisc; | 280 | flow->q = &noop_qdisc; |
282 | pr_debug("atm_tc_change: qdisc %p\n", flow->q); | 281 | pr_debug("atm_tc_change: qdisc %p\n", flow->q); |
@@ -543,7 +542,7 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) | |||
543 | INIT_LIST_HEAD(&p->flows); | 542 | INIT_LIST_HEAD(&p->flows); |
544 | INIT_LIST_HEAD(&p->link.list); | 543 | INIT_LIST_HEAD(&p->link.list); |
545 | list_add(&p->link.list, &p->flows); | 544 | list_add(&p->link.list, &p->flows); |
546 | p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 545 | p->link.q = qdisc_create_dflt(sch->dev_queue, |
547 | &pfifo_qdisc_ops, sch->handle); | 546 | &pfifo_qdisc_ops, sch->handle); |
548 | if (!p->link.q) | 547 | if (!p->link.q) |
549 | p->link.q = &noop_qdisc; | 548 | p->link.q = &noop_qdisc; |
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 28c01ef5abc8..eb7631590865 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c | |||
@@ -1379,9 +1379,9 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) | |||
1379 | q->link.sibling = &q->link; | 1379 | q->link.sibling = &q->link; |
1380 | q->link.common.classid = sch->handle; | 1380 | q->link.common.classid = sch->handle; |
1381 | q->link.qdisc = sch; | 1381 | q->link.qdisc = sch; |
1382 | if (!(q->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1382 | q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
1383 | &pfifo_qdisc_ops, | 1383 | sch->handle); |
1384 | sch->handle))) | 1384 | if (!q->link.q) |
1385 | q->link.q = &noop_qdisc; | 1385 | q->link.q = &noop_qdisc; |
1386 | 1386 | ||
1387 | q->link.priority = TC_CBQ_MAXPRIO-1; | 1387 | q->link.priority = TC_CBQ_MAXPRIO-1; |
@@ -1623,7 +1623,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | |||
1623 | struct cbq_class *cl = (struct cbq_class*)arg; | 1623 | struct cbq_class *cl = (struct cbq_class*)arg; |
1624 | 1624 | ||
1625 | if (new == NULL) { | 1625 | if (new == NULL) { |
1626 | new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1626 | new = qdisc_create_dflt(sch->dev_queue, |
1627 | &pfifo_qdisc_ops, cl->common.classid); | 1627 | &pfifo_qdisc_ops, cl->common.classid); |
1628 | if (new == NULL) | 1628 | if (new == NULL) |
1629 | return -ENOBUFS; | 1629 | return -ENOBUFS; |
@@ -1874,8 +1874,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t | |||
1874 | cl->R_tab = rtab; | 1874 | cl->R_tab = rtab; |
1875 | rtab = NULL; | 1875 | rtab = NULL; |
1876 | cl->refcnt = 1; | 1876 | cl->refcnt = 1; |
1877 | if (!(cl->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1877 | cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid); |
1878 | &pfifo_qdisc_ops, classid))) | 1878 | if (!cl->q) |
1879 | cl->q = &noop_qdisc; | 1879 | cl->q = &noop_qdisc; |
1880 | cl->common.classid = classid; | 1880 | cl->common.classid = classid; |
1881 | cl->tparent = parent; | 1881 | cl->tparent = parent; |
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index b74046a95397..aa8b5313f8cf 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c | |||
@@ -110,7 +110,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
110 | cl->refcnt = 1; | 110 | cl->refcnt = 1; |
111 | cl->common.classid = classid; | 111 | cl->common.classid = classid; |
112 | cl->quantum = quantum; | 112 | cl->quantum = quantum; |
113 | cl->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 113 | cl->qdisc = qdisc_create_dflt(sch->dev_queue, |
114 | &pfifo_qdisc_ops, classid); | 114 | &pfifo_qdisc_ops, classid); |
115 | if (cl->qdisc == NULL) | 115 | if (cl->qdisc == NULL) |
116 | cl->qdisc = &noop_qdisc; | 116 | cl->qdisc = &noop_qdisc; |
@@ -218,7 +218,7 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg, | |||
218 | struct drr_class *cl = (struct drr_class *)arg; | 218 | struct drr_class *cl = (struct drr_class *)arg; |
219 | 219 | ||
220 | if (new == NULL) { | 220 | if (new == NULL) { |
221 | new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 221 | new = qdisc_create_dflt(sch->dev_queue, |
222 | &pfifo_qdisc_ops, cl->common.classid); | 222 | &pfifo_qdisc_ops, cl->common.classid); |
223 | if (new == NULL) | 223 | if (new == NULL) |
224 | new = &noop_qdisc; | 224 | new = &noop_qdisc; |
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 63d41f86679c..1d295d62bb5c 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c | |||
@@ -61,8 +61,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, | |||
61 | sch, p, new, old); | 61 | sch, p, new, old); |
62 | 62 | ||
63 | if (new == NULL) { | 63 | if (new == NULL) { |
64 | new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 64 | new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
65 | &pfifo_qdisc_ops, | ||
66 | sch->handle); | 65 | sch->handle); |
67 | if (new == NULL) | 66 | if (new == NULL) |
68 | new = &noop_qdisc; | 67 | new = &noop_qdisc; |
@@ -384,8 +383,7 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) | |||
384 | p->default_index = default_index; | 383 | p->default_index = default_index; |
385 | p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]); | 384 | p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]); |
386 | 385 | ||
387 | p->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 386 | p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle); |
388 | &pfifo_qdisc_ops, sch->handle); | ||
389 | if (p->q == NULL) | 387 | if (p->q == NULL) |
390 | p->q = &noop_qdisc; | 388 | p->q = &noop_qdisc; |
391 | 389 | ||
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index 5948bafa8ce2..4dfecb0cba37 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c | |||
@@ -172,8 +172,7 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, | |||
172 | struct Qdisc *q; | 172 | struct Qdisc *q; |
173 | int err = -ENOMEM; | 173 | int err = -ENOMEM; |
174 | 174 | ||
175 | q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 175 | q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1)); |
176 | ops, TC_H_MAKE(sch->handle, 1)); | ||
177 | if (q) { | 176 | if (q) { |
178 | err = fifo_set_limit(q, limit); | 177 | err = fifo_set_limit(q, limit); |
179 | if (err < 0) { | 178 | if (err < 0) { |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 2aeb3a4386a1..5dbb3cd96e59 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -383,6 +383,7 @@ struct Qdisc noop_qdisc = { | |||
383 | .list = LIST_HEAD_INIT(noop_qdisc.list), | 383 | .list = LIST_HEAD_INIT(noop_qdisc.list), |
384 | .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), | 384 | .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), |
385 | .dev_queue = &noop_netdev_queue, | 385 | .dev_queue = &noop_netdev_queue, |
386 | .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock), | ||
386 | }; | 387 | }; |
387 | EXPORT_SYMBOL(noop_qdisc); | 388 | EXPORT_SYMBOL(noop_qdisc); |
388 | 389 | ||
@@ -409,6 +410,7 @@ static struct Qdisc noqueue_qdisc = { | |||
409 | .list = LIST_HEAD_INIT(noqueue_qdisc.list), | 410 | .list = LIST_HEAD_INIT(noqueue_qdisc.list), |
410 | .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), | 411 | .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), |
411 | .dev_queue = &noqueue_netdev_queue, | 412 | .dev_queue = &noqueue_netdev_queue, |
413 | .busylock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock), | ||
412 | }; | 414 | }; |
413 | 415 | ||
414 | 416 | ||
@@ -574,10 +576,8 @@ errout: | |||
574 | return ERR_PTR(err); | 576 | return ERR_PTR(err); |
575 | } | 577 | } |
576 | 578 | ||
577 | struct Qdisc * qdisc_create_dflt(struct net_device *dev, | 579 | struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, |
578 | struct netdev_queue *dev_queue, | 580 | struct Qdisc_ops *ops, unsigned int parentid) |
579 | struct Qdisc_ops *ops, | ||
580 | unsigned int parentid) | ||
581 | { | 581 | { |
582 | struct Qdisc *sch; | 582 | struct Qdisc *sch; |
583 | 583 | ||
@@ -682,7 +682,7 @@ static void attach_one_default_qdisc(struct net_device *dev, | |||
682 | struct Qdisc *qdisc; | 682 | struct Qdisc *qdisc; |
683 | 683 | ||
684 | if (dev->tx_queue_len) { | 684 | if (dev->tx_queue_len) { |
685 | qdisc = qdisc_create_dflt(dev, dev_queue, | 685 | qdisc = qdisc_create_dflt(dev_queue, |
686 | &pfifo_fast_ops, TC_H_ROOT); | 686 | &pfifo_fast_ops, TC_H_ROOT); |
687 | if (!qdisc) { | 687 | if (!qdisc) { |
688 | printk(KERN_INFO "%s: activation failed\n", dev->name); | 688 | printk(KERN_INFO "%s: activation failed\n", dev->name); |
@@ -709,7 +709,7 @@ static void attach_default_qdiscs(struct net_device *dev) | |||
709 | dev->qdisc = txq->qdisc_sleeping; | 709 | dev->qdisc = txq->qdisc_sleeping; |
710 | atomic_inc(&dev->qdisc->refcnt); | 710 | atomic_inc(&dev->qdisc->refcnt); |
711 | } else { | 711 | } else { |
712 | qdisc = qdisc_create_dflt(dev, txq, &mq_qdisc_ops, TC_H_ROOT); | 712 | qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT); |
713 | if (qdisc) { | 713 | if (qdisc) { |
714 | qdisc->ops->attach(qdisc); | 714 | qdisc->ops->attach(qdisc); |
715 | dev->qdisc = qdisc; | 715 | dev->qdisc = qdisc; |
@@ -753,7 +753,8 @@ void dev_activate(struct net_device *dev) | |||
753 | 753 | ||
754 | need_watchdog = 0; | 754 | need_watchdog = 0; |
755 | netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog); | 755 | netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog); |
756 | transition_one_qdisc(dev, &dev->rx_queue, NULL); | 756 | if (dev_ingress_queue(dev)) |
757 | transition_one_qdisc(dev, dev_ingress_queue(dev), NULL); | ||
757 | 758 | ||
758 | if (need_watchdog) { | 759 | if (need_watchdog) { |
759 | dev->trans_start = jiffies; | 760 | dev->trans_start = jiffies; |
@@ -812,7 +813,8 @@ static bool some_qdisc_is_busy(struct net_device *dev) | |||
812 | void dev_deactivate(struct net_device *dev) | 813 | void dev_deactivate(struct net_device *dev) |
813 | { | 814 | { |
814 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); | 815 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); |
815 | dev_deactivate_queue(dev, &dev->rx_queue, &noop_qdisc); | 816 | if (dev_ingress_queue(dev)) |
817 | dev_deactivate_queue(dev, dev_ingress_queue(dev), &noop_qdisc); | ||
816 | 818 | ||
817 | dev_watchdog_down(dev); | 819 | dev_watchdog_down(dev); |
818 | 820 | ||
@@ -838,7 +840,8 @@ void dev_init_scheduler(struct net_device *dev) | |||
838 | { | 840 | { |
839 | dev->qdisc = &noop_qdisc; | 841 | dev->qdisc = &noop_qdisc; |
840 | netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); | 842 | netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); |
841 | dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); | 843 | if (dev_ingress_queue(dev)) |
844 | dev_init_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc); | ||
842 | 845 | ||
843 | setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); | 846 | setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); |
844 | } | 847 | } |
@@ -861,7 +864,8 @@ static void shutdown_scheduler_queue(struct net_device *dev, | |||
861 | void dev_shutdown(struct net_device *dev) | 864 | void dev_shutdown(struct net_device *dev) |
862 | { | 865 | { |
863 | netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); | 866 | netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); |
864 | shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); | 867 | if (dev_ingress_queue(dev)) |
868 | shutdown_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc); | ||
865 | qdisc_destroy(dev->qdisc); | 869 | qdisc_destroy(dev->qdisc); |
866 | dev->qdisc = &noop_qdisc; | 870 | dev->qdisc = &noop_qdisc; |
867 | 871 | ||
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 47496098d35c..069c62b7bb36 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c | |||
@@ -1088,7 +1088,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | |||
1088 | cl->refcnt = 1; | 1088 | cl->refcnt = 1; |
1089 | cl->sched = q; | 1089 | cl->sched = q; |
1090 | cl->cl_parent = parent; | 1090 | cl->cl_parent = parent; |
1091 | cl->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1091 | cl->qdisc = qdisc_create_dflt(sch->dev_queue, |
1092 | &pfifo_qdisc_ops, classid); | 1092 | &pfifo_qdisc_ops, classid); |
1093 | if (cl->qdisc == NULL) | 1093 | if (cl->qdisc == NULL) |
1094 | cl->qdisc = &noop_qdisc; | 1094 | cl->qdisc = &noop_qdisc; |
@@ -1209,8 +1209,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | |||
1209 | if (cl->level > 0) | 1209 | if (cl->level > 0) |
1210 | return -EINVAL; | 1210 | return -EINVAL; |
1211 | if (new == NULL) { | 1211 | if (new == NULL) { |
1212 | new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1212 | new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
1213 | &pfifo_qdisc_ops, | ||
1214 | cl->cl_common.classid); | 1213 | cl->cl_common.classid); |
1215 | if (new == NULL) | 1214 | if (new == NULL) |
1216 | new = &noop_qdisc; | 1215 | new = &noop_qdisc; |
@@ -1452,8 +1451,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) | |||
1452 | q->root.cl_common.classid = sch->handle; | 1451 | q->root.cl_common.classid = sch->handle; |
1453 | q->root.refcnt = 1; | 1452 | q->root.refcnt = 1; |
1454 | q->root.sched = q; | 1453 | q->root.sched = q; |
1455 | q->root.qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1454 | q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
1456 | &pfifo_qdisc_ops, | ||
1457 | sch->handle); | 1455 | sch->handle); |
1458 | if (q->root.qdisc == NULL) | 1456 | if (q->root.qdisc == NULL) |
1459 | q->root.qdisc = &noop_qdisc; | 1457 | q->root.qdisc = &noop_qdisc; |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 4be8d04b262d..01b519d6c52d 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -1121,8 +1121,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | |||
1121 | if (cl->level) | 1121 | if (cl->level) |
1122 | return -EINVAL; | 1122 | return -EINVAL; |
1123 | if (new == NULL && | 1123 | if (new == NULL && |
1124 | (new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1124 | (new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
1125 | &pfifo_qdisc_ops, | ||
1126 | cl->common.classid)) == NULL) | 1125 | cl->common.classid)) == NULL) |
1127 | return -ENOBUFS; | 1126 | return -ENOBUFS; |
1128 | 1127 | ||
@@ -1247,8 +1246,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) | |||
1247 | return -EBUSY; | 1246 | return -EBUSY; |
1248 | 1247 | ||
1249 | if (!cl->level && htb_parent_last_child(cl)) { | 1248 | if (!cl->level && htb_parent_last_child(cl)) { |
1250 | new_q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1249 | new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, |
1251 | &pfifo_qdisc_ops, | ||
1252 | cl->parent->common.classid); | 1250 | cl->parent->common.classid); |
1253 | last_child = 1; | 1251 | last_child = 1; |
1254 | } | 1252 | } |
@@ -1302,14 +1300,14 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1302 | struct htb_class *cl = (struct htb_class *)*arg, *parent; | 1300 | struct htb_class *cl = (struct htb_class *)*arg, *parent; |
1303 | struct nlattr *opt = tca[TCA_OPTIONS]; | 1301 | struct nlattr *opt = tca[TCA_OPTIONS]; |
1304 | struct qdisc_rate_table *rtab = NULL, *ctab = NULL; | 1302 | struct qdisc_rate_table *rtab = NULL, *ctab = NULL; |
1305 | struct nlattr *tb[TCA_HTB_RTAB + 1]; | 1303 | struct nlattr *tb[__TCA_HTB_MAX]; |
1306 | struct tc_htb_opt *hopt; | 1304 | struct tc_htb_opt *hopt; |
1307 | 1305 | ||
1308 | /* extract all subattrs from opt attr */ | 1306 | /* extract all subattrs from opt attr */ |
1309 | if (!opt) | 1307 | if (!opt) |
1310 | goto failure; | 1308 | goto failure; |
1311 | 1309 | ||
1312 | err = nla_parse_nested(tb, TCA_HTB_RTAB, opt, htb_policy); | 1310 | err = nla_parse_nested(tb, TCA_HTB_MAX, opt, htb_policy); |
1313 | if (err < 0) | 1311 | if (err < 0) |
1314 | goto failure; | 1312 | goto failure; |
1315 | 1313 | ||
@@ -1377,7 +1375,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1377 | /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) | 1375 | /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) |
1378 | so that can't be used inside of sch_tree_lock | 1376 | so that can't be used inside of sch_tree_lock |
1379 | -- thanks to Karlis Peisenieks */ | 1377 | -- thanks to Karlis Peisenieks */ |
1380 | new_q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 1378 | new_q = qdisc_create_dflt(sch->dev_queue, |
1381 | &pfifo_qdisc_ops, classid); | 1379 | &pfifo_qdisc_ops, classid); |
1382 | sch_tree_lock(sch); | 1380 | sch_tree_lock(sch); |
1383 | if (parent && !parent->level) { | 1381 | if (parent && !parent->level) { |
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index fe91e50f9d98..ecc302f4d2a1 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c | |||
@@ -56,7 +56,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt) | |||
56 | 56 | ||
57 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { | 57 | for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { |
58 | dev_queue = netdev_get_tx_queue(dev, ntx); | 58 | dev_queue = netdev_get_tx_queue(dev, ntx); |
59 | qdisc = qdisc_create_dflt(dev, dev_queue, &pfifo_fast_ops, | 59 | qdisc = qdisc_create_dflt(dev_queue, &pfifo_fast_ops, |
60 | TC_H_MAKE(TC_H_MAJ(sch->handle), | 60 | TC_H_MAKE(TC_H_MAJ(sch->handle), |
61 | TC_H_MIN(ntx + 1))); | 61 | TC_H_MIN(ntx + 1))); |
62 | if (qdisc == NULL) | 62 | if (qdisc == NULL) |
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 6ae251279fc2..32690deab5d0 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c | |||
@@ -227,8 +227,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) | |||
227 | for (i = 0; i < q->bands; i++) { | 227 | for (i = 0; i < q->bands; i++) { |
228 | if (q->queues[i] == &noop_qdisc) { | 228 | if (q->queues[i] == &noop_qdisc) { |
229 | struct Qdisc *child, *old; | 229 | struct Qdisc *child, *old; |
230 | child = qdisc_create_dflt(qdisc_dev(sch), | 230 | child = qdisc_create_dflt(sch->dev_queue, |
231 | sch->dev_queue, | ||
232 | &pfifo_qdisc_ops, | 231 | &pfifo_qdisc_ops, |
233 | TC_H_MAKE(sch->handle, | 232 | TC_H_MAKE(sch->handle, |
234 | i + 1)); | 233 | i + 1)); |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 4714ff162bbd..e5593c083a78 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -538,8 +538,7 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt) | |||
538 | 538 | ||
539 | qdisc_watchdog_init(&q->watchdog, sch); | 539 | qdisc_watchdog_init(&q->watchdog, sch); |
540 | 540 | ||
541 | q->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 541 | q->qdisc = qdisc_create_dflt(sch->dev_queue, &tfifo_qdisc_ops, |
542 | &tfifo_qdisc_ops, | ||
543 | TC_H_MAKE(sch->handle, 1)); | 542 | TC_H_MAKE(sch->handle, 1)); |
544 | if (!q->qdisc) { | 543 | if (!q->qdisc) { |
545 | pr_debug("netem: qdisc create failed\n"); | 544 | pr_debug("netem: qdisc create failed\n"); |
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 0748fb1e3a49..b1c95bce33ce 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c | |||
@@ -200,7 +200,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) | |||
200 | for (i=0; i<q->bands; i++) { | 200 | for (i=0; i<q->bands; i++) { |
201 | if (q->queues[i] == &noop_qdisc) { | 201 | if (q->queues[i] == &noop_qdisc) { |
202 | struct Qdisc *child, *old; | 202 | struct Qdisc *child, *old; |
203 | child = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, | 203 | child = qdisc_create_dflt(sch->dev_queue, |
204 | &pfifo_qdisc_ops, | 204 | &pfifo_qdisc_ops, |
205 | TC_H_MAKE(sch->handle, i + 1)); | 205 | TC_H_MAKE(sch->handle, i + 1)); |
206 | if (child) { | 206 | if (child) { |
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 201cbac2b32c..3cf478d012dd 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c | |||
@@ -123,40 +123,39 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) | |||
123 | case htons(ETH_P_IP): | 123 | case htons(ETH_P_IP): |
124 | { | 124 | { |
125 | const struct iphdr *iph; | 125 | const struct iphdr *iph; |
126 | int poff; | ||
126 | 127 | ||
127 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 128 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
128 | goto err; | 129 | goto err; |
129 | iph = ip_hdr(skb); | 130 | iph = ip_hdr(skb); |
130 | h = (__force u32)iph->daddr; | 131 | h = (__force u32)iph->daddr; |
131 | h2 = (__force u32)iph->saddr ^ iph->protocol; | 132 | h2 = (__force u32)iph->saddr ^ iph->protocol; |
132 | if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && | 133 | if (iph->frag_off & htons(IP_MF|IP_OFFSET)) |
133 | (iph->protocol == IPPROTO_TCP || | 134 | break; |
134 | iph->protocol == IPPROTO_UDP || | 135 | poff = proto_ports_offset(iph->protocol); |
135 | iph->protocol == IPPROTO_UDPLITE || | 136 | if (poff >= 0 && |
136 | iph->protocol == IPPROTO_SCTP || | 137 | pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) { |
137 | iph->protocol == IPPROTO_DCCP || | 138 | iph = ip_hdr(skb); |
138 | iph->protocol == IPPROTO_ESP) && | 139 | h2 ^= *(u32*)((void *)iph + iph->ihl * 4 + poff); |
139 | pskb_network_may_pull(skb, iph->ihl * 4 + 4)) | 140 | } |
140 | h2 ^= *(((u32*)iph) + iph->ihl); | ||
141 | break; | 141 | break; |
142 | } | 142 | } |
143 | case htons(ETH_P_IPV6): | 143 | case htons(ETH_P_IPV6): |
144 | { | 144 | { |
145 | struct ipv6hdr *iph; | 145 | struct ipv6hdr *iph; |
146 | int poff; | ||
146 | 147 | ||
147 | if (!pskb_network_may_pull(skb, sizeof(*iph))) | 148 | if (!pskb_network_may_pull(skb, sizeof(*iph))) |
148 | goto err; | 149 | goto err; |
149 | iph = ipv6_hdr(skb); | 150 | iph = ipv6_hdr(skb); |
150 | h = (__force u32)iph->daddr.s6_addr32[3]; | 151 | h = (__force u32)iph->daddr.s6_addr32[3]; |
151 | h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr; | 152 | h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr; |
152 | if ((iph->nexthdr == IPPROTO_TCP || | 153 | poff = proto_ports_offset(iph->nexthdr); |
153 | iph->nexthdr == IPPROTO_UDP || | 154 | if (poff >= 0 && |
154 | iph->nexthdr == IPPROTO_UDPLITE || | 155 | pskb_network_may_pull(skb, sizeof(*iph) + 4 + poff)) { |
155 | iph->nexthdr == IPPROTO_SCTP || | 156 | iph = ipv6_hdr(skb); |
156 | iph->nexthdr == IPPROTO_DCCP || | 157 | h2 ^= *(u32*)((void *)iph + sizeof(*iph) + poff); |
157 | iph->nexthdr == IPPROTO_ESP) && | 158 | } |
158 | pskb_network_may_pull(skb, sizeof(*iph) + 4)) | ||
159 | h2 ^= *(u32*)&iph[1]; | ||
160 | break; | 159 | break; |
161 | } | 160 | } |
162 | default: | 161 | default: |
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index feaabc103ce6..401af9596709 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c | |||
@@ -241,11 +241,11 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * | |||
241 | } | 241 | } |
242 | if (neigh_event_send(n, skb_res) == 0) { | 242 | if (neigh_event_send(n, skb_res) == 0) { |
243 | int err; | 243 | int err; |
244 | char haddr[MAX_ADDR_LEN]; | ||
244 | 245 | ||
245 | read_lock(&n->lock); | 246 | neigh_ha_snapshot(haddr, n, dev); |
246 | err = dev_hard_header(skb, dev, ntohs(skb->protocol), | 247 | err = dev_hard_header(skb, dev, ntohs(skb->protocol), haddr, |
247 | n->ha, NULL, skb->len); | 248 | NULL, skb->len); |
248 | read_unlock(&n->lock); | ||
249 | 249 | ||
250 | if (err < 0) { | 250 | if (err < 0) { |
251 | neigh_release(n); | 251 | neigh_release(n); |