Subject: [iccrg] On RFC3168 ECN signaling in TCP implememtations

From: "Scheffenegger, Richard" <[email-masked]>
Date: Mon, 13 Jan 2020 15:44:00 +0100

Hi group,

I just wanted to report a few findings that Neil and I found while
looking into corner cases of the TCP header RFC3168 ECN flags signaling.

tl;dnr: Please confirm, that the TCP RFC3168 header flags are
independent from the IP ECT codepoint. And that CWR shall be sent
immediately whenever cwnd is reduced, including during RTO events (for
ECN-enabled sessions across a loss-only congestion point).

First, there is an implementation oversight in FBSD, for ECN+SACK
enabled sessions. While RFC3168 is quite strict in stipulating, that all
retransmissions (and control packets) are not to be sent with the
ECN-capable-transport Codepoint in the IP header, this is only true for
non-SACK loss recovery at the moment in that stack.

I have mentioned this on the tcpm list already with the subject ECN++.

Second, I found that FreeBSD (not checked OpenBSD or NetBSD) is not
setting the CWR (congestion window reduced) flag for
Retransmission-Timeout retransmissions.

This is also problematic in a larger context (which is how we found this
initially) - if the RTO happens due to lost retransmissions, and CE is
set during the same window - while loss recovery is happening - the lack
of the CWR bit will keep the latched ECE flag on the receiver to remain set.

Thus, the ACK for the RTO retransmission is returned with ECE still set
- preventing the growth of cwnd in this first RTT after RTO. On top, the
RTO has a 0.5 probability to run into the delayed ACK timeout. The 1st
packet thereafter, sent with the ECE-marked ACK, will have a probabiliy
of 1.0 to wait for an delayed ACK timeout.

In that cornercase (two different congestion points, one with loss-only
and one with ECN), the above reults in very sluggish recovery from an
RTO, since the cwnd is also set to 1 MSS when the RTO happens.

While discussing this with Neal, he found that there exists another
oversight on the Linux side. Apparently, TCP ECN header flags are only
set when the IP packet of the segment is also ECT-marked.

With other words, during RTO the Linux stack does want to send out the
CWR bit (as we believe is the correct behavior), but doesn't because
that RTO retransmission is sent without the ECN-capable-transport
codepoint in the IP header.

Effectively, a similar scenario as in the FreeBSD plays out - the RTO is
sent, doesn't clear the latched ECE flag on the receiver; the ACK to the
RTO retransmission still carries an ECE flag, to which the stack then
responds by reducing cwnd once more (to 1 segment), setting CWR only
then (or when the first new data segment is transmitted).

We wanted to confirm if our understaning of RFC3168 signaling is
correct, and what the expected interaction between RFC3168 signaling
with loss / RTO should be.

Best regards,
   Richard