TCP: DcTcp behaves incorrectly with non-ECN routers

DcTcp behaves incorrectly if there are packet losses due to drop in routers, e.g. due to the router not being ECN-aware or being short on memory.

From RFC 8257:

3.5. Handling of Packet Loss

A DCTCP sender MUST react to loss episodes in the same way as conventional TCP, including fast retransmit and fast recovery algorithms, as specified in [RFC5681]. For cases where the packet loss is inferred and not explicitly signaled by ECN, the cwnd and other state variables like ssthresh MUST be changed in the same way that a conventional TCP would have changed them.

The RFC mandates different ways of reducing ssthresh depending on the type of the congestion event (loss or ECN), However, apparently TcpDctcp:GetSsThresh ignores the type of the loss event (e.g. packet loss or ECN).

uint32_t
TcpDctcp::GetSsThresh(Ptr<const TcpSocketState> tcb, uint32_t bytesInFlight)
{
    NS_LOG_FUNCTION(this << tcb << bytesInFlight);
    return static_cast<uint32_t>((1 - m_alpha / 2.0) * tcb->m_cWnd);
}

Moreover, m_alpha converges to zero because m_ackedBytesEcn is always zero (non-ECN aware routers).

if (m_ackedBytesTotal > 0)
{
    bytesEcn = static_cast<double>(m_ackedBytesEcn * 1.0 / m_ackedBytesTotal);
}
m_alpha = (1.0 - m_g) * m_alpha + m_g * bytesEcn;