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 #ifndef lint
00027 static const char rcsid[] =
00028 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-sack-rh.cc,v 1.5 2002/10/09 03:47:02 difa Exp $ (PSC-SACKRH)";
00029 #endif
00030
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <sys/types.h>
00034
00035 #include "ip.h"
00036 #include "tcp.h"
00037 #include "flags.h"
00038 #include "scoreboard-rh.h"
00039 #include "random.h"
00040
00041 #define TRUE 1
00042 #define FALSE 0
00043
00044 #define RH_INCR 0
00045 #define RH_EXACT 11
00046 #define RH_EST 12
00047 #define RH_EST_REPAIR 13
00048
00049 #define RHEH_NONE 0
00050 #define RHEH_COUNTING 1
00051 #define RHEH_NEW_HOLE 2
00052 #define RHEH_RETRANS_OCCURRED 3
00053
00054
00055
00056 class SackRHTcpAgent : public TcpAgent {
00057 public:
00058 SackRHTcpAgent();
00059 virtual int window();
00060 virtual void recv(Packet *pkt, Handler*);
00061 virtual void timeout(int tno);
00062 void plot();
00063 virtual void send_much(int force, int reason, int maxburst);
00064 virtual void boundparms();
00065 virtual void estadjust();
00066 virtual void rhclear();
00067 virtual void computefack();
00068 virtual void SackRHTcpAgent::newack(Packet* pkt);
00069 protected:
00070 int fack_;
00071 int retran_data_;
00072 int num_dupacks_;
00073 int rh_state_;
00074 double prior_cwnd_;
00075 int prior_max_seq_;
00076 int rh_id_;
00077 int rh_max_;
00078 int rh_est_hole_state_;
00079 int num_retrans_;
00080 int rh_retran_flag_;
00081 int rh_ecn_flag_;
00082 ScoreBoardRH scb_;
00083 };
00084
00085 static class SackRHTcpClass : public TclClass {
00086 public:
00087 SackRHTcpClass() : TclClass("Agent/TCP/SackRH") {}
00088 TclObject* create(int, const char*const*) {
00089 return (new SackRHTcpAgent());
00090 }
00091 } class_sack_rh;
00092
00093 int SackRHTcpAgent::window()
00094 {
00095 return(cwnd_ < wnd_ ? (int) cwnd_ : (int) wnd_);
00096 }
00097
00098 SackRHTcpAgent::SackRHTcpAgent() : fack_(-1),
00099 retran_data_(0), num_dupacks_(0), rh_state_(RH_INCR), rh_id_(0), rh_max_(0),
00100 rh_est_hole_state_(0), rh_retran_flag_(0), rh_ecn_flag_(0), scb_(&numdupacks_)
00101 {
00102 }
00103
00104 void SackRHTcpAgent::recv(Packet *pkt, Handler*)
00105 {
00106 int old_fack, old_retran_data, old_ack, old_numdupacks;
00107 hdr_tcp *tcph = hdr_tcp::access(pkt);
00108
00109 int ecnecho = (hdr_flags::access(pkt)->ecnecho() && last_ack_ != -1);
00110 int sackpresent = (tcph->sa_length() > 0);
00111
00112 ++nackpack_;
00113
00114 #ifdef DEBUGRH
00115 printf ("ENTER: RH=%02d snd.nxt=%3d fack=%3d ack=%3d retran_data=%03d \n",
00116 rh_state_, (int)t_seqno_, fack_, last_ack_, retran_data_);
00117 printf (" prior_max_seq=%3d prior_cwnd=%f rheh=%2d num_dupacks=%2d\n",
00118 prior_max_seq_, prior_cwnd_, rh_est_hole_state_, num_dupacks_);
00119 printf (" cwnd:%f=%d curseq=%d\n",
00120 (float)cwnd_, int(cwnd_), (int)curseq_);
00121 #endif
00122 old_ack = last_ack_;
00123 newack(pkt);
00124
00125 if (ecnecho) rh_ecn_flag_=1;
00126
00127
00128 old_fack = fack_;
00129 old_retran_data = retran_data_;
00130 retran_data_ -= scb_.UpdateScoreBoard (last_ack_, tcph, rh_id_);
00131
00132 old_numdupacks = num_dupacks_;
00133 if (!sackpresent && (old_ack == last_ack_)) {
00134 num_dupacks_++;
00135 if ((rh_est_hole_state_ == RHEH_COUNTING) &&
00136 (num_dupacks_ == numdupacks_)) {
00137 rh_est_hole_state_ = RHEH_NEW_HOLE;
00138 }
00139 }
00140
00141 computefack();
00142
00143
00144
00145 if (!rh_retran_flag_ && !rh_ecn_flag_) {
00146 if (((rh_state_ == RH_EXACT) && !sackpresent && !ecnecho) ||
00147 ((rh_state_ == RH_EST) && (last_ack_ > old_ack))) {
00148 rh_state_ = RH_INCR;
00149 cwnd_ = prior_cwnd_;
00150 rhclear();
00151 computefack();
00152 }
00153 }
00154
00155
00156 if (rh_state_ == RH_EXACT) {
00157 if ((fack_ >= prior_max_seq_) || scb_.RetranSacked(rh_id_)) {
00158 boundparms();
00159 rh_state_ = RH_INCR;
00160 rhclear();
00161 }
00162 }
00163
00164
00165 if ((rh_state_ == RH_EST) || (rh_state_ == RH_EST_REPAIR)) {
00166 if (last_ack_ >= prior_max_seq_) {
00167 retran_data_ = 0;
00168
00169
00170 estadjust();
00171 boundparms();
00172 rh_state_ = RH_INCR;
00173 rhclear();
00174 computefack();
00175
00176 }
00177 }
00178
00179
00180 if ((rh_state_ == RH_EST) && (cwnd_ <= prior_cwnd_/2)) {
00181 rh_state_ = RH_EST_REPAIR;
00182 }
00183
00184
00185 if (((rh_state_ == RH_EST) || (rh_state_ == RH_EST_REPAIR))
00186 && (last_ack_ > old_ack)) {
00187 retran_data_ = 0;
00188 num_dupacks_ -= (last_ack_ - old_ack - 1);
00189 if (num_dupacks_ >= numdupacks_) {
00190 rh_est_hole_state_ = RHEH_NEW_HOLE;
00191 }
00192 else {
00193
00194
00195 rh_est_hole_state_ = RHEH_COUNTING;
00196 }
00197 computefack();
00198 }
00199
00200
00201
00202
00203 if ((rh_state_ == RH_INCR) && (ecnecho || scb_.GetNewHoles() != 0)) {
00204 rh_state_ = RH_EXACT;
00205 prior_cwnd_ = cwnd_;
00206 prior_max_seq_ = t_seqno_;
00207 cong_action_ = TRUE;
00208 rh_id_ = ++rh_max_;
00209 }
00210
00211
00212 if ((rh_state_ == RH_INCR) && (num_dupacks_ > 0)) {
00213 rh_state_ = RH_EST;
00214 rh_est_hole_state_ = RHEH_COUNTING;
00215 prior_cwnd_ = cwnd_;
00216 prior_max_seq_ = t_seqno_;
00217 cong_action_ = TRUE;
00218 rh_id_ = ++rh_max_;
00219 }
00220
00221 if ((rh_state_ == RH_EXACT) && (num_dupacks_ > 0)) {
00222 rh_state_ = RH_EST;
00223 rh_est_hole_state_ = RHEH_COUNTING;
00224
00225
00226
00227 rh_id_ = ++rh_max_;
00228 }
00229
00230 if ((rh_state_ == RH_EST_REPAIR) && (ecnecho)) {
00231 rh_state_ = RH_EST;
00232 prior_cwnd_ = cwnd_;
00233 prior_max_seq_ = t_seqno_;
00234 cong_action_ = TRUE;
00235 rh_id_ = ++rh_max_;
00236 }
00237
00238
00239 switch (rh_state_) {
00240 case RH_INCR:
00241
00242 if ((t_seqno_ - old_fack + old_retran_data + 1) >= (int)cwnd_) {
00243 opencwnd();
00244 }
00245 break;
00246 case RH_EXACT:
00247
00248 cwnd_ -= ((float)((fack_ - old_fack) + (scb_.GetNewHoles()))) / 2.0;
00249 break;
00250 case RH_EST:
00251
00252 cwnd_ -= 0.5;
00253 break;
00254 case RH_EST_REPAIR:
00255
00256 break;
00257 }
00258
00259 #ifdef DEBUGRH
00260 printf ("EXIT: RH=%02d snd.nxt=%3d fack=%3d ack=%3d retran_data=%03d \n cwnd:%f=%d curseq=%d\n",
00261 rh_state_, (int)t_seqno_, fack_, last_ack_, retran_data_, (float)cwnd_, int(cwnd_),
00262 (int)curseq_);
00263 #endif
00264 send_much(FALSE, 0, maxburst_);
00265
00266 Packet::free(pkt);
00267 #ifdef notyet
00268 if (trace_)
00269 plot();
00270 #endif
00271 }
00272
00273 void SackRHTcpAgent::rhclear()
00274 {
00275 rh_id_ = prior_max_seq_ = num_dupacks_ = rh_est_hole_state_ =
00276 rh_ecn_flag_ = num_retrans_ = rh_retran_flag_ = 0;
00277 prior_cwnd_ = 0;
00278 }
00279
00280
00281 void SackRHTcpAgent::computefack()
00282 {
00283 if ((rh_state_ == RH_INCR) || (rh_state_ == RH_EXACT)) {
00284 fack_ = scb_.GetFack (last_ack_);
00285 }
00286 else {
00287 fack_ = last_ack_ + num_dupacks_ + 1;
00288 }
00289 }
00290
00291
00292 void SackRHTcpAgent::boundparms()
00293 {
00294 if (cwnd_ > prior_cwnd_/2.0)
00295 cwnd_ = prior_cwnd_/2.0;
00296 ssthresh_ = cwnd_;
00297 if (ssthresh_ < prior_cwnd_/4.0)
00298 ssthresh_ = (int) (prior_cwnd_/4.0);
00299 }
00300
00301
00302 void SackRHTcpAgent::estadjust()
00303 {
00304 cwnd_ = (prior_cwnd_ - num_retrans_)/2.0;
00305 }
00306
00307
00308 void SackRHTcpAgent::timeout(int tno)
00309 {
00310
00311 if (tno == TCP_TIMER_RTX) {
00312 if (highest_ack_ == maxseq_ && !slow_start_restart_)
00313
00314
00315
00316
00317 return;
00318 if (highest_ack_ == -1 && wnd_init_option_ == 2)
00319
00320
00321
00322
00323 wnd_init_option_ = 1;
00324
00325 #ifdef DEBUGRH
00326 printf ("timeout. last_ack: %d seqno: %d\n",
00327 (int)last_ack_, (int)t_seqno_);
00328 #endif
00329
00330 if (rh_state_ != RH_INCR) {
00331
00332
00333
00334 cwnd_ = prior_cwnd_;
00335 rhclear();
00336 rh_state_ = RH_INCR;
00337
00338 }
00339 ++nrexmit_;
00340 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
00341
00342 retran_data_ = 0;
00343 scb_.TimeoutScoreBoard(t_seqno_);
00344 computefack();
00345
00346
00347
00348 if (t_seqno_ > fack_+1) {
00349 t_seqno_ = fack_+1;
00350 }
00351 reset_rtx_timer(1,1);
00352
00353 last_cwnd_action_ = CWND_ACTION_TIMEOUT;
00354 send_much(0, TCP_REASON_TIMEOUT, maxburst_);
00355 }
00356 else {
00357 timeout_nonrtx(tno);
00358 }
00359 }
00360
00361
00362 void SackRHTcpAgent::send_much(int force, int reason, int maxburst)
00363 {
00364 register int found, npacket = 0;
00365 int xmit_seqno;
00366
00367 found = 1;
00368 if (!force && delsnd_timer_.status() == TIMER_PENDING)
00369 return;
00370
00371
00372
00373
00374
00375 while (int(cwnd_) >= (t_seqno_ - fack_ + retran_data_)
00376 && found) {
00377 if (overhead_ == 0 || force) {
00378 found = 0;
00379 xmit_seqno = scb_.GetNextRetran ();
00380
00381 if (xmit_seqno == -1) {
00382
00383 if (((rh_state_ == RH_EST) || (rh_state_ == RH_EST_REPAIR)) &&
00384 (rh_est_hole_state_ == RHEH_NEW_HOLE)) {
00385 xmit_seqno = last_ack_ + 1;
00386 rh_est_hole_state_ = RHEH_RETRANS_OCCURRED;
00387 num_retrans_++;
00388 retran_data_++;
00389 rh_retran_flag_ = 1;
00390 found = 1;
00391 }
00392 else if ((t_seqno_ < curseq_) &&
00393 (t_seqno_<=last_ack_+int(wnd_))) {
00394 found = 1;
00395 xmit_seqno = t_seqno_++;
00396 }
00397 } else if (xmit_seqno<=last_ack_+int(wnd_)) {
00398 found = 1;
00399 scb_.MarkRetran (xmit_seqno, t_seqno_, rh_id_);
00400 retran_data_++;
00401 rh_retran_flag_ = 1;
00402 }
00403 if (found) {
00404 #ifdef DEBUGRH
00405 printf (" Sending: %3d\n", xmit_seqno);
00406 #endif
00407 output(xmit_seqno, reason);
00408 if (t_seqno_ <= xmit_seqno)
00409 t_seqno_ = xmit_seqno + 1;
00410 npacket++;
00411 }
00412 } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
00413
00414
00415
00416
00417
00418 delsnd_timer_.resched(Random::uniform(overhead_));
00419 return;
00420 }
00421 if (maxburst && npacket == maxburst)
00422 break;
00423 }
00424 }
00425
00426 void SackRHTcpAgent::plot()
00427 {
00428 #ifdef notyet
00429 double t = Scheduler::instance().clock();
00430 sprintf(trace_->buffer(), "t %g %d rtt %g\n",
00431 t, class_, t_rtt_ * tcp_tick_);
00432 trace_->dump();
00433 sprintf(trace_->buffer(), "t %g %d dev %g\n",
00434 t, class_, t_rttvar_ * tcp_tick_);
00435 trace_->dump();
00436 sprintf(trace_->buffer(), "t %g %d win %f\n", t, class_, cwnd_);
00437 trace_->dump();
00438 sprintf(trace_->buffer(), "t %g %d bck %d\n", t, class_, t_backoff_);
00439 trace_->dump();
00440 #endif
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 void SackRHTcpAgent::newack(Packet* pkt)
00452 {
00453 double now = Scheduler::instance().clock();
00454 hdr_tcp *tcph = hdr_tcp::access(pkt);
00455
00456
00457
00458
00459 newtimer(pkt);
00460 last_ack_ = tcph->seqno();
00461 highest_ack_ = last_ack_;
00462
00463 if (t_seqno_ < last_ack_ + 1)
00464 t_seqno_ = last_ack_ + 1;
00465
00466
00467
00468
00469
00470
00471 hdr_flags *fh = hdr_flags::access(pkt);
00472 if (!fh->no_ts_) {
00473 if (ts_option_)
00474 rtt_update(now - tcph->ts_echo());
00475
00476 if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
00477 if (!hdr_flags::access(pkt)->ecnecho()) {
00478
00479
00480
00481
00482 t_backoff_ = 1;
00483 }
00484 rtt_active_ = 0;
00485 if (!ts_option_)
00486 rtt_update(now - rtt_ts_);
00487 }
00488 }
00489
00490 awnd_ *= 1.0 - wnd_th_;
00491 awnd_ += wnd_th_ * cwnd_;
00492 }