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