tcp: Modularization of Fast Recovery - I

This commit is contained in:
Viyom
2018-05-11 19:30:43 +02:00
parent b84b30547d
commit aeb3d27b4d
24 changed files with 521 additions and 42 deletions

View File

@@ -63,7 +63,9 @@ nodes to be placed outside of buildings defined in the scenario.</li>
<h2>Changes to existing API:</h2>
<ul>
<li>TrafficControlHelper::Install now only includes root queue discs in the returned
QueueDiscContainer.</li>
QueueDiscContainer.</li>
<li>Recovery algorithms are now in a different class, instead of being tied to TcpSocketBase.
Take a look to TcpRecoveryOps for more information.</li>
</ul>
<h2>Changes to build system:</h2>
<ul>

View File

@@ -867,11 +867,63 @@ provided by TcpTxBuffer to query the scoreboard; please refer to the Doxygen
documentation (and to in-code comments) if you want to learn more about this
implementation.
Loss Recovery Algorithms
++++++++++++++++++++++++
The following loss recovery algorithms are supported in ns-3 TCP:
Classic Recovery
^^^^^^^^^^^^^^^^
Classic Recovery refers to the combination of NewReno algorithm described in
RFC 6582 along with SACK based loss recovery algorithm mentioned in RFC 6675.
SACK based loss recovery is used when sender and receiver support SACK options.
In the case when SACK options are disabled, the NewReno modification handles
the recovery.
At the start of recovery phase the congestion window is reduced diffently for
NewReno and SACK based recovery. For NewReno the reduction is done as given below:
.. math:: cWnd = ssThresh
For SACK based recovery, this is done as follows:
.. math:: cWnd = ssThresh + (dupAckCount * segmentSize)
While in the recovery phase, the congestion window is inflated by segmentSize
on arrival of every ACK when NewReno is used. The congestion window is kept
same when SACK based loss recovery is used.
Adding a new loss recovery algorithm in ns-3
++++++++++++++++++++++++++++++++++++++++++++
Writing (or porting) a loss recovery algorithms from scratch (or from
other systems) is a process completely separated from the internals of
TcpSocketBase.
All operations that are delegated to a loss recovery are contained in
the class TcpRecoveryOps and are given below:
.. code-block:: c++
virtual std::string GetName () const;
virtual void EnterRecovery (Ptr<const TcpSocketState> tcb, uint32_t unAckDataCount,
bool isSackEnabled, uint32_t dupAckCount,
uint32_t bytesInFlight, uint32_t lastDeliveredBytes);
virtual void DoRecovery (Ptr<const TcpSocketState> tcb, uint32_t unAckDataCount,
bool isSackEnabled, uint32_t dupAckCount,
uint32_t bytesInFlight, uint32_t lastDeliveredBytes);
virtual void ExitRecovery (Ptr<TcpSocketState> tcb, uint32_t bytesInFlight);
virtual Ptr<TcpRecoveryOps> Fork ();
EnterRecovery is called when packet loss is detected and recovery is triggered.
While in recovery phase, each time when an ACK arrives, DoRecovery is called which
performs the necessary congestion window changes as per the recovery algorithm.
ExitRecovery is called just prior to exiting recovery phase in order to perform the
required congestion window ajustments.
Current limitations
+++++++++++++++++++
* TcpCongestionOps interface does not contain every possible Linux operation
* Fast retransmit / fast recovery are bound with TcpSocketBase, thereby preventing easy simulation of TCP Tahoe
.. _Writing-tcp-tests:

View File

@@ -21,6 +21,7 @@
#define TCPBIC_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
class TcpBicIncrementTest;
class TcpBicDecrementTest;

View File

