首页 > 代码库 > tcp.cc

tcp.cc

ns2-tcp-tcp.cc

   1 /* -*-    Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */   2 /*   3  * Copyright (c) 1991-1997 Regents of the University of California.   4  * All rights reserved.   5  *   6  * Redistribution and use in source and binary forms, with or without   7  * modification, are permitted provided that the following conditions   8  * are met:   9  * 1. Redistributions of source code must retain the above copyright  10  *    notice, this list of conditions and the following disclaimer.  11  * 2. Redistributions in binary form must reproduce the above copyright  12  *    notice, this list of conditions and the following disclaimer in the  13  *    documentation and/or other materials provided with the distribution.  14  * 3. All advertising materials mentioning features or use of this software  15  *    must display the following acknowledgement:  16  *    This product includes software developed by the Computer Systems  17  *    Engineering Group at Lawrence Berkeley Laboratory.  18  * 4. Neither the name of the University nor of the Laboratory may be used  19  *    to endorse or promote products derived from this software without  20  *    specific prior written permission.  21  *  22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS‘‘ AND  23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  32  * SUCH DAMAGE.  33  */  34   35 #ifndef lint  36 static const char rcsid[] =  37     "@(#) $Header: /cvsroot/nsnam/ns-2/tcp/tcp.cc,v 1.182 2011/06/20 04:51:46 tom_henderson Exp $ (LBL)";  38 #endif  39   40 #include <stdlib.h>  41 #include <math.h>  42 #include <sys/types.h>  43 #include <iostream>  44 #include "ip.h"  45 #include "tcp.h"  46 #include "flags.h"  47 #include "random.h"  48 #include "basetrace.h"  49 #include "hdr_qs.h"  50   51 int hdr_tcp::offset_;  52   53 static class TCPHeaderClass : public PacketHeaderClass {  54 public:  55         TCPHeaderClass() : PacketHeaderClass("PacketHeader/TCP",  56                          sizeof(hdr_tcp)) {  57         bind_offset(&hdr_tcp::offset_);  58     }  59 } class_tcphdr;  60   61 static class TcpClass : public TclClass {  62 public:  63     TcpClass() : TclClass("Agent/TCP") {}  64     TclObject* create(int , const char*const*) {  65         return (new TcpAgent());  66     }  67 } class_tcp;  68   69 TcpAgent::TcpAgent()   70     : Agent(PT_TCP),   71       t_seqno_(0), dupacks_(0), curseq_(0), highest_ack_(0),   72           cwnd_(0), ssthresh_(0), maxseq_(0), count_(0),   73           rtt_active_(0), rtt_seq_(-1), rtt_ts_(0.0),   74           lastreset_(0.0), closed_(0), t_rtt_(0), t_srtt_(0), t_rttvar_(0),   75       t_backoff_(0), ts_peer_(0), ts_echo_(0), tss(NULL), tss_size_(100),   76       rtx_timer_(this), delsnd_timer_(this), burstsnd_timer_(this),   77       first_decrease_(1), fcnt_(0), nrexmit_(0), restart_bugfix_(1),   78           cong_action_(0), ecn_burst_(0), ecn_backoff_(0), ect_(0),   79           use_rtt_(0), qs_requested_(0), qs_approved_(0),  80       qs_window_(0), qs_cwnd_(0), frto_(0)  81 {  82 #ifdef TCP_DELAY_BIND_ALL  83         // defined since Dec 1999.  84 #else /* ! TCP_DELAY_BIND_ALL */  85     bind("t_seqno_", &t_seqno_);  86     bind("rtt_", &t_rtt_);  87     bind("srtt_", &t_srtt_);  88     bind("rttvar_", &t_rttvar_);  89     bind("backoff_", &t_backoff_);  90     bind("dupacks_", &dupacks_);  91     bind("seqno_", &curseq_);  92     bind("ack_", &highest_ack_);  93     bind("cwnd_", &cwnd_);  94     bind("ssthresh_", &ssthresh_);  95     bind("maxseq_", &maxseq_);  96         bind("ndatapack_", &ndatapack_);  97         bind("ndatabytes_", &ndatabytes_);  98         bind("nackpack_", &nackpack_);  99         bind("nrexmit_", &nrexmit_); 100         bind("nrexmitpack_", &nrexmitpack_); 101         bind("nrexmitbytes_", &nrexmitbytes_); 102         bind("necnresponses_", &necnresponses_); 103         bind("ncwndcuts_", &ncwndcuts_); 104     bind("ncwndcuts1_", &ncwndcuts1_); 105 #endif /* TCP_DELAY_BIND_ALL */ 106  107 } 108  109 void 110 TcpAgent::delay_bind_init_all() 111 { 112  113         // Defaults for bound variables should be set in ns-default.tcl. 114         delay_bind_init_one("window_"); 115         delay_bind_init_one("windowInit_"); 116         delay_bind_init_one("windowInitOption_"); 117  118         delay_bind_init_one("syn_"); 119         delay_bind_init_one("max_connects_"); 120         delay_bind_init_one("windowOption_"); 121         delay_bind_init_one("windowConstant_"); 122         delay_bind_init_one("windowThresh_"); 123         delay_bind_init_one("delay_growth_"); 124         delay_bind_init_one("overhead_"); 125         delay_bind_init_one("tcpTick_"); 126         delay_bind_init_one("ecn_"); 127         delay_bind_init_one("SetCWRonRetransmit_"); 128         delay_bind_init_one("old_ecn_"); 129         delay_bind_init_one("bugfix_ss_"); 130         delay_bind_init_one("eln_"); 131         delay_bind_init_one("eln_rxmit_thresh_"); 132         delay_bind_init_one("packetSize_"); 133         delay_bind_init_one("tcpip_base_hdr_size_"); 134     delay_bind_init_one("ts_option_size_"); 135         delay_bind_init_one("bugFix_"); 136     delay_bind_init_one("bugFix_ack_"); 137     delay_bind_init_one("bugFix_ts_"); 138     delay_bind_init_one("lessCareful_"); 139         delay_bind_init_one("slow_start_restart_"); 140         delay_bind_init_one("restart_bugfix_"); 141         delay_bind_init_one("timestamps_"); 142     delay_bind_init_one("ts_resetRTO_"); 143         delay_bind_init_one("maxburst_"); 144     delay_bind_init_one("aggressive_maxburst_"); 145         delay_bind_init_one("maxcwnd_"); 146     delay_bind_init_one("numdupacks_"); 147     delay_bind_init_one("numdupacksFrac_"); 148     delay_bind_init_one("exitFastRetrans_"); 149         delay_bind_init_one("maxrto_"); 150     delay_bind_init_one("minrto_"); 151         delay_bind_init_one("srtt_init_"); 152         delay_bind_init_one("rttvar_init_"); 153         delay_bind_init_one("rtxcur_init_"); 154         delay_bind_init_one("T_SRTT_BITS"); 155         delay_bind_init_one("T_RTTVAR_BITS"); 156         delay_bind_init_one("rttvar_exp_"); 157         delay_bind_init_one("awnd_"); 158         delay_bind_init_one("decrease_num_"); 159         delay_bind_init_one("increase_num_"); 160     delay_bind_init_one("k_parameter_"); 161     delay_bind_init_one("l_parameter_"); 162         delay_bind_init_one("trace_all_oneline_"); 163         delay_bind_init_one("nam_tracevar_"); 164  165         delay_bind_init_one("QOption_"); 166         delay_bind_init_one("EnblRTTCtr_"); 167         delay_bind_init_one("control_increase_"); 168     delay_bind_init_one("noFastRetrans_"); 169     delay_bind_init_one("precisionReduce_"); 170     delay_bind_init_one("oldCode_"); 171     delay_bind_init_one("useHeaders_"); 172     delay_bind_init_one("low_window_"); 173     delay_bind_init_one("high_window_"); 174     delay_bind_init_one("high_p_"); 175     delay_bind_init_one("high_decrease_"); 176     delay_bind_init_one("max_ssthresh_"); 177     delay_bind_init_one("cwnd_range_"); 178     delay_bind_init_one("timerfix_"); 179     delay_bind_init_one("rfc2988_"); 180     delay_bind_init_one("singledup_"); 181     delay_bind_init_one("LimTransmitFix_"); 182     delay_bind_init_one("rate_request_"); 183     delay_bind_init_one("qs_enabled_"); 184     delay_bind_init_one("tcp_qs_recovery_"); 185     delay_bind_init_one("qs_request_mode_"); 186     delay_bind_init_one("qs_thresh_"); 187     delay_bind_init_one("qs_rtt_"); 188     delay_bind_init_one("print_request_"); 189  190     delay_bind_init_one("frto_enabled_"); 191     delay_bind_init_one("sfrto_enabled_"); 192     delay_bind_init_one("spurious_response_"); 193  194 #ifdef TCP_DELAY_BIND_ALL 195     // out because delay-bound tracevars aren‘t yet supported 196         delay_bind_init_one("t_seqno_"); 197         delay_bind_init_one("rtt_"); 198         delay_bind_init_one("srtt_"); 199         delay_bind_init_one("rttvar_"); 200         delay_bind_init_one("backoff_"); 201         delay_bind_init_one("dupacks_"); 202         delay_bind_init_one("seqno_"); 203         delay_bind_init_one("ack_"); 204         delay_bind_init_one("cwnd_"); 205         delay_bind_init_one("ssthresh_"); 206         delay_bind_init_one("maxseq_"); 207         delay_bind_init_one("ndatapack_"); 208         delay_bind_init_one("ndatabytes_"); 209         delay_bind_init_one("nackpack_"); 210         delay_bind_init_one("nrexmit_"); 211         delay_bind_init_one("nrexmitpack_"); 212         delay_bind_init_one("nrexmitbytes_"); 213         delay_bind_init_one("necnresponses_"); 214         delay_bind_init_one("ncwndcuts_"); 215     delay_bind_init_one("ncwndcuts1_"); 216 #endif /* TCP_DELAY_BIND_ALL */ 217  218     Agent::delay_bind_init_all(); 219  220         reset(); 221 } 222  223 int 224 TcpAgent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer) 225 { 226         if (delay_bind(varName, localName, "window_", &wnd_, tracer)) return TCL_OK; 227         if (delay_bind(varName, localName, "windowInit_", &wnd_init_, tracer)) return TCL_OK; 228         if (delay_bind(varName, localName, "windowInitOption_", &wnd_init_option_, tracer)) return TCL_OK; 229         if (delay_bind_bool(varName, localName, "syn_", &syn_, tracer)) return TCL_OK; 230         if (delay_bind(varName, localName, "max_connects_", &max_connects_, tracer)) return TCL_OK; 231         if (delay_bind(varName, localName, "windowOption_", &wnd_option_ , tracer)) return TCL_OK; 232         if (delay_bind(varName, localName, "windowConstant_",  &wnd_const_, tracer)) return TCL_OK; 233         if (delay_bind(varName, localName, "windowThresh_", &wnd_th_ , tracer)) return TCL_OK; 234         if (delay_bind_bool(varName, localName, "delay_growth_", &delay_growth_ , tracer)) return TCL_OK; 235         if (delay_bind(varName, localName, "overhead_", &overhead_, tracer)) return TCL_OK; 236         if (delay_bind(varName, localName, "tcpTick_", &tcp_tick_, tracer)) return TCL_OK; 237         if (delay_bind_bool(varName, localName, "ecn_", &ecn_, tracer)) return TCL_OK; 238         if (delay_bind_bool(varName, localName, "SetCWRonRetransmit_", &SetCWRonRetransmit_, tracer)) return TCL_OK; 239         if (delay_bind_bool(varName, localName, "old_ecn_", &old_ecn_ , tracer)) return TCL_OK; 240         if (delay_bind_bool(varName, localName, "bugfix_ss_", &bugfix_ss_ , tracer)) return TCL_OK; 241         if (delay_bind(varName, localName, "eln_", &eln_ , tracer)) return TCL_OK; 242         if (delay_bind(varName, localName, "eln_rxmit_thresh_", &eln_rxmit_thresh_ , tracer)) return TCL_OK; 243         if (delay_bind(varName, localName, "packetSize_", &size_ , tracer)) return TCL_OK; 244         if (delay_bind(varName, localName, "tcpip_base_hdr_size_", &tcpip_base_hdr_size_, tracer)) return TCL_OK; 245     if (delay_bind(varName, localName, "ts_option_size_", &ts_option_size_, tracer)) return TCL_OK; 246         if (delay_bind_bool(varName, localName, "bugFix_", &bug_fix_ , tracer)) return TCL_OK; 247     if (delay_bind_bool(varName, localName, "bugFix_ack_", &bugfix_ack_, tracer)) return TCL_OK; 248     if (delay_bind_bool(varName, localName, "bugFix_ts_", &bugfix_ts_ , tracer)) return TCL_OK; 249         if (delay_bind_bool(varName, localName, "lessCareful_", &less_careful_ , tracer)) return TCL_OK; 250         if (delay_bind_bool(varName, localName, "timestamps_", &ts_option_ , tracer)) return TCL_OK; 251         if (delay_bind_bool(varName, localName, "ts_resetRTO_", &ts_resetRTO_, tracer)) return TCL_OK; 252         if (delay_bind_bool(varName, localName, "slow_start_restart_", &slow_start_restart_ , tracer)) return TCL_OK; 253         if (delay_bind_bool(varName, localName, "restart_bugfix_", &restart_bugfix_ , tracer)) return TCL_OK; 254         if (delay_bind(varName, localName, "maxburst_", &maxburst_ , tracer)) return TCL_OK; 255         if (delay_bind_bool(varName, localName, "aggressive_maxburst_", &aggressive_maxburst_ , tracer)) return TCL_OK; 256         if (delay_bind(varName, localName, "maxcwnd_", &maxcwnd_ , tracer)) return TCL_OK; 257     if (delay_bind(varName, localName, "numdupacks_", &numdupacks_, tracer)) return TCL_OK; 258     if (delay_bind(varName, localName, "numdupacksFrac_", &numdupacksFrac_, tracer)) return TCL_OK; 259     if (delay_bind_bool(varName, localName, "exitFastRetrans_", &exitFastRetrans_, tracer)) return TCL_OK; 260         if (delay_bind(varName, localName, "maxrto_", &maxrto_ , tracer)) return TCL_OK; 261     if (delay_bind(varName, localName, "minrto_", &minrto_ , tracer)) return TCL_OK; 262         if (delay_bind(varName, localName, "srtt_init_", &srtt_init_ , tracer)) return TCL_OK; 263         if (delay_bind(varName, localName, "rttvar_init_", &rttvar_init_ , tracer)) return TCL_OK; 264         if (delay_bind(varName, localName, "rtxcur_init_", &rtxcur_init_ , tracer)) return TCL_OK; 265         if (delay_bind(varName, localName, "T_SRTT_BITS", &T_SRTT_BITS , tracer)) return TCL_OK; 266         if (delay_bind(varName, localName, "T_RTTVAR_BITS", &T_RTTVAR_BITS , tracer)) return TCL_OK; 267         if (delay_bind(varName, localName, "rttvar_exp_", &rttvar_exp_ , tracer)) return TCL_OK; 268         if (delay_bind(varName, localName, "awnd_", &awnd_ , tracer)) return TCL_OK; 269         if (delay_bind(varName, localName, "decrease_num_", &decrease_num_, tracer)) return TCL_OK; 270         if (delay_bind(varName, localName, "increase_num_", &increase_num_, tracer)) return TCL_OK; 271     if (delay_bind(varName, localName, "k_parameter_", &k_parameter_, tracer)) return TCL_OK; 272         if (delay_bind(varName, localName, "l_parameter_", &l_parameter_, tracer)) return TCL_OK; 273  274  275         if (delay_bind_bool(varName, localName, "trace_all_oneline_", &trace_all_oneline_ , tracer)) return TCL_OK; 276         if (delay_bind_bool(varName, localName, "nam_tracevar_", &nam_tracevar_ , tracer)) return TCL_OK; 277         if (delay_bind(varName, localName, "QOption_", &QOption_ , tracer)) return TCL_OK; 278         if (delay_bind(varName, localName, "EnblRTTCtr_", &EnblRTTCtr_ , tracer)) return TCL_OK; 279         if (delay_bind(varName, localName, "control_increase_", &control_increase_ , tracer)) return TCL_OK; 280         if (delay_bind_bool(varName, localName, "noFastRetrans_", &noFastRetrans_, tracer)) return TCL_OK; 281         if (delay_bind_bool(varName, localName, "precisionReduce_", &precision_reduce_, tracer)) return TCL_OK; 282     if (delay_bind_bool(varName, localName, "oldCode_", &oldCode_, tracer)) return TCL_OK; 283     if (delay_bind_bool(varName, localName, "useHeaders_", &useHeaders_, tracer)) return TCL_OK; 284     if (delay_bind(varName, localName, "low_window_", &low_window_, tracer)) return TCL_OK; 285     if (delay_bind(varName, localName, "high_window_", &high_window_, tracer)) return TCL_OK; 286     if (delay_bind(varName, localName, "high_p_", &high_p_, tracer)) return TCL_OK; 287     if (delay_bind(varName, localName, "high_decrease_", &high_decrease_, tracer)) return TCL_OK; 288     if (delay_bind(varName, localName, "max_ssthresh_", &max_ssthresh_, tracer)) return TCL_OK; 289     if (delay_bind(varName, localName, "cwnd_range_", &cwnd_range_, tracer)) return TCL_OK; 290     if (delay_bind_bool(varName, localName, "timerfix_", &timerfix_, tracer)) return TCL_OK; 291     if (delay_bind_bool(varName, localName, "rfc2988_", &rfc2988_, tracer)) return TCL_OK; 292         if (delay_bind(varName, localName, "singledup_", &singledup_ , tracer)) return TCL_OK; 293         if (delay_bind_bool(varName, localName, "LimTransmitFix_", &LimTransmitFix_ , tracer)) return TCL_OK; 294         if (delay_bind(varName, localName, "rate_request_", &rate_request_ , tracer)) return TCL_OK; 295         if (delay_bind_bool(varName, localName, "qs_enabled_", &qs_enabled_ , tracer)) return TCL_OK; 296     if (delay_bind_bool(varName, localName, "tcp_qs_recovery_", &tcp_qs_recovery_, tracer)) return TCL_OK; 297     if (delay_bind(varName, localName, "qs_request_mode_", &qs_request_mode_, tracer)) return TCL_OK; 298     if (delay_bind(varName, localName, "qs_thresh_", &qs_thresh_, tracer)) return TCL_OK; 299     if (delay_bind(varName, localName, "qs_rtt_", &qs_rtt_, tracer)) return TCL_OK; 300     if (delay_bind_bool(varName, localName, "print_request_", &print_request_, tracer)) return TCL_OK; 301     if (delay_bind_bool(varName, localName, "frto_enabled_", &frto_enabled_, tracer)) return TCL_OK; 302     if (delay_bind_bool(varName, localName, "sfrto_enabled_", &sfrto_enabled_, tracer)) return TCL_OK; 303     if (delay_bind_bool(varName, localName, "spurious_response_", &spurious_response_, tracer)) return TCL_OK; 304  305 #ifdef TCP_DELAY_BIND_ALL 306     // not if (delay-bound delay-bound tracevars aren‘t yet supported 307         if (delay_bind(varName, localName, "t_seqno_", &t_seqno_ , tracer)) return TCL_OK; 308         if (delay_bind(varName, localName, "rtt_", &t_rtt_ , tracer)) return TCL_OK; 309         if (delay_bind(varName, localName, "srtt_", &t_srtt_ , tracer)) return TCL_OK; 310         if (delay_bind(varName, localName, "rttvar_", &t_rttvar_ , tracer)) return TCL_OK; 311         if (delay_bind(varName, localName, "backoff_", &t_backoff_ , tracer)) return TCL_OK; 312  313         if (delay_bind(varName, localName, "dupacks_", &dupacks_ , tracer)) return TCL_OK; 314         if (delay_bind(varName, localName, "seqno_", &curseq_ , tracer)) return TCL_OK; 315         if (delay_bind(varName, localName, "ack_", &highest_ack_ , tracer)) return TCL_OK; 316         if (delay_bind(varName, localName, "cwnd_", &cwnd_ , tracer)) return TCL_OK; 317         if (delay_bind(varName, localName, "ssthresh_", &ssthresh_ , tracer)) return TCL_OK; 318         if (delay_bind(varName, localName, "maxseq_", &maxseq_ , tracer)) return TCL_OK; 319         if (delay_bind(varName, localName, "ndatapack_", &ndatapack_ , tracer)) return TCL_OK; 320         if (delay_bind(varName, localName, "ndatabytes_", &ndatabytes_ , tracer)) return TCL_OK; 321         if (delay_bind(varName, localName, "nackpack_", &nackpack_ , tracer)) return TCL_OK; 322         if (delay_bind(varName, localName, "nrexmit_", &nrexmit_ , tracer)) return TCL_OK; 323         if (delay_bind(varName, localName, "nrexmitpack_", &nrexmitpack_ , tracer)) return TCL_OK; 324         if (delay_bind(varName, localName, "nrexmitbytes_", &nrexmitbytes_ , tracer)) return TCL_OK; 325         if (delay_bind(varName, localName, "necnresponses_", &necnresponses_ , tracer)) return TCL_OK; 326         if (delay_bind(varName, localName, "ncwndcuts_", &ncwndcuts_ , tracer)) return TCL_OK; 327      if (delay_bind(varName, localName, "ncwndcuts1_", &ncwndcuts1_ , tracer)) return TCL_OK; 328  329 #endif 330  331         return Agent::delay_bind_dispatch(varName, localName, tracer); 332 } 333  334 #define TCP_WRK_SIZE        512 335 /* Print out all the traced variables whenever any one is changed */ 336 void 337 TcpAgent::traceAll() { 338     if (!channel_) 339         return; 340  341     double curtime; 342     Scheduler& s = Scheduler::instance(); 343     char wrk[TCP_WRK_SIZE]; 344  345     curtime = &s ? s.clock() : 0; 346     snprintf(wrk, TCP_WRK_SIZE, 347          "time: %-12.9f saddr: %-2d sport: %-2d daddr: %-2d dport:" 348          " %-2d maxseq: %-4d hiack: %-4d seqno: %-4d cwnd: %-6.3f" 349          " ssthresh: %-3d dupacks: %-2d rtt: %-10.9f srtt: %-10.9f" 350          " rttvar: %-10.9f bkoff: %-d fid: %-2d wnd: %-6.3f\n", 351          curtime, addr(), port(), 352          daddr(), dport(), int(maxseq_), int(highest_ack_), 353          int(t_seqno_), double(cwnd_), int(ssthresh_), 354          int(dupacks_), int(t_rtt_)*tcp_tick_,  355          (int(t_srtt_) >> T_SRTT_BITS)*tcp_tick_,  356          int(t_rttvar_)*tcp_tick_/4.0, int(t_backoff_), 357          int(fid_), double(wnd_));  358     (void)Tcl_Write(channel_, wrk, -1); 359 } 360  361 /* Print out just the variable that is modified */ 362 void 363 TcpAgent::traceVar(TracedVar* v)  364 { 365     if (!channel_) 366         return; 367  368     double curtime; 369     Scheduler& s = Scheduler::instance(); 370     char wrk[TCP_WRK_SIZE]; 371  372     curtime = &s ? s.clock() : 0; 373  374     // XXX comparing addresses is faster than comparing names 375     if (v == &cwnd_) 376         snprintf(wrk, TCP_WRK_SIZE, 377              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f\n", 378              curtime, addr(), port(), daddr(), dport(), 379              v->name(), double(*((TracedDouble*) v)));  380      else if (v == &t_rtt_) 381         snprintf(wrk, TCP_WRK_SIZE, 382              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f\n", 383              curtime, addr(), port(), daddr(), dport(), 384              v->name(), int(*((TracedInt*) v))*tcp_tick_);  385     else if (v == &t_srtt_) 386         snprintf(wrk, TCP_WRK_SIZE, 387              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f\n", 388              curtime, addr(), port(), daddr(), dport(), 389              v->name(),  390              (int(*((TracedInt*) v)) >> T_SRTT_BITS)*tcp_tick_);  391     else if (v == &t_rttvar_) 392         snprintf(wrk, TCP_WRK_SIZE, 393              "%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f\n", 394              curtime, addr(), port(), daddr(), dport(), 395              v->name(),  396              int(*((TracedInt*) v))*tcp_tick_/4.0);  397     else 398         snprintf(wrk, TCP_WRK_SIZE, 399              "%-8.5f %-2d %-2d %-2d %-2d %s %d\n", 400              curtime, addr(), port(), daddr(), dport(), 401              v->name(), int(*((TracedInt*) v)));  402  403     (void)Tcl_Write(channel_, wrk, -1); 404 } 405  406 void 407 TcpAgent::trace(TracedVar* v)  408 { 409     if (nam_tracevar_) { 410         Agent::trace(v); 411     } else if (trace_all_oneline_) 412         traceAll(); 413     else  414         traceVar(v); 415 } 416  417 // 418 // in 1-way TCP, syn_ indicates we are modeling 419 // a SYN exchange at the beginning.  If this is true 420 // and we are delaying growth, then use an initial 421 // window of one.  If not, we do whatever initial_window() 422 // says to do. 423 // 424  425 void 426 TcpAgent::set_initial_window() 427 { 428     if (syn_ && delay_growth_) { 429         cwnd_ = 1.0;  430         syn_connects_ = 0; 431     } else 432         cwnd_ = initial_window(); 433 } 434  435 void 436 TcpAgent::reset_qoption() 437 { 438     int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5); 439  440     T_start = now ;  441     RTT_count = 0 ;  442     RTT_prev = 0 ;  443     RTT_goodcount = 1 ;  444     F_counting = 0 ;  445     W_timed = -1 ;  446     F_full = 0 ; 447     Backoffs = 0 ;  448 } 449  450 void 451 TcpAgent::reset() 452 { 453     rtt_init(); 454     rtt_seq_ = -1; 455     /*XXX lookup variables */ 456     dupacks_ = 0; 457     curseq_ = 0; 458     set_initial_window(); 459  460     t_seqno_ = 0; 461     maxseq_ = -1; 462     last_ack_ = -1; 463     highest_ack_ = -1; 464     //highest_ack_ = 1; 465     ssthresh_ = int(wnd_); 466     if (max_ssthresh_ > 0 && max_ssthresh_ < ssthresh_)  467         ssthresh_ = max_ssthresh_; 468     wnd_restart_ = 1.; 469     awnd_ = wnd_init_ / 2.0; 470     recover_ = 0; 471     closed_ = 0; 472     last_cwnd_action_ = 0; 473     boot_time_ = Random::uniform(tcp_tick_); 474     first_decrease_ = 1; 475     /* W.N.: for removing packets from previous incarnations */ 476     lastreset_ = Scheduler::instance().clock(); 477  478     /* Now these variables will be reset  479        - Debojyoti Dutta 12th Oct‘2000 */ 480   481     ndatapack_ = 0; 482     ndatabytes_ = 0; 483     nackpack_ = 0; 484     nrexmitbytes_ = 0; 485     nrexmit_ = 0; 486     nrexmitpack_ = 0; 487     necnresponses_ = 0; 488     ncwndcuts_ = 0; 489     ncwndcuts1_ = 0; 490         cancel_timers();      // suggested by P. Anelli. 491  492     if (control_increase_) { 493         prev_highest_ack_ = highest_ack_ ;  494     } 495  496     if (wnd_option_ == 8) { 497         // HighSpeed TCP 498         hstcp_.low_p = 1.5/(low_window_*low_window_); 499         double highLowWin = log(high_window_)-log(low_window_); 500         double highLowP = log(high_p_) - log(hstcp_.low_p); 501         hstcp_.dec1 =  502            0.5 - log(low_window_) * (high_decrease_ - 0.5)/highLowWin; 503         hstcp_.dec2 = (high_decrease_ - 0.5)/highLowWin; 504             hstcp_.p1 =  505           log(hstcp_.low_p) - log(low_window_) * highLowP/highLowWin; 506         hstcp_.p2 = highLowP/highLowWin; 507     } 508  509     if (QOption_) { 510         int now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5); 511         T_last = now ;  512         T_prev = now ;  513         W_used = 0 ; 514         if (EnblRTTCtr_) { 515             reset_qoption(); 516         } 517     } 518 } 519  520 /* 521  * Initialize variables for the retransmit timer. 522  */ 523 void TcpAgent::rtt_init() 524 { 525     t_rtt_ = 0; 526     t_srtt_ = int(srtt_init_ / tcp_tick_) << T_SRTT_BITS; 527     t_rttvar_ = int(rttvar_init_ / tcp_tick_) << T_RTTVAR_BITS; 528     t_rtxcur_ = rtxcur_init_; 529     t_backoff_ = 1; 530 } 531  532 double TcpAgent::rtt_timeout() 533 { 534     double timeout; 535     if (rfc2988_) { 536     // Correction from Tom Kelly to be RFC2988-compliant, by 537     // clamping minrto_ before applying t_backoff_. 538         if (t_rtxcur_ < minrto_ && !use_rtt_) 539             timeout = minrto_ * t_backoff_; 540         else 541             timeout = t_rtxcur_ * t_backoff_; 542     } else { 543         // only of interest for backwards compatibility 544         timeout = t_rtxcur_ * t_backoff_; 545         if (timeout < minrto_) 546             timeout = minrto_; 547     } 548  549     if (timeout > maxrto_) 550         timeout = maxrto_; 551  552         if (timeout < 2.0 * tcp_tick_) { 553         if (timeout < 0) { 554             fprintf(stderr, "TcpAgent: negative RTO!  (%f)\n", 555                 timeout); 556             exit(1); 557         } else if (use_rtt_ && timeout < tcp_tick_) 558             timeout = tcp_tick_; 559         else 560             timeout = 2.0 * tcp_tick_; 561     } 562     use_rtt_ = 0; 563     return (timeout); 564 } 565  566  567 /* This has been modified to use the tahoe code. */ 568 void TcpAgent::rtt_update(double tao) 569 { 570     double now = Scheduler::instance().clock(); 571     if (ts_option_) 572         t_rtt_ = int(tao /tcp_tick_ + 0.5); 573     else { 574         double sendtime = now - tao; 575         sendtime += boot_time_; 576         double tickoff = fmod(sendtime, tcp_tick_); 577         t_rtt_ = int((tao + tickoff) / tcp_tick_); 578     } 579     if (t_rtt_ < 1) 580         t_rtt_ = 1; 581     // 582     // t_srtt_ has 3 bits to the right of the binary point 583     // t_rttvar_ has 2 584         // Thus "t_srtt_ >> T_SRTT_BITS" is the actual srtt,  585       //   and "t_srtt_" is 8*srtt. 586     // Similarly, "t_rttvar_ >> T_RTTVAR_BITS" is the actual rttvar, 587     //   and "t_rttvar_" is 4*rttvar. 588     // 589         if (t_srtt_ != 0) { 590         register short delta; 591         delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS);    // d = (m - a0) 592         if ((t_srtt_ += delta) <= 0)    // a1 = 7/8 a0 + 1/8 m 593             t_srtt_ = 1; 594         if (delta < 0) 595             delta = -delta; 596         delta -= (t_rttvar_ >> T_RTTVAR_BITS); 597         if ((t_rttvar_ += delta) <= 0)    // var1 = 3/4 var0 + 1/4 |d| 598             t_rttvar_ = 1; 599     } else { 600         t_srtt_ = t_rtt_ << T_SRTT_BITS;        // srtt = rtt 601         t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1);    // rttvar = rtt / 2 602     } 603     // 604     // Current retransmit value is  605     //    (unscaled) smoothed round trip estimate 606     //    plus 2^rttvar_exp_ times (unscaled) rttvar.  607     // 608     t_rtxcur_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS))) + 609         t_srtt_)  >> T_SRTT_BITS ) * tcp_tick_; 610  611     return; 612 } 613  614 void TcpAgent::rtt_backoff() 615 { 616     if (t_backoff_ < 64 || (rfc2988_ && rtt_timeout() < maxrto_)) 617             t_backoff_ <<= 1; 618         // RFC2988 allows a maximum for the backed-off RTO of 60 seconds. 619         // This is applied by maxrto_. 620  621     if (t_backoff_ > 8) { 622         /* 623          * If backed off this far, clobber the srtt 624          * value, storing it in the mean deviation 625          * instead. 626          */ 627         t_rttvar_ += (t_srtt_ >> T_SRTT_BITS); 628         t_srtt_ = 0; 629     } 630 } 631  632 /* 633  * headersize: 634  *      how big is an IP+TCP header in bytes; include options such as ts 635  * this function should be virtual so others (e.g. SACK) can override 636  */ 637 int TcpAgent::headersize() 638 { 639         int total = tcpip_base_hdr_size_; 640     if (total < 1) { 641         fprintf(stderr, 642           "TcpAgent(%s): warning: tcpip hdr size is only %d bytes\n", 643           name(), tcpip_base_hdr_size_); 644     } 645     if (ts_option_) 646         total += ts_option_size_; 647         return (total); 648 } 649  650 void TcpAgent::output(int seqno, int reason) 651 { 652     int force_set_rtx_timer = 0; 653     Packet* p = allocpkt(); 654     hdr_tcp *tcph = hdr_tcp::access(p); 655     hdr_flags* hf = hdr_flags::access(p); 656     hdr_ip *iph = hdr_ip::access(p); 657     int databytes = hdr_cmn::access(p)->size(); 658     tcph->seqno() = seqno; 659     tcph->ts() = Scheduler::instance().clock(); 660     int is_retransmit = (seqno < maxseq_); 661   662     // Mark packet for diagnosis purposes if we are in Quick-Start Phase 663     if (qs_approved_) { 664         hf->qs() = 1; 665     } 666   667         // store timestamps, with bugfix_ts_.  From Andrei Gurtov.  668     // (A real TCP would use scoreboard for this.) 669         if (bugfix_ts_ && tss==NULL) { 670                 tss = (double*) calloc(tss_size_, sizeof(double)); 671                 if (tss==NULL) exit(1); 672         } 673         //dynamically grow the timestamp array if it‘s getting full 674         if (bugfix_ts_ && ((seqno - highest_ack_) > tss_size_* 0.9)) { 675                 double *ntss; 676                 ntss = (double*) calloc(tss_size_*2, sizeof(double)); 677                 printf("%p resizing timestamp table\n", this); 678                 if (ntss == NULL) exit(1); 679                 for (int i=0; i<tss_size_; i++) 680                         ntss[(highest_ack_ + i) % (tss_size_ * 2)] = 681                                 tss[(highest_ack_ + i) % tss_size_]; 682                 free(tss); 683                 tss_size_ *= 2; 684                 tss = ntss; 685         } 686   687         if (tss!=NULL) 688                 tss[seqno % tss_size_] = tcph->ts();  689  690     tcph->ts_echo() = ts_peer_; 691     tcph->reason() = reason; 692     tcph->last_rtt() = int(int(t_rtt_)*tcp_tick_*1000); 693  694     if (ecn_) { 695         hf->ect() = 1;    // ECN-capable transport 696     } 697     if (cong_action_ && (!is_retransmit || SetCWRonRetransmit_)) { 698         hf->cong_action() = TRUE;  // Congestion action. 699         cong_action_ = FALSE; 700         } 701     /* Check if this is the initial SYN packet. */ 702     if (seqno == 0) { 703         if (syn_) { 704             databytes = 0; 705             if (maxseq_ == -1) { 706                 curseq_ += 1; /*increment only on initial SYN*/ 707             } 708             hdr_cmn::access(p)->size() = tcpip_base_hdr_size_; 709             ++syn_connects_; 710             //fprintf(stderr, "TCPAgent: syn_connects_ %d max_connects_ %d\n", 711             //    syn_connects_, max_connects_); 712             if (max_connects_ > 0 && 713                                syn_connects_ > max_connects_) { 714                   // Abort the connection.     715                   // What is the best way to abort the connection?     716                   curseq_ = 0; 717                           rtx_timer_.resched(10000); 718                               return; 719                         } 720         } 721         if (ecn_) { 722             hf->ecnecho() = 1; 723 //            hf->cong_action() = 1; 724             hf->ect() = 0; 725         } 726         if (qs_enabled_) { 727             hdr_qs *qsh = hdr_qs::access(p); 728  729             // dataout is kilobytes queued for sending 730             int dataout = (curseq_ - maxseq_ - 1) * (size_ + headersize()) / 1024; 731             int qs_rr = rate_request_; 732             if (qs_request_mode_ == 1 && qs_rtt_ > 0) { 733                 // PS: Avoid making unnecessary QS requests 734                 // use a rough estimation of RTT in qs_rtt_ 735                 // to calculate the desired rate from dataout. 736                 // printf("dataout %d qs_rr %d qs_rtt_ %d\n", 737                 //    dataout, qs_rr, qs_rtt_); 738                 if (dataout * 1000 / qs_rtt_ < qs_rr) { 739                     qs_rr = dataout * 1000 / qs_rtt_; 740                 } 741                 // printf("request %d\n", qs_rr); 742                 // qs_thresh_ is minimum number of unsent 743                 // segments needed to activate QS request 744                 // printf("curseq_ %d maxseq_ %d qs_thresh_ %d\n", 745                 //     int(curseq_), int(maxseq_), qs_thresh_); 746                 if ((curseq_ - maxseq_ - 1) < qs_thresh_) { 747                     qs_rr = 0; 748                 } 749             }  750  751                 if (qs_rr > 0) { 752                 if (print_request_)  753                     printf("QS request (before encoding): %d KBps\n", qs_rr); 754                 // QuickStart code from Srikanth Sundarrajan. 755                 qsh->flag() = QS_REQUEST; 756                 qsh->ttl() = Random::integer(256); 757                 ttl_diff_ = (iph->ttl() - qsh->ttl()) % 256; 758                 qsh->rate() = hdr_qs::Bps_to_rate(qs_rr * 1024); 759                 qs_requested_ = 1; 760                 } else { 761                 qsh->flag() = QS_DISABLE; 762             } 763         } 764     } 765     else if (useHeaders_ == true) { 766         hdr_cmn::access(p)->size() += headersize(); 767     } 768         hdr_cmn::access(p)->size(); 769  770     /* if no outstanding data, be sure to set rtx timer again */ 771     if (highest_ack_ == maxseq_) 772         force_set_rtx_timer = 1; 773     /* call helper function to fill in additional fields */ 774     output_helper(p); 775  776         ++ndatapack_; 777         ndatabytes_ += databytes; 778     send(p, 0); 779     if (seqno == curseq_ && seqno > maxseq_) 780         idle();  // Tell application I have sent everything so far 781     if (seqno > maxseq_) { 782         maxseq_ = seqno; 783         if (!rtt_active_) { 784             rtt_active_ = 1; 785             if (seqno > rtt_seq_) { 786                 rtt_seq_ = seqno; 787                 rtt_ts_ = Scheduler::instance().clock(); 788             } 789                      790         } 791     } else { 792             ++nrexmitpack_; 793         nrexmitbytes_ += databytes; 794     } 795     if (!(rtx_timer_.status() == TIMER_PENDING) || force_set_rtx_timer) 796         /* No timer pending.  Schedule one. */ 797         set_rtx_timer(); 798 } 799  800 /* 801  * Must convert bytes into packets for one-way TCPs. 802  * If nbytes == -1, this corresponds to infinite send.  We approximate 803  * infinite by a very large number (TCP_MAXSEQ). 804  */ 805 void TcpAgent::sendmsg(int nbytes, const char* /*flags*/) 806 { 807     if (nbytes == -1 && curseq_ <= TCP_MAXSEQ) 808         curseq_ = TCP_MAXSEQ;  809     else 810         curseq_ += (nbytes/size_ + (nbytes%size_ ? 1 : 0)); 811     send_much(0, 0, maxburst_); 812 } 813  814 void TcpAgent::advanceby(int delta) 815 { 816   curseq_ += delta; 817     if (delta > 0) 818         closed_ = 0; 819     send_much(0, 0, maxburst_);  820 } 821  822  823 int TcpAgent::command(int argc, const char*const* argv) 824 { 825     if (argc == 3) { 826         if (strcmp(argv[1], "advance") == 0) { 827             int newseq = atoi(argv[2]); 828             if (newseq > maxseq_) 829                 advanceby(newseq - curseq_); 830             else 831                 advanceby(maxseq_ - curseq_); 832             return (TCL_OK); 833         } 834         if (strcmp(argv[1], "advanceby") == 0) { 835             advanceby(atoi(argv[2])); 836             return (TCL_OK); 837         } 838         if (strcmp(argv[1], "eventtrace") == 0) { 839             et_ = (EventTrace *)TclObject::lookup(argv[2]); 840             return (TCL_OK); 841         } 842         /* 843          * Curtis Villamizar‘s trick to transfer tcp connection 844          * parameters to emulate http persistent connections. 845          * 846          * Another way to do the same thing is to open one tcp 847          * object and use start/stop/maxpkts_ or advanceby to control 848          * how much data is sent in each burst. 849          * With a single connection, slow_start_restart_ 850          * should be configured as desired. 851          * 852          * This implementation (persist) may not correctly 853          * emulate pure-BSD-based systems which close cwnd 854          * after the connection goes idle (slow-start 855          * restart).  See appendix C in 856          * Jacobson and Karels ``Congestion 857          * Avoidance and Control‘‘ at 858          * <ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z> 859          * (*not* the original 860          * ‘88 paper) for why BSD does this.  See 861          * ``Performance Interactions Between P-HTTP and TCP 862          * Implementations‘‘ in CCR 27(2) for descriptions of 863          * what other systems do the same. 864          * 865          */ 866         if (strcmp(argv[1], "persist") == 0) { 867             TcpAgent *other 868               = (TcpAgent*)TclObject::lookup(argv[2]); 869             cwnd_ = other->cwnd_; 870             awnd_ = other->awnd_; 871             ssthresh_ = other->ssthresh_; 872             t_rtt_ = other->t_rtt_; 873             t_srtt_ = other->t_srtt_; 874             t_rttvar_ = other->t_rttvar_; 875             t_backoff_ = other->t_backoff_; 876             return (TCL_OK); 877         } 878     } 879     return (Agent::command(argc, argv)); 880 } 881  882 /* 883  * Returns the window size adjusted to allow <num> segments past recovery 884  * point to be transmitted on next ack. 885  */ 886 int TcpAgent::force_wnd(int num) 887 { 888     return recover_ + num - (int)highest_ack_; 889 } 890  891 int TcpAgent::window() 892 { 893         /* 894          * If F-RTO is enabled and first ack has come in, temporarily open 895          * window for sending two segments. 896      * The F-RTO code is from Pasi Sarolahti.  F-RTO is an algorithm 897      * for detecting spurious retransmission timeouts. 898          */ 899         if (frto_ == 2) { 900                 return (force_wnd(2) < wnd_ ? 901                         force_wnd(2) : (int)wnd_); 902         } else { 903         return (cwnd_ < wnd_ ? (int)cwnd_ : (int)wnd_); 904         } 905 } 906  907 double TcpAgent::windowd() 908 { 909     return (cwnd_ < wnd_ ? (double)cwnd_ : (double)wnd_); 910 } 911  912 /* 913  * Try to send as much data as the window will allow.  The link layer will  914  * do the buffering; we ask the application layer for the size of the packets. 915  */ 916 void TcpAgent::send_much(int force, int reason, int maxburst) 917 { 918     send_idle_helper(); 919     int win = window(); 920     int npackets = 0; 921  922     if (!force && delsnd_timer_.status() == TIMER_PENDING) 923         return; 924     /* Save time when first packet was sent, for newreno  --Allman */ 925     if (t_seqno_ == 0) 926         firstsent_ = Scheduler::instance().clock(); 927  928     if (burstsnd_timer_.status() == TIMER_PENDING) 929         return; 930     while (t_seqno_ <= highest_ack_ + win && t_seqno_ < curseq_) { 931         if (overhead_ == 0 || force || qs_approved_) { 932             output(t_seqno_, reason); 933             npackets++; 934             if (QOption_) 935                 process_qoption_after_send () ;  936             t_seqno_ ++ ; 937             if (qs_approved_ == 1) { 938                 // delay = effective RTT / window 939                 double delay = (double) t_rtt_ * tcp_tick_ / win; 940                 if (overhead_) {  941                     delsnd_timer_.resched(delay + Random::uniform(overhead_)); 942                 } else { 943                     delsnd_timer_.resched(delay); 944                 } 945                 return; 946             } 947         } else if (!(delsnd_timer_.status() == TIMER_PENDING)) { 948             /* 949              * Set a delayed send timeout. 950              */ 951             delsnd_timer_.resched(Random::uniform(overhead_)); 952             return; 953         } 954         win = window(); 955         if (maxburst && npackets == maxburst) 956             break; 957     } 958     /* call helper function */ 959     send_helper(maxburst); 960 } 961  962 /* 963  * We got a timeout or too many duplicate acks.  Clear the retransmit timer.   964  * Resume the sequence one past the last packet acked.   965  * "mild" is 0 for timeouts and Tahoe dup acks, 1 for Reno dup acks. 966  * "backoff" is 1 if the timer should be backed off, 0 otherwise. 967  */ 968 void TcpAgent::reset_rtx_timer(int mild, int backoff) 969 { 970     if (backoff) 971         rtt_backoff(); 972     set_rtx_timer(); 973     if (!mild) 974         t_seqno_ = highest_ack_ + 1; 975     rtt_active_ = 0; 976 } 977  978 /* 979  * Set retransmit timer using current rtt estimate.  By calling resched(),  980  * it does not matter whether the timer was already running. 981  */ 982 void TcpAgent::set_rtx_timer() 983 { 984     rtx_timer_.resched(rtt_timeout()); 985 } 986  987 /* 988  * Set new retransmission timer if not all outstanding 989  * or available data acked, or if we are unable to send because  990  * cwnd is less than one (as when the ECN bit is set when cwnd was 1). 991  * Otherwise, if a timer is still outstanding, cancel it. 992  */ 993 void TcpAgent::newtimer(Packet* pkt) 994 { 995     hdr_tcp *tcph = hdr_tcp::access(pkt); 996     /* 997      * t_seqno_, the next packet to send, is reset (decreased)  998      *   to highest_ack_ + 1 after a timeout, 999      *   so we also have to check maxseq_, the highest seqno sent.1000      * In addition, if the packet sent after the timeout has1001      *   the ECN bit set, then the returning ACK caused cwnd_ to1002      *   be decreased to less than one, and we can‘t send another1003      *   packet until the retransmit timer again expires.1004      *   So we have to check for "cwnd_ < 1" as well.1005      */1006     if (t_seqno_ > tcph->seqno() || tcph->seqno() < maxseq_ || cwnd_ < 1) 1007         set_rtx_timer();1008     else1009         cancel_rtx_timer();1010 }1011 1012 /*1013  * for experimental, high-speed TCP1014  */1015 double TcpAgent::linear(double x, double x_1, double y_1, double x_2, double y_2)1016 {1017     // The y coordinate factor ranges from y_1 to y_21018     //  as the x coordinate ranges from x_1 to x_2.1019     double y = y_1 + ((y_2 - y_1) * ((x - x_1)/(x_2-x_1)));1020     return y;1021 }1022 1023 /*1024  * Limited Slow-Start for large congestion windows.1025  * This should only be called when max_ssthresh_ is non-zero.1026  */1027 double TcpAgent::limited_slow_start(double cwnd, int max_ssthresh, double increment)1028 {1029         if (max_ssthresh <= 0) {1030           return increment;1031     } else {1032                 double increment1 = 0.0;1033         int round = int(cwnd / (double(max_ssthresh)/2.0));1034         if (round > 0) {1035               increment1 = 1.0/double(round); 1036         } 1037         if (increment < increment1) {1038               return increment1;1039         } else {1040               return increment;1041         }1042     }1043 }1044 1045 /*1046  * For retrieving numdupacks_.1047  */1048 int TcpAgent::numdupacks(double cwnd)1049 {1050         int cwndfraction = (int) cwnd/numdupacksFrac_;1051     if (numdupacks_ > cwndfraction) {1052           return numdupacks_;1053         } else {1054           return cwndfraction;1055     }1056 }1057 1058 /*1059  * Calculating the decrease parameter for highspeed TCP.1060  */1061 double TcpAgent::decrease_param()1062 {1063     double decrease;1064     // OLD:1065     // decrease = linear(log(cwnd_), log(low_window_), 0.5, log(high_window_), high_decrease_);1066     // NEW (but equivalent):1067         decrease = hstcp_.dec1 + log(cwnd_) * hstcp_.dec2;  1068     return decrease;1069 }1070 1071 /*1072  * Calculating the increase parameter for highspeed TCP.1073  */1074 double TcpAgent::increase_param()1075 {1076     double increase, decrease, p, answer;1077     /* extending the slow-start for high-speed TCP */1078 1079     /* for highspeed TCP -- from Sylvia Ratnasamy, */1080     /* modifications by Sally Floyd and Evandro de Souza */1081      // p ranges from 1.5/W^2 at congestion window low_window_, to1082     //    high_p_ at congestion window high_window_, on a log-log scale.1083         // The decrease factor ranges from 0.5 to high_decrease1084     //  as the window ranges from low_window to high_window, 1085     //  as the log of the window. 1086     // For an efficient implementation, this would just be looked up1087     //   in a table, with the increase and decrease being a function of the1088     //   congestion window.1089 1090        if (cwnd_ <= low_window_) { 1091         answer = 1 / cwnd_;1092                return answer; 1093        } else if (cwnd_ >= hstcp_.cwnd_last_ && 1094           cwnd_ < hstcp_.cwnd_last_ + cwnd_range_) {1095           // cwnd_range_ can be set to 0 to be disabled,1096           //  or can be set from 1 to 100 1097                answer = hstcp_.increase_last_ / cwnd_;1098                   return answer;1099        } else { 1100         // OLD:1101          // p = exp(linear(log(cwnd_), log(low_window_), log(hstcp_.low_p), log(high_window_), log(high_p_)));1102         // NEW, but equivalent:1103             p = exp(hstcp_.p1 + log(cwnd_) * hstcp_.p2);  1104             decrease = decrease_param();1105         // OLD:1106         // increase = cwnd_*cwnd_*p *(2.0*decrease)/(2.0 - decrease); 1107         // NEW, but equivalent:1108         increase = cwnd_ * cwnd_ * p /(1/decrease - 0.5);1109         //    if (increase > max_increase) { 1110         //        increase = max_increase;1111         //    } 1112         answer = increase / cwnd_;1113         hstcp_.cwnd_last_ = cwnd_;1114         hstcp_.increase_last_ = increase;1115                return answer;1116     }       1117 }1118 1119 /*1120  * open up the congestion window1121  */1122 void TcpAgent::opencwnd()1123 {1124     double increment;1125     if (cwnd_ < ssthresh_) {1126         /* slow-start (exponential) */1127         cwnd_ += 1;1128     } else {1129         /* linear */1130         double f;1131         switch (wnd_option_) {1132         case 0:1133             if (++count_ >= cwnd_) {1134                 count_ = 0;1135                 ++cwnd_;1136             }1137             break;1138 1139         case 1:1140             /* This is the standard algorithm. */1141             increment = increase_num_ / cwnd_;1142             if ((last_cwnd_action_ == 0 ||1143               last_cwnd_action_ == CWND_ACTION_TIMEOUT) 1144               && max_ssthresh_ > 0) {1145                 increment = limited_slow_start(cwnd_,1146                   max_ssthresh_, increment);1147             }1148             cwnd_ += increment;1149             break;1150 1151         case 2:1152             /* These are window increase algorithms1153              * for experimental purposes only. */1154             /* This is the Constant-Rate increase algorithm 1155                          *  from the 1991 paper by S. Floyd on "Connections  1156              *  with Multiple Congested Gateways". 1157              *  The window is increased by roughly 1158              *  wnd_const_*RTT^2 packets per round-trip time.  */1159             f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;1160             f *= f;1161             f *= wnd_const_;1162             /* f = wnd_const_ * RTT^2 */1163             f += fcnt_;1164             if (f > cwnd_) {1165                 fcnt_ = 0;1166                 ++cwnd_;1167             } else1168                 fcnt_ = f;1169             break;1170 1171         case 3:1172             /* The window is increased by roughly 1173              *  awnd_^2 * wnd_const_ packets per RTT,1174              *  for awnd_ the average congestion window. */1175             f = awnd_;1176             f *= f;1177             f *= wnd_const_;1178             f += fcnt_;1179             if (f > cwnd_) {1180                 fcnt_ = 0;1181                 ++cwnd_;1182             } else1183                 fcnt_ = f;1184             break;1185 1186                 case 4:1187             /* The window is increased by roughly 1188              *  awnd_ * wnd_const_ packets per RTT,1189              *  for awnd_ the average congestion window. */1190                         f = awnd_;1191                         f *= wnd_const_;1192                         f += fcnt_;1193                         if (f > cwnd_) {1194                                 fcnt_ = 0;1195                                 ++cwnd_;1196                         } else1197                                 fcnt_ = f;1198                         break;1199         case 5:1200             /* The window is increased by roughly wnd_const_*RTT 1201              *  packets per round-trip time, as discussed in1202              *  the 1992 paper by S. Floyd on "On Traffic 1203              *  Phase Effects in Packet-Switched Gateways". */1204                         f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;1205                         f *= wnd_const_;1206                         f += fcnt_;1207                         if (f > cwnd_) {1208                                 fcnt_ = 0;1209                                 ++cwnd_;1210                         } else1211                                 fcnt_ = f;1212                         break;1213                 case 6:1214                         /* binomial controls */ 1215                         cwnd_ += increase_num_ / (cwnd_*pow(cwnd_,k_parameter_));                1216                         break; 1217          case 8: 1218             /* high-speed TCP, RFC 3649 */1219             increment = increase_param();1220             if ((last_cwnd_action_ == 0 ||1221               last_cwnd_action_ == CWND_ACTION_TIMEOUT) 1222               && max_ssthresh_ > 0) {1223                 increment = limited_slow_start(cwnd_,1224                   max_ssthresh_, increment);1225             }1226             cwnd_ += increment;1227                         break;1228         default:1229 #ifdef notdef1230             /*XXX*/1231             error("illegal window option %d", wnd_option_);1232 #endif1233             abort();1234         }1235     }1236     // if maxcwnd_ is set (nonzero), make it the cwnd limit1237     if (maxcwnd_ && (int(cwnd_) > maxcwnd_))1238         cwnd_ = maxcwnd_;1239 1240     return;1241 }1242 1243 // Shigeyuki Osada 2012/01/081244 void TcpAgent::recv_helper(Packet* pkt)1245 {1246     hdr_tcp *tcph = hdr_tcp::access(pkt);1247      //double now = Scheduler::instance().clock();1248     //hdr_ip *iph   = hdr_ip::access(pkt);1249     //cout << now << ": Server recv pkt with win "1250     //     << tcph->wnd() 1251     //     << " seqno: "  << tcph->seqno()1252     //     << " nodeid: " << iph->daddr() 1253     //     << "\n";1254     if (tcph->wnd() > 0) {1255         // wnd == 0 can be occuerd but this is not considered.1256         // future works. Shigeyuki Osada 2012/01/081257         wnd_ = tcph->wnd();1258     }1259     return;1260 }1261 1262 void1263 TcpAgent::slowdown(int how)1264 {1265     double decrease;  /* added for highspeed - sylvia */1266     double win, halfwin, decreasewin;1267     int slowstart = 0;1268     ++ncwndcuts_;1269     if (!(how & TCP_IDLE) && !(how & NO_OUTSTANDING_DATA)){1270         ++ncwndcuts1_; 1271     }1272     // we are in slowstart for sure if cwnd < ssthresh1273     if (cwnd_ < ssthresh_) 1274         slowstart = 1;1275         if (precision_reduce_) {1276         halfwin = windowd() / 2;1277                 if (wnd_option_ == 6) {         1278                         /* binomial controls */1279                         decreasewin = windowd() - (1.0-decrease_num_)*pow(windowd(),l_parameter_);1280                 } else if (wnd_option_ == 8 && (cwnd_ > low_window_)) { 1281                         /* experimental highspeed TCP */1282             decrease = decrease_param();1283             //if (decrease < 0.1) 1284             //    decrease = 0.1;1285             decrease_num_ = decrease;1286                         decreasewin = windowd() - (decrease * windowd());1287                 } else {1288              decreasewin = decrease_num_ * windowd();1289         }1290         win = windowd();1291     } else  {1292         int temp;1293         temp = (int)(window() / 2);1294         halfwin = (double) temp;1295                 if (wnd_option_ == 6) {1296                         /* binomial controls */1297                         temp = (int)(window() - (1.0-decrease_num_)*pow(window(),l_parameter_));1298                 } else if ((wnd_option_ == 8) && (cwnd_ > low_window_)) { 1299                         /* experimental highspeed TCP */1300             decrease = decrease_param();1301             //if (decrease < 0.1)1302                         //       decrease = 0.1;        1303             decrease_num_ = decrease;1304                         temp = (int)(windowd() - (decrease * windowd()));1305                 } else {1306              temp = (int)(decrease_num_ * window());1307         }1308         decreasewin = (double) temp;1309         win = (double) window();1310     }1311     if (how & CLOSE_SSTHRESH_HALF)1312         // For the first decrease, decrease by half1313         // even for non-standard values of decrease_num_.1314         if (first_decrease_ == 1 || slowstart ||1315             last_cwnd_action_ == CWND_ACTION_TIMEOUT) {1316             // Do we really want halfwin instead of decreasewin1317         // after a timeout?1318             ssthresh_ = (int) halfwin;1319         } else {1320             ssthresh_ = (int) decreasewin;1321         }1322         else if (how & THREE_QUARTER_SSTHRESH)1323         if (ssthresh_ < 3*cwnd_/4)1324             ssthresh_  = (int)(3*cwnd_/4);1325     if (how & CLOSE_CWND_HALF)1326         // For the first decrease, decrease by half1327         // even for non-standard values of decrease_num_.1328         if (first_decrease_ == 1 || slowstart || decrease_num_ == 0.5) {1329             cwnd_ = halfwin;1330         } else cwnd_ = decreasewin;1331         else if (how & CWND_HALF_WITH_MIN) {1332         // We have not thought about how non-standard TCPs, with1333         // non-standard values of decrease_num_, should respond1334         // after quiescent periods.1335                 cwnd_ = decreasewin;1336                 if (cwnd_ < 1)1337                         cwnd_ = 1;1338     }1339     else if (how & CLOSE_CWND_RESTART) 1340         cwnd_ = int(wnd_restart_);1341     else if (how & CLOSE_CWND_INIT)1342         cwnd_ = int(wnd_init_);1343     else if (how & CLOSE_CWND_ONE)1344         cwnd_ = 1;1345     else if (how & CLOSE_CWND_HALF_WAY) {1346         // cwnd_ = win - (win - W_used)/2 ;1347         cwnd_ = W_used + decrease_num_ * (win - W_used);1348                 if (cwnd_ < 1)1349                         cwnd_ = 1;1350     }1351     if (ssthresh_ < 2)1352         ssthresh_ = 2;1353     if (how & (CLOSE_CWND_HALF|CLOSE_CWND_RESTART|CLOSE_CWND_INIT|CLOSE_CWND_ONE))1354         cong_action_ = TRUE;1355 1356     fcnt_ = count_ = 0;1357     if (first_decrease_ == 1)1358         first_decrease_ = 0;1359     // for event tracing slow start1360     if (cwnd_ == 1 || slowstart) 1361         // Not sure if this is best way to capture slow_start1362         // This is probably tracing a superset of slowdowns of1363         // which all may not be slow_start‘s --Padma, 07/‘01.1364         trace_event("SLOW_START");1365     1366 1367 1368     1369 }1370 1371 /*1372  * Process a packet that acks previously unacknowleged data.1373  */1374 void TcpAgent::newack(Packet* pkt)1375 {1376      double now = Scheduler::instance().clock();1377     hdr_tcp *tcph = hdr_tcp::access(pkt);1378     /* 1379      * Wouldn‘t it be better to set the timer *after*1380      * updating the RTT, instead of *before*? 1381      */1382     if (!timerfix_) newtimer(pkt);1383     dupacks_ = 0;1384     last_ack_ = tcph->seqno();1385     prev_highest_ack_ = highest_ack_ ;1386     highest_ack_ = last_ack_;1387 1388     if (t_seqno_ < last_ack_ + 1)1389         t_seqno_ = last_ack_ + 1;1390     /* 1391      * Update RTT only if it‘s OK to do so from info in the flags header.1392      * This is needed for protocols in which intermediate agents1393      * in the network intersperse acks (e.g., ack-reconstructors) for1394      * various reasons (without violating e2e semantics).1395      */    1396     hdr_flags *fh = hdr_flags::access(pkt);1397     if (!fh->no_ts_) {1398         if (ts_option_) {1399             ts_echo_=tcph->ts_echo();1400             rtt_update(now - tcph->ts_echo());1401             if (ts_resetRTO_ && (!ect_ || !ecn_backoff_ ||1402                 !hdr_flags::access(pkt)->ecnecho())) { 1403                 // From Andrei Gurtov1404                 /* 1405                  * Don‘t end backoff if still in ECN-Echo with1406                   * a congestion window of 1 packet. 1407                  */1408                 t_backoff_ = 1;1409                 ecn_backoff_ = 0;1410             }1411         }1412         if (rtt_active_ && tcph->seqno() >= rtt_seq_) {1413             if (!ect_ || !ecn_backoff_ || 1414                 !hdr_flags::access(pkt)->ecnecho()) {1415                 /* 1416                  * Don‘t end backoff if still in ECN-Echo with1417                   * a congestion window of 1 packet. 1418                  */1419                 t_backoff_ = 1;1420                 ecn_backoff_ = 0;1421             }1422             rtt_active_ = 0;1423             if (!ts_option_)1424                 rtt_update(now - rtt_ts_);1425         }1426     }1427     if (timerfix_) newtimer(pkt);1428     /* update average window */1429     awnd_ *= 1.0 - wnd_th_;1430     awnd_ += wnd_th_ * cwnd_;1431 }1432 1433 1434 /*1435  * Respond either to a source quench or to a congestion indication bit.1436  * This is done at most once a roundtrip time;  after a source quench,1437  * another one will not be done until the last packet transmitted before1438  * the previous source quench has been ACKed.1439  *1440  * Note that this procedure is called before "highest_ack_" is1441  * updated to reflect the current ACK packet.  1442  */1443 void TcpAgent::ecn(int seqno)1444 {1445     if (seqno > recover_ || 1446           last_cwnd_action_ == CWND_ACTION_TIMEOUT) {1447         recover_ =  maxseq_;1448         last_cwnd_action_ = CWND_ACTION_ECN;1449         if (cwnd_ <= 1.0) {1450             if (ecn_backoff_) 1451                 rtt_backoff();1452             else ecn_backoff_ = 1;1453         } else ecn_backoff_ = 0;1454         slowdown(CLOSE_CWND_HALF|CLOSE_SSTHRESH_HALF);1455         ++necnresponses_ ;1456         // added by sylvia to count number of ecn responses 1457     }1458 }1459 1460 /*1461  *  Is the connection limited by the network (instead of by a lack1462  *    of data from the application?1463  */1464 int TcpAgent::network_limited() {1465     int win = window () ;1466     if (t_seqno_ > (prev_highest_ack_ + win))1467         return 1;1468     else1469         return 0;1470 }1471 1472 void TcpAgent::recv_newack_helper(Packet *pkt) {1473     //hdr_tcp *tcph = hdr_tcp::access(pkt);1474     newack(pkt);1475         if (qs_window_ && highest_ack_ >= qs_window_) {1476                 // All segments in the QS window have been acknowledged.1477                 // We can exit the Quick-Start phase.1478                 qs_window_ = 0;1479         }1480     if (!ect_ || !hdr_flags::access(pkt)->ecnecho() ||1481         (old_ecn_ && ecn_burst_)) {1482         /* If "old_ecn", this is not the first ACK carrying ECN-Echo1483          * after a period of ACKs without ECN-Echo.1484          * Therefore, open the congestion window. */1485         /* if control option is set, and the sender is not1486              window limited, then do not increase the window size */1487         1488         if (!control_increase_ || 1489            (control_increase_ && (network_limited() == 1))) 1490                   opencwnd();1491     }1492     if (ect_) {1493         if (!hdr_flags::access(pkt)->ecnecho())1494             ecn_backoff_ = 0;1495         if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho())1496             ecn_burst_ = TRUE;1497         else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho())1498             ecn_burst_ = FALSE;1499     }1500     if (!ect_ && hdr_flags::access(pkt)->ecnecho() &&1501         !hdr_flags::access(pkt)->cong_action())1502         ect_ = 1;1503     /* if the connection is done, call finish() */1504     if ((highest_ack_ >= curseq_-1) && !closed_) {1505         closed_ = 1;1506         finish();1507     }1508     if (QOption_ && curseq_ == highest_ack_ +1) {1509         cancel_rtx_timer();1510     }1511     if (frto_ == 1) {1512         /*1513          * New ack after RTO. If F-RTO is enabled, try to transmit new1514          * previously unsent segments.1515          * If there are no new data or receiver window limits the1516          * transmission, revert to traditional recovery.1517          */1518         if (recover_ + 1 >= highest_ack_ + wnd_ ||1519             recover_ + 1 >= curseq_) {1520             frto_ = 0;1521          } else if (highest_ack_ == recover_) {1522              /*1523               * F-RTO step 2a) RTO retransmission fixes whole1524              * window => cancel F-RTO1525               */1526              frto_ = 0;1527         } else {1528             t_seqno_ = recover_ + 1;1529             frto_ = 2;1530         }1531     } else if (frto_ == 2) {1532         /*1533          * Second new ack after RTO. If F-RTO is enabled, RTO can be1534          * declared spurious1535          */1536         spurious_timeout();1537     }1538 }1539 1540 /*1541  * Set the initial window. 1542  */1543 double1544 TcpAgent::initial_window()1545 {1546         // If Quick-Start Request was approved, use that as a basis for1547         // initial window1548         if (qs_cwnd_) {1549                 return (qs_cwnd_);1550         }1551     //1552     // init_option = 1: static iw of wnd_init_1553     //1554     if (wnd_init_option_ == 1) {1555         return (wnd_init_);1556     }1557         else if (wnd_init_option_ == 2) {1558         // do iw according to Internet draft1559          if (size_ <= 1095) {1560             return (4.0);1561          } else if (size_ < 2190) {1562             return (3.0);1563         } else {1564             return (2.0);1565         }1566     }1567     // XXX what should we return here???1568     fprintf(stderr, "Wrong number of wnd_init_option_ %d\n", 1569         wnd_init_option_);1570     abort();1571     return (2.0); // XXX make msvc happy.1572 }1573 1574 /*1575  * Dupack-action: what to do on a DUP ACK.  After the initial check1576  * of ‘recover‘ below, this function implements the following truth1577  * table:1578  *1579  *    bugfix    ecn    last-cwnd == ecn    action1580  *1581  *    0    0    0            tahoe_action1582  *    0    0    1            tahoe_action    [impossible]1583  *    0    1    0            tahoe_action1584  *    0    1    1            slow-start, return1585  *    1    0    0            nothing1586  *    1    0    1            nothing        [impossible]1587  *    1    1    0            nothing1588  *    1    1    1            slow-start, return1589  */1590 1591 /* 1592  * A first or second duplicate acknowledgement has arrived, and1593  * singledup_ is enabled.1594  * If the receiver‘s advertised window permits, and we are exceeding our1595  * congestion window by less than numdupacks_, then send a new packet.1596  */1597 void1598 TcpAgent::send_one()1599 {1600     if (t_seqno_ <= highest_ack_ + wnd_ && t_seqno_ < curseq_ &&1601         t_seqno_ <= highest_ack_ + cwnd_ + dupacks_ ) {1602         output(t_seqno_, 0);1603         if (QOption_)1604             process_qoption_after_send () ;1605         t_seqno_ ++ ;1606         // send_helper(); ??1607     }1608     return;1609 }1610 1611 void1612 TcpAgent::dupack_action()1613 {1614     int recovered = (highest_ack_ > recover_);1615     if (recovered || (!bug_fix_ && !ecn_) || 1616         (bugfix_ss_ && highest_ack_ == 0)) {1617         // (highest_ack_ == 0) added to allow Fast Retransmit1618         //  when the first data packet is dropped.1619         //  Bug report from Mark Allman.1620         goto tahoe_action;1621     }1622 1623     if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {1624         last_cwnd_action_ = CWND_ACTION_DUPACK;1625         slowdown(CLOSE_CWND_ONE);1626         reset_rtx_timer(0,0);1627         return;1628     }1629 1630     if (bug_fix_) {1631         /*1632          * The line below, for "bug_fix_" true, avoids1633          * problems with multiple fast retransmits in one1634          * window of data. 1635          */1636         return;1637     }1638 1639 tahoe_action:1640         recover_ = maxseq_;1641         if (!lossQuickStart()) {1642         // we are now going to fast-retransmit and willtrace that event1643         trace_event("FAST_RETX");1644         last_cwnd_action_ = CWND_ACTION_DUPACK;1645         slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_ONE);1646     }1647     reset_rtx_timer(0,0);1648     return;1649 }1650 1651 /*1652  * When exiting QuickStart, reduce the congestion window to the1653  *   size that was actually used.1654  */1655 void TcpAgent::endQuickStart()1656 {1657     qs_approved_ = 0;1658         qs_cwnd_ = 0;1659         qs_window_ = maxseq_;1660     int new_cwnd = maxseq_ - last_ack_;1661     if (new_cwnd > 1 && new_cwnd < cwnd_) {1662          cwnd_ = new_cwnd;1663         if (cwnd_ < initial_window()) 1664             cwnd_ = initial_window();1665     }1666 }1667 1668 void TcpAgent::processQuickStart(Packet *pkt)1669 {1670     // QuickStart code from Srikanth Sundarrajan.1671     hdr_tcp *tcph = hdr_tcp::access(pkt);1672     hdr_qs *qsh = hdr_qs::access(pkt);1673     double now = Scheduler::instance().clock();1674     int app_rate;1675 1676         // printf("flag: %d ttl: %d ttl_diff: %d rate: %d\n", qsh->flag(),1677     //     qsh->ttl(), ttl_diff_, qsh->rate());1678     qs_requested_ = 0;1679     qs_approved_ = 0;1680     if (qsh->flag() == QS_RESPONSE && qsh->ttl() == ttl_diff_ && 1681             qsh->rate() > 0) {1682                 app_rate = (int) ((hdr_qs::rate_to_Bps(qsh->rate()) *1683                       (now - tcph->ts_echo())) / (size_ + headersize()));1684         if (print_request_) {1685           double num1 = hdr_qs::rate_to_Bps(qsh->rate());1686           double time = now - tcph->ts_echo();1687           int size = size_ + headersize();1688           printf("Quick Start request, rate: %g Bps, encoded rate: %d\n", 1689              num1, qsh->rate());1690           printf("Quick Start request, window %d rtt: %4.2f pktsize: %d\n",1691              app_rate, time, size);1692         }1693                 if (app_rate > initial_window()) {1694             qs_cwnd_ = app_rate;1695                         qs_approved_ = 1;1696                 }1697         } else { // Quick Start rejected1698 #ifdef QS_DEBUG1699                 printf("Quick Start rejected\n");1700 #endif1701         }1702 1703 }1704 1705 1706 1707 /*1708  * ACK has been received, hook from recv()1709  */1710 void TcpAgent::recv_frto_helper(Packet *pkt)1711 {1712     hdr_tcp *tcph = hdr_tcp::access(pkt);1713     if (tcph->seqno() == last_ack_ && frto_ != 0) {1714         /*1715          * Duplicate ACK while in F-RTO indicates that the1716          * timeout was valid. Go to slow start retransmissions.1717          */1718         t_seqno_ = highest_ack_ + 1;1719         cwnd_ = frto_;1720         frto_ = 0;1721 1722         // Must zero dupacks (in order to trigger send_much at recv)1723         // dupacks is increased in recv after exiting this function1724         dupacks_ = -1;1725     }1726 }1727 1728 1729 /*1730  * A spurious timeout has been detected. Do appropriate actions.1731  */1732 void TcpAgent::spurious_timeout()1733 {1734     frto_ = 0;1735 1736     switch (spurious_response_) {1737     case 1:1738     default:1739         /*1740          * Full revert of congestion window1741          * (FlightSize before last acknowledgment)1742          */1743         cwnd_ = t_seqno_ - prev_highest_ack_;1744         break;1745  1746     case 2:1747         /*1748          * cwnd = reduced ssthresh (approx. half of the earlier pipe)1749          */1750         cwnd_ = ssthresh_; break;1751     case 3:1752         /*1753          * slow start, but without retransmissions1754          */1755         cwnd_ = 1; break;1756     }1757 1758     /*1759      * Revert ssthresh to size before retransmission timeout1760      */1761     ssthresh_ = pipe_prev_;1762 1763     /* If timeout was spurious, bugfix is not needed */1764     recover_ = highest_ack_ - 1;1765 }1766 1767 1768 /*1769  * Loss occurred in Quick-Start window.1770  * If Quick-Start is enabled, packet loss in the QS phase, during slow-start,1771  * should trigger slow start instead of the regular fast retransmit.1772  * We use variable tcp_qs_recovery_ to toggle this behaviour on and off.1773  * If tcp_qs_recovery_ is true, initiate slow start to probe for1774  * a correct window size.1775  *1776  * Return value: non-zero if Quick-Start specific loss recovery took place1777  */1778 int TcpAgent::lossQuickStart()1779 {1780        if (qs_window_ && tcp_qs_recovery_) {1781                 //recover_ = maxseq_;1782                 //reset_rtx_timer(1,0);1783                 slowdown(CLOSE_CWND_INIT);1784         // reset ssthresh to half of W-D/2?1785                 qs_window_ = 0;1786                 output(last_ack_ + 1, TCP_REASON_DUPACK);1787                 return 1;1788        }1789        return 0;1790 }1791 1792 1793 1794 1795 /*1796  * main reception path - should only see acks, otherwise the1797  * network connections are misconfigured1798  */1799 void TcpAgent::recv(Packet *pkt, Handler*)1800 {1801     hdr_tcp *tcph = hdr_tcp::access(pkt);1802     int valid_ack = 0;1803     if (qs_approved_ == 1 && tcph->seqno() > last_ack_) 1804         endQuickStart();1805     if (qs_requested_ == 1)1806         processQuickStart(pkt);1807 #ifdef notdef1808     if (pkt->type_ != PT_ACK) {1809         Tcl::instance().evalf("%s error \"received non-ack\"",1810                       name());1811         Packet::free(pkt);1812         return;1813     }1814 #endif1815     /* W.N.: check if this is from a previous incarnation */1816     if (tcph->ts() < lastreset_) {1817         // Remove packet and do nothing1818         Packet::free(pkt);1819         return;1820     }1821     ++nackpack_;1822     ts_peer_ = tcph->ts();1823     int ecnecho = hdr_flags::access(pkt)->ecnecho();1824     if (ecnecho && ecn_)1825         ecn(tcph->seqno());1826     recv_helper(pkt);1827     recv_frto_helper(pkt);1828     /* grow cwnd and check if the connection is done */ 1829     if (tcph->seqno() > last_ack_) {1830         recv_newack_helper(pkt);1831         if (last_ack_ == 0 && delay_growth_) { 1832             cwnd_ = initial_window();1833         }1834     } else if (tcph->seqno() == last_ack_) {1835                 if (hdr_flags::access(pkt)->eln_ && eln_) {1836                         tcp_eln(pkt);1837                         return;1838                 }1839         if (++dupacks_ == numdupacks_ && !noFastRetrans_) {1840             dupack_action();1841         } else if (dupacks_ < numdupacks_ && singledup_ ) {1842             send_one();1843         }1844     }1845 1846     if (QOption_ && EnblRTTCtr_)1847         process_qoption_after_ack (tcph->seqno());1848 1849     if (tcph->seqno() >= last_ack_)  1850         // Check if ACK is valid.  Suggestion by Mark Allman. 1851         valid_ack = 1;1852     Packet::free(pkt);1853     /*1854      * Try to send more data.1855      */1856     if (valid_ack || aggressive_maxburst_)1857         send_much(0, 0, maxburst_);1858 }1859 1860 /*1861  * Process timeout events other than rtx timeout. Having this as a separate 1862  * function allows derived classes to make alterations/enhancements (e.g.,1863  * response to new types of timeout events).1864  */ 1865 void TcpAgent::timeout_nonrtx(int tno) 1866 {1867     if (tno == TCP_TIMER_DELSND)  {1868      /*1869          * delayed-send timer, with random overhead1870          * to avoid phase effects1871          */1872         send_much(1, TCP_REASON_TIMEOUT, maxburst_);1873     }1874 }1875     1876 void TcpAgent::timeout(int tno)1877 {1878     /* retransmit timer */1879     if (tno == TCP_TIMER_RTX) {1880 1881         // There has been a timeout - will trace this event1882         trace_event("TIMEOUT");1883 1884         frto_ = 0;1885         // Set pipe_prev as per Eifel Response1886         pipe_prev_ = (window() > ssthresh_) ?1887             window() : (int)ssthresh_;1888 1889             if (cwnd_ < 1) cwnd_ = 1;1890         if (qs_approved_ == 1) qs_approved_ = 0;1891         if (highest_ack_ == maxseq_ && !slow_start_restart_) {1892             /*1893              * TCP option:1894              * If no outstanding data, then don‘t do anything.  1895              */1896              // Should this return be here?1897              // What if CWND_ACTION_ECN and cwnd < 1?1898              // return;1899         } else {1900             recover_ = maxseq_;1901             if (highest_ack_ == -1 && wnd_init_option_ == 2)1902                 /* 1903                  * First packet dropped, so don‘t use larger1904                  * initial windows. 1905                  */1906                 wnd_init_option_ = 1;1907                         else if ((highest_ack_ == -1) &&1908                                 (wnd_init_option_ == 1) && (wnd_init_ > 1)1909                 && bugfix_ss_)1910                                 /*1911                                  * First packet dropped, so don‘t use larger1912                                  * initial windows.  Bugfix from Mark Allman.1913                                  */1914                                 wnd_init_ = 1;1915             if (highest_ack_ == maxseq_ && restart_bugfix_)1916                    /* 1917                 * if there is no outstanding data, don‘t cut 1918                 * down ssthresh_.1919                 */1920                 slowdown(CLOSE_CWND_ONE|NO_OUTSTANDING_DATA);1921             else if (highest_ack_ < recover_ &&1922               last_cwnd_action_ == CWND_ACTION_ECN) {1923                    /*1924                 * if we are in recovery from a recent ECN,1925                 * don‘t cut down ssthresh_.1926                 */1927                 slowdown(CLOSE_CWND_ONE);1928                 if (frto_enabled_ || sfrto_enabled_) {1929                     frto_ = 1;1930                 }1931             }1932             else {1933                 ++nrexmit_;1934                 last_cwnd_action_ = CWND_ACTION_TIMEOUT;1935                 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);1936                 if (frto_enabled_ || sfrto_enabled_) {1937                     frto_ = 1;1938                 }1939             }1940         }1941         /* if there is no outstanding data, don‘t back off rtx timer */1942         if (highest_ack_ == maxseq_ && restart_bugfix_) {1943             reset_rtx_timer(0,0);1944         }1945         else {1946             reset_rtx_timer(0,1);1947         }1948         last_cwnd_action_ = CWND_ACTION_TIMEOUT;1949         send_much(0, TCP_REASON_TIMEOUT, maxburst_);1950     } 1951     else {1952         timeout_nonrtx(tno);1953     }1954 }1955 1956 /* 1957  * Check if the packet (ack) has the ELN bit set, and if it does, and if the1958  * last ELN-rxmitted packet is smaller than this one, then retransmit the1959  * packet.  Do not adjust the cwnd when this happens.1960  */1961 void TcpAgent::tcp_eln(Packet *pkt)1962 {1963         //int eln_rxmit;1964         hdr_tcp *tcph = hdr_tcp::access(pkt);1965         int ack = tcph->seqno();1966 1967         if (++dupacks_ == eln_rxmit_thresh_ && ack > eln_last_rxmit_) {1968                 /* Retransmit this packet */1969                 output(last_ack_ + 1, TCP_REASON_DUPACK);1970                 eln_last_rxmit_ = last_ack_+1;1971         } else1972                 send_much(0, 0, maxburst_);1973 1974         Packet::free(pkt);1975         return;1976 }1977 1978 /*1979  * This function is invoked when the connection is done. It in turn1980  * invokes the Tcl finish procedure that was registered with TCP.1981  */1982 void TcpAgent::finish()1983 {1984     Tcl::instance().evalf("%s done", this->name());1985 }1986 1987 void RtxTimer::expire(Event*)1988 {1989     a_->timeout(TCP_TIMER_RTX);1990 }1991 1992 void DelSndTimer::expire(Event*)1993 {1994     a_->timeout(TCP_TIMER_DELSND);1995 }1996 1997 void BurstSndTimer::expire(Event*)1998 {1999     a_->timeout(TCP_TIMER_BURSTSND);2000 }2001 2002 /*2003  * THE FOLLOWING FUNCTIONS ARE OBSOLETE, but REMAIN HERE2004  * DUE TO OTHER PEOPLE‘s TCPs THAT MIGHT USE THEM2005  *2006  * These functions are now replaced by ecn() and slowdown(),2007  * respectively.2008  */2009 2010 /*2011  * Respond either to a source quench or to a congestion indication bit.2012  * This is done at most once a roundtrip time;  after a source quench,2013  * another one will not be done until the last packet transmitted before2014  * the previous source quench has been ACKed.2015  */2016 void TcpAgent::quench(int how)2017 {2018     if (highest_ack_ >= recover_) {2019         recover_ =  maxseq_;2020         last_cwnd_action_ = CWND_ACTION_ECN;2021         closecwnd(how);2022     }2023 }2024 2025 /*2026  * close down the congestion window2027  */2028 void TcpAgent::closecwnd(int how)2029 {   2030     static int first_time = 1;2031     if (first_time == 1) {2032         fprintf(stderr, "the TcpAgent::closecwnd() function is now deprecated, please use the function slowdown() instead\n");2033     }2034     switch (how) {2035     case 0:2036         /* timeouts */2037         ssthresh_ = int( window() / 2 );2038         if (ssthresh_ < 2)2039             ssthresh_ = 2;2040         cwnd_ = int(wnd_restart_);2041         break;2042 2043     case 1:2044         /* Reno dup acks, or after a recent congestion indication. */2045         // cwnd_ = window()/2;2046         cwnd_ = decrease_num_ * window();2047         ssthresh_ = int(cwnd_);2048         if (ssthresh_ < 2)2049             ssthresh_ = 2;        2050         break;2051 2052     case 2:2053         /* Tahoe dup acks          2054          * after a recent congestion indication */2055         cwnd_ = wnd_init_;2056         break;2057 2058     case 3:2059         /* Retransmit timeout, but no outstanding data. */ 2060         cwnd_ = int(wnd_init_);2061         break;2062     case 4:2063         /* Tahoe dup acks */2064         ssthresh_ = int( window() / 2 );2065         if (ssthresh_ < 2)2066             ssthresh_ = 2;2067         cwnd_ = 1;2068         break;2069 2070     default:2071         abort();2072     }2073     fcnt_ = 0.;2074     count_ = 0;2075 }2076 2077 /*2078  * Check if the sender has been idle or application-limited for more2079  * than an RTO, and if so, reduce the congestion window.2080  */2081 void TcpAgent::process_qoption_after_send ()2082 {2083     int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);2084     int rto = (int)(t_rtxcur_/tcp_tick_) ; 2085     /*double ct = Scheduler::instance().clock();*/2086 2087     if (!EnblRTTCtr_) {2088         if (tcp_now - T_last >= rto) {2089             // The sender has been idle.2090              slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE) ;2091             for (int i = 0 ; i < (tcp_now - T_last)/rto; i ++) {2092                 slowdown(CWND_HALF_WITH_MIN|TCP_IDLE);2093             }2094             T_prev = tcp_now ;2095             W_used = 0 ;2096         }2097         T_last = tcp_now ;2098         if (t_seqno_ == highest_ack_+ window()) {2099             T_prev = tcp_now ; 2100             W_used = 0 ; 2101         }2102         else if (t_seqno_ == curseq_-1) {2103             // The sender has no more data to send.2104             int tmp = t_seqno_ - highest_ack_ ;2105             if (tmp > W_used)2106                 W_used = tmp ;2107             if (tcp_now - T_prev >= rto) {2108                 // The sender has been application-limited.2109                 slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE);2110                 slowdown(CLOSE_CWND_HALF_WAY|TCP_IDLE);2111                 T_prev = tcp_now ;2112                 W_used = 0 ;2113             }2114         }2115     } else {2116         rtt_counting();2117     }2118 }2119 2120 /*2121  * Check if the sender has been idle or application-limited for more2122  * than an RTO, and if so, reduce the congestion window, for a TCP sender2123  * that "counts RTTs" by estimating the number of RTTs that fit into2124  * a single clock tick.2125  */2126 void2127 TcpAgent::rtt_counting()2128 {2129         int tcp_now = (int)(Scheduler::instance().clock()/tcp_tick_ + 0.5);2130     int rtt = (int(t_srtt_) >> T_SRTT_BITS) ;2131 2132     if (rtt < 1) 2133         rtt = 1 ;2134     if (tcp_now - T_last >= 2*rtt) {2135         // The sender has been idle.2136         int RTTs ; 2137         RTTs = (tcp_now -T_last)*RTT_goodcount/(rtt*2) ; 2138         RTTs = RTTs - Backoffs ; 2139         Backoffs = 0 ; 2140         if (RTTs > 0) {2141             slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE) ;2142             for (int i = 0 ; i < RTTs ; i ++) {2143                 slowdown(CWND_HALF_WITH_MIN|TCP_IDLE);2144                 RTT_prev = RTT_count ; 2145                 W_used = 0 ;2146             }2147         }2148     }2149     T_last = tcp_now ;2150     if (tcp_now - T_start >= 2*rtt) {2151         if ((RTT_count > RTT_goodcount) || (F_full == 1)) {2152             RTT_goodcount = RTT_count ; 2153             if (RTT_goodcount < 1) RTT_goodcount = 1 ; 2154         }2155         RTT_prev = RTT_prev - RTT_count ;2156         RTT_count = 0 ; 2157         T_start  = tcp_now ;2158         F_full = 0;2159     }2160     if (t_seqno_ == highest_ack_ + window()) {2161         W_used = 0 ; 2162         F_full = 1 ; 2163         RTT_prev = RTT_count ;2164     }2165     else if (t_seqno_ == curseq_-1) {2166         // The sender has no more data to send.2167         int tmp = t_seqno_ - highest_ack_ ;2168         if (tmp > W_used)2169             W_used = tmp ;2170         if (RTT_count - RTT_prev >= 2) {2171             // The sender has been application-limited.2172             slowdown(THREE_QUARTER_SSTHRESH|TCP_IDLE) ;2173             slowdown(CLOSE_CWND_HALF_WAY|TCP_IDLE);2174             RTT_prev = RTT_count ; 2175             Backoffs ++ ; 2176             W_used = 0;2177         }2178     }2179     if (F_counting == 0) {2180         W_timed = t_seqno_  ;2181         F_counting = 1 ;2182     }2183 }2184 2185 void TcpAgent::process_qoption_after_ack (int seqno)2186 {2187     if (F_counting == 1) {2188         if (seqno >= W_timed) {2189             RTT_count ++ ; 2190             F_counting = 0 ; 2191         }2192         else {2193             if (dupacks_ == numdupacks_)2194                 RTT_count ++ ;2195         }2196     }2197 }2198 2199 void TcpAgent::trace_event(char *eventtype)2200 {2201     if (et_ == NULL) return;2202     int seqno = t_seqno_;2203     char *wrk = et_->buffer();2204     char *nwrk = et_->nbuffer();2205     if (wrk != 0)2206         sprintf(wrk,2207             "E "TIME_FORMAT" %d %d TCP %s %d %d %d",2208             et_->round(Scheduler::instance().clock()),   // time2209             addr(),                       // owner (src) node id2210             daddr(),                      // dst node id2211             eventtype,                    // event type2212             fid_,                         // flow-id2213             seqno,                        // current seqno2214             int(cwnd_)                         //cong. window2215             );2216     2217     if (nwrk != 0)2218         sprintf(nwrk,2219             "E -t "TIME_FORMAT" -o TCP -e %s -s %d.%d -d %d.%d",2220             et_->round(Scheduler::instance().clock()),   // time2221             eventtype,                    // event type2222             addr(),                       // owner (src) node id2223             port(),                       // owner (src) port id2224             daddr(),                      // dst node id2225             dport()                       // dst port id2226             );2227     et_->trace();2228 }

 

tcp.cc