SCTPCCFunctions.cc

Go to the documentation of this file.
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 }