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 "TCPTahoe_old.h" 00020 #include "TCP_old.h" 00021 00022 using namespace tcp_old; 00023 00024 Register_Class(TCPTahoe); 00025 00026 00027 TCPTahoe::TCPTahoe() : TCPTahoeRenoFamily(), 00028 state((TCPTahoeStateVariables *&)TCPAlgorithm::state) 00029 { 00030 } 00031 00032 void TCPTahoe::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 TCPTahoe::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 // Tahoe retransmits only one segment at the front of the queue 00057 conn->retransmitOneSegment(true); 00058 } 00059 00060 void TCPTahoe::receivedDataAck(uint32 firstSeqAcked) 00061 { 00062 TCPTahoeRenoFamily::receivedDataAck(firstSeqAcked); 00063 00064 // 00065 // Perform slow start and congestion avoidance. 00066 // 00067 if (state->snd_cwnd < state->ssthresh) 00068 { 00069 tcpEV << "cwnd<=ssthresh: Slow Start: increasing cwnd by one segment, to "; 00070 00071 // perform Slow Start. rfc 2581: "During slow start, a TCP increments cwnd 00072 // by at most SMSS bytes for each ACK received that acknowledges new data." 00073 state->snd_cwnd += state->snd_mss; 00074 00075 // NOTE: we could increase cwnd based on the number of bytes being 00076 // acknowledged by each arriving ACK, rather than by the number of ACKs 00077 // that arrive. This is called "Appropriate Byte Counting" (ABC) and is 00078 // described in rfc 3465 (experimental). 00079 // 00080 // int bytesAcked = state->snd_una - firstSeqAcked; 00081 // state->snd_cwnd += bytesAcked; 00082 00083 if (cwndVector) cwndVector->record(state->snd_cwnd); 00084 00085 tcpEV << "cwnd=" << state->snd_cwnd << "\n"; 00086 } 00087 else 00088 { 00089 // perform Congestion Avoidance (rfc 2581) 00090 int incr = state->snd_mss * state->snd_mss / state->snd_cwnd; 00091 if (incr==0) 00092 incr = 1; 00093 state->snd_cwnd += incr; 00094 if (cwndVector) cwndVector->record(state->snd_cwnd); 00095 00096 // 00097 // NOTE: some implementations use extra additive constant mss/8 here 00098 // which is known to be incorrect (rfc 2581 p5) 00099 // 00100 // NOTE 2: rfc 3465 (experimental) "Appropriate Byte Counting" (ABC) 00101 // would require maintaining a bytes_acked variable here which we don't do 00102 // 00103 00104 tcpEV << "cwnd>ssthresh: Congestion Avoidance: increasing cwnd linearly, to " << state->snd_cwnd << "\n"; 00105 } 00106 00107 // ack and/or cwnd increase may have freed up some room in the window, try sending 00108 sendData(); 00109 } 00110 00111 void TCPTahoe::receivedDuplicateAck() 00112 { 00113 TCPTahoeRenoFamily::receivedDuplicateAck(); 00114 00115 if (state->dupacks==3) 00116 { 00117 tcpEV << "Tahoe on dupAck=3: perform Fast Retransmit, and enter Slow Start:\n"; 00118 00119 // enter Slow Start 00120 recalculateSlowStartThreshold(); 00121 state->snd_cwnd = state->snd_mss; 00122 if (cwndVector) cwndVector->record(state->snd_cwnd); 00123 00124 tcpEV << "Set cwnd=" << state->snd_cwnd << ", ssthresh=" << state->ssthresh << "\n"; 00125 00126 // Fast Retransmission: retransmit missing segment without waiting 00127 // for the REXMIT timer to expire 00128 conn->retransmitOneSegment(false); 00129 00130 // Do not restart REXMIT timer. 00131 // Note: Restart of REXMIT timer on retransmission is not part of RFC 2581, however optional in RFC 3517 if sent during recovery. 00132 // Resetting the REXMIT timer is discussed in RFC 2582/3782 (NewReno) and RFC 2988. 00133 } 00134 } 00135 00136