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

tcp-rbp.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1997 University of Southern California.
00004  * All rights reserved.                                            
00005  *                                                                
00006  * Redistribution and use in source and binary forms are permitted
00007  * provided that the above copyright notice and this paragraph are
00008  * duplicated in all such forms and that any documentation, advertising
00009  * materials, and other materials related to such distribution and use
00010  * acknowledge that the software was developed by the University of
00011  * Southern California, Information Sciences Institute.  The name of the
00012  * University may not be used to endorse or promote products derived from
00013  * this software without specific prior written permission.
00014  * 
00015  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
00016  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
00017  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00018  *
00019  *
00020  * Tcp-vegas with Rate-based pacing by John Heidemann <johnh@isi.edu>
00021  * and Vikram Visweswaraiah <visweswa@isi.edu>.
00022  * The original SunOS implementation was by Vikram Visweswaraiah
00023  * and Ashish Savla <asavla@usc.edu>.
00024  *
00025  * Rate-based pacing is an experimental addition to TCP
00026  * to address the slow-start restart problem.
00027  * See <http://www.isi.edu/lsam/publications/rate_based_pacing/index.html>
00028  * for details.
00029  *
00030  * A paper analysing RBP performance is in progress (as of 19-Jun-97).
00031  */
00032 
00033 
00034 #ifndef lint
00035 static const char rcsid[] =
00036 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tcp/tcp-rbp.cc,v 1.20 2002/05/06 22:23:16 difa Exp $ (NCSU/IBM)";
00037 #endif
00038 
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <sys/types.h>
00042 
00043 #include "ip.h"
00044 #include "tcp.h"
00045 #include "flags.h"
00046 
00047 #ifndef MIN
00048 #define MIN(x, y) ((x)<(y) ? (x) : (y))
00049 #endif /* ! MIN */
00050 
00051 #if 0
00052 #define RBP_DEBUG_PRINTF(x) printf x
00053 #else /* ! 0 */
00054 #define RBP_DEBUG_PRINTF(x)
00055 #endif /* 0 */
00056 
00057 
00058 #define RBP_MIN_SEGMENTS 2
00059 
00060 class RBPVegasTcpAgent;
00061 
00062 class RBPVegasPaceTimer : public TimerHandler {
00063 public:
00064         RBPVegasPaceTimer(RBPVegasTcpAgent *a) : TimerHandler() { a_ = a; }
00065 protected:
00066         virtual void expire(Event *e);
00067         RBPVegasTcpAgent *a_;
00068 };
00069 // Hmmm... ``a is a'' in the construction of the RBPVegasPaceTimer edifice :->
00070 
00071 class RBPVegasTcpAgent : public virtual VegasTcpAgent {
00072         friend class RBPVegasPaceTimer;
00073  public:
00074         RBPVegasTcpAgent();
00075         virtual void recv(Packet *pkt, Handler *);
00076         virtual void timeout(int tno);
00077         virtual void send_much(int force, int reason, int maxburst);
00078 
00079         double rbp_scale_;   // conversion from actual -> rbp send rates
00080         enum rbp_rate_algorithms { RBP_NO_ALGORITHM, RBP_VEGAS_RATE_ALGORITHM, RBP_CWND_ALGORITHM };
00081         int rbp_rate_algorithm_;
00082 protected:
00083         void paced_send_one();
00084         int able_to_rbp_send_one();
00085 
00086         // stats on what we did
00087         int rbp_segs_actually_paced_;
00088 
00089         enum rbp_modes { RBP_GOING, RBP_POSSIBLE, RBP_OFF };
00090         enum rbp_modes rbp_mode_;
00091         double rbp_inter_pace_delay_;
00092         RBPVegasPaceTimer pace_timer_;
00093 };
00094 
00095 static class RBPVegasTcpClass : public TclClass {
00096 public:
00097         RBPVegasTcpClass() : TclClass("Agent/TCP/Vegas/RBP") {}
00098         TclObject* create(int, const char*const*) {
00099                 return (new RBPVegasTcpAgent());
00100         }
00101 } class_vegas_rbp;
00102 
00103 
00104 void RBPVegasPaceTimer::expire(Event *) { a_->paced_send_one(); }
00105 
00106 
00107 RBPVegasTcpAgent::RBPVegasTcpAgent() : VegasTcpAgent(),
00108         rbp_mode_(RBP_OFF),
00109         pace_timer_(this)
00110 {
00111         bind("rbp_scale_", &rbp_scale_);
00112         bind("rbp_rate_algorithm_", &rbp_rate_algorithm_);
00113         bind("rbp_segs_actually_paced_", &rbp_segs_actually_paced_);
00114         bind("rbp_inter_pace_delay_", &rbp_inter_pace_delay_);
00115 }
00116 
00117 void
00118 RBPVegasTcpAgent::recv(Packet *pkt, Handler *hand)
00119 {
00120         if (rbp_mode_ != RBP_OFF) {
00121                 // reciept of anything disables rbp
00122                 rbp_mode_ = RBP_OFF;
00123                 // Vegas takes care of cwnd.
00124         };
00125         VegasTcpAgent::recv(pkt, hand);
00126 }
00127 
00128 void
00129 RBPVegasTcpAgent::timeout(int tno)
00130 {
00131         if (tno == TCP_TIMER_RTX) {
00132                 if (highest_ack_ == maxseq_) {
00133                         // Idle for a while => RBP next time.
00134                         rbp_mode_ = RBP_POSSIBLE;
00135                         return;
00136                 };
00137         };
00138         VegasTcpAgent::timeout(tno);
00139 }
00140 
00141 void
00142 RBPVegasTcpAgent::send_much(int force, int reason, int maxburst)
00143 {
00144         if (rbp_mode_ == RBP_POSSIBLE && able_to_rbp_send_one()) {
00145                 // start paced mode
00146                 rbp_mode_ = RBP_GOING; 
00147                 rbp_segs_actually_paced_ = 0;
00148                 double rbwin_vegas;
00149                 switch (rbp_rate_algorithm_) {
00150                 case RBP_VEGAS_RATE_ALGORITHM:
00151                         // Try to follow tcp_output.c here
00152                         // Calculate the vegas window as its reported rate
00153                         // times the rtt.
00154                         rbwin_vegas = v_actual_ * v_rtt_;
00155                         RBP_DEBUG_PRINTF(("-----------------\n"));
00156                         RBP_DEBUG_PRINTF(("rbwin_vegas = %g\nv_actual = %g\nv_rtt =%g\nbase_rtt=%g\n",
00157                                           rbwin_vegas, v_actual_, v_rtt_, v_baseRTT_));
00158                         // Smooth the vegas window
00159                         rbwin_vegas *= rbp_scale_;
00160                         break;
00161                 case RBP_CWND_ALGORITHM:
00162                         // Pace out scaled cwnd.
00163                         rbwin_vegas = cwnd_ * rbp_scale_;
00164                         break;
00165                 default:
00166                         abort();
00167                 };
00168                 rbwin_vegas = int(rbwin_vegas + 0.5);   // round
00169                 // Always pace at least RBP_MIN_SEGMENTS
00170                 if (rbwin_vegas <= RBP_MIN_SEGMENTS) {
00171                         rbwin_vegas = RBP_MIN_SEGMENTS;
00172                 };
00173 
00174                 // Conservatively set the congestion window to min of
00175                 // congestion window and the smoothed rbwin_vegas
00176                 RBP_DEBUG_PRINTF(("cwnd before check = %g\n", double(cwnd_)));
00177                 cwnd_ = MIN(cwnd_,(TracedDouble) rbwin_vegas);
00178                 RBP_DEBUG_PRINTF(("cwnd after check = %g\n", double(cwnd_)));
00179                 RBP_DEBUG_PRINTF(("recv win = %g\n", wnd_));
00180                 // RBP timer calculations must be based on the actual
00181                 // window which is the min of the receiver's
00182                 // advertised window and the congestion window.
00183                 // TcpAgent::window() does this job.
00184                 // What this means is we expect to send window() pkts
00185                 // in v_rtt_ time.
00186                 rbp_inter_pace_delay_ = (v_rtt_)/(window() * 1.0);
00187                 RBP_DEBUG_PRINTF(("window is %d\n", window()));
00188                 RBP_DEBUG_PRINTF(("ipt = %g\n", rbp_inter_pace_delay_));
00189                 paced_send_one();
00190         } else {
00191                 VegasTcpAgent::send_much(force,reason, maxburst);
00192         };
00193 }
00194 
00195 void
00196 RBPVegasTcpAgent::paced_send_one()
00197 {
00198         if (rbp_mode_ == RBP_GOING && able_to_rbp_send_one()) {
00199                 RBP_DEBUG_PRINTF(("Sending one rbp packet\n"));
00200                 // send one packet
00201                 output(t_seqno_++, TCP_REASON_RBP);
00202                 rbp_segs_actually_paced_++;
00203                 // schedule next pkt
00204                 pace_timer_.resched(rbp_inter_pace_delay_);
00205         };
00206 }
00207 
00208 int
00209 RBPVegasTcpAgent::able_to_rbp_send_one()
00210 {
00211         return t_seqno_ < curseq_ && t_seqno_ <= highest_ack_ + window();
00212 }
00213 
00214 
00215 /***********************************************************************
00216  *
00217  * The reno-based version
00218  *
00219  */
00220 
00221 
00222 class RBPRenoTcpAgent;
00223 
00224 class RBPRenoPaceTimer : public TimerHandler {
00225 public:
00226         RBPRenoPaceTimer(RBPRenoTcpAgent *a) : TimerHandler() { a_ = a; }
00227 protected:
00228         virtual void expire(Event *e);
00229         RBPRenoTcpAgent *a_;
00230 };
00231 // Hmmm... ``a is a'' in the construction of the RBPRenoPaceTimer edifice :->
00232 
00233 class RBPRenoTcpAgent : public virtual RenoTcpAgent {
00234         friend class RBPRenoPaceTimer;
00235  public:
00236         RBPRenoTcpAgent();
00237         virtual void recv(Packet *pkt, Handler *);
00238         virtual void timeout(int tno);
00239         virtual void send_much(int force, int reason, int maxburst);
00240 
00241         double rbp_scale_;   // conversion from actual -> rbp send rates
00242         // enum rbp_rate_algorithms { RBP_NO_ALGORITHM, RBP_VEGAS_RATE_ALGORITHM, RBP_CWND_ALGORITHM };
00243         // int rbp_rate_algorithm_;
00244 protected:
00245         void paced_send_one();
00246         int able_to_rbp_send_one();
00247 
00248         // stats on what we did
00249         int rbp_segs_actually_paced_;
00250 
00251         enum rbp_modes { RBP_GOING, RBP_POSSIBLE, RBP_OFF };
00252         enum rbp_modes rbp_mode_;
00253         double rbp_inter_pace_delay_;
00254         RBPRenoPaceTimer pace_timer_;
00255 };
00256 
00257 static class RBPRenoTcpClass : public TclClass {
00258 public:
00259         RBPRenoTcpClass() : TclClass("Agent/TCP/Reno/RBP") {}
00260         TclObject* create(int, const char*const*) {
00261                 return (new RBPRenoTcpAgent());
00262         }
00263 } class_reno_rbp;
00264 
00265 
00266 void RBPRenoPaceTimer::expire(Event *) { a_->paced_send_one(); }
00267 
00268 RBPRenoTcpAgent::RBPRenoTcpAgent() : TcpAgent(),
00269         rbp_mode_(RBP_OFF),
00270         pace_timer_(this)
00271 {
00272         bind("rbp_scale_", &rbp_scale_);
00273         // algorithm is not used in Reno
00274         // bind("rbp_rate_algorithm_", &rbp_rate_algorithm_);
00275         bind("rbp_segs_actually_paced_", &rbp_segs_actually_paced_);
00276         bind("rbp_inter_pace_delay_", &rbp_inter_pace_delay_);
00277 }
00278 
00279 void
00280 RBPRenoTcpAgent::recv(Packet *pkt, Handler *hand)
00281 {
00282         if (rbp_mode_ != RBP_OFF) {
00283                 // reciept of anything disables rbp
00284                 rbp_mode_ = RBP_OFF;
00285 
00286                 // reset cwnd such that we're now ack clocked.
00287                 hdr_tcp *tcph = hdr_tcp::access(pkt);
00288                 if (tcph->seqno() > last_ack_) {
00289                         /* reno does not do rate adjustments as Vegas;
00290                          * normally, one wouldn't do any adjustments to
00291                          * cwnd and allow the sliding window to do its job
00292                          * But, if cwnd >> amt_paced, then there's a
00293                          * bunch of data that can be sent asap, plus the
00294                          * two (typically, due to delacks) that get opened
00295                          * up due to the first ack. This would lead to
00296                          * a burst, defeating the purpose of pacing.
00297                          * Ideally, one would want cwnd = amt_paced
00298                          * ALWAYS. Since this doesn't necessarily happen,
00299                          * `cap' cwnd to the amt paced and THEN let
00300                          * sliding windows take over. Note that this
00301                          * mechanism will typically result in 3 segs
00302                          * being sent out when the first ack is received.
00303                          */
00304                         cwnd_ = maxseq_ - last_ack_;
00305                         RBP_DEBUG_PRINTF(("\ncwnd-after-first-ack=%g\n", (double)cwnd_));
00306                 };
00307 
00308         };
00309         RenoTcpAgent::recv(pkt, hand);
00310 }
00311 
00312 void
00313 RBPRenoTcpAgent::timeout(int tno)
00314 {
00315         if (tno == TCP_TIMER_RTX) {
00316                 if (highest_ack_ == maxseq_) {
00317                         // Idle for a while => RBP next time.
00318                         rbp_mode_ = RBP_POSSIBLE;
00319                         return;
00320                 };
00321         };
00322         RenoTcpAgent::timeout(tno);
00323 }
00324 
00325 void
00326 RBPRenoTcpAgent::send_much(int force, int reason, int maxburst)
00327 {
00328         if (rbp_mode_ == RBP_POSSIBLE && able_to_rbp_send_one()) {
00329                 // start paced mode
00330                 rbp_mode_ = RBP_GOING; 
00331                 rbp_segs_actually_paced_ = 0;
00332 
00333                 // Pace out scaled cwnd.
00334                 double rbwin_reno;
00335                 rbwin_reno = cwnd_ * rbp_scale_;
00336 
00337                 rbwin_reno = int(rbwin_reno + 0.5);   // round
00338                 // Always pace at least RBP_MIN_SEGMENTS
00339                 if (rbwin_reno <= RBP_MIN_SEGMENTS) {
00340                         rbwin_reno = RBP_MIN_SEGMENTS;
00341                 };
00342 
00343                 // Conservatively set the congestion window to min of
00344                 // congestion window and the smoothed rbwin_reno
00345                 RBP_DEBUG_PRINTF(("cwnd before check = %g\n", double(cwnd_)));
00346                 cwnd_ = MIN(cwnd_,(TracedDouble) rbwin_reno);
00347                 RBP_DEBUG_PRINTF(("cwnd after check = %g\n", double(cwnd_)));
00348                 RBP_DEBUG_PRINTF(("recv win = %g\n", wnd_));
00349                 // RBP timer calculations must be based on the actual
00350                 // window which is the min of the receiver's
00351                 // advertised window and the congestion window.
00352                 // TcpAgent::window() does this job.
00353                 // What this means is we expect to send window() pkts
00354                 // in v_srtt_ time.
00355                 static double srtt_scale = 0.0;
00356                 if (srtt_scale == 0.0) {  // yuck yuck yuck!
00357                         srtt_scale = 1.0; // why are we doing fixed point?
00358                         int i;
00359                         for (i = T_SRTT_BITS; i > 0; i--) {
00360                                 srtt_scale /= 2.0;
00361                         };
00362                 }
00363                 rbp_inter_pace_delay_ = (t_srtt_ * srtt_scale * tcp_tick_) / (window() * 1.0);
00364                 RBP_DEBUG_PRINTF(("window is %d\n", window()));
00365                 RBP_DEBUG_PRINTF(("ipt = %g\n", rbp_inter_pace_delay_));
00366                 paced_send_one();
00367         } else {
00368                 RenoTcpAgent::send_much(force,reason, maxburst);
00369         };
00370 }
00371 
00372 void
00373 RBPRenoTcpAgent::paced_send_one()
00374 {
00375         if (rbp_mode_ == RBP_GOING && able_to_rbp_send_one()) {
00376                 RBP_DEBUG_PRINTF(("Sending one rbp packet\n"));
00377                 // send one packet
00378                 output(t_seqno_++, TCP_REASON_RBP);
00379                 rbp_segs_actually_paced_++;
00380                 // schedule next pkt
00381                 pace_timer_.resched(rbp_inter_pace_delay_);
00382         };
00383 }
00384 
00385 int
00386 RBPRenoTcpAgent::able_to_rbp_send_one()
00387 {
00388         return t_seqno_ < curseq_ && t_seqno_ <= highest_ack_ + window();
00389 }

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