Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

tcp-fs.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * tcp-fs: TCP with "fast start", a procedure for avoiding the penalty of
00004  * slow start when a connection resumes after a pause. The connection tries
00005  * to reuse values old values of variables such as cwnd_, ssthresh_, srtt_,
00006  * etc., with suitable modifications. The same procedure as used in tcp-asym
00007  * is used to clock out packets until ack clocking kicks in. A connection 
00008  * doing fast start protects itself and other connections in the network against 
00009  * the adverse consequences of stale information by (a) marking all packets sent 
00010  * during fast start as low priority for the purposes of a priority-drop router, 
00011  * and (b) quickly detecting the loss of several fast start packets and falling 
00012  * back to a regular slow start, almost as if a fast start had never been attempted
00013  * in the first place.
00014  * 
00015  * Contributed by Venkat Padmanabhan (padmanab@cs.berkeley.edu), 
00016  * Daedalus Research Group, U.C.Berkeley
00017  */
00018 
00019 #include "tcp-fs.h"
00020 
00021 void ResetTimer::expire(Event *) {
00022         a_->timeout(TCP_TIMER_RESET);
00023 }
00024 
00025 static class TcpFsClass : public TclClass {
00026 public:
00027         TcpFsClass() : TclClass("Agent/TCP/FS") {}
00028         TclObject* create(int, const char*const*) {
00029                 return (new TcpFsAgent());
00030         }
00031 } class_tcpfs;
00032 
00033 static class RenoTcpFsClass : public TclClass {
00034 public:
00035         RenoTcpFsClass() : TclClass("Agent/TCP/Reno/FS") {}
00036         TclObject* create(int, const char*const*) {
00037                 return (new RenoTcpFsAgent());
00038         }
00039 } class_renotcpfs;      
00040 
00041 static class NewRenoTcpFsClass : public TclClass {
00042 public:
00043         NewRenoTcpFsClass() : TclClass("Agent/TCP/Newreno/FS") {}
00044         TclObject* create(int, const char*const*) {
00045                 return (new NewRenoTcpFsAgent());
00046         }
00047 } class_newrenotcpfs;   
00048 
00049 #ifdef USE_FACK
00050 static class FackTcpFsClass : public TclClass {
00051 public:
00052         FackTcpFsClass() : TclClass("Agent/TCP/Fack/FS") {}
00053         TclObject* create(int, const char*const*) {
00054                 return (new FackTcpFsAgent());
00055         }
00056 } class_facktcpfs;      
00057 #endif
00058 
00059 
00060 /* mark packets sent as part of fast start */
00061 void
00062 TcpFsAgent::output_helper(Packet *pkt)
00063 {
00064         hdr_tcp *tcph = hdr_tcp::access(pkt);
00065         double now = Scheduler::instance().clock();
00066         double idle_time = now - last_recv_time_;
00067         double timeout = ((t_srtt_ >> 3) + t_rttvar_) * tcp_tick_ ;
00068         maxseq_ = max(maxseq_, highest_ack_);
00069 
00070         /* 
00071          * if the connection has been idle (with no outstanding data) for long 
00072          * enough, we enter the fast start phase. We compute the start and end
00073          * sequence numbers that define the fast start phase. Note that the
00074          * first packet to be sent next is not included because it would have
00075          * been sent even with regular slow start.
00076          */
00077         if ((idle_time > timeout) && (maxseq_ == highest_ack_) && (cwnd_ > 1)){
00078                 /*
00079                  * We set cwnd_ to a "safe" value: cwnd_/2 if the connection
00080                  * was in slow start before the start of the idle period and
00081                  * cwnd_-1 if it was in congestion avoidance phase.
00082                  */
00083 /*              if (cwnd_ < ssthresh_+1)*/
00084                 if (cwnd_ < ssthresh_)
00085                         cwnd_ = int(cwnd_/2);
00086                 else
00087                         cwnd_ -= 1;
00088                 /* set the start and end seq. nos. for the fast start phase */
00089                 fs_startseq_ = highest_ack_+2;
00090                 fs_endseq_ = highest_ack_+window()+1;
00091                 fs_mode_ = 1;
00092         }
00093         /* initially set fs_ flag to 0 */
00094         hdr_flags::access(pkt)->fs_ = 0;
00095         /* check if packet belongs to the fast start phase. */
00096         if (tcph->seqno() >= fs_startseq_ && tcph->seqno() < fs_endseq_ && fs_mode_) {
00097                 /* if not a retransmission, mark the packet */
00098                 if (tcph->seqno() > maxseq_) {
00099                         hdr_flags::access(pkt)->fs_ = 1;
00100                 }
00101         }
00102 }
00103 
00104 /* update last_output_time_ */
00105 void
00106 TcpFsAgent::recv_helper(Packet *) 
00107 {
00108         double now = Scheduler::instance().clock();
00109         last_recv_time_ = now;
00110 }
00111 
00112 /* schedule the next burst of data (of size at most maxburst) */
00113 void 
00114 TcpFsAgent::send_helper(int maxburst) 
00115 {
00116         /* 
00117          * If there is still data to be sent and there is space in the
00118          * window, set a timer to schedule the next burst. Note that
00119          * we wouldn't get here if TCP_TIMER_BURSTSEND were pending,
00120          * so we do not need an explicit check here.
00121          */
00122         if (t_seqno_ <= highest_ack_ + window() && t_seqno_ < curseq_) {
00123                 burstsnd_timer_.resched(t_exact_srtt_*maxburst/window());
00124         }
00125 }
00126 
00127 #ifdef USE_FACK
00128 /* schedule the next burst of data (of size at most maxburst) */
00129 void 
00130 FackTcpFsAgent::send_helper(int maxburst) 
00131 {
00132         /* 
00133          * If there is still data to be sent and there is space in the
00134          * window, set a timer to schedule the next burst. Note that
00135          * we wouldn't get here if TCP_TIMER_BURSTSEND were pending,
00136          * so we do not need an explicit check here.
00137          */
00138         if ((t_seqno_ <= fack_ + window() - retran_data_) && (!timeout_) && (t_seqno_ < curseq_)) {
00139                 burstsnd_timer_.resched(t_exact_srtt_*maxburst/window());
00140         }
00141 }
00142 #endif
00143 
00144 /* do appropriate processing depending on the length of idle time */
00145 void
00146 TcpFsAgent::send_idle_helper() 
00147 {
00148         // Commented out because they are not used
00149         // XXX What processing belong here??? - haoboy
00150 
00151         //double now = Scheduler::instance().clock();
00152         //double idle_time = now - last_recv_time_;
00153 }
00154 
00155 /* update srtt estimate */
00156 void
00157 TcpFsAgent::recv_newack_helper(Packet *pkt) 
00158 {
00159         hdr_tcp *tcph = hdr_tcp::access(pkt);
00160         double tao = Scheduler::instance().clock() - tcph->ts_echo();
00161         double g = 1/8; /* gain used for smoothing rtt */
00162         double h = 1/4; /* gain used for smoothing rttvar */
00163         double delta;
00164         int ackcount, i;
00165 
00166         /*
00167          * If we are counting the actual amount of data acked, ackcount >= 1.
00168          * Otherwise, ackcount=1 just as in standard TCP.
00169          */
00170         if (count_bytes_acked_)
00171                 ackcount = tcph->seqno() - last_ack_;
00172         else
00173                 ackcount = 1;
00174         newack(pkt);
00175         maxseq_ = max(maxseq_, highest_ack_);
00176         if (t_exact_srtt_ != 0) {
00177                 delta = tao - t_exact_srtt_;
00178                 if (delta < 0)
00179                         delta = -delta;
00180                 /* update the fine-grained estimate of the smoothed RTT */
00181                 if (t_exact_srtt_ != 0) 
00182                         t_exact_srtt_ = g*tao + (1-g)*t_exact_srtt_;
00183                 else
00184                         t_exact_srtt_ = tao;
00185                 /* update the fine-grained estimate of mean deviation in RTT */
00186                 delta -= t_exact_rttvar_;
00187                 t_exact_rttvar_ += h*delta;
00188         }
00189         else {
00190                 t_exact_srtt_ = tao;
00191                 t_exact_rttvar_ = tao/2;
00192         }
00193         /* grow cwnd. ackcount > 1 indicates that actual ack counting is enabled */
00194         for (i=0; i<ackcount; i++)
00195                 opencwnd();
00196         /* check if we are out of fast start mode */
00197         if (fs_mode_ && (highest_ack_ >= fs_endseq_-1)) 
00198                 fs_mode_ = 0;
00199         /* if the connection is done, call finish() */
00200         if ((highest_ack_ >= curseq_-1) && !closed_) {
00201                 closed_ = 1;
00202                 finish();
00203         }
00204 }
00205 
00206 void
00207 NewRenoTcpFsAgent::partialnewack_helper(Packet* pkt)
00208 {
00209         partialnewack(pkt);
00210         /* Do this because we may have retracted maxseq_ */
00211         maxseq_ = max(maxseq_, highest_ack_);
00212         if (fs_mode_ && fast_loss_recov_) {
00213                 /* 
00214                  * A partial new ack implies that more than one packet has been lost
00215                  * in the window. Rather than recover one loss per RTT, we get out of
00216                  * fast start mode and do a slow start (no rtx timeout, though).
00217                  */
00218                 timeout_nonrtx(TCP_TIMER_RESET);
00219         }
00220         else {
00221                 output(last_ack_ + 1, 0);
00222         }
00223 }
00224 
00225 void 
00226 TcpFsAgent::set_rtx_timer()
00227 {
00228         if (rtx_timer_.status() == TIMER_PENDING)
00229                 rtx_timer_.cancel();
00230         if (reset_timer_.status() == TIMER_PENDING)
00231                 reset_timer_.cancel();
00232         if (fs_mode_ && fast_loss_recov_ && fast_reset_timer_)
00233                 reset_timer_.resched(rtt_exact_timeout());
00234         else if (fs_mode_ && fast_loss_recov_)
00235                 reset_timer_.resched(rtt_timeout());
00236         else 
00237                 rtx_timer_.resched(rtt_timeout());
00238 }
00239 
00240 void 
00241 TcpFsAgent::cancel_rtx_timer() 
00242 {
00243         rtx_timer_.force_cancel();
00244         reset_timer_.force_cancel();
00245 }
00246 
00247 void 
00248 TcpFsAgent::cancel_timers() 
00249 {
00250         rtx_timer_.force_cancel();
00251         reset_timer_.force_cancel();
00252         burstsnd_timer_.force_cancel();
00253         delsnd_timer_.force_cancel();
00254 }
00255 
00256 void 
00257 TcpFsAgent::timeout_nonrtx(int tno) 
00258 {
00259         if (tno == TCP_TIMER_RESET) {
00260                 fs_mode_ = 0;   /* out of fast start mode */
00261                 dupacks_ = 0;   /* just to be safe */
00262                 if (highest_ack_ == maxseq_ && !slow_start_restart_) {
00263                         /*
00264                          * TCP option:
00265                          * If no outstanding data, then don't do anything.
00266                          */
00267                         return;
00268                 };
00269                 /* 
00270                  * If the pkt sent just before the fast start phase has not
00271                  * gotten through, treat this as a regular rtx timeout.
00272                  */
00273                 if (highest_ack_ < fs_startseq_-1) {
00274                         maxseq_ = fs_startseq_ - 1;
00275                         recover_ = maxseq_;
00276                         timeout(TCP_TIMER_RTX);
00277                 }
00278                 /* otherwise decrease window size to 1 but don't back off rtx timer */
00279                 else {
00280                         if (highest_ack_ > last_ack_)
00281                                 last_ack_ = highest_ack_;
00282                         maxseq_ = last_ack_;
00283                         recover_ = maxseq_;
00284                         last_cwnd_action_ = CWND_ACTION_TIMEOUT;
00285                         slowdown(CLOSE_CWND_INIT);
00286                         timeout_nonrtx_helper(tno);
00287                 }
00288         }
00289         else {
00290                 TcpAgent::timeout_nonrtx(tno);
00291         }
00292 }
00293 
00294 void 
00295 TcpFsAgent::timeout_nonrtx_helper(int tno)
00296 {
00297         if (tno == TCP_TIMER_RESET) {
00298                 reset_rtx_timer(0,0);
00299                 send_much(0, TCP_REASON_TIMEOUT, maxburst_);
00300         }
00301 }
00302 
00303 void 
00304 RenoTcpFsAgent::timeout_nonrtx_helper(int tno)
00305 {
00306         if (tno == TCP_TIMER_RESET) {
00307                 dupwnd_ = 0;
00308                 dupacks_ = 0;
00309                 TcpFsAgent::timeout_nonrtx_helper(tno);
00310         }
00311 }               
00312 
00313 void 
00314 NewRenoTcpFsAgent::timeout_nonrtx_helper(int tno)
00315 {
00316         if (tno == TCP_TIMER_RESET) {
00317                 dupwnd_ = 0;
00318                 dupacks_ = 0;
00319                 TcpFsAgent::timeout_nonrtx_helper(tno);
00320         }
00321 }
00322 
00323 #ifdef USE_FACK
00324 void 
00325 FackTcpFsAgent::timeout_nonrtx_helper(int tno)
00326 {
00327         if (tno == TCP_TIMER_RESET) {
00328                 timeout_ = FALSE;
00329                 retran_data_ = 0;
00330                 fack_ = last_ack_;
00331                 t_seqno_ = last_ack_ + 1;
00332                 reset_rtx_timer(TCP_REASON_TIMEOUT, 0);
00333                 send_much(0, TCP_REASON_TIMEOUT);
00334         }
00335 }
00336 #endif

Generated on Tue Apr 20 12:14:34 2004 for NS2.26SourcesOriginal by doxygen 1.3.3