00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #ifndef lint
00060 static const char rcsid[] =
00061 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-vegas.cc,v 1.37 2005/08/25 18:58:12 johnh Exp $ (NCSU/IBM)";
00062 #endif
00063
00064 #include <stdio.h>
00065 #include <stdlib.h>
00066 #include <sys/types.h>
00067
00068 #include "ip.h"
00069 #include "tcp.h"
00070 #include "flags.h"
00071
00072 #define MIN(x, y) ((x)<(y) ? (x) : (y))
00073
00074
00075 static class VegasTcpClass : public TclClass {
00076 public:
00077 VegasTcpClass() : TclClass("Agent/TCP/Vegas") {}
00078 TclObject* create(int, const char*const*) {
00079 return (new VegasTcpAgent());
00080 }
00081 } class_vegas;
00082
00083
00084 VegasTcpAgent::VegasTcpAgent() : TcpAgent()
00085 {
00086 v_sendtime_ = NULL;
00087 v_transmits_ = NULL;
00088 }
00089
00090 VegasTcpAgent::~VegasTcpAgent()
00091 {
00092 if (v_sendtime_)
00093 delete []v_sendtime_;
00094 if (v_transmits_)
00095 delete []v_transmits_;
00096 }
00097
00098 void
00099 VegasTcpAgent::delay_bind_init_all()
00100 {
00101 delay_bind_init_one("v_alpha_");
00102 delay_bind_init_one("v_beta_");
00103 delay_bind_init_one("v_gamma_");
00104 delay_bind_init_one("v_rtt_");
00105 TcpAgent::delay_bind_init_all();
00106 reset();
00107 }
00108
00109 int
00110 VegasTcpAgent::delay_bind_dispatch(const char *varName, const char *localName,
00111 TclObject *tracer)
00112 {
00113
00114 if (delay_bind(varName, localName, "v_alpha_", &v_alpha_, tracer))
00115 return TCL_OK;
00116 if (delay_bind(varName, localName, "v_beta_", &v_beta_, tracer))
00117 return TCL_OK;
00118 if (delay_bind(varName, localName, "v_gamma_", &v_gamma_, tracer))
00119 return TCL_OK;
00120 if (delay_bind(varName, localName, "v_rtt_", &v_rtt_, tracer))
00121 return TCL_OK;
00122 return TcpAgent::delay_bind_dispatch(varName, localName, tracer);
00123 }
00124
00125 void
00126 VegasTcpAgent::reset()
00127 {
00128 t_cwnd_changed_ = 0.;
00129 firstrecv_ = -1.0;
00130 v_slowstart_ = 2;
00131 v_sa_ = 0;
00132 v_sd_ = 0;
00133 v_timeout_ = 1000.;
00134 v_worried_ = 0;
00135 v_begseq_ = 0;
00136 v_begtime_ = 0.;
00137 v_cntRTT_ = 0; v_sumRTT_ = 0.;
00138 v_baseRTT_ = 1000000000.;
00139 v_incr_ = 0;
00140 v_inc_flag_ = 1;
00141
00142 TcpAgent::reset();
00143 }
00144
00145 void
00146 VegasTcpAgent::recv_newack_helper(Packet *pkt)
00147 {
00148 newack(pkt);
00149 #if 0
00150
00151 if ( !hdr_flags::access(pkt)->ecnecho() || !ecn_ ) {
00152 opencwnd();
00153 }
00154 #endif
00155
00156 if ((highest_ack_ >= curseq_-1) && !closed_) {
00157 closed_ = 1;
00158 finish();
00159 }
00160 }
00161
00162 void
00163 VegasTcpAgent::recv(Packet *pkt, Handler *)
00164 {
00165 double currentTime = vegastime();
00166 hdr_tcp *tcph = hdr_tcp::access(pkt);
00167 hdr_flags *flagh = hdr_flags::access(pkt);
00168
00169 #if 0
00170 if (pkt->type_ != PT_ACK) {
00171 Tcl::instance().evalf("%s error \"recieved non-ack\"",
00172 name());
00173 Packet::free(pkt);
00174 return;
00175 }
00176 #endif
00177 ++nackpack_;
00178
00179 if(firstrecv_<0) {
00180 firstrecv_ = currentTime;
00181 v_baseRTT_ = v_rtt_ = firstrecv_;
00182 v_sa_ = v_rtt_ * 8.;
00183 v_sd_ = v_rtt_;
00184 v_timeout_ = ((v_sa_/4.)+v_sd_)/2.;
00185 }
00186
00187 if (flagh->ecnecho())
00188 ecn(tcph->seqno());
00189 if (tcph->seqno() > last_ack_) {
00190 if (last_ack_ == 0 && delay_growth_) {
00191 cwnd_ = initial_window();
00192 }
00193
00194 if(dupacks_ > numdupacks_ && cwnd_ > v_newcwnd_) {
00195 cwnd_ = v_newcwnd_;
00196
00197 ssthresh_ = 2;
00198 }
00199 int oldack = last_ack_;
00200
00201 recv_newack_helper(pkt);
00202
00203
00204
00205
00206
00207
00208
00209 if(tcph->seqno() >= v_begseq_) {
00210 double rtt;
00211 if(v_cntRTT_ > 0)
00212 rtt = v_sumRTT_ / v_cntRTT_;
00213 else
00214 rtt = currentTime - v_begtime_;
00215
00216 v_sumRTT_ = 0.0;
00217 v_cntRTT_ = 0;
00218
00219
00220 int rttLen = t_seqno_ - v_begseq_;
00221
00222
00223
00224
00225 if(rtt>0) {
00226
00227
00228
00229 if(rtt<v_baseRTT_ || rttLen<=1)
00230 v_baseRTT_ = rtt;
00231
00232 double expect;
00233
00234 v_actual_ = double(rttLen)/rtt;
00235
00236 expect = double(t_seqno_-last_ack_)/v_baseRTT_;
00237
00238
00239 int delta=int((expect-v_actual_)*v_baseRTT_+0.5);
00240 if(cwnd_ < ssthresh_) {
00241
00242 v_inc_flag_ = !v_inc_flag_;
00243 if(!v_inc_flag_)
00244 v_incr_ = 0;
00245 else {
00246 if(delta > v_gamma_) {
00247
00248
00249 ssthresh_ = 2;
00250 cwnd_-=(cwnd_/8);
00251 if(cwnd_<2)
00252 cwnd_ = 2.;
00253 v_incr_ = 0;
00254 } else
00255 v_incr_ = 1;
00256 }
00257 } else {
00258 if(delta>v_beta_) {
00259
00260
00261
00262
00263
00264 --cwnd_;
00265 if(cwnd_<2) cwnd_ = 2;
00266 v_incr_ = 0;
00267 } else if(delta<v_alpha_)
00268
00269 v_incr_ = 1/cwnd_;
00270 else
00271 v_incr_ = 0;
00272 }
00273 }
00274
00275
00276 v_begseq_ = t_seqno_;
00277 v_begtime_ = currentTime;
00278 }
00279
00280
00281
00282
00283
00284 if(v_incr_ == 1 && cwnd_ >= ssthresh_)
00285 v_incr_ = 0;
00286
00287
00288
00289
00290 if(v_incr_>0 && (cwnd_-(t_seqno_-last_ack_))<=2)
00291 cwnd_ = cwnd_+v_incr_;
00292
00293
00294 if (maxcwnd_ && (int(cwnd_) > maxcwnd_)) {
00295 cwnd_ = maxcwnd_;
00296 }
00297
00298
00299
00300
00301
00302
00303
00304 double sendTime = v_sendtime_[tcph->seqno()%v_maxwnd_];
00305 int transmits = v_transmits_[tcph->seqno()% v_maxwnd_];
00306 int range = tcph->seqno() - oldack;
00307 for(int k=((oldack+1) %v_maxwnd_);
00308 k<=(tcph->seqno()%v_maxwnd_) && range >0 ;
00309 k=((k+1) % v_maxwnd_), range--) {
00310 v_sendtime_[k] = -1.0;
00311 v_transmits_[k] = 0;
00312 }
00313
00314 if((sendTime !=0.) && (transmits==1)) {
00315
00316 double rtt, n;
00317 rtt = currentTime - sendTime;
00318 v_sumRTT_ += rtt;
00319 ++v_cntRTT_;
00320 if(rtt>0) {
00321 v_rtt_ = rtt;
00322 if(v_rtt_ < v_baseRTT_)
00323 v_baseRTT_ = v_rtt_;
00324 n = v_rtt_ - v_sa_/8;
00325 v_sa_ += n;
00326 n = n<0 ? -n : n;
00327 n -= v_sd_ / 4;
00328 v_sd_ += n;
00329 v_timeout_ = ((v_sa_/4)+v_sd_)/2;
00330 v_timeout_ += (v_timeout_/16);
00331 }
00332 }
00333
00334
00335
00336
00337 if(v_worried_>0) {
00338
00339
00340
00341
00342
00343 --v_worried_;
00344 int expired=vegas_expire(pkt);
00345 if(expired>=0) {
00346 dupacks_ = numdupacks_;
00347 output(expired, TCP_REASON_DUPACK);
00348 } else
00349 v_worried_ = 0;
00350 }
00351 } else if (tcph->seqno() == last_ack_) {
00352
00353 ++dupacks_;
00354 int expired=vegas_expire(pkt);
00355 if (expired>=0 || dupacks_ == numdupacks_) {
00356 double sendTime=v_sendtime_[(last_ack_+1) % v_maxwnd_];
00357 int transmits=v_transmits_[(last_ack_+1) % v_maxwnd_];
00358
00359
00360
00361
00362 if ( !bug_fix_ || (highest_ack_ > recover_) || \
00363 ( last_cwnd_action_ != CWND_ACTION_TIMEOUT)) {
00364 int win = window();
00365 last_cwnd_action_ = CWND_ACTION_DUPACK;
00366 recover_ = maxseq_;
00367
00368 v_worried_ = MIN(2, t_seqno_ - last_ack_ );
00369
00370
00371 if(transmits > 1)
00372 v_timeout_ *=2.;
00373 else
00374 v_timeout_ += (v_timeout_/8.);
00375
00376
00377
00378
00379 if(t_cwnd_changed_ < sendTime ) {
00380 if(win<=3)
00381 win=2;
00382 else if(transmits > 1)
00383 win >>=1;
00384 else
00385 win -= (win>>2);
00386
00387
00388 v_newcwnd_ = double(win);
00389
00390 cwnd_ = v_newcwnd_ + dupacks_;
00391 t_cwnd_changed_ = currentTime;
00392 }
00393
00394
00395 reset_rtx_timer(1);
00396 if(expired>=0)
00397 output(expired, TCP_REASON_DUPACK);
00398 else
00399 output(last_ack_ + 1, TCP_REASON_DUPACK);
00400
00401 if(transmits==1)
00402 dupacks_ = numdupacks_;
00403 }
00404 } else if (dupacks_ > numdupacks_)
00405 ++cwnd_;
00406 }
00407 Packet::free(pkt);
00408
00409 #if 0
00410 if (trace_)
00411 plot();
00412 #endif
00413
00414
00415
00416
00417 if (dupacks_ == 0 || dupacks_ > numdupacks_ - 1)
00418 send_much(0, 0, maxburst_);
00419 }
00420
00421 void
00422 VegasTcpAgent::timeout(int tno)
00423 {
00424 if (tno == TCP_TIMER_RTX) {
00425 if (highest_ack_ == maxseq_ && !slow_start_restart_) {
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 return;
00436 };
00437 dupacks_ = 0;
00438 recover_ = maxseq_;
00439 last_cwnd_action_ = CWND_ACTION_TIMEOUT;
00440 reset_rtx_timer(0);
00441 ++nrexmit_;
00442 slowdown(CLOSE_CWND_RESTART|CLOSE_SSTHRESH_HALF);
00443 cwnd_ = double(v_slowstart_);
00444 v_newcwnd_ = 0;
00445 t_cwnd_changed_ = vegastime();
00446 send_much(0, TCP_REASON_TIMEOUT);
00447 } else {
00448
00449
00450 send_much(1, TCP_REASON_TIMEOUT);
00451 };
00452 }
00453
00454 void
00455 VegasTcpAgent::output(int seqno, int reason)
00456 {
00457 Packet* p = allocpkt();
00458 hdr_tcp *tcph = hdr_tcp::access(p);
00459 double now = Scheduler::instance().clock();
00460 tcph->seqno() = seqno;
00461 tcph->ts() = now;
00462 tcph->reason() = reason;
00463
00464
00465
00466
00467 if (seqno==0) {
00468 v_maxwnd_ = int(wnd_);
00469 if (v_sendtime_)
00470 delete []v_sendtime_;
00471 if (v_transmits_)
00472 delete []v_transmits_;
00473 v_sendtime_ = new double[v_maxwnd_];
00474 v_transmits_ = new int[v_maxwnd_];
00475 for(int i=0;i<v_maxwnd_;i++) {
00476 v_sendtime_[i] = -1.;
00477 v_transmits_[i] = 0;
00478 }
00479 }
00480
00481
00482 int index = seqno % v_maxwnd_;
00483 v_sendtime_[index] = vegastime();
00484 ++v_transmits_[index];
00485
00486
00487 int bytes = hdr_cmn::access(p)->size();
00488 ndatabytes_ += bytes;
00489 ndatapack_++;
00490 send(p, 0);
00491 if (seqno == curseq_ && seqno > maxseq_)
00492 idle();
00493
00494 if (seqno > maxseq_) {
00495 maxseq_ = seqno;
00496 if (!rtt_active_) {
00497 rtt_active_ = 1;
00498 if (seqno > rtt_seq_) {
00499 rtt_seq_ = seqno;
00500 rtt_ts_ = now;
00501 }
00502 }
00503 } else {
00504 ++nrexmitpack_;
00505 nrexmitbytes_ += bytes;
00506 }
00507
00508 if (!(rtx_timer_.status() == TIMER_PENDING))
00509
00510 set_rtx_timer();
00511 }
00512
00513
00514
00515
00516
00517 int
00518 VegasTcpAgent::vegas_expire(Packet* pkt)
00519 {
00520 hdr_tcp *tcph = hdr_tcp::access(pkt);
00521 double elapse = vegastime() - v_sendtime_[(tcph->seqno()+1)%v_maxwnd_];
00522 if (elapse >= v_timeout_) {
00523 return(tcph->seqno()+1);
00524 }
00525 return(-1);
00526 }
00527