tcp (fixes #966): Suppress cwnd growth when rate-limited

This commit is contained in:
Tom Henderson
2024-05-17 14:10:18 -07:00
parent 2bbcec0688
commit f75345fa03
10 changed files with 55 additions and 6 deletions

View File

@@ -55,6 +55,7 @@ Applications have a new Attribute to set the IPv4 ToS field.
### Changed behavior
* Fixed the corner rebound direction in `RandomWalk2d[Outdoor]MobilityModel` and the initial direction in case of node starting from a border or corner.
* (tcp) TcpCubic and TcpLinuxReno will no longer grow their congestion window when application-limited, now matching Linux behavior
Changes from ns-3.40 to ns-3.41
-------------------------------

View File

@@ -54,6 +54,7 @@ topocentric coordinate systems
- (bindings, core) - Introduced a helper class to manage static initialization of Time as a workaround for Cppyy3 static initialization problems.
- (bindings, lte, wifi) - Relocated statically initialized variables from header files to source files for Cppyy3 compatibility.
- (tests) - Enhanced error handling in test.py to avoid attempts to open non-existent XML files following early test termination by sanitizers.
- (tcp) #966 - Tcp Cubic (and LinuxReno) cwnd should not grow during application-limited phase
- (tcp) #1085 - Do not reset Cubic W_max upon timeout
- (wifi) #1072 - Support configuration of custom EDCA parameters via Txop attributes before device installation
- (wifi) - Fix operation in 6 GHz band (added support for FILS Discovery frames and HE 6GHz Band Capabilities information element, fixed HE Operation information element, fixed NSS selection, fixed HT and VHT not supported on 6GHz links).

View File

@@ -189,6 +189,13 @@ TcpCubic::IncreaseWindow(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked)
{
NS_LOG_FUNCTION(this << tcb << segmentsAcked);
if (!tcb->m_isCwndLimited)
{
NS_LOG_DEBUG("No increase because current cwnd " << tcb->m_cWnd
<< " is not limiting the flow");
return;
}
if (tcb->m_cWnd < tcb->m_ssThresh)
{
if (m_hystart && tcb->m_lastAckedSeq > m_endSeq)

View File

@@ -121,6 +121,7 @@ TcpDctcp::Init(Ptr<TcpSocketState> tcb)
tcb->m_useEcn = TcpSocketState::On;
tcb->m_ecnMode = TcpSocketState::DctcpEcn;
tcb->m_ectCodePoint = m_useEct0 ? TcpSocketState::Ect0 : TcpSocketState::Ect1;
SetSuppressIncreaseIfCwndLimited(false);
m_initialized = true;
}

View File

@@ -79,6 +79,13 @@ TcpLinuxReno::CongestionAvoidance(Ptr<TcpSocketState> tcb, uint32_t segmentsAcke
{
NS_LOG_FUNCTION(this << tcb << segmentsAcked);
if (m_suppressIncreaseIfCwndLimited && !tcb->m_isCwndLimited)
{
NS_LOG_DEBUG("No increase because current cwnd " << tcb->m_cWnd
<< " is not limiting the flow");
return;
}
uint32_t w = tcb->m_cWnd / tcb->m_segmentSize;
// Floor w to 1 if w == 0
@@ -150,4 +157,11 @@ TcpLinuxReno::Fork()
return CopyObject<TcpLinuxReno>(this);
}
void
TcpLinuxReno::SetSuppressIncreaseIfCwndLimited(bool value)
{
NS_LOG_FUNCTION(this << value);
m_suppressIncreaseIfCwndLimited = value;
}
} // namespace ns3

View File

@@ -76,8 +76,25 @@ class TcpLinuxReno : public TcpCongestionOps
*/
virtual void CongestionAvoidance(Ptr<TcpSocketState> tcb, uint32_t segmentsAcked);
/**
* TcpSocketBase follows the Linux way of setting a flag 'isCwndLimited'
* when BytesInFlight() >= cwnd. This flag, if true, will suppress
* additive increase window updates for this class. However, some
* derived classes using the IncreaseWindow() method may not want this
* behavior, so this method exists to allow subclasses to set it to false.
*
* \param value Value to set whether the isCwndLimited condition
* suppresses window updates
*/
void SetSuppressIncreaseIfCwndLimited(bool value);
private:
uint32_t m_cWndCnt{0}; //!< Linear increase counter
// The below flag exists for classes derived from TcpLinuxReno (such as
// TcpDctcp) that may not want to suppress cwnd increase, unlike Linux's
// tcp_reno_cong_avoid()
bool m_suppressIncreaseIfCwndLimited{
true}; //!< Suppress window increase if TCP is not cwnd limited
};
} // namespace ns3

