00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <sys/types.h>
00027
00028 #include "ip.h"
00029 #include "tcp.h"
00030 #include "flags.h"
00031 #include "scoreboard.h"
00032 #include "scoreboard-rq.h"
00033 #include "random.h"
00034
00035 #define TRUE 1
00036 #define FALSE 0
00037 #define RECOVER_DUPACK 1
00038 #define RECOVER_TIMEOUT 2
00039 #define RECOVER_QUENCH 3
00040
00041 class Sack1TcpAgent : public TcpAgent {
00042 public:
00043 Sack1TcpAgent();
00044 virtual ~Sack1TcpAgent();
00045 virtual void recv(Packet *pkt, Handler*);
00046 int is_sacked(hdr_tcp *tcph, int seqlo, int seqhi);
00047 void reset();
00048 virtual void timeout(int tno);
00049 virtual void dupack_action();
00050 virtual void partial_ack_action();
00051 void plot();
00052 virtual void send_much(int force, int reason, int maxburst);
00053 protected:
00054 u_char timeout_;
00055 u_char fastrecov_;
00056 int pipe_;
00057 int partial_ack_;
00058
00059 int next_pkt_;
00060
00061 int firstpartial_;
00062 ScoreBoard* scb_;
00063 static const int SBSIZE=64;
00064 };
00065
00066 static class Sack1TcpClass : public TclClass {
00067 public:
00068 Sack1TcpClass() : TclClass("Agent/TCP/Sack1") {}
00069 TclObject* create(int, const char*const*) {
00070 return (new Sack1TcpAgent());
00071 }
00072 } class_sack;
00073
00074 Sack1TcpAgent::Sack1TcpAgent() : fastrecov_(FALSE), pipe_(-1), next_pkt_(0), firstpartial_(0)
00075 {
00076 bind_bool("partial_ack_", &partial_ack_);
00077
00078
00079
00080
00081 scb_ = new ScoreBoardRQ();
00082 }
00083
00084 Sack1TcpAgent::~Sack1TcpAgent(){
00085 delete scb_;
00086 }
00087
00088 void Sack1TcpAgent::reset ()
00089 {
00090 scb_->ClearScoreBoard();
00091 TcpAgent::reset ();
00092 }
00093
00094
00095 void Sack1TcpAgent::recv(Packet *pkt, Handler*)
00096 {
00097 hdr_tcp *tcph = hdr_tcp::access(pkt);
00098 int valid_ack = 0;
00099
00100 if (qs_approved_ == 1 && tcph->seqno() > last_ack_)
00101 endQuickStart();
00102 if (qs_requested_ == 1)
00103 processQuickStart(pkt);
00104 #ifdef notdef
00105 if (pkt->type_ != PT_ACK) {
00106 Tcl::instance().evalf("%s error \"received non-ack\"",
00107 name());
00108 Packet::free(pkt);
00109 return;
00110 }
00111 #endif
00112
00113 if (tcph->ts() < lastreset_) {
00114
00115 Packet::free(pkt);
00116 return;
00117 }
00118 ++nackpack_;
00119 int ecnecho = hdr_flags::access(pkt)->ecnecho();
00120 if (ecnecho && ecn_)
00121 ecn(tcph->seqno());
00122 if (tcph->seqno() >= last_ack_)
00123
00124 valid_ack = 1;
00125
00126
00127
00128
00129 if (!fastrecov_) {
00130
00131 if ((int)tcph->seqno() > last_ack_) {
00132
00133
00134
00135 firstpartial_ = 0;
00136 recv_newack_helper(pkt);
00137 timeout_ = FALSE;
00138 scb_->ClearScoreBoard();
00139 if (last_ack_ == 0 && delay_growth_) {
00140 cwnd_ = initial_window();
00141 }
00142 } else if ((int)tcph->seqno() < last_ack_) {
00143
00144 } else if (timeout_ == FALSE) {
00145 if (tcph->seqno() != last_ack_) {
00146 fprintf(stderr, "pkt seq %d should be %d\n" ,
00147 tcph->seqno(), last_ack_);
00148 abort();
00149 }
00150 scb_->UpdateScoreBoard (highest_ack_, tcph);
00151
00152
00153
00154
00155
00156 if(scb_->CheckUpdate()) {
00157 if (++dupacks_ == numdupacks(cwnd_)) {
00158
00159
00160
00161
00162
00163 dupack_action();
00164 } else if (dupacks_ < numdupacks(cwnd_) && singledup_ ) {
00165 send_one();
00166 }
00167 }
00168 if (sfrto_enabled_ && frto_ == 2) {
00169
00170
00171
00172
00173
00174
00175 if (scb_->IsChanged() &&
00176 !is_sacked(tcph, recover_, maxseq_)) {
00177 spurious_timeout();
00178 } else {
00179 t_seqno_ = highest_ack_ + 1;
00180 cwnd_ = frto_;
00181 frto_ = 0;
00182 dupacks_ = 0;
00183 }
00184 }
00185 }
00186 if (valid_ack || aggressive_maxburst_)
00187 if (dupacks_ == 0)
00188 send_much(FALSE, 0, maxburst_);
00189 } else {
00190
00191 --pipe_;
00192 if ((int)tcph->seqno() >= recover_) {
00193
00194 recover_ = 0;
00195 fastrecov_ = FALSE;
00196 newack(pkt);
00197
00198 if ((highest_ack_ >= curseq_-1) && !closed_) {
00199 closed_ = 1;
00200 finish();
00201 }
00202 timeout_ = FALSE;
00203 scb_->ClearScoreBoard();
00204
00205
00206 } else if ((int)tcph->seqno() > highest_ack_) {
00207
00208
00209 highest_ack_ = (int)tcph->seqno();
00210 scb_->UpdateScoreBoard (highest_ack_, tcph);
00211 if (partial_ack_) {
00212
00213
00214
00215 partial_ack_action();
00216 ++pipe_;
00217 if (firstpartial_ == 0) {
00218 newtimer(pkt);
00219 t_backoff_ = 1;
00220 firstpartial_ = 1;
00221 }
00222 } else {
00223 --pipe_;
00224 newtimer(pkt);
00225 t_backoff_ = 1;
00226
00227
00228
00229
00230
00231 }
00232 } else if (timeout_ == FALSE) {
00233
00234 scb_->UpdateScoreBoard (highest_ack_, tcph);
00235 if(scb_->CheckUpdate()) {
00236 if (dupacks_ > 0)
00237 dupacks_++;
00238 }
00239 }
00240 if (valid_ack || aggressive_maxburst_)
00241 send_much(FALSE, 0, maxburst_);
00242 }
00243
00244 Packet::free(pkt);
00245 #ifdef notyet
00246 if (trace_)
00247 plot();
00248 #endif
00249 }
00250
00251
00252
00253
00254
00255
00256 int Sack1TcpAgent::is_sacked(hdr_tcp *tcph, int seqlo, int seqhi)
00257 {
00258 int i, sleft, sright;
00259 for (i=0; i < tcph->sa_length(); i++) {
00260 sleft = tcph->sa_left(i);
00261 sright = tcph->sa_right(i);
00262
00263 if ((sright > seqlo && sright <= seqhi) ||
00264 (sleft >= seqlo && sleft < seqhi) ||
00265 (sleft < seqlo && sright > seqhi)) {
00266 return TRUE;
00267 }
00268 }
00269 return FALSE;
00270 }
00271
00272
00273 void
00274 Sack1TcpAgent::dupack_action()
00275 {
00276 int recovered = (highest_ack_ > recover_);
00277 if (recovered || (!bug_fix_ && !ecn_)) {
00278 goto sack_action;
00279 }
00280
00281 if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
00282 last_cwnd_action_ = CWND_ACTION_DUPACK;
00283
00284
00285
00286
00287
00288
00289
00290
00291 reset_rtx_timer(1,0);
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 if (singledup_ && LimTransmitFix_) {
00302 pipe_ = maxseq_ - highest_ack_ - 1;
00303 }
00304 else {
00305
00306 pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
00307 }
00308 fastrecov_ = TRUE;
00309 scb_->MarkRetran(highest_ack_+1);
00310 output(last_ack_ + 1, TCP_REASON_DUPACK);
00311 return;
00312 }
00313
00314 if (bug_fix_) {
00315
00316
00317
00318
00319
00320 return;
00321 }
00322
00323 sack_action:
00324 recover_ = maxseq_;
00325 if (oldCode_) {
00326 pipe_ = int(cwnd_) - numdupacks(cwnd_);
00327 } else if (singledup_ && LimTransmitFix_) {
00328 pipe_ = maxseq_ - highest_ack_ - 1;
00329 }
00330 else {
00331
00332 pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
00333 }
00334 reset_rtx_timer(1,0);
00335 fastrecov_ = TRUE;
00336 scb_->MarkRetran(highest_ack_+1);
00337 if (!lossQuickStart()) {
00338
00339 trace_event("FAST_RECOVERY");
00340 last_cwnd_action_ = CWND_ACTION_DUPACK;
00341 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
00342 output(last_ack_ + 1, TCP_REASON_DUPACK);
00343
00344
00345
00346
00347 }
00348 return;
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 void
00363 Sack1TcpAgent::partial_ack_action()
00364 {
00365 if (next_pkt_ < highest_ack_ + 1) {
00366 next_pkt_ = highest_ack_ + 1;
00367 }
00368
00369
00370 int i;
00371 for (i = 1; i<=2; i++) {
00372 int getNext = scb_->GetNextUnacked(next_pkt_);
00373 if (getNext > next_pkt_) {
00374 next_pkt_ = getNext;
00375 }
00376 if (t_seqno_ < next_pkt_) {
00377 t_seqno_ = next_pkt_;
00378 }
00379 output(next_pkt_, TCP_REASON_PARTIALACK);
00380 scb_->MarkRetran(next_pkt_);
00381 ++next_pkt_;
00382 }
00383 return;
00384 }
00385
00386 void Sack1TcpAgent::timeout(int tno)
00387 {
00388
00389 int no_frto = fastrecov_;
00390
00391 if (tno == TCP_TIMER_RTX) {
00392
00393
00394
00395
00396
00397
00398
00399 dupacks_ = 0;
00400 fastrecov_ = FALSE;
00401 timeout_ = TRUE;
00402 if (highest_ack_ > last_ack_)
00403 last_ack_ = highest_ack_;
00404 #ifdef DEBUGSACK1A
00405 printf ("timeout. highest_ack: %i seqno: %i fid: %i\n",
00406 (int)highest_ack_, (int)t_seqno_, fid_);
00407 #endif
00408 recover_ = maxseq_;
00409 scb_->ClearScoreBoard();
00410 }
00411 TcpAgent::timeout(tno);
00412
00413
00414 if (no_frto)
00415 frto_ = 0;
00416 }
00417
00418 void Sack1TcpAgent::send_much(int force, int reason, int maxburst)
00419 {
00420 register int found, npacket = 0;
00421 int win = window();
00422 int xmit_seqno;
00423
00424 found = 1;
00425 if (!force && delsnd_timer_.status() == TIMER_PENDING)
00426 return;
00427
00428
00429
00430 while (((!fastrecov_ && (t_seqno_ <= last_ack_ + win)) ||
00431 (fastrecov_ && (pipe_ < int(cwnd_))))
00432 && t_seqno_ < curseq_ && found) {
00433
00434 if (overhead_ == 0 || force) {
00435 found = 0;
00436 xmit_seqno = scb_->GetNextRetran ();
00437
00438 #ifdef DEBUGSACK1A
00439 printf("highest_ack: %d xmit_seqno: %d\n",
00440 (int)highest_ack_, xmit_seqno);
00441 #endif
00442 if (xmit_seqno == -1) {
00443 if ((!fastrecov_ && t_seqno_<=highest_ack_+win)||
00444 (fastrecov_ && t_seqno_<=highest_ack_+int(wnd_))) {
00445 found = 1;
00446 xmit_seqno = t_seqno_++;
00447 #ifdef DEBUGSACK1A
00448 printf("sending %d fastrecovery: %d win %d\n",
00449 xmit_seqno, fastrecov_, win);
00450 #endif
00451 }
00452 } else if (recover_>0 && xmit_seqno<=highest_ack_+int(wnd_)) {
00453 found = 1;
00454 scb_->MarkRetran (xmit_seqno);
00455 win = window();
00456 }
00457 if (found) {
00458 output(xmit_seqno, reason);
00459 if (t_seqno_ <= xmit_seqno)
00460 t_seqno_ = xmit_seqno + 1;
00461 npacket++;
00462 pipe_++;
00463 if (QOption_)
00464 process_qoption_after_send () ;
00465 if (qs_approved_ == 1) {
00466 double delay = (double) t_rtt_ * tcp_tick_ / cwnd_;
00467 delsnd_timer_.resched(delay);
00468 return;
00469 }
00470 }
00471 } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
00472
00473
00474
00475
00476
00477 delsnd_timer_.resched(Random::uniform(overhead_));
00478 return;
00479 }
00480 if (maxburst && npacket == maxburst)
00481 break;
00482 }
00483 }
00484
00485 void Sack1TcpAgent::plot()
00486 {
00487 #ifdef notyet
00488 double t = Scheduler::instance().clock();
00489 sprintf(trace_->buffer(), "t %g %d rtt %g\n",
00490 t, class_, t_rtt_ * tcp_tick_);
00491 trace_->dump();
00492 sprintf(trace_->buffer(), "t %g %d dev %g\n",
00493 t, class_, t_rttvar_ * tcp_tick_);
00494 trace_->dump();
00495 sprintf(trace_->buffer(), "t %g %d win %f\n", t, class_, cwnd_);
00496 trace_->dump();
00497 sprintf(trace_->buffer(), "t %g %d bck %d\n", t, class_, t_backoff_);
00498 trace_->dump();
00499 #endif
00500 }