tcp-fack.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) 1990, 1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms are permitted
00007  * provided that the above copyright notice and this paragraph are
00008  * duplicated in all such forms and that any documentation,
00009  * advertising materials, and other materials related to such
00010  * distribution and use acknowledge that the software was developed
00011  * by the University of California, Lawrence Berkeley Laboratory,
00012  * Berkeley, CA.  The name of the University may not be used to
00013  * endorse or promote products derived from this software without
00014  * specific prior written permission.
00015  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00017  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00018  */
00019 
00020 #ifndef lint
00021 static const char rcsid[] =
00022     "@(#) /home/ctk21/cvsroot//hssstcp/ns/ns-2.1b9/tcp/tcp-fack.cc,v 1.2 2002/08/12 10:43:58 ctk21 Exp (PSC)";
00023 #endif
00024 
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <sys/types.h>
00028 
00029 #include "ip.h"
00030 #include "tcp.h"
00031 #include "flags.h"
00032 #include "scoreboard.h"
00033 #include "random.h"
00034 #include "tcp-fack.h"
00035 #include "template.h"
00036 
00037 static class FackTcpClass : public TclClass {
00038 public:
00039     FackTcpClass() : TclClass("Agent/TCP/Fack") {}
00040     TclObject* create(int, const char*const*) {
00041         return (new FackTcpAgent());
00042     }
00043 } class_fack;
00044 
00045 
00046 FackTcpAgent::FackTcpAgent() :  timeout_(FALSE), wintrim_(0),
00047     wintrimmult_(.5), rampdown_(0), fack_(-1), retran_data_(0),
00048     ss_div4_(0)     // What about fastrecov_ and scb_
00049 {
00050     bind_bool("ss-div4_", &ss_div4_);
00051     bind_bool("rampdown_", &rampdown_);
00052     scb_ = new ScoreBoard(new ScoreBoardNode[SBSIZE],SBSIZE);
00053 }
00054 
00055 FackTcpAgent::~FackTcpAgent(){
00056     delete [] scb_;
00057 }
00058 
00059 int FackTcpAgent::window() 
00060 {
00061     int win;
00062     win = int((cwnd_ < wnd_ ? (double) cwnd_ : (double) wnd_) + wintrim_);
00063     return (win);
00064 }
00065 
00066 void FackTcpAgent::reset ()
00067 {
00068     scb_->ClearScoreBoard();
00069     TcpAgent::reset ();
00070 }
00071 
00072 /*
00073  * Process a dupack.
00074  */
00075 void FackTcpAgent::oldack(Packet* pkt)
00076 {
00077     hdr_tcp *tcph = hdr_tcp::access(pkt);
00078 
00079     last_ack_ = tcph->seqno();
00080     highest_ack_ = last_ack_;
00081     fack_ = max(fack_,highest_ack_);
00082     /* 
00083      * There are conditions under which certain versions of TCP (e.g., tcp-fs)
00084      * retract maxseq_. The following line of code helps in those cases. For
00085      * versions of TCP, it is a NOP.
00086 */
00087     maxseq_ = max(maxseq_, highest_ack_);
00088     if (t_seqno_ < last_ack_ + 1)
00089         t_seqno_ = last_ack_ + 1;
00090     newtimer(pkt);
00091     if (rtt_active_ && tcph->seqno() >= rtt_seq_) { 
00092         rtt_active_ = 0;
00093         t_backoff_ = 1;
00094     }
00095     /* with timestamp option */
00096     double tao = Scheduler::instance().clock() - tcph->ts_echo();
00097     rtt_update(tao);
00098     if (ts_resetRTO_) {
00099         // From Andrei Gurtov
00100         // FACK has not been updated to make sure the ECN works
00101         //   correctly in this case - Sally.
00102         t_backoff_ = 1;
00103     }
00104     /* update average window */
00105     awnd_ *= 1.0 - wnd_th_;
00106     awnd_ += wnd_th_ * cwnd_;
00107     /* if the connection is done, call finish() */
00108     if ((highest_ack_ >= curseq_-1) && !closed_) {
00109         closed_ = 1;
00110         finish();
00111     }
00112 }
00113 
00114 
00115 int FackTcpAgent::maxsack(Packet *pkt)
00116 {
00117     hdr_tcp *tcph = hdr_tcp::access(pkt);
00118     int maxsack=-1, sack_index; 
00119 
00120     for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) {
00121         if (tcph->sa_right(sack_index) > maxsack)
00122             maxsack = tcph->sa_right(sack_index);
00123     }
00124     return (maxsack-1);
00125 }
00126 
00127 
00128 void FackTcpAgent::recv_newack_helper(Packet *pkt) {
00129     newack(pkt);
00130     opencwnd();
00131     /* if the connection is done, call finish() */
00132     if ((highest_ack_ >= curseq_-1) && !closed_) {
00133         closed_ = 1;
00134         finish();
00135     }
00136 }
00137 
00138 void FackTcpAgent::recv(Packet *pkt, Handler*)
00139 {
00140     hdr_tcp *tcph = hdr_tcp::access(pkt);
00141     int ms; 
00142 
00143 #ifdef notdef
00144     if (pkt->type_ != PT_ACK) {
00145         Tcl::instance().evalf("%s error \"received non-ack\"",
00146                       name());
00147         Packet::free(pkt);
00148         return;
00149     }
00150 #endif
00151 
00152     ts_peer_ = tcph->ts();
00153     if (hdr_flags::access(pkt)->ecnecho() && ecn_)
00154         ecn(tcph->seqno());
00155     recv_helper(pkt);
00156 
00157     if (!fastrecov_) {  // Not in fast recovery 
00158         if ((int)tcph->seqno() > last_ack_ && tcph->sa_length() == 0) {
00159             /*
00160              * regular ACK not in fast recovery... normal
00161              */
00162             recv_newack_helper(pkt);
00163             fack_ = last_ack_;
00164             timeout_ = FALSE;
00165             scb_->ClearScoreBoard();
00166             retran_data_ = 0;
00167             wintrim_ = 0;
00168         } else if ((int)tcph->seqno() < last_ack_) {
00169             // Do nothing; ack may have been misordered
00170 
00171         } else {
00172             retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph);
00173             oldack(pkt);
00174             ms = maxsack(pkt);
00175             if (ms > fack_)
00176                 fack_ = ms;
00177             if (fack_ >= t_seqno_)
00178                 t_seqno_ = fack_ + 1;
00179             dupacks_ = (fack_ - last_ack_) - 1;
00180             /* 
00181              * a duplicate ACK
00182              */
00183             if (dupacks_ >= numdupacks_) {
00184                 /*
00185                  * Assume we dropped just one packet.
00186                  * Retransmit last ack + 1
00187                  * and try to resume the sequence.
00188                  */
00189                 recover_ = t_seqno_;
00190                 last_cwnd_action_ = CWND_ACTION_DUPACK;
00191                 if ((ss_div4_ == 1) && (cwnd_ <= ssthresh_ + .5)) {
00192                     cwnd_ /= 2;
00193                     wintrimmult_ = .75;
00194                 } else {
00195                     wintrimmult_ = .5;
00196                 }
00197                 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
00198 
00199                 if (rampdown_) {
00200                     wintrim_ = (t_seqno_ - fack_ - 1) * wintrimmult_;
00201                 }
00202                 reset_rtx_timer(1,0);
00203                 fastrecov_ = TRUE;
00204                 scb_->MarkRetran (last_ack_+1, t_seqno_);
00205                 retran_data_++;
00206                 output(last_ack_ + 1, TCP_REASON_DUPACK);
00207             }
00208         }
00209         if (dupacks_ == 0)
00210             send_much(FALSE, 0, maxburst_);
00211     } else {
00212         // we are in fast recovery
00213         oldack(pkt);
00214         ms = maxsack(pkt);
00215         if (ms > fack_) {
00216             if (rampdown_) {
00217                 wintrim_ -= ((float)ms - (float)fack_)* wintrimmult_;
00218                 if (wintrim_< 0) 
00219                     wintrim_ = 0;
00220             }
00221             fack_ = ms;
00222         }       
00223         
00224         if (fack_ >= t_seqno_)
00225             t_seqno_ = fack_ + 1;
00226 
00227         retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph);
00228     
00229         // If the retransmission was lost again, timeout_ forced to TRUE
00230         // if timeout_ TRUE, this shuts off send()
00231         timeout_ |= scb_->CheckSndNxt (tcph);
00232         
00233         opencwnd();
00234 
00235         if (retran_data_ < 0) {
00236             printf("Error, retran_data_ < 0");
00237         }
00238                 
00239         if ((int)tcph->sa_length() == 0 && (last_ack_ >= recover_)) {
00240             // No SACK blocks indicates fast recovery is over
00241             fastrecov_ = FALSE;
00242             timeout_ = FALSE;
00243             scb_->ClearScoreBoard();
00244             retran_data_ = 0;
00245             wintrim_ = 0;
00246             dupacks_ = 0;
00247         }
00248         send_much(FALSE, 0, maxburst_);
00249     }
00250 
00251     Packet::free(pkt);
00252 #ifdef notyet
00253     if (trace_)
00254         plot();
00255 #endif
00256 }
00257 
00258 void FackTcpAgent::timeout(int tno)
00259 {
00260     if (tno == TCP_TIMER_RTX) {
00261         if (highest_ack_ == maxseq_ && !slow_start_restart_) {
00262             /*
00263              * TCP option:
00264              * If no outstanding data, then don't do anything.
00265              */
00266             return;
00267         };
00268         // Do not clear fastrecov_ or alter recover_ variable
00269         timeout_ = FALSE;
00270         if (highest_ack_ > last_ack_)
00271             last_ack_ = highest_ack_;
00272 #ifdef DEBUGSACK1A
00273         printf ("timeout. highest_ack: %d seqno: %d\n", 
00274             highest_ack_, t_seqno_);
00275 #endif
00276         retran_data_ = 0;
00277         last_cwnd_action_ = CWND_ACTION_TIMEOUT;
00278         /* if there is no outstanding data, don't cut down ssthresh_ */
00279         if (highest_ack_ == maxseq_ && restart_bugfix_) 
00280             slowdown(CLOSE_CWND_INIT);
00281         else {
00282             // close down to 1 segment
00283             slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
00284         }
00285         scb_->ClearScoreBoard();
00286         /* if there is no outstanding data, don't back off rtx timer */
00287         if (highest_ack_ == maxseq_)
00288             reset_rtx_timer(TCP_REASON_TIMEOUT,0);
00289         else
00290             reset_rtx_timer(TCP_REASON_TIMEOUT,1);
00291         fack_ = last_ack_;
00292         t_seqno_ = last_ack_ + 1;
00293         send_much(0, TCP_REASON_TIMEOUT);
00294     } else {
00295         TcpAgent::timeout(tno);
00296     }
00297 }
00298 
00299 
00300 void FackTcpAgent::send_much(int force, int reason, int maxburst)
00301 {
00302     register int found, npacket = 0;
00303     send_idle_helper();
00304     int win = window();
00305     int xmit_seqno;
00306 
00307     if (!force && delsnd_timer_.status() == TIMER_PENDING)
00308         return;
00309     /* 
00310      * If TCP_TIMER_BURSTSND is pending, cancel it. The timer is
00311      * set again, if necessary, after the maxburst pakts have been
00312      * sent out.
00313 */
00314     if (burstsnd_timer_.status() == TIMER_PENDING)
00315         burstsnd_timer_.cancel();
00316     found = 1;
00317     /*
00318 * as long as the pipe is open and there is app data to send...
00319 */
00320     while (( t_seqno_ <= fack_ + win - retran_data_) && (!timeout_)) {
00321         if (overhead_ == 0 || force) {
00322             found = 0;
00323             xmit_seqno = scb_->GetNextRetran ();
00324 #ifdef DEBUGSACK1A
00325             printf("highest_ack: %d xmit_seqno: %d timeout: %d seqno: %d fack: % d win: %d retran_data: %d\n",
00326                    highest_ack_, xmit_seqno, timeout_, t_seqno_, fack_, win, retran_data_);
00327 #endif
00328 
00329             if (xmit_seqno == -1) {  // no retransmissions to send
00330                 /* 
00331                  * if there is no more application data to send,
00332                  * do nothing
00333                  */
00334                 if (t_seqno_ >= curseq_) 
00335                     return;
00336                 found = 1;
00337                 xmit_seqno = t_seqno_++;
00338 #ifdef DEBUGSACK1A
00339                 printf("sending %d fastrecovery: %d win %d\n",
00340                        xmit_seqno, fastrecov_, win);
00341 #endif
00342             } else {
00343                 found = 1;
00344                 scb_->MarkRetran (xmit_seqno, t_seqno_);
00345                 retran_data_++;
00346                 win = window();
00347             }
00348             if (found) {
00349                 output(xmit_seqno, reason);
00350                 if (t_seqno_ <= xmit_seqno) {
00351                     printf("Hit a strange case 2.\n");
00352                     t_seqno_ = xmit_seqno + 1;
00353                 }
00354                 npacket++;
00355             }
00356         } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
00357             /*
00358              * Set a delayed send timeout.
00359              */
00360             delsnd_timer_.resched(Random::uniform(overhead_));
00361             return;
00362         }
00363         if (maxburst && npacket == maxburst)
00364             break;
00365     } /* while */
00366     /* call helper function */
00367     send_helper(maxburst);
00368 }
00369 
00370 /*
00371  * open up the congestion window -- Hack hack hack
00372  */
00373 void FackTcpAgent::opencwnd()
00374 {
00375     TcpAgent::opencwnd();
00376 
00377     // if maxcwnd_ is set (nonzero), make it the cwnd limit
00378     if (maxcwnd_ && (int (cwnd_) > maxcwnd_))
00379         cwnd_ = maxcwnd_;
00380 }
00381 
00382 
00383 void FackTcpAgent::plot()
00384 {
00385 #ifdef notyet
00386     double t = Scheduler::instance().clock();
00387     sprintf(trace_->buffer(), "t %g %d rtt %g\n", 
00388         t, class_, t_rtt_ * tcp_tick_);
00389     trace_->dump();
00390     sprintf(trace_->buffer(), "t %g %d dev %g\n", 
00391         t, class_, t_rttvar_ * tcp_tick_);
00392     trace_->dump();
00393     sprintf(trace_->buffer(), "t %g %d win %f\n", t, class_, cwnd_);
00394     trace_->dump();
00395     sprintf(trace_->buffer(), "t %g %d bck %d\n", t, class_, t_backoff_);
00396     trace_->dump();
00397 #endif
00398 }

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