src/internet/model/tcp-reno.cc
changeset 6834 036f9a0b9899
parent 6697 6f1114f669ff
child 7176 9f2663992e99
equal deleted inserted replaced
6833:1bc4bc4f3568 6834:036f9a0b9899
       
     1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
       
     2 /*
       
     3  * Copyright (c) 2010 Adrian Sai-wah Tam
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License version 2 as
       
     7  * published by the Free Software Foundation;
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    17  *
       
    18  * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
       
    19  */
       
    20 
       
    21 #define NS_LOG_APPEND_CONTEXT \
       
    22   if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
       
    23 
       
    24 #include "tcp-reno.h"
       
    25 #include "ns3/log.h"
       
    26 #include "ns3/trace-source-accessor.h"
       
    27 #include "ns3/simulator.h"
       
    28 #include "ns3/abort.h"
       
    29 #include "ns3/node.h"
       
    30 
       
    31 NS_LOG_COMPONENT_DEFINE ("TcpReno");
       
    32 
       
    33 namespace ns3 {
       
    34 
       
    35 NS_OBJECT_ENSURE_REGISTERED (TcpReno);
       
    36 
       
    37 TypeId
       
    38 TcpReno::GetTypeId (void)
       
    39 {
       
    40   static TypeId tid = TypeId ("ns3::TcpReno")
       
    41     .SetParent<TcpSocketBase> ()
       
    42     .AddConstructor<TcpReno> ()
       
    43     .AddTraceSource ("CongestionWindow",
       
    44                      "The TCP connection's congestion window",
       
    45                      MakeTraceSourceAccessor (&TcpReno::m_cWnd))
       
    46   ;
       
    47   return tid;
       
    48 }
       
    49 
       
    50 TcpReno::TcpReno (void) : m_inFastRec (false)
       
    51 {
       
    52   NS_LOG_FUNCTION (this);
       
    53 }
       
    54 
       
    55 TcpReno::TcpReno (const TcpReno& sock)
       
    56   : TcpSocketBase (sock),
       
    57     m_cWnd (sock.m_cWnd),
       
    58     m_ssThresh (sock.m_ssThresh),
       
    59     m_initialCWnd (sock.m_initialCWnd),
       
    60     m_inFastRec (false)
       
    61 {
       
    62   NS_LOG_FUNCTION (this);
       
    63   NS_LOG_LOGIC ("Invoked the copy constructor");
       
    64 }
       
    65 
       
    66 TcpReno::~TcpReno (void)
       
    67 {
       
    68 }
       
    69 
       
    70 /** We initialize m_cWnd from this function, after attributes initialized */
       
    71 int
       
    72 TcpReno::Listen (void)
       
    73 {
       
    74   NS_LOG_FUNCTION (this);
       
    75   InitializeCwnd ();
       
    76   return TcpSocketBase::Listen ();
       
    77 }
       
    78 
       
    79 /** We initialize m_cWnd from this function, after attributes initialized */
       
    80 int
       
    81 TcpReno::Connect (const Address & address)
       
    82 {
       
    83   NS_LOG_FUNCTION (this << address);
       
    84   InitializeCwnd ();
       
    85   return TcpSocketBase::Connect (address);
       
    86 }
       
    87 
       
    88 /** Limit the size of in-flight data by cwnd and receiver's rxwin */
       
    89 uint32_t
       
    90 TcpReno::Window (void)
       
    91 {
       
    92   NS_LOG_FUNCTION (this);
       
    93   return std::min (m_rWnd.Get (), m_cWnd.Get ());
       
    94 }
       
    95 
       
    96 Ptr<TcpSocketBase>
       
    97 TcpReno::Fork (void)
       
    98 {
       
    99   return CopyObject<TcpReno> (this);
       
   100 }
       
   101 
       
   102 /** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::NewAck() */
       
   103 void
       
   104 TcpReno::NewAck (const SequenceNumber32& seq)
       
   105 {
       
   106   NS_LOG_FUNCTION (this << seq);
       
   107   NS_LOG_LOGIC ("TcpReno receieved ACK for seq " << seq <<
       
   108                 " cwnd " << m_cWnd <<
       
   109                 " ssthresh " << m_ssThresh);
       
   110 
       
   111   // Check for exit condition of fast recovery
       
   112   if (m_inFastRec)
       
   113     { // RFC2001, sec.4; RFC2581, sec.3.2
       
   114       // First new ACK after fast recovery: reset cwnd
       
   115       m_cWnd = m_ssThresh;
       
   116       m_inFastRec = false;
       
   117       NS_LOG_INFO ("Reset cwnd to " << m_cWnd);
       
   118     };
       
   119 
       
   120   // Increase of cwnd based on current phase (slow start or congestion avoidance)
       
   121   if (m_cWnd < m_ssThresh)
       
   122     { // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535. (RFC2001, sec.1)
       
   123       m_cWnd += m_segmentSize;
       
   124       NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
       
   125     }
       
   126   else
       
   127     { // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
       
   128       // To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
       
   129       double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
       
   130       adder = std::max (1.0, adder);
       
   131       m_cWnd += static_cast<uint32_t> (adder);
       
   132       NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
       
   133     }
       
   134 
       
   135   // Complete newAck processing
       
   136   TcpSocketBase::NewAck (seq);
       
   137 }
       
   138 
       
   139 // Fast recovery and fast retransmit
       
   140 void
       
   141 TcpReno::DupAck (const TcpHeader& t, uint32_t count)
       
   142 {
       
   143   NS_LOG_FUNCTION (this << "t " << count);
       
   144   if (count == 3 && ! m_inFastRec)
       
   145     { // triple duplicate ack triggers fast retransmit (RFC2581, sec.3.2)
       
   146       m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
       
   147       m_cWnd = m_ssThresh + 3 * m_segmentSize;
       
   148       m_inFastRec = true;
       
   149       NS_LOG_INFO ("Triple dupack. Reset cwnd to " << m_cWnd << ", ssthresh to " << m_ssThresh);
       
   150       DoRetransmit ();
       
   151     }
       
   152   else if (m_inFastRec)
       
   153     { // In fast recovery, inc cwnd for every additional dupack (RFC2581, sec.3.2)
       
   154       m_cWnd += m_segmentSize;
       
   155       NS_LOG_INFO ("Increased cwnd to " << m_cWnd);
       
   156       SendPendingData (m_connected);
       
   157     };
       
   158 }
       
   159 
       
   160 // Retransmit timeout
       
   161 void TcpReno::Retransmit (void)
       
   162 {
       
   163   NS_LOG_FUNCTION (this);
       
   164   NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
       
   165   m_inFastRec = false;
       
   166 
       
   167   // If erroneous timeout in closed/timed-wait state, just return
       
   168   if (m_state == CLOSED || m_state == TIME_WAIT) return;
       
   169   // If all data are received, just return
       
   170   if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return;
       
   171 
       
   172   // According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight
       
   173   // size and cwnd is set to 1*MSS, then the lost packet is retransmitted and
       
   174   // TCP back to slow start
       
   175   m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
       
   176   m_cWnd = m_segmentSize;
       
   177   m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
       
   178   NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
       
   179                 ", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
       
   180   m_rtt->IncreaseMultiplier ();             // Double the next RTO
       
   181   DoRetransmit ();                          // Retransmit the packet
       
   182 }
       
   183 
       
   184 void
       
   185 TcpReno::SetSegSize (uint32_t size)
       
   186 {
       
   187   NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpReno::SetSegSize() cannot change segment size after connection started.");
       
   188   m_segmentSize = size;
       
   189 }
       
   190 
       
   191 void
       
   192 TcpReno::SetSSThresh (uint32_t threshold)
       
   193 {
       
   194   m_ssThresh = threshold;
       
   195 }
       
   196 
       
   197 uint32_t
       
   198 TcpReno::GetSSThresh (void) const
       
   199 {
       
   200   return m_ssThresh;
       
   201 }
       
   202 
       
   203 void
       
   204 TcpReno::SetInitialCwnd (uint32_t cwnd)
       
   205 {
       
   206   NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpReno::SetInitialCwnd() cannot change initial cwnd after connection started.");
       
   207   m_initialCWnd = cwnd;
       
   208 }
       
   209 
       
   210 uint32_t
       
   211 TcpReno::GetInitialCwnd (void) const
       
   212 {
       
   213   return m_initialCWnd;
       
   214 }
       
   215 
       
   216 void 
       
   217 TcpReno::InitializeCwnd (void)
       
   218 {
       
   219   /*
       
   220    * Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
       
   221    * not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
       
   222    * m_segmentSize are set by the attribute system in ns3::TcpSocket.
       
   223    */
       
   224   m_cWnd = m_initialCWnd * m_segmentSize;
       
   225 }
       
   226 
       
   227 } // namespace ns3