# HG changeset patch # User Tommaso Pecorella # Date 1424677743 -3600 # Parent 4c6637fccb7b242f8731a0ce1d7228240057b6be Bug 2067 - TCP performances drop when Advertised Window is larger than Sender Buffer size diff --git a/src/applications/model/bulk-send-application.cc b/src/applications/model/bulk-send-application.cc --- a/src/applications/model/bulk-send-application.cc +++ b/src/applications/model/bulk-send-application.cc @@ -224,7 +224,7 @@ if (m_connected) { // Only send new data if the connection has completed - Simulator::ScheduleNow (&BulkSendApplication::SendData, this); + SendData (); } } diff --git a/src/internet/model/tcp-newreno.cc b/src/internet/model/tcp-newreno.cc --- a/src/internet/model/tcp-newreno.cc +++ b/src/internet/model/tcp-newreno.cc @@ -182,7 +182,10 @@ { // Increase cwnd for every additional dupack (RFC2582, sec.3 bullet #3) m_cWnd += m_segmentSize; NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_cWnd); - SendPendingData (m_connected); + if (!m_sendPendingDataEvent.IsRunning ()) + { + SendPendingData (m_connected); + } } else if (!m_inFastRec && m_limitedTx && m_txBuffer->SizeFromSequence (m_nextTxSequence) > 0) { // RFC3042 Limited transmit: Send a new packet for each duplicated ACK before fast retransmit @@ -261,4 +264,10 @@ m_ssThresh = m_initialSsThresh; } +void +TcpNewReno::ScaleSsThresh (uint8_t scaleFactor) +{ + m_ssThresh <<= scaleFactor; +} + } // namespace ns3 diff --git a/src/internet/model/tcp-newreno.h b/src/internet/model/tcp-newreno.h --- a/src/internet/model/tcp-newreno.h +++ b/src/internet/model/tcp-newreno.h @@ -69,6 +69,8 @@ virtual uint32_t GetInitialSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); virtual uint32_t GetInitialCwnd (void) const; + virtual void ScaleSsThresh (uint8_t scaleFactor); + private: /** * \brief Set the congestion window when connection starts diff --git a/src/internet/model/tcp-reno.cc b/src/internet/model/tcp-reno.cc --- a/src/internet/model/tcp-reno.cc +++ b/src/internet/model/tcp-reno.cc @@ -164,7 +164,10 @@ { // In fast recovery, inc cwnd for every additional dupack (RFC2581, sec.3.2) m_cWnd += m_segmentSize; NS_LOG_INFO ("Increased cwnd to " << m_cWnd); - SendPendingData (m_connected); + if (!m_sendPendingDataEvent.IsRunning ()) + { + SendPendingData (m_connected); + } }; } @@ -236,4 +239,11 @@ m_ssThresh = m_initialSsThresh; } +void +TcpReno::ScaleSsThresh (uint8_t scaleFactor) +{ + m_ssThresh <<= scaleFactor; +} + + } // namespace ns3 diff --git a/src/internet/model/tcp-reno.h b/src/internet/model/tcp-reno.h --- a/src/internet/model/tcp-reno.h +++ b/src/internet/model/tcp-reno.h @@ -71,6 +71,8 @@ virtual uint32_t GetInitialSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); virtual uint32_t GetInitialCwnd (void) const; + virtual void ScaleSsThresh (uint8_t scaleFactor); + private: /** * \brief Set the congestion window when connection starts diff --git a/src/internet/model/tcp-rfc793.cc b/src/internet/model/tcp-rfc793.cc --- a/src/internet/model/tcp-rfc793.cc +++ b/src/internet/model/tcp-rfc793.cc @@ -88,4 +88,19 @@ return 0; } +uint32_t +TcpRfc793::Window () +{ + NS_LOG_FUNCTION (this); + return m_rWnd; +} + +void +TcpRfc793::ScaleSsThresh (uint8_t scaleFactor) +{ + NS_LOG_WARN ("DoD TCP does not perform slow start"); + return; +} + + } // namespace ns3 diff --git a/src/internet/model/tcp-rfc793.h b/src/internet/model/tcp-rfc793.h --- a/src/internet/model/tcp-rfc793.h +++ b/src/internet/model/tcp-rfc793.h @@ -62,6 +62,10 @@ virtual uint32_t GetInitialSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); virtual uint32_t GetInitialCwnd (void) const; + + virtual uint32_t Window (void); + virtual void ScaleSsThresh (uint8_t scaleFactor); + }; } // namespace ns3 diff --git a/src/internet/model/tcp-socket-base.cc b/src/internet/model/tcp-socket-base.cc --- a/src/internet/model/tcp-socket-base.cc +++ b/src/internet/model/tcp-socket-base.cc @@ -600,7 +600,10 @@ NS_LOG_LOGIC ("txBufSize=" << m_txBuffer->Size () << " state " << TcpStateName[m_state]); if (m_state == ESTABLISHED || m_state == CLOSE_WAIT) { // Try to send the data out - SendPendingData (m_connected); + if (!m_sendPendingDataEvent.IsRunning ()) + { + m_sendPendingDataEvent = Simulator::Schedule ( TimeStep (1), &TcpSocketBase::SendPendingData, this, m_connected); + } } return p->GetSize (); } @@ -947,8 +950,7 @@ NS_LOG_LOGIC (this << " Leaving zerowindow persist state"); m_persistEvent.Cancel (); } - m_rWnd = tcpHeader.GetWindowSize (); - m_rWnd <<= m_rcvScaleFactor; + m_rWnd = (uint32_t(tcpHeader.GetWindowSize ()) << m_rcvScaleFactor); // Discard fully out of range data packets if (packet->GetSize () @@ -1051,8 +1053,7 @@ NS_LOG_LOGIC (this << " Leaving zerowindow persist state"); m_persistEvent.Cancel (); } - m_rWnd = tcpHeader.GetWindowSize (); - m_rWnd <<= m_rcvScaleFactor; + m_rWnd = (uint32_t(tcpHeader.GetWindowSize ()) << m_rcvScaleFactor); // Discard fully out of range packets if (packet->GetSize () @@ -2063,7 +2064,6 @@ if (m_txBuffer->Size () == 0) { return false; // Nothing to send - } if (m_endPoint == 0 && m_endPoint6 == 0) { @@ -2074,17 +2074,10 @@ while (m_txBuffer->SizeFromSequence (m_nextTxSequence)) { uint32_t w = AvailableWindow (); // Get available window size - NS_LOG_LOGIC ("TcpSocketBase " << this << " SendPendingData" << - " w " << w << - " rxwin " << m_rWnd << - " segsize " << m_segmentSize << - " nextTxSeq " << m_nextTxSequence << - " highestRxAck " << m_txBuffer->HeadSequence () << - " pd->Size " << m_txBuffer->Size () << - " pd->SFS " << m_txBuffer->SizeFromSequence (m_nextTxSequence)); // Stop sending if we need to wait for a larger Tx window (prevent silly window syndrome) if (w < m_segmentSize && m_txBuffer->SizeFromSequence (m_nextTxSequence) > w) { + NS_LOG_LOGIC ("Preventing Silly Window Syndrome. Wait to send."); break; // No more } // Nagle's algorithm (RFC896): Hold off sending if there is unacked data @@ -2095,6 +2088,14 @@ NS_LOG_LOGIC ("Invoking Nagle's algorithm. Wait to send."); break; } + NS_LOG_LOGIC ("TcpSocketBase " << this << " SendPendingData" << + " w " << w << + " rxwin " << m_rWnd << + " segsize " << m_segmentSize << + " nextTxSeq " << m_nextTxSequence << + " highestRxAck " << m_txBuffer->HeadSequence () << + " pd->Size " << m_txBuffer->Size () << + " pd->SFS " << m_txBuffer->SizeFromSequence (m_nextTxSequence)); uint32_t s = std::min (w, m_segmentSize); // Send no more than window uint32_t sz = SendDataPacket (m_nextTxSequence, s, withAck); nPacketsSent++; // Count sent this loop @@ -2119,13 +2120,6 @@ } uint32_t -TcpSocketBase::Window () -{ - NS_LOG_FUNCTION (this); - return m_rWnd; -} - -uint32_t TcpSocketBase::AvailableWindow () { NS_LOG_FUNCTION_NOARGS (); @@ -2313,7 +2307,10 @@ m_retxEvent.Cancel (); } // Try to send more data - SendPendingData (m_connected); + if (!m_sendPendingDataEvent.IsRunning ()) + { + m_sendPendingDataEvent = Simulator::Schedule ( TimeStep (1), &TcpSocketBase::SendPendingData, this, m_connected); + } } // Retransmit timeout @@ -2450,6 +2447,7 @@ m_delAckEvent.Cancel (); m_lastAckEvent.Cancel (); m_timewaitEvent.Cancel (); + m_sendPendingDataEvent.Cancel (); } /* Move TCP to Time_Wait state and schedule a transition to Closed state */ @@ -2604,6 +2602,7 @@ { m_winScalingEnabled = true; ProcessOptionWScale (header.GetOption (TcpOption::WINSCALE)); + ScaleSsThresh (m_sndScaleFactor); } } } diff --git a/src/internet/model/tcp-socket-base.h b/src/internet/model/tcp-socket-base.h --- a/src/internet/model/tcp-socket-base.h +++ b/src/internet/model/tcp-socket-base.h @@ -518,7 +518,7 @@ * \brief Return the max possible number of unacked bytes * \returns the max possible number of unacked bytes */ - virtual uint32_t Window (void); + virtual uint32_t Window (void) = 0; /** * \brief Return unfilled portion of window @@ -675,6 +675,15 @@ */ void AddOptionTimestamp (TcpHeader& header); + /** + * \brief Scale the initial SsThresh value to the correct one + * + * Set the initial SsThresh to the largest possible advertised window + * according to the sender scale factor. + * + * \param scaleFactor the sender scale factor + */ + virtual void ScaleSsThresh (uint8_t scaleFactor) = 0; protected: // Counters and events @@ -736,6 +745,8 @@ bool m_timestampEnabled; //!< Timestamp option enabled uint32_t m_timestampToEcho; //!< Timestamp to echo + + EventId m_sendPendingDataEvent; //!< micro-delay event to send pending data }; } // namespace ns3 diff --git a/src/internet/model/tcp-tahoe.cc b/src/internet/model/tcp-tahoe.cc --- a/src/internet/model/tcp-tahoe.cc +++ b/src/internet/model/tcp-tahoe.cc @@ -214,4 +214,11 @@ m_ssThresh = m_initialSsThresh; } +void +TcpTahoe::ScaleSsThresh (uint8_t scaleFactor) +{ + m_ssThresh <<= scaleFactor; +} + + } // namespace ns3 diff --git a/src/internet/model/tcp-tahoe.h b/src/internet/model/tcp-tahoe.h --- a/src/internet/model/tcp-tahoe.h +++ b/src/internet/model/tcp-tahoe.h @@ -75,6 +75,7 @@ virtual uint32_t GetInitialSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); virtual uint32_t GetInitialCwnd (void) const; + virtual void ScaleSsThresh (uint8_t scaleFactor); private: /** * \brief Set the congestion window when connection starts diff --git a/src/internet/model/tcp-westwood.cc b/src/internet/model/tcp-westwood.cc --- a/src/internet/model/tcp-westwood.cc +++ b/src/internet/model/tcp-westwood.cc @@ -292,7 +292,10 @@ {// Increase cwnd for every additional DUPACK as in Reno m_cWnd += m_segmentSize; NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_cWnd); - SendPendingData (m_connected); + if (!m_sendPendingDataEvent.IsRunning ()) + { + SendPendingData (m_connected); + } } } @@ -425,4 +428,11 @@ m_ssThresh = m_initialSsThresh; } +void +TcpWestwood::ScaleSsThresh (uint8_t scaleFactor) +{ + m_ssThresh <<= scaleFactor; +} + + } // namespace ns3 diff --git a/src/internet/model/tcp-westwood.h b/src/internet/model/tcp-westwood.h --- a/src/internet/model/tcp-westwood.h +++ b/src/internet/model/tcp-westwood.h @@ -126,6 +126,7 @@ virtual uint32_t GetInitialSSThresh (void) const; virtual void SetInitialCwnd (uint32_t cwnd); virtual uint32_t GetInitialCwnd (void) const; + virtual void ScaleSsThresh (uint8_t scaleFactor); private: /**