diff options
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_cgroup.c | 2 | ||||
| -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 |
22 files changed, 753 insertions, 118 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_cgroup.c b/net/sched/cls_cgroup.c index 78ef2c5e130b..37dff78e9cb1 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c | |||
| @@ -123,7 +123,7 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
| 123 | * calls by looking at the number of nested bh disable calls because | 123 | * calls by looking at the number of nested bh disable calls because |
| 124 | * softirqs always disables bh. | 124 | * softirqs always disables bh. |
| 125 | */ | 125 | */ |
| 126 | if (softirq_count() != SOFTIRQ_OFFSET) { | 126 | if (in_serving_softirq()) { |
| 127 | /* If there is an sk_classid we'll use that. */ | 127 | /* If there is an sk_classid we'll use that. */ |
| 128 | if (!skb->sk) | 128 | if (!skb->sk) |
| 129 | return -1; | 129 | return -1; |
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); |
