diff options
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); |
