dsredq.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2000 Nortel Networks
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 Nortel Networks.
00016  * 4. The name of the Nortel Networks may not be used
00017  *    to endorse or promote products derived from this software without
00018  *    specific prior written permission.
00019  * 
00020  * THIS SOFTWARE IS PROVIDED BY NORTEL AND CONTRIBUTORS ``AS IS'' AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023  * ARE DISCLAIMED.  IN NO EVENT SHALL NORTEL OR CONTRIBUTORS BE LIABLE
00024  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00025  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00026  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00027  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00028  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00029  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * Developed by: Farhan Shallwani, Jeremy Ethridge
00033  *               Peter Pieda, and Mandeep Baines
00034  * Maintainer: Peter Pieda <ppieda@nortelnetworks.com>
00035  */
00036 
00037 #include <stdio.h>
00038 #include "ip.h"
00039 #include "dsred.h"
00040 #include "random.h"
00041 #include "dsredq.h"
00042 
00043 
00044 // redQueue() Constructor.
00045 //     Initializes virtual queue parameters.
00046 redQueue::redQueue() {
00047   numPrec = MAX_PREC;
00048   mredMode = rio_c;
00049   //underlying physical queue
00050   q_ = new PacketQueue();   
00051 }
00052 
00053 // void config(int prec, int argc, const char*const* argv)
00054 //   Configures a virtual queue according to values supplied by the user.
00055 //   Added option to config q_w by Thilo, 
00056 //     xuanc (12/14/01)
00057 void redQueue::config(int prec, int argc, const char*const* argv) {
00058   qParam_[prec].qlen = 0;
00059   qParam_[prec].edp_.th_min = atoi(argv[4]);
00060   qParam_[prec].edp_.th_max = atoi(argv[5]);
00061   qParam_[prec].edp_.max_p_inv = 1.0 / atof(argv[6]);
00062 
00063   // modification to set the parameter q_w by Thilo
00064   // it's an optional parameter to conserve backward compatibility
00065   if (argc > 7)  
00066     qParam_[prec].edp_.q_w = atof(argv[7]);
00067   else 
00068     qParam_[prec].edp_.q_w = 0.002;
00069   
00070   qParam_[prec].edv_.v_ave = 0.0;
00071   qParam_[prec].idle_ = 1;
00072   if (&Scheduler::instance() != NULL)
00073     qParam_[prec].idletime_ = Scheduler::instance().clock();
00074   else
00075     qParam_[prec].idletime_ = 0.0;
00076 }
00077 
00078 // void initREDStateVar(void)
00079 //    Initializes each virtual queue in one physical queue.
00080 void redQueue::initREDStateVar(void) {
00081   for (int i = 0; i < numPrec; i++) {
00082     qParam_[i].idle_ = 1;
00083     
00084     if (&Scheduler::instance() != NULL)
00085       qParam_[i].idletime_ = Scheduler::instance().clock();
00086     else
00087       qParam_[i].idletime_ = 0.0;
00088   }
00089 }
00090 
00091 // void updateVREDLen(int prec)
00092 //    Updates a virtual queue's length after dequeueing
00093 void redQueue::updateVREDLen(int prec) {
00094   // decrement virtual queue length
00095   qParam_[prec].qlen--;     
00096 }
00097 
00098 // void updateIdleFlag(int)
00099 //    Called by enque() to set idle_ to 0 
00100 //      if a packet was enqueued successfully
00101 void redQueue::updateIdleFlag(int prec) {
00102   if (mredMode == rio_c) { 
00103     for (int i = prec; i < numPrec; i++) 
00104       qParam_[i].idle_ = 0;
00105   } else if (mredMode == rio_d) { 
00106     qParam_[prec].idle_ = 0; 
00107   } else {
00108     qParam_[0].idle_ = 0;
00109   } 
00110 }
00111 
00112 // void updateREDStateVar(int prec)
00113 //    Updates a virtual queue's state variables after dequing.
00114 void redQueue::updateREDStateVar(int prec) {
00115   int idle = 1;
00116   int i;
00117   
00118   double now = Scheduler::instance().clock();
00119   
00120   //qParam_[prec].qlen--;       // decrement virtual queue length
00121   
00122   if (qParam_[prec].qlen == 0) {
00123     if (mredMode == rio_c) {
00124       for(i=0; i<prec; i++) 
00125     if(qParam_[i].qlen != 0) idle = 0;
00126       if (idle) {
00127     for (i=prec;i<numPrec;i++) {
00128       if (qParam_[i].qlen == 0) {
00129         qParam_[i].idle_ = 1;
00130         qParam_[i].idletime_ = now;
00131       } else break;
00132     }           
00133       }
00134     } else if (mredMode == rio_d) {
00135       qParam_[prec].idle_ = 1;
00136       qParam_[prec].idletime_ = now;
00137     } else if (mredMode == wred) { //wred
00138       qParam_[0].idle_ = 1;
00139       qParam_[0].idletime_ = now;
00140     }           
00141   }
00142 }
00143 
00144 // void enque(Packet *pkt, int prec, int ecn)
00145 //    Enques a packet associated with one of the precedence levels of
00146 //      the physical queue.
00147 //    Fix the bug that idle_ flag may be set to 0 when 
00148 //      the incoming packet is actually dropped (xuanc, 12/08/01)
00149 //      Reported and fixed by T. Wagner <wagner@panasonic.de>
00150 int redQueue::enque(Packet *pkt, int prec, int ecn) {
00151   int m = 0;
00152   double now, u;
00153   double pa,pb;
00154   
00155   if (q_->length() > (qlim-1))
00156     return PKT_DROPPED;
00157   
00158   now = Scheduler::instance().clock();
00159   
00160   //now determining the avg for that queue
00161   // fix to correct behavior of droptail mode
00162   // contributed by  Alexander Sayenko <sayenko@cc.jyu.fi>
00163   if (mredMode == dropTail) {
00164     if (qParam_[prec].qlen >= qParam_[prec].edp_.th_min) {
00165       return PKT_DROPPED;
00166     }
00167   } else if (mredMode == rio_c) {
00168     // Can't set idle_ flag to 0 now, because the incoming packet
00169     //   may be actually dropped.
00170     for (int i = prec; i < numPrec; i++) {  
00171       m = 0;
00172       if (qParam_[i].idle_) {
00173     //qParam_[i].idle_ = 0;
00174     m = int(qParam_[i].edp_.ptc * (now - qParam_[i].idletime_));
00175       }
00176       calcAvg(i, m+1); 
00177     }
00178   } else if (mredMode == rio_d) {
00179     if (qParam_[prec].idle_) {
00180       //qParam_[prec].idle_ = 0;
00181       m = int(qParam_[prec].edp_.ptc * (now - qParam_[prec].idletime_));
00182     }   
00183     calcAvg(prec, m+1);
00184   } else { //wred
00185     if (qParam_[0].idle_) {
00186       //qParam_[0].idle_ = 0;
00187       m = int(qParam_[0].edp_.ptc * (now - qParam_[0].idletime_));
00188     }   
00189     calcAvg(0, m+1);
00190   }
00191   
00192   // enqueu packet if we are using ecn
00193   if (ecn) {
00194     q_->enque(pkt); 
00195     
00196     //virtually, this new packet is queued in one of the multiple queues,
00197     //thus increasing the length of that virtual queue
00198     qParam_[prec].qlen++;
00199   }
00200   
00201   //if the avg is greater than the min threshold,
00202   //there can be only two cases.....
00203   if (qParam_[prec].edv_.v_ave > qParam_[prec].edp_.th_min) {
00204     //either the avg is less than the max threshold
00205     if (qParam_[prec].edv_.v_ave <= qParam_[prec].edp_.th_max) {
00206       //in which case determine the probabilty for dropping the packet,
00207       
00208       qParam_[prec].edv_.count++;
00209       qParam_[prec].edv_.v_prob = (1/qParam_[prec].edp_.max_p_inv) *
00210     (qParam_[prec].edv_.v_ave-qParam_[prec].edp_.th_min) /
00211     (qParam_[prec].edp_.th_max-qParam_[prec].edp_.th_min);
00212       
00213       pb = qParam_[prec].edv_.v_prob;
00214       pa = pb/(1.0 - qParam_[prec].edv_.count*pb);
00215 
00216       //now determining whether to drop the packet or not
00217       u = Random::uniform(0.0, 1.0);
00218       
00219       //drop it
00220       if (u <= pa) {
00221     // When average queue length is between min. threshold and max. threshold 
00222     // and the packet is dropped, the value of edv_.count should be set to 0.
00223     // by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002
00224     qParam_[prec].edv_.count = 0; 
00225     if (ecn) {
00226       // set idle_ to 0
00227       updateIdleFlag(prec); 
00228       return PKT_MARKED;
00229     }
00230     return PKT_EDROPPED;
00231       }
00232     } else { //if avg queue is greater than max. threshold
00233       qParam_[prec].edv_.count = 0;
00234       if (ecn) {
00235     // set idle_ to 0
00236     updateIdleFlag(prec); 
00237     return PKT_MARKED;
00238       }
00239       return PKT_DROPPED;
00240     }
00241   } else {
00242     // When average queue length is between min. threshold and max. threshold 
00243     // and the packet is not dropped the value of edv_.count should be unchanged
00244     // rather than -1 (which causes a significant impact on the number of early packet drops).
00245     // by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002
00246     qParam_[prec].edv_.count = -1;
00247   }
00248 
00249   // if ecn is on, then the packet has already been enqueued
00250   if(ecn) { 
00251     // set idle_ to 0
00252     updateIdleFlag(prec); 
00253     return PKT_ENQUEUED;
00254   }
00255   
00256   //if the packet survives the above conditions it
00257   //is finally queued in the underlying queue
00258   q_->enque(pkt);
00259   
00260   //virtually, this new packet is queued in one of the multiple queues,
00261   //thus increasing the length of that virtual queue
00262   qParam_[prec].qlen++;
00263 
00264   // set idle_ to 0
00265   updateIdleFlag(prec); 
00266   
00267   return PKT_ENQUEUED;
00268 }
00269 
00270 //  Packet* deque()
00271 //    Deques a packet from the physical queue.
00272 Packet* redQueue::deque() {
00273   return(q_->deque());
00274 }
00275 
00276 // void calcAvg(int prec, int m)
00277 //   This method calculates avg queue length, given the prec number, 
00278 //   m (a value used to adjust the queue size appropriately during idle times).
00279 //   If mredMode is rio_c, each virtual queue size is calculated independently.
00280 //   If it is true, the calculated size of queue n includes the sizes of all 
00281 //   virtual queues up to and including n.
00282 void redQueue::calcAvg(int prec, int m) {
00283   float f;
00284   int i;
00285   
00286   f = qParam_[prec].edv_.v_ave;
00287   
00288   while (--m >= 1) {
00289     f *= 1.0 - qParam_[prec].edp_.q_w;
00290   }
00291   f *= 1.0 - qParam_[prec].edp_.q_w;
00292   
00293   if (mredMode == rio_c)
00294     for (i = 0; i <= prec; i ++)
00295       f += qParam_[i].edp_.q_w * qParam_[i].qlen;
00296   else if (mredMode == rio_d)
00297     f += qParam_[prec].edp_.q_w * qParam_[prec].qlen;
00298   else //wred
00299     f += qParam_[prec].edp_.q_w * q_->length();
00300   
00301   if (mredMode == wred)
00302     for (i = 0; i < numPrec; i ++)
00303       qParam_[i].edv_.v_ave = f;
00304   else //rio_c, rio_d
00305     qParam_[prec].edv_.v_ave = f;
00306 }
00307 
00308 // double getWeightedLength()
00309 //    Returns the weighted RED queue length for the entire physical queue, 
00310 //       in packets.
00311 double redQueue::getWeightedLength() {
00312   double sum = 0.0;
00313   
00314   if (mredMode == rio_c)
00315     return qParam_[numPrec-1].edv_.v_ave;
00316   else {
00317     for (int prec = 0; prec < numPrec; prec++)
00318       sum += qParam_[prec].edv_.v_ave;
00319     return(sum);
00320   }
00321 }
00322 
00323 // int getRealLength(void)
00324 //    Returns the length of the physical queue, in packets.
00325 int redQueue::getRealLength(void) {
00326   return(q_->length());
00327 }
00328 
00329 // Returns the weighted RED queue length for one virtual queue in packets
00330 // Added by Thilo (12/14/2001), xuanc
00331 double redQueue::getWeightedLength_v(int prec) {
00332   return qParam_[prec].edv_.v_ave;
00333 }
00334 
00335 // Returns the length of one virtual queue, in packets
00336 // Added by Thilo (12/14/2001), xuanc
00337 int redQueue::getRealLength_v(int prec) {
00338   return qParam_[prec].qlen;
00339 }
00340 
00341 //  void setPTC(int outLinkBW)
00342 //    Sets the packet time constant, given the outgoing link bandwidth from the
00343 //    router.
00344 void redQueue::setPTC(double outLinkBW) {
00345   for (int i = 0; i < numPrec; i++)
00346     qParam_[i].edp_.ptc = outLinkBW/(8.0*qParam_[i].edp_.mean_pktsize);
00347 }
00348 
00349 //  void setMPS(int mps)
00350 //    Sets the mean packet size for each of the virtual queues.
00351 void redQueue::setMPS(int mps) {
00352   for (int i = 0; i < numPrec; i++)
00353     qParam_[i].edp_.mean_pktsize = mps;
00354 }

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