View File

@@ -3238,6 +3238,12 @@ TcpSocketBase::SendDataPacket(SequenceNumber32 seq, uint32_t maxSize, bool withA
<< m_endPoint6->GetPeerAddress() << ". Header " << header);
}
// Signal to congestion control whether the cwnd is fully used
// This is a simple version of Linux tcp_cwnd_validate() but following
// the principle implemented in Linux that limits the updating of cwnd
// (in the congestion controls) when flight size is >= cwnd
m_tcb->m_isCwndLimited = (BytesInFlight() >= m_tcb->m_cWnd);
UpdateRttHistory(seq, sz, isRetransmission);
// Update bytes sent during recovery phase

View File

@@ -119,6 +119,7 @@ TcpSocketState::TcpSocketState(const TcpSocketState& other)
m_paceInitialWindow(other.m_paceInitialWindow),
m_minRtt(other.m_minRtt),
m_bytesInFlight(other.m_bytesInFlight),
m_isCwndLimited(other.m_isCwndLimited),
m_lastRtt(other.m_lastRtt),
m_ecnMode(other.m_ecnMode),
m_useEcn(other.m_useEcn),

View File

@@ -207,6 +207,7 @@ class TcpSocketState : public Object
Time m_minRtt{Time::Max()}; //!< Minimum RTT observed throughout the connection
TracedValue<uint32_t> m_bytesInFlight{0}; //!< Bytes in flight
bool m_isCwndLimited{false}; //!< Whether throughput is limited by cwnd
TracedValue<Time> m_lastRtt{Seconds(0.0)}; //!< Last RTT sample collected
Ptr<TcpRxBuffer> m_rxBuffer; //!< Rx buffer (reordering buffer)

View File

@@ -363,7 +363,7 @@ Ns3TcpCubicTestCase::DoRun()
true,
"cwnd outside range");
// Time just before a reduction does not have much variation
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(9), Seconds(9.7), 84, 89),
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(9), Seconds(9.6), 84, 89),
true,
"cwnd outside range");
}
@@ -380,20 +380,20 @@ Ns3TcpCubicTestCase::DoRun()
}
else if (m_prefix == "ns3-tcp-cubic-no-friendly")
{
// Between time 12 and 16, cwnd should be fairly constant
// Between time 11 and 15, cwnd should be fairly constant
// because without TCP friendliness, Cubic does not respond quickly
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(12), Seconds(16), 107, 123),
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(11), Seconds(15), 107, 123),
true,
"cwnd outside range");
// After time 19.5, cwnd should have grown much higher
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(19.5), Seconds(20), 180, 210),
// After time 17.5, cwnd should have grown much higher
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(17.5), Seconds(18.5), 170, 215),
true,
"cwnd outside range");
}
else if (m_prefix == "ns3-tcp-cubic-friendly")
{
// In contrast to previous case, cwnd should grow above 150 much sooner
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(12), Seconds(14), 150, 210),
NS_TEST_ASSERT_MSG_EQ(CheckValues(Seconds(13), Seconds(15), 150, 210),
true,
"cwnd outside range");
}