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 has
1001      *   the ECN bit set, then the returning ACK caused cwnd_ to
1002      *   be decreased to less than one, and we can‘t send another
1003      *   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     else
1009         cancel_rtx_timer();
1010 }
1011
1012 /*
1013  * for experimental, high-speed TCP
1014  */
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_2
1018     //  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_, to
1082     //    high_p_ at congestion window high_window_, on a log-log scale.
1083         // The decrease factor ranges from 0.5 to high_decrease
1084     //  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 up
1087     //   in a table, with the increase and decrease being a function of the
1088     //   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 window
1121  */
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 algorithms
1153              * 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             } else
1168                 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             } else
1183                 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                         } else
1197                                 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 in
1202              *  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                         } else
1211                                 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 notdef
1230             /*XXX*/
1231             error("illegal window option %d", wnd_option_);
1232 #endif
1233             abort();
1234         }
1235     }
1236     // if maxcwnd_ is set (nonzero), make it the cwnd limit
1237     if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
1238         cwnd_ = maxcwnd_;
1239
1240     return;
1241 }
1242
1243 // Shigeyuki Osada 2012/01/08
1244 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/08
1257         wnd_ = tcph->wnd();
1258     }
1259     return;
1260 }
1261
1262 void
1263 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 < ssthresh
1273     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 half
1313         // 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 decreasewin
1317         // 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 half
1327         // 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, with
1333         // non-standard values of decrease_num_, should respond
1334         // 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 start
1360     if (cwnd_ == 1 || slowstart)
1361         // Not sure if this is best way to capture slow_start
1362         // This is probably tracing a superset of slowdowns of
1363         // 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 agents
1393      * in the network intersperse acks (e.g., ack-reconstructors) for
1394      * 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 Gurtov
1404                 /*
1405                  * Don‘t end backoff if still in ECN-Echo with
1406                   * 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 with
1417                   * 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 before
1438  * the previous source quench has been ACKed.
1439  *
1440  * Note that this procedure is called before "highest_ack_" is
1441  * 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 lack
1462  *    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     else
1469         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-Echo
1483          * after a period of ACKs without ECN-Echo.
1484          * Therefore, open the congestion window. */
1485         /* if control option is set, and the sender is not
1486              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 new
1514          * previously unsent segments.
1515          * If there are no new data or receiver window limits the
1516          * 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 whole
1524              * window => cancel F-RTO
1525               */
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 be
1534          * declared spurious
1535          */
1536         spurious_timeout();
1537     }
1538 }
1539
1540 /*
1541  * Set the initial window.
1542  */
1543 double
1544 TcpAgent::initial_window()
1545 {
1546         // If Quick-Start Request was approved, use that as a basis for
1547         // initial window
1548         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 draft
1559          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 check
1576  * of ‘recover‘ below, this function implements the following truth
1577  * table:
1578  *
1579  *    bugfix    ecn    last-cwnd == ecn    action
1580  *
1581  *    0    0    0            tahoe_action
1582  *    0    0    1            tahoe_action    [impossible]
1583  *    0    1    0            tahoe_action
1584  *    0    1    1            slow-start, return
1585  *    1    0    0            nothing
1586  *    1    0    1            nothing        [impossible]
1587  *    1    1    0            nothing
1588  *    1    1    1            slow-start, return
1589  */
1590
1591 /*
1592  * A first or second duplicate acknowledgement has arrived, and
1593  * singledup_ is enabled.
1594  * If the receiver‘s advertised window permits, and we are exceeding our
1595  * congestion window by less than numdupacks_, then send a new packet.
1596  */
1597 void
1598 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 void
1612 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 Retransmit
1618         //  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, avoids
1633          * problems with multiple fast retransmits in one
1634          * 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 event
1643         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 the
1653  *   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 rejected
1698 #ifdef QS_DEBUG
1699                 printf("Quick Start rejected\n");
1700 #endif
1701         }
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 the
1716          * 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 function
1724         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 window
1741          * (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 retransmissions
1754          */
1755         cwnd_ = 1; break;
1756     }
1757
1758     /*
1759      * Revert ssthresh to size before retransmission timeout
1760      */
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 for
1774  * a correct window size.
1775  *
1776  * Return value: non-zero if Quick-Start specific loss recovery took place
1777  */
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 the
1797  * network connections are misconfigured
1798  */
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 notdef
1808     if (pkt->type_ != PT_ACK) {
1809         Tcl::instance().evalf("%s error \"received non-ack\"",
1810                       name());
1811         Packet::free(pkt);
1812         return;
1813     }
1814 #endif
1815     /* W.N.: check if this is from a previous incarnation */
1816     if (tcph->ts() < lastreset_) {
1817         // Remove packet and do nothing
1818         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 overhead
1870          * to avoid phase effects
1871          */
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 event
1882         trace_event("TIMEOUT");
1883
1884         frto_ = 0;
1885         // Set pipe_prev as per Eifel Response
1886         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 larger
1904                  * 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 larger
1912                                  * 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 the
1958  * last ELN-rxmitted packet is smaller than this one, then retransmit the
1959  * 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         } else
1972                 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 turn
1980  * 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 HERE
2004  * DUE TO OTHER PEOPLE‘s TCPs THAT MIGHT USE THEM
2005  *
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 before
2014  * 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 window
2027  */
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 more
2079  * 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 more
2122  * than an RTO, and if so, reduce the congestion window, for a TCP sender
2123  * that "counts RTTs" by estimating the number of RTTs that fit into
2124  * a single clock tick.
2125  */
2126 void
2127 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()),   // time
2209             addr(),                       // owner (src) node id
2210             daddr(),                      // dst node id
2211             eventtype,                    // event type
2212             fid_,                         // flow-id
2213             seqno,                        // current seqno
2214             int(cwnd_)                         //cong. window
2215             );
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()),   // time
2221             eventtype,                    // event type
2222             addr(),                       // owner (src) node id
2223             port(),                       // owner (src) port id
2224             daddr(),                      // dst node id
2225             dport()                       // dst port id
2226             );
2227     et_->trace();
2228 }
时间: 2024-11-03 21:19:48

