diff --git a/examples/tcp/tcp-validation.cc b/examples/tcp/tcp-validation.cc index b9a8c023d..18ee32031 100644 --- a/examples/tcp/tcp-validation.cc +++ b/examples/tcp/tcp-validation.cc @@ -663,6 +663,9 @@ main(int argc, char* argv[]) Config::SetDefault("ns3::TcpSocket::InitialCwnd", UintegerValue(10)); Config::SetDefault("ns3::TcpL4Protocol::RecoveryType", TypeIdValue(TcpPrrRecovery::GetTypeId())); + // Validation criteria were written for TCP Cubic without Reno-friendly behavior, so disable it + // for these tests + Config::SetDefault("ns3::TcpCubic::TcpFriendliness", BooleanValue(false)); //////////////////////////////////////////////////////////// // command-line argument parsing // diff --git a/src/internet/model/tcp-cubic.cc b/src/internet/model/tcp-cubic.cc index 41bf4920f..6a6a987c1 100644 --- a/src/internet/model/tcp-cubic.cc +++ b/src/internet/model/tcp-cubic.cc @@ -45,6 +45,11 @@ TcpCubic::GetTypeId() BooleanValue(true), MakeBooleanAccessor(&TcpCubic::m_fastConvergence), MakeBooleanChecker()) + .AddAttribute("TcpFriendliness", + "Enable (true) or disable (false) TCP friendliness", + BooleanValue(true), + MakeBooleanAccessor(&TcpCubic::m_tcpFriendliness), + MakeBooleanChecker()) .AddAttribute("Beta", "Beta for multiplicative decrease", DoubleValue(0.7), @@ -209,7 +214,7 @@ TcpCubic::IncreaseWindow(Ptr tcb, uint32_t segmentsAcked) if (tcb->m_cWnd >= tcb->m_ssThresh && segmentsAcked > 0) { m_cWndCnt += segmentsAcked; - uint32_t cnt = Update(tcb); + uint32_t cnt = Update(tcb, segmentsAcked); /* According to RFC 6356 even once the new cwnd is * calculated you must compare this to the number of ACKs received since @@ -232,19 +237,24 @@ TcpCubic::IncreaseWindow(Ptr tcb, uint32_t segmentsAcked) } uint32_t -TcpCubic::Update(Ptr tcb) +TcpCubic::Update(Ptr tcb, uint32_t segmentsAcked) { NS_LOG_FUNCTION(this); Time t; uint32_t delta; uint32_t bicTarget; uint32_t cnt = 0; + uint32_t maxCnt; double offs; uint32_t segCwnd = tcb->GetCwndInSegments(); + m_ackCnt += segmentsAcked; + if (m_epochStart == Time::Min()) { m_epochStart = Simulator::Now(); // record the beginning of an epoch + m_ackCnt = segmentsAcked; + m_tcpCwnd = segCwnd; if (m_lastMaxCwnd <= segCwnd) { @@ -311,6 +321,26 @@ TcpCubic::Update(Ptr tcb) cnt = m_cntClamp; } + if (m_tcpFriendliness) + { + auto scale = static_cast(8 * (1024 + m_beta * 1024) / 3 / (1024 - m_beta * 1024)); + delta = (segCwnd * scale) >> 3; + while (m_ackCnt > delta) + { + m_ackCnt -= delta; + m_tcpCwnd++; + } + if (m_tcpCwnd > segCwnd) + { + delta = m_tcpCwnd - segCwnd; + maxCnt = segCwnd / delta; + if (cnt > maxCnt) + { + cnt = maxCnt; + } + } + } + // The maximum rate of cwnd increase CUBIC allows is 1 packet per // 2 packets ACKed, meaning cwnd grows at 1.5x per RTT. return std::max(cnt, 2U); @@ -463,6 +493,8 @@ TcpCubic::CubicReset(Ptr tcb) m_lastMaxCwnd = 0; m_bicOriginPoint = 0; m_bicK = 0; + m_ackCnt = 0; + m_tcpCwnd = 0; m_delayMin = Time::Min(); m_found = false; } diff --git a/src/internet/model/tcp-cubic.h b/src/internet/model/tcp-cubic.h index c395b3888..9da52ee1b 100644 --- a/src/internet/model/tcp-cubic.h +++ b/src/internet/model/tcp-cubic.h @@ -104,6 +104,7 @@ class TcpCubic : public TcpCongestionOps private: bool m_fastConvergence; //!< Enable or disable fast convergence algorithm + bool m_tcpFriendliness; //!< Enable or disable TCP-friendliness heuristic double m_beta; //!< Beta for cubic multiplicative increase bool m_hystart; //!< Enable or disable HyStart algorithm @@ -134,6 +135,8 @@ class TcpCubic : public TcpCongestionOps Time m_cubicDelta; //!< Time to wait after recovery before update Time m_currRtt; //!< Current Rtt uint32_t m_sampleCnt; //!< Count of samples for HyStart + uint32_t m_ackCnt; //!< Count the number of ACKed packets + uint32_t m_tcpCwnd; //!< Estimated tcp cwnd (for Reno-friendliness) private: /** @@ -151,9 +154,10 @@ class TcpCubic : public TcpCongestionOps /** * \brief Cubic window update after a new ack received * \param tcb Transmission Control Block of the connection + * \param segmentsAcked Segments acked * \returns the congestion window update counter */ - uint32_t Update(Ptr tcb); + uint32_t Update(Ptr tcb, uint32_t segmentsAcked); /** * \brief Update HyStart parameters