Commit 71d93b39 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 73cc19f1
...@@ -1687,6 +1687,8 @@ extern int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, ...@@ -1687,6 +1687,8 @@ extern int skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
int shiftlen); int shiftlen);
extern struct sk_buff *skb_segment(struct sk_buff *skb, int features); extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
extern int skb_gro_receive(struct sk_buff **head,
struct sk_buff *skb);
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer) int len, void *buffer)
......
...@@ -2582,6 +2582,65 @@ err: ...@@ -2582,6 +2582,65 @@ err:
EXPORT_SYMBOL_GPL(skb_segment); EXPORT_SYMBOL_GPL(skb_segment);
int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
{
struct sk_buff *p = *head;
struct sk_buff *nskb;
unsigned int headroom;
unsigned int hlen = p->data - skb_mac_header(p);
if (hlen + p->len + skb->len >= 65536)
return -E2BIG;
if (skb_shinfo(p)->frag_list)
goto merge;
headroom = skb_headroom(p);
nskb = netdev_alloc_skb(p->dev, headroom);
if (unlikely(!nskb))
return -ENOMEM;
__copy_skb_header(nskb, p);
nskb->mac_len = p->mac_len;
skb_reserve(nskb, headroom);
skb_set_mac_header(nskb, -hlen);
skb_set_network_header(nskb, skb_network_offset(p));
skb_set_transport_header(nskb, skb_transport_offset(p));
memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen);
*NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
skb_shinfo(nskb)->frag_list = p;
skb_header_release(p);
nskb->prev = p;
nskb->data_len += p->len;
nskb->truesize += p->len;
nskb->len += p->len;
*head = nskb;
nskb->next = p->next;
p->next = NULL;
p = nskb;
merge:
NAPI_GRO_CB(p)->count++;
p->prev->next = skb;
p->prev = skb;
skb_header_release(skb);
p->data_len += skb->len;
p->truesize += skb->len;
p->len += skb->len;
NAPI_GRO_CB(skb)->same_flow = 1;
return 0;
}
EXPORT_SYMBOL_GPL(skb_gro_receive);
void __init skb_init(void) void __init skb_init(void)
{ {
skbuff_head_cache = kmem_cache_create("skbuff_head_cache", skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment