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

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