/*											/*
 * Copyright (c) 2000 Nortel Networks							 * Copyright (c) 2000 Nortel Networks
 * All rights reserved.									 * All rights reserved.
 *										      |	 * 
 * Redistribution and use in source and binary forms, with or without			 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions			 * modification, are permitted provided that the following conditions
 * are met:										 * are met:
 * 1. Redistributions of source code must retain the above copyright			 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.			 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright			 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the		 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.		 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software		 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:					 *    must display the following acknowledgement:
 *      This product includes software developed by Nortel Networks.			 *      This product includes software developed by Nortel Networks.
 * 4. The name of the Nortel Networks may not be used					 * 4. The name of the Nortel Networks may not be used
 *    to endorse or promote products derived from this software without			 *    to endorse or promote products derived from this software without
 *    specific prior written permission.						 *    specific prior written permission.
 *										      |	 * 
 * THIS SOFTWARE IS PROVIDED BY NORTEL AND CONTRIBUTORS ``AS IS'' AND			 * THIS SOFTWARE IS PROVIDED BY NORTEL AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE		 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE		 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL NORTEL OR CONTRIBUTORS BE LIABLE			 * ARE DISCLAIMED.  IN NO EVENT SHALL NORTEL OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL		 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS		 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)		 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT		 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY		 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF		 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.										 * SUCH DAMAGE.
 *											 *
 * Developed by: Farhan Shallwani, Jeremy Ethridge					 * Developed by: Farhan Shallwani, Jeremy Ethridge
 *               Peter Pieda, and Mandeep Baines					 *               Peter Pieda, and Mandeep Baines
 * Maintainer: Peter Pieda <ppieda@nortelnetworks.com>					 * Maintainer: Peter Pieda <ppieda@nortelnetworks.com>
 */											 */

#include <stdio.h>									#include <stdio.h>
#include "ip.h"										#include "ip.h"
#include "dsred.h"									#include "dsred.h"
#include "random.h"									#include "random.h"
#include "dsredq.h"									#include "dsredq.h"


// redQueue() Constructor.								// redQueue() Constructor.
//     Initializes virtual queue parameters.						//     Initializes virtual queue parameters.
redQueue::redQueue() {									redQueue::redQueue() {
  bytes = 0;									      <
  numPrec = MAX_PREC;									  numPrec = MAX_PREC;
  mredMode = rio_c;									  mredMode = rio_c;
  //underlying physical queue								  //underlying physical queue
  q_ = new PacketQueue();							      |	  q_ = new PacketQueue();	
										      <
  // prevent division by zero for unconfigured queues				      <
  for (int i=0; i<MAX_PREC; i++) {						      <
    qParam_[i].bp_.ifreeze_time_ = 1;						      <
    qParam_[i].bp_.dfreeze_time_ = 1;						      <
  }										      <
}											}

