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: handle unexpected AccECN negotiation feedback

According to Sections 3.1.2 and 3.1.3 of AccECN spec (RFC9768).

In Section 3.1.2, it says an AccECN implementation has no need to
recognize or support the Server response labelled 'Nonce' or ECN-nonce
feedback more generally, as RFC 3540 has been reclassified as Historic.
AccECN is compatible with alternative ECN feedback integrity approaches
to the nonce. The SYN/ACK labelled 'Nonce' with (AE,CWR,ECE) = (1,0,1)
is reserved for future use. A TCP Client (A) that receives such a SYN/ACK
follows the procedure for forward compatibility given in Section 3.1.3.

Then in Section 3.1.3, it says if a TCP Client has sent a SYN requesting
AccECN feedback with (AE,CWR,ECE) = (1,1,1) then receives a SYN/ACK with
the currently reserved combination (AE,CWR,ECE) = (1,0,1) but it does not
have logic specific to such a combination, the Client MUST enable AccECN
mode as if the SYN/ACK onfirmed that the Server supported AccECN and as
if it fed back that the IP-ECN field on the SYN had arrived unchanged.

Fixes: 3cae34274c79 ("tcp: accecn: AccECN negotiation").
Signed-off-by: Chia-Yu Chang <chia-yu.chang@nokia-bell-labs.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260131222515.8485-7-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
c5ff6b83 e68c28f2

+31 -13
+31 -13
include/net/tcp_ecn.h
··· 473 473 return TCP_ACCECN_OPT_COUNTER_SEEN; 474 474 } 475 475 476 + static inline void tcp_ecn_rcv_synack_accecn(struct sock *sk, 477 + const struct sk_buff *skb, u8 dsf) 478 + { 479 + struct tcp_sock *tp = tcp_sk(sk); 480 + 481 + tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); 482 + tp->syn_ect_rcv = dsf & INET_ECN_MASK; 483 + /* Demand Accurate ECN option in response to the SYN on the SYN/ACK 484 + * and the TCP server will try to send one more packet with an AccECN 485 + * Option at a later point during the connection. 486 + */ 487 + if (tp->rx_opt.accecn && 488 + tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) { 489 + u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn); 490 + 491 + tcp_accecn_saw_opt_fail_recv(tp, saw_opt); 492 + tp->accecn_opt_demand = 2; 493 + } 494 + } 495 + 476 496 /* See Table 2 of the AccECN draft */ 477 497 static inline void tcp_ecn_rcv_synack(struct sock *sk, const struct sk_buff *skb, 478 498 const struct tcphdr *th, u8 ip_dsfield) ··· 515 495 tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); 516 496 break; 517 497 case 0x1: 518 - case 0x5: 519 498 /* +========+========+============+=============+ 520 499 * | A | B | SYN/ACK | Feedback | 521 500 * | | | B->A | Mode of A | 522 501 * | | | AE CWR ECE | | 523 502 * +========+========+============+=============+ 524 - * | AccECN | Nonce | 1 0 1 | (Reserved) | 525 503 * | AccECN | ECN | 0 0 1 | Classic ECN | 526 504 * | Nonce | AccECN | 0 0 1 | Classic ECN | 527 505 * | ECN | AccECN | 0 0 1 | Classic ECN | ··· 527 509 */ 528 510 if (tcp_ca_no_fallback_rfc3168(sk)) 529 511 tcp_ecn_mode_set(tp, TCP_ECN_DISABLED); 530 - else if (tcp_ecn_mode_pending(tp)) 531 - /* Downgrade from AccECN, or requested initially */ 512 + else 532 513 tcp_ecn_mode_set(tp, TCP_ECN_MODE_RFC3168); 533 514 break; 534 - default: 535 - tcp_ecn_mode_set(tp, TCP_ECN_MODE_ACCECN); 536 - tp->syn_ect_rcv = ip_dsfield & INET_ECN_MASK; 537 - if (tp->rx_opt.accecn && 538 - tp->saw_accecn_opt < TCP_ACCECN_OPT_COUNTER_SEEN) { 539 - u8 saw_opt = tcp_accecn_option_init(skb, tp->rx_opt.accecn); 540 - 541 - tcp_accecn_saw_opt_fail_recv(tp, saw_opt); 542 - tp->accecn_opt_demand = 2; 515 + case 0x5: 516 + if (tcp_ecn_mode_pending(tp)) { 517 + tcp_ecn_rcv_synack_accecn(sk, skb, ip_dsfield); 518 + if (INET_ECN_is_ce(ip_dsfield)) { 519 + tp->received_ce++; 520 + tp->received_ce_pending++; 521 + } 543 522 } 523 + break; 524 + default: 525 + tcp_ecn_rcv_synack_accecn(sk, skb, ip_dsfield); 544 526 if (INET_ECN_is_ce(ip_dsfield) && 545 527 tcp_accecn_validate_syn_feedback(sk, ace, 546 528 tp->syn_ect_snt)) {