gso: AccECN support
authorIlpo Järvinen <ij@kernel.org>
Wed, 5 Mar 2025 22:38:48 +0000 (23:38 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 17 Mar 2025 13:54:50 +0000 (13:54 +0000)
Handling the CWR flag differs between RFC 3168 ECN and AccECN.
With RFC 3168 ECN aware TSO (NETIF_F_TSO_ECN) CWR flag is cleared
starting from 2nd segment which is incompatible how AccECN handles
the CWR flag. Such super-segments are indicated by SKB_GSO_TCP_ECN.
With AccECN, CWR flag (or more accurately, the ACE field that also
includes ECE & AE flags) changes only when new packet(s) with CE
mark arrives so the flag should not be changed within a super-skb.
The new skb/feature flags are necessary to prevent such TSO engines
corrupting AccECN ACE counters by clearing the CWR flag (if the
CWR handling feature cannot be turned off).

If NIC is completely unaware of RFC3168 ECN (doesn't support
NETIF_F_TSO_ECN) or its TSO engine can be set to not touch CWR flag
despite supporting also NETIF_F_TSO_ECN, TSO could be safely used
with AccECN on such NIC. This should be evaluated per NIC basis
(not done in this patch series for any NICs).

For the cases, where TSO cannot keep its hands off the CWR flag,
a GSO fallback is provided by this patch.

Signed-off-by: Ilpo Järvinen <ij@kernel.org>
Signed-off-by: Chia-Yu Chang <chia-yu.chang@nokia-bell-labs.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/skbuff.h
net/ethtool/common.c
net/ipv4/tcp_offload.c

index 11be70a7929f2891610399367e529062d32f0272..7a01c518e5730ae5611a454af7ca96a7791944ce 100644 (file)
@@ -53,12 +53,12 @@ enum {
        NETIF_F_GSO_UDP_BIT,            /* ... UFO, deprecated except tuntap */
        NETIF_F_GSO_UDP_L4_BIT,         /* ... UDP payload GSO (not UFO) */
        NETIF_F_GSO_FRAGLIST_BIT,               /* ... Fraglist GSO */
+       NETIF_F_GSO_ACCECN_BIT,         /* TCP AccECN w/ TSO (no clear CWR) */
        /**/NETIF_F_GSO_LAST =          /* last bit, see GSO_MASK */
-               NETIF_F_GSO_FRAGLIST_BIT,
+               NETIF_F_GSO_ACCECN_BIT,
 
        NETIF_F_FCOE_CRC_BIT,           /* FCoE CRC32 */
        NETIF_F_SCTP_CRC_BIT,           /* SCTP checksum offload */
-       __UNUSED_NETIF_F_37,
        NETIF_F_NTUPLE_BIT,             /* N-tuple filters supported */
        NETIF_F_RXHASH_BIT,             /* Receive hashing offload */
        NETIF_F_RXCSUM_BIT,             /* Receive checksumming offload */
@@ -128,6 +128,7 @@ enum {
 #define NETIF_F_SG             __NETIF_F(SG)
 #define NETIF_F_TSO6           __NETIF_F(TSO6)
 #define NETIF_F_TSO_ECN                __NETIF_F(TSO_ECN)
+#define NETIF_F_GSO_ACCECN     __NETIF_F(GSO_ACCECN)
 #define NETIF_F_TSO            __NETIF_F(TSO)
 #define NETIF_F_VLAN_CHALLENGED        __NETIF_F(VLAN_CHALLENGED)
 #define NETIF_F_RXFCS          __NETIF_F(RXFCS)
@@ -210,7 +211,8 @@ static inline int find_next_netdev_feature(u64 feature, unsigned long start)
                                 NETIF_F_TSO_ECN | NETIF_F_TSO_MANGLEID)
 
 /* List of features with software fallbacks. */
-#define NETIF_F_GSO_SOFTWARE   (NETIF_F_ALL_TSO | NETIF_F_GSO_SCTP |        \
+#define NETIF_F_GSO_SOFTWARE   (NETIF_F_ALL_TSO | \
+                                NETIF_F_GSO_ACCECN | NETIF_F_GSO_SCTP | \
                                 NETIF_F_GSO_UDP_L4 | NETIF_F_GSO_FRAGLIST)
 
 /*
index 0dbfe069a6e38afbb3b8eb2e5a21354e819b7373..67527243459b358ef16610c597bf3606af2ca020 100644 (file)
@@ -5269,6 +5269,8 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
        BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_GSO_UDP >> NETIF_F_GSO_SHIFT));
        BUILD_BUG_ON(SKB_GSO_UDP_L4 != (NETIF_F_GSO_UDP_L4 >> NETIF_F_GSO_SHIFT));
        BUILD_BUG_ON(SKB_GSO_FRAGLIST != (NETIF_F_GSO_FRAGLIST >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_TCP_ACCECN !=
+                    (NETIF_F_GSO_ACCECN >> NETIF_F_GSO_SHIFT));
 
        return (features & feature) == feature;
 }
index 14517e95a46c4e6f9a04ef7c7193b82b5e145b28..b8a1343d6785cff6b270a0be7777061fc9dfafbb 100644 (file)
@@ -708,6 +708,8 @@ enum {
        SKB_GSO_UDP_L4 = 1 << 17,
 
        SKB_GSO_FRAGLIST = 1 << 18,
+
+       SKB_GSO_TCP_ACCECN = 1 << 19,
 };
 
 #if BITS_PER_LONG > 32
index ac8b6107863e52d3843411b55001130a29efa778..1c6f2a2f18714786f3ae1320b36703f5460e0fd7 100644 (file)
@@ -36,6 +36,7 @@ const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
        [NETIF_F_TSO_BIT] =              "tx-tcp-segmentation",
        [NETIF_F_GSO_ROBUST_BIT] =       "tx-gso-robust",
        [NETIF_F_TSO_ECN_BIT] =          "tx-tcp-ecn-segmentation",
+       [NETIF_F_GSO_ACCECN_BIT] =       "tx-tcp-accecn-segmentation",
        [NETIF_F_TSO_MANGLEID_BIT] =     "tx-tcp-mangleid-segmentation",
        [NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
        [NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",
index e27f4ee2a0de32b19e08628e0cd03cf14b5d04d6..8c74fd69db2a8acc6e38d09ec81f1a741b83e540 100644 (file)
@@ -142,6 +142,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
        struct sk_buff *gso_skb = skb;
        __sum16 newcheck;
        bool ooo_okay, copy_destructor;
+       bool ecn_cwr_mask;
        __wsum delta;
 
        th = tcp_hdr(skb);
@@ -201,6 +202,8 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
 
        newcheck = ~csum_fold(csum_add(csum_unfold(th->check), delta));
 
+       ecn_cwr_mask = !!(skb_shinfo(gso_skb)->gso_type & SKB_GSO_TCP_ACCECN);
+
        while (skb->next) {
                th->fin = th->psh = 0;
                th->check = newcheck;
@@ -220,7 +223,8 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
                th = tcp_hdr(skb);
 
                th->seq = htonl(seq);
-               th->cwr = 0;
+
+               th->cwr &= ecn_cwr_mask;
        }
 
        /* Following permits TCP Small Queues to work well with GSO :