diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2009-04-16 05:02:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-16 05:02:07 -0400 |
commit | 76620aafd66f0004829764940c5466144969cffc (patch) | |
tree | 38041e6938121b5611546c582cd23f289db047b0 /net/core | |
parent | 861ab44059350e5cab350238606cf8814abab93b (diff) |
gro: New frags interface to avoid copying shinfo
It turns out that copying a 16-byte area at ~800k times a second
can be really expensive :) This patch redesigns the frags GRO
interface to avoid copying that area twice.
The two disciples of the frags interface have been converted.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 81 |
1 files changed, 36 insertions, 45 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 91d792d17e09..619fa141b8f5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2519,16 +2519,10 @@ void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) | |||
2519 | } | 2519 | } |
2520 | EXPORT_SYMBOL(napi_reuse_skb); | 2520 | EXPORT_SYMBOL(napi_reuse_skb); |
2521 | 2521 | ||
2522 | struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi, | 2522 | struct sk_buff *napi_get_frags(struct napi_struct *napi) |
2523 | struct napi_gro_fraginfo *info) | ||
2524 | { | 2523 | { |
2525 | struct net_device *dev = napi->dev; | 2524 | struct net_device *dev = napi->dev; |
2526 | struct sk_buff *skb = napi->skb; | 2525 | struct sk_buff *skb = napi->skb; |
2527 | struct ethhdr *eth; | ||
2528 | skb_frag_t *frag; | ||
2529 | int i; | ||
2530 | |||
2531 | napi->skb = NULL; | ||
2532 | 2526 | ||
2533 | if (!skb) { | 2527 | if (!skb) { |
2534 | skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN); | 2528 | skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN); |
@@ -2536,47 +2530,14 @@ struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi, | |||
2536 | goto out; | 2530 | goto out; |
2537 | 2531 | ||
2538 | skb_reserve(skb, NET_IP_ALIGN); | 2532 | skb_reserve(skb, NET_IP_ALIGN); |
2539 | } | ||
2540 | |||
2541 | BUG_ON(info->nr_frags > MAX_SKB_FRAGS); | ||
2542 | frag = &info->frags[info->nr_frags - 1]; | ||
2543 | 2533 | ||
2544 | for (i = skb_shinfo(skb)->nr_frags; i < info->nr_frags; i++) { | 2534 | napi->skb = skb; |
2545 | skb_fill_page_desc(skb, i, frag->page, frag->page_offset, | ||
2546 | frag->size); | ||
2547 | frag++; | ||
2548 | } | 2535 | } |
2549 | skb_shinfo(skb)->nr_frags = info->nr_frags; | ||
2550 | |||
2551 | skb->data_len = info->len; | ||
2552 | skb->len += info->len; | ||
2553 | skb->truesize += info->len; | ||
2554 | |||
2555 | skb_reset_mac_header(skb); | ||
2556 | skb_gro_reset_offset(skb); | ||
2557 | |||
2558 | eth = skb_gro_header(skb, sizeof(*eth)); | ||
2559 | if (!eth) { | ||
2560 | napi_reuse_skb(napi, skb); | ||
2561 | skb = NULL; | ||
2562 | goto out; | ||
2563 | } | ||
2564 | |||
2565 | skb_gro_pull(skb, sizeof(*eth)); | ||
2566 | |||
2567 | /* | ||
2568 | * This works because the only protocols we care about don't require | ||
2569 | * special handling. We'll fix it up properly at the end. | ||
2570 | */ | ||
2571 | skb->protocol = eth->h_proto; | ||
2572 | |||
2573 | skb->ip_summed = info->ip_summed; | ||
2574 | skb->csum = info->csum; | ||
2575 | 2536 | ||
2576 | out: | 2537 | out: |
2577 | return skb; | 2538 | return skb; |
2578 | } | 2539 | } |
2579 | EXPORT_SYMBOL(napi_fraginfo_skb); | 2540 | EXPORT_SYMBOL(napi_get_frags); |
2580 | 2541 | ||
2581 | int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) | 2542 | int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) |
2582 | { | 2543 | { |
@@ -2606,9 +2567,39 @@ int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) | |||
2606 | } | 2567 | } |
2607 | EXPORT_SYMBOL(napi_frags_finish); | 2568 | EXPORT_SYMBOL(napi_frags_finish); |
2608 | 2569 | ||
2609 | int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info) | 2570 | struct sk_buff *napi_frags_skb(struct napi_struct *napi) |
2571 | { | ||
2572 | struct sk_buff *skb = napi->skb; | ||
2573 | struct ethhdr *eth; | ||
2574 | |||
2575 | napi->skb = NULL; | ||
2576 | |||
2577 | skb_reset_mac_header(skb); | ||
2578 | skb_gro_reset_offset(skb); | ||
2579 | |||
2580 | eth = skb_gro_header(skb, sizeof(*eth)); | ||
2581 | if (!eth) { | ||
2582 | napi_reuse_skb(napi, skb); | ||
2583 | skb = NULL; | ||
2584 | goto out; | ||
2585 | } | ||
2586 | |||
2587 | skb_gro_pull(skb, sizeof(*eth)); | ||
2588 | |||
2589 | /* | ||
2590 | * This works because the only protocols we care about don't require | ||
2591 | * special handling. We'll fix it up properly at the end. | ||
2592 | */ | ||
2593 | skb->protocol = eth->h_proto; | ||
2594 | |||
2595 | out: | ||
2596 | return skb; | ||
2597 | } | ||
2598 | EXPORT_SYMBOL(napi_frags_skb); | ||
2599 | |||
2600 | int napi_gro_frags(struct napi_struct *napi) | ||
2610 | { | 2601 | { |
2611 | struct sk_buff *skb = napi_fraginfo_skb(napi, info); | 2602 | struct sk_buff *skb = napi_frags_skb(napi); |
2612 | 2603 | ||
2613 | if (!skb) | 2604 | if (!skb) |
2614 | return NET_RX_DROP; | 2605 | return NET_RX_DROP; |
@@ -2712,7 +2703,7 @@ void netif_napi_del(struct napi_struct *napi) | |||
2712 | struct sk_buff *skb, *next; | 2703 | struct sk_buff *skb, *next; |
2713 | 2704 | ||
2714 | list_del_init(&napi->dev_list); | 2705 | list_del_init(&napi->dev_list); |
2715 | kfree_skb(napi->skb); | 2706 | napi_free_frags(napi); |
2716 | 2707 | ||
2717 | for (skb = napi->gro_list; skb; skb = next) { | 2708 | for (skb = napi->gro_list; skb; skb = next) { |
2718 | next = skb->next; | 2709 | next = skb->next; |