Commit 23cca87f authored by Jesse Gross's avatar Jesse Gross Committed by Ben Hutchings

tunnels: Don't apply GRO to multiple layers of encapsulation.

commit fac8e0f5 upstream.

When drivers express support for TSO of encapsulated packets, they
only mean that they can do it for one layer of encapsulation.
Supporting additional levels would mean updating, at a minimum,
more IP length fields and they are unaware of this.

No encapsulation device expresses support for handling offloaded
encapsulated packets, so we won't generate these types of frames
in the transmit path. However, GRO doesn't have a check for
multiple levels of encapsulation and will attempt to build them.

UDP tunnel GRO actually does prevent this situation but it only
handles multiple UDP tunnels stacked on top of each other. This
generalizes that solution to prevent any kind of tunnel stacking
that would cause problems.

Fixes: bf5a755f ("net-gre-gro: Add GRE support to the GRO stack")
Signed-off-by: default avatarJesse Gross <jesse@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
[bwh: Backported to 3.16:
 - Drop the ipip and sit cases
 - Adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 8c487c21
...@@ -1759,8 +1759,8 @@ struct napi_gro_cb { ...@@ -1759,8 +1759,8 @@ struct napi_gro_cb {
/* Used in ipv6_gro_receive() */ /* Used in ipv6_gro_receive() */
u16 proto; u16 proto;
/* Used in udp_gro_receive */ /* Used in tunnel GRO receive */
u16 udp_mark; u16 encap_mark;
/* used to support CHECKSUM_COMPLETE for tunneling protocols */ /* used to support CHECKSUM_COMPLETE for tunneling protocols */
__wsum csum; __wsum csum;
......
...@@ -3974,7 +3974,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff ...@@ -3974,7 +3974,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
NAPI_GRO_CB(skb)->same_flow = 0; NAPI_GRO_CB(skb)->same_flow = 0;
NAPI_GRO_CB(skb)->flush = 0; NAPI_GRO_CB(skb)->flush = 0;
NAPI_GRO_CB(skb)->free = 0; NAPI_GRO_CB(skb)->free = 0;
NAPI_GRO_CB(skb)->udp_mark = 0; NAPI_GRO_CB(skb)->encap_mark = 0;
pp = ptype->callbacks.gro_receive(&napi->gro_list, skb); pp = ptype->callbacks.gro_receive(&napi->gro_list, skb);
break; break;
......
...@@ -154,6 +154,11 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, ...@@ -154,6 +154,11 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
struct packet_offload *ptype; struct packet_offload *ptype;
__be16 type; __be16 type;
if (NAPI_GRO_CB(skb)->encap_mark)
goto out;
NAPI_GRO_CB(skb)->encap_mark = 1;
off = skb_gro_offset(skb); off = skb_gro_offset(skb);
hlen = off + sizeof(*greh); hlen = off + sizeof(*greh);
greh = skb_gro_header_fast(skb, off); greh = skb_gro_header_fast(skb, off);
......
...@@ -160,12 +160,12 @@ static struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *s ...@@ -160,12 +160,12 @@ static struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *s
unsigned int hlen, off; unsigned int hlen, off;
int flush = 1; int flush = 1;
if (NAPI_GRO_CB(skb)->udp_mark || if (NAPI_GRO_CB(skb)->encap_mark ||
(!skb->encapsulation && skb->ip_summed != CHECKSUM_COMPLETE)) (!skb->encapsulation && skb->ip_summed != CHECKSUM_COMPLETE))
goto out; goto out;
/* mark that this skb passed once through the udp gro layer */ /* mark that this skb passed once through the tunnel gro layer */
NAPI_GRO_CB(skb)->udp_mark = 1; NAPI_GRO_CB(skb)->encap_mark = 1;
off = skb_gro_offset(skb); off = skb_gro_offset(skb);
hlen = off + sizeof(*uh); hlen = off + sizeof(*uh);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment