old/flavours/TCPReno.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004-2005 Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #include <algorithm>   // min,max
00019 #include "TCPReno_old.h"
00020 #include "TCP_old.h"
00021 
00022 using namespace tcp_old;
00023 
00024 Register_Class(TCPReno);
00025 
00026 
00027 TCPReno::TCPReno() : TCPTahoeRenoFamily(),
00028   state((TCPRenoStateVariables *&)TCPAlgorithm::state)
00029 {
00030 }
00031 
00032 void TCPReno::recalculateSlowStartThreshold()
00033 {
00034     // set ssthresh to flight size/2, but at least 2 MSS
00035     // (the formula below practically amounts to ssthresh=cwnd/2 most of the time)
00036     uint flight_size = std::min(state->snd_cwnd, state->snd_wnd);
00037     state->ssthresh = std::max(flight_size/2, 2*state->snd_mss);
00038     if (ssthreshVector) ssthreshVector->record(state->ssthresh);
00039 }
00040 
00041 void TCPReno::processRexmitTimer(TCPEventCode& event)
00042 {
00043     TCPTahoeRenoFamily::processRexmitTimer(event);
00044     if (event==TCP_E_ABORT)
00045         return;
00046 
00047     // begin Slow Start (RFC 2581)
00048     recalculateSlowStartThreshold();
00049     state->snd_cwnd = state->snd_mss;
00050     if (cwndVector) cwndVector->record(state->snd_cwnd);
00051     tcpEV << "Begin Slow Start: resetting cwnd to " << state->snd_cwnd
00052           << ", ssthresh=" << state->ssthresh << "\n";
00053 
00054     state->afterRto = true;
00055 
00056     // Reno retransmits all data (unlike Tahoe which transmits only the segment)
00057     // conn->retransmitData();
00058     // After REXMIT timeout TCP Reno should start slow start with snd_cwnd = snd_mss.
00059     // If calling "retransmitData();" there is no rexmit limitation (bytesToSend > snd_cwnd)
00060     // therefore "sendData();" has been modified and is called to rexmit outstanding data.
00061     conn->retransmitOneSegment(true);
00062 }
00063 
00064 void TCPReno::receivedDataAck(uint32 firstSeqAcked)
00065 {
00066     TCPTahoeRenoFamily::receivedDataAck(firstSeqAcked);
00067 
00068     if (state->dupacks>=3)
00069     {
00070         //
00071         // Perform Fast Recovery: set cwnd to ssthresh (deflating the window).
00072         //
00073         tcpEV << "Fast Recovery: setting cwnd to ssthresh=" << state->ssthresh << "\n";
00074         state->snd_cwnd = state->ssthresh;
00075         if (cwndVector) cwndVector->record(state->snd_cwnd);
00076     }
00077     else
00078     {
00079         //
00080         // Perform slow start and congestion avoidance.
00081         //
00082         if (state->snd_cwnd < state->ssthresh)
00083         {
00084             tcpEV << "cwnd<=ssthresh: Slow Start: increasing cwnd by one segment, to ";
00085 
00086             // perform Slow Start. rfc 2581: "During slow start, a TCP increments cwnd
00087             // by at most SMSS bytes for each ACK received that acknowledges new data."
00088             state->snd_cwnd += state->snd_mss;
00089 
00090             // NOTE: we could increase cwnd based on the number of bytes being
00091             // acknowledged by each arriving ACK, rather than by the number of ACKs
00092             // that arrive. This is called "Appropriate Byte Counting" (ABC) and is
00093             // described in rfc 3465. This rfc is experimental and probably not
00094             // implemented in real-life TCPs, hence it's commented out. Also, the ABC
00095             // rfc would require other modifications as well in addition to the
00096             // two lines below.
00097             //
00098             // int bytesAcked = state->snd_una - firstSeqAcked;
00099             // state->snd_cwnd += bytesAcked*state->snd_mss;
00100 
00101             if (cwndVector) cwndVector->record(state->snd_cwnd);
00102 
00103             tcpEV << "cwnd=" << state->snd_cwnd << "\n";
00104         }
00105         else
00106         {
00107             // perform Congestion Avoidance (rfc 2581)
00108             int incr = state->snd_mss * state->snd_mss / state->snd_cwnd;
00109             if (incr==0)
00110                 incr = 1;
00111             state->snd_cwnd += incr;
00112             if (cwndVector) cwndVector->record(state->snd_cwnd);
00113 
00114             //
00115             // NOTE: some implementations use extra additive constant mss/8 here
00116             // which is known to be incorrect (rfc 2581 p5)
00117             //
00118             // NOTE 2: rfc 3465 (experimental) "Appropriate Byte Counting" (ABC)
00119             // would require maintaining a bytes_acked variable here which we don't do
00120             //
00121 
00122             tcpEV << "cwnd>ssthresh: Congestion Avoidance: increasing cwnd linearly, to " << state->snd_cwnd << "\n";
00123         }
00124     }
00125 
00126     // ack and/or cwnd increase may have freed up some room in the window, try sending
00127     sendData();
00128 }
00129 
00130 void TCPReno::receivedDuplicateAck()
00131 {
00132     TCPTahoeRenoFamily::receivedDuplicateAck();
00133 
00134     if (state->dupacks==3)
00135     {
00136         tcpEV << "Reno on dupAck=3: perform Fast Retransmit, and enter Fast Recovery:";
00137 
00138         // enter slow start
00139         // "set cwnd to ssthresh plus 3 times the segment size." (rfc 2001)
00140         recalculateSlowStartThreshold();
00141         state->snd_cwnd = state->ssthresh + 3*state->snd_mss;  // 20051129 (1)
00142         if (cwndVector) cwndVector->record(state->snd_cwnd);
00143 
00144         tcpEV << "set cwnd=" << state->snd_cwnd << ", ssthresh=" << state->ssthresh << "\n";
00145 
00146         // Fast Retransmission: retransmit missing segment without waiting
00147         // for the REXMIT timer to expire
00148         conn->retransmitOneSegment(false);
00149 
00150         // Do not restart REXMIT timer.
00151         // Note: Restart of REXMIT timer on retransmission is not part of RFC 2581, however optional in RFC 3517 if sent during recovery.
00152         // Resetting the REXMIT timer is discussed in RFC 2582/3782 (NewReno) and RFC 2988.
00153     }
00154     else if (state->dupacks > 3)
00155     {
00156         //
00157         // Reno: For each additional duplicate ACK received, increment cwnd by MSS.
00158         // This artificially inflates the congestion window in order to reflect the
00159         // additional segment that has left the network
00160         //
00161         state->snd_cwnd += state->snd_mss;
00162         tcpEV << "Reno on dupAck>3: Fast Recovery: inflating cwnd by MSS, new cwnd=" << state->snd_cwnd << "\n";
00163         if (cwndVector) cwndVector->record(state->snd_cwnd);
00164 
00165         // cwnd increased, try sending
00166         sendData();  // 20051129 (2)
00167     }
00168 }
00169 
00170