summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJosh Hunt <johunt@akamai.com>2019-10-02 13:29:23 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-10-07 18:58:24 +0200
commitd6870bbdacd64f94254338d6c9558fdad7c0ac8b (patch)
tree9688eaa76714252e966c8680b1744b728c18632b /net
parentda0f508134bb76e6b535faa0c303f9785188fea6 (diff)
downloadlinux-stable-d6870bbdacd64f94254338d6c9558fdad7c0ac8b.tar.gz
linux-stable-d6870bbdacd64f94254338d6c9558fdad7c0ac8b.tar.bz2
linux-stable-d6870bbdacd64f94254338d6c9558fdad7c0ac8b.zip
udp: only do GSO if # of segs > 1
[ Upstream commit 4094871db1d65810acab3d57f6089aa39ef7f648 ] Prior to this change an application sending <= 1MSS worth of data and enabling UDP GSO would fail if the system had SW GSO enabled, but the same send would succeed if HW GSO offload is enabled. In addition to this inconsistency the error in the SW GSO case does not get back to the application if sending out of a real device so the user is unaware of this failure. With this change we only perform GSO if the # of segments is > 1 even if the application has enabled segmentation. I've also updated the relevant udpgso selftests. Fixes: bec1f6f69736 ("udp: generate gso with UDP_SEGMENT") Signed-off-by: Josh Hunt <johunt@akamai.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Reviewed-by: Alexander Duyck <alexander.h.duyck@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/udp.c11
-rw-r--r--net/ipv6/udp.c11
2 files changed, 14 insertions, 8 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index b43075bd66d8..665f26e32d77 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -833,6 +833,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
int is_udplite = IS_UDPLITE(sk);
int offset = skb_transport_offset(skb);
int len = skb->len - offset;
+ int datalen = len - sizeof(*uh);
__wsum csum = 0;
/*
@@ -866,10 +867,12 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4,
return -EIO;
}
- skb_shinfo(skb)->gso_size = cork->gso_size;
- skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4;
- skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(len - sizeof(*uh),
- cork->gso_size);
+ if (datalen > cork->gso_size) {
+ skb_shinfo(skb)->gso_size = cork->gso_size;
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4;
+ skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(datalen,
+ cork->gso_size);
+ }
goto csum_partial;
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 7cf85955b996..f0b5edd861d0 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1122,6 +1122,7 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
__wsum csum = 0;
int offset = skb_transport_offset(skb);
int len = skb->len - offset;
+ int datalen = len - sizeof(*uh);
/*
* Create a UDP header
@@ -1154,10 +1155,12 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6,
return -EIO;
}
- skb_shinfo(skb)->gso_size = cork->gso_size;
- skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4;
- skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(len - sizeof(*uh),
- cork->gso_size);
+ if (datalen > cork->gso_size) {
+ skb_shinfo(skb)->gso_size = cork->gso_size;
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4;
+ skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(datalen,
+ cork->gso_size);
+ }
goto csum_partial;
}