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