]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tcp: accecn: unset ECT if receive or send ACE=0 in AccECN negotiaion
authorChia-Yu Chang <chia-yu.chang@nokia-bell-labs.com>
Sat, 31 Jan 2026 22:25:10 +0000 (23:25 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 3 Feb 2026 14:13:24 +0000 (15:13 +0100)
Based on specification:
  https://tools.ietf.org/id/draft-ietf-tcpm-accurate-ecn-28.txt

Based on Section 3.1.5 of AccECN spec (RFC9768), a TCP Server in
AccECN mode MUST NOT set ECT on any packet for the rest of the connection,
if it has received or sent at least one valid SYN or Acceptable SYN/ACK
with (AE,CWR,ECE) = (0,0,0) during the handshake.

In addition, a host in AccECN mode that is feeding back the IP-ECN
field on a SYN or SYN/ACK MUST feed back the IP-ECN field on the
latest valid SYN or acceptable SYN/ACK to arrive.

Signed-off-by: Chia-Yu Chang <chia-yu.chang@nokia-bell-labs.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260131222515.8485-11-chia-yu.chang@nokia-bell-labs.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/ipv4/inet_connection_sock.c
net/ipv4/tcp_input.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c

index 13372d2cbed53e83510e24a34bc57c7de0a17004..018e8ffc07176dd4f6ecbaae5697b90b67cb1294 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/tcp_states.h>
 #include <net/xfrm.h>
 #include <net/tcp.h>
+#include <net/tcp_ecn.h>
 #include <net/sock_reuseport.h>
 #include <net/addrconf.h>
 
@@ -1103,6 +1104,8 @@ static void reqsk_timer_handler(struct timer_list *t)
            (!resend ||
             !tcp_rtx_synack(sk_listener, req) ||
             inet_rsk(req)->acked)) {
+               if (req->num_retrans > 1 && tcp_rsk(req)->accecn_ok)
+                       tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_SEND;
                if (req->num_timeout++ == 0)
                        atomic_dec(&queue->young);
                mod_timer(&req->rsk_timer, jiffies + tcp_reqsk_timeout(req));
index 59dafcb45c168c96a04ac79280b0a1ee81dd2615..988d161e9918c7d79d9b62a3e68de559319484e0 100644 (file)
@@ -6469,6 +6469,8 @@ step1:
        if (th->syn) {
                if (tcp_ecn_mode_accecn(tp)) {
                        accecn_reflector = true;
+                       tp->syn_ect_rcv = TCP_SKB_CB(skb)->ip_dsfield &
+                                         INET_ECN_MASK;
                        if (tp->rx_opt.accecn &&
                            tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) {
                                u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn);
index 9776c921d1bb4d7d7c0f6f2b17e4e55eb508159e..ec128865f5c029c971eb00cb9ee058b742efafd1 100644 (file)
@@ -481,6 +481,10 @@ static void tcp_ecn_openreq_child(struct sock *sk,
                tp->syn_ect_snt = treq->syn_ect_snt;
                tcp_accecn_third_ack(sk, skb, treq->syn_ect_snt);
                tp->saw_accecn_opt = treq->saw_accecn_opt;
+               if (treq->accecn_fail_mode & TCP_ACCECN_ACE_FAIL_SEND)
+                       tcp_accecn_fail_mode_set(tp, TCP_ACCECN_ACE_FAIL_SEND);
+               if (treq->accecn_fail_mode & TCP_ACCECN_ACE_FAIL_RECV)
+                       tcp_accecn_fail_mode_set(tp, TCP_ACCECN_ACE_FAIL_RECV);
                tp->prev_ecnfield = treq->syn_ect_rcv;
                tp->accecn_opt_demand = 1;
                tcp_ecn_received_counters_payload(sk, skb);
@@ -749,16 +753,28 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
                 */
                if (!tcp_oow_rate_limited(sock_net(sk), skb,
                                          LINUX_MIB_TCPACKSKIPPEDSYNRECV,
-                                         &tcp_rsk(req)->last_oow_ack_time) &&
-
-                   !tcp_rtx_synack(sk, req)) {
-                       unsigned long expires = jiffies;
-
-                       expires += tcp_reqsk_timeout(req);
-                       if (!fastopen)
-                               mod_timer_pending(&req->rsk_timer, expires);
-                       else
-                               req->rsk_timer.expires = expires;
+                                         &tcp_rsk(req)->last_oow_ack_time)) {
+                       if (tcp_rsk(req)->accecn_ok) {
+                               u8 ect_rcv = TCP_SKB_CB(skb)->ip_dsfield &
+                                            INET_ECN_MASK;
+
+                               tcp_rsk(req)->syn_ect_rcv = ect_rcv;
+                               if (tcp_accecn_ace(tcp_hdr(skb)) == 0x0)
+                                       tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_RECV;
+                       }
+                       if (!tcp_rtx_synack(sk, req)) {
+                               unsigned long expires = jiffies;
+
+                               if (req->num_retrans > 1 && tcp_rsk(req)->accecn_ok)
+                                       tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_SEND;
+
+                               expires += tcp_reqsk_timeout(req);
+                               if (!fastopen)
+                                       mod_timer_pending(&req->rsk_timer,
+                                                         expires);
+                               else
+                                       req->rsk_timer.expires = expires;
+                       }
                }
                return NULL;
        }
index 22728daed436a55af250000d7bc019d9599d14ed..2b356fdbf2ca3907183822925ed2fce39155c033 100644 (file)
@@ -334,8 +334,11 @@ static void tcp_ecn_send(struct sock *sk, struct sk_buff *skb,
                return;
 
        if (tcp_ecn_mode_accecn(tp)) {
-               if (!tcp_accecn_ace_fail_recv(tp))
+               if (!tcp_accecn_ace_fail_recv(tp) &&
+                   !tcp_accecn_ace_fail_send(tp))
                        INET_ECN_xmit(sk);
+               else
+                       INET_ECN_dontxmit(sk);
                tcp_accecn_set_ace(tp, skb, th);
                skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ACCECN;
        } else {
index 160080c9021d0717605520af3f1a47d071e7bf4d..5a14a53a3c9ef9d04bf47dd3f9f2d2b425acfd0d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <net/tcp.h>
+#include <net/tcp_ecn.h>
 #include <net/rstreason.h>
 
 static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
@@ -479,6 +480,8 @@ static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req)
         * it's not good to give up too easily.
         */
        tcp_rtx_synack(sk, req);
+       if (req->num_retrans > 1 && tcp_rsk(req)->accecn_ok)
+               tcp_rsk(req)->accecn_fail_mode |= TCP_ACCECN_ACE_FAIL_SEND;
        req->num_timeout++;
        tcp_update_rto_stats(sk);
        if (!tp->retrans_stamp)