dsredq.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 2000 Nortel Networks
  3.  * All rights reserved.
  4.  * 
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *      This product includes software developed by Nortel Networks.
  16.  * 4. The name of the Nortel Networks may not be used
  17.  *    to endorse or promote products derived from this software without
  18.  *    specific prior written permission.
  19.  * 
  20.  * THIS SOFTWARE IS PROVIDED BY NORTEL AND CONTRIBUTORS ``AS IS'' AND
  21.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED.  IN NO EVENT SHALL NORTEL OR CONTRIBUTORS BE LIABLE
  24.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30.  * SUCH DAMAGE.
  31.  *
  32.  * Developed by: Farhan Shallwani, Jeremy Ethridge
  33.  *               Peter Pieda, and Mandeep Baines
  34.  * Maintainer: Peter Pieda <ppieda@nortelnetworks.com>
  35.  */
  36. #include <stdio.h>
  37. #include "ip.h"
  38. #include "dsred.h"
  39. #include "random.h"
  40. #include "dsredq.h"
  41. // redQueue() Constructor.
  42. //     Initializes virtual queue parameters.
  43. redQueue::redQueue() {
  44.   numPrec = MAX_PREC;
  45.   mredMode = rio_c;
  46.   //underlying physical queue
  47.   q_ = new PacketQueue();
  48. }
  49. // void config(int prec, int argc, const char*const* argv)
  50. //   Configures a virtual queue according to values supplied by the user.
  51. //   Added option to config q_w by Thilo, 
  52. //     xuanc (12/14/01)
  53. void redQueue::config(int prec, int argc, const char*const* argv) {
  54.   qParam_[prec].qlen = 0;
  55.   qParam_[prec].edp_.th_min = atoi(argv[4]);
  56.   qParam_[prec].edp_.th_max = atoi(argv[5]);
  57.   qParam_[prec].edp_.max_p_inv = 1.0 / atof(argv[6]);
  58.   // modification to set the parameter q_w by Thilo
  59.   // it's an optional parameter to conserve backward compatibility
  60.   if (argc > 7)  
  61.     qParam_[prec].edp_.q_w = atof(argv[7]);
  62.   else 
  63.     qParam_[prec].edp_.q_w = 0.002;
  64.   
  65.   qParam_[prec].edv_.v_ave = 0.0;
  66.   qParam_[prec].idle_ = 1;
  67.   if (&Scheduler::instance() != NULL)
  68.     qParam_[prec].idletime_ = Scheduler::instance().clock();
  69.   else
  70.     qParam_[prec].idletime_ = 0.0;
  71. }
  72. // void initREDStateVar(void)
  73. //    Initializes each virtual queue in one physical queue.
  74. void redQueue::initREDStateVar(void) {
  75.   for (int i = 0; i < numPrec; i++) {
  76.     qParam_[i].idle_ = 1;
  77.     
  78.     if (&Scheduler::instance() != NULL)
  79.       qParam_[i].idletime_ = Scheduler::instance().clock();
  80.     else
  81.       qParam_[i].idletime_ = 0.0;
  82.   }
  83. }
  84. // void updateVREDLen(int prec)
  85. //    Updates a virtual queue's length after dequeueing
  86. void redQueue::updateVREDLen(int prec) {
  87.   // decrement virtual queue length
  88.   qParam_[prec].qlen--;
  89. }
  90. // void updateIdleFlag(int)
  91. //    Called by enque() to set idle_ to 0 
  92. //      if a packet was enqueued successfully
  93. void redQueue::updateIdleFlag(int prec) {
  94.   if (mredMode == rio_c) { 
  95.     for (int i = prec; i < numPrec; i++) 
  96.       qParam_[i].idle_ = 0;
  97.   } else if (mredMode == rio_d) { 
  98.     qParam_[prec].idle_ = 0; 
  99.   } else {
  100.     qParam_[0].idle_ = 0;
  101.   } 
  102. }
  103. // void updateREDStateVar(int prec)
  104. //    Updates a virtual queue's state variables after dequing.
  105. void redQueue::updateREDStateVar(int prec) {
  106.   int idle = 1;
  107.   int i;
  108.   
  109.   double now = Scheduler::instance().clock();
  110.   
  111.   //qParam_[prec].qlen--; // decrement virtual queue length
  112.   
  113.   if (qParam_[prec].qlen == 0) {
  114.     if (mredMode == rio_c) {
  115.       for(i=0; i<prec; i++) 
  116. if(qParam_[i].qlen != 0) idle = 0;
  117.       if (idle) {
  118. for (i=prec;i<numPrec;i++) {
  119.   if (qParam_[i].qlen == 0) {
  120.     qParam_[i].idle_ = 1;
  121.     qParam_[i].idletime_ = now;
  122.   } else break;
  123. }
  124.       }
  125.     } else if (mredMode == rio_d) {
  126.       qParam_[prec].idle_ = 1;
  127.       qParam_[prec].idletime_ = now;
  128.     } else if (mredMode == wred) { //wred
  129.       qParam_[0].idle_ = 1;
  130.       qParam_[0].idletime_ = now;
  131.     }
  132.   }
  133. }
  134. // void enque(Packet *pkt, int prec, int ecn)
  135. //    Enques a packet associated with one of the precedence levels of
  136. //      the physical queue.
  137. //    Fix the bug that idle_ flag may be set to 0 when 
  138. //      the incoming packet is actually dropped (xuanc, 12/08/01)
  139. //      Reported and fixed by T. Wagner <wagner@panasonic.de>
  140. int redQueue::enque(Packet *pkt, int prec, int ecn) {
  141.   int m = 0;
  142.   double now, u;
  143.   double pa,pb;
  144.   
  145.   if (q_->length() > (qlim-1))
  146.     return PKT_DROPPED;
  147.   
  148.   now = Scheduler::instance().clock();
  149.   
  150.   //now determining the avg for that queue
  151.   // fix to correct behavior of droptail mode
  152.   // contributed by  Alexander Sayenko <sayenko@cc.jyu.fi>
  153.   if (mredMode == dropTail) {
  154.     if (qParam_[prec].qlen >= qParam_[prec].edp_.th_min) {
  155.       return PKT_DROPPED;
  156.     }
  157.   } else if (mredMode == rio_c) {
  158.     // Can't set idle_ flag to 0 now, because the incoming packet
  159.     //   may be actually dropped.
  160.     for (int i = prec; i < numPrec; i++) {
  161.       m = 0;
  162.       if (qParam_[i].idle_) {
  163. //qParam_[i].idle_ = 0;
  164. m = int(qParam_[i].edp_.ptc * (now - qParam_[i].idletime_));
  165.       }
  166.       calcAvg(i, m+1); 
  167.     }
  168.   } else if (mredMode == rio_d) {
  169.     if (qParam_[prec].idle_) {
  170.       //qParam_[prec].idle_ = 0;
  171.       m = int(qParam_[prec].edp_.ptc * (now - qParam_[prec].idletime_));
  172.     }
  173.     calcAvg(prec, m+1);
  174.   } else { //wred
  175.     if (qParam_[0].idle_) {
  176.       //qParam_[0].idle_ = 0;
  177.       m = int(qParam_[0].edp_.ptc * (now - qParam_[0].idletime_));
  178.     }
  179.     calcAvg(0, m+1);
  180.   }
  181.   
  182.   // enqueu packet if we are using ecn
  183.   if (ecn) {
  184.     q_->enque(pkt);
  185.     
  186.     //virtually, this new packet is queued in one of the multiple queues,
  187.     //thus increasing the length of that virtual queue
  188.     qParam_[prec].qlen++;
  189.   }
  190.   
  191.   //if the avg is greater than the min threshold,
  192.   //there can be only two cases.....
  193.   if (qParam_[prec].edv_.v_ave > qParam_[prec].edp_.th_min) {
  194.     //either the avg is less than the max threshold
  195.     if (qParam_[prec].edv_.v_ave <= qParam_[prec].edp_.th_max) {
  196.       //in which case determine the probabilty for dropping the packet,
  197.       
  198.       qParam_[prec].edv_.count++;
  199.       qParam_[prec].edv_.v_prob = (1/qParam_[prec].edp_.max_p_inv) *
  200. (qParam_[prec].edv_.v_ave-qParam_[prec].edp_.th_min) /
  201. (qParam_[prec].edp_.th_max-qParam_[prec].edp_.th_min);
  202.       
  203.       pb = qParam_[prec].edv_.v_prob;
  204.       pa = pb/(1.0 - qParam_[prec].edv_.count*pb);
  205.       //now determining whether to drop the packet or not
  206.       u = Random::uniform(0.0, 1.0);
  207.       
  208.       //drop it
  209.       if (u <= pa) {
  210. // When average queue length is between min. threshold and max. threshold 
  211. // and the packet is dropped, the value of edv_.count should be set to 0.
  212. // by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002
  213. qParam_[prec].edv_.count = 0; 
  214. if (ecn) {
  215.   // set idle_ to 0
  216.   updateIdleFlag(prec); 
  217.   return PKT_MARKED;
  218. }
  219. return PKT_EDROPPED;
  220.       }
  221.     } else { //if avg queue is greater than max. threshold
  222.       qParam_[prec].edv_.count = 0;
  223.       if (ecn) {
  224. // set idle_ to 0
  225. updateIdleFlag(prec); 
  226. return PKT_MARKED;
  227.       }
  228.       return PKT_DROPPED;
  229.     }
  230.   } else {
  231.     // When average queue length is between min. threshold and max. threshold 
  232.     // and the packet is not dropped the value of edv_.count should be unchanged
  233.     // rather than -1 (which causes a significant impact on the number of early packet drops).
  234.     // by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002
  235.     qParam_[prec].edv_.count = -1;
  236.   }
  237.   // if ecn is on, then the packet has already been enqueued
  238.   if(ecn) { 
  239.     // set idle_ to 0
  240.     updateIdleFlag(prec); 
  241.     return PKT_ENQUEUED;
  242.   }
  243.   
  244.   //if the packet survives the above conditions it
  245.   //is finally queued in the underlying queue
  246.   q_->enque(pkt);
  247.   
  248.   //virtually, this new packet is queued in one of the multiple queues,
  249.   //thus increasing the length of that virtual queue
  250.   qParam_[prec].qlen++;
  251.   // set idle_ to 0
  252.   updateIdleFlag(prec); 
  253.   
  254.   return PKT_ENQUEUED;
  255. }
  256. //  Packet* deque()
  257. //    Deques a packet from the physical queue.
  258. Packet* redQueue::deque() {
  259.   return(q_->deque());
  260. }
  261. // void calcAvg(int prec, int m)
  262. //   This method calculates avg queue length, given the prec number, 
  263. //   m (a value used to adjust the queue size appropriately during idle times).
  264. //   If mredMode is rio_c, each virtual queue size is calculated independently.
  265. //   If it is true, the calculated size of queue n includes the sizes of all 
  266. //   virtual queues up to and including n.
  267. void redQueue::calcAvg(int prec, int m) {
  268.   float f;
  269.   int i;
  270.   
  271.   f = qParam_[prec].edv_.v_ave;
  272.   
  273.   while (--m >= 1) {
  274.     f *= 1.0 - qParam_[prec].edp_.q_w;
  275.   }
  276.   f *= 1.0 - qParam_[prec].edp_.q_w;
  277.   
  278.   if (mredMode == rio_c)
  279.     for (i = 0; i <= prec; i ++)
  280.       f += qParam_[i].edp_.q_w * qParam_[i].qlen;
  281.   else if (mredMode == rio_d)
  282.     f += qParam_[prec].edp_.q_w * qParam_[prec].qlen;
  283.   else //wred
  284.     f += qParam_[prec].edp_.q_w * q_->length();
  285.   
  286.   if (mredMode == wred)
  287.     for (i = 0; i < numPrec; i ++)
  288.       qParam_[i].edv_.v_ave = f;
  289.   else //rio_c, rio_d
  290.     qParam_[prec].edv_.v_ave = f;
  291. }
  292. // double getWeightedLength()
  293. //    Returns the weighted RED queue length for the entire physical queue, 
  294. //       in packets.
  295. double redQueue::getWeightedLength() {
  296.   double sum = 0.0;
  297.   
  298.   if (mredMode == rio_c)
  299.     return qParam_[numPrec-1].edv_.v_ave;
  300.   else {
  301.     for (int prec = 0; prec < numPrec; prec++)
  302.       sum += qParam_[prec].edv_.v_ave;
  303.     return(sum);
  304.   }
  305. }
  306. // int getRealLength(void)
  307. //    Returns the length of the physical queue, in packets.
  308. int redQueue::getRealLength(void) {
  309.   return(q_->length());
  310. }
  311. // Returns the weighted RED queue length for one virtual queue in packets
  312. // Added by Thilo (12/14/2001), xuanc
  313. double redQueue::getWeightedLength_v(int prec) {
  314.   return qParam_[prec].edv_.v_ave;
  315. }
  316. // Returns the length of one virtual queue, in packets
  317. // Added by Thilo (12/14/2001), xuanc
  318. int redQueue::getRealLength_v(int prec) {
  319.   return qParam_[prec].qlen;
  320. }
  321. //  void setPTC(int outLinkBW)
  322. //    Sets the packet time constant, given the outgoing link bandwidth from the
  323. //    router.
  324. void redQueue::setPTC(double outLinkBW) {
  325.   for (int i = 0; i < numPrec; i++)
  326.     qParam_[i].edp_.ptc = outLinkBW/(8.0*qParam_[i].edp_.mean_pktsize);
  327. }
  328. //  void setMPS(int mps)
  329. //    Sets the mean packet size for each of the virtual queues.
  330. void redQueue::setMPS(int mps) {
  331.   for (int i = 0; i < numPrec; i++)
  332.     qParam_[i].edp_.mean_pktsize = mps;
  333. }