chost.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) 1997 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 Daedalus Research
00017  *  Group at the University of California Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be
00019  *    used 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  * $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/chost.cc,v 1.13 2000/09/01 03:04:05 haoboy Exp $
00035  */
00036 
00037 /*
00038  * Functions invoked by TcpSessionAgent
00039  */
00040 #include "nilist.h"
00041 #include "chost.h"
00042 #include "tcp-int.h"
00043 #include "random.h"
00044 
00045 CorresHost::CorresHost() : slink(), TcpFsAgent(),
00046     lastackTS_(0), dontAdjustOwnd_(0), dontIncrCwnd_(0), rexmtSegCount_(0),
00047     connWithPktBeforeFS_(NULL)
00048 {
00049     nActive_ = nTimeout_ = nFastRec_ = 0;
00050     ownd_ = 0;
00051     owndCorrection_ = 0;
00052     closecwTS_ = 0;
00053     connIter_ = new Islist_iter<IntTcpAgent> (conns_);
00054     rtt_seg_ = NULL;
00055 }
00056 
00057 
00058 /*
00059  * Open up the congestion window.
00060  */
00061 void 
00062 CorresHost::opencwnd(int /*size*/, IntTcpAgent *sender)
00063 {
00064     if (cwnd_ < ssthresh_) {
00065         /* slow-start (exponential) */
00066         cwnd_ += 1;
00067     } else {
00068         /* linear */
00069         //double f;
00070         if (!proxyopt_) {
00071             switch (wnd_option_) {
00072             case 0:
00073                 if ((count_ = count_ + winInc_) >= cwnd_) {
00074                     count_ = 0;
00075                     cwnd_ += winInc_;
00076                 }
00077                 break;
00078             case 1:
00079                 /* This is the standard algorithm. */
00080                 cwnd_ += winInc_ / cwnd_;
00081                 break;
00082             default:
00083 #ifdef notdef
00084                 /*XXX*/
00085                 error("illegal window option %d", wnd_option_);
00086 #endif
00087                 abort();
00088             }
00089         } else {    // proxy
00090             switch (wnd_option_) {
00091             case 0: 
00092             case 1:
00093                 if (sender->highest_ack_ >= sender->wndIncSeqno_) {
00094                     cwnd_ += winInc_;
00095                     sender->wndIncSeqno_ = 0;
00096                 }
00097                 break;
00098             default:
00099 #ifdef notdef
00100                 /*XXX*/
00101                 error("illegal window option %d", wnd_option_);
00102 #endif
00103                 abort();
00104             }
00105         }
00106     }
00107     // if maxcwnd_ is set (nonzero), make it the cwnd limit
00108     if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
00109         cwnd_ = maxcwnd_;
00110     
00111     return;
00112 }
00113 
00114 void 
00115 CorresHost::closecwnd(int how, double ts, IntTcpAgent *sender)
00116 {
00117     if (proxyopt_) {
00118         if (!sender || ts > sender->closecwTS_)
00119             closecwnd(how, sender);
00120     }
00121     else {
00122         if (ts > closecwTS_)
00123             closecwnd(how, sender);
00124     }
00125 }
00126 
00127 void 
00128 CorresHost::closecwnd(int how, IntTcpAgent *sender)
00129 {
00130     int sender_ownd = 0;
00131     if (sender)
00132         sender_ownd = sender->maxseq_ - sender->highest_ack_;
00133     closecwTS_ = Scheduler::instance().clock();
00134     if (proxyopt_) {
00135         if (sender)
00136             sender->closecwTS_ = closecwTS_;
00137         how += 10;
00138     }
00139     switch (how) {
00140     case 0:
00141     case 10:
00142         /* timeouts */
00143 
00144         /* 
00145          * XXX we use cwnd_ instead of ownd_ here, which may not be
00146          * appropriate if the sender does not fully utilize the
00147          * available congestion window (ownd_ < cwnd_).
00148          */
00149         ssthresh_ = int(cwnd_ * winMult_);
00150         cwnd_ = int(wndInit_);
00151         break;
00152         
00153     case 1:
00154         /* Reno dup acks, or after a recent congestion indication. */
00155 
00156         /* 
00157          * XXX we use cwnd_ instead of ownd_ here, which may not be
00158          * appropriate if the sender does not fully utilize the
00159          * available congestion window (ownd_ < cwnd_).
00160          */
00161         cwnd_ *= winMult_;
00162         ssthresh_ = int(cwnd_);
00163         if (ssthresh_ < 2)
00164             ssthresh_ = 2;
00165         break;
00166 
00167     case 11:
00168         /* Reno dup acks, or after a recent congestion indication. */
00169         /* XXX fix this -- don't make it dependent on ownd */
00170         cwnd_ = ownd_ - sender_ownd*(1-winMult_);
00171         ssthresh_ = int(cwnd_);
00172         if (ssthresh_ < 2)
00173             ssthresh_ = 2;
00174         break;
00175 
00176     case 3:
00177     case 13:
00178         /* idle time >= t_rtxcur_ */
00179         cwnd_ = wndInit_;
00180         break;
00181         
00182     default:
00183         abort();
00184     }
00185     fcnt_ = 0.;
00186     count_ = 0;
00187     if (sender)
00188         sender->count_ = 0;
00189 }
00190 
00191 Segment* 
00192 CorresHost::add_pkts(int /*size*/, int seqno, int sessionSeqno, int daddr, int dport, 
00193              int sport, double ts, IntTcpAgent *sender)
00194 {
00195     class Segment *news;
00196 
00197     ownd_ += 1;
00198     news = new Segment;
00199     news->seqno_ = seqno;
00200     news->sessionSeqno_ = sessionSeqno;
00201     news->daddr_ = daddr;
00202     news->dport_ = dport;
00203     news->sport_ = sport;
00204     news->ts_ = ts;
00205     news->size_ = 1;
00206     news->dupacks_ = 0;
00207     news->later_acks_ = 0;
00208     news->thresh_dupacks_ = 0;
00209     news->partialack_ = 0;
00210     news->rxmitted_ = 0;
00211     news->sender_ = sender;
00212     seglist_.append(news);
00213     return news;
00214 }
00215 
00216 void
00217 CorresHost::adjust_ownd(int size) 
00218 {
00219     if (double(owndCorrection_) < size)
00220         ownd_ -= min(double(ownd_), size - double(owndCorrection_));
00221     owndCorrection_ -= min(double(owndCorrection_),size);
00222     if (double(ownd_) < -0.5 || double(owndCorrection_ < -0.5))
00223         printf("In adjust_ownd(): ownd_ = %g  owndCorrection_ = %g\n", double(ownd_), double(owndCorrection_));
00224 }
00225 
00226 int
00227 CorresHost::clean_segs(int /*size*/, Packet *pkt, IntTcpAgent *sender, int sessionSeqno, int amt_data_acked)
00228 { 
00229     Segment *cur, *prev=NULL, *newseg;
00230     int i;
00231     //int rval = -1;
00232 
00233     /* remove all acked pkts from list */
00234     int latest_susp_loss = rmv_old_segs(pkt, sender, amt_data_acked);
00235     /* 
00236      * XXX If no new data is acked and the last time we shrunk the window 
00237      * covers the most recent suspected loss, update the estimate of the amount
00238      * of outstanding data.
00239      */
00240     if (amt_data_acked == 0 && latest_susp_loss <= recover_ && 
00241     !dontAdjustOwnd_ && last_cwnd_action_ != CWND_ACTION_TIMEOUT) {
00242         owndCorrection_ += min(double(ownd_),1);
00243         ownd_ -= min(double(ownd_),1);
00244     }
00245     /*
00246      * A pkt is a candidate for retransmission if it is the leftmost one in the
00247      * unacked window for the connection AND has at least numdupacks_
00248      * dupacks/later acks AND (at least one dupack OR a later packet also
00249      * with the threshold number of dup/later acks). A pkt is also a candidate
00250      * for immediate retransmission if it has partialack_ set, indicating that
00251      * a partial new ack has been received for it.
00252      */
00253 
00254     for (i=0; i < rexmtSegCount_; i++) {
00255         int remove_flag = 0;
00256         /* 
00257          * curArray_ only contains segments that are the first oldest
00258          * unacked segments of their connection (i.e., they are at the left
00259          * edge of their window) and have either received a
00260          * partial ack and/or have received at least cur->numdupacks_
00261          * dupacks/later acks. Thus, segments in curArray_ have a high
00262          * probability (but not certain) of being eligible for 
00263          * retransmission. Using curArray_ avoids having to scan
00264          * through all the segments.
00265          */
00266         cur = curArray_[i];
00267         prev = prevArray_[i];
00268         if (cur->partialack_ || cur->dupacks_ > 0 || 
00269         cur->sender_->num_thresh_dupack_segs_ > 1 ) {
00270             if (cur->thresh_dupacks_) {
00271                 cur->thresh_dupacks_ = 0;
00272                 cur->sender_->num_thresh_dupack_segs_--;
00273             }
00274             if (cur->sessionSeqno_ <= recover_ && 
00275             last_cwnd_action_ != CWND_ACTION_TIMEOUT /* XXX 2 */)
00276                 dontAdjustOwnd_ = 1;
00277             if ((cur->sessionSeqno_ > recover_) || 
00278             (last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)
00279             || (proxyopt_ && cur->seqno_ > cur->sender_->recover_)
00280             || (proxyopt_ && cur->sender_->last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)) { 
00281                 /* new loss window */
00282                 closecwnd(1, cur->ts_, cur->sender_);
00283                 recover_ = sessionSeqno - 1;
00284                 last_cwnd_action_ = CWND_ACTION_DUPACK /* XXX 1 */;
00285                 cur->sender_->recover_ = cur->sender_->maxseq_;
00286                 cur->sender_->last_cwnd_action_ = 
00287                     CWND_ACTION_DUPACK /* XXX 1 */;
00288                 dontAdjustOwnd_ = 0;
00289             }
00290             if ((newseg = cur->sender_->rxmit_last(TCP_REASON_DUPACK, 
00291                cur->seqno_, cur->sessionSeqno_, cur->ts_))) {
00292                 newseg->rxmitted_ = 1;
00293                 adjust_ownd(cur->size_);
00294                 if (!dontAdjustOwnd_) {
00295                     owndCorrection_ += 
00296                         min(double(ownd_),cur->dupacks_);
00297                     ownd_ -= min(double(ownd_),cur->dupacks_);
00298                 }
00299                 seglist_.remove(cur, prev);
00300                 remove_flag = 1;
00301                 delete cur;
00302             }
00303             /* 
00304              * if segment just removed used to be the one just previous
00305              * to the next segment in the array, update prev for the
00306              * next segment
00307              */
00308             if (remove_flag && cur == prevArray_[i+1])
00309                 prevArray_[i+1] = prev;
00310         }
00311     }
00312     rexmtSegCount_ = 0;
00313     return(0);
00314 }
00315             
00316 
00317 int
00318 CorresHost::rmv_old_segs(Packet *pkt, IntTcpAgent *sender, int amt_data_acked)
00319 {
00320     Islist_iter<Segment> seg_iter(seglist_);
00321     Segment *cur, *prev=0;
00322     int found = 0;
00323     int done = 0;
00324     int new_data_acked = 0;
00325     int partialack = 0;
00326     int latest_susp_loss = -1;
00327     hdr_tcp *tcph = hdr_tcp::access(pkt);
00328 
00329     if (tcph->ts_echo() > lastackTS_)
00330         lastackTS_ = tcph->ts_echo();
00331 
00332     while (((cur = seg_iter()) != NULL) &&
00333            (!done || tcph->ts_echo() > cur->ts_)) {
00334         int remove_flag = 0;
00335         /* ack for older pkt of another connection */
00336         if (sender != cur->sender_ && tcph->ts_echo() > cur->ts_) { 
00337             if (!disableIntLossRecov_)
00338                 cur->later_acks_++;
00339             latest_susp_loss = 
00340                 max(latest_susp_loss,cur->sessionSeqno_);
00341             dontIncrCwnd_ = 1;
00342         } 
00343         /* ack for same connection */
00344         else if (sender == cur->sender_) {
00345             /* found packet acked */
00346             if (tcph->seqno() == cur->seqno_ && 
00347                 tcph->ts_echo() == cur->ts_) 
00348                 found = 1;
00349             /* higher ack => clean up acked packets */
00350             if (tcph->seqno() >= cur->seqno_) {
00351                 adjust_ownd(cur->size_);
00352                 seglist_.remove(cur, prev);
00353                 remove_flag = 1;
00354                 new_data_acked += cur->size_;
00355                 if (new_data_acked >= amt_data_acked)
00356                     done = 1;
00357                 if (prev == cur) 
00358                     prev = NULL;
00359                 if (cur == rtt_seg_)
00360                     rtt_seg_ = NULL;
00361                 delete cur;
00362                 if (seg_iter.get_cur() && prev)
00363                     seg_iter.set_cur(prev);
00364                 else if (seg_iter.get_cur())
00365                     seg_iter.set_cur(seg_iter.get_last());
00366             } 
00367             /* partial new ack => rexmt immediately */
00368             /* XXX should we check recover for session? */
00369             else if (amt_data_acked > 0 && 
00370                  tcph->seqno() == cur->seqno_-1 &&
00371                  cur->seqno_ <= sender->recover_ &&
00372                  sender->last_cwnd_action_ == CWND_ACTION_DUPACK) {
00373                 cur->partialack_ = 1;
00374                 partialack = 1;
00375                 latest_susp_loss = 
00376                     max(latest_susp_loss,cur->sessionSeqno_);
00377                 if (new_data_acked >= amt_data_acked)
00378                     done = 1;
00379                 dontIncrCwnd_ = 1;
00380             }
00381             /* 
00382              * If no new data has been acked AND this segment has
00383              * not been retransmitted before AND the ack indicates 
00384              * that this is the next segment to be acked, then
00385              * increment dupack count.
00386              */
00387             else if (!amt_data_acked && !cur->rxmitted_ &&
00388                  tcph->seqno() == cur->seqno_-1) {
00389                 cur->dupacks_++;
00390                 latest_susp_loss = 
00391                     max(latest_susp_loss,cur->sessionSeqno_);
00392                 done = 1;
00393                 dontIncrCwnd_ = 1;
00394             } 
00395         }
00396         if (cur->dupacks_+cur->later_acks_ >= sender->numdupacks_ &&
00397             !cur->thresh_dupacks_) {
00398             cur->thresh_dupacks_ = 1;
00399             cur->sender_->num_thresh_dupack_segs_++;
00400         }
00401 
00402         if (amt_data_acked==0 && tcph->seqno()==cur->seqno_-1)
00403             done = 1;
00404         /* XXX we could check for rexmt candidates here if we ignore 
00405            the num_thresh_dupack_segs_ check */
00406         if (!remove_flag &&
00407             cur->seqno_ == cur->sender_->highest_ack_ + 1 &&
00408             (cur->dupacks_ + cur->later_acks_ >= sender->numdupacks_ ||
00409              cur->partialack_)) {
00410             curArray_[rexmtSegCount_] = cur;
00411             prevArray_[rexmtSegCount_] = prev;
00412             rexmtSegCount_++;
00413         }
00414         if (!remove_flag)
00415             prev = cur;
00416     }
00417     /* partial ack => terminate fast start mode */
00418     if (partialack && fs_enable_ && fs_mode_) {
00419         timeout(TCP_TIMER_RESET);
00420         rexmtSegCount_ = 0;
00421     }
00422     return latest_susp_loss;
00423 }
00424     
00425 void
00426 CorresHost::add_agent(IntTcpAgent *agent, int /*size*/, double winMult, 
00427               int winInc, int /*ssthresh*/)
00428 {
00429     if (nActive_ >= MAX_PARALLEL_CONN) {
00430         printf("In add_agent(): reached limit of number of parallel conn (%d); returning\n", nActive_);
00431         return;
00432     }
00433     nActive_++;
00434     if ((!fixedIw_ && nActive_ > 1) || cwnd_ == 0)
00435         cwnd_ += 1; /* XXX should this be done? */
00436     wndInit_ = 1;
00437     winMult_ = winMult;
00438     winInc_ = winInc;
00439 /*  ssthresh_ = ssthresh;*/
00440     conns_.append(agent);
00441 }
00442 
00443 int
00444 CorresHost::ok_to_snd(int /*size*/)
00445 {
00446     if (ownd_ <= -0.5)
00447         printf("In ok_to_snd(): ownd_ = %g  owndCorrection_ = %g\n", double(ownd_), double(owndCorrection_));
00448     return (cwnd_ >= ownd_+1);
00449 }
00450 
00451 
00452 
00453 
00454 

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