// void config(int prec, int argc, const char*const* argv)				// void config(int prec, int argc, const char*const* argv)
//   Configures a virtual queue according to values supplied by the user.		//   Configures a virtual queue according to values supplied by the user.
//   Added option to config q_w by Thilo,					      |	//   Added option to config q_w by Thilo, 
//     xuanc (12/14/01)									//     xuanc (12/14/01)
void redQueue::config(int prec, int argc, const char*const* argv) {			void redQueue::config(int prec, int argc, const char*const* argv) {
  if (mredMode == dropTail) {								  if (mredMode == dropTail) {
    qParam_[0].edp_.th_min = atoi(argv[4]);						    qParam_[0].edp_.th_min = atoi(argv[4]);
    return;										    return;
  } else if ((mredMode >= bio_ssi) && (mredMode <= bio_aat)) {			      <
    qParam_[prec].bp_.increment_    = atof(argv[4]);				      <
    qParam_[prec].bp_.decrement_    = atof(argv[5]);				      <
    qParam_[prec].bp_.ifreeze_time_ = atof(argv[6]);				      <
    qParam_[prec].bp_.dfreeze_time_ = atof(argv[7]);				      <
    qParam_[prec].edp_.th_max       = atoi(argv[8]);				      <
										      <
    // ensure that we do not care hold_time for the first time			      <
    qParam_[prec].bv_.ihold_time_   = -1 * qParam_[prec].bp_.ifreeze_time_ - 0.000000 <
    qParam_[prec].bv_.dhold_time_   = -1 * qParam_[prec].bp_.dfreeze_time_ - 0.000000 <
										      <
    qParam_[prec].bv_.pmark_        = 0;					      <
    qParam_[prec].qlen              = 0;					      <
										      <
    qParam_[prec].edv_.v_ave        = 0;					      <
										      <
    // minth is optional							      <
    if (argc > 9)								      <
      qParam_[prec].edp_.th_min     = atoi(argv[9]);				      <
    else									      <
      qParam_[prec].edp_.th_min     = 0;					      <
    return;									      <
  }											  }
										      |	  
  qParam_[prec].qlen = 0;								  qParam_[prec].qlen = 0;
  qParam_[prec].edp_.th_min = atoi(argv[4]);						  qParam_[prec].edp_.th_min = atoi(argv[4]);
  qParam_[prec].edp_.th_max = atoi(argv[5]);						  qParam_[prec].edp_.th_max = atoi(argv[5]);
  qParam_[prec].edp_.max_p_inv = 1.0 / atof(argv[6]);					  qParam_[prec].edp_.max_p_inv = 1.0 / atof(argv[6]);

  // modification to set the parameter q_w by Thilo					  // modification to set the parameter q_w by Thilo
  // it's an optional parameter to conserve backward compatibility			  // it's an optional parameter to conserve backward compatibility
  if (argc > 7)									      |	  if (argc > 7)  
    qParam_[prec].edp_.q_w = atof(argv[7]);						    qParam_[prec].edp_.q_w = atof(argv[7]);
  else										      |	  else 
    qParam_[prec].edp_.q_w = 0.002;							    qParam_[prec].edp_.q_w = 0.002;
										      |	  
  qParam_[prec].edv_.v_ave = 0.0;							  qParam_[prec].edv_.v_ave = 0.0;
  qParam_[prec].idle_ = 1;								  qParam_[prec].idle_ = 1;
  if (&Scheduler::instance() != NULL)							  if (&Scheduler::instance() != NULL)
    qParam_[prec].idletime_ = Scheduler::instance().clock();				    qParam_[prec].idletime_ = Scheduler::instance().clock();
  else											  else
    qParam_[prec].idletime_ = 0.0;							    qParam_[prec].idletime_ = 0.0;
}											}

// void initREDStateVar(void)								// void initREDStateVar(void)
//    Initializes each virtual queue in one physical queue.				//    Initializes each virtual queue in one physical queue.
void redQueue::initREDStateVar(void) {							void redQueue::initREDStateVar(void) {
  for (int i = 0; i < numPrec; i++) {							  for (int i = 0; i < numPrec; i++) {
    qParam_[i].idle_ = 1;								    qParam_[i].idle_ = 1;
										      |	    
    if (&Scheduler::instance() != NULL)							    if (&Scheduler::instance() != NULL)
      qParam_[i].idletime_ = Scheduler::instance().clock();				      qParam_[i].idletime_ = Scheduler::instance().clock();
    else										    else
      qParam_[i].idletime_ = 0.0;							      qParam_[i].idletime_ = 0.0;
  }											  }
}											}

// void updateVREDLen(int prec)								// void updateVREDLen(int prec)
//    Updates a virtual queue's length after dequeueing					//    Updates a virtual queue's length after dequeueing
void redQueue::updateVREDLen(int prec) {						void redQueue::updateVREDLen(int prec) {
  // decrement virtual queue length							  // decrement virtual queue length
  qParam_[prec].qlen--;								      |	  qParam_[prec].qlen--;		
}											}

// void updateIdleFlag(int)								// void updateIdleFlag(int)
//    Called by enque() to set idle_ to 0					      |	//    Called by enque() to set idle_ to 0 
//      if a packet was enqueued successfully						//      if a packet was enqueued successfully
void redQueue::updateIdleFlag(int prec) {						void redQueue::updateIdleFlag(int prec) {
  // do not act for BIO								      |	  if (mredMode == rio_c) { 
  if ((mredMode >= bio_ssi) && (mredMode <= bio_aat))				      |	    for (int i = prec; i < numPrec; i++) 
    return;									      <
										      <
  if (mredMode == rio_c) {							      <
    for (int i = prec; i < numPrec; i++)					      <
      qParam_[i].idle_ = 0;								      qParam_[i].idle_ = 0;
  } else if (mredMode == rio_d) {						      |	  } else if (mredMode == rio_d) { 
    qParam_[prec].idle_ = 0;							      |	    qParam_[prec].idle_ = 0; 
  } else {										  } else {
    qParam_[0].idle_ = 0;								    qParam_[0].idle_ = 0;
  }										      |	  } 
}										      <
										      <
