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 Mar 6 16:47:52 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6