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

tcp-rfc793edu.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1999  International Computer Science Institute
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. All advertising materials mentioning features or use of this software
00014  *    must display the following acknowledgement:
00015  *      This product includes software developed by ACIRI, the AT&T
00016  *      Center for Internet Research at ICSI (the International Computer
00017  *      Science Institute).
00018  * 4. Neither the name of ACIRI nor of ICSI may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <sys/types.h>
00038 #include <math.h>
00039 
00040 
00041 #include "ip.h"
00042 #include "tcp-rfc793edu.h"
00043 #include "flags.h"
00044 
00045 // Original code contributed by Fernando Cela Diaz,
00046 // <fcela@ce.chalmers.se>.
00047 // For more information, see the following:
00048 // URL "http://www.ce.chalmers.se/~fcela/tcp-tour.html"
00049 
00050 static class  RFC793eduTcpClass : public TclClass {
00051 public:
00052         RFC793eduTcpClass() : TclClass("Agent/TCP/RFC793edu") {}
00053         TclObject* create(int, const char*const*) {
00054                 return (new RFC793eduTcpAgent());
00055         }
00056 } class_rfc793edu;
00057 
00058 
00059 RFC793eduTcpAgent::RFC793eduTcpAgent() : TcpAgent() 
00060 {
00061 }
00062 
00063 void
00064 RFC793eduTcpAgent::delay_bind_init_all()
00065 {
00066         delay_bind_init_one("add793expbackoff_");
00067         delay_bind_init_one("add793jacobsonrtt_");
00068         delay_bind_init_one("add793fastrtx_");
00069         delay_bind_init_one("add793slowstart_");
00070         delay_bind_init_one("add793additiveinc_");
00071         delay_bind_init_one("add793karnrtt_");
00072         delay_bind_init_one("add793exponinc_"); 
00073         delay_bind_init_one("rto_");
00074         TcpAgent::delay_bind_init_all();
00075         reset();
00076 }
00077 
00078 int
00079 RFC793eduTcpAgent::delay_bind_dispatch(const char *varName, 
00080                                        const char *localName,TclObject *tracer)
00081 {
00082         if (delay_bind_bool(varName, localName, "add793expbackoff_", 
00083                             &add793expbackoff_, tracer)) 
00084                 return TCL_OK;
00085         if (delay_bind_bool(varName, localName, "add793jacobsonrtt_", 
00086                             &add793jacobsonrtt_, tracer)) 
00087                 return TCL_OK;
00088         if (delay_bind_bool(varName, localName, "add793fastrtx_", 
00089                             &add793fastrtx_, tracer)) 
00090                 return TCL_OK;
00091         if (delay_bind_bool(varName, localName, "add793slowstart_", 
00092                             &add793slowstart_, tracer)) 
00093                 return TCL_OK;
00094         if (delay_bind_bool(varName, localName, "add793slowstart_", 
00095                             &add793slowstart_, tracer)) 
00096                 return TCL_OK;
00097         if (delay_bind_bool(varName, localName, "add793additiveinc_", 
00098                             &add793additiveinc_, tracer)) 
00099                 return TCL_OK;
00100         if (delay_bind_bool(varName, localName, "add793karnrtt_", 
00101                             &add793karnrtt_, tracer)) 
00102                 return TCL_OK;
00103         if (delay_bind_bool(varName, localName, "add793exponinc_", 
00104                             &add793exponinc_, tracer)) 
00105                 return TCL_OK;
00106         if (delay_bind(varName, localName, "rto_", 
00107                        &rto_, tracer)) 
00108                 return TCL_OK;
00109         return TcpAgent::delay_bind_dispatch(varName, localName, tracer);
00110 }
00111 
00112 void RFC793eduTcpAgent::reset()
00113 {
00114   //Reset here protected vars. 
00115 
00116   rto_ = rtxcur_init_ / tcp_tick_;
00117   TcpAgent::reset();
00118 }
00119 
00120 
00121 void RFC793eduTcpAgent::rtt_update(double tao)
00122 {
00123   double now = Scheduler::instance().clock();
00124   if (ts_option_)
00125     t_rtt_ = int(tao /tcp_tick_ + 0.5);
00126   else {
00127     double sendtime = now - tao;
00128     sendtime += boot_time_;
00129     double tickoff = fmod(sendtime, tcp_tick_);
00130     t_rtt_ = int((tao + tickoff) / tcp_tick_);
00131   }
00132   if (t_rtt_ < 1)
00133     t_rtt_ = 1;
00134   
00135       // Jacobson/Karels RTT estimation as implemented in tcp.cc
00136       //
00137       // Diference    = SampleRTT - EstimatedRTT
00138       // EstimatedRTT = EstimatedRTT + (delta * Difference)
00139       // Deviation    = Deviation + delta * (|Difference| - Deviation)
00140       // TimeOut      = EstimatedRTT + 4 * Deviation
00141 
00142       // srtt has 3 bits to the right of the binary point
00143       // rttvar has 2
00144       if (t_srtt_ != 0) {
00145         register short delta;
00146         delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS);      // d = (m - a0)
00147         if ((t_srtt_ += delta) <= 0)    // a1 = 7/8 a0 + 1/8 m
00148           t_srtt_ = 1;
00149         if (delta < 0)
00150           delta = -delta;
00151         delta -= (t_rttvar_ >> T_RTTVAR_BITS);
00152         if ((t_rttvar_ += delta) <= 0)  // var1 = 3/4 var0 + 1/4 |d|
00153           t_rttvar_ = 1;
00154       } else {
00155         t_srtt_ = t_rtt_ << T_SRTT_BITS;                // srtt = rtt
00156         t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1);        // rttvar = rtt / 2
00157       }
00158 
00159    if (add793jacobsonrtt_) 
00160     {
00161       //
00162       // Current retransmit value is 
00163       //    (unscaled) smoothed round trip estimate
00164       //    plus 2^rttvar_exp_ times (unscaled) rttvar. 
00165       //
00166       rto_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS)))                   + t_srtt_)  >> T_SRTT_BITS );
00167     }
00168    else { 
00169      // RFC 793
00170      rto_ = (t_srtt_ >> ( T_SRTT_BITS - 1) );
00171    }
00172       t_rtxcur_ = rto_  * tcp_tick_;
00173   return;
00174 }
00175 
00176 
00177 void RFC793eduTcpAgent::rtt_backoff()
00178 {
00179   if (add793expbackoff_) {
00180     // Standard Tahoe Code
00181 
00182         if (t_backoff_ < 64)
00183                 t_backoff_ <<= 1;
00184 
00185         if (t_backoff_ > 8) {
00186                 /*
00187                  * If backed off this far, clobber the srtt
00188                  * value, storing it in the mean deviation
00189                  * instead.
00190                  */
00191                 t_rttvar_ += (t_srtt_ >> T_SRTT_BITS);
00192                 t_srtt_ = 0;
00193         }
00194   }
00195   // safe paranoia
00196   else 
00197     t_backoff_ = 1;
00198 }
00199 
00200 
00201 void RFC793eduTcpAgent::recv(Packet *pkt, Handler*)
00202 {
00203         hdr_tcp *tcph = hdr_tcp::access(pkt);
00204 #ifdef notdef
00205         if (pkt->type_ != PT_ACK) {
00206                 Tcl::instance().evalf("%s error \"received non-ack\"",
00207                                       name());
00208                 Packet::free(pkt);
00209                 return;
00210         }
00211 #endif
00212         ++nackpack_;
00213         ts_peer_ = tcph->ts();
00214         int ecnecho = hdr_flags::access(pkt)->ecnecho();
00215         if (ecnecho && ecn_)
00216                 ecn(tcph->seqno());
00217         recv_helper(pkt);
00218         /* grow cwnd and check if the connection is done */ 
00219         if (tcph->seqno() > last_ack_) {
00220                 recv_newack_helper(pkt);
00221                 if (last_ack_ == 0 && delay_growth_) { 
00222                         cwnd_ = initial_window();
00223                 }
00224         } else if (tcph->seqno() == last_ack_) {
00225                 if (hdr_flags::access(pkt)->eln_ && eln_) {
00226                         tcp_eln(pkt);
00227                         return;
00228                 }
00229                 // fast retransmission
00230                 if ( (++dupacks_ == numdupacks_) && add793fastrtx_ ) {
00231                         dupack_action();
00232                 }
00233         }
00234         Packet::free(pkt);
00235         /*
00236          * Try to send more data.
00237          */
00238         send_much(0, 0, maxburst_);
00239 }
00240 
00241 
00242 
00243 void RFC793eduTcpAgent::opencwnd()
00244 {
00245         if ( !(add793slowstart_ || add793exponinc_ || add793additiveinc_)) {
00246           cwnd_ = wnd_;
00247         } else if (((cwnd_ < ssthresh_) && (!add793additiveinc_)) 
00248                    || add793exponinc_)
00249           {
00250                 /* slow-start (exponential) */
00251                 if (add793exponinc_ && (cwnd_ < ssthresh_))
00252                   cwnd_ = ssthresh_;
00253                 else cwnd_ += 1;
00254         } else {
00255                 /* linear */
00256                 double f;
00257 
00258                 if (add793additiveinc_ && (cwnd_ < ssthresh_))
00259                   cwnd_ = ssthresh_;
00260                 else {
00261                   switch (wnd_option_) {
00262                   case 0:
00263                     if (++count_ >= cwnd_) {
00264                       count_ = 0;
00265                       ++cwnd_;
00266                     }
00267                     break;
00268                     
00269                   case 1:
00270                         /* This is the standard algorithm. */
00271                     cwnd_ += 1 / cwnd_;
00272                     break;
00273                     
00274                   case 2:
00275                     /* These are window increase algorithms
00276                      * for experimental purposes only. */
00277                     f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
00278                     f *= f;
00279                     f *= wnd_const_;
00280                     f += fcnt_;
00281                     if (f > cwnd_) {
00282                       fcnt_ = 0;
00283                       ++cwnd_;
00284                     } else
00285                       fcnt_ = f;
00286                     break;
00287                         
00288                   case 3:
00289                     f = awnd_;
00290                     f *= f;
00291                     f *= wnd_const_;
00292                     f += fcnt_;
00293                     if (f > cwnd_) {
00294                       fcnt_ = 0;
00295                       ++cwnd_;
00296                     } else
00297                       fcnt_ = f;
00298                     break;
00299                     
00300                   case 4:
00301                     f = awnd_;
00302                     f *= wnd_const_;
00303                     f += fcnt_;
00304                     if (f > cwnd_) {
00305                       fcnt_ = 0;
00306                       ++cwnd_;
00307                     } else
00308                                 fcnt_ = f;
00309                     break;
00310                   case 5:
00311                     f = (t_srtt_ >> T_SRTT_BITS) * tcp_tick_;
00312                     f *= wnd_const_;
00313                     f += fcnt_;
00314                     if (f > cwnd_) {
00315                       fcnt_ = 0;
00316                       ++cwnd_;
00317                     } else
00318                       fcnt_ = f;
00319                     break;
00320                     
00321                   default:
00322 #ifdef notdef
00323                     /*XXX*/
00324                     error("illegal window option %d", wnd_option_);
00325 #endif
00326                     abort();
00327                   }
00328                 }
00329         }
00330         // if maxcwnd_ is set (nonzero), make it the cwnd limit
00331         if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
00332           cwnd_ = maxcwnd_;
00333         
00334         return;
00335 }
00336 
00337 
00338 void  RFC793eduTcpAgent::output(int seqno, int reason)
00339 {
00340         int force_set_rtx_timer = 0;
00341         Packet* p = allocpkt();
00342         hdr_tcp *tcph = hdr_tcp::access(p);
00343         hdr_flags* hf = hdr_flags::access(p);
00344         tcph->seqno() = seqno;
00345         tcph->ts() = Scheduler::instance().clock();
00346         tcph->ts_echo() = ts_peer_;
00347         tcph->reason() = reason;
00348         if (ecn_) {
00349                 hf->ect() = 1;  // ECN-capable transport
00350         }
00351         if (cong_action_) {
00352                 hf->cong_action() = TRUE;  // Congestion action.
00353                 cong_action_ = FALSE;
00354         }
00355         /* Check if this is the initial SYN packet. */
00356         if (seqno == 0) {
00357                 if (syn_) {
00358                         hdr_cmn::access(p)->size() = tcpip_base_hdr_size_;
00359                 }
00360                 if (ecn_) {
00361                         hf->ecnecho() = 1;
00362 //                      hf->cong_action() = 1;
00363                         hf->ect() = 0;
00364                 }
00365         }
00366         int bytes = hdr_cmn::access(p)->size();
00367 
00368         /* if no outstanding data, be sure to set rtx timer again */
00369         if (highest_ack_ == maxseq_)
00370                 force_set_rtx_timer = 1;
00371         /* call helper function to fill in additional fields */
00372         output_helper(p);
00373 
00374         ++ndatapack_;
00375         ndatabytes_ += bytes;
00376         send(p, 0);
00377         if (seqno == curseq_ && seqno > maxseq_)
00378                 idle();  // Tell application I have sent everything so far
00379         if (seqno > maxseq_) {
00380                 maxseq_ = seqno;
00381                 if (!rtt_active_) {
00382                         rtt_active_ = 1;                        
00383                         if (seqno > rtt_seq_) {
00384                                 rtt_seq_ = seqno;                       
00385                                 rtt_ts_ = Scheduler::instance().clock();
00386                         }
00387                                         
00388                 }
00389         } else {
00390           if (!add793karnrtt_) {
00391                 rtt_active_ = 1;
00392                 rtt_seq_ = seqno;                       
00393                 rtt_ts_ = Scheduler::instance().clock();
00394           }     
00395                 ++nrexmitpack_;
00396                 nrexmitbytes_ += bytes;
00397         }
00398         if (!(rtx_timer_.status() == TIMER_PENDING) || force_set_rtx_timer)
00399                 /* No timer pending.  Schedule one. */
00400                 set_rtx_timer();
00401 }
00402 
00403 void RFC793eduTcpAgent::recv_newack_helper(Packet *pkt) {
00404         //hdr_tcp *tcph = hdr_tcp::access(pkt);
00405         newack(pkt);
00406         if (!ect_ || !hdr_flags::access(pkt)->ecnecho() ||
00407                 (old_ecn_ && ecn_burst_)) 
00408                 /* If "old_ecn", this is not the first ACK carrying ECN-Echo
00409                  * after a period of ACKs without ECN-Echo.
00410                  * Therefore, open the congestion window. */
00411                 opencwnd();
00412         if (ect_) {
00413                 if (!hdr_flags::access(pkt)->ecnecho())
00414                         ecn_backoff_ = 0;
00415                 if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho())
00416                         ecn_burst_ = TRUE;
00417                 else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho())
00418                         ecn_burst_ = FALSE;
00419         }
00420         if (!ect_ && hdr_flags::access(pkt)->ecnecho() &&
00421                 !hdr_flags::access(pkt)->cong_action())
00422                 ect_ = 1;
00423         /* if the connection is done, call finish() */
00424         if ((highest_ack_ >= curseq_-1) && !closed_) {
00425                 closed_ = 1;
00426                 finish();
00427         }
00428 }
00429 
00430 void RFC793eduTcpAgent::newack(Packet* pkt)
00431 {
00432         double now = Scheduler::instance().clock();
00433         hdr_tcp *tcph = hdr_tcp::access(pkt);
00434         /* 
00435          * Wouldn't it be better to set the timer *after*
00436          * updating the RTT, instead of *before*? 
00437          */
00438         newtimer(pkt);
00439         dupacks_ = 0;
00440         last_ack_ = tcph->seqno();
00441         highest_ack_ = last_ack_;
00442 
00443         if (t_seqno_ < last_ack_ + 1)
00444                 t_seqno_ = last_ack_ + 1;
00445         /* 
00446          * Update RTT only if it's OK to do so from info in the flags header.
00447          * This is needed for protocols in which intermediate agents
00448          * in the network intersperse acks (e.g., ack-reconstructors) for
00449          * various reasons (without violating e2e semantics).
00450          */     
00451         hdr_flags *fh = hdr_flags::access(pkt);
00452         if (!fh->no_ts_) {
00453                 if (ts_option_)
00454                         rtt_update(now - tcph->ts_echo());
00455 
00456                 if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
00457                         if (!ect_ || !ecn_backoff_ || 
00458                                 !hdr_flags::access(pkt)->ecnecho()) {
00459                                 /* 
00460                                  * Don't end backoff if still in ECN-Echo with
00461                                  * a congestion window of 1 packet. 
00462                                  */
00463                                 t_backoff_ = 1;
00464                                 ecn_backoff_ = 0;
00465                         }
00466                         rtt_active_ = 0;
00467                         if (!ts_option_)
00468                                 rtt_update(now - rtt_ts_);
00469                 }
00470         }
00471         /* update average window */
00472         awnd_ *= 1.0 - wnd_th_;
00473         awnd_ += wnd_th_ * cwnd_;
00474 }
00475 
00476         

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