aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-01-29 09:19:50 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-29 19:33:03 -0500
commit86911732d3996a9da07914b280621450111bb6da (patch)
treee787240d5ba869ddf4d0adfc3f9c69e0372e96ef /net/core/skbuff.c
parent5d0d9be8ef456afc6c3fb5f8aad06ef19b704b05 (diff)
gro: Avoid copying headers of unmerged packets
Unfortunately simplicity isn't always the best. The fraginfo interface turned out to be suboptimal. The problem was quite obvious. For every packet, we have to copy the headers from the frags structure into skb->head, even though for 99% of the packets this part is immediately thrown away after the merge. LRO didn't have this problem because it directly read the headers from the frags structure. This patch attempts to address this by creating an interface that allows GRO to access the headers in the first frag without having to copy it. Because all drivers that use frags place the headers in the first frag this optimisation should be enough. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2e5f2ca3bdcd..f9f4065a7e9b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2584,17 +2584,21 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2584 struct sk_buff *p = *head; 2584 struct sk_buff *p = *head;
2585 struct sk_buff *nskb; 2585 struct sk_buff *nskb;
2586 unsigned int headroom; 2586 unsigned int headroom;
2587 unsigned int hlen = p->data - skb_mac_header(p); 2587 unsigned int len = skb_gro_len(skb);
2588 unsigned int len = skb->len;
2589 2588
2590 if (hlen + p->len + len >= 65536) 2589 if (p->len + len >= 65536)
2591 return -E2BIG; 2590 return -E2BIG;
2592 2591
2593 if (skb_shinfo(p)->frag_list) 2592 if (skb_shinfo(p)->frag_list)
2594 goto merge; 2593 goto merge;
2595 else if (!skb_headlen(p) && !skb_headlen(skb) && 2594 else if (skb_headlen(skb) <= skb_gro_offset(skb) &&
2596 skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags < 2595 skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags <=
2597 MAX_SKB_FRAGS) { 2596 MAX_SKB_FRAGS) {
2597 skb_shinfo(skb)->frags[0].page_offset +=
2598 skb_gro_offset(skb) - skb_headlen(skb);
2599 skb_shinfo(skb)->frags[0].size -=
2600 skb_gro_offset(skb) - skb_headlen(skb);
2601
2598 memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags, 2602 memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags,
2599 skb_shinfo(skb)->frags, 2603 skb_shinfo(skb)->frags,
2600 skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); 2604 skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
@@ -2611,7 +2615,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2611 } 2615 }
2612 2616
2613 headroom = skb_headroom(p); 2617 headroom = skb_headroom(p);
2614 nskb = netdev_alloc_skb(p->dev, headroom); 2618 nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p));
2615 if (unlikely(!nskb)) 2619 if (unlikely(!nskb))
2616 return -ENOMEM; 2620 return -ENOMEM;
2617 2621
@@ -2619,12 +2623,15 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2619 nskb->mac_len = p->mac_len; 2623 nskb->mac_len = p->mac_len;
2620 2624
2621 skb_reserve(nskb, headroom); 2625 skb_reserve(nskb, headroom);
2626 __skb_put(nskb, skb_gro_offset(p));
2622 2627
2623 skb_set_mac_header(nskb, -hlen); 2628 skb_set_mac_header(nskb, skb_mac_header(p) - p->data);
2624 skb_set_network_header(nskb, skb_network_offset(p)); 2629 skb_set_network_header(nskb, skb_network_offset(p));
2625 skb_set_transport_header(nskb, skb_transport_offset(p)); 2630 skb_set_transport_header(nskb, skb_transport_offset(p));
2626 2631
2627 memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen); 2632 __skb_pull(p, skb_gro_offset(p));
2633 memcpy(skb_mac_header(nskb), skb_mac_header(p),
2634 p->data - skb_mac_header(p));
2628 2635
2629 *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p); 2636 *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
2630 skb_shinfo(nskb)->frag_list = p; 2637 skb_shinfo(nskb)->frag_list = p;