00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] =
00022 "@(#) /home/ctk21/cvsroot//hssstcp/ns/ns-2.1b9/tcp/tcp-fack.cc,v 1.2 2002/08/12 10:43:58 ctk21 Exp (PSC)";
00023 #endif
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <sys/types.h>
00028
00029 #include "ip.h"
00030 #include "tcp.h"
00031 #include "flags.h"
00032 #include "scoreboard.h"
00033 #include "random.h"
00034 #include "tcp-fack.h"
00035 #include "template.h"
00036
00037 static class FackTcpClass : public TclClass {
00038 public:
00039 FackTcpClass() : TclClass("Agent/TCP/Fack") {}
00040 TclObject* create(int, const char*const*) {
00041 return (new FackTcpAgent());
00042 }
00043 } class_fack;
00044
00045
00046 FackTcpAgent::FackTcpAgent() : timeout_(FALSE), wintrim_(0),
00047 wintrimmult_(.5), rampdown_(0), fack_(-1), retran_data_(0),
00048 ss_div4_(0)
00049 {
00050 bind_bool("ss-div4_", &ss_div4_);
00051 bind_bool("rampdown_", &rampdown_);
00052 scb_ = new ScoreBoard(new ScoreBoardNode[SBSIZE],SBSIZE);
00053 }
00054
00055 FackTcpAgent::~FackTcpAgent(){
00056 delete [] scb_;
00057 }
00058
00059 int FackTcpAgent::window()
00060 {
00061 int win;
00062 win = int((cwnd_ < wnd_ ? (double) cwnd_ : (double) wnd_) + wintrim_);
00063 return (win);
00064 }
00065
00066 void FackTcpAgent::reset ()
00067 {
00068 scb_->ClearScoreBoard();
00069 TcpAgent::reset ();
00070 }
00071
00072
00073
00074
00075 void FackTcpAgent::oldack(Packet* pkt)
00076 {
00077 hdr_tcp *tcph = hdr_tcp::access(pkt);
00078
00079 last_ack_ = tcph->seqno();
00080 highest_ack_ = last_ack_;
00081 fack_ = max(fack_,highest_ack_);
00082
00083
00084
00085
00086
00087 maxseq_ = max(maxseq_, highest_ack_);
00088 if (t_seqno_ < last_ack_ + 1)
00089 t_seqno_ = last_ack_ + 1;
00090 newtimer(pkt);
00091 if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
00092 rtt_active_ = 0;
00093 t_backoff_ = 1;
00094 }
00095
00096 double tao = Scheduler::instance().clock() - tcph->ts_echo();
00097 rtt_update(tao);
00098 if (ts_resetRTO_) {
00099
00100
00101
00102 t_backoff_ = 1;
00103 }
00104
00105 awnd_ *= 1.0 - wnd_th_;
00106 awnd_ += wnd_th_ * cwnd_;
00107
00108 if ((highest_ack_ >= curseq_-1) && !closed_) {
00109 closed_ = 1;
00110 finish();
00111 }
00112 }
00113
00114
00115 int FackTcpAgent::maxsack(Packet *pkt)
00116 {
00117 hdr_tcp *tcph = hdr_tcp::access(pkt);
00118 int maxsack=-1, sack_index;
00119
00120 for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) {
00121 if (tcph->sa_right(sack_index) > maxsack)
00122 maxsack = tcph->sa_right(sack_index);
00123 }
00124 return (maxsack-1);
00125 }
00126
00127
00128 void FackTcpAgent::recv_newack_helper(Packet *pkt) {
00129 newack(pkt);
00130 opencwnd();
00131
00132 if ((highest_ack_ >= curseq_-1) && !closed_) {
00133 closed_ = 1;
00134 finish();
00135 }
00136 }
00137
00138 void FackTcpAgent::recv(Packet *pkt, Handler*)
00139 {
00140 hdr_tcp *tcph = hdr_tcp::access(pkt);
00141 int ms;
00142
00143 #ifdef notdef
00144 if (pkt->type_ != PT_ACK) {
00145 Tcl::instance().evalf("%s error \"received non-ack\"",
00146 name());
00147 Packet::free(pkt);
00148 return;
00149 }
00150 #endif
00151
00152 ts_peer_ = tcph->ts();
00153 if (hdr_flags::access(pkt)->ecnecho() && ecn_)
00154 ecn(tcph->seqno());
00155 recv_helper(pkt);
00156
00157 if (!fastrecov_) {
00158 if ((int)tcph->seqno() > last_ack_ && tcph->sa_length() == 0) {
00159
00160
00161
00162 recv_newack_helper(pkt);
00163 fack_ = last_ack_;
00164 timeout_ = FALSE;
00165 scb_->ClearScoreBoard();
00166 retran_data_ = 0;
00167 wintrim_ = 0;
00168 } else if ((int)tcph->seqno() < last_ack_) {
00169
00170
00171 } else {
00172 retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph);
00173 oldack(pkt);
00174 ms = maxsack(pkt);
00175 if (ms > fack_)
00176 fack_ = ms;
00177 if (fack_ >= t_seqno_)
00178 t_seqno_ = fack_ + 1;
00179 dupacks_ = (fack_ - last_ack_) - 1;
00180
00181
00182
00183 if (dupacks_ >= numdupacks_) {
00184
00185
00186
00187
00188
00189 recover_ = t_seqno_;
00190 last_cwnd_action_ = CWND_ACTION_DUPACK;
00191 if ((ss_div4_ == 1) && (cwnd_ <= ssthresh_ + .5)) {
00192 cwnd_ /= 2;
00193 wintrimmult_ = .75;
00194 } else {
00195 wintrimmult_ = .5;
00196 }
00197 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
00198
00199 if (rampdown_) {
00200 wintrim_ = (t_seqno_ - fack_ - 1) * wintrimmult_;
00201 }
00202 reset_rtx_timer(1,0);
00203 fastrecov_ = TRUE;
00204 scb_->MarkRetran (last_ack_+1, t_seqno_);
00205 retran_data_++;
00206 output(last_ack_ + 1, TCP_REASON_DUPACK);
00207 }
00208 }
00209 if (dupacks_ == 0)
00210 send_much(FALSE, 0, maxburst_);
00211 } else {
00212
00213 oldack(pkt);
00214 ms = maxsack(pkt);
00215 if (ms > fack_) {
00216 if (rampdown_) {
00217 wintrim_ -= ((float)ms - (float)fack_)* wintrimmult_;
00218 if (wintrim_< 0)
00219 wintrim_ = 0;
00220 }
00221 fack_ = ms;
00222 }
00223
00224 if (fack_ >= t_seqno_)
00225 t_seqno_ = fack_ + 1;
00226
00227 retran_data_ -= scb_->UpdateScoreBoard (highest_ack_, tcph);
00228
00229
00230
00231 timeout_ |= scb_->CheckSndNxt (tcph);
00232
00233 opencwnd();
00234
00235 if (retran_data_ < 0) {
00236 printf("Error, retran_data_ < 0");
00237 }
00238
00239 if ((int)tcph->sa_length() == 0 && (last_ack_ >= recover_)) {
00240
00241 fastrecov_ = FALSE;
00242 timeout_ = FALSE;
00243 scb_->ClearScoreBoard();
00244 retran_data_ = 0;
00245 wintrim_ = 0;
00246 dupacks_ = 0;
00247 }
00248 send_much(FALSE, 0, maxburst_);
00249 }
00250
00251 Packet::free(pkt);
00252 #ifdef notyet
00253 if (trace_)
00254 plot();
00255 #endif
00256 }
00257
00258 void FackTcpAgent::timeout(int tno)
00259 {
00260 if (tno == TCP_TIMER_RTX) {
00261 if (highest_ack_ == maxseq_ && !slow_start_restart_) {
00262
00263
00264
00265
00266 return;
00267 };
00268
00269 timeout_ = FALSE;
00270 if (highest_ack_ > last_ack_)
00271 last_ack_ = highest_ack_;
00272 #ifdef DEBUGSACK1A
00273 printf ("timeout. highest_ack: %d seqno: %d\n",
00274 highest_ack_, t_seqno_);
00275 #endif
00276 retran_data_ = 0;
00277 last_cwnd_action_ = CWND_ACTION_TIMEOUT;
00278
00279 if (highest_ack_ == maxseq_ && restart_bugfix_)
00280 slowdown(CLOSE_CWND_INIT);
00281 else {
00282
00283 slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
00284 }
00285 scb_->ClearScoreBoard();
00286
00287 if (highest_ack_ == maxseq_)
00288 reset_rtx_timer(TCP_REASON_TIMEOUT,0);
00289 else
00290 reset_rtx_timer(TCP_REASON_TIMEOUT,1);
00291 fack_ = last_ack_;
00292 t_seqno_ = last_ack_ + 1;
00293 send_much(0, TCP_REASON_TIMEOUT);
00294 } else {
00295 TcpAgent::timeout(tno);
00296 }
00297 }
00298
00299
00300 void FackTcpAgent::send_much(int force, int reason, int maxburst)
00301 {
00302 register int found, npacket = 0;
00303 send_idle_helper();
00304 int win = window();
00305 int xmit_seqno;
00306
00307 if (!force && delsnd_timer_.status() == TIMER_PENDING)
00308 return;
00309
00310
00311
00312
00313
00314 if (burstsnd_timer_.status() == TIMER_PENDING)
00315 burstsnd_timer_.cancel();
00316 found = 1;
00317
00318
00319
00320 while (( t_seqno_ <= fack_ + win - retran_data_) && (!timeout_)) {
00321 if (overhead_ == 0 || force) {
00322 found = 0;
00323 xmit_seqno = scb_->GetNextRetran ();
00324 #ifdef DEBUGSACK1A
00325 printf("highest_ack: %d xmit_seqno: %d timeout: %d seqno: %d fack: % d win: %d retran_data: %d\n",
00326 highest_ack_, xmit_seqno, timeout_, t_seqno_, fack_, win, retran_data_);
00327 #endif
00328
00329 if (xmit_seqno == -1) {
00330
00331
00332
00333
00334 if (t_seqno_ >= curseq_)
00335 return;
00336 found = 1;
00337 xmit_seqno = t_seqno_++;
00338 #ifdef DEBUGSACK1A
00339 printf("sending %d fastrecovery: %d win %d\n",
00340 xmit_seqno, fastrecov_, win);
00341 #endif
00342 } else {
00343 found = 1;
00344 scb_->MarkRetran (xmit_seqno, t_seqno_);
00345 retran_data_++;
00346 win = window();
00347 }
00348 if (found) {
00349 output(xmit_seqno, reason);
00350 if (t_seqno_ <= xmit_seqno) {
00351 printf("Hit a strange case 2.\n");
00352 t_seqno_ = xmit_seqno + 1;
00353 }
00354 npacket++;
00355 }
00356 } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
00357
00358
00359
00360 delsnd_timer_.resched(Random::uniform(overhead_));
00361 return;
00362 }
00363 if (maxburst && npacket == maxburst)
00364 break;
00365 }
00366
00367 send_helper(maxburst);
00368 }
00369
00370
00371
00372
00373 void FackTcpAgent::opencwnd()
00374 {
00375 TcpAgent::opencwnd();
00376
00377
00378 if (maxcwnd_ && (int (cwnd_) > maxcwnd_))
00379 cwnd_ = maxcwnd_;
00380 }
00381
00382
00383 void FackTcpAgent::plot()
00384 {
00385 #ifdef notyet
00386 double t = Scheduler::instance().clock();
00387 sprintf(trace_->buffer(), "t %g %d rtt %g\n",
00388 t, class_, t_rtt_ * tcp_tick_);
00389 trace_->dump();
00390 sprintf(trace_->buffer(), "t %g %d dev %g\n",
00391 t, class_, t_rttvar_ * tcp_tick_);
00392 trace_->dump();
00393 sprintf(trace_->buffer(), "t %g %d win %f\n", t, class_, cwnd_);
00394 trace_->dump();
00395 sprintf(trace_->buffer(), "t %g %d bck %d\n", t, class_, t_backoff_);
00396 trace_->dump();
00397 #endif
00398 }