@@ -20,6 +20,7 @@
#define TCPCONGESTIONOPS_H
#include "ns3/tcp-socket-base.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -21,6 +21,7 @@
#define TCPHIGHSPEED_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -28,6 +28,7 @@
#define TCP_HTCP_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -20,6 +20,7 @@
#define TCPHYBLA_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
#include "ns3/traced-value.h"
namespace ns3 {

View File

@@ -29,6 +29,7 @@
#define TCPILLINOIS_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -42,6 +42,7 @@
#include "tcp-socket-factory-impl.h"
#include "tcp-socket-base.h"
#include "tcp-congestion-ops.h"
#include "tcp-recovery-ops.h"
#include "rtt-estimator.h"
#include <vector>
@@ -80,6 +81,11 @@ TcpL4Protocol::GetTypeId (void)
TypeIdValue (TcpNewReno::GetTypeId ()),
MakeTypeIdAccessor (&TcpL4Protocol::m_congestionTypeId),
MakeTypeIdChecker ())
.AddAttribute ("RecoveryType",
"Recovery type of TCP objects.",
TypeIdValue (ClassicRecovery::GetTypeId ()),
MakeTypeIdAccessor (&TcpL4Protocol::m_recoveryTypeId),
MakeTypeIdChecker ())
.AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
ObjectVectorValue (),
MakeObjectVectorAccessor (&TcpL4Protocol::m_sockets),
@@ -175,22 +181,26 @@ TcpL4Protocol::DoDispose (void)
}
Ptr<Socket>
TcpL4Protocol::CreateSocket (TypeId congestionTypeId)
TcpL4Protocol::CreateSocket (TypeId congestionTypeId, TypeId recoveryTypeId)
{
NS_LOG_FUNCTION (this << congestionTypeId.GetName ());
ObjectFactory rttFactory;
ObjectFactory congestionAlgorithmFactory;
ObjectFactory recoveryAlgorithmFactory;
rttFactory.SetTypeId (m_rttTypeId);
congestionAlgorithmFactory.SetTypeId (congestionTypeId);
recoveryAlgorithmFactory.SetTypeId (recoveryTypeId);
Ptr<RttEstimator> rtt = rttFactory.Create<RttEstimator> ();
Ptr<TcpSocketBase> socket = CreateObject<TcpSocketBase> ();
Ptr<TcpCongestionOps> algo = congestionAlgorithmFactory.Create<TcpCongestionOps> ();
Ptr<TcpRecoveryOps> recovery = recoveryAlgorithmFactory.Create<TcpRecoveryOps> ();
socket->SetNode (m_node);
socket->SetTcp (this);
socket->SetRtt (rtt);
socket->SetCongestionControlAlgorithm (algo);
socket->SetRecoveryAlgorithm (recovery);
m_sockets.push_back (socket);
return socket;
@@ -199,7 +209,7 @@ TcpL4Protocol::CreateSocket (TypeId congestionTypeId)
Ptr<Socket>
TcpL4Protocol::CreateSocket (void)
{
return CreateSocket (m_congestionTypeId);
return CreateSocket (m_congestionTypeId, m_recoveryTypeId);
}
Ipv4EndPoint *

View File

@@ -113,7 +113,7 @@ public:
*
* \param congestionTypeId the congestion control algorithm TypeId
*/
Ptr<Socket> CreateSocket (TypeId congestionTypeId);
Ptr<Socket> CreateSocket (TypeId congestionTypeId, TypeId recoveryTypeId);
/**
* \brief Allocate an IPv4 Endpoint
@@ -306,6 +306,7 @@ private:
Ipv6EndPointDemux *m_endPoints6; //!< A list of IPv6 end points.
TypeId m_rttTypeId; //!< The RTT Estimator TypeId
TypeId m_congestionTypeId; //!< The socket TypeId
TypeId m_recoveryTypeId; //!< The recovery TypeId
std::vector<Ptr<TcpSocketBase> > m_sockets; //!< list of sockets
IpL4Protocol::DownTargetCallback m_downTarget; //!< Callback to send packets over IPv4
IpL4Protocol::DownTargetCallback6 m_downTarget6; //!< Callback to send packets over IPv6

View File

@@ -24,6 +24,7 @@
#include <vector>
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -25,6 +25,7 @@
#define TCPLP_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
#include "ns3/traced-value.h"
namespace ns3 {

View File

@@ -0,0 +1,124 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 NITK Surathkal
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Viyom Mittal <viyommittal@gmail.com>
* Vivek Jain <jain.vivek.anand@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*
*/
#include "tcp-recovery-ops.h"
#include "tcp-socket-base.h"
#include "tcp-congestion-ops.h"
#include "ns3/log.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("TcpRecoveryOps");
NS_OBJECT_ENSURE_REGISTERED (TcpRecoveryOps);
TypeId
TcpRecoveryOps::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpRecoveryOps")
.SetParent<Object> ()
.SetGroupName ("Internet")
;
return tid;
}
TcpRecoveryOps::TcpRecoveryOps () : Object ()
{
}
TcpRecoveryOps::TcpRecoveryOps (const TcpRecoveryOps &other) : Object (other)
{
}
TcpRecoveryOps::~TcpRecoveryOps ()
{
}
// Classic recovery
NS_OBJECT_ENSURE_REGISTERED (ClassicRecovery);
TypeId
ClassicRecovery::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::ClassicRecovery")
.SetParent<TcpRecoveryOps> ()
.SetGroupName ("Internet")
.AddConstructor<ClassicRecovery> ()
;
return tid;
}
ClassicRecovery::ClassicRecovery (void) : TcpRecoveryOps ()
{
NS_LOG_FUNCTION (this);
}
ClassicRecovery::ClassicRecovery (const ClassicRecovery& sock)
: TcpRecoveryOps (sock)
{
NS_LOG_FUNCTION (this);
}
ClassicRecovery::~ClassicRecovery (void)
{
}
void
ClassicRecovery::EnterRecovery (Ptr<TcpSocketState> tcb, uint32_t dupAckCount)
{
tcb->m_cWnd = tcb->m_ssThresh;
tcb->m_cWndInfl = tcb->m_ssThresh + (dupAckCount * tcb->m_segmentSize);
}
void
ClassicRecovery::DoRecovery (Ptr<TcpSocketState> tcb)
{
tcb->m_cWndInfl += tcb->m_segmentSize;
}
void
ClassicRecovery::ExitRecovery (Ptr<TcpSocketState> tcb)
{
// Follow NewReno procedures to exit FR if SACK is disabled
// (RFC2582 sec.3 bullet #5 paragraph 2, option 2)
// For SACK connections, we maintain the cwnd = ssthresh. In fact,
// this ACK was received in RECOVERY phase, not in OPEN. So we
// are not allowed to increase the window
tcb->m_cWndInfl = tcb->m_ssThresh.Get ();
}
std::string
ClassicRecovery::GetName () const
{
return "ClassicRecovery";
}
Ptr<TcpRecoveryOps>
ClassicRecovery::Fork ()
{
return CopyObject<ClassicRecovery> (this);
}
} // namespace ns3

