]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
tunnels: Don't apply GRO to multiple layers of encapsulation.
authorJesse Gross <jesse@kernel.org>
Sat, 19 Mar 2016 16:32:01 +0000 (09:32 -0700)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 30 Apr 2016 22:06:03 +0000 (00:06 +0200)
commit fac8e0f579695a3ecbc4d3cac369139d7f819971 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: Jesse Gross <jesse@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
[bwh: Backported to 3.16:
 - Drop the ipip and sit cases
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
include/linux/netdevice.h
net/core/dev.c
net/ipv4/gre_offload.c
net/ipv4/udp_offload.c

index ab4ce78c5bb85ea8d6438dd4e3e497d709f8b5b1..b3404718fda186d3c5739829a51500609bfe8c58 100644 (file)
@@ -1759,8 +1759,8 @@ struct napi_gro_cb {
        /* Used in ipv6_gro_receive() */
        u16     proto;
 
-       /* Used in udp_gro_receive */
-       u16     udp_mark;
+       /* Used in tunnel GRO receive */
+       u16     encap_mark;
 
        /* used to support CHECKSUM_COMPLETE for tunneling protocols */
        __wsum  csum;
index e12823e68bb07a84bd247a8c9d1ac8dd1a2d825f..75be7e22626877d15225371b625a2bebc2a96890 100644 (file)
@@ -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)->flush = 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);
                break;
index 85c84f487d595e272c867a2ef5d6cc2a6a7911a5..7ff682f7e1c367e3d04ab1e935892a8201c605cd 100644 (file)
@@ -154,6 +154,11 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
        struct packet_offload *ptype;
        __be16 type;
 
+       if (NAPI_GRO_CB(skb)->encap_mark)
+               goto out;
+
+       NAPI_GRO_CB(skb)->encap_mark = 1;
+
        off = skb_gro_offset(skb);
        hlen = off + sizeof(*greh);
        greh = skb_gro_header_fast(skb, off);
index 546d2d439dda65a195f7e635b7dc564def1da077..ca41bcbea39c32a08eec38178605c0549970f14b 100644 (file)
@@ -160,12 +160,12 @@ static struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *s
        unsigned int hlen, off;
        int flush = 1;
 
-       if (NAPI_GRO_CB(skb)->udp_mark ||
+       if (NAPI_GRO_CB(skb)->encap_mark ||
            (!skb->encapsulation && skb->ip_summed != CHECKSUM_COMPLETE))
                goto out;
 
-       /* mark that this skb passed once through the udp gro layer */
-       NAPI_GRO_CB(skb)->udp_mark = 1;
+       /* mark that this skb passed once through the tunnel gro layer */
+       NAPI_GRO_CB(skb)->encap_mark = 1;
 
        off  = skb_gro_offset(skb);
        hlen = off + sizeof(*uh);