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