rem.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) 1990-1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *  This product includes software developed by the Computer Systems
00017  *  Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory 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 THE REGENTS 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 THE REGENTS 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  * ns-2 code written by: Sanjeewa Athuraliya (sanjeewa@caltech.edu)
00036  *                       Caltech, Pasadena,
00037  *           CA 91125
00038  *                       Victor Li
00039  *                       University of Melbourne, Parkville
00040  *                       Vic., Australia.
00041  *
00042  * Ref: Active Queue Management (REM), IEEE Network, May/June 2001.
00043  *      http://netlab.caltech.edu
00044  */
00045 
00046 #include <math.h>
00047 #include <sys/types.h>
00048 #include "config.h"
00049 #include "template.h"
00050 #include "random.h"
00051 #include "flags.h"
00052 #include "delay.h"
00053 #include "rem.h"
00054 #include <iostream>
00055 
00056 static class REMClass : public TclClass {
00057 public:
00058     REMClass() : TclClass("Queue/REM") {}
00059     TclObject* create(int, const char*const*) {
00060         return (new REMQueue);
00061     }
00062 } class_rem;
00063 
00064 
00065 void REMQueue :: set_update_timer()
00066 {
00067     rem_timer_.resched(remp_.p_updtime);
00068 }
00069 
00070 void REMQueue :: timeout()
00071 {
00072     //do price update
00073     run_updaterule();
00074     set_update_timer();
00075 }
00076 
00077 
00078 void REMTimer :: expire (Event *e) {
00079      a_->timeout();
00080 }
00081 
00082 
00083 
00084 REMQueue::REMQueue() : link_(NULL), tchan_(0), rem_timer_(this) 
00085 {
00086     bind("gamma_", &remp_.p_gamma);
00087     bind("phi_", &remp_.p_phi);
00088     bind("inw_", &remp_.p_inw);
00089     bind("mean_pktsize_", &remp_.p_pktsize); 
00090     bind("pupdtime_", &remp_.p_updtime); 
00091     bind("pbo_", &remp_.p_bo); 
00092     bind("prob_", &remv_.v_prob);           // dropping probability
00093     bind("curq_", &curq_);              // current queue size
00094     bind("pmark_", &pmark_);        //number of packets being marked 
00095     bind_bool("markpkts_", &markpkts_); /* Whether to mark or drop?  Default is drop */
00096     bind_bool("qib_", &qib_); /* queue in bytes? */ 
00097 
00098     q_ = new PacketQueue();             // underlying queue
00099     pq_ = q_;
00100     reset();
00101 
00102 #ifdef notdef
00103 print_remp();
00104 print_remv();
00105 #endif
00106 
00107 }
00108 
00109 void REMQueue::reset()
00110 {
00111     /*
00112      * Compute the "packet time constant" if we know the
00113      * link bandwidth.  The ptc is the max number of 
00114      * pkts per second which can be placed on the link.
00115      * The link bw is given in bits/sec, so scale psize
00116      * accordingly.
00117      */
00118      
00119     if (link_)
00120         remp_.p_ptc = link_->bandwidth() / (8.0 * remp_.p_pktsize);
00121 
00122     remv_.v_pl = 0.0;
00123     remv_.v_prob = 0.0;
00124     remv_.v_in = 0.0;
00125     remv_.v_ave = 0.0;
00126     remv_.v_count = 0.0;
00127 
00128     remv_.v_pl1 = 0.0;
00129     remv_.v_pl2 = 0.0;
00130     remv_.v_in1 = 0.0;
00131     remv_.v_in2 = 0.0;
00132     pmark_ = 0.0;
00133     bcount_ = 0; 
00134     
00135     //Queue::reset();
00136     set_update_timer();
00137 }
00138 
00139 /*
00140  * Compute the average input rate, the price and the marking prob..
00141  */
00142 void REMQueue::run_updaterule()
00143 {
00144 
00145     double in, in_avg, nqueued, pl, pr;
00146 
00147         // link price, the congestion measure
00148 
00149     pl = remv_.v_pl;
00150 
00151     // in is the number of bytes (if qib_ is true) or packets (otherwise)
00152     // arriving at the link (input rate) during one update time interval
00153 
00154     in = remv_.v_count;
00155        
00156     // in_avg is the low pss filtered input rate
00157     // which is in bytes if qib_ is true and in packets otherwise.
00158 
00159     in_avg = remv_.v_ave;
00160   
00161     in_avg *= (1.0 - remp_.p_inw);
00162     
00163     if (qib_) {
00164         in_avg += remp_.p_inw*in/remp_.p_pktsize; 
00165         nqueued = bcount_/remp_.p_pktsize; 
00166         }
00167     else {
00168         in_avg += remp_.p_inw*in;
00169         nqueued = q_ -> length();
00170     }
00171 
00172 
00173     // c measures the maximum number of packets that 
00174     // could be sent during one update interval.
00175 
00176     double c  = remp_.p_updtime*remp_.p_ptc;
00177 
00178     pl = pl + remp_.p_gamma*( in_avg + 0.1*(nqueued-remp_.p_bo) - c );
00179 
00180     if ( pl < 0.0) {
00181         pl = 0.0;
00182     }
00183 
00184     double pow1 = pow (remp_.p_phi, -pl);
00185     pr = 1.0-pow1;
00186 
00187 
00188     remv_.v_count = 0.0;
00189     remv_.v_ave = in_avg;
00190     remv_.v_pl = pl;
00191     remv_.v_prob = pr;
00192 }
00193 
00194 
00195 /*
00196  * Return the next packet in the queue for transmission.
00197  */
00198 Packet* REMQueue::deque() 
00199 {
00200     Packet *p = q_->deque();
00201     if (p != 0) {
00202         bcount_ -= hdr_cmn::access(p)->size ();
00203     }
00204     if (markpkts_) {
00205         double u = Random::uniform();
00206         if (p!=0) {
00207             double pro = remv_.v_prob;
00208             if (qib_) {
00209                 int size = hdr_cmn::access(p)->size ();
00210                 pro = remv_.v_prob*size/remp_.p_pktsize; 
00211             }
00212         if ( u <= pro ) {
00213                 hdr_flags* hf = hdr_flags::access(p);
00214                 if(hf->ect() == 1) { 
00215                     hf->ce() = 1; 
00216                     pmark_++;
00217                 }
00218             }
00219         }
00220     }
00221     double qlen = qib_ ? bcount_ : q_->length();
00222     curq_ = (int) qlen;
00223     return (p);
00224 }
00225 
00226 /*
00227  * Receive a new packet arriving at the queue.
00228  * The packet is dropped if the maximum queue size is exceeded.
00229  */
00230 
00231 void REMQueue::enque(Packet* pkt)
00232 {
00233     hdr_cmn* ch = hdr_cmn::access(pkt);
00234     double qlen; 
00235 
00236     if (qib_) {
00237         remv_.v_count += ch->size();
00238     }
00239     else {
00240         ++remv_.v_count;
00241     }
00242 
00243     double qlim = qib_ ? (qlim_*remp_.p_pktsize) : qlim_ ;
00244 
00245     q_ -> enque(pkt);
00246     bcount_ += ch->size();
00247 
00248     qlen = qib_ ? bcount_ : q_->length();
00249 
00250     if (qlen >= qlim) {
00251         q_->remove(pkt);
00252         bcount_ -= ch->size();
00253         drop(pkt);
00254     }
00255     else  {
00256         if (!markpkts_) {
00257             double u = Random::uniform(); 
00258             double pro = remv_.v_prob;
00259             if (qib_) {
00260                 pro = remv_.v_prob*ch->size()/remp_.p_pktsize; 
00261             }
00262             if ( u <= pro ) {
00263                 q_->remove(pkt);
00264                 bcount_ -= ch->size();
00265                 drop(pkt);
00266             }           
00267         }
00268     }
00269     qlen = qib_ ? bcount_ : q_->length();
00270     curq_ = (int) qlen;
00271 }
00272 
00273 
00274 int REMQueue::command(int argc, const char*const* argv)
00275 {
00276 
00277     Tcl& tcl = Tcl::instance();
00278     if (argc == 2) {
00279         if (strcmp(argv[1], "reset") == 0) {
00280             reset();
00281             return (TCL_OK);
00282         }
00283     } else if (argc == 3) {
00284         // attach a file for variable tracing
00285         if (strcmp(argv[1], "attach") == 0) {
00286             int mode;
00287             const char* id = argv[2];
00288             tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00289             if (tchan_ == 0) {
00290                 tcl.resultf("REM: trace: can't attach %s for writing", id);
00291                 return (TCL_ERROR);
00292             }
00293             return (TCL_OK);
00294         }
00295         // tell REM about link stats
00296         if (strcmp(argv[1], "link") == 0) {
00297             LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00298             if (del == 0) {
00299                 tcl.resultf("REM: no LinkDelay object %s",
00300                     argv[2]);
00301                 return(TCL_ERROR);
00302             }
00303             // set ptc now
00304             link_ = del;
00305             remp_.p_ptc = link_->bandwidth() /
00306                 (8. * remp_.p_pktsize);
00307 
00308             return (TCL_OK);
00309         }
00310         if (!strcmp(argv[1], "packetqueue-attach")) {
00311             delete q_;
00312             if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
00313                 return (TCL_ERROR);
00314             else {
00315                 pq_ = q_;
00316                 return (TCL_OK);
00317             }
00318         }
00319     }
00320     return (Queue::command(argc, argv));
00321 }
00322 
00323 /*
00324  * Routine called by TracedVar facility when variables change values.
00325  * Currently used to trace values of avg queue size, drop probability,
00326  * and the instantaneous queue size seen by arriving packets.
00327  * Note that the tracing of each var must be enabled in tcl to work.
00328  */
00329 
00330 void
00331 REMQueue::trace(TracedVar* v)
00332 {
00333     char wrk[500], *p;
00334 
00335     if (((p = strstr(v->name(), "ave")) == NULL) &&
00336         ((p = strstr(v->name(), "prob")) == NULL) &&
00337         ((p = strstr(v->name(), "curq")) == NULL)) {
00338         fprintf(stderr, "REM:unknown trace var %s\n",
00339             v->name());
00340         return;
00341     }
00342 
00343     if (tchan_) {
00344         int n;
00345         double t = Scheduler::instance().clock();
00346         if (*p == 'c') {
00347             sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
00348         } else {
00349             sprintf(wrk, "%c %g %g", *p, t,
00350                 double(*((TracedDouble*) v)));
00351         }
00352         n = strlen(wrk);
00353         wrk[n] = '\n'; 
00354         wrk[n+1] = 0;
00355         (void)Tcl_Write(tchan_, wrk, n+1);
00356     }
00357     return; 
00358 }
00359 
00360 /* for debugging help */
00361 void REMQueue::print_remp()
00362 {
00363     printf("=========\n");
00364 }
00365 
00366 void REMQueue::print_remv()
00367 {
00368     printf("=========\n");
00369 }

Generated on Tue Mar 6 16:47:49 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6