aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-12-16 02:42:33 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-16 02:42:33 -0500
commit71d93b39e52e92aea35f1058d957cf12250d0b75 (patch)
tree270e3fe674d15467454504a99af2146c0324e08b /net
parent73cc19f1556b95976934de236fd9043f7208844f (diff)
net: Add skb_gro_receive
This patch adds the helper skb_gro_receive to merge packets for GRO. The current method is to allocate a new header skb and then chain the original packets to its frag_list. This is done to make it easier to integrate into the existing GSO framework. In future as GSO is moved into the drivers, we can undo this and simply chain the original packets together. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/skbuff.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 18e224af05a6..b8d0abb26433 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2582,6 +2582,65 @@ err:
2582 2582
2583EXPORT_SYMBOL_GPL(skb_segment); 2583EXPORT_SYMBOL_GPL(skb_segment);
2584 2584
2585int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2586{
2587 struct sk_buff *p = *head;
2588 struct sk_buff *nskb;
2589 unsigned int headroom;
2590 unsigned int hlen = p->data - skb_mac_header(p);
2591
2592 if (hlen + p->len + skb->len >= 65536)
2593 return -E2BIG;
2594
2595 if (skb_shinfo(p)->frag_list)
2596 goto merge;
2597
2598 headroom = skb_headroom(p);
2599 nskb = netdev_alloc_skb(p->dev, headroom);
2600 if (unlikely(!nskb))
2601 return -ENOMEM;
2602
2603 __copy_skb_header(nskb, p);
2604 nskb->mac_len = p->mac_len;
2605
2606 skb_reserve(nskb, headroom);
2607
2608 skb_set_mac_header(nskb, -hlen);
2609 skb_set_network_header(nskb, skb_network_offset(p));
2610 skb_set_transport_header(nskb, skb_transport_offset(p));
2611
2612 memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen);
2613
2614 *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
2615 skb_shinfo(nskb)->frag_list = p;
2616 skb_header_release(p);
2617 nskb->prev = p;
2618
2619 nskb->data_len += p->len;
2620 nskb->truesize += p->len;
2621 nskb->len += p->len;
2622
2623 *head = nskb;
2624 nskb->next = p->next;
2625 p->next = NULL;
2626
2627 p = nskb;
2628
2629merge:
2630 NAPI_GRO_CB(p)->count++;
2631 p->prev->next = skb;
2632 p->prev = skb;
2633 skb_header_release(skb);
2634
2635 p->data_len += skb->len;
2636 p->truesize += skb->len;
2637 p->len += skb->len;
2638
2639 NAPI_GRO_CB(skb)->same_flow = 1;
2640 return 0;
2641}
2642EXPORT_SYMBOL_GPL(skb_gro_receive);
2643
2585void __init skb_init(void) 2644void __init skb_init(void)
2586{ 2645{
2587 skbuff_head_cache = kmem_cache_create("skbuff_head_cache", 2646 skbuff_head_cache = kmem_cache_create("skbuff_head_cache",