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

tcp.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) 1991-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 Computer Systems
00017  *      Engineering Group at Lawrence Berkeley 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 #ifndef lint
00036 static const char rcsid[] =
00037     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp.cc,v 1.144 2003/02/12 04:16:09 sfloyd Exp $ (LBL)";
00038 #endif
00039 
00040 #include <stdlib.h>
00041 #include <math.h>
00042 #include <sys/types.h>
00043 #include "ip.h"
00044 #include "tcp.h"
00045 #include "flags.h"
00046 #include "random.h"
00047 #include "basetrace.h"
00048 #include "hdr_qs.h"
00049 
00050 int hdr_tcp::offset_;
00051 
00052 static class TCPHeaderClass : public PacketHeaderClass {
00053 public:
00054         TCPHeaderClass() : PacketHeaderClass("PacketHeader/TCP",
00055                                              sizeof(hdr_tcp)) {
00056                 bind_offset(&hdr_tcp::offset_);
00057         }
00058 } class_tcphdr;
00059 
00060 static class TcpClass : public TclClass {
00061 public:
00062         TcpClass() : TclClass("Agent/TCP") {}
00063         TclObject* create(int , const char*const*) {
00064                 return (new TcpAgent());
00065         }
00066 } class_tcp;
00067 
00068 TcpAgent::TcpAgent() : Agent(PT_TCP), 
00069         t_seqno_(0), t_rtt_(0), t_srtt_(0), t_rttvar_(0), 
00070         t_backoff_(0), ts_peer_(0), 
00071         rtx_timer_(this), delsnd_timer_(this), 
00072         burstsnd_timer_(this), 
00073         dupacks_(0), curseq_(0), highest_ack_(0), cwnd_(0), ssthresh_(0), 
00074         count_(0), fcnt_(0), rtt_active_(0), rtt_seq_(-1), rtt_ts_(0.0), 
00075         maxseq_(0), cong_action_(0), ecn_burst_(0), ecn_backoff_(0),
00076         ect_(0), lastreset_(0.0),
00077         restart_bugfix_(1), closed_(0), nrexmit_(0),
00078         first_decrease_(1), qs_requested_(0), qs_approved_(0)
00079 {
00080 #ifdef TCP_DELAY_BIND_ALL
00081 #else /* ! TCP_DELAY_BIND_ALL */
00082         // not delay-bound because delay-bound tracevars aren't yet supported
00083         bind("t_seqno_", &t_seqno_);
00084         bind("rtt_", &t_rtt_);
00085         bind("srtt_", &t_srtt_);
00086         bind("rttvar_", &t_rttvar_);
00087         bind("backoff_", &t_backoff_);
00088         bind("dupacks_", &dupacks_);
00089         bind("seqno_", &curseq_);
00090         bind("ack_", &highest_ack_);
00091         bind("cwnd_", &cwnd_);
00092         bind("ssthresh_", &ssthresh_);
00093         bind("maxseq_", &maxseq_);
00094         bind("ndatapack_", &ndatapack_);
00095         bind("ndatabytes_", &ndatabytes_);
00096         bind("nackpack_", &nackpack_);
00097         bind("nrexmit_", &nrexmit_);
00098         bind("nrexmitpack_", &nrexmitpack_);
00099         bind("nrexmitbytes_", &nrexmitbytes_);
00100         bind("necnresponses_", &necnresponses_);
00101         bind("ncwndcuts_", &ncwndcuts_);
00102 #endif /* TCP_DELAY_BIND_ALL */
00103 
00104 }
00105 
00106 void
00107 TcpAgent::delay_bind_init_all()
00108 {
00109 
00110         // Defaults for bound variables should be set in ns-default.tcl.
00111         delay_bind_init_one("window_");
00112         delay_bind_init_one("windowInit_");
00113         delay_bind_init_one("windowInitOption_");
00114 
00115         delay_bind_init_one("syn_");
00116         delay_bind_init_one("windowOption_");
00117         delay_bind_init_one("windowConstant_");
00118         delay_bind_init_one("windowThresh_");
00119         delay_bind_init_one("delay_growth_");
00120         delay_bind_init_one("overhead_");
00121         delay_bind_init_one("tcpTick_");
00122         delay_bind_init_one("ecn_");
00123         delay_bind_init_one("old_ecn_");
00124         delay_bind_init_one("eln_");
00125         delay_bind_init_one("eln_rxmit_thresh_");
00126         delay_bind_init_one("packetSize_");
00127         delay_bind_init_one("tcpip_base_hdr_size_");
00128         delay_bind_init_one("ts_option_size_");
00129         delay_bind_init_one("bugFix_");
00130         delay_bind_init_one("lessCareful_");
00131         delay_bind_init_one("slow_start_restart_");
00132         delay_bind_init_one("restart_bugfix_");
00133         delay_bind_init_one("timestamps_");
00134         delay_bind_init_one("maxburst_");
00135         delay_bind_init_one("maxcwnd_");
00136         delay_bind_init_one("numdupacks_");
00137         delay_bind_init_one("numdupacksFrac_");
00138         delay_bind_init_one("maxrto_");
00139         delay_bind_init_one("minrto_");
00140         delay_bind_init_one("srtt_init_");
00141         delay_bind_init_one("rttvar_init_");
00142         delay_bind_init_one("rtxcur_init_");
00143         delay_bind_init_one("T_SRTT_BITS");
00144         delay_bind_init_one("T_RTTVAR_BITS");
00145         delay_bind_init_one("rttvar_exp_");
00146         delay_bind_init_one("awnd_");
00147         delay_bind_init_one("decrease_num_");
00148         delay_bind_init_one("increase_num_");
00149         delay_bind_init_one("k_parameter_");
00150         delay_bind_init_one("l_parameter_");
00151         delay_bind_init_one("trace_all_oneline_");
00152         delay_bind_init_one("nam_tracevar_");
00153 
00154         delay_bind_init_one("QOption_");
00155         delay_bind_init_one("EnblRTTCtr_");
00156         delay_bind_init_one("control_increase_");
00157         delay_bind_init_one("noFastRetrans_");
00158         delay_bind_init_one("precisionReduce_");
00159         delay_bind_init_one("oldCode_");
00160         delay_bind_init_one("useHeaders_");
00161         delay_bind_init_one("low_window_");
00162         delay_bind_init_one("high_window_");
00163         delay_bind_init_one("high_p_");
00164         delay_bind_init_one("high_decrease_");
00165         delay_bind_init_one("max_ssthresh_");
00166         delay_bind_init_one("cwnd_frac_");
00167         delay_bind_init_one("timerfix_");
00168         delay_bind_init_one("rfc2988_");
00169         delay_bind_init_one("singledup_");
00170         delay_bind_init_one("rate_request_");
00171         delay_bind_init_one("qs_enabled_");
00172 
00173 #ifdef TCP_DELAY_BIND_ALL
00174         // out because delay-bound tracevars aren't yet supported
00175         delay_bind_init_one("t_seqno_");
00176         delay_bind_init_one("rtt_");
00177         delay_bind_init_one("srtt_");
00178         delay_bind_init_one("rttvar_");
00179         delay_bind_init_one("backoff_");
00180         delay_bind_init_one("dupacks_");
00181         delay_bind_init_one("seqno_");
00182         delay_bind_init_one("ack_");
00183         delay_bind_init_one("cwnd_");
00184         delay_bind_init_one("ssthresh_");
00185         delay_bind_init_one("maxseq_");
00186         delay_bind_init_one("ndatapack_");
00187         delay_bind_init_one("ndatabytes_");
00188         delay_bind_init_one("nackpack_");
00189         delay_bind_init_one("nrexmit_");
00190         delay_bind_init_one("nrexmitpack_");
00191         delay_bind_init_one("nrexmitbytes_");
00192         delay_bind_init_one("necnresponses_");
00193         delay_bind_init_one("ncwndcuts_");
00194 #endif /* TCP_DELAY_BIND_ALL */
00195 
00196         Agent::delay_bind_init_all();
00197 
00198         reset();
00199 }
00200 
00201 int
00202 TcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
00203 {
00204         if (delay_bind(varName, localName, "window_", &wnd_, tracer)) return TCL_OK;
00205         if (delay_bind(varName, localName, "windowInit_", &wnd_init_, tracer)) return TCL_OK;
00206         if (delay_bind(varName, localName, "windowInitOption_", &wnd_init_option_, tracer)) return TCL_OK;
00207         if (delay_bind_bool(varName, localName, "syn_", &syn_, tracer)) return TCL_OK;
00208         if (delay_bind(varName, localName, "windowOption_", &wnd_option_ , tracer)) return TCL_OK;
00209         if (delay_bind(varName, localName, "windowConstant_",  &wnd_const_, tracer)) return TCL_OK;
00210         if (delay_bind(varName, localName, "windowThresh_", &wnd_th_ , tracer)) return TCL_OK;
00211         if (delay_bind_bool(varName, localName, "delay_growth_", &delay_growth_ , tracer)) return TCL_OK;
00212         if (delay_bind(varName, localName, "overhead_", &overhead_, tracer)) return TCL_OK;
00213         if (delay_bind(varName, localName, "tcpTick_", &tcp_tick_, tracer)) return TCL_OK;
00214         if (delay_bind_bool(varName, localName, "ecn_", &ecn_, tracer)) return TCL_OK;
00215         if (delay_bind_bool(varName, localName, "old_ecn_", &old_ecn_ , tracer)) return TCL_OK;
00216         if (delay_bind(varName, localName, "eln_", &eln_ , tracer)) return TCL_OK;
00217         if (delay_bind(varName, localName, "eln_rxmit_thresh_", &eln_rxmit_thresh_ , tracer)) return TCL_OK;
00218         if (delay_bind(varName, localName, "packetSize_", &size_ , tracer)) return TCL_OK;
00219         if (delay_bind(varName, localName, "tcpip_base_hdr_size_", &tcpip_base_hdr_size_, tracer)) return TCL_OK;
00220         if (delay_bind(varName, localName, "ts_option_size_", &ts_option_size_, tracer)) return TCL_OK;
00221         if (delay_bind_bool(varName, localName, "bugFix_", &bug_fix_ , tracer)) return TCL_OK;
00222         if (delay_bind_bool(varName, localName, "lessCareful_", &less_careful_ , tracer)) return TCL_OK;
00223         if (delay_bind_bool(varName, localName, "timestamps_", &ts_option_ , tracer)) return TCL_OK;
00224         if (delay_bind_bool(varName, localName, "slow_start_restart_", &slow_start_restart_ , tracer)) return TCL_OK;
00225         if (delay_bind_bool(varName, localName, "restart_bugfix_", &restart_bugfix_ , tracer)) return TCL_OK;
00226         if (delay_bind(varName, localName, "maxburst_", &maxburst_ , tracer)) return TCL_OK;
00227         if (delay_bind(varName, localName, "maxcwnd_", &maxcwnd_ , tracer)) return TCL_OK;
00228         if (delay_bind(varName, localName, "numdupacks_", &numdupacks_, tracer)) return TCL_OK;
00229         if (delay_bind(varName, localName, "numdupacksFrac_", &numdupacksFrac_, tracer)) return TCL_OK;
00230         if (delay_bind(varName, localName, "maxrto_", &maxrto_ , tracer)) return TCL_OK;
00231         if (delay_bind(varName, localName, "minrto_", &minrto_ , tracer)) return TCL_OK;
00232         if (delay_bind(varName, localName, "srtt_init_", &srtt_init_ , tracer)) return TCL_OK;
00233         if (delay_bind(varName, localName, "rttvar_init_", &rttvar_init_ , tracer)) return TCL_OK;
00234         if (delay_bind(varName, localName, "rtxcur_init_", &rtxcur_init_ , tracer)) return TCL_OK;
00235         if (delay_bind(varName, localName, "T_SRTT_BITS", &T_SRTT_BITS , tracer)) return TCL_OK;
00236         if (delay_bind(varName, localName, "T_RTTVAR_BITS", &T_RTTVAR_BITS , tracer)) return TCL_OK;
00237         if (delay_bind(varName, localName, "rttvar_exp_", &rttvar_exp_ , tracer)) return TCL_OK;
00238         if (delay_bind(varName, localName, "awnd_", &awnd_ , tracer)) return TCL_OK;
00239         if (delay_bind(varName, localName, "decrease_num_", &decrease_num_, tracer)) return TCL_OK;
00240         if (delay_bind(varName, localName, "increase_num_", &increase_num_, tracer)) return TCL_OK;
00241         if (delay_bind(varName, localName, "k_parameter_", &k_parameter_, tracer)) return TCL_OK;
00242         if (delay_bind(varName, localName, "l_parameter_", &l_parameter_, tracer)) return TCL_OK;
00243 
00244 
00245         if (delay_bind_bool(varName, localName, "trace_all_oneline_", &trace_all_oneline_ , tracer)) return TCL_OK;
00246         if (delay_bind_bool(varName, localName, "nam_tracevar_", &nam_tracevar_ , tracer)) return TCL_OK;
00247         if (delay_bind(varName, localName, "QOption_", &QOption_ , tracer)) return TCL_OK;
00248         if (delay_bind(varName, localName, "EnblRTTCtr_", &EnblRTTCtr_ , tracer)) return TCL_OK;
00249         if (delay_bind(varName, localName, "control_increase_", &control_increase_ , tracer)) return TCL_OK;
00250         if (delay_bind_bool(varName, localName, "noFastRetrans_", &noFastRetrans_, tracer)) return TCL_OK;
00251         if (delay_bind_bool(varName, localName, "precisionReduce_", &precision_reduce_, tracer)) return TCL_OK;
00252         if (delay_bind_bool(varName, localName, "oldCode_", &oldCode_, tracer)) return TCL_OK;
00253         if (delay_bind_bool(varName, localName, "useHeaders_", &useHeaders_, tracer)) return TCL_OK;
00254         if (delay_bind(varName, localName, "low_window_", &low_window_, tracer)) return TCL_OK;
00255         if (delay_bind(varName, localName, "high_window_", &high_window_, tracer)) return TCL_OK;
00256         if (delay_bind(varName, localName, "high_p_", &high_p_, tracer)) return TCL_OK;
00257         if (delay_bind(varName, localName, "high_decrease_", &high_decrease_, tracer)) return TCL_OK;
00258         if (delay_bind(varName, localName, "max_ssthresh_", &max_ssthresh_, tracer)) return TCL_OK;
00259         if (delay_bind(varName, localName, "cwnd_frac_", &cwnd_frac_, tracer)) return TCL_OK;
00260         if (delay_bind_bool(varName, localName, "timerfix_", &timerfix_, tracer)) return TCL_OK;
00261         if (delay_bind_bool(varName, localName, "rfc2988_", &rfc2988_, tracer)) return TCL_OK;
00262         if (delay_bind(varName, localName, "singledup_", &singledup_ , tracer)) return TCL_OK;
00263         if (delay_bind(varName, localName, "rate_request_", &rate_request_ , tracer)) return TCL_OK;
00264         if (delay_bind_bool(varName, localName, "qs_enabled_", &qs_enabled_, tracer)) return TCL_OK;
00265 
00266 
00267 #ifdef TCP_DELAY_BIND_ALL
00268         // not if (delay-bound delay-bound tracevars aren't yet supported
00269         if (delay_bind(varName, localName, "t_seqno_", &t_seqno_ , tracer)) return TCL_OK;
00270         if (delay_bind(varName, localName, "rtt_", &t_rtt_ , tracer)) return TCL_OK;
00271         if (delay_bind(varName, localName, "srtt_", &t_srtt_ , tracer)) return TCL_OK;
00272         if (delay_bind(varName, localName, "rttvar_", &t_rttvar_ , tracer)) return TCL_OK;
00273         if (delay_bind(varName, localName, "backoff_", &t_backoff_ , tracer)) return TCL_OK;
00274 
00275         if (delay_bind(varName, localName, "dupacks_", &dupacks_ , tracer)) return TCL_OK;
00276         if (delay_bind(varName, localName, "seqno_", &curseq_ , tracer)) return TCL_OK;
00277         if (delay_bind(varName, localName, "ack_", &highest_ack_ , tracer)) return TCL_OK;
00278         if (delay_bind(varName, localName, "cwnd_", &cwnd_ , tracer)) return TCL_OK;
00279         if (delay_bind(varName, localName, "ssthresh_", &ssthresh_ , tracer)) return TCL_OK;
00280         if (delay_bind(varName, localName, "maxseq_", &maxseq_ , tracer)) return TCL_OK;
00281         if (delay_bind(varName, localName, "ndatapack_", &ndatapack_ , tracer)) return TCL_OK;
00282         if (delay_bind(varName, localName, "ndatabytes_", &ndatabytes_ , tracer)) return TCL_OK;
00283         if (delay_bind(varName, localName, "nackpack_", &nackpack_ , tracer)) return TCL_OK;
00284         if (delay_bind(varName, localName, "nrexmit_", &nrexmit_ , tracer)) return TCL_OK;
00285         if (delay_bind(varName, localName, "nrexmitpack_", &nrexmitpack_ , tracer)) return TCL_OK;
00286         if (delay_bind(varName, localName, "nrexmitbytes_", &nrexmitbytes_ , tracer)) return TCL_OK;
00287         if (delay_bind(varName, localName, "necnresponses_", &necnresponses_ , tracer)) return TCL_OK;
00288         if (delay_bind(varName, localName, "ncwndcuts_", &ncwndcuts_ , tracer)) return TCL_OK;
00289 #endif
00290 
00291         return Agent::delay_bind_dispatch(varName, localName, tracer);
00292 }
00293 
00294 /* Print out all the traced variables whenever any one is changed */
00295 void
00296 TcpAgent::traceAll() {
00297         double curtime;
00298         Scheduler& s = Scheduler::instance();
00299         char wrk[500];
00300         int n;
00301 
00302         curtime = &s ? s.clock() : 0;
00303         sprintf(wrk,"time: %-8.5f saddr: %-2d sport: %-2d daddr: %-2d dport:"
00304                 " %-2d maxseq: %-4d hiack: %-4d seqno: %-4d cwnd: %-6.3f"
00305                 " ssthresh: %-3d dupacks: %-2d rtt: %-6.3f srtt: %-6.3f"
00306                 " rttvar: %-6.3f bkoff: %-d", curtime, addr(), port(),
00307                 daddr(), dport(), int(maxseq_), int(highest_ack_),
00308                 int(t_seqno_), double(cwnd_), int(ssthresh_),
00309                 int(dupacks_), int(t_rtt_)*tcp_tick_, 
00310                 (int(t_srtt_) >> T_SRTT_BITS)*tcp_tick_, 
00311                 int(t_rttvar_)*tcp_tick_/4.0, int(t_backoff_)); 
00312         n = strlen(wrk);
00313         wrk[n] = '\n';
00314         wrk[n+1] = 0;
00315         if (channel_)
00316                 (void)Tcl_Write(channel_, wrk, n+1);
00317         wrk[n] = 0;
00318         return;
00319 }
00320 
00321 /* Print out just the variable that is modified */
00322 void
00323 TcpAgent::traceVar(TracedVar* v) 
00324 {
00325         double curtime;
00326         Scheduler& s = Scheduler::instance();
00327         char wrk[500];
00328         int n;
00329 
00330         curtime = &s ? s.clock() : 0;
00331         if (!strcmp(v->name(), "cwnd_") || !strcmp(v->name(), "maxrto_")) 
00332                 sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f",
00333                         curtime, addr(), port(), daddr(), dport(),
00334                         v->name(), double(*((TracedDouble*) v))); 
00335         else if (!strcmp(v->name(), "minrto_")) 
00336                 sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f",
00337                         curtime, addr(), port(), daddr(), dport(),
00338                         v->name(), double(*((TracedDouble*) v))); 
00339         else if (!strcmp(v->name(), "rtt_"))
00340                 sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f",
00341                         curtime, addr(), port(), daddr(), dport(),
00342                         v->name(), int(*((TracedInt*) v))*tcp_tick_); 
00343         else if (!strcmp(v->name(), "srtt_")) 
00344                 sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f",
00345                         curtime, addr(), port(), daddr(), dport(),
00346                         v->name(), 
00347                         (int(*((TracedInt*) v)) >> T_SRTT_BITS)*tcp_tick_); 
00348         else if (!strcmp(v->name(), "rttvar_"))
00349                 sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f",
00350                         curtime, addr(), port(), daddr(), dport(),
00351                         v->name(), 
00352                         int(*((TracedInt*) v))*tcp_tick_/4.0); 
00353         else
00354                 sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %d",
00355                         curtime, addr(), port(), daddr(), dport(),
00356                         v->name(), int(*((TracedInt*) v))); 
00357         n = strlen(wrk);
00358         wrk[n] = '\n';
00359         wrk[n+1] = 0;
00360         if (channel_)
00361                 (void)Tcl_Write(channel_, wrk, n+1);
00362         wrk[n] = 0;
00363         return;
00364 }
00365 
00366 void
00367 TcpAgent::trace(TracedVar* v) 
00368 {
00369         if (nam_tracevar_) {
00370                 Agent::trace(v);
00371         } else if (trace_all_oneline_)
00372                 traceAll();
00373         else 
00374                 traceVar(v);
00375 }
00376 
00377 //
00378 // in 1-way TCP, syn_ indicates we are modeling
00379 // a SYN exchange at the beginning.  If this is true
00380 // and we are delaying growth, then use an initial
00381 // window of one.  If not, we do whatever initial_window()
00382 // says to do.
00383 //
00384 
00385 void
00386 TcpAgent::set_initial_window()
00387 {
00388         if (syn_ && delay_growth_)
00389                 cwnd_ = 1.0; 
00390         else
00391                 cwnd_ = initial_window();
00392 }
00393 
00394 void
00395 TcpAgent::reset_qoption()
00396 {
00397         int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
00398 
00399         T_start = now ; 
00400         RTT_count = 0 ; 
00401         RTT_prev = 0 ; 
00402         RTT_goodcount = 1 ; 
00403         F_counting = 0 ; 
00404         W_timed = -1 ; 
00405         F_full = 0 ;
00406         Backoffs = 0 ; 
00407 }
00408 
00409 void
00410 TcpAgent::reset()
00411 {
00412         rtt_init();
00413         rtt_seq_ = -1;
00414         /*XXX lookup variables */
00415         dupacks_ = 0;
00416         curseq_ = 0;
00417         set_initial_window();
00418 
00419         t_seqno_ = 0;
00420         maxseq_ = -1;
00421         last_ack_ = -1;
00422         highest_ack_ = -1;
00423         ssthresh_ = int(wnd_);
00424         if (max_ssthresh_ > 0 && max_ssthresh_ < ssthresh_) 
00425                 ssthresh_ = max_ssthresh_;
00426         wnd_restart_ = 1.;
00427         awnd_ = wnd_init_ / 2.0;
00428         recover_ = 0;
00429         closed_ = 0;
00430         last_cwnd_action_ = 0;
00431         boot_time_ = Random::uniform(tcp_tick_);
00432         first_decrease_ = 1;
00433         /* W.N.: for removing packets from previous incarnations */
00434         lastreset_ = Scheduler::instance().clock();
00435 
00436         /* Now these variables will be reset 
00437            - Debojyoti Dutta 12th Oct'2000 */
00438  
00439         ndatapack_ = 0;
00440         ndatabytes_ = 0;
00441         nackpack_ = 0;
00442         nrexmitbytes_ = 0;
00443         nrexmit_ = 0;
00444         nrexmitpack_ = 0;
00445         necnresponses_ = 0;
00446         ncwndcuts_ = 0;
00447 
00448         cwnd_last_ = 0.0;
00449 
00450         if (control_increase_) {
00451                 prev_highest_ack_ = highest_ack_ ; 
00452         }
00453 
00454         if (QOption_) {
00455                 int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
00456                 T_last = now ; 
00457                 T_prev = now ; 
00458                 W_used = 0 ;
00459                 if (EnblRTTCtr_) {
00460                         reset_qoption();
00461                 }
00462         }
00463 }
00464 
00465 /*
00466  * Initialize variables for the retransmit timer.
00467  */
00468 void TcpAgent::rtt_init()
00469 {
00470         t_rtt_ = 0;
00471         t_srtt_ = int(srtt_init_ / tcp_tick_) << T_SRTT_BITS;
00472         t_rttvar_ = int(rttvar_init_ / tcp_tick_) << T_RTTVAR_BITS;
00473         t_rtxcur_ = rtxcur_init_;
00474         t_backoff_ = 1;
00475 }
00476 
00477 double TcpAgent::rtt_timeout()
00478 {
00479         double timeout;
00480         if (rfc2988_) {
00481         // Correction from Tom Kelly to be RFC2988-compliant, by
00482         // clamping minrto_ before applying t_backoff_.
00483                 if (t_rtxcur_ < minrto_)
00484                         timeout = minrto_ * t_backoff_;
00485                 else
00486                         timeout = t_rtxcur_ * t_backoff_;
00487         } else {
00488                 timeout = t_rtxcur_ * t_backoff_;
00489                 if (timeout < minrto_)
00490                         timeout = minrto_;
00491         }
00492 
00493         if (timeout > maxrto_)
00494                 timeout = maxrto_;
00495 
00496         if (timeout < 2.0 * tcp_tick_) {
00497                 if (timeout < 0) {
00498                         fprintf(stderr, "TcpAgent: negative RTO!  (%f)\n",
00499                                 timeout);
00500                         exit(1);
00501                 }
00502                 timeout = 2.0 * tcp_tick_;
00503         }
00504         return (timeout);
00505 }
00506 
00507 
00508 /* This has been modified to use the tahoe code. */
00509 void TcpAgent::rtt_update(double tao)
00510 {
00511         double now = Scheduler::instance().clock();
00512         if (ts_option_)
00513                 t_rtt_ = int(tao /tcp_tick_ + 0.5);
00514         else {
00515                 double sendtime = now - tao;
00516                 sendtime += boot_time_;
00517                 double tickoff = fmod(sendtime, tcp_tick_);
00518                 t_rtt_ = int((tao + tickoff) / tcp_tick_);
00519         }
00520         if (t_rtt_ < 1)
00521                 t_rtt_ = 1;
00522 
00523         //
00524         // srtt has 3 bits to the right of the binary point
00525         // rttvar has 2
00526         //
00527         if (t_srtt_ != 0) {
00528                 register short delta;
00529                 delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS);      // d = (m - a0)
00530                 if ((t_srtt_ += delta) <= 0)    // a1 = 7/8 a0 + 1/8 m
00531                         t_srtt_ = 1;
00532                 if (delta < 0)
00533                         delta = -delta;
00534                 delta -= (t_rttvar_ >> T_RTTVAR_BITS);
00535                 if ((t_rttvar_ += delta) <= 0)  // var1 = 3/4 var0 + 1/4 |d|
00536                         t_rttvar_ = 1;
00537         } else {
00538                 t_srtt_ = t_rtt_ << T_SRTT_BITS;                // srtt = rtt
00539                 t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1);        // rttvar = rtt / 2
00540         }
00541         //
00542         // Current retransmit value is 
00543         //    (unscaled) smoothed round trip estimate
00544         //    plus 2^rttvar_exp_ times (unscaled) rttvar. 
00545         //
00546         t_rtxcur_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS))) +
00547                 t_srtt_)  >> T_SRTT_BITS ) * tcp_tick_;
00548 
00549         return;
00550 }
00551 
00552 void TcpAgent::rtt_backoff()
00553 {
00554         if (t_backoff_ < 64)
00555                 t_backoff_ <<= 1;
00556 
00557         if (t_backoff_ > 8) {
00558                 /*
00559                  * If backed off this far, clobber the srtt
00560                  * value, storing it in the mean deviation
00561                  * instead.
00562                  */
00563                 t_rttvar_ += (t_srtt_ >> T_SRTT_BITS);
00564                 t_srtt_ = 0;
00565         }
00566 }
00567 
00568 /*
00569  * headersize:
00570  *      how big is an IP+TCP header in bytes; include options such as ts
00571  * this function should be virtual so others (e.g. SACK) can override
00572  */
00573 int TcpAgent::headersize()
00574 {
00575         int total = tcpip_base_hdr_size_;
00576         if (total < 1) {
00577                 fprintf(stderr,
00578                   "TcpAgent(%s): warning: tcpip hdr size is only %d bytes\n",
00579                   name(), tcpip_base_hdr_size_);
00580         }
00581         if (ts_option_)
00582                 total += ts_option_size_;
00583         return (total);
00584 }
00585 
00586 void TcpAgent::output(int seqno, int reason)
00587 {
00588         int force_set_rtx_timer = 0;
00589         Packet* p = allocpkt();
00590         hdr_tcp *tcph = hdr_tcp::access(p);
00591         hdr_flags* hf = hdr_flags::access(p);
00592         hdr_ip *iph = hdr_ip::access(p);
00593         int databytes = hdr_cmn::access(p)->size();
00594         tcph->seqno() = seqno;
00595         tcph->ts() = Scheduler::instance().clock();
00596         tcph->ts_echo() = ts_peer_;
00597         tcph->reason() = reason;
00598         tcph->last_rtt() = int(int(t_rtt_)*tcp_tick_*1000);
00599 
00600         if (ecn_) {
00601                 hf->ect() = 1;  // ECN-capable transport
00602         }
00603         if (cong_action_) {
00604                 hf->cong_action() = TRUE;  // Congestion action.
00605                 cong_action_ = FALSE;
00606         }
00607         /* Check if this is the initial SYN packet. */
00608         if (seqno == 0) {
00609                 if (syn_) {
00610                         databytes = 0;
00611                         curseq_ += 1;
00612                         hdr_cmn::access(p)->size() = tcpip_base_hdr_size_;
00613                 }
00614                 if (ecn_) {
00615                         hf->ecnecho() = 1;
00616 //                      hf->cong_action() = 1;
00617                         hf->ect() = 0;
00618                 }
00619                 if (qs_enabled_) {
00620                         hdr_qs *qsh = hdr_qs::access(p);
00621                         if (rate_request_ > 0) {
00622                                 // QuickStart code from Srikanth Sundarrajan.
00623                                 qsh->flag() = QS_REQUEST;
00624                                 Random::seed_heuristically();
00625                                 qsh->ttl() = Random::integer(256);
00626                                 ttl_diff_ = (iph->ttl() - qsh->ttl()) % 256;
00627                                 qsh->rate() = rate_request_;
00628                                 qs_requested_ = 1;
00629                         } else {
00630                                 qsh->flag() = QS_DISABLE;
00631                         }
00632                 }
00633         }
00634         else if (useHeaders_ == true) {
00635                 hdr_cmn::access(p)->size() += headersize();
00636         }
00637         hdr_cmn::access(p)->size();
00638 
00639         /* if no outstanding data, be sure to set rtx timer again */
00640         if (highest_ack_ == maxseq_)
00641                 force_set_rtx_timer = 1;
00642         /* call helper function to fill in additional fields */
00643         output_helper(p);
00644 
00645         ++ndatapack_;
00646         ndatabytes_ += databytes;
00647         send(p, 0);
00648         if (seqno == curseq_ && seqno > maxseq_)
00649                 idle();  // Tell application I have sent everything so far
00650         if (seqno > maxseq_) {
00651                 maxseq_ = seqno;
00652                 if (!rtt_active_) {
00653                         rtt_active_ = 1;
00654                         if (seqno > rtt_seq_) {
00655                                 rtt_seq_ = seqno;
00656                                 rtt_ts_ = Scheduler::instance().clock();
00657                         }
00658                                         
00659                 }
00660         } else {
00661                 ++nrexmitpack_;
00662                 nrexmitbytes_ += databytes;
00663         }
00664         if (!(rtx_timer_.status() == TIMER_PENDING) || force_set_rtx_timer)
00665                 /* No timer pending.  Schedule one. */
00666                 set_rtx_timer();
00667 }
00668 
00669 /*
00670  * Must convert bytes into packets for one-way TCPs.
00671  * If nbytes == -1, this corresponds to infinite send.  We approximate
00672  * infinite by a very large number (TCP_MAXSEQ).
00673  */
00674 void TcpAgent::sendmsg(int nbytes, const char* /*flags*/)
00675 {
00676         if (nbytes == -1 && curseq_ <= TCP_MAXSEQ)
00677                 curseq_ = TCP_MAXSEQ; 
00678         else
00679                 curseq_ += (nbytes/size_ + (nbytes%size_ ? 1 : 0));
00680         send_much(0, 0, maxburst_);
00681 }
00682 
00683 void TcpAgent::advanceby(int delta)
00684 {
00685   curseq_ += delta;
00686         if (delta > 0)
00687                 closed_ = 0;
00688         send_much(0, 0, maxburst_); 
00689 }
00690 
00691 
00692 int TcpAgent::command(int argc, const char*const* argv)
00693 {
00694         if (argc == 3) {
00695                 if (strcmp(argv[1], "advance") == 0) {
00696                         int newseq = atoi(argv[2]);
00697                         if (newseq > maxseq_)
00698                                 advanceby(newseq - curseq_);
00699                         else
00700                                 advanceby(maxseq_ - curseq_);
00701                         return (TCL_OK);
00702                 }
00703                 if (strcmp(argv[1], "advanceby") == 0) {
00704                         advanceby(atoi(argv[2]));
00705                         return (TCL_OK);
00706                 }
00707                 if (strcmp(argv[1], "eventtrace") == 0) {
00708                         et_ = (EventTrace *)TclObject::lookup(argv[2]);
00709                         return (TCL_OK);
00710                 }
00711                 /*
00712                  * Curtis Villamizar's trick to transfer tcp connection
00713                  * parameters to emulate http persistent connections.
00714                  *
00715                  * Another way to do the same thing is to open one tcp
00716                  * object and use start/stop/maxpkts_ or advanceby to control
00717                  * how much data is sent in each burst.
00718                  * With a single connection, slow_start_restart_
00719                  * should be configured as desired.
00720                  *
00721                  * This implementation (persist) may not correctly
00722                  * emulate pure-BSD-based systems which close cwnd
00723                  * after the connection goes idle (slow-start
00724                  * restart).  See appendix C in
00725                  * Jacobson and Karels ``Congestion
00726                  * Avoidance and Control'' at
00727                  * <ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z>
00728                  * (*not* the original
00729                  * '88 paper) for why BSD does this.  See
00730                  * ``Performance Interactions Between P-HTTP and TCP
00731                  * Implementations'' in CCR 27(2) for descriptions of
00732                  * what other systems do the same.
00733                  *
00734                  */
00735                 if (strcmp(argv[1], "persist") == 0) {
00736                         TcpAgent *other
00737                           = (TcpAgent*)TclObject::lookup(argv[2]);
00738                         cwnd_ = other->cwnd_;
00739                         awnd_ = other->awnd_;
00740                         ssthresh_ = other->ssthresh_;
00741                         t_rtt_ = other->t_rtt_;
00742                         t_srtt_ = other->t_srtt_;
00743                         t_rttvar_ = other->t_rttvar_;
00744                         t_backoff_ = other->t_backoff_;
00745                         return (TCL_OK);
00746                 }
00747         }
00748         return (Agent::command(argc, argv));
00749 }
00750 
00751 int TcpAgent::window()
00752 {
00753         return (cwnd_ < wnd_ ? (int)cwnd_ : (int)wnd_);
00754 }
00755 
00756 double TcpAgent::windowd()
00757 {
00758         return (cwnd_ < wnd_ ? (double)cwnd_ : (double)wnd_);
00759 }
00760 
00761 /*
00762  * Try to send as much data as the window will allow.  The link layer will 
00763  * do the buffering; we ask the application layer for the size of the packets.
00764  */
00765 void TcpAgent::send_much(int force, int reason, int maxburst)
00766 {
00767         send_idle_helper();
00768         int win = window();
00769         int npackets = 0;
00770 
00771         if (!force && delsnd_timer_.status() == TIMER_PENDING)
00772                 return;
00773         /* Save time when first packet was sent, for newreno  --Allman */
00774         if (t_seqno_ == 0)
00775                 firstsent_ = Scheduler::instance().clock();
00776 
00777         if (burstsnd_timer_.status() == TIMER_PENDING)
00778                 return;
00779         while (t_seqno_ <= highest_ack_ + win && t_seqno_ < curseq_) {
00780                 if (overhead_ == 0 || force) {
00781                         output(t_seqno_, reason);
00782                         npackets++;
00783                         if (QOption_)
00784                                 process_qoption_after_send () ; 
00785                         t_seqno_ ++ ;
00786                         if (qs_approved_ == 1) {
00787                                 // delay = effective RTT / window
00788                                 double delay = (double) t_rtt_ * tcp_tick_ / win;
00789                                 delsnd_timer_.resched(delay);
00790                                 return;
00791                         }
00792                 } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
00793                         /*
00794                          * Set a delayed send timeout.
00795                          */
00796                         delsnd_timer_.resched(Random::uniform(overhead_));
00797                         return;
00798                 }
00799                 win = window();
00800                 if (maxburst && npackets == maxburst)
00801                         break;
00802         }
00803         /* call helper function */
00804         send_helper(maxburst);
00805 }
00806 
00807 /*
00808  * We got a timeout or too many duplicate acks.  Clear the retransmit timer.  
00809  * Resume the sequence one past the last packet acked.  
00810  * "mild" is 0 for timeouts and Tahoe dup acks, 1 for Reno dup acks.
00811  * "backoff" is 1 if the timer should be backed off, 0 otherwise.
00812  */
00813 void TcpAgent::reset_rtx_timer(int mild, int backoff)
00814 {
00815         if (backoff)
00816                 rtt_backoff();
00817         set_rtx_timer();
00818         if (!mild)
00819                 t_seqno_ = highest_ack_ + 1;
00820         rtt_active_ = 0;
00821 }
00822 
00823 /*
00824  * Set retransmit timer using current rtt estimate.  By calling resched(), 
00825  * it does not matter whether the timer was already running.
00826  */
00827 void TcpAgent::set_rtx_timer()
00828 {
00829         rtx_timer_.resched(rtt_timeout());
00830 }
00831 
00832 /*
00833  * Set new retransmission timer if not all outstanding
00834  * or available data acked, or if we are unable to send because 
00835  * cwnd is less than one (as when the ECN bit is set when cwnd was 1).
00836  * Otherwise, if a timer is still outstanding, cancel it.
00837  */
00838 void TcpAgent::newtimer(Packet* pkt)
00839 {
00840         hdr_tcp *tcph = hdr_tcp::access(pkt);
00841         /*
00842          * t_seqno_, the next packet to send, is reset (decreased) 
00843          *   to highest_ack_ + 1 after a timeout,
00844          *   so we also have to check maxseq_, the highest seqno sent.
00845          * In addition, if the packet sent after the timeout has
00846          *   the ECN bit set, then the returning ACK caused cwnd_ to
00847          *   be decreased to less than one, and we can't send another
00848          *   packet until the retransmit timer again expires.
00849          *   So we have to check for "cwnd_ < 1" as well.
00850          */
00851         if (t_seqno_ > tcph->seqno() || tcph->seqno() < maxseq_ || cwnd_ < 1) 
00852                 set_rtx_timer();
00853         else
00854                 cancel_rtx_timer();
00855 }
00856 
00857 /*
00858  * for experimental, high-speed TCP
00859  */
00860 double TcpAgent::linear(double x, double x_1, double y_1, double x_2, double y_2)
00861 {
00862         // The y coordinate factor ranges from y_1 to y_2
00863         //  as the x coordinate ranges from x_1 to x_2.
00864         double y = y_1 + ((y_2 - y_1) * ((x - x_1)/(x_2-x_1)));
00865         return y;
00866 }
00867 
00868 /*
00869  * Limited Slow-Start for large congestion windows.
00870  * This is only used when max_ssthresh_ is non-zero.
00871  */
00872 double TcpAgent::limited_slow_start(double cwnd, double max_ssthresh, double increment)
00873 {
00874         int round = int(cwnd / (double(max_ssthresh)/2.0));
00875         double increment1 = 1.0/(double(round)); 
00876         if (increment < increment1)
00877                 increment = increment1;
00878         return increment;
00879 }
00880 
00881 /*
00882  * For retrieving numdupacks_.
00883  */
00884 int TcpAgent::numdupacks(double cwnd)
00885 {
00886         int cwndfraction = (int) cwnd/numdupacksFrac_;
00887         if (numdupacks_ > cwndfraction) {
00888                 return numdupacks_;
00889         } else {
00890                 return cwndfraction;
00891         }
00892 }
00893 
00894 /*
00895  * Calculating the packet drop rate p for highspeed TCP.
00896  */
00897 double TcpAgent::compute_p()
00898 {
00899         double p;
00900         double low_p = 1.5/(low_window_*low_window_);
00901         p = exp(linear(log(cwnd_), log(low_window_), log(low_p), log(high_window_), log(high_p_)));
00902         return p;
00903 }
00904 
00905 /*
00906  * Calculating the decrease parameter for highspeed TCP.
00907  */
00908 double TcpAgent::decrease_param()
00909 {
00910         double decrease;
00911         decrease = linear(log(cwnd_), log(low_window_), 0.5, log(high_window_), high_decrease_);
00912         return decrease;
00913 }
00914 
00915 /*
00916  * Calculating the increase parameter for highspeed TCP.
00917  */
00918 double TcpAgent::increase_param()
00919 {
00920         double increase, decrease, p, answer;
00921         /* extending the slow-start for high-speed TCP */
00922 
00923         /* for highspeed TCP -- from Sylvia Ratnasamy, */
00924         /* modifications by Sally Floyd and Evandro de Souza */
00925         // p ranges from 1.5/W^2 at congestion window low_window_, to
00926         //    high_p_ at congestion window high_window_, on a log-log scale.
00927         // The decrease factor ranges from 0.5 to high_decrease
00928         //  as the window ranges from low_window to high_window, 
00929         //  as the log of the window. 
00930         // For an efficient implementation, this would just be looked up
00931         //   in a table, with the increase and decrease being a function of the
00932         //   congestion window.
00933 
00934        if (cwnd_ <= low_window_) { 
00935                 answer = 1 / cwnd_;
00936                 return answer; 
00937        } else if (cwnd_ >= cwnd_last_ && cwnd_ < cwnd_frac_ * cwnd_last_ ) {
00938                 answer = increase_last_ / cwnd_;
00939                 return answer;
00940        } else { 
00941                 p = compute_p();
00942                 decrease = decrease_param();
00943                 increase = (cwnd_ * cwnd_ *2.0* decrease * p)/(2.0 - decrease); 
00944                 //      double max_increase = 157.8;
00945                 //      if (increase > max_increase) { 
00946                 //              increase = max_increase;
00947                 //      } 
00948                 answer = increase / cwnd_;
00949                 cwnd_last_ = cwnd_;
00950                 increase_last_ = increase;
00951                 return answer;
00952         }       
00953 }
00954 
00955 /*
00956  * open up the congestion window
00957  */
00958 void TcpAgent::opencwnd()
00959 {
00960         double increment;
00961         if (cwnd_ < ssthresh_) {
00962                 /* slow-start (exponential) */
00963                 cwnd_ += 1;
00964         } else {
00965                 /* linear */
00966                 double f;
00967                 switch (wnd_option_) {
00968                 case 0:
00969                         if (++count_ >= cwnd_) {
00970                                 count_ = 0;
00971                                 ++cwnd_;
00972                         }
00973                         break;
00974 
00975                 case 1:
00976                         /* This is the standard algorithm. */
00977                         increment = increase_num_ / cwnd_;
00978                         if ((last_cwnd_action_ == 0 ||
00979                           last_cwnd_action_ == CWND_ACTION_TIMEOUT) 
00980                           && max_ssthresh_ > 0) {
00981                                 increment = limited_slow_start(cwnd_,
00982                                   max_ssthresh_, increment);
00983                         }
00984                         cwnd_ += increment;
00985                         break;
00986 
00987                 case 2:
00988                         /* These are window increase algorithms
00989                          * for experimental purposes only. */
00990                         f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
00991                         f *= f;
00992                         f *= wnd_const_;
00993                         f += fcnt_;
00994                         if (f > cwnd_) {
00995                                 fcnt_ = 0;
00996                                 ++cwnd_;
00997                         } else
00998                                 fcnt_ = f;
00999                         break;
01000 
01001                 case 3:
01002                         f = awnd_;
01003                         f *= f;
01004                         f *= wnd_const_;
01005                         f += fcnt_;
01006                         if (f > cwnd_) {
01007                                 fcnt_ = 0;
01008                                 ++cwnd_;
01009                         } else
01010                                 fcnt_ = f;
01011                         break;
01012 
01013                 case 4:
01014                         f = awnd_;
01015                         f *= wnd_const_;
01016                         f += fcnt_;
01017                         if (f > cwnd_) {
01018                                 fcnt_ = 0;
01019                                 ++cwnd_;
01020                         } else
01021                                 fcnt_ = f;
01022                         break;
01023                 case 5:
01024                         f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
01025                         f *= wnd_const_;
01026                         f += fcnt_;
01027                         if (f > cwnd_) {
01028                                 fcnt_ = 0;
01029                                 ++cwnd_;
01030                         } else
01031                                 fcnt_ = f;
01032                         break;
01033                 case 6:
01034                         /* binomial controls */ 
01035                         cwnd_ += increase_num_ / (cwnd_*pow(cwnd_,k_parameter_));                
01036                         break; 
01037                 case 8: 
01038                         /* high-speed TCP */
01039                         increment = increase_param();
01040                         if ((last_cwnd_action_ == 0 ||
01041                           last_cwnd_action_ == CWND_ACTION_TIMEOUT) 
01042                           && max_ssthresh_ > 0) {
01043                                 increment = limited_slow_start(cwnd_,
01044                                   max_ssthresh_, increment);
01045                         }
01046                         cwnd_ += increment;
01047                         break;
01048                 default:
01049 #ifdef notdef
01050                         /*XXX*/
01051                         error("illegal window option %d", wnd_option_);
01052 #endif
01053                         abort();
01054                 }
01055         }
01056         // if maxcwnd_ is set (nonzero), make it the cwnd limit
01057         if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
01058                 cwnd_ = maxcwnd_;
01059 
01060         return;
01061 }
01062 
01063 void
01064 TcpAgent::slowdown(int how)
01065 {
01066         double decrease;  /* added for highspeed - sylvia */
01067         double win, halfwin, decreasewin;
01068         int slowstart = 0;
01069         ++ncwndcuts_; 
01070         // we are in slowstart for sure if cwnd < ssthresh
01071         if (cwnd_ < ssthresh_) 
01072                 slowstart = 1;
01073         if (precision_reduce_) {
01074                 halfwin = windowd() / 2;
01075                 if (wnd_option_ == 6) {         
01076                         /* binomial controls */
01077                         decreasewin = windowd() - (1.0-decrease_num_)*pow(windowd(),l_parameter_);
01078                 } else if (wnd_option_ == 8 && (cwnd_ > low_window_)) { 
01079                         /* experimental highspeed TCP */
01080                         decrease = decrease_param();
01081                         //if (decrease < 0.1) 
01082                         //      decrease = 0.1;
01083                         decrease_num_ = decrease;
01084                         decreasewin = windowd() - (decrease * windowd());
01085                 } else {
01086                         decreasewin = decrease_num_ * windowd();
01087                 }
01088                 win = windowd();
01089         } else  {
01090                 int temp;
01091                 temp = (int)(window() / 2);
01092                 halfwin = (double) temp;
01093                 if (wnd_option_ == 6) {
01094                         /* binomial controls */
01095                         temp = (int)(window() - (1.0-decrease_num_)*pow(window(),l_parameter_));
01096                 } else if ((wnd_option_ == 8) && (cwnd_ > low_window_)) { 
01097                         /* experimental highspeed TCP */
01098                         decrease = decrease_param();
01099                         //if (decrease < 0.1)
01100                         //       decrease = 0.1;                
01101                         decrease_num_ = decrease;
01102                         temp = (int)(windowd() - (decrease * windowd()));
01103                 } else {
01104                         temp = (int)(decrease_num_ * window());
01105                 }
01106                 decreasewin = (double) temp;
01107                 win = (double) window();
01108         }
01109         if (how & CLOSE_SSTHRESH_HALF)
01110                 // For the first decrease, decrease by half
01111                 // even for non-standard values of decrease_num_.
01112                 if (first_decrease_ == 1 || slowstart ||
01113                         last_cwnd_action_ == CWND_ACTION_TIMEOUT) {
01114                         // Do we really want halfwin instead of decreasewin
01115                 // after a timeout?
01116                         ssthresh_ = (int) halfwin;
01117                 } else {
01118                         ssthresh_ = (int) decreasewin;
01119                 }
01120         else if (how & THREE_QUARTER_SSTHRESH)
01121                 if (ssthresh_ < 3*cwnd_/4)
01122                         ssthresh_  = (int)(3*cwnd_/4);
01123         if (how & CLOSE_CWND_HALF)
01124                 // For the first decrease, decrease by half
01125                 // even for non-standard values of decrease_num_.
01126                 if (first_decrease_ == 1 || slowstart || decrease_num_ == 0.5) {
01127                         cwnd_ = halfwin;
01128                 } else cwnd_ = decreasewin;
01129         else if (how & CWND_HALF_WITH_MIN) {
01130                 // We have not thought about how non-standard TCPs, with
01131                 // non-standard values of decrease_num_, should respond
01132                 // after quiescent periods.
01133                 cwnd_ = decreasewin;
01134                 if (cwnd_ < 1)
01135                         cwnd_ = 1;
01136         }
01137         else if (how & CLOSE_CWND_RESTART) 
01138                 cwnd_ = int(wnd_restart_);
01139         else if (how & CLOSE_CWND_INIT)
01140                 cwnd_ = int(wnd_init_);
01141         else if (how & CLOSE_CWND_ONE)
01142                 cwnd_ = 1;
01143         else if (how & CLOSE_CWND_HALF_WAY) {
01144                 // cwnd_ = win - (win - W_used)/2 ;
01145                 cwnd_ = W_used + decrease_num_ * (win - W_used);
01146                 if (cwnd_ < 1)
01147                         cwnd_ = 1;
01148         }
01149         if (ssthresh_ < 2)
01150                 ssthresh_ = 2;
01151         if (how & (CLOSE_CWND_HALF|CLOSE_CWND_RESTART|CLOSE_CWND_INIT|CLOSE_CWND_ONE))
01152                 cong_action_ = TRUE;
01153 
01154         fcnt_ = count_ = 0;
01155         if (first_decrease_ == 1)
01156                 first_decrease_ = 0;
01157         // for event tracing slow start
01158         if (cwnd_ == 1 || slowstart) 
01159                 // Not sure if this is best way to capture slow_start
01160                 // This is probably tracing a superset of slowdowns of
01161                 // which all may not be slow_start's --Padma, 07/'01.
01162                 trace_event("SLOW_START");
01163         
01164 
01165 
01166         
01167 }
01168 
01169 
01170 
01171 /*
01172  * Process a packet that acks previously unacknowleged data.
01173  */
01174 void TcpAgent::newack(Packet* pkt)
01175 {
01176         double now = Scheduler::instance().clock();
01177         hdr_tcp *tcph = hdr_tcp::access(pkt);
01178         /* 
01179          * Wouldn't it be better to set the timer *after*
01180          * updating the RTT, instead of *before*? 
01181          */
01182         if (!timerfix_) newtimer(pkt);
01183         dupacks_ = 0;
01184         last_ack_ = tcph->seqno();
01185         prev_highest_ack_ = highest_ack_ ;
01186         highest_ack_ = last_ack_;
01187 
01188         if (t_seqno_ < last_ack_ + 1)
01189                 t_seqno_ = last_ack_ + 1;
01190         /* 
01191          * Update RTT only if it's OK to do so from info in the flags header.
01192          * This is needed for protocols in which intermediate agents
01193          * in the network intersperse acks (e.g., ack-reconstructors) for
01194          * various reasons (without violating e2e semantics).
01195          */     
01196         hdr_flags *fh = hdr_flags::access(pkt);
01197         if (!fh->no_ts_) {
01198                 if (ts_option_)
01199                         rtt_update(now - tcph->ts_echo());
01200 
01201                 if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
01202                         if (!ect_ || !ecn_backoff_ || 
01203                                 !hdr_flags::access(pkt)->ecnecho()) {
01204                                 /* 
01205                                  * Don't end backoff if still in ECN-Echo with
01206                                  * a congestion window of 1 packet. 
01207                                  */
01208                                 t_backoff_ = 1;
01209                                 ecn_backoff_ = 0;
01210                         }
01211                         rtt_active_ = 0;
01212                         if (!ts_option_)
01213                                 rtt_update(now - rtt_ts_);
01214                 }
01215         }
01216         if (timerfix_) newtimer(pkt);
01217         /* update average window */
01218         awnd_ *= 1.0 - wnd_th_;
01219         awnd_ += wnd_th_ * cwnd_;
01220 }
01221 
01222 
01223 /*
01224  * Respond either to a source quench or to a congestion indication bit.
01225  * This is done at most once a roundtrip time;  after a source quench,
01226  * another one will not be done until the last packet transmitted before
01227  * the previous source quench has been ACKed.
01228  *
01229  * Note that this procedure is called before "highest_ack_" is
01230  * updated to reflect the current ACK packet.  
01231  */
01232 void TcpAgent::ecn(int seqno)
01233 {
01234         if (seqno > recover_ || 
01235               last_cwnd_action_ == CWND_ACTION_TIMEOUT) {
01236                 recover_ =  maxseq_;
01237                 last_cwnd_action_ = CWND_ACTION_ECN;
01238                 if (cwnd_ <= 1.0) {
01239                         if (ecn_backoff_) 
01240                                 rtt_backoff();
01241                         else ecn_backoff_ = 1;
01242                 } else ecn_backoff_ = 0;
01243                 slowdown(CLOSE_CWND_HALF|CLOSE_SSTHRESH_HALF);
01244                 ++necnresponses_ ;
01245                 // added by sylvia to count number of ecn responses 
01246         }
01247 }
01248 
01249 /*
01250  *  Is the connection limited by the network (instead of by a lack
01251  *    of data from the application?
01252  */
01253 int TcpAgent::network_limited() {
01254         int win = window () ;
01255         if (t_seqno_ > (prev_highest_ack_ + win))
01256                 return 1;
01257         else
01258                 return 0;
01259 }
01260 
01261 void TcpAgent::recv_newack_helper(Packet *pkt) {
01262         //hdr_tcp *tcph = hdr_tcp::access(pkt);
01263         newack(pkt);
01264         if (!ect_ || !hdr_flags::access(pkt)->ecnecho() ||
01265                 (old_ecn_ && ecn_burst_)) {
01266                 /* If "old_ecn", this is not the first ACK carrying ECN-Echo
01267                  * after a period of ACKs without ECN-Echo.
01268                  * Therefore, open the congestion window. */
01269                 /* if control option is set, and the sender is not
01270                          window limited, then do not increase the window size */
01271                 
01272                 if (!control_increase_ || 
01273                    (control_increase_ && (network_limited() == 1))) 
01274                         opencwnd();
01275         }
01276         if (ect_) {
01277                 if (!hdr_flags::access(pkt)->ecnecho())
01278                         ecn_backoff_ = 0;
01279                 if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho())
01280                         ecn_burst_ = TRUE;
01281                 else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho())
01282                         ecn_burst_ = FALSE;
01283         }
01284         if (!ect_ && hdr_flags::access(pkt)->ecnecho() &&
01285                 !hdr_flags::access(pkt)->cong_action())
01286                 ect_ = 1;
01287         /* if the connection is done, call finish() */
01288         if ((highest_ack_ >= curseq_-1) && !closed_) {
01289                 closed_ = 1;
01290                 finish();
01291         }
01292         if (QOption_ && curseq_ == highest_ack_ +1) {
01293                 cancel_rtx_timer();
01294         }
01295 }
01296 
01297 /*
01298  * Set the initial window. 
01299  */
01300 double
01301 TcpAgent::initial_window()
01302 {
01303         //
01304         // init_option = 1: static iw of wnd_init_
01305         //
01306         if (wnd_init_option_ == 1) {
01307                 return (wnd_init_);
01308         }
01309         else if (wnd_init_option_ == 2) {
01310                 // do iw according to Internet draft
01311                 if (size_ <= 1095) {
01312                         return (4.0);
01313                 } else if (size_ < 2190) {
01314                         return (3.0);
01315                 } else {
01316                         return (2.0);
01317                 }
01318         }
01319         // XXX what should we return here???
01320         fprintf(stderr, "Wrong number of wnd_init_option_ %d\n", 
01321                 wnd_init_option_);
01322         abort();
01323         return (2.0); // XXX make msvc happy.
01324 }
01325 
01326 /*
01327  * Dupack-action: what to do on a DUP ACK.  After the initial check
01328  * of 'recover' below, this function implements the following truth
01329  * table:
01330  *
01331  *      bugfix  ecn     last-cwnd == ecn        action
01332  *
01333  *      0       0       0                       tahoe_action
01334  *      0       0       1                       tahoe_action    [impossible]
01335  *      0       1       0                       tahoe_action
01336  *      0       1       1                       slow-start, return
01337  *      1       0       0                       nothing
01338  *      1       0       1                       nothing         [impossible]
01339  *      1       1       0                       nothing
01340  *      1       1       1                       slow-start, return
01341  */
01342 
01343 /* 
01344  * A first or second duplicate acknowledgement has arrived, and
01345  * singledup_ is enabled.
01346  * If the receiver's advertised window permits, and we are exceeding our
01347  * congestion window by less than numdupacks_, then send a new packet.
01348  */
01349 void
01350 TcpAgent::send_one()
01351 {
01352         if (t_seqno_ <= highest_ack_ + wnd_ && t_seqno_ < curseq_ &&
01353                 t_seqno_ <= highest_ack_ + cwnd_ + dupacks_ ) {
01354                 output(t_seqno_, 0);
01355                 if (QOption_)
01356                         process_qoption_after_send () ;
01357                 t_seqno_ ++ ;
01358                 // send_helper(); ??
01359         }
01360         return;
01361 }
01362 
01363 void
01364 TcpAgent::dupack_action()
01365 {
01366         int recovered = (highest_ack_ > recover_);
01367         if (recovered || (!bug_fix_ && !ecn_)) {
01368                 goto tahoe_action;
01369         }
01370 
01371         if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
01372                 last_cwnd_action_ = CWND_ACTION_DUPACK;
01373                 slowdown(CLOSE_CWND_ONE);
01374                 reset_rtx_timer(0,0);
01375                 return;
01376         }
01377 
01378         if (bug_fix_) {
01379                 /*
01380                  * The line below, for "bug_fix_" true, avoids
01381                  * problems with multiple fast retransmits in one
01382                  * window of data. 
01383                  */
01384                 return;
01385         }
01386 
01387 tahoe_action:
01388         // we are now going to fast-retransmit and willtrace that event
01389         trace_event("FAST_RETX");
01390 
01391         recover_ = maxseq_;
01392         last_cwnd_action_ = CWND_ACTION_DUPACK;
01393         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_ONE);
01394         reset_rtx_timer(0,0);
01395         return;
01396 }
01397 
01398 /*
01399  * When exiting QuickStart, reduce the congestion window to the
01400  *   size that was actually used.
01401  */
01402 void TcpAgent::endQuickStart()
01403 {
01404         qs_approved_ = 0;
01405         int new_cwnd = maxseq_ - last_ack_;
01406         if (new_cwnd > 1 && new_cwnd < cwnd_) {
01407                 cwnd_ = new_cwnd;
01408                 if (cwnd_ < initial_window()) 
01409                         cwnd_ = initial_window();
01410         }
01411 }
01412 
01413 void TcpAgent::processQuickStart(Packet *pkt)
01414 {
01415         // QuickStart code from Srikanth Sundarrajan.
01416         hdr_tcp *tcph = hdr_tcp::access(pkt);
01417         hdr_qs *qsh = hdr_qs::access(pkt);
01418         double now = Scheduler::instance().clock();
01419         int app_rate;
01420 
01421         // printf("flag: %d ttl: %d ttl_diff: %d rate: %d\n", qsh->flag(),
01422         //     qsh->ttl(), ttl_diff_, qsh->rate());
01423         qs_requested_ = 0;
01424         qs_approved_ = 0;
01425         if (qsh->flag() == QS_RESPONSE && qsh->ttl() == ttl_diff_ && 
01426             qsh->rate() > 0) {
01427                 app_rate = (int) (qsh->rate() * (now - tcph->ts_echo())) ;
01428                 printf("Quick Start approved, rate %d, window %d\n", 
01429                                      qsh->rate(), app_rate);
01430                 if (app_rate > initial_window()) {
01431                         wnd_init_option_ = 1;
01432                         wnd_init_ = app_rate;
01433                         qs_approved_ = 1;
01434                 }
01435         } else { // Quick Start rejected
01436                 printf("Quick Start rejected\n");
01437         }
01438 
01439 }
01440 
01441 /*
01442  * main reception path - should only see acks, otherwise the
01443  * network connections are misconfigured
01444  */
01445 void TcpAgent::recv(Packet *pkt, Handler*)
01446 {
01447         hdr_tcp *tcph = hdr_tcp::access(pkt);
01448         if (qs_approved_ == 1 && tcph->seqno() > last_ack_) 
01449                 endQuickStart();
01450         if (qs_requested_ == 1)
01451                 processQuickStart(pkt);
01452 #ifdef notdef
01453         if (pkt->type_ != PT_ACK) {
01454                 Tcl::instance().evalf("%s error \"received non-ack\"",
01455                                       name());
01456                 Packet::free(pkt);
01457                 return;
01458         }
01459 #endif
01460         /* W.N.: check if this is from a previous incarnation */
01461         if (tcph->ts() < lastreset_) {
01462                 // Remove packet and do nothing
01463                 Packet::free(pkt);
01464                 return;
01465         }
01466         ++nackpack_;
01467         ts_peer_ = tcph->ts();
01468         int ecnecho = hdr_flags::access(pkt)->ecnecho();
01469         if (ecnecho && ecn_)
01470                 ecn(tcph->seqno());
01471         recv_helper(pkt);
01472         /* grow cwnd and check if the connection is done */ 
01473         if (tcph->seqno() > last_ack_) {
01474                 recv_newack_helper(pkt);
01475                 if (last_ack_ == 0 && delay_growth_) { 
01476                         cwnd_ = initial_window();
01477                 }
01478         } else if (tcph->seqno() == last_ack_) {
01479                 if (hdr_flags::access(pkt)->eln_ && eln_) {
01480                         tcp_eln(pkt);
01481                         return;
01482                 }
01483                 if (++dupacks_ == numdupacks_ && !noFastRetrans_) {
01484                         dupack_action();
01485                 } else if (dupacks_ < numdupacks_ && singledup_ ) {
01486                         send_one();
01487                 }
01488         }
01489 
01490         if (QOption_ && EnblRTTCtr_)
01491                 process_qoption_after_ack (tcph->seqno());
01492 
01493         Packet::free(pkt);
01494         /*
01495          * Try to send more data.
01496          */
01497         send_much(0, 0, maxburst_);
01498 }
01499 
01500 /*
01501  * Process timeout events other than rtx timeout. Having this as a separate 
01502  * function allows derived classes to make alterations/enhancements (e.g.,
01503  * response to new types of timeout events).
01504  */ 
01505 void TcpAgent::timeout_nonrtx(int tno) 
01506 {
01507         if (tno == TCP_TIMER_DELSND)  {
01508          /*
01509                 * delayed-send timer, with random overhead
01510                 * to avoid phase effects
01511                 */
01512                 send_much(1, TCP_REASON_TIMEOUT, maxburst_);
01513         }
01514 }
01515         
01516 void TcpAgent::timeout(int tno)
01517 {
01518         /* retransmit timer */
01519         if (tno == TCP_TIMER_RTX) {
01520 
01521                 // There has been a timeout - will trace this event
01522                 trace_event("TIMEOUT");
01523 
01524                 if (cwnd_ < 1) cwnd_ = 1;
01525                 if (qs_approved_ == 1) qs_approved_ = 0;
01526                 if (highest_ack_ == maxseq_ && !slow_start_restart_) {
01527                         /*
01528                          * TCP option:
01529                          * If no outstanding data, then don't do anything.  
01530                          */
01531                          // Should this return be here?
01532                          // What if CWND_ACTION_ECN and cwnd < 1?
01533                          // return;
01534                 } else {
01535                         recover_ = maxseq_;
01536                         if (highest_ack_ == -1 && wnd_init_option_ == 2)
01537                                 /* 
01538                                  * First packet dropped, so don't use larger
01539                                  * initial windows. 
01540                                  */
01541                                 wnd_init_option_ = 1;
01542                         if (highest_ack_ == maxseq_ && restart_bugfix_)
01543                                /* 
01544                                 * if there is no outstanding data, don't cut 
01545                                 * down ssthresh_.
01546                                 */
01547                                 slowdown(CLOSE_CWND_ONE);
01548                         else if (highest_ack_ < recover_ &&
01549                           last_cwnd_action_ == CWND_ACTION_ECN) {
01550                                /*
01551                                 * if we are in recovery from a recent ECN,
01552                                 * don't cut down ssthresh_.
01553                                 */
01554                                 slowdown(CLOSE_CWND_ONE);
01555                         }
01556                         else {
01557                                 ++nrexmit_;
01558                                 last_cwnd_action_ = CWND_ACTION_TIMEOUT;
01559                                 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
01560                         }
01561                 }
01562                 /* if there is no outstanding data, don't back off rtx timer */
01563                 if (highest_ack_ == maxseq_ && restart_bugfix_) {
01564                         reset_rtx_timer(0,0);
01565                 }
01566                 else {
01567                         reset_rtx_timer(0,1);
01568                 }
01569                 last_cwnd_action_ = CWND_ACTION_TIMEOUT;
01570                 send_much(0, TCP_REASON_TIMEOUT, maxburst_);
01571         } 
01572         else {
01573                 timeout_nonrtx(tno);
01574         }
01575 }
01576 
01577 /* 
01578  * Check if the packet (ack) has the ELN bit set, and if it does, and if the
01579  * last ELN-rxmitted packet is smaller than this one, then retransmit the
01580  * packet.  Do not adjust the cwnd when this happens.
01581  */
01582 void TcpAgent::tcp_eln(Packet *pkt)
01583 {
01584         //int eln_rxmit;
01585         hdr_tcp *tcph = hdr_tcp::access(pkt);
01586         int ack = tcph->seqno();
01587 
01588         if (++dupacks_ == eln_rxmit_thresh_ && ack > eln_last_rxmit_) {
01589                 /* Retransmit this packet */
01590                 output(last_ack_ + 1, TCP_REASON_DUPACK);
01591                 eln_last_rxmit_ = last_ack_+1;
01592         } else
01593                 send_much(0, 0, maxburst_);
01594 
01595         Packet::free(pkt);
01596         return;
01597 }
01598 
01599 /*
01600  * This function is invoked when the connection is done. It in turn
01601  * invokes the Tcl finish procedure that was registered with TCP.
01602  */
01603 void TcpAgent::finish()
01604 {
01605         Tcl::instance().evalf("%s done", this->name());
01606 }
01607 
01608 void RtxTimer::expire(Event*)
01609 {
01610         a_->timeout(TCP_TIMER_RTX);
01611 }
01612 
01613 void DelSndTimer::expire(Event*)
01614 {
01615         a_->timeout(TCP_TIMER_DELSND);
01616 }
01617 
01618 void BurstSndTimer::expire(Event*)
01619 {
01620         a_->timeout(TCP_TIMER_BURSTSND);
01621 }
01622 
01623 /*
01624  * THE FOLLOWING FUNCTIONS ARE OBSOLETE, but REMAIN HERE
01625  * DUE TO OTHER PEOPLE's TCPs THAT MIGHT USE THEM
01626  *
01627  * These functions are now replaced by ecn() and slowdown(),
01628  * respectively.
01629  */
01630 
01631 /*
01632  * Respond either to a source quench or to a congestion indication bit.
01633  * This is done at most once a roundtrip time;  after a source quench,
01634  * another one will not be done until the last packet transmitted before
01635  * the previous source quench has been ACKed.
01636  */
01637 void TcpAgent::quench(int how)
01638 {
01639         if (highest_ack_ >= recover_) {
01640                 recover_ =  maxseq_;
01641                 last_cwnd_action_ = CWND_ACTION_ECN;
01642                 closecwnd(how);
01643         }
01644 }
01645 
01646 /*
01647  * close down the congestion window
01648  */
01649 void TcpAgent::closecwnd(int how)
01650 {   
01651         static int first_time = 1;
01652         if (first_time == 1) {
01653                 fprintf(stderr, "the TcpAgent::closecwnd() function is now deprecated, please use the function slowdown() instead\n");
01654         }
01655         switch (how) {
01656         case 0:
01657                 /* timeouts */
01658                 ssthresh_ = int( window() / 2 );
01659                 if (ssthresh_ < 2)
01660                         ssthresh_ = 2;
01661                 cwnd_ = int(wnd_restart_);
01662                 break;
01663 
01664         case 1:
01665                 /* Reno dup acks, or after a recent congestion indication. */
01666                 // cwnd_ = window()/2;
01667                 cwnd_ = decrease_num_ * window();
01668                 ssthresh_ = int(cwnd_);
01669                 if (ssthresh_ < 2)
01670                         ssthresh_ = 2;          
01671                 break;
01672 
01673         case 2:
01674                 /* Tahoe dup acks               
01675                  * after a recent congestion indication */
01676                 cwnd_ = wnd_init_;
01677                 break;
01678 
01679         case 3:
01680                 /* Retransmit timeout, but no outstanding data. */ 
01681                 cwnd_ = int(wnd_init_);
01682                 break;
01683         case 4:
01684                 /* Tahoe dup acks */
01685                 ssthresh_ = int( window() / 2 );
01686                 if (ssthresh_ < 2)
01687                         ssthresh_ = 2;
01688                 cwnd_ = 1;
01689                 break;
01690 
01691         default:
01692                 abort();
01693         }
01694         fcnt_ = 0.;
01695         count_ = 0;
01696 }
01697 
01698 /*
01699  * Check if the sender has been idle or application-limited for more
01700  * than an RTO, and if so, reduce the congestion window.
01701  */
01702 void TcpAgent::process_qoption_after_send ()
01703 {
01704         int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
01705         int rto = (int)(t_rtxcur_/tcp_tick_) ; 
01706         /*double ct = Scheduler::instance().clock();*/
01707 
01708         if (!EnblRTTCtr_) {
01709                 if (tcp_now - T_last >= rto) {
01710                         // The sender has been idle.
01711                         slowdown(THREE_QUARTER_SSTHRESH) ;
01712                         for (int i = 0 ; i < (tcp_now - T_last)/rto; i ++) {
01713                                 slowdown(CWND_HALF_WITH_MIN);
01714                         }
01715                         T_prev = tcp_now ;
01716                         W_used = 0 ;
01717                 }
01718                 T_last = tcp_now ;
01719                 if (t_seqno_ == highest_ack_+ window()) {
01720                         T_prev = tcp_now ; 
01721                         W_used = 0 ; 
01722                 }
01723                 else if (t_seqno_ == curseq_-1) {
01724                         // The sender has no more data to send.
01725                         int tmp = t_seqno_ - highest_ack_ ;
01726                         if (tmp > W_used)
01727                                 W_used = tmp ;
01728                         if (tcp_now - T_prev >= rto) {
01729                                 // The sender has been application-limited.
01730                                 slowdown(THREE_QUARTER_SSTHRESH);
01731                                 slowdown(CLOSE_CWND_HALF_WAY);
01732                                 T_prev = tcp_now ;
01733                                 W_used = 0 ;
01734                         }
01735                 }
01736         } else {
01737                 rtt_counting();
01738         }
01739 }
01740 
01741 /*
01742  * Check if the sender has been idle or application-limited for more
01743  * than an RTO, and if so, reduce the congestion window, for a TCP sender
01744  * that "counts RTTs" by estimating the number of RTTs that fit into
01745  * a single clock tick.
01746  */
01747 void
01748 TcpAgent::rtt_counting()
01749 {
01750         int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);
01751         int rtt = (int(t_srtt_) >> T_SRTT_BITS) ;
01752 
01753         if (rtt < 1) 
01754                 rtt = 1 ;
01755         if (tcp_now - T_last >= 2*rtt) {
01756                 // The sender has been idle.
01757                 int RTTs ; 
01758                 RTTs = (tcp_now -T_last)*RTT_goodcount/(rtt*2) ; 
01759                 RTTs = RTTs - Backoffs ; 
01760                 Backoffs = 0 ; 
01761                 if (RTTs > 0) {
01762                         slowdown(THREE_QUARTER_SSTHRESH) ;
01763                         for (int i = 0 ; i < RTTs ; i ++) {
01764                                 slowdown(CWND_HALF_WITH_MIN);
01765                                 RTT_prev = RTT_count ; 
01766                                 W_used = 0 ;
01767                         }
01768                 }
01769         }
01770         T_last = tcp_now ;
01771         if (tcp_now - T_start >= 2*rtt) {
01772                 if ((RTT_count > RTT_goodcount) || (F_full == 1)) {
01773                         RTT_goodcount = RTT_count ; 
01774                         if (RTT_goodcount < 1) RTT_goodcount = 1 ; 
01775                 }
01776                 RTT_prev = RTT_prev - RTT_count ;
01777                 RTT_count = 0 ; 
01778                 T_start  = tcp_now ;
01779                 F_full = 0;
01780         }
01781         if (t_seqno_ == highest_ack_ + window()) {
01782                 W_used = 0 ; 
01783                 F_full = 1 ; 
01784                 RTT_prev = RTT_count ;
01785         }
01786         else if (t_seqno_ == curseq_-1) {
01787                 // The sender has no more data to send.
01788                 int tmp = t_seqno_ - highest_ack_ ;
01789                 if (tmp > W_used)
01790                         W_used = tmp ;
01791                 if (RTT_count - RTT_prev >= 2) {
01792                         // The sender has been application-limited.
01793                         slowdown(THREE_QUARTER_SSTHRESH) ;
01794                         slowdown(CLOSE_CWND_HALF_WAY);
01795                         RTT_prev = RTT_count ; 
01796                         Backoffs ++ ; 
01797                         W_used = 0;
01798                 }
01799         }
01800         if (F_counting == 0) {
01801                 W_timed = t_seqno_  ;
01802                 F_counting = 1 ;
01803         }
01804 }
01805 
01806 void TcpAgent::process_qoption_after_ack (int seqno)
01807 {
01808         if (F_counting == 1) {
01809                 if (seqno >= W_timed) {
01810                         RTT_count ++ ; 
01811                         F_counting = 0 ; 
01812                 }
01813                 else {
01814                         if (dupacks_ == numdupacks_)
01815                                 RTT_count ++ ;
01816                 }
01817         }
01818 }
01819 
01820 void TcpAgent::trace_event(char *eventtype)
01821 {
01822         if (et_ == NULL) return;
01823         int seqno = t_seqno_;
01824         char *wrk = et_->buffer();
01825         char *nwrk = et_->nbuffer();
01826         if (wrk != 0)
01827                 sprintf(wrk,
01828                         "E "TIME_FORMAT" %d %d TCP %s %d %d %d",
01829                         et_->round(Scheduler::instance().clock()),   // time
01830                         addr(),                       // owner (src) node id
01831                         daddr(),                      // dst node id
01832                         eventtype,                    // event type
01833                         fid_,                         // flow-id
01834                         seqno,                        // current seqno
01835                         int(cwnd_)                         //cong. window
01836                         );
01837         
01838         if (nwrk != 0)
01839                 sprintf(nwrk,
01840                         "E -t "TIME_FORMAT" -o TCP -e %s -s %d.%d -d %d.%d",
01841                         et_->round(Scheduler::instance().clock()),   // time
01842                         eventtype,                    // event type
01843                         addr(),                       // owner (src) node id
01844                         port(),                       // owner (src) port id
01845                         daddr(),                      // dst node id
01846                         dport()                       // dst port id
01847                         );
01848         et_->trace();
01849 }

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