diff options
| author | Eric Dumazet <edumazet@google.com> | 2014-09-29 01:18:47 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-09-29 12:27:20 -0400 |
| commit | b1937227316417aa7568d01e6fa1f272e98fb890 (patch) | |
| tree | 93891f7672c803b767de6621c028f45edf242f17 /net/core | |
| parent | 842abe08aa6f81f1062cf9624e9f6afc117d73e4 (diff) | |
net: reorganize sk_buff for faster __copy_skb_header()
With proliferation of bit fields in sk_buff, __copy_skb_header() became
quite expensive, showing as the most expensive function in a GSO
workload.
__copy_skb_header() performance is also critical for non GSO TCP
operations, as it is used from skb_clone()
This patch carefully moves all the fields that were not copied in a
separate zone : cloned, nohdr, fclone, peeked, head_frag, xmit_more
Then I moved all other fields and all other copied fields in a section
delimited by headers_start[0]/headers_end[0] section so that we
can use a single memcpy() call, inlined by compiler using long
word load/stores.
I also tried to make all copies in the natural orders of sk_buff,
to help hardware prefetching.
I made sure sk_buff size did not change.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/skbuff.c | 80 |
1 files changed, 41 insertions, 39 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d4fdc649112c..4be570a4ab21 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -261,7 +261,6 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, | |||
| 261 | atomic_t *fclone_ref = (atomic_t *) (child + 1); | 261 | atomic_t *fclone_ref = (atomic_t *) (child + 1); |
| 262 | 262 | ||
| 263 | kmemcheck_annotate_bitfield(child, flags1); | 263 | kmemcheck_annotate_bitfield(child, flags1); |
| 264 | kmemcheck_annotate_bitfield(child, flags2); | ||
| 265 | skb->fclone = SKB_FCLONE_ORIG; | 264 | skb->fclone = SKB_FCLONE_ORIG; |
| 266 | atomic_set(fclone_ref, 1); | 265 | atomic_set(fclone_ref, 1); |
| 267 | 266 | ||
| @@ -675,57 +674,61 @@ void consume_skb(struct sk_buff *skb) | |||
| 675 | } | 674 | } |
| 676 | EXPORT_SYMBOL(consume_skb); | 675 | EXPORT_SYMBOL(consume_skb); |
| 677 | 676 | ||
| 677 | /* Make sure a field is enclosed inside headers_start/headers_end section */ | ||
| 678 | #define CHECK_SKB_FIELD(field) \ | ||
| 679 | BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ | ||
| 680 | offsetof(struct sk_buff, headers_start)); \ | ||
| 681 | BUILD_BUG_ON(offsetof(struct sk_buff, field) > \ | ||
| 682 | offsetof(struct sk_buff, headers_end)); \ | ||
| 683 | |||
| 678 | static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) | 684 | static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) |
| 679 | { | 685 | { |
| 680 | new->tstamp = old->tstamp; | 686 | new->tstamp = old->tstamp; |
| 687 | /* We do not copy old->sk */ | ||
| 681 | new->dev = old->dev; | 688 | new->dev = old->dev; |
| 682 | new->transport_header = old->transport_header; | 689 | memcpy(new->cb, old->cb, sizeof(old->cb)); |
| 683 | new->network_header = old->network_header; | ||
| 684 | new->mac_header = old->mac_header; | ||
| 685 | new->inner_protocol = old->inner_protocol; | ||
| 686 | new->inner_transport_header = old->inner_transport_header; | ||
| 687 | new->inner_network_header = old->inner_network_header; | ||
| 688 | new->inner_mac_header = old->inner_mac_header; | ||
| 689 | skb_dst_copy(new, old); | 690 | skb_dst_copy(new, old); |
| 690 | skb_copy_hash(new, old); | ||
| 691 | new->ooo_okay = old->ooo_okay; | ||
| 692 | new->no_fcs = old->no_fcs; | ||
| 693 | new->encapsulation = old->encapsulation; | ||
| 694 | new->encap_hdr_csum = old->encap_hdr_csum; | ||
| 695 | new->csum_valid = old->csum_valid; | ||
| 696 | new->csum_complete_sw = old->csum_complete_sw; | ||
| 697 | #ifdef CONFIG_XFRM | 691 | #ifdef CONFIG_XFRM |
| 698 | new->sp = secpath_get(old->sp); | 692 | new->sp = secpath_get(old->sp); |
| 699 | #endif | 693 | #endif |
| 700 | memcpy(new->cb, old->cb, sizeof(old->cb)); | 694 | __nf_copy(new, old, false); |
| 701 | new->csum = old->csum; | 695 | |
| 702 | new->ignore_df = old->ignore_df; | 696 | /* Note : this field could be in headers_start/headers_end section |
| 703 | new->pkt_type = old->pkt_type; | 697 | * It is not yet because we do not want to have a 16 bit hole |
| 704 | new->ip_summed = old->ip_summed; | 698 | */ |
| 705 | skb_copy_queue_mapping(new, old); | 699 | new->queue_mapping = old->queue_mapping; |
| 706 | new->priority = old->priority; | 700 | |
| 707 | #if IS_ENABLED(CONFIG_IP_VS) | 701 | memcpy(&new->headers_start, &old->headers_start, |
| 708 | new->ipvs_property = old->ipvs_property; | 702 | offsetof(struct sk_buff, headers_end) - |
| 703 | offsetof(struct sk_buff, headers_start)); | ||
| 704 | CHECK_SKB_FIELD(protocol); | ||
| 705 | CHECK_SKB_FIELD(csum); | ||
| 706 | CHECK_SKB_FIELD(hash); | ||
| 707 | CHECK_SKB_FIELD(priority); | ||
| 708 | CHECK_SKB_FIELD(skb_iif); | ||
| 709 | CHECK_SKB_FIELD(vlan_proto); | ||
| 710 | CHECK_SKB_FIELD(vlan_tci); | ||
| 711 | CHECK_SKB_FIELD(transport_header); | ||
| 712 | CHECK_SKB_FIELD(network_header); | ||
| 713 | CHECK_SKB_FIELD(mac_header); | ||
| 714 | CHECK_SKB_FIELD(inner_protocol); | ||
| 715 | CHECK_SKB_FIELD(inner_transport_header); | ||
| 716 | CHECK_SKB_FIELD(inner_network_header); | ||
| 717 | CHECK_SKB_FIELD(inner_mac_header); | ||
| 718 | CHECK_SKB_FIELD(mark); | ||
| 719 | #ifdef CONFIG_NETWORK_SECMARK | ||
| 720 | CHECK_SKB_FIELD(secmark); | ||
| 721 | #endif | ||
| 722 | #ifdef CONFIG_NET_RX_BUSY_POLL | ||
| 723 | CHECK_SKB_FIELD(napi_id); | ||
| 709 | #endif | 724 | #endif |
| 710 | new->pfmemalloc = old->pfmemalloc; | ||
| 711 | new->protocol = old->protocol; | ||
| 712 | new->mark = old->mark; | ||
| 713 | new->skb_iif = old->skb_iif; | ||
| 714 | __nf_copy(new, old); | ||
| 715 | #ifdef CONFIG_NET_SCHED | 725 | #ifdef CONFIG_NET_SCHED |
| 716 | new->tc_index = old->tc_index; | 726 | CHECK_SKB_FIELD(tc_index); |
| 717 | #ifdef CONFIG_NET_CLS_ACT | 727 | #ifdef CONFIG_NET_CLS_ACT |
| 718 | new->tc_verd = old->tc_verd; | 728 | CHECK_SKB_FIELD(tc_verd); |
| 719 | #endif | 729 | #endif |
| 720 | #endif | 730 | #endif |
| 721 | new->vlan_proto = old->vlan_proto; | ||
| 722 | new->vlan_tci = old->vlan_tci; | ||
| 723 | |||
| 724 | skb_copy_secmark(new, old); | ||
| 725 | 731 | ||
| 726 | #ifdef CONFIG_NET_RX_BUSY_POLL | ||
| 727 | new->napi_id = old->napi_id; | ||
| 728 | #endif | ||
| 729 | } | 732 | } |
| 730 | 733 | ||
| 731 | /* | 734 | /* |
| @@ -876,7 +879,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) | |||
| 876 | return NULL; | 879 | return NULL; |
| 877 | 880 | ||
| 878 | kmemcheck_annotate_bitfield(n, flags1); | 881 | kmemcheck_annotate_bitfield(n, flags1); |
| 879 | kmemcheck_annotate_bitfield(n, flags2); | ||
| 880 | n->fclone = SKB_FCLONE_UNAVAILABLE; | 882 | n->fclone = SKB_FCLONE_UNAVAILABLE; |
| 881 | } | 883 | } |
| 882 | 884 | ||
