aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarno Rajahalme <jarno@ovn.org>2016-05-03 19:10:21 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-06 18:25:26 -0400
commit229740c63169462a838a8b8e16391ed000934631 (patch)
tree3ca6aa48885be0f37d0b7f4832936b183c630a80
parent43b8448cd7b42a4c39476c9a12c960c1408f1946 (diff)
udp_offload: Set encapsulation before inner completes.
UDP tunnel segmentation code relies on the inner offsets being set for an UDP tunnel GSO packet, but the inner *_complete() functions will set the inner offsets only if 'encapsulation' is set before calling them. Currently, udp_gro_complete() sets 'encapsulation' only after the inner *_complete() functions are done. This causes the inner offsets having invalid values after udp_gro_complete() returns, which in turn will make it impossible to properly segment the packet in case it needs to be forwarded, which would be visible to the user either as invalid packets being sent or as packet loss. This patch fixes this by setting skb's 'encapsulation' in udp_gro_complete() before calling into the inner complete functions, and by making each possible UDP tunnel gro_complete() callback set the inner_mac_header to the beginning of the tunnel payload. Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Reviewed-by: Alexander Duyck <aduyck@mirantis.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/geneve.c3
-rw-r--r--drivers/net/vxlan.c3
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/ipv4/fou.c4
-rw-r--r--net/ipv4/udp_offload.c8
5 files changed, 18 insertions, 3 deletions
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 98f12244714f..7b0a644122eb 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -514,6 +514,9 @@ static int geneve_gro_complete(struct sk_buff *skb, int nhoff,
514 err = ptype->callbacks.gro_complete(skb, nhoff + gh_len); 514 err = ptype->callbacks.gro_complete(skb, nhoff + gh_len);
515 515
516 rcu_read_unlock(); 516 rcu_read_unlock();
517
518 skb_set_inner_mac_header(skb, nhoff + gh_len);
519
517 return err; 520 return err;
518} 521}
519 522
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index dd2d032fba5f..8ac261ab7d7d 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -616,6 +616,9 @@ out:
616static int vxlan_gro_complete(struct sk_buff *skb, int nhoff, 616static int vxlan_gro_complete(struct sk_buff *skb, int nhoff,
617 struct udp_offload *uoff) 617 struct udp_offload *uoff)
618{ 618{
619 /* Sets 'skb->inner_mac_header' since we are always called with
620 * 'skb->encapsulation' set.
621 */
619 return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr)); 622 return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
620} 623}
621 624
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index b3c46b019ac1..78181a88903b 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2164,6 +2164,9 @@ struct packet_offload {
2164 2164
2165struct udp_offload; 2165struct udp_offload;
2166 2166
2167/* 'skb->encapsulation' is set before gro_complete() is called. gro_complete()
2168 * must set 'skb->inner_mac_header' to the beginning of tunnel payload.
2169 */
2167struct udp_offload_callbacks { 2170struct udp_offload_callbacks {
2168 struct sk_buff **(*gro_receive)(struct sk_buff **head, 2171 struct sk_buff **(*gro_receive)(struct sk_buff **head,
2169 struct sk_buff *skb, 2172 struct sk_buff *skb,
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 305d9ac68bd9..a6962ccad98a 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -236,6 +236,8 @@ static int fou_gro_complete(struct sk_buff *skb, int nhoff,
236 236
237 err = ops->callbacks.gro_complete(skb, nhoff); 237 err = ops->callbacks.gro_complete(skb, nhoff);
238 238
239 skb_set_inner_mac_header(skb, nhoff);
240
239out_unlock: 241out_unlock:
240 rcu_read_unlock(); 242 rcu_read_unlock();
241 243
@@ -412,6 +414,8 @@ static int gue_gro_complete(struct sk_buff *skb, int nhoff,
412 414
413 err = ops->callbacks.gro_complete(skb, nhoff + guehlen); 415 err = ops->callbacks.gro_complete(skb, nhoff + guehlen);
414 416
417 skb_set_inner_mac_header(skb, nhoff + guehlen);
418
415out_unlock: 419out_unlock:
416 rcu_read_unlock(); 420 rcu_read_unlock();
417 return err; 421 return err;
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 0ed2dafb7cc4..e330c0e56b11 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -399,6 +399,11 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff)
399 399
400 uh->len = newlen; 400 uh->len = newlen;
401 401
402 /* Set encapsulation before calling into inner gro_complete() functions
403 * to make them set up the inner offsets.
404 */
405 skb->encapsulation = 1;
406
402 rcu_read_lock(); 407 rcu_read_lock();
403 408
404 uo_priv = rcu_dereference(udp_offload_base); 409 uo_priv = rcu_dereference(udp_offload_base);
@@ -421,9 +426,6 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff)
421 if (skb->remcsum_offload) 426 if (skb->remcsum_offload)
422 skb_shinfo(skb)->gso_type |= SKB_GSO_TUNNEL_REMCSUM; 427 skb_shinfo(skb)->gso_type |= SKB_GSO_TUNNEL_REMCSUM;
423 428
424 skb->encapsulation = 1;
425 skb_set_inner_mac_header(skb, nhoff + sizeof(struct udphdr));
426
427 return err; 429 return err;
428} 430}
429 431