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 17d67b579beb..b10ff0a71855 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -1515,6 +1515,14 @@ static inline bool is_skb_forwardable(struct net_device *dev, | |||
| 1515 | */ | 1515 | */ |
| 1516 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) | 1516 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) |
| 1517 | { | 1517 | { |
| 1518 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | ||
| 1519 | if (skb_copy_ubufs(skb, GFP_ATOMIC)) { | ||
| 1520 | atomic_long_inc(&dev->rx_dropped); | ||
| 1521 | kfree_skb(skb); | ||
| 1522 | return NET_RX_DROP; | ||
| 1523 | } | ||
| 1524 | } | ||
| 1525 | |||
| 1518 | skb_orphan(skb); | 1526 | skb_orphan(skb); |
| 1519 | nf_reset(skb); | 1527 | nf_reset(skb); |
| 1520 | 1528 | ||
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index e7ab0c0285b5..3231b468bb72 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 8fab9b0bb203..1334d7e56f02 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
| @@ -1319,11 +1319,15 @@ static void neigh_proxy_process(unsigned long arg) | |||
| 1319 | 1319 | ||
| 1320 | if (tdif <= 0) { | 1320 | if (tdif <= 0) { |
| 1321 | struct net_device *dev = skb->dev; | 1321 | struct net_device *dev = skb->dev; |
| 1322 | |||
| 1322 | __skb_unlink(skb, &tbl->proxy_queue); | 1323 | __skb_unlink(skb, &tbl->proxy_queue); |
| 1323 | if (tbl->proxy_redo && netif_running(dev)) | 1324 | if (tbl->proxy_redo && netif_running(dev)) { |
| 1325 | rcu_read_lock(); | ||
| 1324 | tbl->proxy_redo(skb); | 1326 | tbl->proxy_redo(skb); |
| 1325 | else | 1327 | rcu_read_unlock(); |
| 1328 | } else { | ||
| 1326 | kfree_skb(skb); | 1329 | kfree_skb(skb); |
| 1330 | } | ||
| 1327 | 1331 | ||
| 1328 | dev_put(dev); | 1332 | dev_put(dev); |
| 1329 | } else if (!sched_next || tdif < sched_next) | 1333 | } else if (!sched_next || tdif < sched_next) |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index adf84dd8c7b5..52622517e0d8 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 27002dffe7ed..387703f56fce 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -611,8 +611,21 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src) | |||
| 611 | } | 611 | } |
| 612 | EXPORT_SYMBOL_GPL(skb_morph); | 612 | EXPORT_SYMBOL_GPL(skb_morph); |
| 613 | 613 | ||
| 614 | /* skb frags copy userspace buffers to kernel */ | 614 | /* skb_copy_ubufs - copy userspace skb frags buffers to kernel |
| 615 | static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | 615 | * @skb: the skb to modify |
| 616 | * @gfp_mask: allocation priority | ||
| 617 | * | ||
| 618 | * This must be called on SKBTX_DEV_ZEROCOPY skb. | ||
| 619 | * It will copy all frags into kernel and drop the reference | ||
| 620 | * to userspace pages. | ||
| 621 | * | ||
| 622 | * If this function is called from an interrupt gfp_mask() must be | ||
| 623 | * %GFP_ATOMIC. | ||
| 624 | * | ||
| 625 | * Returns 0 on success or a negative error code on failure | ||
| 626 | * to allocate kernel memory to copy to. | ||
| 627 | */ | ||
| 628 | int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | ||
| 616 | { | 629 | { |
| 617 | int i; | 630 | int i; |
| 618 | int num_frags = skb_shinfo(skb)->nr_frags; | 631 | int num_frags = skb_shinfo(skb)->nr_frags; |
| @@ -652,6 +665,8 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) | |||
| 652 | skb_shinfo(skb)->frags[i - 1].page = head; | 665 | skb_shinfo(skb)->frags[i - 1].page = head; |
| 653 | head = (struct page *)head->private; | 666 | head = (struct page *)head->private; |
| 654 | } | 667 | } |
| 668 | |||
| 669 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
| 655 | return 0; | 670 | return 0; |
| 656 | } | 671 | } |
| 657 | 672 | ||
| @@ -677,7 +692,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) | |||
| 677 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 692 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
| 678 | if (skb_copy_ubufs(skb, gfp_mask)) | 693 | if (skb_copy_ubufs(skb, gfp_mask)) |
| 679 | return NULL; | 694 | return NULL; |
| 680 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
| 681 | } | 695 | } |
| 682 | 696 | ||
| 683 | n = skb + 1; | 697 | n = skb + 1; |
| @@ -803,7 +817,6 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask) | |||
| 803 | n = NULL; | 817 | n = NULL; |
| 804 | goto out; | 818 | goto out; |
| 805 | } | 819 | } |
| 806 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
| 807 | } | 820 | } |
| 808 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | 821 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
| 809 | skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; | 822 | skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; |
| @@ -896,7 +909,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
| 896 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { | 909 | if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { |
| 897 | if (skb_copy_ubufs(skb, gfp_mask)) | 910 | if (skb_copy_ubufs(skb, gfp_mask)) |
| 898 | goto nofrags; | 911 | goto nofrags; |
| 899 | skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; | ||
| 900 | } | 912 | } |
| 901 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | 913 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) |
| 902 | get_page(skb_shinfo(skb)->frags[i].page); | 914 | get_page(skb_shinfo(skb)->frags[i].page); |
