Created TCB: Transmission Control Block
The data structure contains information that should be exchanged between congestion control and the socket.
This commit is contained in:
@@ -74,8 +74,8 @@ TcpNewReno::NewAck (const SequenceNumber32& seq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
NS_LOG_LOGIC ("TcpNewReno received ACK for seq " << seq <<
|
||||
" cwnd " << m_cWnd <<
|
||||
" ssthresh " << m_ssThresh);
|
||||
" cwnd " << m_tcb->m_cWnd <<
|
||||
" ssthresh " << m_tcb->m_ssThresh);
|
||||
|
||||
// No cWnd management while recovering
|
||||
if (m_ackState == RECOVERY && seq < m_recover)
|
||||
@@ -85,18 +85,18 @@ TcpNewReno::NewAck (const SequenceNumber32& seq)
|
||||
}
|
||||
|
||||
// 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. Default m_ssThresh is 65535. (RFC2001, sec.1)
|
||||
m_cWnd += m_segmentSize;
|
||||
NS_LOG_INFO ("In SlowStart, ACK of seq " << seq << "; update cwnd to " << m_cWnd << "; ssthresh " << m_ssThresh);
|
||||
if (m_tcb->m_cWnd < m_tcb->m_ssThresh)
|
||||
{ // Slow start mode, add one segSize to cWnd. Default m_tcb->m_ssThresh is 65535. (RFC2001, sec.1)
|
||||
m_tcb->m_cWnd += m_tcb->m_segmentSize;
|
||||
NS_LOG_INFO ("In SlowStart, ACK of seq " << seq << "; update cwnd to " << m_tcb->m_cWnd << "; ssthresh " << m_tcb->m_ssThresh);
|
||||
}
|
||||
else
|
||||
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
|
||||
// To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
|
||||
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
|
||||
double adder = static_cast<double> (m_tcb->m_segmentSize * m_tcb->m_segmentSize) / m_tcb->m_cWnd.Get ();
|
||||
adder = std::max (1.0, adder);
|
||||
m_cWnd += static_cast<uint32_t> (adder);
|
||||
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
m_tcb->m_cWnd += static_cast<uint32_t> (adder);
|
||||
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_tcb->m_cWnd << " ssthresh " << m_tcb->m_ssThresh);
|
||||
}
|
||||
|
||||
// Complete newAck processing
|
||||
@@ -106,7 +106,7 @@ TcpNewReno::NewAck (const SequenceNumber32& seq)
|
||||
uint32_t
|
||||
TcpNewReno::GetSsThresh ()
|
||||
{
|
||||
return std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
return std::max (2 * m_tcb->m_segmentSize, BytesInFlight () / 2);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -164,16 +164,50 @@ TcpSocketBase::GetTypeId (void)
|
||||
"ns3::SequenceNumber32TracedValueCallback")
|
||||
.AddTraceSource ("CongestionWindow",
|
||||
"The TCP connection's congestion window",
|
||||
MakeTraceSourceAccessor (&TcpSocketBase::m_cWnd),
|
||||
MakeTraceSourceAccessor (&TcpSocketBase::m_cWndTrace),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
.AddTraceSource ("SlowStartThreshold",
|
||||
"TCP slow start threshold (bytes)",
|
||||
MakeTraceSourceAccessor (&TcpSocketBase::m_ssThresh),
|
||||
MakeTraceSourceAccessor (&TcpSocketBase::m_ssThTrace),
|
||||
"ns3::TracedValueCallback::Uint32")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
// TcpSocketState
|
||||
TypeId
|
||||
TcpSocketState::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpSocketState")
|
||||
.SetParent<Object> ()
|
||||
.SetGroupName ("Internet")
|
||||
.AddConstructor <TcpSocketState> ()
|
||||
.AddTraceSource ("CongestionWindow",
|
||||
"The TCP connection's congestion window",
|
||||
MakeTraceSourceAccessor (&TcpSocketState::m_cWnd),
|
||||
"ns3::TracedValue::Uint32Callback")
|
||||
.AddTraceSource ("SlowStartThreshold",
|
||||
"TCP slow start threshold (bytes)",
|
||||
MakeTraceSourceAccessor (&TcpSocketState::m_ssThresh),
|
||||
"ns3::TracedValue::Uint32Callback")
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpSocketState::TcpSocketState (void)
|
||||
: Object ()
|
||||
{
|
||||
}
|
||||
|
||||
TcpSocketState::TcpSocketState (const TcpSocketState &other)
|
||||
: m_cWnd (other.m_cWnd),
|
||||
m_ssThresh (other.m_ssThresh),
|
||||
m_initialCWnd (other.m_initialCWnd),
|
||||
m_initialSsThresh (other.m_initialSsThresh),
|
||||
m_segmentSize (other.m_segmentSize)
|
||||
{
|
||||
}
|
||||
|
||||
TcpSocketBase::TcpSocketBase (void)
|
||||
: m_dupAckCount (0),
|
||||
m_delAckCount (0),
|
||||
@@ -194,7 +228,6 @@ TcpSocketBase::TcpSocketBase (void)
|
||||
m_shutdownSend (false),
|
||||
m_shutdownRecv (false),
|
||||
m_connected (false),
|
||||
m_segmentSize (0),
|
||||
// For attribute initialization consistency (quiet valgrind)
|
||||
m_rWnd (0),
|
||||
m_highRxMark (0),
|
||||
@@ -211,6 +244,17 @@ TcpSocketBase::TcpSocketBase (void)
|
||||
NS_LOG_FUNCTION (this);
|
||||
m_rxBuffer = CreateObject<TcpRxBuffer> ();
|
||||
m_txBuffer = CreateObject<TcpTxBuffer> ();
|
||||
m_tcb = CreateObject<TcpSocketState> ();
|
||||
|
||||
bool ok;
|
||||
|
||||
ok = m_tcb->TraceConnectWithoutContext ("CongestionWindow",
|
||||
MakeCallback (&TcpSocketBase::UpdateCwnd, this));
|
||||
NS_ASSERT (ok == true);
|
||||
|
||||
ok = m_tcb->TraceConnectWithoutContext ("SlowStartThreshold",
|
||||
MakeCallback (&TcpSocketBase::UpdateSsThresh, this));
|
||||
NS_ASSERT (ok == true);
|
||||
}
|
||||
|
||||
TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
|
||||
@@ -239,15 +283,10 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
|
||||
m_shutdownRecv (sock.m_shutdownRecv),
|
||||
m_connected (sock.m_connected),
|
||||
m_msl (sock.m_msl),
|
||||
m_segmentSize (sock.m_segmentSize),
|
||||
m_maxWinSize (sock.m_maxWinSize),
|
||||
m_rWnd (sock.m_rWnd),
|
||||
m_highRxMark (sock.m_highRxMark),
|
||||
m_highRxAckMark (sock.m_highRxAckMark),
|
||||
m_cWnd (sock.m_cWnd),
|
||||
m_ssThresh (sock.m_ssThresh),
|
||||
m_initialCWnd (sock.m_initialCWnd),
|
||||
m_initialSsThresh (sock.m_initialSsThresh),
|
||||
m_winScalingEnabled (sock.m_winScalingEnabled),
|
||||
m_sndScaleFactor (sock.m_sndScaleFactor),
|
||||
m_rcvScaleFactor (sock.m_rcvScaleFactor),
|
||||
@@ -255,8 +294,8 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
|
||||
m_timestampToEcho (sock.m_timestampToEcho),
|
||||
m_ackState (sock.m_ackState),
|
||||
m_retxThresh (sock.m_retxThresh),
|
||||
m_limitedTx (sock.m_limitedTx)
|
||||
|
||||
m_limitedTx (sock.m_limitedTx),
|
||||
m_tcb (sock.m_tcb)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("Invoked the copy constructor");
|
||||
@@ -275,6 +314,16 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock)
|
||||
SetRecvCallback (vPS);
|
||||
m_txBuffer = CopyObject (sock.m_txBuffer);
|
||||
m_rxBuffer = CopyObject (sock.m_rxBuffer);
|
||||
|
||||
bool ok;
|
||||
|
||||
ok = m_tcb->TraceConnectWithoutContext ("CongestionWindow",
|
||||
MakeCallback (&TcpSocketBase::UpdateCwnd, this));
|
||||
NS_ASSERT (ok == true);
|
||||
|
||||
ok = m_tcb->TraceConnectWithoutContext ("SlowStartThreshold",
|
||||
MakeCallback (&TcpSocketBase::UpdateSsThresh, this));
|
||||
NS_ASSERT (ok == true);
|
||||
}
|
||||
|
||||
TcpSocketBase::~TcpSocketBase (void)
|
||||
@@ -457,8 +506,8 @@ TcpSocketBase::Bind (const Address &address)
|
||||
void
|
||||
TcpSocketBase::InitializeCwnd (void)
|
||||
{
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
m_ssThresh = m_initialSsThresh;
|
||||
m_tcb->m_cWnd = m_tcb->m_initialCWnd * m_tcb->m_segmentSize;
|
||||
m_tcb->m_ssThresh = m_tcb->m_initialSsThresh;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -467,13 +516,13 @@ TcpSocketBase::SetInitialSSThresh (uint32_t threshold)
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED,
|
||||
"TcpSocketBase::SetSSThresh() cannot change initial ssThresh after connection started.");
|
||||
|
||||
m_initialSsThresh = threshold;
|
||||
m_tcb->m_initialSsThresh = threshold;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpSocketBase::GetInitialSSThresh (void) const
|
||||
{
|
||||
return m_initialSsThresh;
|
||||
return m_tcb->m_initialSsThresh;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -482,19 +531,19 @@ TcpSocketBase::SetInitialCwnd (uint32_t cwnd)
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED,
|
||||
"TcpSocketBase::SetInitialCwnd() cannot change initial cwnd after connection started.");
|
||||
|
||||
m_initialCWnd = cwnd;
|
||||
m_tcb->m_initialCWnd = cwnd;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpSocketBase::GetInitialCwnd (void) const
|
||||
{
|
||||
return m_initialCWnd;
|
||||
return m_tcb->m_initialCWnd;
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketBase::ScaleSsThresh (uint8_t scaleFactor)
|
||||
{
|
||||
m_ssThresh <<= scaleFactor;
|
||||
m_tcb->m_ssThresh <<= scaleFactor;
|
||||
}
|
||||
|
||||
/* Inherit from Socket class: Initiate connection to a remote address:port */
|
||||
@@ -1227,7 +1276,7 @@ TcpSocketBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
|
||||
{
|
||||
// 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);
|
||||
uint32_t sz = SendDataPacket (m_nextTxSequence, m_tcb->m_segmentSize, true);
|
||||
m_nextTxSequence += sz;
|
||||
}
|
||||
else if (m_dupAckCount == m_retxThresh)
|
||||
@@ -1236,25 +1285,26 @@ TcpSocketBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
|
||||
m_recover = m_highTxMark;
|
||||
m_ackState = RECOVERY;
|
||||
|
||||
m_ssThresh = GetSsThresh ();
|
||||
m_cWnd = m_ssThresh + m_dupAckCount * m_segmentSize;
|
||||
m_tcb->m_ssThresh = GetSsThresh ();
|
||||
m_tcb->m_cWnd = m_tcb->m_ssThresh + m_dupAckCount * m_tcb->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);
|
||||
"Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " <<
|
||||
m_tcb->m_ssThresh << " at fast recovery seqnum " << m_recover);
|
||||
DoRetransmit ();
|
||||
|
||||
NS_LOG_DEBUG ("DISORDER -> RECOVERY");
|
||||
NS_LOG_DEBUG (TcpAckStateName[m_ackState] << " -> RECOVERY");
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_FATAL_ERROR ("m_dupAckCount > m_retxThresh and we still are in DISORDER state");
|
||||
NS_FATAL_ERROR ("m_dupAckCount > m_retxThresh and we still are "
|
||||
"in DISORDER state");
|
||||
}
|
||||
}
|
||||
else if (m_ackState == RECOVERY)
|
||||
{ // 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);
|
||||
m_tcb->m_cWnd += m_tcb->m_segmentSize;
|
||||
NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_tcb->m_cWnd);
|
||||
if (!m_sendPendingDataEvent.IsRunning ())
|
||||
{
|
||||
m_sendPendingDataEvent = Simulator::Schedule (TimeStep (1), &TcpSocketBase::SendPendingData, this, m_connected);
|
||||
@@ -1279,17 +1329,19 @@ TcpSocketBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
|
||||
{
|
||||
if (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_tcb->m_cWnd += m_tcb->m_segmentSize -
|
||||
(tcpHeader.GetAckNumber () - m_txBuffer->HeadSequence ());
|
||||
NS_LOG_INFO ("Partial ACK for seq " << tcpHeader.GetAckNumber () <<
|
||||
" in fast recovery: cwnd set to " << m_tcb->m_cWnd);
|
||||
m_txBuffer->DiscardUpTo(tcpHeader.GetAckNumber ()); //Bug 1850: retransmit before newack
|
||||
DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
|
||||
}
|
||||
else if (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_tcb->m_cWnd = std::min ( m_tcb->m_ssThresh.Get (), BytesInFlight () + m_tcb->m_segmentSize);
|
||||
m_ackState = OPEN;
|
||||
NS_LOG_INFO ("Received full ACK for seq " << tcpHeader.GetAckNumber () <<
|
||||
". Leaving fast recovery with cwnd set to " << m_cWnd);
|
||||
". Leaving fast recovery with cwnd set to " << m_tcb->m_cWnd);
|
||||
NS_LOG_DEBUG ("RECOVERY -> OPEN");
|
||||
}
|
||||
}
|
||||
@@ -2170,7 +2222,7 @@ TcpSocketBase::SendPendingData (bool withAck)
|
||||
{
|
||||
uint32_t w = AvailableWindow (); // Get available window size
|
||||
// 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)
|
||||
if (w < m_tcb->m_segmentSize && m_txBuffer->SizeFromSequence (m_nextTxSequence) > w)
|
||||
{
|
||||
NS_LOG_LOGIC ("Preventing Silly Window Syndrome. Wait to send.");
|
||||
break; // No more
|
||||
@@ -2178,7 +2230,7 @@ TcpSocketBase::SendPendingData (bool withAck)
|
||||
// Nagle's algorithm (RFC896): Hold off sending if there is unacked data
|
||||
// in the buffer and the amount of data to send is less than one segment
|
||||
if (!m_noDelay && UnAckDataCount () > 0
|
||||
&& m_txBuffer->SizeFromSequence (m_nextTxSequence) < m_segmentSize)
|
||||
&& m_txBuffer->SizeFromSequence (m_nextTxSequence) < m_tcb->m_segmentSize)
|
||||
{
|
||||
NS_LOG_LOGIC ("Invoking Nagle's algorithm. Wait to send.");
|
||||
break;
|
||||
@@ -2186,12 +2238,12 @@ TcpSocketBase::SendPendingData (bool withAck)
|
||||
NS_LOG_LOGIC ("TcpSocketBase " << this << " SendPendingData" <<
|
||||
" w " << w <<
|
||||
" rxwin " << m_rWnd <<
|
||||
" segsize " << m_segmentSize <<
|
||||
" segsize " << m_tcb->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 s = std::min (w, m_tcb->m_segmentSize); // Send no more than window
|
||||
uint32_t sz = SendDataPacket (m_nextTxSequence, s, withAck);
|
||||
nPacketsSent++; // Count sent this loop
|
||||
m_nextTxSequence += sz; // Advance next tx sequence
|
||||
@@ -2221,7 +2273,7 @@ uint32_t
|
||||
TcpSocketBase::Window (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return std::min (m_rWnd.Get (), m_cWnd.Get ());
|
||||
return std::min (m_rWnd.Get (), m_tcb->m_cWnd.Get ());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@@ -2532,12 +2584,12 @@ TcpSocketBase::Retransmit ()
|
||||
if (m_ackState != LOSS)
|
||||
{
|
||||
m_ackState = LOSS;
|
||||
m_cWnd = m_segmentSize;
|
||||
m_ssThresh = GetSsThresh ();
|
||||
m_tcb->m_ssThresh = GetSsThresh ();
|
||||
m_tcb->m_cWnd = m_tcb->m_segmentSize;
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG ("RTO. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
|
||||
NS_LOG_DEBUG ("RTO. Reset cwnd to " << m_tcb->m_cWnd << ", ssthresh to " <<
|
||||
m_tcb->m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
}
|
||||
|
||||
@@ -2569,7 +2621,7 @@ TcpSocketBase::DoRetransmit ()
|
||||
}
|
||||
// Retransmit a data packet: Call SendDataPacket
|
||||
NS_LOG_LOGIC ("TcpSocketBase " << this << " retxing seq " << m_txBuffer->HeadSequence ());
|
||||
uint32_t sz = SendDataPacket (m_txBuffer->HeadSequence (), m_segmentSize, true);
|
||||
uint32_t sz = SendDataPacket (m_txBuffer->HeadSequence (), m_tcb->m_segmentSize, true);
|
||||
// In case of RTO, advance m_nextTxSequence
|
||||
m_nextTxSequence = std::max (m_nextTxSequence.Get (), m_txBuffer->HeadSequence () + sz);
|
||||
|
||||
@@ -2631,7 +2683,7 @@ void
|
||||
TcpSocketBase::SetSegSize (uint32_t size)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << size);
|
||||
m_segmentSize = size;
|
||||
m_tcb->m_segmentSize = size;
|
||||
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "Cannot change segment size dynamically.");
|
||||
}
|
||||
@@ -2639,7 +2691,7 @@ TcpSocketBase::SetSegSize (uint32_t size)
|
||||
uint32_t
|
||||
TcpSocketBase::GetSegSize (void) const
|
||||
{
|
||||
return m_segmentSize;
|
||||
return m_tcb->m_segmentSize;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2957,10 +3009,21 @@ TcpSocketBase::GetRxBuffer (void) const
|
||||
const char* const
|
||||
TcpSocketBase::TcpAckStateName[TcpSocketBase::LAST_ACKSTATE] =
|
||||
{
|
||||
"OPEN", "DISORDER", "CWR", "RECOVERY",
|
||||
"LOSS"
|
||||
"OPEN", "DISORDER", "CWR", "RECOVERY", "LOSS"
|
||||
};
|
||||
|
||||
void
|
||||
TcpSocketBase::UpdateCwnd (uint32_t oldValue, uint32_t newValue)
|
||||
{
|
||||
m_cWndTrace (oldValue, newValue);
|
||||
}
|
||||
|
||||
void
|
||||
TcpSocketBase::UpdateSsThresh (uint32_t oldValue, uint32_t newValue)
|
||||
{
|
||||
m_ssThTrace (oldValue, newValue);
|
||||
}
|
||||
|
||||
|
||||
//RttHistory methods
|
||||
RttHistory::RttHistory (SequenceNumber32 s, uint32_t c, Time t)
|
||||
|
||||
@@ -45,6 +45,7 @@ class Node;
|
||||
class Packet;
|
||||
class TcpL4Protocol;
|
||||
class TcpHeader;
|
||||
class TcpSocketState;
|
||||
|
||||
/**
|
||||
* \ingroup tcp
|
||||
@@ -104,6 +105,13 @@ typedef std::deque<RttHistory> RttHistory_t;
|
||||
* the TcpAckState_t documentation.
|
||||
*
|
||||
*
|
||||
* Congestion control interface
|
||||
* ---------------------------
|
||||
*
|
||||
* The variables needed to congestion control subclasses have been moved inside
|
||||
* the TcpSocketState class. It contains information on the congestion window,
|
||||
* slow start threshold, segment size and the state of the Ack state machine.
|
||||
*
|
||||
* Fast retransmit
|
||||
* ---------------------------
|
||||
*
|
||||
@@ -244,6 +252,30 @@ public:
|
||||
*/
|
||||
static const char* const TcpAckStateName[TcpSocketBase::LAST_ACKSTATE];
|
||||
|
||||
/**
|
||||
* \brief Callback pointer for cWnd trace chaining
|
||||
*/
|
||||
TracedCallback<uint32_t, uint32_t> m_cWndTrace;
|
||||
|
||||
/**
|
||||
* \brief Callback pointer for ssTh trace chaining
|
||||
*/
|
||||
TracedCallback<uint32_t, uint32_t> m_ssThTrace;
|
||||
|
||||
/**
|
||||
* \brief Callback function to hook to TcpSocketState congestion window
|
||||
* \param oldValue old cWnd value
|
||||
* \param newValue new cWnd value
|
||||
*/
|
||||
void UpdateCwnd (uint32_t oldValue, uint32_t newValue);
|
||||
|
||||
/**
|
||||
* \brief Callback function to hook to TcpSocketState slow start threshold
|
||||
* \param oldValue old ssTh value
|
||||
* \param newValue new ssTh value
|
||||
*/
|
||||
void UpdateSsThresh (uint32_t oldValue, uint32_t newValue);
|
||||
|
||||
// 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
|
||||
@@ -828,18 +860,11 @@ protected:
|
||||
double m_msl; //!< Max segment lifetime
|
||||
|
||||
// Window management
|
||||
uint32_t m_segmentSize; //!< Segment size
|
||||
uint16_t m_maxWinSize; //!< Maximum window size to advertise
|
||||
TracedValue<uint32_t> m_rWnd; //!< Receiver window (RCV.WND in RFC793)
|
||||
TracedValue<SequenceNumber32> m_highRxMark; //!< Highest seqno received
|
||||
TracedValue<SequenceNumber32> m_highRxAckMark; //!< Highest ack received
|
||||
|
||||
// Congestion control
|
||||
TracedValue<uint32_t> m_cWnd; //!< Congestion window
|
||||
TracedValue<uint32_t> m_ssThresh; //!< Slow start threshold
|
||||
uint32_t m_initialCWnd; //!< Initial cWnd value
|
||||
uint32_t m_initialSsThresh; //!< Initial Slow Start Threshold value
|
||||
|
||||
// Options
|
||||
bool m_winScalingEnabled; //!< Window Scale option enabled
|
||||
uint8_t m_sndScaleFactor; //!< Sent Window Scale (i.e., the one of the node)
|
||||
@@ -857,6 +882,44 @@ protected:
|
||||
SequenceNumber32 m_recover; //!< Previous highest Tx seqnum for fast recovery
|
||||
uint32_t m_retxThresh; //!< Fast Retransmit threshold
|
||||
bool m_limitedTx; //!< perform limited transmit
|
||||
|
||||
// Transmission Control Block
|
||||
Ptr<TcpSocketState> m_tcb; //!< Congestion control informations
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Data structure that records the congestion state of a connection
|
||||
*
|
||||
* In this data structure, basic informations that should be passed between
|
||||
* socket and the congestion control algorithm are saved. Through the code,
|
||||
* it will be referred as Transmission Control Block (TCB), but there are some
|
||||
* differencies. In the RFCs, the TCB contains all the variables that defines
|
||||
* a connection, while we preferred to maintain in this class only the values
|
||||
* that should be exchanged between socket and other parts, like congestion
|
||||
* control algorithms.
|
||||
*
|
||||
*/
|
||||
class TcpSocketState : public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Get the type ID.
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
TcpSocketState ();
|
||||
TcpSocketState (const TcpSocketState &other);
|
||||
|
||||
// Congestion control
|
||||
TracedValue<uint32_t> m_cWnd; //!< Congestion window
|
||||
TracedValue<uint32_t> m_ssThresh; //!< Slow start threshold
|
||||
uint32_t m_initialCWnd; //!< Initial cWnd value
|
||||
uint32_t m_initialSsThresh; //!< Initial Slow Start Threshold value
|
||||
|
||||
// Segment
|
||||
uint32_t m_segmentSize; //!< Segment size
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -117,21 +117,21 @@ TcpWestwood::NewAck (const SequenceNumber32& seq)
|
||||
{ // Same as Reno
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
NS_LOG_LOGIC ("TcpWestwood receieved ACK for seq " << seq <<
|
||||
" cwnd " << m_cWnd <<
|
||||
" ssthresh " << m_ssThresh);
|
||||
" cwnd " << m_tcb->m_cWnd <<
|
||||
" ssthresh " << m_tcb->m_ssThresh);
|
||||
|
||||
// Increase of cwnd based on current phase (slow start or congestion avoidance)
|
||||
if (m_cWnd < m_ssThresh)
|
||||
if (m_tcb->m_cWnd < m_tcb->m_ssThresh)
|
||||
{ // Slow start mode, add one segSize to cWnd as in Reno
|
||||
m_cWnd += m_segmentSize;
|
||||
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
m_tcb->m_cWnd += m_tcb->m_segmentSize;
|
||||
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_tcb->m_cWnd << " ssthresh " << m_tcb->m_ssThresh);
|
||||
}
|
||||
else
|
||||
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd as in Reno
|
||||
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get();
|
||||
double adder = static_cast<double> (m_tcb->m_segmentSize * m_tcb->m_segmentSize) / m_tcb->m_cWnd.Get();
|
||||
adder = std::max(1.0, adder);
|
||||
m_cWnd += static_cast<uint32_t>(adder);
|
||||
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
m_tcb->m_cWnd += static_cast<uint32_t>(adder);
|
||||
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_tcb->m_cWnd << " ssthresh " << m_tcb->m_ssThresh);
|
||||
}
|
||||
|
||||
// Complete newAck processing
|
||||
@@ -172,14 +172,14 @@ TcpWestwood::EstimateBW (int acked, const TcpHeader& tcpHeader, Time rtt)
|
||||
// Get the time when the current ACK is received
|
||||
double currentAck = static_cast<double> (Simulator::Now().GetSeconds());
|
||||
// Calculate the BW
|
||||
m_currentBW = acked * m_segmentSize / (currentAck - m_lastAck);
|
||||
m_currentBW = acked * m_tcb->m_segmentSize / (currentAck - m_lastAck);
|
||||
// Update the last ACK time
|
||||
m_lastAck = currentAck;
|
||||
}
|
||||
else if (m_pType == TcpWestwood::WESTWOODPLUS)
|
||||
{
|
||||
// Calculate the BW
|
||||
m_currentBW = m_ackedSegments * m_segmentSize / rtt.GetSeconds();
|
||||
m_currentBW = m_ackedSegments * m_tcb->m_segmentSize / rtt.GetSeconds();
|
||||
// Reset m_ackedSegments and m_IsCount for the next sampling
|
||||
m_ackedSegments = 0;
|
||||
m_IsCount = false;
|
||||
@@ -195,7 +195,7 @@ TcpWestwood::CountAck (const TcpHeader& tcpHeader)
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
// Calculate the number of acknowledged segments based on the received ACK number
|
||||
int cumul_ack = (tcpHeader.GetAckNumber() - m_prevAckNo) / m_segmentSize;
|
||||
int cumul_ack = (tcpHeader.GetAckNumber() - m_prevAckNo) / m_tcb->m_segmentSize;
|
||||
|
||||
if (cumul_ack == 0)
|
||||
{// A DUPACK counts for 1 segment delivered successfully
|
||||
|
||||
Reference in New Issue
Block a user