Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

tcp-reno.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     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-reno.cc,v 1.38 2003/01/27 02:34:38 sfloyd Exp $ (LBL)";
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 
00033 
00034 static class RenoTcpClass : public TclClass {
00035 public:
00036         RenoTcpClass() : TclClass("Agent/TCP/Reno") {}
00037         TclObject* create(int, const char*const*) {
00038                 return (new RenoTcpAgent());
00039         }
00040 } class_reno;
00041 
00042 int RenoTcpAgent::window()
00043 {
00044         //
00045         // reno: inflate the window by dupwnd_
00046         //      dupwnd_ will be non-zero during fast recovery,
00047         //      at which time it contains the number of dup acks
00048         //
00049         int win = int(cwnd_) + dupwnd_;
00050         if (win > int(wnd_))
00051                 win = int(wnd_);
00052         return (win);
00053 }
00054 
00055 double RenoTcpAgent::windowd()
00056 {
00057         //
00058         // reno: inflate the window by dupwnd_
00059         //      dupwnd_ will be non-zero during fast recovery,
00060         //      at which time it contains the number of dup acks
00061         //
00062         double win = cwnd_ + dupwnd_;
00063         if (win > wnd_)
00064                 win = wnd_;
00065         return (win);
00066 }
00067 
00068 RenoTcpAgent::RenoTcpAgent() : TcpAgent(), dupwnd_(0)
00069 {
00070 }
00071 
00072 void RenoTcpAgent::recv(Packet *pkt, Handler*)
00073 {
00074         hdr_tcp *tcph = hdr_tcp::access(pkt);
00075         if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
00076                 endQuickStart();
00077         if (qs_requested_ == 1)
00078                 processQuickStart(pkt);
00079 #ifdef notdef
00080         if (pkt->type_ != PT_ACK) {
00081                 fprintf(stderr,
00082                         "ns: confiuration error: tcp received non-ack\n");
00083                 exit(1);
00084         }
00085 #endif
00086         /* W.N.: check if this is from a previous incarnation */
00087         if (tcph->ts() < lastreset_) {
00088                 // Remove packet and do nothing
00089                 Packet::free(pkt);
00090                 return;
00091         }
00092         ++nackpack_;
00093         ts_peer_ = tcph->ts();
00094 
00095         if (hdr_flags::access(pkt)->ecnecho() && ecn_)
00096                 ecn(tcph->seqno());
00097         recv_helper(pkt);
00098         if (tcph->seqno() > last_ack_) {
00099                 dupwnd_ = 0;
00100                 recv_newack_helper(pkt);
00101                 if (last_ack_ == 0 && delay_growth_) {
00102                         cwnd_ = initial_window();
00103                 }
00104         } else if (tcph->seqno() == last_ack_) {
00105                 if (hdr_flags::access(pkt)->eln_ && eln_) {
00106                         tcp_eln(pkt);
00107                         return;
00108                 }
00109                 if (++dupacks_ == numdupacks_) {
00110                         dupack_action();
00111                         dupwnd_ = numdupacks_;
00112                 } else if (dupacks_ > numdupacks_) {
00113                         ++dupwnd_;      // fast recovery
00114                 } else if (dupacks_ < numdupacks_ && singledup_ ) {
00115                         send_one();
00116                 }
00117         }
00118         Packet::free(pkt);
00119 #ifdef notyet
00120         if (trace_)
00121                 plot();
00122 #endif
00123 
00124         /*
00125          * Try to send more data
00126          */
00127 
00128         if (dupacks_ == 0 || dupacks_ > numdupacks_ - 1)
00129                 send_much(0, 0, maxburst_);
00130 }
00131 
00132 int
00133 RenoTcpAgent::allow_fast_retransmit(int last_cwnd_action_)
00134 {
00135         return (last_cwnd_action_ == CWND_ACTION_DUPACK);
00136 }
00137 
00138 /*
00139  * Dupack-action: what to do on a DUP ACK.  After the initial check
00140  * of 'recover' below, this function implements the following truth
00141  * table:
00142  *  
00143  *      bugfix  ecn     last-cwnd == ecn        action  
00144  *  
00145  *      0       0       0                       reno_action
00146  *      0       0       1                       reno_action    [impossible]
00147  *      0       1       0                       reno_action
00148  *      0       1       1                       retransmit, return  
00149  *      1       0       0                       nothing 
00150  *      1       0       1                       nothing        [impossible]
00151  *      1       1       0                       nothing 
00152  *      1       1       1                       retransmit, return
00153  */ 
00154     
00155 void
00156 RenoTcpAgent::dupack_action()
00157 {
00158         int recovered = (highest_ack_ > recover_);
00159         int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_);
00160         if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) {
00161                 goto reno_action;
00162         }
00163 
00164         if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
00165                 last_cwnd_action_ = CWND_ACTION_DUPACK;
00166                 /* 
00167                  * What if there is a DUPACK action followed closely by ECN
00168                  * followed closely by a DUPACK action?
00169                  * The optimal thing to do would be to remember all
00170                  * congestion actions from the most recent window
00171                  * of data.  Otherwise "bugfix" might not prevent
00172                  * all unnecessary Fast Retransmits.
00173                  */
00174                 reset_rtx_timer(1,0);
00175                 output(last_ack_ + 1, TCP_REASON_DUPACK);
00176                 return; 
00177         }
00178 
00179         if (bug_fix_) {
00180                 /*
00181                  * The line below, for "bug_fix_" true, avoids
00182                  * problems with multiple fast retransmits in one
00183                  * window of data.
00184                  */
00185                 return;
00186         }
00187 
00188 reno_action:
00189         // we are now going to fast-retransmit and will trace that event
00190         trace_event("RENO_FAST_RETX");
00191         recover_ = maxseq_;
00192         last_cwnd_action_ = CWND_ACTION_DUPACK;
00193         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
00194         reset_rtx_timer(1,0);
00195         output(last_ack_ + 1, TCP_REASON_DUPACK);       // from top
00196         return;
00197 }
00198 
00199 void RenoTcpAgent::timeout(int tno)
00200 {
00201         if (tno == TCP_TIMER_RTX) {
00202                 dupwnd_ = 0;
00203                 dupacks_ = 0;
00204                 if (bug_fix_) recover_ = maxseq_;
00205                 TcpAgent::timeout(tno);
00206         } else {
00207                 timeout_nonrtx(tno);
00208         }
00209 }

Generated on Tue Apr 20 12:14:35 2004 for NS2.26SourcesOriginal by doxygen 1.3.3