diff options
author | David S. Miller <davem@davemloft.net> | 2011-09-22 03:23:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-09-22 03:23:13 -0400 |
commit | 8decf868790b48a727d7e7ca164f2bcd3c1389c0 (patch) | |
tree | b759a5f861f842af7ea76f9011b579d06e9d5508 /net/core | |
parent | 3fc72370186be2f9d4d6ef06d99e1caa5d92c564 (diff) | |
parent | d93dc5c4478c1fd5de85a3e8aece9aad7bbae044 (diff) |
Merge branch 'master' of github.com:davem330/net
Conflicts:
MAINTAINERS
drivers/net/Kconfig
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/wl12xx/main.c
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 8 | ||||
-rw-r--r-- | net/core/fib_rules.c | 4 | ||||
-rw-r--r-- | net/core/flow.c | 36 | ||||
-rw-r--r-- | net/core/neighbour.c | 8 | ||||
-rw-r--r-- | net/core/netpoll.c | 4 | ||||
-rw-r--r-- | net/core/skbuff.c | 22 |
6 files changed, 57 insertions, 25 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 4b9981caf06f..bf49a47ddfdb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1517,6 +1517,14 @@ static inline bool is_skb_forwardable(struct net_device *dev, | |||
1517 | */ | 1517 | */ |
1518 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) | 1518 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) |
1519 | { | 1519 | { |
1520 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | ||
1521 | if (skb_copy_ubufs(skb, GFP_ATOMIC)) { | ||
1522 | atomic_long_inc(&dev->rx_dropped); | ||
1523 | kfree_skb(skb); | ||
1524 | return NET_RX_DROP; | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1520 | skb_orphan(skb); | 1528 | skb_orphan(skb); |
1521 | nf_reset(skb); | 1529 | nf_reset(skb); |
1522 | 1530 | ||
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 67c5c288cd80..38be4744133f 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -384,8 +384,8 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
384 | */ | 384 | */ |
385 | list_for_each_entry(r, &ops->rules_list, list) { | 385 | list_for_each_entry(r, &ops->rules_list, list) { |
386 | if (r->action == FR_ACT_GOTO && | 386 | if (r->action == FR_ACT_GOTO && |
387 | r->target == rule->pref) { | 387 | r->target == rule->pref && |
388 | BUG_ON(rtnl_dereference(r->ctarget) != NULL); | 388 | rtnl_dereference(r->ctarget) == NULL) { |
389 | rcu_assign_pointer(r->ctarget, rule); | 389 | rcu_assign_pointer(r->ctarget, rule); |
390 | if (--ops->unresolved_rules == 0) | 390 | if (--ops->unresolved_rules == 0) |
391 | break; | 391 | break; |
diff --git a/net/core/flow.c b/net/core/flow.c index bf32c33cad3b..555a456efb07 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
@@ -30,6 +30,7 @@ struct flow_cache_entry { | |||
30 | struct hlist_node hlist; | 30 | struct hlist_node hlist; |
31 | struct list_head gc_list; | 31 | struct list_head gc_list; |
32 | } u; | 32 | } u; |
33 | struct net *net; | ||
33 | u16 family; | 34 | u16 family; |
34 | u8 dir; | 35 | u8 dir; |
35 | u32 genid; | 36 | u32 genid; |
@@ -172,29 +173,26 @@ static void flow_new_hash_rnd(struct flow_cache *fc, | |||
172 | 173 | ||
173 | static u32 flow_hash_code(struct flow_cache *fc, | 174 | static u32 flow_hash_code(struct flow_cache *fc, |
174 | struct flow_cache_percpu *fcp, | 175 | struct flow_cache_percpu *fcp, |
175 | const struct flowi *key) | 176 | const struct flowi *key, |
177 | size_t keysize) | ||
176 | { | 178 | { |
177 | const u32 *k = (const u32 *) key; | 179 | const u32 *k = (const u32 *) key; |
180 | const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32); | ||
178 | 181 | ||
179 | return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd) | 182 | return jhash2(k, length, fcp->hash_rnd) |
180 | & (flow_cache_hash_size(fc) - 1); | 183 | & (flow_cache_hash_size(fc) - 1); |
181 | } | 184 | } |
182 | 185 | ||
183 | typedef unsigned long flow_compare_t; | ||
184 | |||
185 | /* I hear what you're saying, use memcmp. But memcmp cannot make | 186 | /* I hear what you're saying, use memcmp. But memcmp cannot make |
186 | * important assumptions that we can here, such as alignment and | 187 | * important assumptions that we can here, such as alignment. |
187 | * constant size. | ||
188 | */ | 188 | */ |
189 | static int flow_key_compare(const struct flowi *key1, const struct flowi *key2) | 189 | static int flow_key_compare(const struct flowi *key1, const struct flowi *key2, |
190 | size_t keysize) | ||
190 | { | 191 | { |
191 | const flow_compare_t *k1, *k1_lim, *k2; | 192 | const flow_compare_t *k1, *k1_lim, *k2; |
192 | const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t); | ||
193 | |||
194 | BUILD_BUG_ON(sizeof(struct flowi) % sizeof(flow_compare_t)); | ||
195 | 193 | ||
196 | k1 = (const flow_compare_t *) key1; | 194 | k1 = (const flow_compare_t *) key1; |
197 | k1_lim = k1 + n_elem; | 195 | k1_lim = k1 + keysize; |
198 | 196 | ||
199 | k2 = (const flow_compare_t *) key2; | 197 | k2 = (const flow_compare_t *) key2; |
200 | 198 | ||
@@ -215,6 +213,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
215 | struct flow_cache_entry *fle, *tfle; | 213 | struct flow_cache_entry *fle, *tfle; |
216 | struct hlist_node *entry; | 214 | struct hlist_node *entry; |
217 | struct flow_cache_object *flo; | 215 | struct flow_cache_object *flo; |
216 | size_t keysize; | ||
218 | unsigned int hash; | 217 | unsigned int hash; |
219 | 218 | ||
220 | local_bh_disable(); | 219 | local_bh_disable(); |
@@ -222,6 +221,11 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
222 | 221 | ||
223 | fle = NULL; | 222 | fle = NULL; |
224 | flo = NULL; | 223 | flo = NULL; |
224 | |||
225 | keysize = flow_key_size(family); | ||
226 | if (!keysize) | ||
227 | goto nocache; | ||
228 | |||
225 | /* Packet really early in init? Making flow_cache_init a | 229 | /* Packet really early in init? Making flow_cache_init a |
226 | * pre-smp initcall would solve this. --RR */ | 230 | * pre-smp initcall would solve this. --RR */ |
227 | if (!fcp->hash_table) | 231 | if (!fcp->hash_table) |
@@ -230,11 +234,12 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
230 | if (fcp->hash_rnd_recalc) | 234 | if (fcp->hash_rnd_recalc) |
231 | flow_new_hash_rnd(fc, fcp); | 235 | flow_new_hash_rnd(fc, fcp); |
232 | 236 | ||
233 | hash = flow_hash_code(fc, fcp, key); | 237 | hash = flow_hash_code(fc, fcp, key, keysize); |
234 | hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { | 238 | hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { |
235 | if (tfle->family == family && | 239 | if (tfle->net == net && |
240 | tfle->family == family && | ||
236 | tfle->dir == dir && | 241 | tfle->dir == dir && |
237 | flow_key_compare(key, &tfle->key) == 0) { | 242 | flow_key_compare(key, &tfle->key, keysize) == 0) { |
238 | fle = tfle; | 243 | fle = tfle; |
239 | break; | 244 | break; |
240 | } | 245 | } |
@@ -246,9 +251,10 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, | |||
246 | 251 | ||
247 | fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); | 252 | fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); |
248 | if (fle) { | 253 | if (fle) { |
254 | fle->net = net; | ||
249 | fle->family = family; | 255 | fle->family = family; |
250 | fle->dir = dir; | 256 | fle->dir = dir; |
251 | memcpy(&fle->key, key, sizeof(*key)); | 257 | memcpy(&fle->key, key, keysize * sizeof(flow_compare_t)); |
252 | fle->object = NULL; | 258 | fle->object = NULL; |
253 | hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); | 259 | hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); |
254 | fcp->hash_count++; | 260 | fcp->hash_count++; |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 4002261f20d1..43449649cf73 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -1331,11 +1331,15 @@ static void neigh_proxy_process(unsigned long arg) | |||
1331 | 1331 | ||
1332 | if (tdif <= 0) { | 1332 | if (tdif <= 0) { |
1333 | struct net_device *dev = skb->dev; | 1333 | struct net_device *dev = skb->dev; |
1334 | |||
1334 | __skb_unlink(skb, &tbl->proxy_queue); | 1335 | __skb_unlink(skb, &tbl->proxy_queue); |
1335 | if (tbl->proxy_redo && netif_running(dev)) | 1336 | if (tbl->proxy_redo && netif_running(dev)) { |
1337 | rcu_read_lock(); | ||
1336 | tbl->proxy_redo(skb); | 1338 | tbl->proxy_redo(skb); |
1337 | else | 1339 | rcu_read_unlock(); |
1340 | } else { | ||
1338 | kfree_skb(skb); | 1341 | kfree_skb(skb); |
1342 | } | ||
1339 | 1343 | ||
1340 | dev_put(dev); | 1344 | dev_put(dev); |
1341 | } else if (!sched_next || tdif < sched_next) | 1345 | } else if (!sched_next || tdif < sched_next) |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index d676a561d983..f57d94627a2a 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -558,13 +558,14 @@ int __netpoll_rx(struct sk_buff *skb) | |||
558 | if (skb_shared(skb)) | 558 | if (skb_shared(skb)) |
559 | goto out; | 559 | goto out; |
560 | 560 | ||
561 | iph = (struct iphdr *)skb->data; | ||
562 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 561 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
563 | goto out; | 562 | goto out; |
563 | iph = (struct iphdr *)skb->data; | ||
564 | if (iph->ihl < 5 || iph->version != 4) | 564 | if (iph->ihl < 5 || iph->version != 4) |
565 | goto out; | 565 | goto out; |
566 | if (!pskb_may_pull(skb, iph->ihl*4)) | 566 | if (!pskb_may_pull(skb, iph->ihl*4)) |
567 | goto out; | 567 | goto out; |
568 | iph = (struct iphdr *)skb->data; | ||
568 | if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) | 569 | if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) |
569 | goto out; | 570 | goto out; |
570 | 571 | ||
@@ -579,6 +580,7 @@ int __netpoll_rx(struct sk_buff *skb) | |||
579 | if (pskb_trim_rcsum(skb, len)) | 580 | if (pskb_trim_rcsum(skb, len)) |
580 | goto out; | 581 | goto out; |
581 | 582 | ||
583 | iph = (struct iphdr *)skb->data; | ||
582 | if (iph->protocol != IPPROTO_UDP) | 584 | if (iph->protocol != IPPROTO_UDP) |
583 | goto out; | 585 | goto out; |
584 | 586 | ||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 296afd0aa8d2..5b2c5f1d4dba 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -613,8 +613,21 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src) | |||
613 | } | 613 | } |
614 | EXPORT_SYMBOL_GPL(skb_morph); | 614 | EXPORT_SYMBOL_GPL(skb_morph); |
615 | 615 | ||
616 | /* skb frags copy userspace buffers to kernel */ | 616 | /* skb_copy_ubufs - copy userspace skb frags buffers to kernel |
617 | static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | 617 | * @skb: the skb to modify |
618 | * @gfp_mask: allocation priority | ||
619 | * | ||
620 | * This must be called on SKBTX_DEV_ZEROCOPY skb. | ||
621 | * It will copy all frags into kernel and drop the reference | ||
622 | * to userspace pages. | ||
623 | * | ||
624 | * If this function is called from an interrupt gfp_mask() must be | ||
625 | * %GFP_ATOMIC. | ||
626 | * | ||
627 | * Returns 0 on success or a negative error code on failure | ||
628 | * to allocate kernel memory to copy to. | ||
629 | */ | ||
630 | int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | ||
618 | { | 631 | { |
619 | int i; | 632 | int i; |
620 | int num_frags = skb_shinfo(skb)->nr_frags; | 633 | int num_frags = skb_shinfo(skb)->nr_frags; |
@@ -654,6 +667,8 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | |||
654 | skb_shinfo(skb)->frags[i - 1].page = head; | 667 | skb_shinfo(skb)->frags[i - 1].page = head; |
655 | head = (struct page *)head->private; | 668 | head = (struct page *)head->private; |
656 | } | 669 | } |
670 | |||
671 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
657 | return 0; | 672 | return 0; |
658 | } | 673 | } |
659 | 674 | ||
@@ -679,7 +694,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) | |||
679 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 694 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
680 | if (skb_copy_ubufs(skb, gfp_mask)) | 695 | if (skb_copy_ubufs(skb, gfp_mask)) |
681 | return NULL; | 696 | return NULL; |
682 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
683 | } | 697 | } |
684 | 698 | ||
685 | n = skb + 1; | 699 | n = skb + 1; |
@@ -805,7 +819,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) | |||
805 | n = NULL; | 819 | n = NULL; |
806 | goto out; | 820 | goto out; |
807 | } | 821 | } |
808 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
809 | } | 822 | } |
810 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 823 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
811 | skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; | 824 | skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; |
@@ -898,7 +911,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
898 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 911 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
899 | if (skb_copy_ubufs(skb, gfp_mask)) | 912 | if (skb_copy_ubufs(skb, gfp_mask)) |
900 | goto nofrags; | 913 | goto nofrags; |
901 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
902 | } | 914 | } |
903 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | 915 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) |
904 | skb_frag_ref(skb, i); | 916 | skb_frag_ref(skb, i); |