ns2-tcp-tcp.cc
1 /* -*- Mode:C++; c-basic-offset:8; tab-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 ", 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 ", 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 ", 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 ", 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 ", 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 ", 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) ", 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 ", 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 ", 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 ", 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 ", 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 ", 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 ", 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 ", 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 // << " "; 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 ", 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 ", 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 ", 1689 num1, qsh->rate()); 1690 printf("Quick Start request, window %d rtt: %4.2f pktsize: %d ", 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 "); 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 "); 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 }