drr.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*-
00002  *
00003  * Copyright (c) Xerox Corporation 1997. All rights reserved.
00004  *  
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU General Public License as published by the
00007  * Free Software Foundation; either version 2 of the License, or (at your
00008  * option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along
00016  * with this program; if not, write to the Free Software Foundation, Inc.,
00017  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  *
00019  * Linking this file statically or dynamically with other modules is making
00020  * a combined work based on this file.  Thus, the terms and conditions of
00021  * the GNU General Public License cover the whole combination.
00022  *
00023  * In addition, as a special exception, the copyright holders of this file
00024  * give you permission to combine this file with free software programs or
00025  * libraries that are released under the GNU LGPL and with code included in
00026  * the standard release of ns-2 under the Apache 2.0 license or under
00027  * otherwise-compatible licenses with advertising requirements (or modified
00028  * versions of such code, with unchanged license).  You may copy and
00029  * distribute such a system following the terms of the GNU GPL for this
00030  * file and the licenses of the other code concerned, provided that you
00031  * include the source code of that other code when and as the GNU GPL
00032  * requires distribution of source code.
00033  *
00034  * Note that people who make modified versions of this file are not
00035  * obligated to grant this special exception for their modified versions;
00036  * it is their choice whether to do so.  The GNU General Public License
00037  * gives permission to release a modified version without this exception;
00038  * this exception also makes it possible to release a modified version
00039  * which carries forward this exception.
00040  *
00041  * This file contributed by Sandeep Bajaj <bajaj@parc.xerox.com>, Mar 1997.
00042  *
00043  * $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/drr.cc,v 1.11 2005/08/26 05:05:29 tomh Exp $
00044  */
00045 
00046 #ifndef lint
00047 static const char rcsid[] =
00048     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/drr.cc,v 1.11 2005/08/26 05:05:29 tomh Exp $ (Xerox)";
00049 #endif
00050 
00051 #include "config.h"   // for string.h
00052 #include <stdlib.h>
00053 #include "queue.h"
00054 
00055 class PacketDRR;
00056 class DRR;
00057 
00058 class PacketDRR : public PacketQueue {
00059     PacketDRR(): pkts(0),src(-1),bcount(0),prev(0),next(0),deficitCounter(0),turn(0) {}
00060     friend class DRR;
00061     protected :
00062     int pkts;
00063     int src;    //to detect collisions keep track of actual src address
00064     int bcount; //count of bytes in each flow to find the max flow;
00065     PacketDRR *prev;
00066     PacketDRR *next;
00067     int deficitCounter; 
00068     int turn;
00069     inline PacketDRR * activate(PacketDRR *head) {
00070         if (head) {
00071             this->prev = head->prev;
00072             this->next = head;
00073             head->prev->next = this;
00074             head->prev = this;
00075             return head;
00076         }
00077         this->prev = this;
00078         this->next = this;
00079         return this;
00080     }
00081     inline PacketDRR * idle(PacketDRR *head) {
00082         if (head == this) {
00083             if (this->next == this)
00084                 return 0;
00085             this->next->prev = this->prev;
00086             this->prev->next = this->next;
00087             return this->next;
00088         }
00089         this->next->prev = this->prev;
00090         this->prev->next = this->next;
00091         return head;
00092     }
00093 };
00094 
00095 class DRR : public Queue {
00096     public :
00097     DRR();
00098     virtual int command(int argc, const char*const* argv);
00099     Packet *deque(void);
00100     void enque(Packet *pkt);
00101     int hash(Packet *pkt);
00102     void clear();
00103 protected:
00104     int buckets_ ; //total number of flows allowed
00105     int blimit_;    //total number of bytes allowed across all flows
00106     int quantum_;  //total number of bytes that a flow can send
00107     int mask_;     /*if set hashes on just the node address otherwise on 
00108              node+port address*/
00109     int bytecnt ; //cumulative sum of bytes across all flows
00110     int pktcnt ; // cumulative sum of packets across all flows
00111     int flwcnt ; //total number of active flows
00112     PacketDRR *curr; //current active flow
00113     PacketDRR *drr ; //pointer to the entire drr struct
00114 
00115     inline PacketDRR *getMaxflow (PacketDRR *curr) { //returns flow with max pkts
00116         int i;
00117         PacketDRR *tmp;
00118         PacketDRR *maxflow=curr;
00119         for (i=0,tmp=curr; i < flwcnt; i++,tmp=tmp->next) {
00120             if (maxflow->bcount < tmp->bcount)
00121                 maxflow=tmp;
00122         }
00123         return maxflow;
00124     }
00125   
00126 public:
00127     //returns queuelength in packets
00128     inline int length () {
00129         return pktcnt;
00130     }
00131 
00132     //returns queuelength in bytes
00133     inline int blength () {
00134         return bytecnt;
00135     }
00136 };
00137 
00138 static class DRRClass : public TclClass {
00139 public:
00140     DRRClass() : TclClass("Queue/DRR") {}
00141     TclObject* create(int, const char*const*) {
00142         return (new DRR);
00143     }
00144 } class_drr;
00145 
00146 DRR::DRR()
00147 {
00148     buckets_=16;
00149     quantum_=250;
00150     drr=0;
00151     curr=0;
00152     flwcnt=0;
00153     bytecnt=0;
00154     pktcnt=0;
00155     mask_=0;
00156     bind("buckets_",&buckets_);
00157     bind("blimit_",&blimit_);
00158     bind("quantum_",&quantum_);
00159     bind("mask_",&mask_);
00160 }
00161  
00162 void DRR::enque(Packet* pkt)
00163 {
00164     PacketDRR *q,*remq;
00165     int which;
00166 
00167     hdr_cmn *ch= hdr_cmn::access(pkt);
00168     hdr_ip *iph = hdr_ip::access(pkt);
00169     if (!drr)
00170         drr=new PacketDRR[buckets_];
00171     which= hash(pkt) % buckets_;
00172     q=&drr[which];
00173 
00174     /*detect collisions here */
00175     int compare=(!mask_ ? ((int)iph->saddr()) : ((int)iph->saddr()&0xfff0));
00176     if (q->src ==-1)
00177         q->src=compare;
00178     else
00179         if (q->src != compare)
00180             fprintf(stderr,"Collisions between %d and %d src addresses\n",q->src,(int)iph->saddr());      
00181 
00182     q->enque(pkt);
00183     ++q->pkts;
00184     ++pktcnt;
00185     q->bcount += ch->size();
00186     bytecnt +=ch->size();
00187 
00188 
00189     if (q->pkts==1)
00190         {
00191             curr = q->activate(curr);
00192             q->deficitCounter=0;
00193             ++flwcnt;
00194         }
00195     while (bytecnt > blimit_) {
00196         Packet *p;
00197         hdr_cmn *remch;
00198         hdr_ip *remiph;
00199         remq=getMaxflow(curr);
00200         p=remq->deque();
00201         remch=hdr_cmn::access(p);
00202         remiph=hdr_ip::access(p);
00203         remq->bcount -= remch->size();
00204         bytecnt -= remch->size();
00205         drop(p);
00206         --remq->pkts;
00207         --pktcnt;
00208         if (remq->pkts==0) {
00209             curr=remq->idle(curr);
00210             --flwcnt;
00211         }
00212     }
00213 }
00214 
00215 Packet *DRR::deque(void) 
00216 {
00217     hdr_cmn *ch;
00218     hdr_ip *iph;
00219     Packet *pkt=0;
00220     if (bytecnt==0) {
00221         //fprintf (stderr,"No active flow\n");
00222         return(0);
00223     }
00224   
00225     while (!pkt) {
00226         if (!curr->turn) {
00227             curr->deficitCounter+=quantum_;
00228             curr->turn=1;
00229         }
00230 
00231         pkt=curr->lookup(0);  
00232         ch=hdr_cmn::access(pkt);
00233         iph=hdr_ip::access(pkt);
00234         if (curr->deficitCounter >= ch->size()) {
00235             curr->deficitCounter -= ch->size();
00236             pkt=curr->deque();
00237             curr->bcount -= ch->size();
00238             --curr->pkts;
00239             --pktcnt;
00240             bytecnt -= ch->size();
00241             if (curr->pkts == 0) {
00242                 curr->turn=0;
00243                 --flwcnt;
00244                 curr->deficitCounter=0;
00245                 curr=curr->idle(curr);
00246             }
00247             return pkt;
00248         }
00249         else {
00250             curr->turn=0;
00251             curr=curr->next;
00252             pkt=0;
00253         }
00254     }
00255     return 0;    // not reached
00256 }
00257 
00258 void DRR::clear()
00259 {
00260     PacketDRR *q =drr;
00261     int i = buckets_;
00262 
00263     if (!q)
00264         return;
00265     while (i--) {
00266         if (q->pkts) {
00267             fprintf(stderr, "Changing non-empty bucket from drr\n");
00268             exit(1);
00269         }
00270         ++q;
00271     }
00272     delete[](drr);
00273     drr = 0;
00274 }
00275 
00276 /*
00277  *Allows one to change blimit_ and bucket_ for a particular drrQ :
00278  *
00279  *
00280  */
00281 int DRR::command(int argc, const char*const* argv)
00282 {
00283     if (argc==3) {
00284         if (strcmp(argv[1], "blimit") == 0) {
00285             blimit_ = atoi(argv[2]);
00286             if (bytecnt > blimit_)
00287                 {
00288                     fprintf (stderr,"More packets in buffer than the new limit");
00289                     exit (1);
00290                 }
00291             return (TCL_OK);
00292         }
00293         if (strcmp(argv[1], "buckets") == 0) {
00294             clear();
00295             buckets_ = atoi(argv[2]);
00296             return (TCL_OK);
00297         }
00298         if (strcmp(argv[1],"quantum") == 0) {
00299             quantum_ = atoi(argv[2]);
00300             return (TCL_OK);
00301         }
00302         if (strcmp(argv[1],"mask")==0) {
00303             mask_= atoi(argv[2]);
00304             return (TCL_OK);
00305         }
00306     }
00307     return (Queue::command(argc, argv));
00308 }
00309 
00310 int DRR::hash(Packet* pkt)
00311 {
00312     hdr_ip *iph=hdr_ip::access(pkt);
00313     int i;
00314     if (mask_)
00315         i = (int)iph->saddr() & (0xfff0);
00316     else
00317         i = (int)iph->saddr();
00318     return ((i + (i >> 8) + ~(i>>4)) % ((2<<23)-1))+1; // modulo a large prime
00319 }

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