void redQueue::increment_pm(int prec) {						      <
  double now;									      <
										      <
  if (qParam_[prec].bv_.pmark_ >= 1)						      <
    return;									      <
										      <
  now = Scheduler::instance().clock();						      <
										      <
  /*										      <
     BLUE algoritmasinda yoktu ama bana geen sre ile orantili bir artim yapmak daha <
     geliyor. Eger ben 2 freetime'lik bir sure idle/overflow kaldi ise o kadar kez in <
     mantikli gibi.								      <
										      <
     Ama deque surekli cagriliyor da, bu islem otomatik olarak mi yapiliyor?	      <
										      <
     Eger bu mantik gerekli ise, t'yi float da yapmak sozkonusu olabilir.	      <
   */										      <
//  int t = (now - qParam_[prec].bv_.ihold_time_) / qParam_[prec].bp_.ifreeze_time_;  <
   int t=1;									      <
										      <
  if (t >= 1) {									      <
    t = 1;									      <
    qParam_[prec].bv_.ihold_time_ = now;					      <
    qParam_[prec].bv_.pmark_ += (float)t * qParam_[prec].bp_.increment_;	      <
    if (qParam_[prec].bv_.pmark_ > 1)						      <
      qParam_[prec].bv_.pmark_ = 1;						      <
  }										      <
}										      <
										      <
void redQueue::decrement_pm(int prec) {						      <
  double now;									      <
										      <
  if (qParam_[prec].bv_.pmark_ <= 0)						      <
    return;									      <
										      <
  now = Scheduler::instance().clock();						      <
										      <
  /*										      <
     BLUE algoritmasinda yoktu ama bana geen sre ile orantili bir artim yapmak daha <
     geliyor. Eger ben 2 freetime'lik bir sure idle/overflow kaldi ise o kadar kez in <
     mantikli gibi.								      <
										      <
     Ama deque surekli cagriliyor da, bu islem otomatik olarak mi yapiliyor?	      <
										      <
     Eger bu mantik gerekli ise, t'yi float da yapmak sozkonusu olabilir.	      <
   */										      <
//  int t = (now - qParam_[prec].bv_.dhold_time_) / qParam_[prec].bp_.dfreeze_time_;  <
   int t=1;									      <
										      <
  if (t >= 1) {									      <
    t = 1;									      <
    qParam_[prec].bv_.dhold_time_ = now;					      <
    qParam_[prec].bv_.pmark_ -= (float)t * qParam_[prec].bp_.decrement_;	      <
    if (qParam_[prec].bv_.pmark_ < 0)						      <
      qParam_[prec].bv_.pmark_ = 0;						      <
  }										      <
}										      <
										      <
										      <
int redQueue::bio_boundary_check(int prec)					      <
{										      <
  int i;									      <
  int ql = 0;									      <
										      <
  // do not do something for RIO 						      <
  if (mredMode < bio_ssi) 							      <
    return -1;									      <
										      <
  for (i=0; i<=prec; i++)							      <
    ql += qParam_[i].qlen;							      <
										      <
  switch (mredMode) {								      <
    case bio_asi:								      <
    case bio_ast:								      <
      if (ql == 0) {								      <
        decrement_pm(prec);							      <
        return -1;								      <
      }										      <
      if (qParam_[prec].qlen >= qParam_[prec].edp_.th_max) {			      <
        increment_pm(prec);							      <
        return 1;								      <
      }										      <
      break;									      <
    case bio_aai:								      <
    case bio_aat:								      <
      if (ql == 0) {								      <
        decrement_pm(prec);							      <
        return -1;								      <
      }										      <
      if (ql >= qParam_[prec].edp_.th_max) {					      <
        increment_pm(prec);							      <
        return 1;								      <
      }										      <
      break;									      <
    case bio_ssi:								      <
    case bio_sst:								      <
      if (qParam_[prec].qlen == 0) {						      <
        decrement_pm(prec);							      <
        return -1;								      <
      }										      <
      if (qParam_[prec].qlen >= qParam_[prec].edp_.th_max) {			      <
        increment_pm(prec);							      <
        return 1;								      <
      }										      <
      break;									      <
    case bio_sai:								      <
    case bio_sat:								      <
      if (qParam_[prec].qlen == 0) {						      <
        decrement_pm(prec);							      <
        return -1;								      <
      }										      <
      if (ql >= qParam_[prec].edp_.th_max) {					      <
        increment_pm(prec);							      <
        return 1;								      <
      }										      <
      break;									      <
  }										      <
  return 0;									      <
}											}

