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.42 2005/07/13 03:51:32 tomh 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 (frto_ == 2) {
00051         // First ack after RTO has arrived.
00052         // Open window to allow two new segments out with F-RTO.
00053         win = force_wnd(2);
00054     }
00055     if (win > int(wnd_))
00056         win = int(wnd_);
00057     return (win);
00058 }
00059 
00060 double RenoTcpAgent::windowd()
00061 {
00062     //
00063     // reno: inflate the window by dupwnd_
00064     //  dupwnd_ will be non-zero during fast recovery,
00065     //  at which time it contains the number of dup acks
00066     //
00067     double win = cwnd_ + dupwnd_;
00068     if (win > wnd_)
00069         win = wnd_;
00070     return (win);
00071 }
00072 
00073 RenoTcpAgent::RenoTcpAgent() : TcpAgent(), dupwnd_(0)
00074 {
00075 }
00076 
00077 void RenoTcpAgent::recv(Packet *pkt, Handler*)
00078 {
00079     hdr_tcp *tcph = hdr_tcp::access(pkt);
00080     int valid_ack = 0;
00081         if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
00082         endQuickStart();
00083         if (qs_requested_ == 1)
00084                 processQuickStart(pkt);
00085 #ifdef notdef
00086     if (pkt->type_ != PT_ACK) {
00087         fprintf(stderr,
00088             "ns: confiuration error: tcp received non-ack\n");
00089         exit(1);
00090     }
00091 #endif
00092         /* W.N.: check if this is from a previous incarnation */
00093         if (tcph->ts() < lastreset_) {
00094                 // Remove packet and do nothing
00095                 Packet::free(pkt);
00096                 return;
00097         }
00098     ++nackpack_;
00099     ts_peer_ = tcph->ts();
00100 
00101     if (hdr_flags::access(pkt)->ecnecho() && ecn_)
00102         ecn(tcph->seqno());
00103     recv_helper(pkt);
00104     recv_frto_helper(pkt);
00105     if (tcph->seqno() > last_ack_) {
00106         if (last_cwnd_action_ == CWND_ACTION_DUPACK)
00107             last_cwnd_action_ = CWND_ACTION_EXITED;
00108         dupwnd_ = 0;
00109         recv_newack_helper(pkt);
00110         if (last_ack_ == 0 && delay_growth_) {
00111             cwnd_ = initial_window();
00112         }
00113     } else if (tcph->seqno() == last_ack_) {
00114         if (hdr_flags::access(pkt)->eln_ && eln_) {
00115             tcp_eln(pkt);
00116             return;
00117         }
00118         if (++dupacks_ == numdupacks_) {
00119             dupack_action();
00120             if (!exitFastRetrans_)
00121                 dupwnd_ = numdupacks_;
00122         } else if (dupacks_ > numdupacks_ && (!exitFastRetrans_ 
00123              || last_cwnd_action_ == CWND_ACTION_DUPACK )) {
00124             ++dupwnd_;  // fast recovery
00125         } else if (dupacks_ < numdupacks_ && singledup_ ) {
00126             send_one();
00127         }
00128     }
00129         if (tcph->seqno() >= last_ack_)
00130                 // Check if ACK is valid.  Suggestion by Mark Allman.
00131                 valid_ack = 1;
00132     Packet::free(pkt);
00133 #ifdef notyet
00134     if (trace_)
00135         plot();
00136 #endif
00137 
00138     /*
00139      * Try to send more data
00140      */
00141 
00142         if (valid_ack || aggressive_maxburst_)
00143         if (dupacks_ == 0 || dupacks_ > numdupacks_ - 1)
00144             send_much(0, 0, maxburst_);
00145 }
00146 
00147 int
00148 RenoTcpAgent::allow_fast_retransmit(int last_cwnd_action_)
00149 {
00150     return (last_cwnd_action_ == CWND_ACTION_DUPACK);
00151 }
00152 
00153 /*
00154  * Dupack-action: what to do on a DUP ACK.  After the initial check
00155  * of 'recover' below, this function implements the following truth
00156  * table:
00157  *  
00158  *      bugfix  ecn     last-cwnd == ecn        action  
00159  *  
00160  *      0       0       0                       reno_action
00161  *      0       0       1                       reno_action    [impossible]
00162  *      0       1       0                       reno_action
00163  *      0       1       1                       retransmit, return  
00164  *      1       0       0                       nothing 
00165  *      1       0       1                       nothing        [impossible]
00166  *      1       1       0                       nothing 
00167  *      1       1       1                       retransmit, return
00168  */ 
00169     
00170 void
00171 RenoTcpAgent::dupack_action()
00172 {
00173     int recovered = (highest_ack_ > recover_);
00174     int allowFastRetransmit = allow_fast_retransmit(last_cwnd_action_);
00175         if (recovered || (!bug_fix_ && !ecn_) || allowFastRetransmit) {
00176         goto reno_action;
00177     }
00178 
00179     if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
00180         last_cwnd_action_ = CWND_ACTION_DUPACK;
00181         /* 
00182          * What if there is a DUPACK action followed closely by ECN
00183          * followed closely by a DUPACK action?
00184          * The optimal thing to do would be to remember all
00185          * congestion actions from the most recent window
00186          * of data.  Otherwise "bugfix" might not prevent
00187          * all unnecessary Fast Retransmits.
00188          */
00189         reset_rtx_timer(1,0);
00190         output(last_ack_ + 1, TCP_REASON_DUPACK);
00191         dupwnd_ = numdupacks_;
00192         return; 
00193     }
00194 
00195     if (bug_fix_) {
00196         /*
00197          * The line below, for "bug_fix_" true, avoids
00198          * problems with multiple fast retransmits in one
00199          * window of data.
00200          */
00201         return;
00202     }
00203 
00204 reno_action:
00205     // we are now going to fast-retransmit and will trace that event
00206     trace_event("RENO_FAST_RETX");
00207     recover_ = maxseq_;
00208     last_cwnd_action_ = CWND_ACTION_DUPACK;
00209     slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
00210     reset_rtx_timer(1,0);
00211     output(last_ack_ + 1, TCP_REASON_DUPACK);   // from top
00212         dupwnd_ = numdupacks_;
00213     return;
00214 }
00215 
00216 void RenoTcpAgent::timeout(int tno)
00217 {
00218     if (tno == TCP_TIMER_RTX) {
00219         dupwnd_ = 0;
00220         dupacks_ = 0;
00221         if (bug_fix_) recover_ = maxseq_;
00222         TcpAgent::timeout(tno);
00223     } else {
00224         timeout_nonrtx(tno);
00225     }
00226 }

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