/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*-
*
* Copyright (c) 1997 The 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 Network Research
* Group at Lawrence Berkeley National Laboratory.
* 4. Neither the name of the University nor of the Laboratory 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tools/flowmon.cc,v 1.26 2005/09/18 23:33:35 tomh Exp $ (LBL)";
#endif
//
// flow-monitor, basically a port from the ns-1 flow manager,
// but architected somewhat differently to better fit the ns-2
// object framework -KF
//
#include "flowmon.h"
void TaggerTSWFlow::tagging(Packet *pkt)
{
double now = Scheduler::instance().clock();;
double p, prob, u;
int count1;
int retVal;
run_rate_estimator(pkt, now);
if (avg_rate_ <= target_rate_) {
prob = 0;
retVal = 0;
}
else {
prob = (avg_rate_ - target_rate_) / avg_rate_;
p = prob;
count1 = count;
if ( p < 0.5) {
if (wait_) {
if (count1 * p < 1)
p = 0;
else if (count1 * p < 2)
p /= (2 - count1 *p);
else
p = 1;
}
else if (!wait_) {
if (count1 * p < 1)
p /= (1 - count1 * p);
else
p = 1;
}
}
u = Random::uniform();
if (u < p) {
retVal = 1;
}
else
retVal = 0;
// if (trace_) {
// sprintf(trace_->buffer(), "Tagged prob %g, p %g, count %d",
// prob, p, count1);
// trace_->dump();
// }
}
if (retVal == 0) {
hdr_flags::access(pkt)->pri_=1; //Tag the packet as In.
total_in = total_in + 1;
++count;
}
else {
total_out = total_out + 1;
count = 0;
}
};
/* ####################################
* Methods for Tagger
* ####################################
*/
void
Tagger::in(Packet *p)
{
Flow* desc;
EDQueueMonitor::in(p);
if ((desc = ((Flow*)classifier_->find(p))) != NULL) {
desc->setfields(p);
desc->tagging(p);
desc->in(p);
}
}
void
Tagger::dumpflows()
{
register int i, j = classifier_->maxslot();
Flow* f;
for (i = 0; i <= j; i++) {
if ((f = (Flow*)classifier_->slot(i)) != NULL)
dumpflow(channel_, f);
}
}
char*
Tagger::flow_list()
{
register const char* z;
register int i, j = classifier_->maxslot();
Flow* f;
register char* p = wrk_;
register char* q;
q = p + sizeof(wrk_) - 2;
*p = '\0';
for (i = 0; i <= j; i++) {
if ((f = (Flow*)classifier_->slot(i)) != NULL) {
z = f->name();
while (*z && p < q)
*p++ = *z++;
*p++ = ' ';
}
if (p >= q) {
fprintf(stderr, "Tagger:: flow list exceeded working buffer\n");
fprintf(stderr, "\t recompile ns with larger Tagger::wrk_[] array\n");
exit (1);
}
}
if (p != wrk_)
*--p = '\0';
return (wrk_);
}
void
Tagger::fformat(Flow* f)
{
double now = Scheduler::instance().clock();
sprintf(wrk_, "%8.3f %d %d %d %d %d %d "
STRTOI64_FMTSTR" "STRTOI64_FMTSTR" %d %d "
STRTOI64_FMTSTR" "STRTOI64_FMTSTR" %d %d %d %d %d %d %d",
now, // 1: time
f->flowid(), // 2: flowid
0, // 3: category
f->ptype(), // 4: type (from common header)
f->flowid(), // 5: flowid (formerly class)
f->src(), // 6: sender
f->dst(), // 7: receiver
f->parrivals(), // 8: arrivals this flow (pkts)
f->barrivals(), // 9: arrivals this flow (bytes)
f->epdrops(), // 10: early drops this flow (pkts)
f->ebdrops(), // 11: early drops this flow (bytes)
parrivals(), // 12: all arrivals (pkts)
barrivals(), // 13: all arrivals (bytes)
epdrops(), // 14: total early drops (pkts)
ebdrops(), // 15: total early drops (bytes)
pdrops(), // 16: total drops (pkts)
bdrops(), // 17: total drops (bytes)
f->pdrops(), // 18: drops this flow (pkts) [includes edrops]
f->bdrops(), // 19: drops this flow (bytes) [includes edrops]
pmarks() // 20: marks this flow (pkts)
);
}
void
Tagger::dumpflow(Tcl_Channel tc, Flow* f)
{
fformat(f);
if (tc != 0) {
int n = strlen(wrk_);
wrk_[n++] = '\n';
wrk_[n] = '\0';
(void)Tcl_Write(tc, wrk_, n);
wrk_[n-1] = '\0';
}
}
int
Tagger::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "classifier") == 0) {
if (classifier_)
tcl.resultf("%s", classifier_->name());
else
tcl.resultf("");
return (TCL_OK);
}
if (strcmp(argv[1], "dump") == 0) {
dumpflows();
return (TCL_OK);
}
if (strcmp(argv[1], "flows") == 0) {
tcl.result(flow_list());
return (TCL_OK);
}
} else if (argc == 3) {
if (strcmp(argv[1], "classifier") == 0) {
classifier_ = (Classifier*)
TclObject::lookup(argv[2]);
if (classifier_ == NULL)
return (TCL_ERROR);
return (TCL_OK);
}
if (strcmp(argv[1], "attach") == 0) {
int mode;
const char* id = argv[2];
channel_ = Tcl_GetChannel(tcl.interp(),
(char*) id, &mode);
if (channel_ == NULL) {
tcl.resultf("Tagger (%s): can't attach %s for writing",
name(), id);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (EDQueueMonitor::command(argc, argv));
}
/* ####################################
* Methods for FlowMon
* ####################################
*/
FlowMon::FlowMon() : classifier_(NULL), channel_(NULL),
enable_in_(1), enable_out_(1), enable_drop_(1), enable_edrop_(1), enable_mon_edrop_(1)
{
bind_bool("enable_in_", &enable_in_);
bind_bool("enable_out_", &enable_out_);
bind_bool("enable_drop_", &enable_drop_);
bind_bool("enable_edrop_", &enable_edrop_);
}
void
FlowMon::in(Packet *p)
{
Flow* desc;
EDQueueMonitor::in(p);
if (!enable_in_)
return;
if ((desc = ((Flow *)classifier_->find(p))) != NULL) {
desc->setfields(p);
desc->in(p);
}
}
void
FlowMon::out(Packet *p)
{
Flow* desc;
EDQueueMonitor::out(p);
if (!enable_out_)
return;
if ((desc = ((Flow*)classifier_->find(p))) != NULL) {
desc->setfields(p);
desc->out(p);
}
}
void
FlowMon::drop(Packet *p)
{
Flow* desc;
EDQueueMonitor::drop(p);
if (!enable_drop_)
return;
if ((desc = ((Flow*)classifier_->find(p))) != NULL) {
desc->setfields(p);
desc->drop(p);
}
}
void
FlowMon::edrop(Packet *p)
{
Flow* desc;
EDQueueMonitor::edrop(p);
if (!enable_edrop_)
return;
if ((desc = ((Flow*)classifier_->find(p))) != NULL) {
desc->setfields(p);
desc->edrop(p);
}
}
//added for monitored early drops - ratul
void
FlowMon::mon_edrop(Packet *p)
{
Flow* desc;
EDQueueMonitor::mon_edrop(p);
if (!enable_mon_edrop_)
return;
if ((desc = ((Flow*)classifier_->find(p))) != NULL) {
desc->setfields(p);
desc->mon_edrop(p);
}
}
void
FlowMon::dumpflows()
{
register int i, j = classifier_->maxslot();
Flow* f;
for (i = 0; i <= j; i++) {
if ((f = (Flow*)classifier_->slot(i)) != NULL)
dumpflow(channel_, f);
}
}
char*
FlowMon::flow_list()
{
register const char* z;
register int i, j = classifier_->maxslot();
Flow* f;
register char* p = wrk_;
register char* q;
q = p + sizeof(wrk_) - 2;
*p = '\0';
for (i = 0; i <= j; i++) {
if ((f = (Flow*)classifier_->slot(i)) != NULL) {
z = f->name();
while (*z && p < q) {
*p++ = *z++;
}
*p++ = ' ';
}
if (p >= q) {
fprintf(stderr, "FlowMon:: flow list exceeded working buffer\n");
fprintf(stderr, "\t recompile ns with larger FlowMon::wrk_[] array\n");
exit (1);
}
}
if (p != wrk_)
*--p = '\0';
return (wrk_);
}
void
FlowMon::fformat(Flow* f)
{
double now = Scheduler::instance().clock();
#if defined(HAVE_INT64)
sprintf(wrk_, "%8.3f %d %d %d %d %d %d " STRTOI64_FMTSTR " " STRTOI64_FMTSTR " %d %d " STRTOI64_FMTSTR " " STRTOI64_FMTSTR " %d %d %d %d %d %d %d %d %d",
#else /* no 64-bit int */
sprintf(wrk_, "%8.3f %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
#endif
now, // 1: time
f->flowid(), // 2: flowid
0, // 3: category
f->ptype(), // 4: type (from common header)
f->flowid(), // 5: flowid (formerly class)
f->src(), // 6: sender
f->dst(), // 7: receiver
f->parrivals(), // 8: arrivals this flow (pkts)
f->barrivals(), // 9: arrivals this flow (bytes)
f->epdrops(), // 10: early drops this flow (pkts)
f->ebdrops(), // 11: early drops this flow (bytes)
parrivals(), // 12: all arrivals (pkts)
barrivals(), // 13: all arrivals (bytes)
epdrops(), // 14: total early drops (pkts)
ebdrops(), // 15: total early drops (bytes)
pdrops(), // 16: total drops (pkts)
bdrops(), // 17: total drops (bytes)
f->pdrops(), // 18: drops this flow (pkts) [includes edrops]
f->bdrops(), // 19: drops this flow (bytes) [includes edrops]
f->qs_pkts(), // 20: Quick-Start packets this flow
f->qs_bytes(), // 21: Quick-Start bytes this flow
f->qs_drops() // 22: dropped Quick-Start pkts this flow
);
};
void
FlowMon::dumpflow(Tcl_Channel tc, Flow* f)
{
fformat(f);
if (tc != 0) {
int n = strlen(wrk_);
wrk_[n++] = '\n';
wrk_[n] = '\0';
(void)Tcl_Write(tc, wrk_, n);
wrk_[n-1] = '\0';
}
}
int
FlowMon::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "classifier") == 0) {
if (classifier_)
tcl.resultf("%s", classifier_->name());
else
tcl.resultf("");
return (TCL_OK);
}
if (strcmp(argv[1], "dump") == 0) {
dumpflows();
return (TCL_OK);
}
if (strcmp(argv[1], "flows") == 0) {
// printf("command says gimme flow list\n");
tcl.result(flow_list());
return (TCL_OK);
}
} else if (argc == 3) {
if (strcmp(argv[1], "classifier") == 0) {
classifier_ = (Classifier*)
TclObject::lookup(argv[2]);
if (classifier_ == NULL)
return (TCL_ERROR);
return (TCL_OK);
}
if (strcmp(argv[1], "attach") == 0) {
int mode;
const char* id = argv[2];
channel_ = Tcl_GetChannel(tcl.interp(),
(char*) id, &mode);
if (channel_ == NULL) {
tcl.resultf("FlowMon (%s): can't attach %s for writing",
name(), id);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (EDQueueMonitor::command(argc, argv));
}
/*#####################################
* Tcl Stuff
*#####################################
*/
static class FlowMonitorClass : public TclClass {
public:
FlowMonitorClass() : TclClass("QueueMonitor/ED/Flowmon") {}
TclObject* create(int, const char*const*) {
return (new FlowMon);
}
} flow_monitor_class;
static class FlowClass : public TclClass {
public:
FlowClass() : TclClass("QueueMonitor/ED/Flow") {}
TclObject* create(int, const char*const*) {
return (new Flow);
}
} flow_class;
/* Added by Yun Wang */
static class TaggerTBFlowClass : public TclClass {
public:
TaggerTBFlowClass() : TclClass("QueueMonitor/ED/Flow/TB") {}
TclObject* create(int, const char*const*) {
return (new TaggerTBFlow);
}
} flow_tb_class;
/* Added by Yun Wang */
static class TaggerTSWFlowClass : public TclClass {
public:
TaggerTSWFlowClass() : TclClass("QueueMonitor/ED/Flow/TSW") {}
TclObject* create(int, const char*const*) {
return (new TaggerTSWFlow);
}
} flow_tsw_class;
/* Added by Yun Wang */
static class TaggerClass : public TclClass {
public:
TaggerClass() : TclClass("QueueMonitor/ED/Tagger") {}
TclObject* create(int, const char*const*) {
return (new Tagger);
}
} tagger_class;
syntax highlighted by Code2HTML, v. 0.9.1