diff options
author | Eric Dumazet <edumazet@google.com> | 2014-03-30 00:28:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-31 16:26:40 -0400 |
commit | a50e233c50dbc881abaa0e4070789064e8d12d70 (patch) | |
tree | 5c4c25d28e0f08f258ff8304fd4582658c1a0780 /net/core | |
parent | bf39b4247b8799935ea91d90db250ab608a58e50 (diff) |
net-gro: restore frag0 optimization
Main difference between napi_frags_skb() and napi_gro_receive() is that
the later is called while ethernet header was already pulled by the NIC
driver (eth_type_trans() was called before napi_gro_receive())
Jerry Chu in commit 299603e8370a ("net-gro: Prepare GRO stack for the
upcoming tunneling support") tried to remove this difference by calling
eth_type_trans() from napi_frags_skb() instead of doing this later from
napi_frags_finish()
Goal was that napi_gro_complete() could call
ptype->callbacks.gro_complete(skb, 0) (offset of first network header =
0)
Also, xxx_gro_receive() handlers all use off = skb_gro_offset(skb) to
point to their own header, for the current skb and ones held in gro_list
Problem is this cleanup work defeated the frag0 optimization:
It turns out the consecutive pskb_may_pull() calls are too expensive.
This patch brings back the frag0 stuff in napi_frags_skb().
As all skb have their mac header in skb head, we no longer need
skb_gro_mac_header()
Reported-by: Michal Schmidt <mschmidt@redhat.com>
Fixes: 299603e8370a ("net-gro: Prepare GRO stack for the upcoming tunneling support")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jerry Chu <hkchu@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 96 |
1 files changed, 64 insertions, 32 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index a923eed976ae..48d81e4a256e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3833,10 +3833,10 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) | |||
3833 | diffs |= p->vlan_tci ^ skb->vlan_tci; | 3833 | diffs |= p->vlan_tci ^ skb->vlan_tci; |
3834 | if (maclen == ETH_HLEN) | 3834 | if (maclen == ETH_HLEN) |
3835 | diffs |= compare_ether_header(skb_mac_header(p), | 3835 | diffs |= compare_ether_header(skb_mac_header(p), |
3836 | skb_gro_mac_header(skb)); | 3836 | skb_mac_header(skb)); |
3837 | else if (!diffs) | 3837 | else if (!diffs) |
3838 | diffs = memcmp(skb_mac_header(p), | 3838 | diffs = memcmp(skb_mac_header(p), |
3839 | skb_gro_mac_header(skb), | 3839 | skb_mac_header(skb), |
3840 | maclen); | 3840 | maclen); |
3841 | NAPI_GRO_CB(p)->same_flow = !diffs; | 3841 | NAPI_GRO_CB(p)->same_flow = !diffs; |
3842 | } | 3842 | } |
@@ -3859,6 +3859,27 @@ static void skb_gro_reset_offset(struct sk_buff *skb) | |||
3859 | } | 3859 | } |
3860 | } | 3860 | } |
3861 | 3861 | ||
3862 | static void gro_pull_from_frag0(struct sk_buff *skb, int grow) | ||
3863 | { | ||
3864 | struct skb_shared_info *pinfo = skb_shinfo(skb); | ||
3865 | |||
3866 | BUG_ON(skb->end - skb->tail < grow); | ||
3867 | |||
3868 | memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow); | ||
3869 | |||
3870 | skb->data_len -= grow; | ||
3871 | skb->tail += grow; | ||
3872 | |||
3873 | pinfo->frags[0].page_offset += grow; | ||
3874 | skb_frag_size_sub(&pinfo->frags[0], grow); | ||
3875 | |||
3876 | if (unlikely(!skb_frag_size(&pinfo->frags[0]))) { | ||
3877 | skb_frag_unref(skb, 0); | ||
3878 | memmove(pinfo->frags, pinfo->frags + 1, | ||
3879 | --pinfo->nr_frags * sizeof(pinfo->frags[0])); | ||
3880 | } | ||
3881 | } | ||
3882 | |||
3862 | static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | 3883 | static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
3863 | { | 3884 | { |
3864 | struct sk_buff **pp = NULL; | 3885 | struct sk_buff **pp = NULL; |
@@ -3867,6 +3888,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
3867 | struct list_head *head = &offload_base; | 3888 | struct list_head *head = &offload_base; |
3868 | int same_flow; | 3889 | int same_flow; |
3869 | enum gro_result ret; | 3890 | enum gro_result ret; |
3891 | int grow; | ||
3870 | 3892 | ||
3871 | if (!(skb->dev->features & NETIF_F_GRO)) | 3893 | if (!(skb->dev->features & NETIF_F_GRO)) |
3872 | goto normal; | 3894 | goto normal; |
@@ -3874,7 +3896,6 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
3874 | if (skb_is_gso(skb) || skb_has_frag_list(skb)) | 3896 | if (skb_is_gso(skb) || skb_has_frag_list(skb)) |
3875 | goto normal; | 3897 | goto normal; |
3876 | 3898 | ||
3877 | skb_gro_reset_offset(skb); | ||
3878 | gro_list_prepare(napi, skb); | 3899 | gro_list_prepare(napi, skb); |
3879 | NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */ | 3900 | NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */ |
3880 | 3901 | ||
@@ -3938,27 +3959,9 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff | |||
3938 | ret = GRO_HELD; | 3959 | ret = GRO_HELD; |
3939 | 3960 | ||
3940 | pull: | 3961 | pull: |
3941 | if (skb_headlen(skb) < skb_gro_offset(skb)) { | 3962 | grow = skb_gro_offset(skb) - skb_headlen(skb); |
3942 | int grow = skb_gro_offset(skb) - skb_headlen(skb); | 3963 | if (grow > 0) |
3943 | 3964 | gro_pull_from_frag0(skb, grow); | |
3944 | BUG_ON(skb->end - skb->tail < grow); | ||
3945 | |||
3946 | memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow); | ||
3947 | |||
3948 | skb->tail += grow; | ||
3949 | skb->data_len -= grow; | ||
3950 | |||
3951 | skb_shinfo(skb)->frags[0].page_offset += grow; | ||
3952 | skb_frag_size_sub(&skb_shinfo(skb)->frags[0], grow); | ||
3953 | |||
3954 | if (unlikely(!skb_frag_size(&skb_shinfo(skb)->frags[0]))) { | ||
3955 | skb_frag_unref(skb, 0); | ||
3956 | memmove(skb_shinfo(skb)->frags, | ||
3957 | skb_shinfo(skb)->frags + 1, | ||
3958 | --skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); | ||
3959 | } | ||
3960 | } | ||
3961 | |||
3962 | ok: | 3965 | ok: |
3963 | return ret; | 3966 | return ret; |
3964 | 3967 | ||
@@ -4026,6 +4029,8 @@ gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) | |||
4026 | { | 4029 | { |
4027 | trace_napi_gro_receive_entry(skb); | 4030 | trace_napi_gro_receive_entry(skb); |
4028 | 4031 | ||
4032 | skb_gro_reset_offset(skb); | ||
4033 | |||
4029 | return napi_skb_finish(dev_gro_receive(napi, skb), skb); | 4034 | return napi_skb_finish(dev_gro_receive(napi, skb), skb); |
4030 | } | 4035 | } |
4031 | EXPORT_SYMBOL(napi_gro_receive); | 4036 | EXPORT_SYMBOL(napi_gro_receive); |
@@ -4054,12 +4059,16 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi) | |||
4054 | } | 4059 | } |
4055 | EXPORT_SYMBOL(napi_get_frags); | 4060 | EXPORT_SYMBOL(napi_get_frags); |
4056 | 4061 | ||
4057 | static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, | 4062 | static gro_result_t napi_frags_finish(struct napi_struct *napi, |
4058 | gro_result_t ret) | 4063 | struct sk_buff *skb, |
4064 | gro_result_t ret) | ||
4059 | { | 4065 | { |
4060 | switch (ret) { | 4066 | switch (ret) { |
4061 | case GRO_NORMAL: | 4067 | case GRO_NORMAL: |
4062 | if (netif_receive_skb_internal(skb)) | 4068 | case GRO_HELD: |
4069 | __skb_push(skb, ETH_HLEN); | ||
4070 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
4071 | if (ret == GRO_NORMAL && netif_receive_skb_internal(skb)) | ||
4063 | ret = GRO_DROP; | 4072 | ret = GRO_DROP; |
4064 | break; | 4073 | break; |
4065 | 4074 | ||
@@ -4068,7 +4077,6 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * | |||
4068 | napi_reuse_skb(napi, skb); | 4077 | napi_reuse_skb(napi, skb); |
4069 | break; | 4078 | break; |
4070 | 4079 | ||
4071 | case GRO_HELD: | ||
4072 | case GRO_MERGED: | 4080 | case GRO_MERGED: |
4073 | break; | 4081 | break; |
4074 | } | 4082 | } |
@@ -4076,17 +4084,41 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * | |||
4076 | return ret; | 4084 | return ret; |
4077 | } | 4085 | } |
4078 | 4086 | ||
4087 | /* Upper GRO stack assumes network header starts at gro_offset=0 | ||
4088 | * Drivers could call both napi_gro_frags() and napi_gro_receive() | ||
4089 | * We copy ethernet header into skb->data to have a common layout. | ||
4090 | */ | ||
4079 | static struct sk_buff *napi_frags_skb(struct napi_struct *napi) | 4091 | static struct sk_buff *napi_frags_skb(struct napi_struct *napi) |
4080 | { | 4092 | { |
4081 | struct sk_buff *skb = napi->skb; | 4093 | struct sk_buff *skb = napi->skb; |
4094 | const struct ethhdr *eth; | ||
4095 | unsigned int hlen = sizeof(*eth); | ||
4082 | 4096 | ||
4083 | napi->skb = NULL; | 4097 | napi->skb = NULL; |
4084 | 4098 | ||
4085 | if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) { | 4099 | skb_reset_mac_header(skb); |
4086 | napi_reuse_skb(napi, skb); | 4100 | skb_gro_reset_offset(skb); |
4087 | return NULL; | 4101 | |
4102 | eth = skb_gro_header_fast(skb, 0); | ||
4103 | if (unlikely(skb_gro_header_hard(skb, hlen))) { | ||
4104 | eth = skb_gro_header_slow(skb, hlen, 0); | ||
4105 | if (unlikely(!eth)) { | ||
4106 | napi_reuse_skb(napi, skb); | ||
4107 | return NULL; | ||
4108 | } | ||
4109 | } else { | ||
4110 | gro_pull_from_frag0(skb, hlen); | ||
4111 | NAPI_GRO_CB(skb)->frag0 += hlen; | ||
4112 | NAPI_GRO_CB(skb)->frag0_len -= hlen; | ||
4088 | } | 4113 | } |
4089 | skb->protocol = eth_type_trans(skb, skb->dev); | 4114 | __skb_pull(skb, hlen); |
4115 | |||
4116 | /* | ||
4117 | * This works because the only protocols we care about don't require | ||
4118 | * special handling. | ||
4119 | * We'll fix it up properly in napi_frags_finish() | ||
4120 | */ | ||
4121 | skb->protocol = eth->h_proto; | ||
4090 | 4122 | ||
4091 | return skb; | 4123 | return skb; |
4092 | } | 4124 | } |