Skip to content

Commit a50e233

Browse files
edumazetdavem330
authored andcommitted
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 299603e ("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 <[email protected]> Fixes: 299603e ("net-gro: Prepare GRO stack for the upcoming tunneling support") Signed-off-by: Eric Dumazet <[email protected]> Cc: Jerry Chu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bf39b42 commit a50e233

File tree

2 files changed

+64
-37
lines changed

2 files changed

+64
-37
lines changed

include/linux/netdevice.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,11 +2014,6 @@ static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
20142014
return skb->data + offset;
20152015
}
20162016

2017-
static inline void *skb_gro_mac_header(struct sk_buff *skb)
2018-
{
2019-
return NAPI_GRO_CB(skb)->frag0 ?: skb_mac_header(skb);
2020-
}
2021-
20222017
static inline void *skb_gro_network_header(struct sk_buff *skb)
20232018
{
20242019
return (NAPI_GRO_CB(skb)->frag0 ?: skb->data) +

net/core/dev.c

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3833,10 +3833,10 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb)
38333833
diffs |= p->vlan_tci ^ skb->vlan_tci;
38343834
if (maclen == ETH_HLEN)
38353835
diffs |= compare_ether_header(skb_mac_header(p),
3836-
skb_gro_mac_header(skb));
3836+
skb_mac_header(skb));
38373837
else if (!diffs)
38383838
diffs = memcmp(skb_mac_header(p),
3839-
skb_gro_mac_header(skb),
3839+
skb_mac_header(skb),
38403840
maclen);
38413841
NAPI_GRO_CB(p)->same_flow = !diffs;
38423842
}
@@ -3859,6 +3859,27 @@ static void skb_gro_reset_offset(struct sk_buff *skb)
38593859
}
38603860
}
38613861

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+
38623883
static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
38633884
{
38643885
struct sk_buff **pp = NULL;
@@ -3867,14 +3888,14 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
38673888
struct list_head *head = &offload_base;
38683889
int same_flow;
38693890
enum gro_result ret;
3891+
int grow;
38703892

38713893
if (!(skb->dev->features & NETIF_F_GRO))
38723894
goto normal;
38733895

38743896
if (skb_is_gso(skb) || skb_has_frag_list(skb))
38753897
goto normal;
38763898

3877-
skb_gro_reset_offset(skb);
38783899
gro_list_prepare(napi, skb);
38793900
NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */
38803901

@@ -3938,27 +3959,9 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
39383959
ret = GRO_HELD;
39393960

39403961
pull:
3941-
if (skb_headlen(skb) < skb_gro_offset(skb)) {
3942-
int grow = skb_gro_offset(skb) - skb_headlen(skb);
3943-
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+
grow = skb_gro_offset(skb) - skb_headlen(skb);
3963+
if (grow > 0)
3964+
gro_pull_from_frag0(skb, grow);
39623965
ok:
39633966
return ret;
39643967

@@ -4026,6 +4029,8 @@ gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
40264029
{
40274030
trace_napi_gro_receive_entry(skb);
40284031

4032+
skb_gro_reset_offset(skb);
4033+
40294034
return napi_skb_finish(dev_gro_receive(napi, skb), skb);
40304035
}
40314036
EXPORT_SYMBOL(napi_gro_receive);
@@ -4054,12 +4059,16 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi)
40544059
}
40554060
EXPORT_SYMBOL(napi_get_frags);
40564061

4057-
static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb,
4058-
gro_result_t ret)
4062+
static gro_result_t napi_frags_finish(struct napi_struct *napi,
4063+
struct sk_buff *skb,
4064+
gro_result_t ret)
40594065
{
40604066
switch (ret) {
40614067
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))
40634072
ret = GRO_DROP;
40644073
break;
40654074

@@ -4068,25 +4077,48 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *
40684077
napi_reuse_skb(napi, skb);
40694078
break;
40704079

4071-
case GRO_HELD:
40724080
case GRO_MERGED:
40734081
break;
40744082
}
40754083

40764084
return ret;
40774085
}
40784086

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+
*/
40794091
static struct sk_buff *napi_frags_skb(struct napi_struct *napi)
40804092
{
40814093
struct sk_buff *skb = napi->skb;
4094+
const struct ethhdr *eth;
4095+
unsigned int hlen = sizeof(*eth);
40824096

40834097
napi->skb = NULL;
40844098

4085-
if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) {
4086-
napi_reuse_skb(napi, skb);
4087-
return NULL;
4099+
skb_reset_mac_header(skb);
4100+
skb_gro_reset_offset(skb);
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;
40884113
}
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;
40904122

40914123
return skb;
40924124
}

0 commit comments

Comments
 (0)