tcp (fixes #966): Suppress cwnd growth when rate-limited
This commit is contained in:
@@ -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
|
||||
-------------------------------
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user