首页 > 代码库 > 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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。