Currently the UDP protocol delivers GSO_FRAGLIST packets to
the sockets without the expected segmentation.
This change addresses the issue introducing and maintaining
a per socket bitmask of GSO types requiring segmentation.
Enabling GSO removes SKB_GSO_UDP_L4 from such mask, while
GSO_FRAGLIST packets are never accepted
Note: this also updates the 'unused' field size to really
fit the otherwise existing hole. It's size become incorrect
after commit bec1f6f69736 ("udp: generate gso with UDP_SEGMENT").
Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
Signed-off-by: Paolo Abeni <[email protected]>
---
include/linux/udp.h | 10 ++++++----
net/ipv4/udp.c | 12 +++++++++++-
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/include/linux/udp.h b/include/linux/udp.h
index aa84597bdc33c..6da342f15f351 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -51,7 +51,7 @@ struct udp_sock {
* different encapsulation layer set
* this
*/
- gro_enabled:1; /* Can accept GRO packets */
+ gro_enabled:1; /* Request GRO aggregation */
/*
* Following member retains the information to create a UDP header
* when the socket is uncorked.
@@ -68,7 +68,10 @@ struct udp_sock {
#define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */
#define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */
__u8 pcflag; /* marks socket as UDP-Lite if > 0 */
- __u8 unused[3];
+ __u8 unused[1];
+ unsigned int unexpected_gso;/* GSO types this socket can't accept,
+ * any of SKB_GSO_UDP_L4 or
SKB_GSO_FRAGLIST
+ */
/*
* For encapsulation sockets.
*/
@@ -131,8 +134,7 @@ static inline void udp_cmsg_recv(struct msghdr *msg, struct
sock *sk,
static inline bool udp_unexpected_gso(struct sock *sk, struct sk_buff *skb)
{
- return !udp_sk(sk)->gro_enabled && skb_is_gso(skb) &&
- skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4;
+ return skb_is_gso(skb) && skb_shinfo(skb)->gso_type &
udp_sk(sk)->unexpected_gso;
}
#define udp_portaddr_for_each_entry(__sk, list) \
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ff54135c51ffa..1ba6d153c2f0a 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1600,8 +1600,13 @@ EXPORT_SYMBOL_GPL(udp_destruct_sock);
int udp_init_sock(struct sock *sk)
{
- skb_queue_head_init(&udp_sk(sk)->reader_queue);
+ struct udp_sock *up = udp_sk(sk);
+
+ skb_queue_head_init(&up->reader_queue);
sk->sk_destruct = udp_destruct_sock;
+
+ /* do not accept any GSO packet by default */
+ up->unexpected_gso = SKB_GSO_FRAGLIST | SKB_GSO_UDP_L4;
return 0;
}
EXPORT_SYMBOL_GPL(udp_init_sock);
@@ -2674,8 +2679,13 @@ int udp_lib_setsockopt(struct sock *sk, int level, int
optname,
case UDP_GRO:
lock_sock(sk);
+
+ /* when enabling GRO, accept the related GSO packet type */
+ up->unexpected_gso = SKB_GSO_FRAGLIST;
if (valbool)
udp_tunnel_encap_enable(sk->sk_socket);
+ else
+ up->unexpected_gso |= SKB_GSO_UDP_L4;
up->gro_enabled = valbool;
release_sock(sk);
break;
--
2.26.2