View File

@@ -0,0 +1,183 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 NITK Surathkal
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Viyom Mittal <viyommittal@gmail.com>
* Vivek Jain <jain.vivek.anand@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*
*/
#ifndef TCPRECOVERYOPS_H
#define TCPRECOVERYOPS_H
#include "ns3/tcp-socket-base.h"
namespace ns3 {
/**
* \ingroup tcp
* \defgroup recoveryOps Recovery Algorithms.
*
* The various recovery algorithms used in recovery phase of TCP.
*/
/**
* \ingroup recoveryOps
*
* \brief recovery abstract class
*
* The design is inspired by the TcpCongestionOps class in ns-3. The fast
* recovery is splitted from the main socket code, and it is a pluggable
* component. An interface has been defined; variables are maintained in the
* TcpSocketState class, while subclasses of TcpRecoveryOps operate over an
* instance of that class.
*
* \see DoRecovery
*/
class TcpRecoveryOps : public Object
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
/**
* \brief Constructor
*/
TcpRecoveryOps ();
/**
* \brief Copy constructor.
* \param other object to copy.
*/
TcpRecoveryOps (const TcpRecoveryOps &other);
/**
* \brief Deconstructor
*/
virtual ~TcpRecoveryOps ();
/**
* \brief Get the name of the recovery algorithm
*
* \return A string identifying the name
*/
virtual std::string GetName () const = 0;
/**
* \brief Performs variable initialization at the start of recovery
*
* The function is called when the TcpSocketState is changed to CA_RECOVERY.
*
* \param tcb internal congestion state
* \param dupAckCount duplicate acknowldgement count
*/
virtual void EnterRecovery (Ptr<TcpSocketState> tcb, uint32_t dupAckCount)
{
NS_UNUSED (tcb);
NS_UNUSED (dupAckCount);
}
/**
* \brief Performs recovery based on the recovery algorithm
*
* The function is called on arrival of every ack when TcpSocketState
* is set to CA_RECOVERY. It performs the necessary cwnd changes
* as per the recovery algorithm.
*
* \param tcb internal congestion state
*/
virtual void DoRecovery (Ptr<TcpSocketState> tcb)
{
NS_UNUSED (tcb);
}
/**
* \brief Performs cwnd adjustments at the end of recovery
*
* The function is called when the TcpSocketState is changed from CA_RECOVERY.
*
* \param tcb internal congestion state
* \param isSackEnabled
*/
virtual void ExitRecovery (Ptr<TcpSocketState> tcb)
{
NS_UNUSED (tcb);
}
/**
* \brief Copy the recovery algorithm across socket
*
* \return a pointer of the copied object
*/
virtual Ptr<TcpRecoveryOps> Fork () = 0;
};
/**
* \brief The Classic recovery implementation
*
* Classic recovery refers to the two well-established recovery algorithms,
* namely, NewReno (RFC 6582) and SACK based recovery (RFC 6675).
*
* The idea of the algorithm is that when we enter recovery, we set the
* congestion window value to the slow start threshold and maintain it
* at such value until we are fully recovered (in other words, until
* the highest sequence transmitted at time of detecting the loss is
* ACKed by the receiver).
*
* \see DoRecovery
*/
class ClassicRecovery : public TcpRecoveryOps
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
/**
* \brief Constructor
*/
ClassicRecovery ();
/**
* \brief Copy constructor.
* \param recovery object to copy.
*/
ClassicRecovery (const ClassicRecovery& recovery);
/**
* \brief Constructor
*/
~ClassicRecovery ();
virtual std::string GetName () const override;
virtual void EnterRecovery (Ptr<TcpSocketState> tcb, uint32_t dupAckCount) override;
virtual void DoRecovery (Ptr<TcpSocketState> tcb) override;
virtual void ExitRecovery (Ptr<TcpSocketState> tcb) override;
virtual Ptr<TcpRecoveryOps> Fork () override;
};
} // namespace ns3
#endif // TCPRECOVERYOPS_H

