UDP GSO segmentation currently propagates socket write ownership only
when the aggregate uses sock_wfree. An encapsulator such as ovpn can
instead retain ownership from the payload socket, including tcp_wfree,
while repackaging its data as UDP GSO.

In that case the destructor remains on the aggregate and runs when
software segmentation consumes it, before the resulting UDP packets
complete transmission. This releases the write-memory charge early and
can wake TCP Small Queues prematurely.

Use is_skb_wmem to recognize the standard write-accounting destructors
and propagate the original destructor to every segment. These
destructors all release ownership using skb->sk and skb->truesize, so
the existing truesize adjustment remains applicable. Skbs owned through
sock_wfree are handled as before.

Signed-off-by: Ralf Lici <[email protected]>
---
New in v4.

 net/ipv4/udp_offload.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index cf07c3c6611a..d41529030fbb 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -481,6 +481,7 @@ static struct sk_buff *__udp_gso_segment_list(struct 
sk_buff *skb,
 struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
                                  netdev_features_t features, bool is_ipv6)
 {
+       void (*destructor)(struct sk_buff *skb) = gso_skb->destructor;
        struct sock *sk = gso_skb->sk;
        unsigned int sum_truesize = 0;
        struct sk_buff *segs, *seg;
@@ -542,7 +543,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
        skb_pull(gso_skb, sizeof(*uh));
 
        /* clear destructor to avoid skb_segment assigning it to tail */
-       copy_dtor = gso_skb->destructor == sock_wfree;
+       copy_dtor = is_skb_wmem(gso_skb);
        if (copy_dtor) {
                gso_skb->destructor = NULL;
                gso_skb->sk = NULL;
@@ -551,7 +552,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
        segs = skb_segment(gso_skb, features);
        if (IS_ERR_OR_NULL(segs)) {
                if (copy_dtor) {
-                       gso_skb->destructor = sock_wfree;
+                       gso_skb->destructor = destructor;
                        gso_skb->sk = sk;
                }
                return segs;
@@ -571,7 +572,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
 
        for (;;) {
                if (copy_dtor) {
-                       seg->destructor = sock_wfree;
+                       seg->destructor = destructor;
                        seg->sk = sk;
                        sum_truesize += seg->truesize;
                }
-- 
2.56.0



_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to