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:
Natale Patriciello
2015-10-16 10:38:51 -07:00
parent 194cca3ad9
commit 70803e884d
8 changed files with 153 additions and 211 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
};
/**

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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