gro: Avoid unnecessary comparison after skb_gro_header
For the overwhelming majority of cases, skb_gro_header's return value cannot be NULL. Yet we must check it because of its current form. This patch splits it up into multiple functions in order to avoid this. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
7489594cb2
commit
a5b1cf288d
@ -1132,20 +1132,25 @@ static inline void skb_gro_pull(struct sk_buff *skb, unsigned int len)
|
|||||||
NAPI_GRO_CB(skb)->data_offset += len;
|
NAPI_GRO_CB(skb)->data_offset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *skb_gro_header(struct sk_buff *skb, unsigned int hlen)
|
static inline void *skb_gro_header_fast(struct sk_buff *skb,
|
||||||
|
unsigned int offset)
|
||||||
{
|
{
|
||||||
unsigned int offset = skb_gro_offset(skb);
|
|
||||||
|
|
||||||
hlen += offset;
|
|
||||||
if (NAPI_GRO_CB(skb)->frag0_len < hlen) {
|
|
||||||
NAPI_GRO_CB(skb)->frag0 = NULL;
|
|
||||||
NAPI_GRO_CB(skb)->frag0_len = 0;
|
|
||||||
return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NAPI_GRO_CB(skb)->frag0 + offset;
|
return NAPI_GRO_CB(skb)->frag0 + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen)
|
||||||
|
{
|
||||||
|
return NAPI_GRO_CB(skb)->frag0_len < hlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
|
||||||
|
unsigned int offset)
|
||||||
|
{
|
||||||
|
NAPI_GRO_CB(skb)->frag0 = NULL;
|
||||||
|
NAPI_GRO_CB(skb)->frag0_len = 0;
|
||||||
|
return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void *skb_gro_mac_header(struct sk_buff *skb)
|
static inline void *skb_gro_mac_header(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
return NAPI_GRO_CB(skb)->frag0 ?: skb_mac_header(skb);
|
return NAPI_GRO_CB(skb)->frag0 ?: skb_mac_header(skb);
|
||||||
|
@ -2590,17 +2590,24 @@ struct sk_buff *napi_frags_skb(struct napi_struct *napi)
|
|||||||
{
|
{
|
||||||
struct sk_buff *skb = napi->skb;
|
struct sk_buff *skb = napi->skb;
|
||||||
struct ethhdr *eth;
|
struct ethhdr *eth;
|
||||||
|
unsigned int hlen;
|
||||||
|
unsigned int off;
|
||||||
|
|
||||||
napi->skb = NULL;
|
napi->skb = NULL;
|
||||||
|
|
||||||
skb_reset_mac_header(skb);
|
skb_reset_mac_header(skb);
|
||||||
skb_gro_reset_offset(skb);
|
skb_gro_reset_offset(skb);
|
||||||
|
|
||||||
eth = skb_gro_header(skb, sizeof(*eth));
|
off = skb_gro_offset(skb);
|
||||||
if (!eth) {
|
hlen = off + sizeof(*eth);
|
||||||
napi_reuse_skb(napi, skb);
|
eth = skb_gro_header_fast(skb, off);
|
||||||
skb = NULL;
|
if (skb_gro_header_hard(skb, hlen)) {
|
||||||
goto out;
|
eth = skb_gro_header_slow(skb, hlen, off);
|
||||||
|
if (unlikely(!eth)) {
|
||||||
|
napi_reuse_skb(napi, skb);
|
||||||
|
skb = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skb_gro_pull(skb, sizeof(*eth));
|
skb_gro_pull(skb, sizeof(*eth));
|
||||||
|
@ -1246,13 +1246,20 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
|
|||||||
struct sk_buff **pp = NULL;
|
struct sk_buff **pp = NULL;
|
||||||
struct sk_buff *p;
|
struct sk_buff *p;
|
||||||
struct iphdr *iph;
|
struct iphdr *iph;
|
||||||
|
unsigned int hlen;
|
||||||
|
unsigned int off;
|
||||||
int flush = 1;
|
int flush = 1;
|
||||||
int proto;
|
int proto;
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
iph = skb_gro_header(skb, sizeof(*iph));
|
off = skb_gro_offset(skb);
|
||||||
if (unlikely(!iph))
|
hlen = off + sizeof(*iph);
|
||||||
goto out;
|
iph = skb_gro_header_fast(skb, off);
|
||||||
|
if (skb_gro_header_hard(skb, hlen)) {
|
||||||
|
iph = skb_gro_header_slow(skb, hlen, off);
|
||||||
|
if (unlikely(!iph))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
proto = iph->protocol & (MAX_INET_PROTOS - 1);
|
proto = iph->protocol & (MAX_INET_PROTOS - 1);
|
||||||
|
|
||||||
|
@ -2518,20 +2518,30 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
|
|||||||
unsigned int thlen;
|
unsigned int thlen;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned int mss = 1;
|
unsigned int mss = 1;
|
||||||
|
unsigned int hlen;
|
||||||
|
unsigned int off;
|
||||||
int flush = 1;
|
int flush = 1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
th = skb_gro_header(skb, sizeof(*th));
|
off = skb_gro_offset(skb);
|
||||||
if (unlikely(!th))
|
hlen = off + sizeof(*th);
|
||||||
goto out;
|
th = skb_gro_header_fast(skb, off);
|
||||||
|
if (skb_gro_header_hard(skb, hlen)) {
|
||||||
|
th = skb_gro_header_slow(skb, hlen, off);
|
||||||
|
if (unlikely(!th))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
thlen = th->doff * 4;
|
thlen = th->doff * 4;
|
||||||
if (thlen < sizeof(*th))
|
if (thlen < sizeof(*th))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
th = skb_gro_header(skb, thlen);
|
hlen = off + thlen;
|
||||||
if (unlikely(!th))
|
if (skb_gro_header_hard(skb, hlen)) {
|
||||||
goto out;
|
th = skb_gro_header_slow(skb, hlen, off);
|
||||||
|
if (unlikely(!th))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
skb_gro_pull(skb, thlen);
|
skb_gro_pull(skb, thlen);
|
||||||
|
|
||||||
|
@ -817,13 +817,20 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
|
|||||||
struct sk_buff *p;
|
struct sk_buff *p;
|
||||||
struct ipv6hdr *iph;
|
struct ipv6hdr *iph;
|
||||||
unsigned int nlen;
|
unsigned int nlen;
|
||||||
|
unsigned int hlen;
|
||||||
|
unsigned int off;
|
||||||
int flush = 1;
|
int flush = 1;
|
||||||
int proto;
|
int proto;
|
||||||
__wsum csum;
|
__wsum csum;
|
||||||
|
|
||||||
iph = skb_gro_header(skb, sizeof(*iph));
|
off = skb_gro_offset(skb);
|
||||||
if (unlikely(!iph))
|
hlen = off + sizeof(*iph);
|
||||||
goto out;
|
iph = skb_gro_header_fast(skb, off);
|
||||||
|
if (skb_gro_header_hard(skb, hlen)) {
|
||||||
|
iph = skb_gro_header_slow(skb, hlen, off);
|
||||||
|
if (unlikely(!iph))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
skb_gro_pull(skb, sizeof(*iph));
|
skb_gro_pull(skb, sizeof(*iph));
|
||||||
skb_set_transport_header(skb, skb_gro_offset(skb));
|
skb_set_transport_header(skb, skb_gro_offset(skb));
|
||||||
|
Reference in New Issue
Block a user