|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2005-2010 Irene Ruengeler 00003 // Copyright (C) 2009-2010 Thomas Dreibholz 00004 // 00005 // This program is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU General Public License 00007 // as published by the Free Software Foundation; either version 2 00008 // of the License, or (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00017 // 00018 00019 #include "SCTPAssociation.h" 00020 00021 #ifdef _MSC_VER 00022 inline double rint(double x) {return floor(x+.5);} 00023 #endif 00024 00025 // #define sctpEV3 std::cout 00026 00027 00028 00029 00030 void SCTPAssociation::recordCwndUpdate(SCTPPathVariables* path) 00031 { 00032 path->statisticsPathSSthresh->record(path->ssthresh); 00033 path->statisticsPathCwnd->record(path->cwnd); 00034 } 00035 00036 00037 00038 00039 void SCTPAssociation::initCCParameters(SCTPPathVariables* path) 00040 { 00041 path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380)); 00042 path->ssthresh = state->peerRwnd; 00043 recordCwndUpdate(path); 00044 00045 sctpEV3 << simTime() << ":\tCC [initCCParameters]\t" << path->remoteAddress 00046 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; 00047 } 00048 00049 00050 void SCTPAssociation::cwndUpdateAfterSack() 00051 { 00052 for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) { 00053 SCTPPathVariables* path = iter->second; 00054 if(path->fastRecoveryActive == false) { 00055 00056 // ====== Retransmission required -> reduce congestion window ====== 00057 if(path->requiresRtx) { 00058 double decreaseFactor = 0.5; 00059 00060 sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack]\t" << path->remoteAddress 00061 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd; 00062 00063 path->ssthresh = max((int32)path->cwnd - (int32)rint(decreaseFactor * (double)path->cwnd), 00064 4 * (int32)path->pmtu); 00065 path->cwnd = path->ssthresh; 00066 00067 sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; 00068 recordCwndUpdate(path); 00069 path->partialBytesAcked = 0; 00070 00071 00072 // ====== Fast Recovery ======================================== 00073 if(state->fastRecoverySupported) { 00074 uint32 highestAckOnPath = state->lastTsnAck; 00075 for(SCTPQueue::PayloadQueue::iterator pq = retransmissionQ->payloadQueue.begin(); 00076 pq != retransmissionQ->payloadQueue.end(); pq++) { 00077 if( (chunkHasBeenAcked(pq->second) == true) && 00078 (tsnGt(pq->second->tsn, highestAckOnPath)) && 00079 (pq->second->getLastDestinationPath() == path) ) { 00080 // T.D. 21.11.09: Only take care of TSNs on the same path! 00081 highestAckOnPath = pq->second->tsn; 00082 } 00083 } 00084 /* this can ONLY become TRUE, when Fast Recovery IS supported */ 00085 path->fastRecoveryActive = true; 00086 path->fastRecoveryExitPoint = highestAckOnPath; 00087 path->fastRecoveryEnteringTime = simTime(); 00088 00089 sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Entering Fast Recovery on path " 00090 << path->remoteAddress 00091 << ", exit point is " << path->fastRecoveryExitPoint << endl; 00092 } 00093 } 00094 } 00095 else { 00096 for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) { 00097 SCTPPathVariables* path = iter->second; 00098 if(path->fastRecoveryActive) { 00099 sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Still in Fast Recovery on path " 00100 << path->remoteAddress 00101 << ", exit point is " << path->fastRecoveryExitPoint << endl; 00102 } 00103 } 00104 } 00105 } 00106 } 00107 00108 00109 void SCTPAssociation::updateFastRecoveryStatus(const uint32 lastTsnAck) 00110 { 00111 for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) { 00112 SCTPPathVariables* path = iter->second; 00113 00114 if (path->fastRecoveryActive) { 00115 if ( (tsnGt(lastTsnAck, path->fastRecoveryExitPoint)) || 00116 (lastTsnAck == path->fastRecoveryExitPoint) 00117 ) { 00118 path->fastRecoveryActive = false; 00119 path->fastRecoveryExitPoint = 0; 00120 00121 sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Leaving Fast Recovery on path " 00122 << path->remoteAddress 00123 << ", lastTsnAck=" << lastTsnAck << endl; 00124 } 00125 } 00126 } 00127 } 00128 00129 00130 void SCTPAssociation::cwndUpdateBytesAcked(SCTPPathVariables* path, 00131 const uint32 ackedBytes, 00132 const bool ctsnaAdvanced) 00133 { 00134 sctpEV3 << simulation.getSimTime() << "====> cwndUpdateBytesAcked:" 00135 << " path=" << path->remoteAddress 00136 << " ackedBytes=" << ackedBytes 00137 << " ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") 00138 << " cwnd=" << path->cwnd 00139 << " ssthresh=" << path->ssthresh 00140 << " ackedBytes=" << ackedBytes 00141 << " pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate 00142 << " pathOsb=" << path->outstandingBytes 00143 << endl; 00144 00145 if (path->fastRecoveryActive == false) { 00146 // T.D. 21.11.09: Increasing cwnd is only allowed when not being in 00147 // Fast Recovery mode! 00148 00149 // ====== Slow Start ================================================== 00150 if (path->cwnd <= path->ssthresh) { 00151 // ------ Clear PartialBytesAcked counter -------------------------- 00152 path->partialBytesAcked = 0; 00153 00154 // ------ Increase Congestion Window ------------------------------- 00155 if ((ctsnaAdvanced == true) && 00156 (path->outstandingBytesBeforeUpdate >= path->cwnd)) { 00157 sctpEV3 << simTime() << ":\tCC [cwndUpdateBytesAcked-SlowStart]\t" << path->remoteAddress 00158 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << " acked=" << ackedBytes; 00159 00160 path->cwnd += (int32)min(path->pmtu, ackedBytes); 00161 00162 sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; 00163 recordCwndUpdate(path); 00164 } 00165 00166 // ------ No need to increase Congestion Window -------------------- 00167 else { 00168 sctpEV3 << simTime() << ":\tCC " 00169 << "Not increasing cwnd of path " << path->remoteAddress << " in slow start:\t" 00170 << "ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t" 00171 << "cwnd=" << path->cwnd << "\t" 00172 << "ssthresh=" << path->ssthresh << "\t" 00173 << "ackedBytes=" << ackedBytes << "\t" 00174 << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t" 00175 << "pathOsb=" << path->outstandingBytes << "\t" 00176 << "(pathOsbBeforeUpdate >= path->cwnd)=" 00177 << (path->outstandingBytesBeforeUpdate >= path->cwnd) << endl; 00178 } 00179 } 00180 00181 // ====== Congestion Avoidance ======================================== 00182 else 00183 { 00184 // ------ Increase PartialBytesAcked counter ----------------------- 00185 path->partialBytesAcked += ackedBytes; 00186 00187 double increaseFactor = 1.0; 00188 00189 // ------ Increase Congestion Window ------------------------------- 00190 if ( (path->partialBytesAcked >= path->cwnd) && 00191 (ctsnaAdvanced == true) && 00192 (path->outstandingBytesBeforeUpdate >= path->cwnd) ) { 00193 sctpEV3 << simTime() << ":\tCC [cwndUpdateBytesAcked-CgAvoidance]\t" << path->remoteAddress 00194 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << " acked=" << ackedBytes; 00195 00196 path->cwnd += (int32)rint(increaseFactor * path->pmtu); 00197 00198 sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; 00199 recordCwndUpdate(path); 00200 path->partialBytesAcked = 00201 ((path->cwnd < path->partialBytesAcked) ? 00202 (path->partialBytesAcked - path->cwnd) : 0); 00203 } 00204 00205 // ------ No need to increase Congestion Window ------------------- 00206 else { 00207 sctpEV3 << simTime() << ":\tCC " 00208 << "Not increasing cwnd of path " << path->remoteAddress << " in congestion avoidance: " 00209 << "ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t" 00210 << "cwnd=" << path->cwnd << "\t" 00211 << "ssthresh=" << path->ssthresh << "\t" 00212 << "ackedBytes=" << ackedBytes << "\t" 00213 << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t" 00214 << "pathOsb=" << path->outstandingBytes << "\t" 00215 << "(pathOsbBeforeUpdate >= path->cwnd)=" 00216 << (path->outstandingBytesBeforeUpdate >= path->cwnd) << "\t" 00217 << "partialBytesAcked=" << path->partialBytesAcked << "\t" 00218 << "(path->partialBytesAcked >= path->cwnd)=" 00219 << (path->partialBytesAcked >= path->cwnd) << endl; 00220 } 00221 } 00222 00223 // ====== Reset PartialBytesAcked counter if no more outstanding bytes 00224 if(path->outstandingBytes == 0) { 00225 path->partialBytesAcked = 0; 00226 } 00227 } 00228 else { 00229 sctpEV3 << simTime() << ":\tCC " 00230 << "Not increasing cwnd of path " << path->remoteAddress 00231 << " during Fast Recovery" << endl; 00232 } 00233 } 00234 00235 00236 void SCTPAssociation::cwndUpdateAfterRtxTimeout(SCTPPathVariables* path) 00237 { 00238 sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterRtxTimeout]\t" << path->remoteAddress 00239 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd; 00240 00241 path->ssthresh = (int32)max(path->cwnd / 2, 4 * path->pmtu); 00242 path->cwnd = path->pmtu; 00243 00244 sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; 00245 path->partialBytesAcked = 0; 00246 recordCwndUpdate(path); 00247 00248 // Leave Fast Recovery mode 00249 if (path->fastRecoveryActive == true) { 00250 path->fastRecoveryActive = false; 00251 path->fastRecoveryExitPoint = 0; 00252 } 00253 } 00254 00255 00256 void SCTPAssociation::cwndUpdateMaxBurst(SCTPPathVariables* path) 00257 { 00258 if(path->cwnd > ((path->outstandingBytes + state->maxBurst * path->pmtu))) { 00259 sctpEV3 << simTime() << ":\tCC [cwndUpdateMaxBurst]\t" << path->remoteAddress 00260 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd 00261 << "\tosb=" << path->outstandingBytes 00262 << "\tmaxBurst=" << state->maxBurst * path->pmtu << endl; 00263 00264 path->cwnd = path->outstandingBytes + (state->maxBurst * path->pmtu); 00265 recordCwndUpdate(path); 00266 00267 sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; 00268 } 00269 } 00270 00271 00272 void SCTPAssociation::cwndUpdateAfterCwndTimeout(SCTPPathVariables* path) 00273 { 00274 // When the association does not transmit data on a given transport address 00275 // within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU. 00276 00277 sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterCwndTimeout]\t" << path->remoteAddress 00278 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd; 00279 path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380)); 00280 sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; 00281 recordCwndUpdate(path); 00282 }