View File

@@ -31,6 +31,7 @@
#define TCPSCALABLE_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -54,6 +54,7 @@
#include "tcp-option-sack-permitted.h"
#include "tcp-option-sack.h"
#include "tcp-congestion-ops.h"
#include "tcp-recovery-ops.h"
#include <math.h>
#include <algorithm>
@@ -187,7 +188,7 @@ TcpSocketBase::GetTypeId (void)
"ns3::TracedValueCallback::Uint32")
.AddTraceSource ("CongestionWindowInflated",
"The TCP connection's congestion window inflates as in older RFC",
MakeTraceSourceAccessor (&TcpSocketBase::m_cWndInfl),
MakeTraceSourceAccessor (&TcpSocketBase::m_cWndInflTrace),
"ns3::TracedValueCallback::Uint32")
.AddTraceSource ("SlowStartThreshold",
"TCP slow start threshold (bytes)",
@@ -232,6 +233,10 @@ TcpSocketState::GetTypeId (void)
"The TCP connection's congestion window",
MakeTraceSourceAccessor (&TcpSocketState::m_cWnd),
"ns3::TracedValue::Uint32Callback")
.AddTraceSource ("CongestionWindowInflated",
"The TCP connection's inflated congestion window",
MakeTraceSourceAccessor (&TcpSocketState::m_cWndInfl),
"ns3::TracedValue::Uint32Callback")
.AddTraceSource ("SlowStartThreshold",
"TCP slow start threshold (bytes)",
MakeTraceSourceAccessor (&TcpSocketState::m_ssThresh),
@@ -305,6 +310,10 @@ TcpSocketBase::TcpSocketBase (void)
MakeCallback (&TcpSocketBase::UpdateCwnd, this));
NS_ASSERT (ok == true);
ok = m_tcb->TraceConnectWithoutContext ("CongestionWindowInflated",
MakeCallback (&TcpSocketBase::UpdateCwndInfl, this));
NS_ASSERT (ok == true);
ok = m_tcb->TraceConnectWithoutContext ("SlowStartThreshold",
MakeCallback (&TcpSocketBase::UpdateSsThresh, this));
NS_ASSERT (ok == true);
@@ -405,12 +414,21 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
m_congestionControl = sock.m_congestionControl->Fork ();
}
if (sock.m_recoveryOps)
{
m_recoveryOps = sock.m_recoveryOps->Fork ();
}
bool ok;
ok = m_tcb->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&TcpSocketBase::UpdateCwnd, this));
NS_ASSERT (ok == true);
ok = m_tcb->TraceConnectWithoutContext ("CongestionWindowInflated",
MakeCallback (&TcpSocketBase::UpdateCwndInfl, this));
NS_ASSERT (ok == true);
ok = m_tcb->TraceConnectWithoutContext ("SlowStartThreshold",
MakeCallback (&TcpSocketBase::UpdateSsThresh, this));
NS_ASSERT (ok == true);
@@ -1250,7 +1268,7 @@ TcpSocketBase::DoForwardUp (Ptr<Packet> packet, const Address &fromAddress,
// Initialize cWnd and ssThresh
m_tcb->m_cWnd = GetInitialCwnd () * GetSegSize ();
m_cWndInfl = m_tcb->m_cWnd;
m_tcb->m_cWndInfl = m_tcb->m_cWnd;
m_tcb->m_ssThresh = GetInitialSSThresh ();
if (tcpHeader.GetFlags () & TcpHeader::ACK)
@@ -1489,7 +1507,7 @@ TcpSocketBase::EnterRecovery ()
}
else
{
if (! m_txBuffer->IsLost (m_txBuffer->HeadSequence ()))
if (!m_txBuffer->IsLost (m_txBuffer->HeadSequence ()))
{
// We received 3 dupacks, but the head is not marked as lost
// (received less than 3 SACK block ahead).
@@ -1511,8 +1529,7 @@ TcpSocketBase::EnterRecovery ()
// compatibility with old ns-3 versions
uint32_t bytesInFlight = m_sackEnabled ? BytesInFlight () : BytesInFlight () + m_tcb->m_segmentSize;
m_tcb->m_ssThresh = m_congestionControl->GetSsThresh (m_tcb, bytesInFlight);
m_tcb->m_cWnd = m_tcb->m_ssThresh;
m_cWndInfl = m_tcb->m_ssThresh + m_dupAckCount * m_tcb->m_segmentSize;
m_recoveryOps->EnterRecovery (m_tcb, m_dupAckCount);
NS_LOG_INFO (m_dupAckCount << " dupack. Enter fast recovery mode." <<
"Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " <<
@@ -1550,15 +1567,6 @@ TcpSocketBase::DupAck ()
++m_dupAckCount;
}
if (!m_sackEnabled && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
{
// If we are in recovery and we receive a dupack, one segment
// has left the network. This is equivalent to a SACK of one block.
m_txBuffer->AddRenoSack ();
m_cWndInfl += m_tcb->m_segmentSize;
}
if (m_tcb->m_congState == TcpSocketState::CA_OPEN)
{
// From Open we go Disorder
@@ -1571,7 +1579,19 @@ TcpSocketBase::DupAck ()
NS_LOG_DEBUG ("CA_OPEN -> CA_DISORDER");
}
if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
if (m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
{
if (!m_sackEnabled)
{
// If we are in recovery and we receive a dupack, one segment
// has left the network. This is equivalent to a SACK of one block.
m_txBuffer->AddRenoSack ();
}
m_recoveryOps->DoRecovery (m_tcb);
NS_LOG_INFO (m_dupAckCount << " Dupack received in fast recovery mode."
"Increase cwnd to " << m_tcb->m_cWnd);
}
else if (m_tcb->m_congState == TcpSocketState::CA_DISORDER)
{
// RFC 6675, Section 5, continuing:
// ... and take the following steps:
@@ -1674,9 +1694,9 @@ TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpd
*/
bool isDupack = m_sackEnabled ?
scoreboardUpdated
: ackNumber == oldHeadSequence &&
ackNumber < m_tcb->m_highTxMark;
scoreboardUpdated
: ackNumber == oldHeadSequence &&
ackNumber < m_tcb->m_highTxMark;
NS_LOG_DEBUG ("ACK of " << ackNumber <<
" SND.UNA=" << oldHeadSequence <<
@@ -1767,10 +1787,10 @@ TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpd
m_txBuffer->DeleteRetransmittedFlagFromHead ();
}
DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
m_cWndInfl = SafeSubtraction (m_cWndInfl, bytesAcked);
m_tcb->m_cWndInfl = SafeSubtraction (m_tcb->m_cWndInfl, bytesAcked);
if (segsAcked >= 1)
{
m_cWndInfl += m_tcb->m_segmentSize;
m_recoveryOps->DoRecovery (m_tcb);
}
// This partial ACK acknowledge the fact that one segment has been
@@ -1891,12 +1911,7 @@ TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpd
if (exitedFastRecovery)
{
NewAck (ackNumber, true);
// Follow NewReno procedures to exit FR if SACK is disabled
// (RFC2582 sec.3 bullet #5 paragraph 2, option 2)
m_cWndInfl = m_tcb->m_ssThresh.Get ();
// For SACK connections, we maintain the cwnd = ssthresh. In fact,
// this ACK was received in RECOVERY phase, not in OPEN. So we
// are not allowed to increase the window
m_recoveryOps->ExitRecovery (m_tcb);
NS_LOG_DEBUG ("Leaving Fast Recovery; BytesInFlight() = " <<
BytesInFlight () << "; cWnd = " << m_tcb->m_cWnd);
}
@@ -1904,7 +1919,7 @@ TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpd
{
m_congestionControl->IncreaseWindow (m_tcb, segsAcked);
m_cWndInfl = m_tcb->m_cWnd;
m_tcb->m_cWndInfl = m_tcb->m_cWnd;
NS_LOG_LOGIC ("Congestion control called: " <<
" cWnd: " << m_tcb->m_cWnd <<
@@ -3306,7 +3321,7 @@ TcpSocketBase::ReTxTimeout ()
// Cwnd set to 1 MSS
m_tcb->m_cWnd = m_tcb->m_segmentSize;
m_cWndInfl = m_tcb->m_cWnd;
m_tcb->m_cWndInfl = m_tcb->m_cWnd;
m_congestionControl->CwndEvent (m_tcb, TcpSocketState::CA_EVENT_LOSS);
m_congestionControl->CongestionStateSet (m_tcb, TcpSocketState::CA_LOSS);
m_tcb->m_congState = TcpSocketState::CA_LOSS;
@@ -3891,6 +3906,12 @@ TcpSocketBase::UpdateCwnd (uint32_t oldValue, uint32_t newValue)
m_cWndTrace (oldValue, newValue);
}
void
TcpSocketBase::UpdateCwndInfl (uint32_t oldValue, uint32_t newValue)
{
m_cWndInflTrace (oldValue, newValue);
}
void
TcpSocketBase::UpdateSsThresh (uint32_t oldValue, uint32_t newValue)
{
@@ -3937,6 +3958,13 @@ TcpSocketBase::SetCongestionControlAlgorithm (Ptr<TcpCongestionOps> algo)
m_congestionControl = algo;
}
void
TcpSocketBase::SetRecoveryAlgorithm (Ptr<TcpRecoveryOps> recovery)
{
NS_LOG_FUNCTION (this << recovery);
m_recoveryOps = recovery;
}
Ptr<TcpSocketBase>
TcpSocketBase::Fork (void)
{

View File

@@ -45,6 +45,7 @@ class Packet;
class TcpL4Protocol;
class TcpHeader;
class TcpCongestionOps;
class TcpRecoveryOps;
class RttEstimator;
class TcpRxBuffer;
class TcpTxBuffer;
@@ -170,6 +171,7 @@ public:
// Congestion control
TracedValue<uint32_t> m_cWnd {0}; //!< Congestion window
TracedValue<uint32_t> m_cWndInfl {0}; //!< Inflated congestion window trace (used only for backward compatibility purpose)
TracedValue<uint32_t> m_ssThresh {0}; //!< Slow start threshold
uint32_t m_initialCWnd {0}; //!< Initial cWnd value
uint32_t m_initialSsThresh {0}; //!< Initial Slow Start Threshold value
@@ -459,6 +461,11 @@ public:
*/
TracedCallback<uint32_t, uint32_t> m_cWndTrace;
/**
* \brief Callback pointer for cWndInfl trace chaining
*/
TracedCallback<uint32_t, uint32_t> m_cWndInflTrace;
/**
* \brief Callback pointer for ssTh trace chaining
*/
@@ -496,6 +503,13 @@ public:
*/
void UpdateCwnd (uint32_t oldValue, uint32_t newValue);
/**
* \brief Callback function to hook to TcpSocketState inflated congestion window
* \param oldValue old cWndInfl value
* \param newValue new cWndInfl value
*/
void UpdateCwndInfl (uint32_t oldValue, uint32_t newValue);
/**
* \brief Callback function to hook to TcpSocketState slow start threshold
* \param oldValue old ssTh value
@@ -546,6 +560,13 @@ public:
*/
void SetCongestionControlAlgorithm (Ptr<TcpCongestionOps> algo);
/**
* \brief Install a recovery algorithm on this socket
*
* \param recovery Algorithm to be installed
*/
void SetRecoveryAlgorithm (Ptr<TcpRecoveryOps> recovery);
// Necessary implementations of null functions from ns3::Socket
virtual enum SocketErrno GetErrno (void) const; // returns m_errno
virtual enum SocketType GetSocketType (void) const; // returns socket type
@@ -1046,7 +1067,7 @@ protected:
void AddOptions (TcpHeader& tcpHeader);
/**
* \brief Read TCP options begore Ack processing
* \brief Read TCP options before Ack processing
*
* Timestamp and Window scale are managed in other pieces of code.
*
@@ -1252,6 +1273,7 @@ protected:
// Transmission Control Block
Ptr<TcpSocketState> m_tcb {nullptr}; //!< Congestion control informations
Ptr<TcpCongestionOps> m_congestionControl {nullptr}; //!< Congestion control
Ptr<TcpRecoveryOps> m_recoveryOps {nullptr}; //!< Recovery Algorithm
// Guesses over the other connection end
bool m_isFirstPartialAck {true}; //!< First partial ACK during RECOVERY
@@ -1265,11 +1287,6 @@ protected:
// Pacing related variable
Timer m_pacingTimer {Timer::REMOVE_ON_DESTROY}; //!< Pacing Event
/**
* \brief Inflated congestion window trace (not used in the real code, deprecated)
*/
TracedValue<uint32_t> m_cWndInfl {0};
};
/**

View File

@@ -28,6 +28,7 @@
#define TCPVEGAS_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -28,6 +28,7 @@
#define TCPVENO_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -34,6 +34,7 @@
#define TCP_WESTWOOD_H
#include "tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
#include "ns3/sequence-number.h"
#include "ns3/traced-value.h"

View File

@@ -28,6 +28,7 @@
#define TCPYEAH_H
#include "ns3/tcp-scalable.h"
#include "ns3/tcp-recovery-ops.h"
namespace ns3 {

View File

@@ -37,6 +37,7 @@ NS_LOG_COMPONENT_DEFINE ("TcpGeneralTest");
TcpGeneralTest::TcpGeneralTest (const std::string &desc)
: TestCase (desc),
m_congControlTypeId (TcpNewReno::GetTypeId ()),
m_recoveryTypeId (ClassicRecovery::GetTypeId ()),
m_remoteAddr (Ipv4Address::GetAny (), 4477)
{
NS_LOG_FUNCTION (this << desc);
@@ -96,6 +97,7 @@ TcpGeneralTest::ConfigureEnvironment ()
NS_LOG_FUNCTION (this);
SetCongestionControl (m_congControlTypeId);
SetRecoveryAlgorithm (m_recoveryTypeId);
SetPropagationDelay (MilliSeconds (500));
SetTransmitStart (Seconds (10));
SetAppPktSize (500);
@@ -197,6 +199,8 @@ TcpGeneralTest::DoRun (void)
m_senderSocket->SetUpdateRttHistoryCb (MakeCallback (&TcpGeneralTest::UpdateRttHistoryCb, this));
m_senderSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&TcpGeneralTest::CWndTrace, this));
m_senderSocket->TraceConnectWithoutContext ("CongestionWindowInflated",
MakeCallback (&TcpGeneralTest::CWndInflTrace, this));
m_senderSocket->TraceConnectWithoutContext ("SlowStartThreshold",
MakeCallback (&TcpGeneralTest::SsThreshTrace, this));
m_senderSocket->TraceConnectWithoutContext ("CongState",
@@ -264,24 +268,34 @@ TcpGeneralTest::CreateChannel ()
Ptr<TcpSocketMsgBase>
TcpGeneralTest::CreateSocket (Ptr<Node> node, TypeId socketType,
TypeId congControl)
{
return CreateSocket (node, socketType, congControl, m_recoveryTypeId);
}
Ptr<TcpSocketMsgBase>
TcpGeneralTest::CreateSocket (Ptr<Node> node, TypeId socketType,
TypeId congControl, TypeId recoveryAlgorithm)
{
ObjectFactory rttFactory;
ObjectFactory congestionAlgorithmFactory;
ObjectFactory recoveryAlgorithmFactory;
ObjectFactory socketFactory;
rttFactory.SetTypeId (RttMeanDeviation::GetTypeId ());
congestionAlgorithmFactory.SetTypeId (congControl);
recoveryAlgorithmFactory.SetTypeId (recoveryAlgorithm);
socketFactory.SetTypeId (socketType);
Ptr<RttEstimator> rtt = rttFactory.Create<RttEstimator> ();
Ptr<TcpSocketMsgBase> socket = DynamicCast<TcpSocketMsgBase> (socketFactory.Create ());
Ptr<TcpCongestionOps> algo = congestionAlgorithmFactory.Create<TcpCongestionOps> ();
Ptr<TcpRecoveryOps> recovery = recoveryAlgorithmFactory.Create<TcpRecoveryOps> ();
socket->SetNode (node);
socket->SetTcp (node->GetObject<TcpL4Protocol> ());
socket->SetRtt (rtt);
socket->SetCongestionControlAlgorithm (algo);
socket->SetRecoveryAlgorithm (recovery);
return socket;
}
@@ -300,13 +314,13 @@ TcpGeneralTest::CreateReceiverErrorModel ()
Ptr<TcpSocketMsgBase>
TcpGeneralTest::CreateSenderSocket (Ptr<Node> node)
{
return CreateSocket (node, TcpSocketMsgBase::GetTypeId (), m_congControlTypeId);
return CreateSocket (node, TcpSocketMsgBase::GetTypeId (), m_congControlTypeId, m_recoveryTypeId);
}
Ptr<TcpSocketMsgBase>
TcpGeneralTest::CreateReceiverSocket (Ptr<Node> node)
{
return CreateSocket (node, TcpSocketMsgBase::GetTypeId (), m_congControlTypeId);
return CreateSocket (node, TcpSocketMsgBase::GetTypeId (), m_congControlTypeId, m_recoveryTypeId);
}
void

View File

@@ -23,6 +23,7 @@
#include "ns3/error-model.h"
#include "ns3/tcp-socket-base.h"
#include "ns3/tcp-congestion-ops.h"
#include "ns3/tcp-recovery-ops.h"
#include "ns3/test.h"
namespace ns3 {
@@ -322,6 +323,18 @@ protected:
virtual Ptr<TcpSocketMsgBase> CreateSocket (Ptr<Node> node, TypeId socketType,
TypeId congControl);
/**
* \brief Create a socket
*
* \param node associated node
* \param socketType Type of the TCP socket
* \param congControl congestion control
* \param recoveryAlgorithm recovery algorithm
* \return a pointer to the newer created socket
*/
virtual Ptr<TcpSocketMsgBase> CreateSocket (Ptr<Node> node, TypeId socketType,
TypeId congControl, TypeId recoveryAlgorithm);
/**
* \brief Get the pointer to a previously created sender socket
* \return ptr to sender socket or 0
@@ -623,6 +636,13 @@ protected:
*/
void SetCongestionControl (TypeId congControl) { m_congControlTypeId = congControl; }
/**
* \brief recovery algorithm of the sender socket
*
* \param recovery typeid of the recovery algorithm
*/
void SetRecoveryAlgorithm (TypeId reccovery) { m_recoveryTypeId = reccovery; }
/**
* \brief MTU of the bottleneck link
*
@@ -654,6 +674,18 @@ protected:
NS_UNUSED (newValue);
}
/**
* \brief Tracks the inflated congestion window changes
*
* \param oldValue old value
* \param newValue new value
*/
virtual void CWndInflTrace (uint32_t oldValue, uint32_t newValue)
{
NS_UNUSED (oldValue);
NS_UNUSED (newValue);
}
/**
* \brief Rtt changes
*
@@ -943,6 +975,7 @@ protected:
}
TypeId m_congControlTypeId; //!< Congestion control
TypeId m_recoveryTypeId; //!< Recovery
private:
// Member variables, accessible through getters

View File

@@ -179,6 +179,7 @@ def build(bld):
'model/udp-socket-factory.cc',
'model/tcp-socket.cc',
'model/tcp-socket-factory.cc',
'model/tcp-recovery-ops.cc',
'model/ipv4.cc',
'model/ipv4-raw-socket-factory.cc',
'model/ipv6-header.cc',
@@ -389,6 +390,7 @@ def build(bld):
'model/tcp-socket-base.h',
'model/tcp-tx-buffer.h',
'model/tcp-rx-buffer.h',
'model/tcp-recovery-ops.h',
'model/rtt-estimator.h',
'model/ipv4-packet-probe.h',
'model/ipv6-packet-probe.h',