Currently the UDP protocol delivers GSO_FRAGLIST packets to
the sockets without the expected segmentation.

This change addresses the issue introducing and maintaining
a couple of new fields to explicitly accept SKB_GSO_UDP_L4
or GSO_FRAGLIST packets. Additionally updates  udp_unexpected_gso()
accordingly.

UDP sockets enabling UDP_GRO stil keep accept_udp_fraglist
zeroed.

v1 -> v2:
 - use 2 bits instead of a whole GSO bitmask (Willem)

Fixes: 9fd1ff5d2ac7 ("udp: Support UDP fraglist GRO/GSO.")
Signed-off-by: Paolo Abeni <pab...@redhat.com>
---
 include/linux/udp.h | 16 +++++++++++++---
 net/ipv4/udp.c      |  3 +++
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/include/linux/udp.h b/include/linux/udp.h
index aa84597bdc33c..ae58ff3b6b5b8 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -51,7 +51,9 @@ struct udp_sock {
                                           * different encapsulation layer set
                                           * this
                                           */
-                        gro_enabled:1; /* Can accept GRO packets */
+                        gro_enabled:1, /* Request GRO aggregation */
+                        accept_udp_l4:1,
+                        accept_udp_fraglist:1;
        /*
         * Following member retains the information to create a UDP header
         * when the socket is uncorked.
@@ -131,8 +133,16 @@ 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;
+       if (!skb_is_gso(skb))
+               return false;
+
+       if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && 
!udp_sk(sk)->accept_udp_l4)
+               return true;
+
+       if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST && 
!udp_sk(sk)->accept_udp_fraglist)
+               return true;
+
+       return false;
 }
 
 #define udp_portaddr_for_each_entry(__sk, list) \
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fe85dcf8c0087..c0695ce42dc53 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2666,9 +2666,12 @@ 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 */
                if (valbool)
                        udp_tunnel_encap_enable(sk->sk_socket);
                up->gro_enabled = valbool;
+               up->accept_udp_l4 = valbool;
                release_sock(sk);
                break;
 
-- 
2.26.2

Reply via email to