Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tcp: accecn: retransmit SYN/ACK without AccECN option or non-AccECN SYN/ACK

For Accurate ECN, the first SYN/ACK sent by the TCP server shall set
the ACE flag (Table 1 of RFC9768) and the AccECN option to complete the
capability negotiation. However, if the TCP server needs to retransmit
such a SYN/ACK (for example, because it did not receive an ACK
acknowledging its SYN/ACK, or received a second SYN requesting AccECN
support), the TCP server retransmits the SYN/ACK without the AccECN
option. This is because the SYN/ACK may be lost due to congestion, or a
middlebox may block the AccECN option. Furthermore, if this retransmission
also times out, to expedite connection establishment, the TCP server
should retransmit the SYN/ACK with (AE,CWR,ECE) = (0,0,0) and without the
AccECN option, while maintaining AccECN feedback mode.

This complies with Section 3.2.3.2.2 of the AccECN spec RFC9768.

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-10-chia-yu.chang@nokia-bell-labs.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Chia-Yu Chang and committed by
Paolo Abeni
f326f1f1 f1eaea55

+17 -7
+15 -5
include/net/tcp_ecn.h
··· 649 649 } 650 650 651 651 static inline void 652 - tcp_ecn_make_synack(const struct request_sock *req, struct tcphdr *th) 652 + tcp_ecn_make_synack(const struct request_sock *req, struct tcphdr *th, 653 + enum tcp_synack_type synack_type) 653 654 { 654 - if (tcp_rsk(req)->accecn_ok) 655 - tcp_accecn_echo_syn_ect(th, tcp_rsk(req)->syn_ect_rcv); 656 - else if (inet_rsk(req)->ecn_ok) 657 - th->ece = 1; 655 + /* Accurate ECN shall retransmit SYN/ACK with ACE=0 if the 656 + * previously retransmitted SYN/ACK also times out. 657 + */ 658 + if (!req->num_timeout || synack_type != TCP_SYNACK_RETRANS) { 659 + if (tcp_rsk(req)->accecn_ok) 660 + tcp_accecn_echo_syn_ect(th, tcp_rsk(req)->syn_ect_rcv); 661 + else if (inet_rsk(req)->ecn_ok) 662 + th->ece = 1; 663 + } else if (tcp_rsk(req)->accecn_ok) { 664 + th->ae = 0; 665 + th->cwr = 0; 666 + th->ece = 0; 667 + } 658 668 } 659 669 660 670 static inline bool tcp_accecn_option_beacon_check(const struct sock *sk)
+2 -2
net/ipv4/tcp_output.c
··· 1106 1106 1107 1107 if (treq->accecn_ok && 1108 1108 READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn_option) && 1109 - req->num_timeout < 1 && remaining >= TCPOLEN_ACCECN_BASE) { 1109 + synack_type != TCP_SYNACK_RETRANS && remaining >= TCPOLEN_ACCECN_BASE) { 1110 1110 opts->use_synack_ecn_bytes = 1; 1111 1111 remaining -= tcp_options_fit_accecn(opts, 0, remaining); 1112 1112 } ··· 4012 4012 memset(th, 0, sizeof(struct tcphdr)); 4013 4013 th->syn = 1; 4014 4014 th->ack = 1; 4015 - tcp_ecn_make_synack(req, th); 4015 + tcp_ecn_make_synack(req, th, synack_type); 4016 4016 th->source = htons(ireq->ir_num); 4017 4017 th->dest = ireq->ir_rmt_port; 4018 4018 skb->mark = ireq->ir_mark;