Merged Fast Recovery and Fast Retransmit in TcpSocketBase
Since RFC 5681 defines Fast Recovery and Fast Retransmit, it has no sense to replicate these algorithms over all TCP variants. The only thing that a variant is allowed to do is using a different slow start threshold: for example, TcpWestwood uses an estimate of the bandwidth to calculate it. So, its calculus has been delegated to a virtual function GetSsThresh which replaces the old DupAck(). Fixed a bug in Tcp Tahoe implementation (slow start threshold diminuished only from an RTO). Fixed a bug on the inflation of the cWnd; it should be inflated of m_dupAckCount segments (and not only 3, which is OK for the default value of m_reTxThresh, but not for the others).
This commit is contained in:
@@ -41,31 +41,18 @@ TcpNewReno::GetTypeId (void)
|
||||
.SetParent<TcpSocketBase> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor<TcpNewReno> ()
|
||||
.AddAttribute ("ReTxThreshold", "Threshold for fast retransmit",
|
||||
UintegerValue (3),
|
||||
MakeUintegerAccessor (&TcpNewReno::m_retxThresh),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("LimitedTransmit", "Enable limited transmit",
|
||||
BooleanValue (false),
|
||||
MakeBooleanAccessor (&TcpNewReno::m_limitedTx),
|
||||
MakeBooleanChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpNewReno::TcpNewReno (void)
|
||||
: m_retxThresh (3), // mute valgrind, actual value set by the attribute system
|
||||
m_inFastRec (false),
|
||||
m_limitedTx (false) // mute valgrind, actual value set by the attribute system
|
||||
: TcpSocketBase ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
TcpNewReno::TcpNewReno (const TcpNewReno& sock)
|
||||
: TcpSocketBase (sock),
|
||||
m_retxThresh (sock.m_retxThresh),
|
||||
m_inFastRec (false),
|
||||
m_limitedTx (sock.m_limitedTx)
|
||||
: TcpSocketBase (sock)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("Invoked the copy constructor");
|
||||
@@ -90,22 +77,12 @@ TcpNewReno::NewAck (const SequenceNumber32& seq)
|
||||
" cwnd " << m_cWnd <<
|
||||
" ssthresh " << m_ssThresh);
|
||||
|
||||
// Check for exit condition of fast recovery
|
||||
// No cWnd management while recovering
|
||||
if (m_inFastRec && seq < m_recover)
|
||||
{ // Partial ACK, partial window deflation (RFC2582 sec.3 bullet #5 paragraph 3)
|
||||
m_cWnd += m_segmentSize - (seq - m_txBuffer->HeadSequence ());
|
||||
NS_LOG_INFO ("Partial ACK for seq " << seq << " in fast recovery: cwnd set to " << m_cWnd);
|
||||
m_txBuffer->DiscardUpTo(seq); //Bug 1850: retransmit before newack
|
||||
DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
|
||||
TcpSocketBase::NewAck (seq); // update m_nextTxSequence and send new data if allowed by window
|
||||
{
|
||||
TcpSocketBase::NewAck (seq);
|
||||
return;
|
||||
}
|
||||
else if (m_inFastRec && seq >= m_recover)
|
||||
{ // Full ACK (RFC2582 sec.3 bullet #5 paragraph 2, option 1)
|
||||
m_cWnd = std::min (m_ssThresh.Get (), BytesInFlight () + m_segmentSize);
|
||||
m_inFastRec = false;
|
||||
NS_LOG_INFO ("Received full ACK for seq " << seq <<". Leaving fast recovery with cwnd set to " << m_cWnd);
|
||||
}
|
||||
|
||||
// Increase of cwnd based on current phase (slow start or congestion avoidance)
|
||||
if (m_cWnd < m_ssThresh)
|
||||
@@ -126,60 +103,10 @@ TcpNewReno::NewAck (const SequenceNumber32& seq)
|
||||
TcpSocketBase::NewAck (seq);
|
||||
}
|
||||
|
||||
/* Cut cwnd and enter fast recovery mode upon triple dupack */
|
||||
void
|
||||
TcpNewReno::DupAck (const TcpHeader& t, uint32_t count)
|
||||
uint32_t
|
||||
TcpNewReno::GetSsThresh ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this << count);
|
||||
if (count == m_retxThresh && !m_inFastRec)
|
||||
{ // triple duplicate ack triggers fast retransmit (RFC2582 sec.3 bullet #1)
|
||||
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
m_cWnd = m_ssThresh + 3 * m_segmentSize;
|
||||
m_recover = m_highTxMark;
|
||||
m_inFastRec = true;
|
||||
NS_LOG_INFO ("Triple dupack. Enter fast recovery mode. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << " at fast recovery seqnum " << m_recover);
|
||||
DoRetransmit ();
|
||||
}
|
||||
else if (m_inFastRec)
|
||||
{ // 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);
|
||||
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
|
||||
NS_LOG_INFO ("Limited transmit");
|
||||
uint32_t sz = SendDataPacket (m_nextTxSequence, m_segmentSize, true);
|
||||
m_nextTxSequence += sz; // Advance next tx sequence
|
||||
};
|
||||
}
|
||||
|
||||
/* Retransmit timeout */
|
||||
void
|
||||
TcpNewReno::Retransmit (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
|
||||
m_inFastRec = false;
|
||||
|
||||
// If erroneous timeout in closed/timed-wait state, just return
|
||||
if (m_state == CLOSED || m_state == TIME_WAIT) return;
|
||||
// If all data are received (non-closing socket and nothing to send), just return
|
||||
if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence () >= m_highTxMark) return;
|
||||
|
||||
// According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight
|
||||
// size and cwnd is set to 1*MSS, then the lost packet is retransmitted and
|
||||
// TCP back to slow start
|
||||
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
m_cWnd = m_segmentSize;
|
||||
m_nextTxSequence = m_txBuffer->HeadSequence (); // Restart from highest Ack
|
||||
NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
return std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -55,14 +55,7 @@ public:
|
||||
protected:
|
||||
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpNewReno> to clone me
|
||||
virtual void NewAck (SequenceNumber32 const& seq); // Inc cwnd and call NewAck() of parent
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count); // Halving cwnd and reset nextTxSequence
|
||||
virtual void Retransmit (void); // Exit fast recovery upon retransmit timeout
|
||||
|
||||
protected:
|
||||
SequenceNumber32 m_recover; //!< Previous highest Tx seqnum for fast recovery
|
||||
uint32_t m_retxThresh; //!< Fast Retransmit threshold
|
||||
bool m_inFastRec; //!< currently in fast recovery
|
||||
bool m_limitedTx; //!< perform limited transmit
|
||||
virtual uint32_t GetSsThresh ();
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -118,6 +118,14 @@ TcpSocketBase::GetTypeId (void)
|
||||
PointerValue (),
|
||||
MakePointerAccessor (&TcpSocketBase::GetRxBuffer),
|
||||
MakePointerChecker<TcpRxBuffer> ())
|
||||
.AddAttribute ("ReTxThreshold", "Threshold for fast retransmit",
|
||||
UintegerValue (3),
|
||||
MakeUintegerAccessor (&TcpSocketBase::m_retxThresh),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("LimitedTransmit", "Enable limited transmit",
|
||||
BooleanValue (true),
|
||||
MakeBooleanAccessor (&TcpSocketBase::m_limitedTx),
|
||||
MakeBooleanChecker ())
|
||||
.AddTraceSource ("RTO",
|
||||
"Retransmission timeout",
|
||||
MakeTraceSourceAccessor (&TcpSocketBase::m_rto),
|
||||
@@ -195,7 +203,10 @@ TcpSocketBase::TcpSocketBase (void)
|
||||
m_rcvScaleFactor (0),
|
||||
m_timestampEnabled (true),
|
||||
m_timestampToEcho (0),
|
||||
m_ackState (OPEN)
|
||||
m_ackState (OPEN),
|
||||
m_retxThresh (3),
|
||||
m_inFastRec (false),
|
||||
m_limitedTx (false)
|
||||
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
@@ -243,7 +254,10 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
|
||||
m_rcvScaleFactor (sock.m_rcvScaleFactor),
|
||||
m_timestampEnabled (sock.m_timestampEnabled),
|
||||
m_timestampToEcho (sock.m_timestampToEcho),
|
||||
m_ackState (sock.m_ackState)
|
||||
m_ackState (sock.m_ackState),
|
||||
m_retxThresh (sock.m_retxThresh),
|
||||
m_inFastRec (false),
|
||||
m_limitedTx (sock.m_limitedTx)
|
||||
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
@@ -1196,7 +1210,38 @@ TcpSocketBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
|
||||
if (tcpHeader.GetAckNumber () < m_nextTxSequence && packet->GetSize() == 0)
|
||||
{
|
||||
NS_LOG_LOGIC ("Dupack of " << tcpHeader.GetAckNumber ());
|
||||
DupAck (tcpHeader, ++m_dupAckCount);
|
||||
++m_dupAckCount;
|
||||
|
||||
if (m_dupAckCount == m_retxThresh && !m_inFastRec)
|
||||
{ // triple duplicate ack triggers fast retransmit (RFC2582 sec.3 bullet #1)
|
||||
m_recover = m_highTxMark;
|
||||
m_inFastRec = true;
|
||||
|
||||
m_ssThresh = GetSsThresh ();
|
||||
m_cWnd = m_ssThresh + m_dupAckCount * m_segmentSize;
|
||||
|
||||
NS_LOG_INFO (m_dupAckCount << " dupack. Enter fast recovery mode." <<
|
||||
"Reset cwnd to " << m_cWnd << ", ssthresh to " <<
|
||||
m_ssThresh << " at fast recovery seqnum " << m_recover);
|
||||
DoRetransmit ();
|
||||
|
||||
NS_LOG_DEBUG ("DISORDER -> RECOVERY");
|
||||
}
|
||||
else if (m_inFastRec)
|
||||
{ // 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);
|
||||
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
|
||||
NS_LOG_INFO ("Limited transmit");
|
||||
uint32_t sz = SendDataPacket (m_nextTxSequence, m_segmentSize, true);
|
||||
m_nextTxSequence += sz; // Advance next tx sequence
|
||||
}
|
||||
}
|
||||
// otherwise, the ACK is precisely equal to the nextTxSequence
|
||||
NS_ASSERT (tcpHeader.GetAckNumber () <= m_nextTxSequence);
|
||||
@@ -1204,6 +1249,24 @@ TcpSocketBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
|
||||
else if (tcpHeader.GetAckNumber () > m_txBuffer->HeadSequence ())
|
||||
{ // Case 3: New ACK, reset m_dupAckCount and update m_txBuffer
|
||||
NS_LOG_LOGIC ("New ack of " << tcpHeader.GetAckNumber ());
|
||||
|
||||
// Check for exit condition of fast recovery
|
||||
if (m_inFastRec && tcpHeader.GetAckNumber () < m_recover)
|
||||
{ // Partial ACK, partial window deflation (RFC2582 sec.3 bullet #5 paragraph 3)
|
||||
m_cWnd += m_segmentSize - (tcpHeader.GetAckNumber () - m_txBuffer->HeadSequence ());
|
||||
NS_LOG_INFO ("Partial ACK for seq " << tcpHeader.GetAckNumber () << " in fast recovery: cwnd set to " << m_cWnd);
|
||||
m_txBuffer->DiscardUpTo(tcpHeader.GetAckNumber ()); //Bug 1850: retransmit before newack
|
||||
DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
|
||||
TcpSocketBase::NewAck (tcpHeader.GetAckNumber ()); // update m_nextTxSequence and send new data if allowed by window
|
||||
return;
|
||||
}
|
||||
else if (m_inFastRec && tcpHeader.GetAckNumber () >= m_recover)
|
||||
{ // Full ACK (RFC2582 sec.3 bullet #5 paragraph 2, option 1)
|
||||
m_cWnd = std::min (m_ssThresh.Get (), BytesInFlight () + m_segmentSize);
|
||||
m_inFastRec = false;
|
||||
NS_LOG_INFO ("Received full ACK for seq " << tcpHeader.GetAckNumber () <<". Leaving fast recovery with cwnd set to " << m_cWnd);
|
||||
}
|
||||
|
||||
NewAck (tcpHeader.GetAckNumber ());
|
||||
m_dupAckCount = 0;
|
||||
}
|
||||
@@ -2400,9 +2463,23 @@ TcpSocketBase::PersistTimeout ()
|
||||
void
|
||||
TcpSocketBase::Retransmit ()
|
||||
{
|
||||
m_nextTxSequence = m_txBuffer->HeadSequence (); // Start from highest Ack
|
||||
m_inFastRec = false;
|
||||
|
||||
// If erroneous timeout in closed/timed-wait state, just return
|
||||
if (m_state == CLOSED || m_state == TIME_WAIT) return;
|
||||
// If all data are received (non-closing socket and nothing to send), just return
|
||||
if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence () >= m_highTxMark) return;
|
||||
|
||||
// According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight
|
||||
// size and cwnd is set to 1*MSS, then the lost packet is retransmitted and
|
||||
// TCP back to slow start
|
||||
m_ssThresh = GetSsThresh ();
|
||||
m_cWnd = m_segmentSize;
|
||||
m_nextTxSequence = m_txBuffer->HeadSequence (); // Restart from highest Ack
|
||||
m_dupAckCount = 0;
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -87,6 +87,34 @@ typedef std::deque<RttHistory> RttHistory_t;
|
||||
* provides connection orientation and sliding window flow control. Part of
|
||||
* this class is modified from the original NS-3 TCP socket implementation
|
||||
* (TcpSocketImpl) by Raj Bhattacharjea <raj.b@gatech.edu> of Georgia Tech.
|
||||
*
|
||||
*
|
||||
* Fast retransmit
|
||||
* ---------------------------
|
||||
*
|
||||
* The fast retransmit enhancement is introduced in RFC 2581 and updated in
|
||||
* RFC 5681. It basically reduces the time a sender waits before retransmitting
|
||||
* a lost segment, through the assumption that if it receives a certain number
|
||||
* of duplicate ACKs, a segment has been lost and it can be retransmitted.
|
||||
* Usually it is coupled with the Limited Transmit algorithm, defined in
|
||||
* RFC 3042.
|
||||
*
|
||||
* In ns-3, these algorithms are included in this class, and it is implemented inside
|
||||
* the ReceivedAck method. The attribute which manages the number of dup ACKs
|
||||
* necessary to start the fast retransmit algorithm is named "ReTxThreshold",
|
||||
* and its default value is 3, while the Limited Transmit one can be enabled
|
||||
* by setting the attribute "LimitedTransmit" to true.
|
||||
*
|
||||
* Fast recovery
|
||||
* --------------------------
|
||||
*
|
||||
* The fast recovery algorithm is introduced RFC 2001, and it basically
|
||||
* avoids to reset cWnd to 1 segment after sensing a loss on the channel. Instead,
|
||||
* the slow start threshold is halved, and the cWnd is set equal to such value,
|
||||
* plus segments for the cWnd inflation.
|
||||
*
|
||||
* The algorithm is implemented in the ReceivedAck method.
|
||||
*
|
||||
*/
|
||||
class TcpSocketBase : public TcpSocket
|
||||
{
|
||||
@@ -612,11 +640,9 @@ protected:
|
||||
virtual void NewAck (SequenceNumber32 const& seq);
|
||||
|
||||
/**
|
||||
* \brief Received dupack (duplicate ACK)
|
||||
* \param tcpHeader the packet's TCP header
|
||||
* \param count counter of duplicate ACKs
|
||||
*/
|
||||
virtual void DupAck (const TcpHeader& tcpHeader, uint32_t count) = 0;
|
||||
* \brief Get the new value of slow start threshold after a loss event
|
||||
*/
|
||||
virtual uint32_t GetSsThresh () = 0;
|
||||
|
||||
/**
|
||||
* \brief Call Retransmit() upon RTO event
|
||||
@@ -809,7 +835,14 @@ protected:
|
||||
|
||||
EventId m_sendPendingDataEvent; //!< micro-delay event to send pending data
|
||||
|
||||
// Ack state
|
||||
TracedValue<TcpAckState_t> m_ackState; //!< State in the ACK state machine
|
||||
|
||||
// Fast Retransmit and Recovery
|
||||
SequenceNumber32 m_recover; //!< Previous highest Tx seqnum for fast recovery
|
||||
uint32_t m_retxThresh; //!< Fast Retransmit threshold
|
||||
bool m_inFastRec; //!< currently in fast recovery
|
||||
bool m_limitedTx; //!< perform limited transmit
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,22 +41,17 @@ TcpTahoe::GetTypeId (void)
|
||||
.SetParent<TcpSocketBase> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor<TcpTahoe> ()
|
||||
.AddAttribute ("ReTxThreshold", "Threshold for fast retransmit",
|
||||
UintegerValue (3),
|
||||
MakeUintegerAccessor (&TcpTahoe::m_retxThresh),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpTahoe::TcpTahoe (void) : m_retxThresh (3)
|
||||
TcpTahoe::TcpTahoe (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
TcpTahoe::TcpTahoe (const TcpTahoe& sock)
|
||||
: TcpSocketBase (sock),
|
||||
m_retxThresh (sock.m_retxThresh)
|
||||
: TcpSocketBase (sock)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("Invoked the copy constructor");
|
||||
@@ -96,40 +91,21 @@ TcpTahoe::NewAck (SequenceNumber32 const& seq)
|
||||
TcpSocketBase::NewAck (seq); // Complete newAck processing
|
||||
}
|
||||
|
||||
/* Cut down ssthresh upon triple dupack */
|
||||
void
|
||||
TcpTahoe::DupAck (const TcpHeader& t, uint32_t count)
|
||||
uint32_t
|
||||
TcpTahoe::GetSsThresh ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this << "t " << count);
|
||||
if (count == m_retxThresh)
|
||||
{ // triple duplicate ack triggers fast retransmit (RFC2001, sec.3)
|
||||
NS_LOG_INFO ("Triple Dup Ack: old ssthresh " << m_ssThresh << " cwnd " << m_cWnd);
|
||||
// fast retransmit in Tahoe means triggering RTO earlier. Tx is restarted
|
||||
// from the highest ack and run slow start again.
|
||||
// (Fall & Floyd 1996, sec.1)
|
||||
m_ssThresh = std::max (static_cast<unsigned> (m_cWnd / 2), m_segmentSize * 2); // Half ssthresh
|
||||
m_cWnd = m_segmentSize; // Run slow start again
|
||||
m_nextTxSequence = m_txBuffer->HeadSequence (); // Restart from highest Ack
|
||||
NS_LOG_INFO ("Triple Dup Ack: new ssthresh " << m_ssThresh << " cwnd " << m_cWnd);
|
||||
NS_LOG_LOGIC ("Triple Dup Ack: retransmit missing segment at " << Simulator::Now ().GetSeconds ());
|
||||
DoRetransmit ();
|
||||
/* Common Tahoe implementations detect congestion only from an RTO.
|
||||
* Since this function is called in two part (Retransmit and when a DupAck is
|
||||
* received, depending on the value of m_inFastRec we know if an RTO is expired
|
||||
* or a triple dupack received */
|
||||
if (m_inFastRec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Retransmit timeout */
|
||||
void TcpTahoe::Retransmit (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
|
||||
// If erroneous timeout in closed/timed-wait state, just return
|
||||
if (m_state == CLOSED || m_state == TIME_WAIT) return;
|
||||
// If all data are received (non-closing socket and nothing to send), just return
|
||||
if (m_state <= ESTABLISHED && m_txBuffer->HeadSequence () >= m_highTxMark) return;
|
||||
|
||||
m_ssThresh = std::max (static_cast<unsigned> (m_cWnd / 2), m_segmentSize * 2); // Half ssthresh
|
||||
m_cWnd = m_segmentSize; // Set cwnd to 1 segSize (RFC2001, sec.2)
|
||||
m_nextTxSequence = m_txBuffer->HeadSequence (); // Restart from highest Ack
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -61,11 +61,7 @@ public:
|
||||
protected:
|
||||
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpTahoe> to clone me
|
||||
virtual void NewAck (SequenceNumber32 const& seq); // Inc cwnd and call NewAck() of parent
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count); // Treat 3 dupack as timeout
|
||||
virtual void Retransmit (void); // Retransmit time out
|
||||
|
||||
protected:
|
||||
uint32_t m_retxThresh; //!< Fast Retransmit threshold
|
||||
virtual uint32_t GetSsThresh ();
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -63,13 +63,13 @@ TcpWestwood::GetTypeId (void)
|
||||
MakeEnumAccessor(&TcpWestwood::m_pType),
|
||||
MakeEnumChecker(TcpWestwood::WESTWOOD, "Westwood",TcpWestwood::WESTWOODPLUS, "WestwoodPlus"))
|
||||
.AddTraceSource("EstimatedBW", "The estimated bandwidth",
|
||||
MakeTraceSourceAccessor(&TcpWestwood::m_currentBW),
|
||||
"ns3::TracedValueCallback::Double");
|
||||
MakeTraceSourceAccessor(&TcpWestwood::m_currentBW),
|
||||
"ns3::TracedValueCallback::Double")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpWestwood::TcpWestwood (void) :
|
||||
m_inFastRec(false),
|
||||
m_currentBW(0),
|
||||
m_lastSampleBW(0),
|
||||
m_lastBW(0),
|
||||
@@ -85,7 +85,6 @@ TcpWestwood::TcpWestwood (void) :
|
||||
|
||||
TcpWestwood::TcpWestwood (const TcpWestwood& sock) :
|
||||
TcpSocketBase(sock),
|
||||
m_inFastRec(false),
|
||||
m_currentBW(sock.m_currentBW),
|
||||
m_lastSampleBW(sock.m_lastSampleBW),
|
||||
m_lastBW(sock.m_lastBW),
|
||||
@@ -121,14 +120,6 @@ TcpWestwood::NewAck (const SequenceNumber32& seq)
|
||||
" cwnd " << m_cWnd <<
|
||||
" ssthresh " << m_ssThresh);
|
||||
|
||||
// Check for exit condition of fast recovery
|
||||
if (m_inFastRec)
|
||||
{// First new ACK after fast recovery, reset cwnd as in Reno
|
||||
m_cWnd = m_ssThresh;
|
||||
m_inFastRec = false;
|
||||
NS_LOG_INFO ("Reset cwnd to " << m_cWnd);
|
||||
};
|
||||
|
||||
// Increase of cwnd based on current phase (slow start or congestion avoidance)
|
||||
if (m_cWnd < m_ssThresh)
|
||||
{ // Slow start mode, add one segSize to cWnd as in Reno
|
||||
@@ -238,59 +229,11 @@ TcpWestwood::UpdateAckedSegments (int acked)
|
||||
m_ackedSegments += acked;
|
||||
}
|
||||
|
||||
void
|
||||
TcpWestwood::DupAck (const TcpHeader& header, uint32_t count)
|
||||
|
||||
uint32_t
|
||||
TcpWestwood::GetSsThresh ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this << count << m_cWnd);
|
||||
|
||||
if (count == 3 && !m_inFastRec)
|
||||
{// Triple duplicate ACK triggers fast retransmit
|
||||
// Adjust cwnd and ssthresh based on the estimated BW
|
||||
m_ssThresh = uint32_t(m_currentBW * static_cast<double> (m_minRtt.GetSeconds()));
|
||||
if (m_cWnd > m_ssThresh)
|
||||
{
|
||||
m_cWnd = m_ssThresh;
|
||||
}
|
||||
m_inFastRec = true;
|
||||
NS_LOG_INFO ("Triple dupack. Enter fast recovery mode. Reset cwnd to " << m_cWnd <<", ssthresh to " << m_ssThresh);
|
||||
DoRetransmit ();
|
||||
}
|
||||
else if (m_inFastRec)
|
||||
{// 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);
|
||||
if (!m_sendPendingDataEvent.IsRunning ())
|
||||
{
|
||||
SendPendingData (m_connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TcpWestwood::Retransmit (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
|
||||
m_inFastRec = false;
|
||||
|
||||
// If erroneous timeout in closed/timed-wait state, just return
|
||||
if (m_state == CLOSED || m_state == TIME_WAIT)
|
||||
return;
|
||||
// If all data are received, just return
|
||||
if (m_txBuffer->HeadSequence () >= m_nextTxSequence)
|
||||
return;
|
||||
|
||||
// Upon an RTO, adjust cwnd and ssthresh based on the estimated BW
|
||||
m_ssThresh = std::max (static_cast<double> (2 * m_segmentSize), m_currentBW.Get () * static_cast<double> (m_minRtt.GetSeconds ()));
|
||||
m_cWnd = m_segmentSize;
|
||||
|
||||
// Restart from highest ACK
|
||||
m_nextTxSequence = m_txBuffer->HeadSequence ();
|
||||
NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
|
||||
|
||||
// Retransmit the packet
|
||||
DoRetransmit ();
|
||||
return uint32_t(m_currentBW * static_cast<double> (m_minRtt.GetSeconds()));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -97,8 +97,7 @@ public:
|
||||
protected:
|
||||
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpTahoe> to clone me
|
||||
virtual void NewAck (SequenceNumber32 const& seq); // Inc cwnd and call NewAck() of parent
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count); // Treat 3 dupack as timeout
|
||||
virtual void Retransmit (void); // Retransmit time out
|
||||
virtual uint32_t GetSsThresh ();
|
||||
|
||||
/**
|
||||
* Process the newly received ACK
|
||||
@@ -146,8 +145,6 @@ private:
|
||||
void Filtering (void);
|
||||
|
||||
protected:
|
||||
bool m_inFastRec; //!< Currently in fast recovery if TRUE
|
||||
|
||||
TracedValue<double> m_currentBW; //!< Current value of the estimated BW
|
||||
double m_lastSampleBW; //!< Last bandwidth sample
|
||||
double m_lastBW; //!< Last bandwidth sample after being filtered
|
||||
|
||||
Reference in New Issue
Block a user