|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2004 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 "TCPBaseAlg_old.h" 00019 #include "TCP_old.h" 00020 00021 using namespace tcp_old; 00022 00023 // 00024 // Some constants below. MIN_REXMIT_TIMEOUT is the minimum allowed retransmit 00025 // interval. It is currently one second but e.g. a FreeBSD kernel comment says 00026 // it "will ultimately be reduced to 3 ticks for algorithmic stability, 00027 // leaving the 200ms variance to deal with delayed-acks, protocol overheads. 00028 // A 1 second minimum badly breaks throughput on any network faster then 00029 // a modem that has minor but continuous packet loss unrelated to congestion, 00030 // such as on a wireless network." 00031 // 00032 #define DELAYED_ACK_TIMEOUT 0.2 // 200ms 00033 #define MAX_REXMIT_COUNT 12 // 12 retries 00034 #define MIN_REXMIT_TIMEOUT 1.0 // 1s 00035 //#define MIN_REXMIT_TIMEOUT 0.6 // 600ms (3 ticks) 00036 #define MAX_REXMIT_TIMEOUT 240 // 2*MSL (RFC1122) 00037 00038 00039 00040 TCPBaseAlgStateVariables::TCPBaseAlgStateVariables() 00041 { 00042 // We disable delayed acks, since it appears that it isn't used in real-life TCPs. 00043 // 00044 // In SSFNet test suite http://www.ssfnet.org/Exchange/tcp/test/f5.html 00045 // the rule for delayed ACK is: 00046 // An ACK must be sent immediatly when either of the following conditions exist: 00047 // * Two full-sized packets received (to avoid too few ACKs). 00048 // * Out of order packets received (to help trigger fast retransmission). 00049 // * Received packet fills in all gap or part of gap of out of order data. 00050 // We do not implement this rule. In our measurements on network traffic, we 00051 // never encountered delayed ACKs. 00052 // 00053 delayed_acks_enabled = false; 00054 00055 nagle_enabled = true; // FIXME this should be parameter eventually 00056 00057 rexmit_count = 0; 00058 rexmit_timeout = 3.0; 00059 00060 snd_cwnd = 0; // will be set to MSS when connection is established 00061 00062 rtseq = 0; 00063 rtseq_sendtime = 0; 00064 00065 // Jacobson's alg: srtt must be initialized to 0, rttvar to a value which 00066 // will yield rto = 3s initially. 00067 srtt = 0; 00068 rttvar = 3.0/4.0; 00069 } 00070 00071 std::string TCPBaseAlgStateVariables::info() const 00072 { 00073 std::stringstream out; 00074 out << TCPStateVariables::info(); 00075 out << " snd_cwnd=" << snd_cwnd; 00076 out << " rto=" << rexmit_timeout; 00077 return out.str(); 00078 } 00079 00080 std::string TCPBaseAlgStateVariables::detailedInfo() const 00081 { 00082 std::stringstream out; 00083 out << TCPStateVariables::detailedInfo(); 00084 out << "snd_cwnd = " << snd_cwnd << "\n"; 00085 out << "rto = " << rexmit_timeout << "\n"; 00086 // TBD add others too 00087 return out.str(); 00088 } 00089 00090 TCPBaseAlg::TCPBaseAlg() : TCPAlgorithm(), 00091 state((TCPBaseAlgStateVariables *&)TCPAlgorithm::state) 00092 { 00093 rexmitTimer = persistTimer = delayedAckTimer = keepAliveTimer = NULL; 00094 cwndVector = ssthreshVector = rttVector = srttVector = rttvarVector = rtoVector = NULL; 00095 } 00096 00097 TCPBaseAlg::~TCPBaseAlg() 00098 { 00099 // Note: don't delete "state" here, it'll be deleted from TCPConnection 00100 00101 // cancel and delete timers 00102 if (rexmitTimer) delete cancelEvent(rexmitTimer); 00103 if (persistTimer) delete cancelEvent(persistTimer); 00104 if (delayedAckTimer) delete cancelEvent(delayedAckTimer); 00105 if (keepAliveTimer) delete cancelEvent(keepAliveTimer); 00106 00107 // delete statistics objects 00108 delete cwndVector; 00109 delete ssthreshVector; 00110 delete rttVector; 00111 delete srttVector; 00112 delete rttvarVector; 00113 delete rtoVector; 00114 } 00115 00116 void TCPBaseAlg::initialize() 00117 { 00118 TCPAlgorithm::initialize(); 00119 00120 rexmitTimer = new cMessage("REXMIT"); 00121 persistTimer = new cMessage("PERSIST"); 00122 delayedAckTimer = new cMessage("DELAYEDACK"); 00123 keepAliveTimer = new cMessage("KEEPALIVE"); 00124 00125 rexmitTimer->setContextPointer(conn); 00126 persistTimer->setContextPointer(conn); 00127 delayedAckTimer->setContextPointer(conn); 00128 keepAliveTimer->setContextPointer(conn); 00129 00130 if (conn->getTcpMain()->recordStatistics) 00131 { 00132 cwndVector = new cOutVector("cwnd"); 00133 ssthreshVector = new cOutVector("ssthresh"); 00134 rttVector = new cOutVector("measured RTT"); 00135 srttVector = new cOutVector("smoothed RTT"); 00136 rttvarVector = new cOutVector("RTTVAR"); 00137 rtoVector = new cOutVector("RTO"); 00138 } 00139 } 00140 00141 void TCPBaseAlg::established(bool active) 00142 { 00143 // initialize cwnd (we may learn MSS during connection setup -- 00144 // this (MSS TCP option) is not implemented yet though) 00145 state->snd_cwnd = state->snd_mss; 00146 if (cwndVector) cwndVector->record(state->snd_cwnd); 00147 00148 if (active) 00149 { 00150 // finish connection setup with ACK (possibly piggybacked on data) 00151 tcpEV << "Completing connection setup by sending ACK (possibly piggybacked on data)\n"; 00152 if (!sendData()) 00153 conn->sendAck(); 00154 } 00155 } 00156 00157 void TCPBaseAlg::connectionClosed() 00158 { 00159 cancelEvent(rexmitTimer); 00160 cancelEvent(persistTimer); 00161 cancelEvent(delayedAckTimer); 00162 cancelEvent(keepAliveTimer); 00163 } 00164 00165 void TCPBaseAlg::processTimer(cMessage *timer, TCPEventCode& event) 00166 { 00167 if (timer==rexmitTimer) 00168 processRexmitTimer(event); 00169 else if (timer==persistTimer) 00170 processPersistTimer(event); 00171 else if (timer==delayedAckTimer) 00172 processDelayedAckTimer(event); 00173 else if (timer==keepAliveTimer) 00174 processKeepAliveTimer(event); 00175 else 00176 throw cRuntimeError(timer, "unrecognized timer"); 00177 } 00178 00179 void TCPBaseAlg::processRexmitTimer(TCPEventCode& event) 00180 { 00181 //" 00182 // For any state if the retransmission timeout expires on a segment in 00183 // the retransmission queue, send the segment at the front of the 00184 // retransmission queue again, reinitialize the retransmission timer, 00185 // and return. 00186 //" 00187 // Also: abort connection after max 12 retries. 00188 // 00189 // However, retransmission is actually more complicated than that 00190 // in RFC 793 above, we'll leave it to subclasses (e.g. TCPTahoe, TCPReno). 00191 // 00192 if (++state->rexmit_count > MAX_REXMIT_COUNT) 00193 { 00194 tcpEV << "Retransmission count exceeds " << MAX_REXMIT_COUNT << ", aborting connection\n"; 00195 conn->signalConnectionTimeout(); 00196 event = TCP_E_ABORT; // TBD maybe rather introduce a TCP_E_TIMEDOUT event 00197 return; 00198 } 00199 00200 tcpEV << "Performing retransmission #" << state->rexmit_count 00201 << "; increasing RTO from " << state->rexmit_timeout << "s "; 00202 00203 // 00204 // Karn's algorithm is implemented below: 00205 // (1) don't measure RTT for retransmitted packets. 00206 // (2) RTO should be doubled after retransmission ("exponential back-off") 00207 // 00208 00209 // restart the retransmission timer with twice the latest RTO value, or with the max, whichever is smaller 00210 state->rexmit_timeout += state->rexmit_timeout; 00211 if (state->rexmit_timeout > MAX_REXMIT_TIMEOUT) 00212 state->rexmit_timeout = MAX_REXMIT_TIMEOUT; 00213 conn->scheduleTimeout(rexmitTimer, state->rexmit_timeout); 00214 00215 tcpEV << " to " << state->rexmit_timeout << "s, and cancelling RTT measurement\n"; 00216 00217 // cancel round-trip time measurement 00218 state->rtseq_sendtime = 0; 00219 00220 // 00221 // Leave congestion window management and actual retransmission to 00222 // subclasses (e.g. TCPTahoe, TCPReno). 00223 // 00224 // That is, subclasses will redefine this method, call us, then perform 00225 // window adjustments and do the retransmission as they like. 00226 // 00227 } 00228 00229 void TCPBaseAlg::processPersistTimer(TCPEventCode& event) 00230 { 00231 // FIXME TBD finish (currently Persist Timer never gets scheduled) 00232 conn->sendProbe(); 00233 } 00234 00235 void TCPBaseAlg::processDelayedAckTimer(TCPEventCode& event) 00236 { 00237 conn->sendAck(); 00238 } 00239 00240 void TCPBaseAlg::processKeepAliveTimer(TCPEventCode& event) 00241 { 00242 // FIXME TBD 00243 } 00244 00245 void TCPBaseAlg::startRexmitTimer() 00246 { 00247 // start counting retransmissions for this seq number. 00248 // Note: state->rexmit_timeout is set from rttMeasurementComplete(). 00249 state->rexmit_count = 0; 00250 00251 // schedule timer 00252 conn->scheduleTimeout(rexmitTimer, state->rexmit_timeout); 00253 } 00254 00255 void TCPBaseAlg::rttMeasurementComplete(simtime_t tSent, simtime_t tAcked) 00256 { 00257 // 00258 // Jacobson's algorithm for estimating RTT and adaptively setting RTO. 00259 // 00260 // Note: this implementation calculates in doubles. An impl. which uses 00261 // 500ms ticks is available from old tcpmodule.cc:calcRetransTimer(). 00262 // 00263 00264 // update smoothed RTT estimate (srtt) and variance (rttvar) 00265 const double g = 0.125; // 1/8; (1-alpha) where alpha=7/8; 00266 simtime_t newRTT = tAcked-tSent; 00267 00268 simtime_t& srtt = state->srtt; 00269 simtime_t& rttvar = state->rttvar; 00270 00271 simtime_t err = newRTT - srtt; 00272 00273 srtt += g*err; 00274 rttvar += g*(fabs(err) - rttvar); 00275 00276 // assign RTO (here: rexmit_timeout) a new value 00277 simtime_t rto = srtt + 4*rttvar; 00278 if (rto>MAX_REXMIT_TIMEOUT) 00279 rto = MAX_REXMIT_TIMEOUT; 00280 else if (rto<MIN_REXMIT_TIMEOUT) 00281 rto = MIN_REXMIT_TIMEOUT; 00282 00283 state->rexmit_timeout = rto; 00284 00285 // record statistics 00286 tcpEV << "Measured RTT=" << (newRTT*1000) << "ms, updated SRTT=" << (srtt*1000) 00287 << "ms, new RTO=" << (rto*1000) << "ms\n"; 00288 if (rttVector) rttVector->record(newRTT); 00289 if (srttVector) srttVector->record(srtt); 00290 if (rttvarVector) rttvarVector->record(rttvar); 00291 if (rtoVector) rtoVector->record(rto); 00292 } 00293 00294 bool TCPBaseAlg::sendData() 00295 { 00296 // 00297 // Nagle's algorithm: when a TCP connection has outstanding data that has not 00298 // yet been acknowledged, small segments cannot be sent until the outstanding 00299 // data is acknowledged. (In this case, small amounts of data are collected 00300 // by TCP and sent in a single segment.) 00301 // 00302 // FIXME there's also something like this: can still send if 00303 // "b) a segment that can be sent is at least half the size of 00304 // the largest window ever advertised by the receiver" 00305 00306 bool fullSegmentsOnly = state->nagle_enabled && state->snd_una!=state->snd_max; 00307 if (fullSegmentsOnly) 00308 tcpEV << "Nagle is enabled and there's unacked data: only full segments will be sent\n"; 00309 00310 // 00311 // Send window is effectively the minimum of the congestion window (cwnd) 00312 // and the advertised window (snd_wnd). 00313 // 00314 return conn->sendData(fullSegmentsOnly, state->snd_cwnd); 00315 } 00316 00317 void TCPBaseAlg::sendCommandInvoked() 00318 { 00319 // try sending 00320 sendData(); 00321 } 00322 00323 void TCPBaseAlg::receivedOutOfOrderSegment() 00324 { 00325 tcpEV << "Out-of-order segment, sending immediate ACK\n"; 00326 conn->sendAck(); 00327 } 00328 00329 void TCPBaseAlg::receiveSeqChanged() 00330 { 00331 // If we send a data segment already (with the updated seqNo) there is no need to send an additional ACK 00332 if (state->last_ack_sent == state->rcv_nxt && !delayedAckTimer->isScheduled()) // ackSent? 00333 { 00334 // tcpEV << "ACK has already been sent (possibly piggybacked on data)\n"; 00335 } 00336 else 00337 { 00338 00339 if (!state->delayed_acks_enabled) 00340 { 00341 tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", sending ACK now (delayed ACKs are disabled)\n"; 00342 conn->sendAck(); 00343 } 00344 else 00345 { 00346 // FIXME ACK should be generated for at least every second SMSS-sized segment! 00347 // schedule delayed ACK timer if not already running 00348 tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", scheduling ACK\n"; 00349 if (!delayedAckTimer->isScheduled()) 00350 conn->scheduleTimeout(delayedAckTimer, DELAYED_ACK_TIMEOUT); 00351 } 00352 } 00353 } 00354 00355 void TCPBaseAlg::receivedDataAck(uint32 firstSeqAcked) 00356 { 00357 // if round-trip time measurement is running, check if rtseq has been acked 00358 if (state->rtseq_sendtime!=0 && seqLess(state->rtseq, state->snd_una)) 00359 { 00360 // print value 00361 tcpEV << "Round-trip time measured on rtseq=" << state->rtseq << ": " 00362 << floor((simTime() - state->rtseq_sendtime)*1000+0.5) << "ms\n"; 00363 00364 // update RTT variables with new value 00365 rttMeasurementComplete(state->rtseq_sendtime, simTime()); 00366 00367 // measurement finished 00368 state->rtseq_sendtime = 0; 00369 } 00370 00371 // 00372 // handling of retransmission timer: if the ACK is for the last segment sent 00373 // (no data in flight), cancel the timer, otherwise restart the timer 00374 // with the current RTO value. 00375 // 00376 if (state->snd_una==state->snd_max) 00377 { 00378 if (rexmitTimer->isScheduled()) 00379 { 00380 tcpEV << "ACK acks all outstanding segments, cancel REXMIT timer\n"; 00381 cancelEvent(rexmitTimer); 00382 } 00383 else 00384 { 00385 tcpEV << "There were no outstanding segments, nothing new in this ACK.\n"; 00386 } 00387 } 00388 else 00389 { 00390 tcpEV << "ACK acks some but not all outstanding segments (" 00391 << (state->snd_max - state->snd_una) << " bytes outstanding), " 00392 << "restarting REXMIT timer\n"; 00393 cancelEvent(rexmitTimer); 00394 startRexmitTimer(); 00395 } 00396 00397 // 00398 // Leave congestion window management and possible sending data to 00399 // subclasses (e.g. TCPTahoe, TCPReno). 00400 // 00401 // That is, subclasses will redefine this method, call us, then perform 00402 // window adjustments and send data (if there's room in the window). 00403 // 00404 } 00405 00406 void TCPBaseAlg::receivedDuplicateAck() 00407 { 00408 tcpEV << "Duplicate ACK #" << state->dupacks << "\n"; 00409 00410 // 00411 // Leave to subclasses (e.g. TCPTahoe, TCPReno) whatever they want to do 00412 // on duplicate Acks. 00413 // 00414 // That is, subclasses will redefine this method, call us, then perform 00415 // whatever action they want to do on dupAcks (e.g. retransmitting one segment). 00416 // 00417 } 00418 00419 void TCPBaseAlg::receivedAckForDataNotYetSent(uint32 seq) 00420 { 00421 tcpEV << "ACK acks something not yet sent, sending immediate ACK\n"; 00422 conn->sendAck(); 00423 } 00424 00425 void TCPBaseAlg::ackSent() 00426 { 00427 state->last_ack_sent = state->rcv_nxt; 00428 // if delayed ACK timer is running, cancel it 00429 if (delayedAckTimer->isScheduled()) 00430 cancelEvent(delayedAckTimer); 00431 } 00432 00433 void TCPBaseAlg::dataSent(uint32 fromseq) 00434 { 00435 // if retransmission timer not running, schedule it 00436 if (!rexmitTimer->isScheduled()) 00437 { 00438 tcpEV << "Starting REXMIT timer\n"; 00439 startRexmitTimer(); 00440 } 00441 00442 // start round-trip time measurement (if not already running) 00443 if (state->rtseq_sendtime==0) 00444 { 00445 // remember this sequence number and when it was sent 00446 state->rtseq = fromseq; 00447 state->rtseq_sendtime = simTime(); 00448 tcpEV << "Starting rtt measurement on seq=" << state->rtseq << "\n"; 00449 } 00450 } 00451 00452 void TCPBaseAlg::restartRexmitTimer() 00453 { 00454 if (rexmitTimer->isScheduled()) 00455 cancelEvent(rexmitTimer); 00456 startRexmitTimer(); 00457 } 00458 00459