/*
* Copyright (c) 2001 University of Southern 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 Information Sciences
* Institute of the University of Southern California.
* 4. Neither the name of the University nor of the Institute 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.
*
*/
#include <stdlib.h>
#include <math.h>
#ifdef WIN32
#include <windows.h>
#endif
#include "netview.h"
#include "node.h"
#include "edge.h"
#include "paint.h"
#include "sincos.h"
#include "queuehandle.h"
#define PROPERTY_STRING_LENGTH 256
static int g_queuehandle_number = 1;
//----------------------------------------------------------------------
// Wrapper for creating QueueHandles in OTcl
//----------------------------------------------------------------------
static class QueueHandleClass : public TclClass {
public:
QueueHandleClass() : TclClass("QueueHandle") {}
TclObject* create(int argc, const char * const * argv) {
const char * type;
int id;
double size;
type = argv[4];
id = strtol(argv[5], NULL, 10);
size = strtod(argv[6], NULL);
return (new QueueHandle(type, id, size));
}
} class_queuehandle;
//----------------------------------------------------------------------
//----------------------------------------------------------------------
QueueHandle::QueueHandle(const char* type, int id, double _size) :
Animation(0, 0) {
setDefaults();
number_ = id;
if (g_queuehandle_number++ <= id) {
g_queuehandle_number = id + 1;
}
width_ = 50.0;
height_ = size_/2.0;
size_ = _size;
size(_size);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
QueueHandle::QueueHandle(Edge * edge) :
Animation(0, 0) {
Node * node;
setDefaults();
edge_ = edge;
number_ = g_queuehandle_number;
g_queuehandle_number++;
node = edge_->getSourceNode();
if (node) {
size(node->size());
} else {
size(10.0);
}
limit_ = 20;
// FQ
secsPerByte_ = 0.0;
// Stocastic Fair Queue
maxqueue_ = 40;
buckets_ = 16;
// DRR
blimit_ = 2500;
quantum_ = 250;
mask_ = false;
// RED
bytes_ = false;
queue_in_bytes_ = false;
thresh_ = 5.0;
maxthresh_ = 15.0;
mean_pktsize_ = 500;
q_weight_ = 0.002;
wait_ = false;
linterm_ = 30.0;
setbit_ = false;
drop_tail_ = false;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void
QueueHandle::setDefaults() {
next_queue_handle_ = NULL;
edge_ = NULL;
x_ = 0.0;
y_ = 0.0;
angle_ = NO_ANGLE;
color_ = "black";
paint_ = Paint::instance()->thin();
width_ = 10.0;
height_ = 10.0;
type_ = NULL;
ns_type_ = NULL;
setType("DropTail");
}
//----------------------------------------------------------------------
// double
// QueueHandle::distance(double x, double y) const {
//----------------------------------------------------------------------
double
QueueHandle::distance(double x, double y) const {
return sqrt((x_-x)*(x_-x) + (y_-y)*(y_-y));
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void
QueueHandle::color(const char * name) {
if (color_) {
delete []color_;
}
color_ = new char[strlen(name) + 1];
strcpy(color_, name);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void QueueHandle::size(double s) {
size_ = s;
width_ = 10.0 + 25.0;
height_ = s/2.0;
update_bb();
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void QueueHandle::update_bb() {
bb_.xmin = x_;
bb_.ymin = y_;
bb_.xmax = x_ + width_;
bb_.ymax = y_ + height_;
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void QueueHandle::setType(const char* type) {
const char * expanded_type;
// Expand Ns Type Names
if (!strcmp(type, "FQ")) {
expanded_type = "FairQueue";
} else if (!strcmp(type, "SFQ")) {
expanded_type = "StocasticFairQueue";
} else if (!strcmp(type, "DRR")) {
expanded_type = "DeficitRoundRobin";
} else {
expanded_type = type;
}
// Deleted existing type strings
if (type_) {
delete[] type_;
}
if (ns_type_) {
delete[] ns_type_;
ns_type_ = NULL;
}
// Set type and ns type to new strings
type_ = new char[strlen(expanded_type) + 1];
strcpy(type_, expanded_type);
if (!strcmp(expanded_type, "DropTail")) {
ns_type_ = new char[strlen("DropTail") + 1];
strcpy(ns_type_, "DropTail");
} else if (!strcmp(expanded_type, "FairQueue")) {
ns_type_ = new char[strlen("FQ") + 1];
strcpy(ns_type_, "FQ");
} else if (!strcmp(expanded_type, "StocasticFairQueue")) {
ns_type_ = new char[strlen("SFQ") + 1];
strcpy(ns_type_, "SFQ");
} else if (!strcmp(expanded_type, "DeficitRoundRobin")) {
ns_type_ = new char[strlen("DRR") + 1];
strcpy(ns_type_, "DRR");
} else if (!strcmp(expanded_type, "RED")) {
ns_type_ = new char[strlen("RED") + 1];
strcpy(ns_type_, "RED");
}
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void QueueHandle::reset(double) {
paint_ = Paint::instance()->thick();
}
//----------------------------------------------------------------------
// void
// QueueHandle::attach(Agent * agent)
//----------------------------------------------------------------------
void
QueueHandle::attachTo(Edge * edge) {
edge_ = edge;
place();
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
void QueueHandle::clearEdge() {
edge_ = NULL;
}
//----------------------------------------------------------------------
// void
// QueueHandle::place()
//----------------------------------------------------------------------
void
QueueHandle::place() {
double sine, cosine, angle;
if (edge_) {
angle = edge_->angle();
sine = sin(angle);
cosine = cos(angle);
if ((angle > 0.0 && angle < M_PI/2.0) ||
(angle < M_PI/-2.0 && angle > -1.0*M_PI)) {
x_ = edge_->x() + cosine * height_;
y_ = edge_->y() + sine * height_ - height_;
} else {
x_ = edge_->x() + cosine * height_;
y_ = edge_->y() + sine * height_;
}
}
update_bb();
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
const char* QueueHandle::info() const {
static char text[128];
sprintf(text, "Queue Type: %s %d->%d", type_, edge_->src(), edge_->dst());
return (text);
}
//----------------------------------------------------------------------
// int
// QueueHandle::inside(double, float px, float py) const
// - Check to see if point (px, py) is within the Loss Model box
//----------------------------------------------------------------------
int
QueueHandle::inside(double, float px, float py) const {
return (px >= x_ &&
px <= (x_ + width_) &&
py >= y_ &&
py <= (y_ + height_));
}
//----------------------------------------------------------------------
// void
// QueueHandle::draw(View * view, double ) const
// - Draw the Loss Model on its edge
//----------------------------------------------------------------------
void
QueueHandle::draw(View * view, double time) {
double label_width, label_height, label_x, label_y;
char * label = "Q";
if (edge_) {
// Draw label centered inside of border
// We have to keep calculting the label width and height because
// we have no way of knowing if the user has zoomed in or out
// on the current network view.
label_height = 0.9 * height_;
label_width = view->getStringWidth(label, label_height);
// Add 10% of padding to width for the box
setWidth(1.1 * label_width);
// Center label in box
label_x = x_ + (width_ - label_width);
label_y = y_ + (height_ - label_height);
view->string(label, label_x , label_y, label_height, NULL);
update_bb();
// Draw Rectangle Border
view->rect(x_, y_, x_ + width_, y_ + height_ , paint_);
}
}
//----------------------------------------------------------------------
// int
// QueueHandle::writeNsScript(FILE * file)
// - outputs ns script format for creating loss models
//----------------------------------------------------------------------
int
QueueHandle::writeNsScript(FILE * file) {
if (edge_) {
fprintf(file, "# Set Queue Properties for link %d->%d\n", edge_->src(), edge_->dst());
if (!strcmp(type_, "DropTail")) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set limit_ %d\n", edge_->src(), edge_->dst(), limit_);
} else if (!strcmp(type_, "FairQueue")) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set secsPerByte_ %f\n", edge_->src(), edge_->dst(), secsPerByte_);
} else if (!strcmp(type_, "StocasticFairQueue")) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set maxqueue_ %d\n", edge_->src(), edge_->dst(), maxqueue_);
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set buckets_ %d\n", edge_->src(), edge_->dst(), buckets_);
} else if (!strcmp(type_, "DeficitRoundRobin")) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set buckets_ %d\n", edge_->src(), edge_->dst(), buckets_);
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set blimit_ %d\n", edge_->src(), edge_->dst(), blimit_);
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set quantum_ %d\n", edge_->src(), edge_->dst(), quantum_);
if (mask_) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set mask_ 1\n", edge_->src(), edge_->dst());
}
} else if (!strcmp(type_, "RED")) {
if (bytes_) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set bytes_ 1\n", edge_->src(), edge_->dst());
}
if (queue_in_bytes_) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set queue_in_bytes_ 1\n", edge_->src(), edge_->dst());
}
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set thresh_ %f\n", edge_->src(), edge_->dst(), thresh_);
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set maxthresh_ %f\n", edge_->src(), edge_->dst(), maxthresh_);
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set mean_pktsize_ %d\n", edge_->src(), edge_->dst(), mean_pktsize_);
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set q_weight_ %f\n", edge_->src(), edge_->dst(), q_weight_);
if (wait_) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set queue_in_bytes_ 1\n", edge_->src(), edge_->dst());
}
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set linterm_ %f\n", edge_->src(), edge_->dst(), linterm_);
if (setbit_) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set setbit_ 1\n", edge_->src(), edge_->dst());
}
if (queue_in_bytes_) {
fprintf(file, "[[$ns link $node(%d) $node(%d)] queue] set drop_tail_ 1\n", edge_->src(), edge_->dst());
}
}
}
return 0;
}
//----------------------------------------------------------------------
// QueueHandle::property()
// - return the list of queue configuration parameters
// (properties) to be shown in the property edit window
//----------------------------------------------------------------------
const char*
QueueHandle::property() {
return getProperties(type_);
}
//----------------------------------------------------------------------
// QueueHandle::property()
// - return the list of queue configuration parameters
// (properties) to be shown in the property edit window
// - This is used if the queue type is changed to a different type
// so we can give the properties related to that specific type of
// queue to which we have switched
//----------------------------------------------------------------------
const char *
QueueHandle::getProperties(char * type) {
static char text[PROPERTY_STRING_LENGTH];
char * property_list;
int total_written = 0;
// object type, id and header info
property_list = text;
total_written = sprintf(text,
"{\"Queue: %s %d->%d\" title title \"QueueHandle %d-%d\"} ",
type_, edge_->src(), edge_->dst(), edge_->src(), edge_->dst());
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Queue Type\" type_ drop_down_list {{%s} {DropTail FairQueue StocasticFairQueue DeficitRoundRobin RED}}} ", type);
if (strcmp(type, "DropTail") == 0) {
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Maximum Queue Size\" limit_ text %d} ",
limit_);
} else if (strcmp(type, "FairQueue") == 0) {
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Seconds Per Byte\" secsPerByte_ text %f} ",
secsPerByte_);
} else if (strcmp(type, "StocasticFairQueue") == 0) {
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Maximum Queue Size\" maxqueue_ text %d} ",
maxqueue_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Number of Buckets\" buckets_ text %d} ",
buckets_);
} else if (strcmp(type, "DeficitRoundRobin") == 0) {
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Number of Buckets\" buckets_ text %d} ",
buckets_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Shared Buffer Size\" blimit_ text %d} ",
blimit_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Flow Quantum\" quantum_ text %d} ",
quantum_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Exclude Port Number from Flow Identification\" mask_ checkbox %d} ",
mask_);
} else if (strcmp(type, "RED") == 0) {
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Enable Byte Mode RED\" bytes_ checkbox %d} ",
bytes_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Queue in Bytes\" queue_in_bytes_ checkbox %d} ",
queue_in_bytes_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Wait Interval Between Drops\" wait_ checkbox %d} ",
wait_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Mark Packets for Congestion Instead of Dropping\" setbit_ checkbox %d} ",
setbit_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Use Drop Tail instead of Random Drop\" drop_tail_ checkbox %d} ",
drop_tail_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Minimum Threshhold for Average Queue Size\" thresh_ text %g} ",
thresh_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Maximum Threshhold for Average Queue Size\" maxthresh_ text %g} ",
maxthresh_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Estimate for Average Queue Size\" mean_pktsize_ text %d} ",
mean_pktsize_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Queue Weight\" q_weight_ text %g} ",
q_weight_);
property_list = &text[strlen(text)];
sprintf(property_list, "{\"Maximum Drop Probability (1/linterm_)\" linterm_ text %g} ",
linterm_);
}
return(text);
}
//----------------------------------------------------------------------
//----------------------------------------------------------------------
int QueueHandle::command(int argc, const char * const * argv) {
return TCL_OK;
}
syntax highlighted by Code2HTML, v. 0.9.1