aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJesse Gross <jesse@kernel.org>2016-03-19 12:32:01 -0400
committerDavid S. Miller <davem@davemloft.net>2016-03-20 16:33:40 -0400
commitfac8e0f579695a3ecbc4d3cac369139d7f819971 (patch)
tree4509655217edeb5184839c67a48298e45ef38039 /net
parentb8cba75bdf6a48ea4811bbefb11a94a5c7281b68 (diff)
tunnels: Don't apply GRO to multiple layers of encapsulation.
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>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c2
-rw-r--r--net/ipv4/af_inet.c15
-rw-r--r--net/ipv4/gre_offload.c5
-rw-r--r--net/ipv4/udp_offload.c6
-rw-r--r--net/ipv6/ip6_offload.c15
5 files changed, 37 insertions, 6 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index edb7179bc051..43c74cad25bc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4438,7 +4438,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
4438 NAPI_GRO_CB(skb)->same_flow = 0; 4438 NAPI_GRO_CB(skb)->same_flow = 0;
4439 NAPI_GRO_CB(skb)->flush = 0; 4439 NAPI_GRO_CB(skb)->flush = 0;
4440 NAPI_GRO_CB(skb)->free = 0; 4440 NAPI_GRO_CB(skb)->free = 0;
4441 NAPI_GRO_CB(skb)->udp_mark = 0; 4441 NAPI_GRO_CB(skb)->encap_mark = 0;
4442 NAPI_GRO_CB(skb)->gro_remcsum_start = 0; 4442 NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
4443 4443
4444 /* Setup for GRO checksum validation */ 4444 /* Setup for GRO checksum validation */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 965923325535..0fefba64ee79 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1380,6 +1380,19 @@ out:
1380 return pp; 1380 return pp;
1381} 1381}
1382 1382
1383static struct sk_buff **ipip_gro_receive(struct sk_buff **head,
1384 struct sk_buff *skb)
1385{
1386 if (NAPI_GRO_CB(skb)->encap_mark) {
1387 NAPI_GRO_CB(skb)->flush = 1;
1388 return NULL;
1389 }
1390
1391 NAPI_GRO_CB(skb)->encap_mark = 1;
1392
1393 return inet_gro_receive(head, skb);
1394}
1395
1383#define SECONDS_PER_DAY 86400 1396#define SECONDS_PER_DAY 86400
1384 1397
1385/* inet_current_timestamp - Return IP network timestamp 1398/* inet_current_timestamp - Return IP network timestamp
@@ -1682,7 +1695,7 @@ static struct packet_offload ip_packet_offload __read_mostly = {
1682static const struct net_offload ipip_offload = { 1695static const struct net_offload ipip_offload = {
1683 .callbacks = { 1696 .callbacks = {
1684 .gso_segment = inet_gso_segment, 1697 .gso_segment = inet_gso_segment,
1685 .gro_receive = inet_gro_receive, 1698 .gro_receive = ipip_gro_receive,
1686 .gro_complete = ipip_gro_complete, 1699 .gro_complete = ipip_gro_complete,
1687 }, 1700 },
1688}; 1701};
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index 540866dbd27d..dd031617160a 100644
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -126,6 +126,11 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
126 struct packet_offload *ptype; 126 struct packet_offload *ptype;
127 __be16 type; 127 __be16 type;
128 128
129 if (NAPI_GRO_CB(skb)->encap_mark)
130 goto out;
131
132 NAPI_GRO_CB(skb)->encap_mark = 1;
133
129 off = skb_gro_offset(skb); 134 off = skb_gro_offset(skb);
130 hlen = off + sizeof(*greh); 135 hlen = off + sizeof(*greh);
131 greh = skb_gro_header_fast(skb, off); 136 greh = skb_gro_header_fast(skb, off);
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 8a3405a80260..8007f73b8981 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -311,14 +311,14 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
311 unsigned int off = skb_gro_offset(skb); 311 unsigned int off = skb_gro_offset(skb);
312 int flush = 1; 312 int flush = 1;
313 313
314 if (NAPI_GRO_CB(skb)->udp_mark || 314 if (NAPI_GRO_CB(skb)->encap_mark ||
315 (skb->ip_summed != CHECKSUM_PARTIAL && 315 (skb->ip_summed != CHECKSUM_PARTIAL &&
316 NAPI_GRO_CB(skb)->csum_cnt == 0 && 316 NAPI_GRO_CB(skb)->csum_cnt == 0 &&
317 !NAPI_GRO_CB(skb)->csum_valid)) 317 !NAPI_GRO_CB(skb)->csum_valid))
318 goto out; 318 goto out;
319 319
320 /* mark that this skb passed once through the udp gro layer */ 320 /* mark that this skb passed once through the tunnel gro layer */
321 NAPI_GRO_CB(skb)->udp_mark = 1; 321 NAPI_GRO_CB(skb)->encap_mark = 1;
322 322
323 rcu_read_lock(); 323 rcu_read_lock();
324 uo_priv = rcu_dereference(udp_offload_base); 324 uo_priv = rcu_dereference(udp_offload_base);
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index eeca943f12dc..82e9f3076028 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -258,6 +258,19 @@ out:
258 return pp; 258 return pp;
259} 259}
260 260
261static struct sk_buff **sit_gro_receive(struct sk_buff **head,
262 struct sk_buff *skb)
263{
264 if (NAPI_GRO_CB(skb)->encap_mark) {
265 NAPI_GRO_CB(skb)->flush = 1;
266 return NULL;
267 }
268
269 NAPI_GRO_CB(skb)->encap_mark = 1;
270
271 return ipv6_gro_receive(head, skb);
272}
273
261static int ipv6_gro_complete(struct sk_buff *skb, int nhoff) 274static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
262{ 275{
263 const struct net_offload *ops; 276 const struct net_offload *ops;
@@ -302,7 +315,7 @@ static struct packet_offload ipv6_packet_offload __read_mostly = {
302static const struct net_offload sit_offload = { 315static const struct net_offload sit_offload = {
303 .callbacks = { 316 .callbacks = {
304 .gso_segment = ipv6_gso_segment, 317 .gso_segment = ipv6_gso_segment,
305 .gro_receive = ipv6_gro_receive, 318 .gro_receive = sit_gro_receive,
306 .gro_complete = sit_gro_complete, 319 .gro_complete = sit_gro_complete,
307 }, 320 },
308}; 321};