// void updateREDStateVar(int prec)							// void updateREDStateVar(int prec)
//    Updates a virtual queue's state variables after dequing.				//    Updates a virtual queue's state variables after dequing.
void redQueue::updateREDStateVar(int prec) {						void redQueue::updateREDStateVar(int prec) {
  int idle = 1;										  int idle = 1;
  int i;										  int i;
										      |	  
  double now = Scheduler::instance().clock();						  double now = Scheduler::instance().clock();
										      |	  
  //qParam_[prec].qlen--;		// decrement virtual queue length		  //qParam_[prec].qlen--;		// decrement virtual queue length
										      |	  
  if (qParam_[prec].qlen == 0) {							  if (qParam_[prec].qlen == 0) {
    if (mredMode == rio_c) {								    if (mredMode == rio_c) {
      for(i=0; i<prec; i++)							      |	      for(i=0; i<prec; i++) 
        if(qParam_[i].qlen != 0) idle = 0;					      |		if(qParam_[i].qlen != 0) idle = 0;
      if (idle) {									      if (idle) {
        for (i=prec;i<numPrec;i++) {						      |		for (i=prec;i<numPrec;i++) {
          if (qParam_[i].qlen == 0) {						      |		  if (qParam_[i].qlen == 0) {
            qParam_[i].idle_ = 1;						      |		    qParam_[i].idle_ = 1;
            qParam_[i].idletime_ = now;						      |		    qParam_[i].idletime_ = now;
          } else break;								      |		  } else break;
        }									      |		}			
      }											      }
    } else if (mredMode == rio_d) {							    } else if (mredMode == rio_d) {
      qParam_[prec].idle_ = 1;								      qParam_[prec].idle_ = 1;
      qParam_[prec].idletime_ = now;							      qParam_[prec].idletime_ = now;
    } else if (mredMode == wred) { //wred						    } else if (mredMode == wred) { //wred
      qParam_[0].idle_ = 1;								      qParam_[0].idle_ = 1;
      qParam_[0].idletime_ = now;							      qParam_[0].idletime_ = now;
    }										      |	    }			
  }											  }
}											}

										      <