tcp.cc的相关文章

tcp-full.cc

ns2--tcp-full.cc 1 /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ 2 3 /* 4 * Copyright (c) Intel Corporation 2001. All rights reserved. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you ma

CloudFoundry.yml修正版

--- name: CFRELEASE02 director_uuid: fdd46e30-f2c5-41dc-9662-0976fdac5716 releases: - name: cf version: 171 meta: environment: null stemcell: name: bosh-vsphere-esxi-ubuntu version: 2366 compilation: workers: 2 cloud_properties: ram: 1024 disk: 6144

《优先级流量调度算法研究》毕业设计工作日志

2016/4/1——2016/4/17 完成了三篇论文的阅读 用XShell工具在hust服务器上安装了测试环境要用的ns2 2016/4/22——2016/4/24把PIAS的附加补丁.重新编译的部分弄好了.阅读论文脚本代码进行中.代码中参数较多,需进一步理解具体含义和论文中对应起来,同时也需要结合C++代码补丁部分 了解具体实现机制. (1)tcp-common-opt.tcl中TCP_pair instproc init {args}{}中的eval $self next $args怎么理

ns-2

暑假学习内容 <<移动环境中三维模型差错复原传输算法研究>>这个项目中,我是做的是第二大块-模型混合传输协议的研究.而在设计此协议之前,首先要掌握网络模拟-NS2.NS2是现在学术界广泛使用的一种网络模拟软件.在设计了协议后要进行模拟,然后改进协议.再模拟,再改进... 直到协议达到预想的结果. NS2的优势在于它内容丰富,它是一个庞大的系统,目前学习资料又相对较少,特别是针对初学者的. 首先学习TCL(tool command language)语言,TCL是一种解释执行的脚本语

Server被UDP流量攻击

问题现象: 全国各地至此Server ping延迟不高,丢包率99%,无法远程进Server,业务100%中断.在对方攻击流量略微有所减少时远程进Server查看网卡流量如图 对方停止攻击时网卡流量图 分析: 虽然流量攻击不太可能是CC攻击,但是还是需要检查一下是否是TCP CC攻击.CMD命令 netstat -an,看是否有大量IP连接你的业务端口(如果你的业务是TCP类型的话),如果你的业务端口是80,那么使用命令 netstat -an|find /c "80"来查看你业务端口

dctcp-ns2-patch

1 diff -crbB ns-allinone-2.35/ns-2.35/queue/red.cc ns-2.35/queue/red.cc 2 *** ns-allinone-2.35/ns-2.35/queue/red.cc 2011-10-02 15:32:34.000000000 -0700 3 --- ns-2.35/queue/red.cc 2012-03-19 02:40:10.827778003 -0700 4 *************** 5 *** 559,565 ***

华为云初体验

听说还不错就买了最便宜的配置, 测试了一下, 发现读写速度不错, download speed美丽 CPU Model : Intel(R) Xeon(R) Gold 6161 CPU @ 2.20GHz CPU Cores : 1 Cores @ 2200.000 MHz x86_64 CPU Cache : 30976 KB OS : CentOS 6.10 (64 Bit) KVM Kernel : 2.6.32-754.23.1.el6.x86_64 Total Space : 2.0

邓紫棋开唱惨被轰:滚出娱乐圈

http://www.cnpoc.cn/HZcommonShowFirst.asp?CID=122&CNAME=%B3%BB%D6%DD%CB%D5%CF%C9%C7%F8%D5%D2%D1%A7%C9%FA%C3%C3%C9%CF%C3%C5%B0%B4%C4%A6%B7%FE%CE%F1%A8%801858885v7572%a1%f8k5u21z http://www.cnpoc.cn/HZcommonShowFirst.asp?CID=122&CNAME=%B3%BB%D6%DD%C

览唾寐了酒rkv2v8h37gg8p6qys1d0

该人士表示,整体思路"就是一个放开一个监管,围绕市场化进行改革,同时防止国有资产流失". "国有资产流失是一顶非常可怕的帽子,很多人怕犯错误,不敢推进员工激励.混合所有制等改革." 该人士表示,整体思路"就是一个放开一个监管,围绕市场化进行改革,同时防止国有资产流失". 两年前,财政部为"什么人能够持股"一事,进行了多次讨论.财政部相关政策制定部门人士认为,目前最纠结的问题是:"哪些人可以持股?管理层.技术骨干还是全