/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1997 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the MASH Research
* Group at the University of California Berkeley.
* 4. Neither the name of the University nor of the Research Group may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* 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
* SUCH DAMAGE.
*
* This file contributed by Curtis Villamizar < curtis@ans.net >, Feb 1997.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/queue/sfq.cc,v 1.11 2002/05/06 22:23:16 difa Exp $ (ANS)";
#endif
#include <stdlib.h>
#include "config.h"
#include "queue.h"
class PacketSFQ; // one queue
class SFQ; // a set of SFQ queues
class PacketSFQ : public PacketQueue {
PacketSFQ() : pkts(0), prev(0), next(0) {}
friend class SFQ;
protected:
void sfqdebug();
int pkts;
PacketSFQ *prev;
PacketSFQ *next;
inline PacketSFQ * activate(PacketSFQ *head) {
if (head) {
this->prev = head->prev;
this->next = head;
head->prev->next = this;
head->prev = this;
return head;
}
this->prev = this;
this->next = this;
return this;
}
inline PacketSFQ * idle(PacketSFQ *head) {
if (head == this) {
if (this->next == this)
return 0;
this->next->prev = this->prev;
this->prev->next = this->next;
return this->next;
}
return head;
}
};
class SFQ : public Queue {
public:
SFQ();
virtual int command(int argc, const char*const* argv);
Packet *deque(void);
void enque(Packet *pkt);
protected:
int maxqueue_; // max queue size in packets
int buckets_; // number of queues
PacketSFQ *bucket;
void initsfq();
void clear();
int hash(Packet *);
PacketSFQ *active;
int occupied;
int fairshare;
};
static class SFQClass : public TclClass {
public:
SFQClass() : TclClass("Queue/SFQ") {}
TclObject* create(int, const char*const*) {
return (new SFQ);
}
} class_sfq;
SFQ::SFQ()
{
maxqueue_ = 40;
buckets_ = 16;
bucket = 0;
active = 0;
bind("maxqueue_", &maxqueue_);
bind("buckets_", &buckets_);
}
void SFQ::clear()
{
PacketSFQ *q = bucket;
int i = buckets_;
if (!q)
return;
while (i) {
if (q->pkts) {
fprintf(stderr, "SFQ changed while queue occupied\n");
exit(1);
}
++q;
}
delete[](bucket);
bucket = 0;
}
void SFQ::initsfq()
{
bucket = new PacketSFQ[buckets_];
active = 0;
occupied = 0;
fairshare = maxqueue_ / buckets_;
// fprintf(stderr, "SFQ initsfq: %d %d\n", maxqueue_, buckets_);
}
/*
* This implements the following tcl commands:
* $sfq limit $size
* $sfq buckets $num
*/
int SFQ::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "limit") == 0) {
maxqueue_ = atoi(argv[2]);
fairshare = maxqueue_ / buckets_;
return (TCL_OK);
}
if (strcmp(argv[1], "buckets") == 0) {
clear();
buckets_ = atoi(argv[2]);
return (TCL_OK);
}
}
return (Queue::command(argc, argv));
}
void PacketSFQ::sfqdebug()
{
PacketSFQ *q = this;
fprintf(stderr, "sfq: ");
while (q) {
fprintf(stderr, " 0x%p(%d)", q, q->pkts);
q = q->next;
if (q == this)
break;
}
fprintf(stderr, "\n");
}
Packet* SFQ::deque(void)
{
Packet* pkt;
if (!bucket)
initsfq();
if (!active) {
// fprintf(stderr, " dequeue: empty\n");
return (0);
}
--active->pkts;
--occupied;
pkt = active->deque();
// fprintf(stderr, "dequeue 0x%x(%d): 0x%x\n",
// (int)active, active->pkts, (int)pkt);
// active->sfqdebug();
if (active->pkts == 0)
active = active->idle(active);
else
active = active->next;
return pkt;
}
void SFQ::enque(Packet* pkt)
{
int which;
PacketSFQ *q;
int used, left;
if (!bucket)
initsfq();
which = hash(pkt) % buckets_;
q = &bucket[which];
// log_packet_arrival(pkt);
used = q->pkts;
left = maxqueue_ - occupied;
// note: if maxqueue_ is changed while running left can be < 0
if ((used >= (left >> 1))
|| (left < buckets_ && used > fairshare)
|| (left <= 0)) {
// log_packet_drop(pkt);
drop(pkt);
// fprintf(stderr, " drop: 0x%x\n", (int)pkt);
return;
}
q->enque(pkt);
++occupied;
++q->pkts;
if (q->pkts == 1)
active = q->activate(active);
// fprintf(stderr, " enqueue(%d=%d): 0x%x\n", which, q->pkts, (int)pkt);
// active->sfqdebug();
}
int SFQ::hash(Packet* pkt)
{
hdr_ip* iph = hdr_ip::access(pkt);
int i = (int)iph->saddr();
int j = (int)iph->daddr();
int k = i + j;
return (k + (k >> 8) + ~(k >> 4)) % ((2<<19)-1); // modulo a large prime
}
syntax highlighted by Code2HTML, v. 0.9.1