// void enque(Packet *pkt, int prec, int ecn)						// void enque(Packet *pkt, int prec, int ecn)
//    Enques a packet associated with one of the precedence levels of			//    Enques a packet associated with one of the precedence levels of
//      the physical queue.								//      the physical queue.
//    Fix the bug that idle_ flag may be set to 0 when				      |	//    Fix the bug that idle_ flag may be set to 0 when 
//      the incoming packet is actually dropped (xuanc, 12/08/01)			//      the incoming packet is actually dropped (xuanc, 12/08/01)
//      Reported and fixed by T. Wagner <wagner@panasonic.de>				//      Reported and fixed by T. Wagner <wagner@panasonic.de>
int redQueue::enque(Packet *pkt, int prec, int ecn) {					int redQueue::enque(Packet *pkt, int prec, int ecn) {
  int m = 0;										  int m = 0;
  double now, u;									  double now, u;
  double pa,pb;										  double pa,pb;
  int ql=0;									      |	  
										      |	  if (q_->length() > (qlim-1))
  if (q_->length() > (qlim-1)) {						      <
    printf("Oops: q overflowed %d %d\n", q_->length(), qlim);			      <
    return PKT_DROPPED;									    return PKT_DROPPED;
  }										      |	  
										      <
  now = Scheduler::instance().clock();							  now = Scheduler::instance().clock();
										      |	  
  //now determining the avg for that queue						  //now determining the avg for that queue
  if (mredMode == dropTail) {								  if (mredMode == dropTail) {
    if (q_->length() >= qParam_[0].edp_.th_min) {					    if (q_->length() >= qParam_[0].edp_.th_min) {
      return PKT_DROPPED;								      return PKT_DROPPED;
    } else {										    } else {
      q_->enque(pkt);									      q_->enque(pkt);
      bytes += (hdr_cmn::access(pkt))->size();					      |	      return PKT_ENQUEUED;		
      return PKT_ENQUEUED;							      <
    }											    }
  } else if (mredMode == rio_c) {							  } else if (mredMode == rio_c) {
    // Can't set idle_ flag to 0 now, because the incoming packet			    // Can't set idle_ flag to 0 now, because the incoming packet
    //   may be actually dropped.							    //   may be actually dropped.
    for (int i = prec; i < numPrec; i++) {					      |	    for (int i = prec; i < numPrec; i++) {	
      m = 0;										      m = 0;
      if (qParam_[i].idle_) {								      if (qParam_[i].idle_) {
	//qParam_[i].idle_ = 0;									//qParam_[i].idle_ = 0;
	m = int(qParam_[i].edp_.ptc * (now - qParam_[i].idletime_));				m = int(qParam_[i].edp_.ptc * (now - qParam_[i].idletime_));
      }											      }
      calcAvg(i, m+1);								      |	      calcAvg(i, m+1); 
    }											    }
  } else if (mredMode == rio_d) {							  } else if (mredMode == rio_d) {
    if (qParam_[prec].idle_) {								    if (qParam_[prec].idle_) {
      //qParam_[prec].idle_ = 0;							      //qParam_[prec].idle_ = 0;
      m = int(qParam_[prec].edp_.ptc * (now - qParam_[prec].idletime_));		      m = int(qParam_[prec].edp_.ptc * (now - qParam_[prec].idletime_));
    }										      |	    }	
    calcAvg(prec, m+1);									    calcAvg(prec, m+1);
  } else { //wred									  } else { //wred
    if (qParam_[0].idle_) {								    if (qParam_[0].idle_) {
      //qParam_[0].idle_ = 0;								      //qParam_[0].idle_ = 0;
      m = int(qParam_[0].edp_.ptc * (now - qParam_[0].idletime_));			      m = int(qParam_[0].edp_.ptc * (now - qParam_[0].idletime_));
    }										      |	    }	
    calcAvg(0, m+1);									    calcAvg(0, m+1);
  }											  }
  											  
										      |	  // enqueu packet if we are using ecn
  switch (mredMode) {								      |	  if (ecn) {
    case bio_aai:								      |	    q_->enque(pkt);	
    case bio_asi:								      <
    case bio_sai:								      <
    case bio_ssi:								      <
      if (bio_boundary_check(prec) > 0) {					      <
        // forced drop								      <
        return PKT_DROPPED;							      <
      }										      <
										      <
      ql = 0;									      <
      for (int i=prec+1; i<numPrec; i++)					      <
        ql += qParam_[i].qlen;							      <
      if (ql == 0) {								      <
        u = Random::uniform(0.0, 1.0);						      <
										      <
        //drop it								      <
        if (u <= qParam_[prec].bv_.pmark_) {					      <
          // early drop								      <
          if (ecn) {								      <
            q_->enque(pkt);							      <
            //virtually, this new packet is queued in one of the multiple queues,     <
            //thus increasing the length of that virtual queue			      <
            qParam_[prec].qlen++;						      <
            bytes += (hdr_cmn::access(pkt))->size();				      <
            return PKT_MARKED;							      <
          }									      <
          return PKT_EDROPPED;							      <
        }									      <
      }										      <
      break;									      <
										      <
    case bio_aat:								      <
    case bio_ast:								      <
    case bio_sat:								      <
    case bio_sst:								      <
      if (bio_boundary_check(prec) > 0) {					      <
        // forced drop								      <
        return PKT_DROPPED;							      <
      }										      <
										      <
      ql = 0;									      <
      for (int i=0; i<=prec; i++)						      <
        ql += qParam_[i].qlen;							      <
      if (ql > qParam_[prec].edp_.th_min) {					      <
        u = Random::uniform(0.0, 1.0);						      <
										      <
        //drop it								      <
        if (u <= qParam_[prec].bv_.pmark_) {					      <
          // early drop								      <
          if (ecn) {								      <
            q_->enque(pkt);							      <
            bytes += (hdr_cmn::access(pkt))->size();				      <
            //virtually, this new packet is queued in one of the multiple queues,     <
            //thus increasing the length of that virtual queue			      <
            qParam_[prec].qlen++;						      <
            return PKT_MARKED;							      <
          }									      <
          return PKT_EDROPPED;							      <
        }									      <
      }										      <
      break;									      <
    default:									      <
      // RIO									      <
    											    
      //if the avg is greater than the min threshold,				      |	    //virtually, this new packet is queued in one of the multiple queues,
      //there can be only two cases.....					      |	    //thus increasing the length of that virtual queue
      if (qParam_[prec].edv_.v_ave > qParam_[prec].edp_.th_min) {		      |	    qParam_[prec].qlen++;
        //either the avg is less than the max threshold				      |	  }
        if (qParam_[prec].edv_.v_ave <= qParam_[prec].edp_.th_max) {		      |	  
          //in which case determine the probabilty for dropping the packet,	      |	  //if the avg is greater than the min threshold,
										      |	  //there can be only two cases.....
          qParam_[prec].edv_.count++;						      |	  if (qParam_[prec].edv_.v_ave > qParam_[prec].edp_.th_min) {
          qParam_[prec].edv_.v_prob = (1/qParam_[prec].edp_.max_p_inv) *	      |	    //either the avg is less than the max threshold
	    (qParam_[prec].edv_.v_ave-qParam_[prec].edp_.th_min) /		      |	    if (qParam_[prec].edv_.v_ave <= qParam_[prec].edp_.th_max) {
            (qParam_[prec].edp_.th_max-qParam_[prec].edp_.th_min);		      |	      //in which case determine the probabilty for dropping the packet,
										      |	      
          pb = qParam_[prec].edv_.v_prob;					      |	      qParam_[prec].edv_.count++;
          pa = pb/(1.0 - qParam_[prec].edv_.count*pb);				      |	      qParam_[prec].edv_.v_prob = (1/qParam_[prec].edp_.max_p_inv) *
										      |		(qParam_[prec].edv_.v_ave-qParam_[prec].edp_.th_min) /
          qParam_[prec].red_pmark_ = pa;					      |		(qParam_[prec].edp_.th_max-qParam_[prec].edp_.th_min);
          if (qParam_[prec].red_pmark_ < 0)					      |	      
            qParam_[prec].red_pmark_ = 0.0;					      |	      pb = qParam_[prec].edv_.v_prob;
          else if (qParam_[prec].red_pmark_ > 1)				      |	      pa = pb/(1.0 - qParam_[prec].edv_.count*pb);
            qParam_[prec].red_pmark_ = 1.0;					      |
										      |	      //now determining whether to drop the packet or not
          //now determining whether to drop the packet or not			      |	      u = Random::uniform(0.0, 1.0);
          u = Random::uniform(0.0, 1.0);					      |	      
										      |	      //drop it
          //drop it								      |	      if (u <= pa) {
          if (u <= pa) {							      |		// When average queue length is between min. threshold and max. threshold 
            // early drop							      |		// and the packet is dropped, the value of edv_.count should be set to 0.
            									      |		// by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002
            // When average queue length is between min. threshold and max. threshold |		qParam_[prec].edv_.count = 0; 
            // and the packet is dropped, the value of edv_.count should be set to 0. |		if (ecn) {
            // by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002		      |		  // set idle_ to 0
            qParam_[prec].edv_.count = 0; 					      |		  updateIdleFlag(prec); 
	    if (ecn) {								      |		  return PKT_MARKED;
              q_->enque(pkt);							      |		}
              bytes += (hdr_cmn::access(pkt))->size();				      |		return PKT_EDROPPED;
    										      |	      }
              //virtually, this new packet is queued in one of the multiple queues,   |	    } else { //if avg queue is greater than max. threshold
              //thus increasing the length of that virtual queue		      |	      qParam_[prec].edv_.count = 0;
              qParam_[prec].qlen++;						      |	      if (ecn) {
										      |		// set idle_ to 0
              // set idle_ to 0							      |		updateIdleFlag(prec); 
	      updateIdleFlag(prec);						      |		return PKT_MARKED;
	      return PKT_MARKED;						      <
	    }									      <
	    return PKT_EDROPPED;						      <
          }									      <
        } else { //if avg queue is greater than max. threshold			      <
          // forced drop (even for ECN)						      <
          									      <
          qParam_[prec].edv_.count = 0;						      <
          return PKT_DROPPED;							      <
        }									      <
      } else {									      <
        // When average queue length is between min. threshold and max. threshold     <
        // and the packet is not dropped the value of edv_.count should be unchanged  <
        // rather than -1 (which causes a significant impact on the number of early p <
        // by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002		      <
        qParam_[prec].edv_.count = -1;						      <
      }											      }
  } // switch (mredMode)							      |	      return PKT_DROPPED;
										      >	    }
										      >	  } else {
										      >	    // When average queue length is between min. threshold and max. threshold 
										      >	    // and the packet is not dropped the value of edv_.count should be unchanged
										      >	    // rather than -1 (which causes a significant impact on the number of early packe
										      >	    // by Janusz Gozdecki <gozdecki@kt.agh.edu.pl>, 7/13/2002
										      >	    qParam_[prec].edv_.count = -1;
										      >	  }

  // if the packet survives the above conditions it				      |	  // if ecn is on, then the packet has already been enqueued
  // is finally queued in the underlying queue					      |	  if(ecn) { 
										      >	    // set idle_ to 0
										      >	    updateIdleFlag(prec); 
										      >	    return PKT_ENQUEUED;
										      >	  }
										      >	  
										      >	  //if the packet survives the above conditions it
										      >	  //is finally queued in the underlying queue
  q_->enque(pkt);									  q_->enque(pkt);
  bytes += (hdr_cmn::access(pkt))->size();					      |	  
										      |	  //virtually, this new packet is queued in one of the multiple queues,
  // virtually, this new packet is queued in one of the multiple queues,	      |	  //thus increasing the length of that virtual queue
  // thus increasing the length of that virtual queue				      <
  qParam_[prec].qlen++;									  qParam_[prec].qlen++;

  // set idle_ to 0									  // set idle_ to 0
  updateIdleFlag(prec);								      |	  updateIdleFlag(prec); 
										      |	  
  return PKT_ENQUEUED;									  return PKT_ENQUEUED;
}											}

