scoreboard-rh.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1996 The Regents of the University of California.
00004  * All rights reserved.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by the Network Research
00017  *  Group at Lawrence Berkeley National Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  * 
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 
00035 
00036 /* 9/96 Pittsburgh Supercomputing Center
00037  *      UpdateScoreBoard, CheckSndNxt, MarkRetran modified for fack
00038  */
00039 
00040 #ifndef lint
00041 static const char rcsid[] =
00042     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/scoreboard-rh.cc,v 1.2 2000/08/12 21:45:39 sfloyd Exp $ (LBL)";
00043 #endif
00044 
00045 /*  A quick hack version of the scoreboard  */
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048 #include <sys/types.h>
00049 #include <math.h>
00050 
00051 #include "packet.h"
00052 #include "scoreboard-rh.h"
00053 #include "tcp.h"
00054 
00055 #define ASSERT(x) if (!(x)) {printf ("Assert SB failed\n"); exit(1);}
00056 #define ASSERT1(x) if (!(x)) {printf ("Assert1 SB (length)\n"); exit(1);}
00057 
00058 #define SBNI SBN[i%SBSIZE]
00059 
00060 // last_ack = TCP last ack
00061 int ScoreBoardRH::UpdateScoreBoard (int last_ack, hdr_tcp* tcph, int rh_id)
00062 {
00063     int i, sack_index, sack_left, sack_right;
00064     int sack_max = 0;
00065     int retran_decr = 0;
00066 
00067     /* Can't do this, because we need to process out the retran_decr  */
00068 #if 0
00069     if (tcph->sa_length() == 0) {
00070         // There are no SACK blocks, so clear the scoreboard.
00071         this->ClearScoreBoard();
00072         return(0);
00073     }
00074 #endif
00075 
00076     /*  What we do need to do is not create a scoreboard if we don't need one.  */
00077     if ((tcph->sa_length() == 0) && (length_ == 0)) {
00078         return(0);
00079     }
00080     
00081 
00082     //  If there is no scoreboard, create one.
00083     if (length_ == 0) {
00084         i = last_ack+1;
00085         SBNI.seq_no_ = i;
00086         SBNI.ack_flag_ = 0;
00087         SBNI.sack_flag_ = 0;
00088         SBNI.retran_ = 0;
00089         SBNI.snd_nxt_ = 0;
00090         SBNI.sack_cnt_ = 0;
00091         SBNI.rh_id_ = 0;
00092         first_ = i%SBSIZE;
00093         length_++;
00094         if (length_ >= SBSIZE) {
00095             printf ("Error, scoreboard too large (increase SBSIZE for more space)\n");
00096             exit(1);
00097         }
00098     }   
00099 
00100     //  Advance the left edge of the block.
00101     if (SBN[first_].seq_no_ <= last_ack) {
00102         for (i=SBN[(first_)%SBSIZE].seq_no_; i<=last_ack; i++) {
00103             //  Advance the ACK
00104             if (SBNI.seq_no_ <= last_ack) {
00105                 ASSERT(first_ == i%SBSIZE);
00106                 first_ = (first_+1)%SBSIZE; 
00107                 length_--;
00108                 ASSERT1(length_ >= 0);
00109                 SBNI.ack_flag_ = 1;
00110                 SBNI.sack_flag_ = 1;
00111                 if (SBNI.retran_) {
00112                     SBNI.retran_ = 0;
00113                     SBNI.snd_nxt_ = 0;
00114                     retran_decr++;
00115                     retran_sacked_ = rh_id;
00116                 }
00117                 if (length_==0) 
00118                     break;
00119             }
00120         }
00121     }
00122 
00123     for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) {
00124         sack_left = tcph->sa_left(sack_index);
00125         sack_right = tcph->sa_right(sack_index);
00126 
00127         /*  Remember the highest segment SACKed by this packet  */
00128         if (sack_right > sack_max) {
00129             sack_max = sack_right;
00130         }
00131 
00132         //  Create new entries off the right side.
00133         if (sack_right > SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_) {
00134             //  Create new entries
00135             for (i = SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_+1; i<sack_right; i++) {
00136                 SBNI.seq_no_ = i;
00137                 SBNI.ack_flag_ = 0;
00138                 SBNI.sack_flag_ = 0;
00139                 SBNI.retran_ = 0;
00140                 SBNI.snd_nxt_ = 0;
00141                 SBNI.sack_cnt_ = 0;
00142                 SBNI.rh_id_ = 0;
00143                 length_++;
00144                 if (length_ >= SBSIZE) {
00145                     printf ("Error, scoreboard too large (increase SBSIZE for more space)\n");
00146                     exit(1);
00147                 }
00148             }
00149         }
00150         
00151         for (i=SBN[(first_)%SBSIZE].seq_no_; i<sack_right; i++) {
00152             //  Check to see if this segment is now covered by the sack block
00153             if (SBNI.seq_no_ >= sack_left && SBNI.seq_no_ < sack_right) {
00154                 if (! SBNI.sack_flag_) {
00155                     SBNI.sack_flag_ = 1;
00156                 }
00157                 if (SBNI.retran_) {
00158                     SBNI.retran_ = 0;
00159                     SBNI.snd_nxt_ = 0;
00160                     retran_decr++;
00161                     retran_sacked_ = rh_id;
00162                 }
00163             }
00164         }
00165     }
00166 
00167     /*  Now go through the whole scoreboard and update sack_cnt
00168         on holes which still exist.  */
00169     if (length_ != 0) {
00170         for (i=SBN[(first_)%SBSIZE].seq_no_; i<sack_max; i++) {
00171             //  Check to see if this segment is a hole
00172             if (!SBNI.ack_flag_ && !SBNI.sack_flag_) {
00173                 SBNI.sack_cnt_++;
00174             }
00175         }
00176     }
00177 
00178     retran_decr += CheckSndNxt(sack_max);
00179 
00180     return (retran_decr);
00181 }
00182 int ScoreBoardRH::CheckSndNxt (int sack_max)
00183 {
00184     int i;
00185     int num_lost = 0;
00186 
00187     if (length_ != 0) {
00188         for (i=SBN[(first_)%SBSIZE].seq_no_; i<sack_max; i++) {
00189             //  Check to see if this segment's snd_nxt_ is now covered by the sack block
00190             if (SBNI.retran_ && SBNI.snd_nxt_ < sack_max) {
00191                 // the packet was lost again
00192                 SBNI.retran_ = 0;
00193                 SBNI.snd_nxt_ = 0;
00194                 SBNI.sack_cnt_ = 1;
00195                 num_lost++;
00196             }
00197         }
00198     }
00199     return (num_lost);
00200 
00201 
00202 }
00203 
00204 void ScoreBoardRH::ClearScoreBoard()
00205 {
00206     length_ = 0;
00207 }
00208 
00209 /*
00210  * GetNextRetran() returns "-1" if there is no packet that is
00211  *   not acked and not sacked and not retransmitted.
00212  */
00213 int ScoreBoardRH::GetNextRetran()   // Returns sequence number of next pkt...
00214 {
00215     int i;
00216 
00217     if (length_) {
00218         for (i=SBN[(first_)%SBSIZE].seq_no_; 
00219              i<SBN[(first_)%SBSIZE].seq_no_+length_; i++) {
00220             if (!SBNI.ack_flag_ && !SBNI.sack_flag_ && !SBNI.retran_
00221                 && (SBNI.sack_cnt_ >= *numdupacks_)) {
00222                 return (i);
00223             }
00224         }
00225     }
00226     return (-1);
00227 }
00228 
00229 
00230 void ScoreBoardRH::MarkRetran (int retran_seqno, int snd_nxt, int rh_id)
00231 {
00232     SBN[retran_seqno%SBSIZE].retran_ = 1;
00233     SBN[retran_seqno%SBSIZE].snd_nxt_ = snd_nxt;
00234     SBN[retran_seqno%SBSIZE].rh_id_ = rh_id;
00235     retran_occured_ = rh_id;
00236 }
00237 
00238 int ScoreBoardRH::GetFack (int last_ack)
00239 {
00240     if (length_) {
00241         return(SBN[(first_)%SBSIZE].seq_no_+length_-1);
00242     }
00243     else {
00244         return(last_ack);
00245     }
00246 }
00247 
00248 int ScoreBoardRH::GetNewHoles ()
00249 {
00250     int i, new_holes=0;
00251 
00252     for (i=SBN[(first_)%SBSIZE].seq_no_;
00253          i<SBN[(first_)%SBSIZE].seq_no_+length_; i++) {
00254         //  Check to see if this segment is a new hole
00255 #if 1
00256         if (!SBNI.ack_flag_ && !SBNI.sack_flag_ && SBNI.sack_cnt_ == 1) {
00257             new_holes++;
00258         }
00259 #else
00260         if (!SBNI.ack_flag_ && !SBNI.sack_flag_ && SBNI.sack_cnt_ == *numdupacks_) {
00261             new_holes++;
00262         }
00263 #endif
00264     }
00265     return (new_holes);
00266 }
00267 
00268 void ScoreBoardRH::TimeoutScoreBoard (int snd_nxt)
00269 {
00270     int i, sack_right;
00271 
00272     if (length_ == 0) {
00273         // No need to do anything!  
00274         return;
00275     }
00276 
00277     sack_right = snd_nxt;  // Use this to know how far to extend.
00278 
00279     //  Create new entries off the right side.
00280     if (sack_right > SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_) {
00281         //  Create new entries
00282         for (i = SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_+1; i<sack_right; i++) {
00283             SBNI.seq_no_ = i;
00284             SBNI.ack_flag_ = 0;
00285             SBNI.sack_flag_ = 0;
00286             SBNI.retran_ = 0;
00287             SBNI.snd_nxt_ = 0;
00288             SBNI.sack_cnt_ = 0;
00289             SBNI.rh_id_ = 0;
00290             length_++;
00291             if (length_ >= SBSIZE) {
00292                 printf ("Error, scoreboard too large (increase SBSIZE for more space)\n");
00293                 exit(1);
00294             }
00295         }
00296     }
00297 
00298     /*  Now go through the whole scoreboard and update sack_cnt on holes;
00299         clear retran flag on everything.  */
00300     for (i=SBN[(first_)%SBSIZE].seq_no_;
00301          i<SBN[(first_)%SBSIZE].seq_no_+length_; i++) {
00302         //  Check to see if this segment is a hole
00303         if (!SBNI.ack_flag_ && !SBNI.sack_flag_) {
00304             SBNI.retran_ = 0;
00305             SBNI.snd_nxt_ = 0;
00306             SBNI.sack_cnt_ = *numdupacks_;  // This forces all holes to be retransmitted.
00307         }
00308     }
00309 
00310     /*  And, finally, check the first segment in case of a renege.  */
00311     i=SBN[(first_)%SBSIZE].seq_no_;
00312     if (!SBNI.ack_flag_ && SBNI.sack_flag_) {
00313         printf ("Renege!!! seqno = %d\n", SBNI.seq_no_);
00314         SBNI.sack_flag_ = 0;
00315         SBNI.retran_ = 0;
00316         SBNI.snd_nxt_ = 0;
00317         SBNI.sack_cnt_ = *numdupacks_;  // This forces it to be retransmitted.
00318     }
00319 }
00320 
00321 #if 0
00322 /*  This routine inserts a fake sack block of length num_dupacks,
00323     starting at last_ack+1.  It is for use during NewReno recovery.
00324 */
00325 int ScoreBoardRH::FakeSack (int last_ack, int num_dupacks)
00326 {
00327     int i, sack_left, sack_right;
00328     int retran_decr = 0;
00329 
00330     //  If there is no scoreboard, create one.
00331     if (length_ == 0) {
00332         i = last_ack+1;
00333         SBNI.seq_no_ = i;
00334         SBNI.ack_flag_ = 0;
00335         SBNI.sack_flag_ = 0;
00336         SBNI.retran_ = 0;
00337         SBNI.snd_nxt_ = 0;
00338         SBNI.sack_cnt_ = 0;
00339         SBNI.rh_id_ = 0;
00340         first_ = i%SBSIZE;
00341         length_++;
00342         if (length_ >= SBSIZE) {
00343             printf ("Error, scoreboard too large (increase SBSIZE for more space)\n");
00344             exit(1);
00345         }
00346     }   
00347 
00348     //  Advance the left edge of the scoreboard.
00349     if (SBN[first_].seq_no_ <= last_ack) {
00350         for (i=SBN[(first_)%SBSIZE].seq_no_; i<=last_ack; i++) {
00351             //  Advance the ACK
00352             if (SBNI.seq_no_ <= last_ack) {
00353                 ASSERT(first_ == i%SBSIZE);
00354                 first_ = (first_+1)%SBSIZE; 
00355                 length_--;
00356                 ASSERT1(length_ >= 0);
00357                 SBNI.ack_flag_ = 1;
00358                 SBNI.sack_flag_ = 1;
00359                 if (SBNI.retran_) {
00360                     SBNI.retran_ = 0;
00361                     SBNI.snd_nxt_ = 0;
00362                     retran_decr++;
00363                 }
00364                 if (length_==0) 
00365                     break;
00366             }
00367         }
00368         /*  Now create a new hole in the first position  */
00369         i=SBN[(first_)%SBSIZE].seq_no_;
00370         SBNI.ack_flag_ = 0;
00371         SBNI.sack_flag_ = 0;
00372         SBNI.retran_ = 0;
00373         SBNI.snd_nxt_ = 0;
00374         SBNI.rh_id_ = 0;
00375         SBNI.sack_cnt_ = num_dupacks;
00376     }
00377 
00378     sack_left = last_ack + 1;
00379     sack_right = sack_left + num_dupacks - 1;
00380 
00381     //  Create new entries off the right side.
00382     if (sack_right > SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_) {
00383         //  Create new entries
00384         for (i = SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_+1; i<sack_right; i++) {
00385             SBNI.seq_no_ = i;
00386             SBNI.ack_flag_ = 0;
00387             SBNI.sack_flag_ = 0;
00388             SBNI.retran_ = 0;
00389             SBNI.snd_nxt_ = 0;
00390             SBNI.sack_cnt_ = 0;
00391             SBNI.rh_id_ = 0;
00392             length_++;
00393             if (length_ >= SBSIZE) {
00394                 printf ("Error, scoreboard too large (increase SBSIZE for more space)\n");
00395                 exit(1);
00396             }
00397         }
00398     }
00399         
00400     for (i=SBN[(first_)%SBSIZE].seq_no_; i<sack_right; i++) {
00401         //  Check to see if this segment is now covered by the sack block
00402         if (SBNI.seq_no_ >= sack_left && SBNI.seq_no_ < sack_right) {
00403             if (! SBNI.sack_flag_) {
00404                 SBNI.sack_flag_ = 1;
00405             }
00406             if (SBNI.retran_) {
00407                 SBNI.retran_ = 0;
00408                 retran_decr++;
00409             }
00410         }
00411     }
00412 
00413     /*  Now go through the whole scoreboard and update sack_cnt
00414         on holes which still exist.  In this case the only possible 
00415         case is the first hole.  */
00416         i=SBN[(first_)%SBSIZE].seq_no_;
00417     //  Check to see if this segment is a hole
00418     if (!SBNI.ack_flag_ && !SBNI.sack_flag_) {
00419         SBNI.sack_cnt_++;
00420     }
00421 
00422     return (retran_decr);
00423 }
00424 
00425 #endif
00426 
00427 int ScoreBoardRH::RetranSacked (int rh_id) {
00428     return (retran_sacked_ == rh_id);
00429 }

Generated on Tue Mar 6 16:47:50 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6