aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2014-03-30 00:28:21 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-31 16:26:40 -0400
commita50e233c50dbc881abaa0e4070789064e8d12d70 (patch)
tree5c4c25d28e0f08f258ff8304fd4582658c1a0780 /net/core
parentbf39b4247b8799935ea91d90db250ab608a58e50 (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.c96
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
3862static 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
3862static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) 3883static 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
3940pull: 3961pull:
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
3962ok: 3965ok:
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}
4031EXPORT_SYMBOL(napi_gro_receive); 4036EXPORT_SYMBOL(napi_gro_receive);
@@ -4054,12 +4059,16 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi)
4054} 4059}
4055EXPORT_SYMBOL(napi_get_frags); 4060EXPORT_SYMBOL(napi_get_frags);
4056 4061
4057static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, 4062static 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 */
4079static struct sk_buff *napi_frags_skb(struct napi_struct *napi) 4091static 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}