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

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         hdr_cmn* ch; 
00202         if (p != 0) {
00203                 ch = hdr_cmn::access(p);
00204                 bcount_ -= ch->size();
00205         }
00206         if (markpkts_) {
00207                 double u = Random::uniform();
00208                 if (p!=0) {
00209                         double pro = remv_.v_prob;
00210                         if (qib_) {
00211                                 pro = remv_.v_prob*ch->size()/remp_.p_pktsize; 
00212                         }
00213                 if ( u <= pro ) {
00214                                 hdr_flags* hf = hdr_flags::access(p);
00215                                 if(hf->ect() == 1) { 
00216                                         hf->ce() = 1; 
00217                                         pmark_++;
00218                                 }
00219                         }
00220                 }
00221         }
00222         double qlen = qib_ ? bcount_ : q_->length();
00223         curq_ = (int) qlen;
00224         return (p);
00225 }
00226 
00227 /*
00228  * Receive a new packet arriving at the queue.
00229  * The packet is dropped if the maximum queue size is exceeded.
00230  */
00231 
00232 void REMQueue::enque(Packet* pkt)
00233 {
00234         hdr_cmn* ch = hdr_cmn::access(pkt);
00235         double qlen; 
00236 
00237         if (qib_) {
00238                 remv_.v_count += ch->size();
00239         }
00240         else {
00241                 ++remv_.v_count;
00242         }
00243 
00244         double qlim = qib_ ? (qlim_*remp_.p_pktsize) : qlim_ ;
00245 
00246         q_ -> enque(pkt);
00247         bcount_ += ch->size();
00248 
00249         qlen = qib_ ? bcount_ : q_->length();
00250 
00251         if (qlen >= qlim) {
00252                 q_->remove(pkt);
00253                 bcount_ -= ch->size();
00254                 drop(pkt);
00255         }
00256         else  {
00257                 if (!markpkts_) {
00258                         double u = Random::uniform(); 
00259                         double pro = remv_.v_prob;
00260                         if (qib_) {
00261                                 pro = remv_.v_prob*ch->size()/remp_.p_pktsize; 
00262                         }
00263                         if ( u <= pro ) {
00264                                 q_->remove(pkt);
00265                                 bcount_ -= ch->size();
00266                                 drop(pkt);
00267                         }                   
00268                 }
00269         }
00270         qlen = qib_ ? bcount_ : q_->length();
00271         curq_ = (int) qlen;
00272 }
00273 
00274 
00275 int REMQueue::command(int argc, const char*const* argv)
00276 {
00277 
00278         Tcl& tcl = Tcl::instance();
00279         if (argc == 2) {
00280                 if (strcmp(argv[1], "reset") == 0) {
00281                         reset();
00282                         return (TCL_OK);
00283                 }
00284         } else if (argc == 3) {
00285                 // attach a file for variable tracing
00286                 if (strcmp(argv[1], "attach") == 0) {
00287                         int mode;
00288                         const char* id = argv[2];
00289                         tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
00290                         if (tchan_ == 0) {
00291                                 tcl.resultf("REM: trace: can't attach %s for writing", id);
00292                                 return (TCL_ERROR);
00293                         }
00294                         return (TCL_OK);
00295                 }
00296                 // tell REM about link stats
00297                 if (strcmp(argv[1], "link") == 0) {
00298                         LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
00299                         if (del == 0) {
00300                                 tcl.resultf("REM: no LinkDelay object %s",
00301                                         argv[2]);
00302                                 return(TCL_ERROR);
00303                         }
00304                         // set ptc now
00305                         link_ = del;
00306                         remp_.p_ptc = link_->bandwidth() /
00307                                 (8. * remp_.p_pktsize);
00308 
00309                         return (TCL_OK);
00310                 }
00311                 if (!strcmp(argv[1], "packetqueue-attach")) {
00312                         delete q_;
00313                         if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
00314                                 return (TCL_ERROR);
00315                         else {
00316                                 pq_ = q_;
00317                                 return (TCL_OK);
00318                         }
00319                 }
00320         }
00321         return (Queue::command(argc, argv));
00322 }
00323 
00324 /*
00325  * Routine called by TracedVar facility when variables change values.
00326  * Currently used to trace values of avg queue size, drop probability,
00327  * and the instantaneous queue size seen by arriving packets.
00328  * Note that the tracing of each var must be enabled in tcl to work.
00329  */
00330 
00331 void
00332 REMQueue::trace(TracedVar* v)
00333 {
00334         char wrk[500], *p;
00335 
00336         if (((p = strstr(v->name(), "ave")) == NULL) &&
00337             ((p = strstr(v->name(), "prob")) == NULL) &&
00338             ((p = strstr(v->name(), "curq")) == NULL)) {
00339                 fprintf(stderr, "REM:unknown trace var %s\n",
00340                         v->name());
00341                 return;
00342         }
00343 
00344         if (tchan_) {
00345                 int n;
00346                 double t = Scheduler::instance().clock();
00347                 if (*p == 'c') {
00348                         sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
00349                 } else {
00350                         sprintf(wrk, "%c %g %g", *p, t,
00351                                 double(*((TracedDouble*) v)));
00352                 }
00353                 n = strlen(wrk);
00354                 wrk[n] = '\n'; 
00355                 wrk[n+1] = 0;
00356                 (void)Tcl_Write(tchan_, wrk, n+1);
00357         }
00358         return; 
00359 }
00360 
00361 /* for debugging help */
00362 void REMQueue::print_remp()
00363 {
00364         printf("=========\n");
00365 }
00366 
00367 void REMQueue::print_remv()
00368 {
00369         printf("=========\n");
00370 }

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