Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

sfq.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) 1997 Regents of the University of California.
00004  * All rights reserved.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the MASH Research
00017  *      Group at the University of California Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be
00019  *    used to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  * 
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * This file contributed by Curtis Villamizar < curtis@ans.net >, Feb 1997.
00035  */
00036 
00037 #ifndef lint
00038 static const char rcsid[] =
00039 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/sfq.cc,v 1.11 2002/05/06 22:23:16 difa Exp $ (ANS)";
00040 #endif
00041 
00042 #include <stdlib.h>
00043 
00044 #include "config.h"
00045 #include "queue.h"
00046 
00047 class PacketSFQ;                // one queue
00048 class SFQ;                      // a set of SFQ queues
00049 
00050 class PacketSFQ : public PacketQueue {
00051   PacketSFQ() : pkts(0), prev(0), next(0) {}
00052   friend class SFQ;
00053 protected:
00054   void sfqdebug();
00055   int pkts;
00056   PacketSFQ *prev;
00057   PacketSFQ *next;
00058   inline PacketSFQ * activate(PacketSFQ *head) {
00059     if (head) {
00060       this->prev = head->prev;
00061       this->next = head;
00062       head->prev->next = this;
00063       head->prev = this;
00064       return head;
00065     }
00066     this->prev = this;
00067     this->next = this;
00068     return this;
00069   }
00070   inline PacketSFQ * idle(PacketSFQ *head) {
00071     if (head == this) {
00072       if (this->next == this)
00073         return 0;
00074       this->next->prev = this->prev;
00075       this->prev->next = this->next;
00076       return this->next;
00077     }
00078     return head;
00079   }
00080 };
00081 
00082 class SFQ : public Queue {
00083 public: 
00084   SFQ();
00085   virtual int command(int argc, const char*const* argv);
00086   Packet *deque(void);
00087   void enque(Packet *pkt);
00088 protected:
00089   int maxqueue_;                // max queue size in packets
00090   int buckets_;                 // number of queues
00091   PacketSFQ *bucket;
00092   void initsfq();
00093   void clear();
00094   int hash(Packet *);
00095   PacketSFQ *active;
00096   int occupied;
00097   int fairshare;
00098 };
00099 
00100 static class SFQClass : public TclClass {
00101 public:
00102   SFQClass() : TclClass("Queue/SFQ") {}
00103   TclObject* create(int, const char*const*) {
00104     return (new SFQ);
00105   }
00106 } class_sfq;
00107 
00108 SFQ::SFQ()
00109 {
00110   maxqueue_ = 40;
00111   buckets_ = 16;
00112   bucket = 0;
00113   active = 0;
00114   bind("maxqueue_", &maxqueue_);
00115   bind("buckets_", &buckets_);
00116 }
00117 
00118 void SFQ::clear()
00119 {
00120   PacketSFQ *q = bucket;
00121   int i = buckets_;
00122 
00123   if (!q)
00124     return;
00125   while (i) {
00126     if (q->pkts) {
00127       fprintf(stderr, "SFQ changed while queue occupied\n");
00128       exit(1);
00129     }
00130     ++q;
00131   }
00132   delete[](bucket);
00133   bucket = 0;
00134 }
00135 
00136 void SFQ::initsfq()
00137 {
00138   bucket = new PacketSFQ[buckets_];
00139   active = 0;
00140   occupied = 0;
00141   fairshare = maxqueue_ / buckets_;
00142   // fprintf(stderr, "SFQ initsfq: %d %d\n", maxqueue_, buckets_);
00143 }
00144 
00145 /*
00146  * This implements the following tcl commands:
00147  *  $sfq limit $size
00148  *  $sfq buckets $num
00149  */
00150 int SFQ::command(int argc, const char*const* argv)
00151 {
00152   if (argc == 3) {
00153     if (strcmp(argv[1], "limit") == 0) {
00154       maxqueue_ = atoi(argv[2]);
00155       fairshare = maxqueue_ / buckets_;
00156       return (TCL_OK);
00157     }
00158     if (strcmp(argv[1], "buckets") == 0) {
00159       clear();
00160       buckets_ = atoi(argv[2]);
00161       return (TCL_OK);
00162     }
00163   }
00164   return (Queue::command(argc, argv));
00165 }
00166 
00167 void PacketSFQ::sfqdebug()
00168 {
00169   PacketSFQ *q = this;
00170   fprintf(stderr, "sfq: ");
00171   while (q) {
00172     fprintf(stderr, " 0x%p(%d)", q, q->pkts);
00173     q = q->next;
00174     if (q == this)
00175       break;
00176   }
00177   fprintf(stderr, "\n");
00178 }
00179 
00180 Packet* SFQ::deque(void)
00181 {
00182   Packet* pkt;
00183 
00184   if (!bucket)
00185     initsfq();
00186   if (!active) {
00187     // fprintf(stderr, "    dequeue: empty\n");
00188     return (0);
00189   }
00190   --active->pkts;
00191   --occupied;
00192   pkt = active->deque();
00193   // fprintf(stderr, "dequeue 0x%x(%d): 0x%x\n",
00194   //      (int)active, active->pkts, (int)pkt);
00195   // active->sfqdebug();
00196   if (active->pkts == 0)
00197     active = active->idle(active);
00198   else
00199     active = active->next;
00200   return pkt;
00201 }
00202 
00203 void SFQ::enque(Packet* pkt)
00204 {
00205   int which;
00206   PacketSFQ *q;
00207   int used, left;
00208 
00209   if (!bucket)
00210     initsfq();
00211   which = hash(pkt) % buckets_;
00212   q = &bucket[which];
00213   // log_packet_arrival(pkt);
00214   used = q->pkts;
00215   left = maxqueue_ - occupied;
00216   // note: if maxqueue_ is changed while running left can be < 0
00217   if ((used >= (left >> 1))
00218       || (left < buckets_ && used > fairshare)
00219       || (left <= 0)) {
00220     // log_packet_drop(pkt);
00221     drop(pkt);
00222     // fprintf(stderr, "    drop: 0x%x\n", (int)pkt);
00223     return;
00224   }
00225   q->enque(pkt);
00226   ++occupied;
00227   ++q->pkts;
00228   if (q->pkts == 1)
00229     active = q->activate(active);
00230   // fprintf(stderr, "    enqueue(%d=%d): 0x%x\n", which, q->pkts, (int)pkt);
00231   // active->sfqdebug();
00232 }
00233 
00234 int SFQ::hash(Packet* pkt)
00235 {
00236   hdr_ip* iph = hdr_ip::access(pkt);
00237   int i = (int)iph->saddr();
00238   int j = (int)iph->daddr();
00239   int k = i + j;
00240 
00241   return (k + (k >> 8) + ~(k >> 4)) % ((2<<19)-1); // modulo a large prime
00242 }

Generated on Tue Apr 20 12:14:32 2004 for NS2.26SourcesOriginal by doxygen 1.3.3