//  Packet* deque()									//  Packet* deque()
//    Deques a packet from the physical queue.						//    Deques a packet from the physical queue.
Packet* redQueue::deque() {								Packet* redQueue::deque() {
  Packet *pkt;									      |	  return(q_->deque());
										      <
  pkt = q_->deque();								      <
  if (pkt != NULL) {								      <
     bytes -= (hdr_cmn::access(pkt))->size();					      <
     if (bytes < 0)								      <
         printf("\n\n\n\t********Error in redQueue:deque()\n\n\n\n\n");		      <
  }										      <
  return(pkt);									      <
}											}

// void calcAvg(int prec, int m)							// void calcAvg(int prec, int m)
//   This method calculates avg queue length, given the prec number,		      |	//   This method calculates avg queue length, given the prec number, 
//   m (a value used to adjust the queue size appropriately during idle times).		//   m (a value used to adjust the queue size appropriately during idle times).
//   If mredMode is rio_c, each virtual queue size is calculated independently.		//   If mredMode is rio_c, each virtual queue size is calculated independently.
//   If it is true, the calculated size of queue n includes the sizes of all	      |	//   If it is true, the calculated size of queue n includes the sizes of all 
//   virtual queues up to and including n.						//   virtual queues up to and including n.
void redQueue::calcAvg(int prec, int m) {						void redQueue::calcAvg(int prec, int m) {
  float f;										  float f;
  int i;										  int i;
  											  
  f = qParam_[prec].edv_.v_ave;								  f = qParam_[prec].edv_.v_ave;
  											  
  while (--m >= 1) {									  while (--m >= 1) {
    f *= 1.0 - qParam_[prec].edp_.q_w;							    f *= 1.0 - qParam_[prec].edp_.q_w;
  }											  }
  f *= 1.0 - qParam_[prec].edp_.q_w;							  f *= 1.0 - qParam_[prec].edp_.q_w;
  											  
  if (mredMode == rio_c)								  if (mredMode == rio_c)
    for (i = 0; i <= prec; i ++)							    for (i = 0; i <= prec; i ++)
      f += qParam_[i].edp_.q_w * qParam_[i].qlen;					      f += qParam_[i].edp_.q_w * qParam_[i].qlen;
  else if (mredMode == rio_d)								  else if (mredMode == rio_d)
    f += qParam_[prec].edp_.q_w * qParam_[prec].qlen;					    f += qParam_[prec].edp_.q_w * qParam_[prec].qlen;
  else //wred										  else //wred
    f += qParam_[prec].edp_.q_w * q_->length();						    f += qParam_[prec].edp_.q_w * q_->length();
  											  
  if (mredMode == wred)									  if (mredMode == wred)
    for (i = 0; i < numPrec; i ++)							    for (i = 0; i < numPrec; i ++)
      qParam_[i].edv_.v_ave = f;							      qParam_[i].edv_.v_ave = f;
  else //rio_c, rio_d									  else //rio_c, rio_d
    qParam_[prec].edv_.v_ave = f;							    qParam_[prec].edv_.v_ave = f;
}											}

