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

通讯编程

开发平台:

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 "delay.h"
  40. #include "random.h"
  41. #include "flags.h"
  42. #include "tcp.h"
  43. #include "dsredq.h"
  44. /*------------------------------------------------------------------------------
  45. dsREDClass declaration. 
  46.     Links the new class in the TCL heirarchy.  See "Notes And Documentation for 
  47. ns-2."
  48. ------------------------------------------------------------------------------*/
  49. static class dsREDClass : public TclClass {
  50. public:
  51. dsREDClass() : TclClass("Queue/dsRED") {}
  52. TclObject* create(int, const char*const*) {
  53. return (new dsREDQueue);
  54. }
  55. } class_dsred;
  56. /*------------------------------------------------------------------------------
  57. dsREDQueue() Constructor.
  58.     Initializes the queue.  Note that the default value assigned to numQueues 
  59. in tcl/lib/ns-default.tcl must be no greater than MAX_QUEUES (the physical 
  60. queue array size).
  61. ------------------------------------------------------------------------------*/
  62. dsREDQueue::dsREDQueue() : de_drop_(NULL), link_(NULL)   {
  63.   bind("numQueues_", &numQueues_);
  64.   bind_bool("ecn_", &ecn_);
  65.   int i;
  66.   
  67.   numPrec = MAX_PREC;
  68.   schedMode = schedModeRR;
  69.   
  70.   for(i=0;i<MAX_QUEUES;i++){
  71.     queueMaxRate[i] = 0;
  72.     queueWeight[i]=1;
  73.   }
  74.   
  75.   queuesDone = MAX_QUEUES;
  76.   phbEntries = 0; // Number of entries in PHB table
  77.   
  78.   reset();
  79. }
  80. // RED queues initilization
  81. void dsREDQueue::reset() {
  82.   int i;
  83.   
  84.   qToDq = 0; // q to be dequed, initialized to 0
  85.   
  86.   for(i=0;i<MAX_QUEUES;i++){
  87.     queueAvgRate[i] = 0.0;
  88.     queueArrTime[i] = 0.0;
  89.     slicecount[i]=0;
  90.     pktcount[i]=0;
  91.     wirrTemp[i]=0;
  92.     wirrqDone[i]=0;
  93.   }
  94.   
  95.   stats.drops = 0;
  96.   stats.edrops = 0;
  97.   stats.pkts = 0;
  98.   
  99.   for(i=0;i<MAX_CP;i++){
  100.     stats.drops_CP[i]=0;
  101.     stats.edrops_CP[i]=0;
  102.     stats.pkts_CP[i]=0;
  103.   }
  104.   
  105.   for (i = 0; i < MAX_QUEUES; i++)
  106.     redq_[i].qlim = limit();
  107.   
  108.   // Compute the "packet time constant" if we know the
  109.   // link bandwidth.  The ptc is the max number of (avg sized)
  110.   // pkts per second which can be placed on the link.
  111.   if (link_)
  112.     for (int i = 0; i < MAX_QUEUES; i++)
  113.       redq_[i].setPTC(link_->bandwidth());
  114.   
  115.   Queue::reset();
  116. }
  117. /*-----------------------------------------------------------------------------
  118. void edrop(Packet* pkt)
  119.     This method is used so that flowmonitor can monitor early drops.
  120. -----------------------------------------------------------------------------*/
  121. void dsREDQueue::edrop(Packet* p)
  122. {
  123. if (de_drop_ != 0){
  124. de_drop_->recv(p);
  125. }
  126. else {
  127. drop(p);
  128. }
  129. }
  130. /*-----------------------------------------------------------------------------
  131. void applyTSWMeter(int q_id, int pkt_size)
  132. Update the average rate for a physical Q (indicated by q_id).
  133. Pre: policy's variables avgRate, arrivalTime, and winLen hold valid values;
  134.   pkt_size specifies the bytes just dequeued (0 means no packet dequeued).
  135. Post: Adjusts policy's TSW state variables avgRate and arrivalTime 
  136.   (also called tFront) according to the bytes sent.
  137. Note: See the paper "Explicit Allocation of Best effor Delivery Service" (David
  138.   Clark and Wenjia Fang), Section 3.3, for a description of the TSW Tagger.
  139. -----------------------------------------------------------------------------*/
  140. void dsREDQueue::applyTSWMeter(int q_id, int pkt_size) {
  141.   double now, bytesInTSW, newBytes;
  142.   double winLen = 1.0;
  143.   bytesInTSW = queueAvgRate[q_id] * winLen;
  144.   // Modified by xuanc(xuanc@isi.edu) Oct 18, 2001, 
  145.   // referring to the patch contributed by 
  146.   // Sergio Andreozzi <sergio.andreozzi@lut.fi>
  147.   newBytes = bytesInTSW + pkt_size;
  148.   // Calculate the average rate (SW)
  149.   now = Scheduler::instance().clock();
  150.   queueAvgRate[q_id] = newBytes / (now - queueArrTime[q_id] + winLen);
  151.   queueArrTime[q_id] = now;
  152. }
  153. /*-----------------------------------------------------------------------------
  154. void enque(Packet* pkt) 
  155.     The following method outlines the enquing mechanism for a Diffserv router.
  156. This method is not used by the inheriting classes; it only serves as an 
  157. outline.
  158. -----------------------------------------------------------------------------*/
  159. void dsREDQueue::enque(Packet* pkt) {
  160.   int codePt, eq_id, prec;
  161.   hdr_ip* iph = hdr_ip::access(pkt);
  162.   //extracting the marking done by the edge router
  163.   codePt = iph->prio();
  164.   int ecn = 0;
  165.   
  166.   //looking up queue and prec numbers for that codept
  167.   lookupPHBTable(codePt, &eq_id, &prec);
  168.   // code added for ECN support
  169.   //hdr_flags* hf = (hdr_flags*)(pkt->access(off_flags_));
  170.   // Changed for the latest version instead of 2.1b6
  171.   hdr_flags* hf = hdr_flags::access(pkt);
  172.   if (ecn_ && hf->ect()) ecn = 1;
  173.   
  174.   stats.pkts_CP[codePt]++;
  175.   stats.pkts++;
  176.   
  177.   switch(redq_[eq_id].enque(pkt, prec, ecn)) {
  178.   case PKT_ENQUEUED:
  179.     break;
  180.   case PKT_DROPPED:
  181.     stats.drops_CP[codePt]++;
  182.     stats.drops++;
  183.     drop(pkt);
  184.          break;
  185.   case PKT_EDROPPED:
  186.     stats.edrops_CP[codePt]++;
  187.     stats.edrops++;
  188.     edrop(pkt);
  189.     break;
  190.   case PKT_MARKED:
  191.     hf->ce() = 1;  // mark Congestion Experienced bit
  192.     break;
  193.   default:
  194.     break;
  195.   }
  196. }
  197. // Dequing mechanism for both edge and core router.
  198. Packet* dsREDQueue::deque() {
  199.   Packet *p = NULL;
  200.   int queue, prec;
  201.   hdr_ip* iph;
  202.   int fid;
  203.   int dq_id;
  204.   // Select queue to deque under the scheduling scheme specified.
  205.   dq_id = selectQueueToDeque();
  206.   
  207.   // Dequeue a packet from the underlying queue:
  208.   if (dq_id < numQueues_) 
  209.     p = redq_[dq_id].deque();
  210.   
  211.   if (p) { 
  212.     iph= hdr_ip::access(p);
  213.     fid = iph->flowid()/32;
  214.     pktcount[dq_id]+=1;
  215.     
  216.     // update the average rate for pri-queue
  217.     // Modified by xuanc(xuanc@isi.edu) Oct 18, 2001, 
  218.     // referring to the patch contributed by 
  219.     // Sergio Andreozzi <sergio.andreozzi@lut.fi>
  220.     // When there is a packet dequeued, 
  221.     // update the average rate of each queue ()
  222.     if (schedMode==schedModePRI) 
  223.       for (int i=0;i<numQueues_;i++) 
  224. if (queueMaxRate[i]) 
  225.   applyTSWMeter(i, (i == dq_id) ? hdr_cmn::access(p)->size() : 0); 
  226.     // Get the precedence level (or virtual queue id)
  227.     // for the packet dequeued.
  228.     lookupPHBTable(getCodePt(p), &queue, &prec);
  229.     
  230.     // decrement virtual queue length
  231.     // Previously in updateREDStateVar, moved by xuanc (12/03/01)
  232.     //redq_[dq_id].qParam_[prec].qlen--;
  233.     redq_[dq_id].updateVREDLen(prec);
  234.     // update state variables for that "virtual" queue
  235.     redq_[dq_id].updateREDStateVar(prec);
  236.   }
  237.   
  238.   // Return the dequed packet:
  239.   return(p);
  240. }
  241. //    Extracts the code point marking from packet header.
  242. int dsREDQueue::getCodePt(Packet *p) {
  243.   hdr_ip* iph = hdr_ip::access(p);
  244.   return(iph->prio());
  245. }
  246. // Reutrn the id of physical queue to be dequeued
  247. int dsREDQueue::selectQueueToDeque() {
  248.   // If the queue to be dequed has no elements, 
  249.   // look for the next queue in line
  250.   int i = 0;
  251.   
  252.   // Round-Robin
  253.   if(schedMode==schedModeRR){
  254.     //printf("RRn");
  255.     qToDq = ((qToDq + 1) % numQueues_);
  256.     while ((i < numQueues_) && (redq_[qToDq].getRealLength() == 0)) {
  257.       qToDq = ((qToDq + 1) % numQueues_);
  258.       i++;
  259.     }
  260.   } else if (schedMode==schedModeWRR) { // Weighted Round Robin
  261.     if(wirrTemp[qToDq]<=0){
  262.       qToDq = ((qToDq + 1) % numQueues_);
  263.       wirrTemp[qToDq] = queueWeight[qToDq] - 1;
  264.     } else {
  265.       wirrTemp[qToDq] = wirrTemp[qToDq] -1;
  266.     }
  267.     while ((i < numQueues_) && (redq_[qToDq].getRealLength() == 0)) {
  268.       wirrTemp[qToDq] = 0;
  269.       qToDq = ((qToDq + 1) % numQueues_);
  270.       wirrTemp[qToDq] = queueWeight[qToDq] - 1;
  271.       i++;
  272.     }
  273.   } else if (schedMode==schedModeWIRR) {
  274.     qToDq = ((qToDq + 1) % numQueues_);
  275.     while ((i<numQueues_) && ((redq_[qToDq].getRealLength()==0) || (wirrqDone[qToDq]))) {
  276.       if (!wirrqDone[qToDq]) {
  277. queuesDone++;
  278. wirrqDone[qToDq]=1;
  279.       }
  280.       qToDq = ((qToDq + 1) % numQueues_);
  281.       i++;
  282.     }
  283.     
  284.     if (wirrTemp[qToDq] == 1) {
  285.       queuesDone +=1;
  286.       wirrqDone[qToDq]=1;
  287.     }
  288.     wirrTemp[qToDq]-=1;
  289.     if(queuesDone >= numQueues_) {
  290.       queuesDone = 0;
  291.       for(i=0;i<numQueues_;i++) {
  292. wirrTemp[i] = queueWeight[i];
  293. wirrqDone[i]=0;
  294.       }   
  295.     }
  296.   } else if (schedMode==schedModePRI) {
  297.     // Find the queue with highest priority, which satisfies:
  298.     // 1. nozero queue length; and either
  299.     // 2.1. has no MaxRate specified; or
  300.     // 2.2. has MaxRate specified and 
  301.     //          its average rate is not beyond that limit.
  302.     i = 0;
  303.     while (i < numQueues_ && 
  304.    (redq_[i].getRealLength() == 0 ||
  305.     (queueMaxRate[i] && queueAvgRate[i]>queueMaxRate[i]))){
  306.       i++;
  307.     }
  308.     qToDq = i;
  309.     // If no queue satisfies the condition above,
  310.     // find the Queue with highest priority, 
  311.     // which has packet to dequeue.
  312.     // NOTE: the high priority queue can still have its packet dequeued
  313.     //       even if its average rate has beyond the MAX rate specified!
  314.     //       Ideally, a NO_PACKET_TO_DEQUEUE should be returned.
  315.     if (i == numQueues_) {
  316.       i = qToDq = 0;
  317.       while ((i < numQueues_) && (redq_[qToDq].getRealLength() == 0)) {
  318. qToDq = ((qToDq + 1) % numQueues_);
  319. i++;
  320.       }
  321.     }
  322.   }
  323.   return(qToDq);
  324. }
  325. /*-----------------------------------------------------------------------------
  326. void lookupPHBTable(int codePt, int* queue, int* prec)
  327.     Assigns the queue and prec parameters values corresponding to a given code 
  328. point.  The code point is assumed to be present in the PHB table.  If it is 
  329. not, an error message is outputted and queue and prec are undefined.
  330. -----------------------------------------------------------------------------*/
  331. void dsREDQueue::lookupPHBTable(int codePt, int* queue, int* prec) {
  332.   for (int i = 0; i < phbEntries; i++) {
  333.     if (phb_[i].codePt_ == codePt) {
  334.       *queue = phb_[i].queue_;
  335.       *prec = phb_[i].prec_;
  336.       return;
  337.     }
  338.   }
  339.   // quiet the compiler
  340.   *queue = 0;
  341.   *prec = 0;
  342.   printf("ERROR: No match found for code point %d in PHB Table.n", codePt);
  343.   assert (false);
  344. }
  345. /*-----------------------------------------------------------------------------
  346. void addPHBEntry(int codePt, int queue, int prec)
  347.     Add a PHB table entry.  (Each entry maps a code point to a queue-precedence
  348. pair.)
  349. -----------------------------------------------------------------------------*/
  350. void dsREDQueue::addPHBEntry(int codePt, int queue, int prec) {
  351.   if (phbEntries == MAX_CP) {
  352.     printf("ERROR: PHB Table size limit exceeded.n");
  353.   } else {
  354.     phb_[phbEntries].codePt_ = codePt;
  355.     phb_[phbEntries].queue_ = queue;
  356.     phb_[phbEntries].prec_ = prec;
  357.     stats.valid_CP[codePt] = 1;
  358.     phbEntries++;
  359.   }
  360. }
  361. /*-----------------------------------------------------------------------------
  362. void addPHBEntry(int codePt, int queue, int prec)
  363.     Add a PHB table entry.  (Each entry maps a code point to a queue-precedence
  364. pair.)
  365. -----------------------------------------------------------------------------*/
  366. double dsREDQueue::getStat(int argc, const char*const* argv) {
  367. if (argc == 3) {
  368. if (strcmp(argv[2], "drops") == 0)
  369.          return (stats.drops*1.0);
  370. if (strcmp(argv[2], "edrops") == 0)
  371.          return (stats.edrops*1.0);
  372. if (strcmp(argv[2], "pkts") == 0)
  373.          return (stats.pkts*1.0);
  374.    }
  375. if (argc == 4) {
  376. if (strcmp(argv[2], "drops") == 0)
  377.          return (stats.drops_CP[atoi(argv[3])]*1.0);
  378. if (strcmp(argv[2], "edrops") == 0)
  379.          return (stats.edrops_CP[atoi(argv[3])]*1.0);
  380. if (strcmp(argv[2], "pkts") == 0)
  381.          return (stats.pkts_CP[atoi(argv[3])]*1.0);
  382. }
  383. return -1.0;
  384. }
  385. /*------------------------------------------------------------------------------
  386. void setNumPrec(int prec) 
  387.     Sets the current number of drop precendences.  The number of precedences is
  388. the number of virtual queues per physical queue.
  389. ------------------------------------------------------------------------------*/
  390. void dsREDQueue::setNumPrec(int prec) {
  391. int i;
  392. if (prec > MAX_PREC) {
  393. printf("ERROR: Cannot declare more than %d prcedence levels (as defined by MAX_PREC)n",MAX_PREC);
  394. } else {
  395. numPrec = prec;
  396. for (i = 0; i < MAX_QUEUES; i++)
  397. redq_[i].numPrec = numPrec;
  398. }
  399. }
  400. /*------------------------------------------------------------------------------
  401. void setMREDMode(const char* mode)
  402.    sets up the average queue accounting mode.
  403. ----------------------------------------------------------------------------*/
  404. void dsREDQueue::setMREDMode(const char* mode, const char* queue) {
  405.   int i;
  406.   mredModeType tempMode;
  407.   
  408.   if (strcmp(mode, "RIO-C") == 0)
  409.     tempMode = rio_c;
  410.   else if (strcmp(mode, "RIO-D") == 0)
  411.     tempMode = rio_d;
  412.   else if (strcmp(mode, "WRED") == 0)
  413.     tempMode = wred;
  414.   else if (strcmp(mode, "DROP") == 0)
  415.     tempMode = dropTail;
  416.   else {
  417.     printf("Error: MRED mode %s does not existn",mode);
  418.     return;
  419.   }
  420.   
  421.   if (!queue)
  422.     for (i = 0; i < MAX_QUEUES; i++)
  423.       redq_[i].mredMode = tempMode;
  424.   else
  425.     redq_[atoi(queue)].mredMode = tempMode;
  426. }
  427. /*------------------------------------------------------------------------------
  428. void printPHBTable()
  429.     Prints the PHB Table, with one entry per line.
  430. ------------------------------------------------------------------------------*/
  431. void dsREDQueue::printPHBTable() {
  432.    printf("PHB Table:n");
  433.    for (int i = 0; i < phbEntries; i++)
  434.       printf("Code Point %d is associated with Queue %d, Precedence %dn", phb_[i].codePt_, phb_[i].queue_, phb_[i].prec_);
  435.    printf("n");
  436. }
  437. /*------------------------------------------------------------------------------
  438. void printStats()
  439.     An output method that may be altered to assist debugging.
  440. ------------------------------------------------------------------------------*/
  441. void dsREDQueue::printStats() {
  442. printf("nPackets Statisticsn");
  443. printf("=======================================n");
  444. printf(" CP  TotPkts   TxPkts   ldrops   edropsn");
  445. printf(" --  -------   ------   ------   ------n");
  446. printf("All %8ld %8ld %8ld %8ldn",stats.pkts,stats.pkts-stats.drops-stats.edrops,stats.drops,stats.edrops);
  447. for (int i = 0; i < MAX_CP; i++)
  448. if (stats.pkts_CP[i] != 0)
  449. printf("%3d %8ld %8ld %8ld %8ldn",i,stats.pkts_CP[i],stats.pkts_CP[i]-stats.drops_CP[i]-stats.edrops_CP[i],stats.drops_CP[i],stats.edrops_CP[i]);
  450. }
  451. void dsREDQueue::printWRRcount() {
  452.    int i;
  453.    for (i = 0; i < numQueues_; i++){
  454.       printf("%d: %d %d %d.n", i, slicecount[i],pktcount[i],queueWeight[i]);
  455.    }
  456. }
  457. /*------------------------------------------------------------------------------
  458. void setSchedularMode(int schedtype)
  459.    sets up the schedular mode.
  460. ----------------------------------------------------------------------------*/
  461. void dsREDQueue::setSchedularMode(const char* schedtype) {
  462. if (strcmp(schedtype, "RR") == 0)
  463.     schedMode = schedModeRR;
  464. else if (strcmp(schedtype, "WRR") == 0)
  465. schedMode = schedModeWRR;
  466. else if (strcmp(schedtype, "WIRR") == 0)
  467. schedMode = schedModeWIRR;
  468. else if (strcmp(schedtype, "PRI") == 0)
  469. schedMode = schedModePRI;
  470. else
  471. printf("Error: Scheduler type %s does not existn",schedtype);
  472. }
  473. /*------------------------------------------------------------------------------
  474. void addQueueWeights(int queueNum, int weight)
  475.    An input method to set the individual Queue Weights.
  476. ----------------------------------------------------------------------------*/
  477. void dsREDQueue::addQueueWeights(int queueNum, int weight) {
  478.   if(queueNum < MAX_QUEUES){
  479.     queueWeight[queueNum]=weight;
  480.   } else {
  481.     printf("The queue number is out of range.n");
  482.   }
  483. }
  484. //Set the individual Queue Max Rates for Priority Queueing.
  485. void dsREDQueue::addQueueRate(int queueNum, int rate) {
  486.   if(queueNum < MAX_QUEUES){
  487.     // Convert to BYTE/SECOND
  488.     queueMaxRate[queueNum]=(double)rate/8.0;
  489.   } else {
  490.     printf("The queue number is out of range.n");
  491.   }
  492. }
  493. /*-----------------------------------------------------------------------------
  494. int command(int argc, const char*const* argv)
  495.     Commands from the ns file are interpreted through this interface.
  496. -----------------------------------------------------------------------------*/
  497. int dsREDQueue::command(int argc, const char*const* argv) {
  498.   if (strcmp(argv[1], "configQ") == 0) {
  499.     // modification to set the parameter q_w by Thilo
  500.     redq_[atoi(argv[2])].config(atoi(argv[3]), argc, argv);
  501.     return(TCL_OK);
  502.   }
  503.   if (strcmp(argv[1], "addPHBEntry") == 0) {
  504.     addPHBEntry(atoi(argv[2]), atoi(argv[3]), atoi(argv[4]));
  505.     return (TCL_OK);
  506.   }
  507.   if (strcmp(argv[1], "meanPktSize") == 0) {
  508.     for (int i = 0; i < MAX_QUEUES; i++)
  509.       redq_[i].setMPS(atoi(argv[2]));
  510.     return(TCL_OK);
  511.   }
  512.   if (strcmp(argv[1], "setNumPrec") == 0) {
  513.     setNumPrec(atoi(argv[2]));
  514.     return(TCL_OK);
  515.   }
  516.   if (strcmp(argv[1], "getAverage") == 0) {
  517.     Tcl& tcl = Tcl::instance();
  518.     tcl.resultf("%f", redq_[atoi(argv[2])].getWeightedLength());
  519.     return(TCL_OK);
  520.   }
  521.   if (strcmp(argv[1], "getStat") == 0) {
  522.     Tcl& tcl = Tcl::instance();
  523.     tcl.resultf("%f", getStat(argc,argv));
  524.     return(TCL_OK);
  525.   }
  526.   if (strcmp(argv[1], "getCurrent") == 0) {
  527.     Tcl& tcl = Tcl::instance();
  528.     tcl.resultf("%f", redq_[atoi(argv[2])].getRealLength()*1.0);
  529.     return(TCL_OK);
  530.   }
  531.   if (strcmp(argv[1], "printStats") == 0) {
  532.     printStats();
  533.     return (TCL_OK);
  534.   }
  535.   if (strcmp(argv[1], "printWRRcount") == 0) {
  536.     printWRRcount();
  537.     return (TCL_OK);
  538.   }
  539.   if (strcmp(argv[1], "printPHBTable") == 0) {
  540.     printPHBTable();
  541.     return (TCL_OK);
  542.   }
  543.   if (strcmp(argv[1], "link") == 0) {
  544.     Tcl& tcl = Tcl::instance();
  545.     LinkDelay* del = (LinkDelay*) TclObject::lookup(argv[2]);
  546.     if (del == 0) {
  547.       tcl.resultf("RED: no LinkDelay object %s",
  548.   argv[2]);
  549.       return(TCL_ERROR);
  550.     }
  551.     link_ = del;
  552.     return (TCL_OK);
  553.   }
  554.   if (strcmp(argv[1], "early-drop-target") == 0) {
  555.     Tcl& tcl = Tcl::instance();
  556.     NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
  557.     if (p == 0) {
  558.       tcl.resultf("no object %s", argv[2]);
  559.       return (TCL_ERROR);
  560.     }
  561.     de_drop_ = p;
  562.     return (TCL_OK);
  563.   }
  564.   if (strcmp(argv[1], "setSchedularMode") == 0) {
  565.     setSchedularMode(argv[2]);
  566.     return(TCL_OK);
  567.   }
  568.   if (strcmp(argv[1], "setMREDMode") == 0) {
  569.     if (argc == 3)
  570.       setMREDMode(argv[2],0);
  571.     else
  572.       setMREDMode(argv[2],argv[3]);
  573.     return(TCL_OK);
  574.   }
  575.   if (strcmp(argv[1], "addQueueWeights") == 0) {
  576.     addQueueWeights(atoi(argv[2]), atoi(argv[3]));
  577.     return(TCL_OK);
  578.   }
  579.   if (strcmp(argv[1], "addQueueRate") == 0) {
  580.     addQueueRate(atoi(argv[2]), atoi(argv[3]));
  581.     return(TCL_OK);
  582.   }
  583.   // Returns the weighted RED queue length for one virtual queue in packets
  584.   // Added by Thilo
  585.   if (strcmp(argv[1], "getAverageV") == 0) {
  586.     Tcl& tcl = Tcl::instance();
  587.     tcl.resultf("%f",
  588. redq_[atoi(argv[2])].getWeightedLength_v(atoi(argv[3])));
  589.     return(TCL_OK);
  590.   } 
  591.   // Returns the length of one virtual queue, in packets 
  592.   // Added by Thilo
  593.   if (strcmp(argv[1], "getCurrentV") == 0) {
  594.     Tcl& tcl = Tcl::instance();
  595.     tcl.resultf("%f",
  596. redq_[atoi(argv[2])].getRealLength_v(atoi(argv[3]))*1.0);
  597.     return(TCL_OK);
  598.   }
  599.   return(Queue::command(argc, argv));
  600. }