[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ns] Some more thoughts about the idle_-flag in the diffserv RED-queueimplementation



After I wrote the last message regarding the bug I made the changes I
suggested in the mail and got some quite acceptable results. The changes
can be found at the end of this mail. But I also had a look at the
sourcecode of red.cc and found out, that they don't drop packets if a
queue was idle before, so they can set idle_ to 0 at the beginning of
enqueue without having to care that the packet might get dropped later. 
Here's a part of red.cc: 

void REDQueue::enque(Packet* pkt)
{
  ..
  ..
        if (idle_) {
		// A packet that arrives to an idle queue will never
		//  be dropped.
		double now = Scheduler::instance().clock();
		/* To account for the period when the queue was empty. */
		idle_ = 0;
		m = int(edp_.ptc * (now - idletime_));
	}
  ..
  ..

	if (qavg >= edp_.th_min && qlen > 1) {
          // decide if packet gets dropped
        } else {
          // packet doesn't get dropped
        }
 ..
 ..
}

So packets never get dropped when qlen is 1 so it can't happen that the
idle_ flag is set to 0 but the queue is empty. 

I had a look at [Sally Floyd, Van Jacobsen, "Random Early Detection
Gateways for Congestion Avoidance", IEEE/ACM Transactions on Networking,
August 1993] but I couldn't find that behaviour described in there so
maybe it's an improvement made after the paper was written.

To add this behavoiur to dsredq.cc would be no problem for rio_d and
probably also MRED-mode but I'm not sure what to do with the rio_c
MRED-mode because there I can't make a test on virtual_queuelength > 1
before dropping a packet as I also have to pay attention to the virtual
queues with lower drop prec's. 

Any comments are welcome!

Best regards, 
Thilo 

---- changes to dsred.cc ----

the call to updareREDStateVar at the end of dsREDQueue::enque (added by
xuanc, 12/03/01) 
must be removed again

---- changes to dsredq.h ----

class redQueue {
 public:
  ..
  ..
++  //sets idle_ to 0
++  void redQueue::updateIdleFlag(int prec);
  ..
}

---- changes to dsredq.cc ----

++ // void updateIdleFlag(int)
++ //    Called by enque() to set idle_ to 0 if a packet was enqueued
successfully
++ void redQueue::updateIdleFlag(int prec) {
++   if (mredMode == rio_c) { 
++     for (int i = prec; i < numPrec; i++) qParam_[i].idle_ = 0;
++   } else if (mredMode == rio_d) { 
++    qParam_[prec].idle_ = 0; 
++   } else {
++    qParam_[0].idle_ = 0;
++   } 
++ }

// void enque(Packet *pkt, int prec, int ecn)
//    Enques a packet associated with one of the precedence levels of
the
//    physical queue.
int redQueue::enque(Packet *pkt, int prec, int ecn) {
  int m = 0;
  double now, u;
  double pa,pb;
  
  if (q_->length() > (qlim-1))
    return PKT_DROPPED;
  
  now = Scheduler::instance().clock();
  
  //now determining the avg for that queue
  if (mredMode == dropTail) {
    if (q_->length() >= qParam_[0].edp_.th_min) {
      return PKT_DROPPED;
    } else {
      q_->enque(pkt);
      return PKT_ENQUEUED;		
    }
  } else if (mredMode == rio_c) {
    for (int i = prec; i < numPrec; i++) {	
      m = 0;
      if (qParam_[i].idle_) {
!! 	// qParam_[i].idle_ = 0;
	m = int(qParam_[i].edp_.ptc * (now - qParam_[i].idletime_));
      }
      calcAvg(i, m+1); 
    }
  } else if (mredMode == rio_d) {
    if (qParam_[prec].idle_) {
!!    // qParam_[prec].idle_ = 0;
      m = int(qParam_[prec].edp_.ptc * (now - qParam_[prec].idletime_));
    }	
    calcAvg(prec, m+1);
  } else { //wred
    if (qParam_[0].idle_) {
!!    // qParam_[0].idle_ = 0;
      m = int(qParam_[0].edp_.ptc * (now - qParam_[0].idletime_));
    }	
    calcAvg(0, m+1);
  }
  
  // enqueu packet if we are using ecn
  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++;
  }
  
  //if the avg is greater than the min threshold,
  //there can be only two cases.....
  if (qParam_[prec].edv_.v_ave > qParam_[prec].edp_.th_min) {
    //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,
      
      qParam_[prec].edv_.count++;
      qParam_[prec].edv_.v_prob = (1/qParam_[prec].edp_.max_p_inv) *
	(qParam_[prec].edv_.v_ave-qParam_[prec].edp_.th_min) /
	(qParam_[prec].edp_.th_max-qParam_[prec].edp_.th_min);
      
      pb = qParam_[prec].edv_.v_prob;
      pa = pb/(1.0 - qParam_[prec].edv_.count*pb);
      //now determining whether to drop the packet or not
      u = Random::uniform(0.0, 1.0);
      
      //drop it
      if (u <= pa) {	
!!     if (ecn) {
!!      updateIdleFlag(prec); // set idle_ to 0
!!      return PKT_MARKED;
!!     } else 	return PKT_EDROPPED;
      }
    } else { //if avg queue is greater than max. threshold
      qParam_[prec].edv_.count = 0;
!!    if (ecn) {
!!     updateIdleFlag(prec); // set idle_ to 0
!!     return PKT_MARKED;
!!    } else return PKT_DROPPED;
    }
  }
  qParam_[prec].edv_.count = -1;
  
  // if ecn is on, then the packet has already been enqueued
!!  if(ecn) {
!!   updateIdleFlag(prec); // set idle_ to 0
!!   return PKT_ENQUEUED;
!!  }
  
  //if the packet survives the above conditions it
  //is finally queued in the underlying queue
  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++;
++  updateIdleFlag(prec); // set idle_ to 0 
 
  return PKT_ENQUEUED;
}