// double getWeightedLength()								// double getWeightedLength()
//    Returns the weighted RED queue length for the entire physical queue, 		//    Returns the weighted RED queue length for the entire physical queue, 
//       in packets.									//       in packets.
double redQueue::getWeightedLength() {							double redQueue::getWeightedLength() {
  double sum = 0.0;									  double sum = 0.0;
										      |	  
  if (mredMode == rio_c)								  if (mredMode == rio_c)
    return qParam_[numPrec-1].edv_.v_ave;						    return qParam_[numPrec-1].edv_.v_ave;
  else {										  else {
    for (int prec = 0; prec < numPrec; prec++)						    for (int prec = 0; prec < numPrec; prec++)
      sum += qParam_[prec].edv_.v_ave;							      sum += qParam_[prec].edv_.v_ave;
    return(sum);									    return(sum);
  }											  }
}											}

// int getRealLength(void)								// int getRealLength(void)
//    Returns the length of the physical queue, in packets.				//    Returns the length of the physical queue, in packets.
int redQueue::getRealLength(void) {							int redQueue::getRealLength(void) {
  return(q_->length());									  return(q_->length());
}											}

// Returns the weighted RED queue length for one virtual queue in packets		// Returns the weighted RED queue length for one virtual queue in packets
// Added by Thilo (12/14/2001), xuanc							// Added by Thilo (12/14/2001), xuanc
double redQueue::getWeightedLength_v(int prec) {					double redQueue::getWeightedLength_v(int prec) {
  return qParam_[prec].edv_.v_ave;							  return qParam_[prec].edv_.v_ave;
}											}

// Returns the length of one virtual queue, in packets					// Returns the length of one virtual queue, in packets
// Added by Thilo (12/14/2001), xuanc							// Added by Thilo (12/14/2001), xuanc
int redQueue::getRealLength_v(int prec) {						int redQueue::getRealLength_v(int prec) {
  return qParam_[prec].qlen;								  return qParam_[prec].qlen;
}											}

//  void setPTC(int outLinkBW)								//  void setPTC(int outLinkBW)
//    Sets the packet time constant, given the outgoing link bandwidth from the		//    Sets the packet time constant, given the outgoing link bandwidth from the
//    router.										//    router.
void redQueue::setPTC(double outLinkBW) {						void redQueue::setPTC(double outLinkBW) {
  for (int i = 0; i < numPrec; i++)							  for (int i = 0; i < numPrec; i++)
    qParam_[i].edp_.ptc = outLinkBW/(8.0*qParam_[i].edp_.mean_pktsize);			    qParam_[i].edp_.ptc = outLinkBW/(8.0*qParam_[i].edp_.mean_pktsize);
}											}

//  void setMPS(int mps)								//  void setMPS(int mps)
//    Sets the mean packet size for each of the virtual queues.				//    Sets the mean packet size for each of the virtual queues.
void redQueue::setMPS(int mps) {							void redQueue::setMPS(int mps) {
  for (int i = 0; i < numPrec; i++)							  for (int i = 0; i < numPrec; i++)
    qParam_[i].edp_.mean_pktsize = mps;							    qParam_[i].edp_.mean_pktsize = mps;
}											}
										      <
float redQueue::getMarkP(int prec) {						      <
  if ((mredMode >= bio_ssi) && (mredMode <= bio_aat)) {				      <
    return qParam_[prec].bv_.pmark_;						      <
  }										      <
  return qParam_[prec].red_pmark_;						      <
}										      <
