win32.c
/*
* Copyright (c) 1996 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.
*
* This module contributed by John Brezak .
* January 31, 1996
*
* @(#) $Header$ (LBL)
*/
#ifdef WIN32
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "config.h"
#include
/* forward declarations */
int WinGetUserName(ClientData, Tcl_Interp*, int ac, char**av);
int WinGetHostName(ClientData, Tcl_Interp*, int ac, char**av);
int WinPutRegistry(ClientData, Tcl_Interp*, int ac, char**av);
int WinGetRegistry(ClientData, Tcl_Interp*, int ac, char**av);
void TkConsoleCreate();
int TkConsoleInit(Tcl_Interp* interp);
int
uname(struct utsname *ub)
{
char *ptr;
DWORD version;
SYSTEM_INFO sysinfo;
char hostname[4096];
version = GetVersion();
GetSystemInfo(&sysinfo);
switch (sysinfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_INTEL:
(void)strcpy(ub->machine, "ix86");
break;
case PROCESSOR_ARCHITECTURE_MIPS :
(void)strcpy(ub->machine, "mips");
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
(void)strcpy(ub->machine, "alpha");
break;
case PROCESSOR_ARCHITECTURE_PPC:
(void)strcpy(ub->machine, "ppc");
break;
default:
(void)strcpy(ub->machine, "unknown");
break;
}
if (version < 0x80000000) {
(void)strcpy(ub->version, "NT");
}
else if (LOBYTE(LOWORD(version))<4) {
(void)strcpy(ub->version, "Win32s");
}
else /* Win95 */ {
(void)strcpy(ub->version, "Win95");
}
(void)sprintf(ub->release, "%u.%u",
(DWORD)(LOBYTE(LOWORD(version))),
(DWORD)(HIBYTE(LOWORD(version))));
(void)strcpy(ub->sysname, "Windows");
if (gethostname(hostname, sizeof(hostname)) == 0) {
if (ptr = strchr(hostname, '.'))
*ptr = '\0';
}
else {
perror("uname: gethostname failed");
strcpy(hostname, "FAILURE");
}
strncpy(ub->nodename, hostname, sizeof(ub->nodename));
ub->nodename[_SYS_NMLN - 1] = '\0';
return 0;
}
int strcasecmp(const char *s1, const char *s2)
{
return stricmp(s1, s2);
}
uid_t getuid(void)
{
return 1;
}
gid_t getgid(void)
{
return 0;
}
int gethostid(void)
{
/*XXX*/
return 0;
}
__inline int nice(int pri)
{
return 0;
}
extern void TkWinXInit(HINSTANCE hInstance);
extern int main(int argc, const char *argv[]);
extern int __argc;
extern char **__argv;
static char argv0[255]; /* Buffer used to hold argv0. */
char *__progname = "mash";
void
ShowMessage(int level, char *msg)
{
MessageBeep(level);
MessageBox(NULL, msg, __progname,
level | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
}
int SetupConsole()
{
/*
* stuff from knowledge base Q105305 (see that for details)
* open a console and do the work around to get the console to work in all
* cases
*/
int hCrt;
FILE *hf=0;
const COORD screenSz = {80, 5000}; /* size of console buffer */
AllocConsole();
hf=0;
hCrt = _open_osfhandle(
(long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
if (hCrt!=-1) hf = _fdopen(hCrt, "w");
if (hf!=0) *stdout = *hf;
if (hCrt==-1 || hf==0 || 0!=setvbuf(stdout, NULL, _IONBF, 0)) {
ShowMessage(MB_ICONINFORMATION,
"unable to mount reroute stdout");
return FALSE;
}
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), screenSz);
hf=0;
hCrt = _open_osfhandle(
(long)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
if (hCrt!=-1) hf = _fdopen(hCrt, "w");
if (hf!=0) *stderr = *hf;
if (hCrt==-1 || hf==0 || 0!=setvbuf(stderr, NULL, _IONBF, 0)) {
ShowMessage(MB_ICONINFORMATION,
"reroute stderr failed in SetupConsole");
return FALSE;
}
hf=0;
hCrt = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
if (hCrt!=-1) hf = _fdopen(hCrt, "r");
if (hf!=0) *stdin = *hf;
if (hCrt==-1 || hf==0 || 0!=setvbuf(stdin, NULL, _IONBF, 0)) {
ShowMessage(MB_ICONINFORMATION,
"reroute stdin failed in SetupConsole");
return FALSE;
}
return TRUE;
}
int APIENTRY
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{
char *p;
WSADATA WSAdata;
int retcode;
setlocale(LC_ALL, "C");
/* XXX
* initialize our socket interface plus the tcl 7.5 socket
* interface (since they redefine some routines we call).
* eventually we should just call the tcl sockets but at
* the moment that's hard to set up since they only support
* tcp in the notifier.
*/
if (WSAStartup(MAKEWORD (1, 1), &WSAdata)) {
perror("Windows Sockets init failed");
abort();
}
/* TclHasSockets(NULL);
TkWinXInit(hInstance); */
/*
* Increase the application queue size from default value of 8.
* At the default value, cross application SendMessage of WM_KILLFOCUS
* will fail because the handler will not be able to do a PostMessage!
* This is only needed for Windows 3.x, since NT dynamically expands
* the queue.
*/
SetMessageQueue(64);
GetModuleFileName(NULL, argv0, 255);
p = argv0;
__progname = strrchr(p, '/');
if (__progname != NULL) {
__progname++;
}
else {
__progname = strrchr(p, '\\');
if (__progname != NULL) {
__progname++;
} else {
__progname = p;
}
}
if (__argc>1) {
SetupConsole();
}
retcode=main(__argc, (const char**)__argv);
if (retcode!=0) {
assert(FALSE); /* don't die without letting user know why */
}
return retcode;
}
#if 0
static char szTemp[4096];
int
printf(const char *fmt, ...)
{
int retval;
va_list ap;
va_start (ap, fmt);
retval = vsprintf(szTemp, fmt, ap);
OutputDebugString(szTemp);
ShowMessage(MB_ICONINFORMATION, szTemp);
va_end (ap);
return(retval);
}
int
fprintf(FILE *f, const char *fmt, ...)
{
int retval;
va_list ap;
va_start (ap, fmt);
if (f == stderr) {
retval = vsprintf(szTemp, fmt, ap);
OutputDebugString(szTemp);
ShowMessage(MB_ICONERROR, szTemp);
va_end (ap);
}
else
retval = vfprintf(f, fmt, ap);
return(retval);
}
void
perror(const char *msg)
{
DWORD cMsgLen;
CHAR *msgBuf;
DWORD dwError = GetLastError();
cMsgLen = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER | 40, NULL,
dwError,
MAKELANGID(0, SUBLANG_ENGLISH_US),
(LPTSTR) &msgBuf, 512,
NULL);
if (!cMsgLen)
fprintf(stderr, "%s%sError code %lu\n",
msg?msg:"", msg?": ":"", dwError);
else {
fprintf(stderr, "%s%s%s\n", msg?msg:"", msg?": ":"", msgBuf);
LocalFree((HLOCAL)msgBuf);
}
}
int
WinPutsCmd(clientData, interp, argc, argv)
ClientData clientData; /* ConsoleInfo pointer. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int i, newline;
char *fileId;
i = 1;
newline = 1;
if ((argc >= 2) && (strcmp(argv[1], "-nonewline") == 0)) {
newline = 0;
i++;
}
if ((i < (argc-3)) || (i >= argc)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ?-nonewline? ?fileId? string\"", (char *) NULL);
return TCL_ERROR;
}
/*
* The code below provides backwards compatibility with an old
* form of the command that is no longer recommended or documented.
*/
if (i == (argc-3)) {
if (strncmp(argv[i+2], "nonewline", strlen(argv[i+2])) != 0) {
Tcl_AppendResult(interp, "bad argument \"", argv[i+2],
"\": should be \"nonewline\"", (char *) NULL);
return TCL_ERROR;
}
newline = 0;
}
if (i == (argc-1)) {
fileId = "stdout";
} else {
fileId = argv[i];
i++;
}
if (strcmp(fileId, "stdout") == 0 || strcmp(fileId, "stderr") == 0) {
char *result;
int level;
if (newline) {
int len = strlen(argv[i]);
result = ckalloc(len+2);
memcpy(result, argv[i], len);
result[len] = '\n';
result[len+1] = 0;
} else {
result = argv[i];
}
if (strcmp(fileId, "stdout") == 0) {
level = MB_ICONINFORMATION;
} else {
level = MB_ICONERROR;
}
OutputDebugString(result);
ShowMessage(level, result);
if (newline)
ckfree(result);
return TCL_OK;
} else {
extern int Tcl_PutsCmd(ClientData clientData, Tcl_Interp *interp,
int argc, char **argv);
return (Tcl_PutsCmd(clientData, interp, argc, argv));
}
}
#endif
int
WinGetUserName(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char *argv[]; /* Argument strings. */
{
char user[256];
int size = sizeof(user);
if (!GetUserName(user, &size)) {
Tcl_AppendResult(interp, "GetUserName failed", NULL);
return TCL_ERROR;
}
Tcl_AppendResult(interp, user, NULL);
return TCL_OK;
}
int WinGetHostName(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char *argv[]; /* Argument strings. */
{
char hostname[MAXGETHOSTSTRUCT];
if (SOCKET_ERROR == gethostname(hostname, MAXGETHOSTSTRUCT)) {
Tcl_AddErrorInfo(interp, "gethostname failed!");
}
Tcl_AppendResult(interp, hostname, NULL);
return TCL_OK;
}
static HKEY
regroot(root)
char *root;
{
if (strcasecmp(root, "HKEY_LOCAL_MACHINE") == 0)
return HKEY_LOCAL_MACHINE;
else if (strcasecmp(root, "HKEY_CURRENT_USER") == 0)
return HKEY_CURRENT_USER;
else if (strcasecmp(root, "HKEY_USERS") == 0)
return HKEY_USERS;
else if (strcasecmp(root, "HKEY_CLASSES_ROOT") == 0)
return HKEY_CLASSES_ROOT;
else
return NULL;
}
int
WinGetRegistry(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
HKEY hKey, hRootKey;
DWORD dwType;
DWORD len, retCode;
CHAR *regRoot, *regPath, *keyValue, *keyData;
int retval = TCL_ERROR;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
"key value\"", (char *) NULL);
return TCL_ERROR;
}
regRoot = argv[1];
keyValue = argv[2];
regPath = strchr(regRoot, '\\');
*regPath++ = '\0';
if ((hRootKey = regroot(regRoot)) == NULL) {
Tcl_AppendResult(interp, "Unknown registry root \"",
regRoot, "\"", NULL);
return (TCL_ERROR);
}
retCode = RegOpenKeyEx(hRootKey, regPath, 0,
KEY_READ, &hKey);
if (retCode == ERROR_SUCCESS) {
retCode = RegQueryValueEx(hKey, keyValue, NULL, &dwType,
NULL, &len);
if (retCode == ERROR_SUCCESS &&
dwType == REG_SZ && len) {
keyData = (CHAR *) ckalloc(len);
retCode = RegQueryValueEx(hKey, keyValue, NULL, NULL,
keyData, &len);
if (retCode == ERROR_SUCCESS) {
Tcl_AppendResult(interp, keyData, NULL);
free(keyData);
retval = TCL_OK;
}
}
RegCloseKey(hKey);
}
if (retval == TCL_ERROR) {
Tcl_AppendResult(interp, "Cannot find registry entry \"", regRoot,
"\\", regPath, "\\", keyValue, "\"", NULL);
}
return (retval);
}
int
WinPutRegistry(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
HKEY hKey, hRootKey;
DWORD retCode;
CHAR *regRoot, *regPath, *keyValue, *keyData;
DWORD new;
int result = TCL_OK;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
"key value data\"", (char *) NULL);
return TCL_ERROR;
}
regRoot = argv[1];
keyValue = argv[2];
keyData = argv[3];
regPath = strchr(regRoot, '\\');
*regPath++ = '\0';
if ((hRootKey = regroot(regRoot)) == NULL) {
Tcl_AppendResult(interp, "Unknown registry root \"",
regRoot, "\"", NULL);
return (TCL_ERROR);
}
retCode = RegCreateKeyEx(hRootKey, regPath, 0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey, &new);
if (retCode == ERROR_SUCCESS) {
retCode = RegSetValueEx(hKey, keyValue, 0, REG_SZ, keyData, strlen(keyData));
if (retCode != ERROR_SUCCESS) {
Tcl_AppendResult(interp, "unable to set key \"", regRoot, "\\",
regPath, "\" with value \"", keyValue, "\"",
(char *) NULL);
result = TCL_ERROR;
}
RegCloseKey(hKey);
}
else {
Tcl_AppendResult(interp, "unable to create key \"", regRoot, "\\",
regPath, "\"", (char *) NULL);
result = TCL_ERROR;
}
return (result);
}
int platformInit(Tcl_Interp* interp)
{
/* tcl.CreateCommand("puts", WinPutsCmd, (ClientData)0); */
Tcl_CreateCommand(interp, "getusername", WinGetUserName,
(ClientData)0, (Tcl_CmdDeleteProc*)0);
Tcl_CreateCommand(interp, "gethostname", WinGetHostName,
(ClientData)0, (Tcl_CmdDeleteProc*)0);
Tcl_CreateCommand(interp, "putregistry", WinPutRegistry,
(ClientData)0, (Tcl_CmdDeleteProc*)0);
Tcl_CreateCommand(interp, "getregistry", WinGetRegistry,
(ClientData)0, (Tcl_CmdDeleteProc*)0);
#ifndef NO_TK
/*
* Initialize the console only if we are running as an interactive
* application.
*/
if (0==strcmp(Tcl_GetVar(interp, "tcl_interactive",
TCL_GLOBAL_ONLY), "1")) {
/*
* Create the console channels and install them as the standard
* channels. All I/O will be discarded until TkConsoleInit is
* called to attach the console to a text widget.
*/
TkConsoleCreate();
if (TkConsoleInit(interp) == TCL_ERROR) {
fprintf(stderr, "error calling TkConsoleInit\n");
}
}
#endif
return TCL_OK;
}
#endif
Decapsulator.cc
#include "Decapsulator.h"
#include "ip.h"
#include "packet.h"
#include "encap.h"
static class DecapsulatorClass : public TclClass {
public:
DecapsulatorClass() : TclClass("Agent/Decapsulator") {}
TclObject* create(int, const char*const*) {
return (new Decapsulator());
}
} class_decapsulator;
int Decapsulator::off_encap_= 0; //static variable, will be set in TCL
Decapsulator::Decapsulator() : Agent(PT_ENCAPSULATED)
{
bind("off_encap_", &off_encap_);
}
Packet* const Decapsulator::decapPacket(Packet* const p)
{
hdr_cmn* ch= (hdr_cmn*)p->access(hdr_cmn::offset_);
if (ch->ptype() == PT_ENCAPSULATED) {
hdr_encap* eh= (hdr_encap*)p->access(off_encap_);
return eh->decap();
}
return 0;
}
void Decapsulator::recv(Packet* p, Handler* h)
{
Packet *decap_p= decapPacket(p);
if (decap_p) {
send(decap_p, h);
Packet::free(p);
return;
}
send(p, h);
}
Encapsulator.cc
#include "packet.h"
#include "ip.h"
#include "Encapsulator.h"
#include "encap.h"
static class EncapsulatorClass : public TclClass {
public:
EncapsulatorClass() : TclClass("Agent/Encapsulator") {}
TclObject* create(int, const char*const*) {
return (new Encapsulator());
}
} class_encapsulator;
Encapsulator::Encapsulator() :
Agent(PT_ENCAPSULATED),
d_target_(0)
{
bind("status_", &status_);
bind("off_encap_", &off_encap_);
bind("overhead_", &overhead_);
}
int Encapsulator::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "decap-target") == 0) {
if (d_target_ != 0) tcl.result(d_target_->name());
return (TCL_OK);
}
}
else if (argc == 3) {
if (strcmp(argv[1], "decap-target") == 0) {
d_target_ = (NsObject*)TclObject::lookup(argv[2]);
// even if it's zero, it's OK, we'll just not send to such
// a target then.
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
void Encapsulator::recv(Packet* p, Handler* h)
{
if (d_target_) {
Packet *copy_p= p->copy();
d_target_->recv(copy_p, h);
}
if (status_) {
Packet* ep= allocpkt(); //sizeof(Packet*));
hdr_encap* eh= (hdr_encap*)ep->access(off_encap_);
eh->encap(p);
//Packet** pp= (Packet**) encap_p->accessdata();
//*pp= p;
hdr_cmn* ch_e= (hdr_cmn*)ep->access(off_cmn_);
hdr_cmn* ch_p= (hdr_cmn*)p->access(off_cmn_);
ch_e->ptype()= PT_ENCAPSULATED;
ch_e->size()= ch_p->size() + overhead_;
ch_e->timestamp()= ch_p->timestamp();
send(ep, h);
}
else send(p, h); //forward the packet as it is
}
ack-recons.cc
/* -*- 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 Daedalus Research
* Group at the University of California at 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.
*
* ack-recons.cc: contributed by the Daedalus Research Group,
* UC Berkeley (http://daedalus.cs.berkeley.edu).
*/
/*
* TCP Ack reconstructor. This object sits on the other end of a constrained
* link and intersperses TCP acks to the source (without violating the e2e
* semantics of TCP acks). This allows us to get good performance for TCP
* over various asymmetric networks, in conjunction with techniques to reduce
* the frequency of acks (such as ack filtering) with making any changes to
* the TCP source (e.g., like those implemented in tcp-asym.cc).
*/
#include "template.h"
#include "ack-recons.h"
static class AckReconsControllerClass : public TclClass {
public:
AckReconsControllerClass() : TclClass("AckReconsControllerClass") { }
TclObject* create(int, const char*const*) {
return (new AckReconsController);
}
} class_ackrecons_controller;
static class AckReconsClass : public TclClass {
public:
AckReconsClass() : TclClass("Agent/AckReconsClass") { }
TclObject* create(int, const char*const* argv) {
return new AckRecons(atoi(argv[4]), atoi(argv[5]));
}
} class_ackrecons;
/*
* Demux a packet to the right ack reconstructor.
*/
void
AckReconsController::recv(Packet *p, Handler *)
{
Tcl& tcl = Tcl::instance();
hdr_ip *ip = (hdr_ip *)p->access(off_ip_);
tcl.evalf("%s demux %d %d", name(),
ip->saddr(), ip->daddr());
AckRecons *ackRecons =
(AckRecons *) TclObject::lookup(tcl.result());
if (ackRecons == NULL) {
printf("Error: malformed ack reconstructor\n");
abort();
}
ackRecons->spq_ = spq_;
ackRecons->recv(p);
}
void
AckRecons::recv(Packet *pkt)
{
double now = Scheduler::instance().clock();
hdr_tcp *tcph = (hdr_tcp *) pkt->access(off_tcp_);
int &ack = tcph->seqno(), a, i;
Tcl& tcl = Tcl::instance();
#ifdef DEBUG
printf("%f\tRecd ack %d\n", now, ack);
#endif
if (ackTemplate_ == 0)
ackTemplate_ = pkt->copy();
if (adaptive_)
tcl.evalf("%s ackbw %d %f\n", name(), ack, now);
/* The ack spacing policy is implemented in Tcl for flexibility */
tcl.evalf("%s spacing %d\n", name(), ack);
/*
* If the difference in acks is less than a threshold, let
* it go through. Later, we will look for rapid ack arrivals
* to smooth them out and avoid the adverse effects of ack comp.
*/
if ((!ackPending_ && ack-lastAck_ <= deltaAckThresh_) || dupacks_) {
if (ack == lastRealAck_)
dupacks_++;
else if (ack > lastAck_) {
dupacks_ = 0;
lastAck_ = ack;
lastTime_ = now;
}
spq_->reconsAcks_ = 0;
spq_->enque(pkt);
spq_->reconsAcks_ = 1;
#ifdef DEBUG
printf("\t%f\tEnqueuing ack %d in order\n", now, ack);
#endif
} else {
if (ack == lastRealAck_)
dupacks_++;
/* Intersperse some acks and schedule their transmissions. */
double starttime = max(now, lastTime_);
for (a = lastAck_+delack_, i=0; a <= ack; a += delack_, i++)
sendack(a, starttime + i*ackSpacing_ - now);
if ((a-ack)%delack_)
sendack(ack, starttime + i*ackSpacing_ - now);
Packet::free(pkt);
}
if (ack >= lastRealAck_) {
lastRealAck_ = ack;
lastRealTime_ = now;
}
}
int
AckRecons::command(int argc, const char*const* argv)
{
return Agent::command(argc, argv);
}
/*
* Arrange to send ack a at time t from now.
*/
void
AckRecons::sendack(int ack, double t)
{
Packet *ackp = ackTemplate_->copy();
Scheduler &s = Scheduler::instance();
hdr_tcp *th = (hdr_tcp *) ackp->access(off_tcp_);
th->seqno() = ack;
/* Set no_ts_ in flags because we don't want an rtt sample for this */
if (th->ts() == ((hdr_tcp *) ackp->access(off_tcp_))->ts()) {
hdr_flags *fh = (hdr_flags *) ackp->access(off_flags_);
fh->no_ts_ = 1;
th->ts_ = s.clock(); /* for debugging purposes only */
}
s.schedule((Handler *)this, (Event *)ackp, t);
ackPending_++;
#ifdef DEBUG
printf("\t%f\tScheduling ack %d to be sent at %f\n",
s.clock(), ack, s.clock() + t);
#endif
}
/*
* Handle scheduling of acks.
*/
void
AckRecons::handle(Event *e)
{
Packet *p = (Packet *) e;
hdr_tcp *th = (hdr_tcp *) p->access(off_tcp_);
ackPending_--;
if (lastAck_ < th->seqno()) {
spq_->reconsAcks_ = 0;
/*
* need to do queue's recv here, so that a deque is
* forced if the queue isn't blocked. It's not
* sufficient to call spq_->recv() alone.
*/
target_->recv(p); /* maybe do acksfirst for this ack? */
spq_->reconsAcks_ = 1;
lastTime_ = Scheduler::instance().clock();
lastAck_ = th->seqno();
#ifdef DEBUG
printf("%f\tSending scheduled ack %d\n",lastTime_,th->seqno());
#endif
} else {
Packet::free(p);
#ifdef DEBUG
printf("%f\tack %d superceded by ack %d at %f\n",
Scheduler::instance().clock(), th->seqno(), lastAck_,
lastTime_);
#endif
}
}
acto-adc.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
//Acceptance region Tangent at Origin Admission Control
#include "adc.h"
#include
#include
class ACTO_ADC : public ADC {
public:
ACTO_ADC();
void teardown_action(int,double,int);
protected:
int admit_flow(int,double,int);
int rejected_;
double s_;
};
ACTO_ADC::ACTO_ADC() : rejected_(0)
{
bind("s_", &s_);
type_ = new char[5];
strcpy(type_, "ACTO");
}
int ACTO_ADC::admit_flow(int cl,double r,int b)
{
double p=peak_rate(cl,r,b);
if (backoff_) {
if (rejected_)
return 0;
}
if (exp(p*s_)*est_[cl]->avload() <= bandwidth_) {
if (dobump_) {
est_[cl]->change_avload(p);
}
return 1;
}
else {
rejected_=1;
return 0;
}
}
void ACTO_ADC::teardown_action(int /*cl*/,double /*r*/,int /*b*/)
{
rejected_=0;
}
static class ACTO_ADCClass : public TclClass {
public :
ACTO_ADCClass() : TclClass("ADC/ACTO") {}
TclObject* create(int,const char*const*) {
return (new ACTO_ADC());
}
}class_acto_adc;
actp-adc.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
//Acceptance region Tangent at Peak Admission Control
#include "adc.h"
#include
#include
class ACTP_ADC : public ADC {
public:
ACTP_ADC();
void teardown_action(int,double,int);
void rej_action(int,double,int);
protected:
int admit_flow(int,double,int);
int rejected_;
double s_;
double sump_;
};
ACTP_ADC::ACTP_ADC() : rejected_(0), sump_(0)
{
bind("s_", &s_);
type_ = new char[5];
strcpy(type_, "ACTP");
}
int ACTP_ADC::admit_flow(int cl,double r,int b)
{
//get peak rate this class of flow
double p=peak_rate(cl,r,b);
if (backoff_) {
if (rejected_)
return 0;
}
//fprintf (stderr,"%f %f %f\n",sump_*(1-exp(-p*s_)),exp(-p*s_)*est_[cl]->avload(),est_[cl]->avload());
if (sump_*(1-exp(-p*s_))+exp(-p*s_)*est_[cl]->avload() <= bandwidth_) {
sump_+= p;
if (dobump_) {
est_[cl]->change_avload(p);
}
return 1;
}
else {
rejected_=1;
return 0;
}
}
void ACTP_ADC::rej_action(int cl,double r,int b)
{
double p=peak_rate(cl,r,b);
sump_ -= p;
}
void ACTP_ADC::teardown_action(int cl,double r,int b)
{
rejected_=0;
double p=peak_rate(cl,r,b);
sump_ -= p;
}
static class ACTP_ADCClass : public TclClass {
public:
ACTP_ADCClass() : TclClass("ADC/ACTP") {}
TclObject* create(int,const char*const*) {
return (new ACTP_ADC());
}
}class_actp_adc;
adaptive-receiver.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "config.h"
#include "agent.h"
#include "tclcl.h"
#include "packet.h"
#include "ip.h"
#include "rtp.h"
#include "adaptive-receiver.h"
#include
#define myabs(r) (r<0)?-r:r
AdaptiveRcvr::AdaptiveRcvr() : Agent(PT_NTYPE)
{
//bind("npkts_",&npkts_);
//bind("ndelay_",&ndelay_);
//bind("nvar_",&nvar_);
bind("off_rtp_",&off_rtp_);
}
void AdaptiveRcvr::recv(Packet *pkt,Handler*)
{
int delay;
int seq_no;
hdr_cmn* ch= (hdr_cmn*)pkt->access(off_cmn_);
//hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_);
hdr_rtp *rh=(hdr_rtp*) pkt->access(off_rtp_);
seq_no= rh->seqno();
register u_int32_t send_time = (int)ch->timestamp();
u_int32_t local_time= (u_int32_t)(Scheduler::instance().clock() * SAMPLERATE);
delay=adapt(pkt,local_time);
Tcl::instance().evalf("%s print-delay-stats %f %f %f",name(),send_time/SAMPLERATE,local_time/SAMPLERATE,(local_time+delay)/SAMPLERATE);
Packet::free(pkt);
}
adc.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "adc.h"
#include
ADC::ADC() :bandwidth_(0), tchan_(0)
{
bind_bw("bandwidth_",&bandwidth_);
bind_bool("backoff_",&backoff_);
bind("src_", &src_);
bind("dst_", &dst_);
bind_bool("dobump_", &dobump_);
}
int ADC::command(int argc,const char*const*argv)
{
Tcl& tcl = Tcl::instance();
if (argc==2) {
if (strcmp(argv[1],"start") ==0) {
/* $adc start */
est_[1]->start();
return (TCL_OK);
}
} else if (argc==4) {
if (strcmp(argv[1],"attach-measmod") == 0) {
/* $adc attach-measmod $meas $cl */
MeasureMod *meas_mod = (MeasureMod *)TclObject::lookup(argv[2]);
if (meas_mod== 0) {
tcl.resultf("no measuremod found");
return(TCL_ERROR);
}
int cl=atoi(argv[3]);
est_[cl]->setmeasmod(meas_mod);
return(TCL_OK);
} else if (strcmp(argv[1],"attach-est") == 0 ) {
/* $adc attach-est $est $cl */
Estimator *est_mod = (Estimator *)TclObject::lookup(argv[2]);
if (est_mod== 0) {
tcl.resultf("no estmod found");
return(TCL_ERROR);
}
int cl=atoi(argv[3]);
setest(cl,est_mod);
return(TCL_OK);
}
}
else if (argc == 3) {
if (strcmp(argv[1], "attach") == 0) {
int mode;
const char* id = argv[2];
tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
if (tchan_ == 0) {
tcl.resultf("ADC: trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "setbuf") == 0) {
/* some sub classes actually do something here */
return(TCL_OK);
}
}
return (NsObject::command(argc,argv));
}
address.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1990-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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*
* $Header$
*/
#include
#include
#include "address.h"
#include "route.h"
static class AddressClass : public TclClass {
public:
AddressClass() : TclClass("Address") {}
TclObject* create(int, const char*const*) {
return (new Address());
}
} class_address;
Address* Address::instance_;
Address::Address() : NodeShift_(NULL), NodeMask_(NULL), McastShift_(0),McastMask_(0), levels_(0)
{ }
Address::~Address()
{
delete [] NodeShift_;
delete [] NodeMask_;
}
int Address::command(int argc, const char*const* argv)
{
int i, c, temp=0;
Tcl& tcl = Tcl::instance();
if ((instance_ == 0) || (instance_ != this))
instance_ = this;
if (argc == 3) {
if (strcmp(argv[1], "str2addr") == 0) {
tcl.resultf("%d", str2addr(argv[2]));
return (TCL_OK);
}
}
if (argc == 4) {
// The following code is no longer supported in the
// 32-bit addressing
// if (strcmp(argv[1], "portbits-are") == 0) {
// PortShift_ = atoi(argv[2]);
// PortMask_ = atoi(argv[3]);
// return (TCL_OK);
// }
if (strcmp(argv[1], "mcastbits-are") == 0) {
McastShift_ = atoi(argv[2]);
McastMask_ = atoi(argv[3]);
return (TCL_OK);
}
}
if (argc >= 4) {
if (strcmp(argv[1], "add-hier") == 0) {
/*
* add-hier
*/
int level = atoi(argv[2]);
int mask = atoi(argv[3]);
int shift = atoi(argv[4]);
if (levels_ < level)
levels_ = level;
NodeShift_[level] = shift;
NodeMask_[level] = mask;
return (TCL_OK);
}
if (strcmp(argv[1], "idsbits-are") == 0) {
temp = (argc - 2)/2;
if (levels_) {
if (temp != levels_) {
tcl.resultf("#idshiftbits don't match with #hier levels\n");
return (TCL_ERROR);
}
}
else
levels_ = temp;
NodeShift_ = new int[levels_ + 1];
for (i = 3, c = 1; c <= levels_; c++, i+=2)
NodeShift_[c] = atoi(argv[i]);
return (TCL_OK);
}
if (strcmp(argv[1], "idmbits-are") == 0) {
temp = (argc - 2)/2;
if (levels_) {
if (temp != levels_) {
tcl.resultf("#idmaskbits don't match with #hier levels\n");
return (TCL_ERROR);
}
}
else
levels_ = temp;
NodeMask_ = new int[levels_ + 1];
for (i = 3, c = 1; c <= levels_; c++, i+=2)
NodeMask_[c] = atoi(argv[i]);
return (TCL_OK);
}
}
return TclObject::command(argc, argv);
}
char *Address::print_nodeaddr(int address)
{
int a;
char temp[SMALL_LEN];
char str[SMALL_LEN];
char *addrstr;
str[0] = '\0';
for (int i=1; i <= levels_; i++) {
a = address >> NodeShift_[i];
if (levels_ > 1)
a = a & NodeMask_[i];
//if (i < levels_)
sprintf(temp, "%d.", a);
//else
//sprintf(temp, "%d", a);
strcat(str, temp);
}
int len;
addrstr = new char[len= strlen(str)];
str[len-1]= 0; //kill the last dot
strcpy(addrstr, str);
// printf("Nodeaddr - %s\n",addrstr);
return(addrstr);
}
char *Address::get_subnetaddr(int address)
{
int a;
char temp[SMALL_LEN];
char str[SMALL_LEN];
char *addrstr;
if (levels_ > 1) {
str[0] = '\0';
for (int i=1; i < levels_; i++) {
a = address >> NodeShift_[i];
a = a & NodeMask_[i];
if (i < (levels_-1))
sprintf(temp, "%d.", a);
else
sprintf(temp, "%d", a);
strcat(str, temp);
}
addrstr = new char[strlen(str)+1];
strcpy(addrstr, str);
//printf("Subnet_addr - %s\n",addrstr);
return(addrstr);
}
return NULL;
}
// returns nodeaddr in integer form (relevant especially for hier-addr)
int Address::get_nodeaddr(int address)
{
int a;
char *temp;
temp = print_nodeaddr(address);
a = str2addr(temp);
delete [] temp;
return a;
}
//Sets address in pkthdr format (having port and node fields)
int Address::create_ipaddr(int nodeid, int portid)
{
return nodeid;
// The following code is obsolete
#if 0
int address;
if (levels_ < 2)
address = (nodeid & NodeMask_[1]) << NodeShift_[1];
else
address = nodeid;
address = ((portid & PortMask_) << PortShift_) | \
((~(PortMask_) << PortShift_) & address);
return address;
#endif
}
int Address::get_lastaddr(int address)
{
int a;
a = address >> NodeShift_[levels_];
a = a & NodeMask_[levels_];
return a;
}
char *Address::print_portaddr(int address)
{
char str[SMALL_LEN];
char *addrstr;
str[0] = '\0';
#if 0
int a;
a = address >> PortShift_;
a = a & PortMask_;
#endif
sprintf(str, "%d", address);
addrstr = new char[strlen(str)+1];
strcpy(addrstr, str);
// printf("Portaddr - %s\n",addrstr);
return(addrstr);
}
// Convert address in string format to binary format (int).
int Address::str2addr(const char *str) const
{
if (levels_ < 2)
return atoi(str);
/*
int istr[levels_], addr= 0;
*/
/*
* for VC++
*/
int *istr= new int[levels_];
int addr= 0;
RouteLogic::ns_strtok((char*)str, istr);
for (int i = 0; i < levels_; i++) {
addr = set_word_field(addr, --istr[i],
NodeShift_[i+1], NodeMask_[i+1]);
}
delete [] istr;
return addr;
}
agent.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1990-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 Computer Systems
* Engineering Group at Lawrence Berkeley 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$ (LBL)";
#endif
#include
#include
#include "config.h"
#include "agent.h"
#include "ip.h"
#include "flags.h"
#include "address.h"
#include "app.h"
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
static class AgentClass : public TclClass {
public:
AgentClass() : TclClass("Agent") {}
TclObject* create(int, const char*const*) {
return (new Agent(PT_NTYPE));
}
} class_agent;
int Agent::uidcnt_; /* running unique id */
Agent::Agent(packet_t pkttype) :
size_(0), type_(pkttype),
channel_(0), traceName_(NULL),
oldValueList_(NULL), app_(0)
{
off_ip_ = hdr_ip::offset();
}
void
Agent::delay_bind_init_all()
{
delay_bind_init_one("agent_addr_");
delay_bind_init_one("agent_port_");
delay_bind_init_one("dst_addr_");
delay_bind_init_one("dst_port_");
delay_bind_init_one("fid_");
delay_bind_init_one("prio_");
delay_bind_init_one("flags_");
delay_bind_init_one("ttl_");
delay_bind_init_one("class_");
#ifdef OFF_HDR
delay_bind_init_one("off_ip_");
#endif
Connector::delay_bind_init_all();
}
int
Agent::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
{
if (delay_bind(varName, localName, "agent_addr_", (int*)&(here_.addr_), tracer)) return TCL_OK;
if (delay_bind(varName, localName, "agent_port_", (int*)&(here_.port_), tracer)) return TCL_OK;
if (delay_bind(varName, localName, "dst_addr_", (int*)&(dst_.addr_), tracer)) return TCL_OK;
if (delay_bind(varName, localName, "dst_port_", (int*)&(dst_.port_), tracer)) return TCL_OK;
if (delay_bind(varName, localName, "fid_", (int*)&fid_, tracer)) return TCL_OK;
if (delay_bind(varName, localName, "prio_", (int*)&prio_, tracer)) return TCL_OK;
if (delay_bind(varName, localName, "flags_", (int*)&flags_, tracer)) return TCL_OK;
if (delay_bind(varName, localName, "ttl_", &defttl_, tracer)) return TCL_OK;
if (delay_bind(varName, localName, "off_ip_", &off_ip_, tracer)) return TCL_OK;
if (delay_bind(varName, localName, "class_", (int*)&fid_, tracer)) return TCL_OK;
return Connector::delay_bind_dispatch(varName, localName, tracer);
}
Agent::~Agent()
{
if (oldValueList_ != NULL) {
OldValue *p;
while (oldValueList_ != NULL) {
oldValueList_ = oldValueList_->next_;
delete p;
p = oldValueList_;
}
}
}
int Agent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "delete-agent-trace") == 0) {
if ((traceName_ == 0) || (channel_ == 0))
return (TCL_OK);
deleteAgentTrace();
return (TCL_OK);
} else if (strcmp(argv[1], "show-monitor") == 0) {
if ((traceName_ == 0) || (channel_ == 0))
return (TCL_OK);
monitorAgentTrace();
return (TCL_OK);
} else if (strcmp(argv[1], "close") == 0) {
close();
return (TCL_OK);
} else if (strcmp(argv[1], "listen") == 0) {
listen();
return (TCL_OK);
} else if (strcmp(argv[1], "dump-namtracedvars") == 0) {
enum_tracedVars();
return (TCL_OK);
}
}
else if (argc == 3) {
if (strcmp(argv[1], "attach") == 0) {
int mode;
const char* id = argv[2];
channel_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
if (channel_ == 0) {
tcl.resultf("trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
} else if (strcmp(argv[1], "add-agent-trace") == 0) {
// we need to write nam traces and set agent trace name
if (channel_ == 0) {
tcl.resultf("agent %s: no trace file attached", name_);
return (TCL_OK);
}
addAgentTrace(argv[2]);
return (TCL_OK);
} else if (strcmp(argv[1], "connect") == 0) {
connect((nsaddr_t)atoi(argv[2]));
return (TCL_OK);
} else if (strcmp(argv[1], "send") == 0) {
sendmsg(atoi(argv[2]));
return (TCL_OK);
} else if (strcmp(argv[1], "set_pkttype") == 0) {
set_pkttype(packet_t(atoi(argv[2])));
return (TCL_OK);
}
}
else if (argc == 4) {
if (strcmp(argv[1], "sendmsg") == 0) {
sendmsg(atoi(argv[2]), argv[3]);
return (TCL_OK);
}
}
else if (argc == 5) {
if (strcmp(argv[1], "sendto") == 0) {
sendto(atoi(argv[2]), argv[3], (nsaddr_t)atoi(argv[4]));
return (TCL_OK);
}
}
if (strcmp(argv[1], "tracevar") == 0) {
// wrapper of TclObject's trace command, because some tcl
// agents (e.g. srm) uses it.
const char* args[4];
char tmp[6];
strcpy(tmp, "trace");
args[0] = argv[0];
args[1] = tmp;
args[2] = argv[2];
if (argc > 3)
args[3] = argv[3];
return (Connector::command(argc, args));
}
return (Connector::command(argc, argv));
}
void Agent::flushAVar(TracedVar *v)
{
char wrk[256], value[128];
int n;
// XXX we need to keep track of old values. What's the best way?
v->value(value, 128);
if (strcmp(value, "") == 0)
// no value, because no writes has occurred to this var
return;
sprintf(wrk, "f -t %.17f -s %d -d %d -n %s -a %s -o %s -T v -x",
Scheduler::instance().clock(), addr(), dst_.addr_,
v->name(), traceName_, value);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(channel_, wrk, n+1);
}
void Agent::deleteAgentTrace()
{
char wrk[256];
// XXX we don't know InstVar outside of Tcl! Is there any
// tracedvars hidden in InstVar? If so, shall we have a tclclInt.h?
TracedVar* var = tracedvar_;
for ( ; var != 0; var = var->next_)
flushAVar(var);
// we need to flush all var values to trace file,
// so nam can do backtracing
sprintf(wrk, "a -t %.17f -s %d -d %d -n %s -x",
Scheduler::instance().clock(), here_.addr_,
dst_.addr_, traceName_);
if (traceName_ != NULL)
delete[] traceName_;
traceName_ = NULL;
}
OldValue* Agent::lookupOldValue(TracedVar *v)
{
OldValue *p = oldValueList_;
while ((p != NULL) && (p->var_ != v))
p = p->next_;
return p;
}
void Agent::insertOldValue(TracedVar *v, const char *value)
{
OldValue *p = new OldValue;
assert(p != NULL);
strncpy(p->val_, value, min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
p->var_ = v;
p->next_ = NULL;
if (oldValueList_ == NULL)
oldValueList_ = p;
else {
p->next_ = oldValueList_;
oldValueList_ = p;
}
}
// callback from traced variable updates
void Agent::trace(TracedVar* v)
{
if (channel_ == 0)
return;
char wrk[256], value[128];
int n;
// XXX we need to keep track of old values. What's the best way?
v->value(value, 128);
// XXX hack: how do I know ns has not started yet?
// if there's nothing in value, return
static int started = 0;
if (!started) {
Tcl::instance().eval("[Simulator instance] is-started");
if (Tcl::instance().result()[0] == '0')
// Simulator not started, do nothing
return;
// remember for next time (so we don't always have to call to tcl)
started = 1;
};
OldValue *ov = lookupOldValue(v);
if (ov != NULL) {
sprintf(wrk,
"f -t %.17f -s %d -d %d -n %s -a %s -v %s -o %s -T v",
Scheduler::instance().clock(), here_.addr_,
dst_.addr_, v->name(), traceName_, value, ov->val_);
strncpy(ov->val_,
value,
min(strlen(value)+1, TRACEVAR_MAXVALUELENGTH));
} else {
// if there is value, insert it into old value list
sprintf(wrk, "f -t %.17f -s %d -d %d -n %s -a %s -v %s -T v",
Scheduler::instance().clock(), here_.addr_,
dst_.addr_, v->name(), traceName_, value);
insertOldValue(v, value);
}
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(channel_, wrk, n+1);
}
void Agent::monitorAgentTrace()
{
char wrk[256];
int n;
double curTime = (&Scheduler::instance() == NULL ? 0 :
Scheduler::instance().clock());
sprintf(wrk, "v -t %.17f monitor_agent %d %s",
curTime, here_.addr_, traceName_);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
if (channel_)
(void)Tcl_Write(channel_, wrk, n+1);
}
void Agent::addAgentTrace(const char *name)
{
char wrk[256];
int n;
double curTime = (&Scheduler::instance() == NULL ? 0 :
Scheduler::instance().clock());
sprintf(wrk, "a -t %.17f -s %d -d %d -n %s",
curTime, here_.addr_, dst_.addr_, name);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
if (channel_)
(void)Tcl_Write(channel_, wrk, n+1);
// keep agent trace name
if (traceName_ != NULL)
delete[] traceName_;
traceName_ = new char[strlen(name)+1];
strcpy(traceName_, name);
}
void Agent::timeout(int)
{
}
/*
* Callback to application to notify the reception of a number of bytes
*/
void Agent::recvBytes(int nbytes)
{
if (app_)
app_->recv(nbytes);
}
/*
* Callback to application to notify the termination of a connection
*/
void Agent::idle()
{
if (app_)
app_->resume();
}
/*
* Assign application pointer for callback purposes
*/
void Agent::attachApp(Application *app)
{
app_ = app;
}
void Agent::close()
{
}
void Agent::listen()
{
}
/*
* This function is a placeholder in case applications want to dynamically
* connect to agents (presently, must be done at configuration time).
*/
void Agent::connect(nsaddr_t /*dst*/)
{
/*
dst_ = dst;
*/
}
/*
* Place holders for sending application data
*/
void Agent::sendmsg(int /*sz*/, AppData* /*data*/, const char* /*flags*/)
{
fprintf(stderr,
"Agent::sendmsg(int, AppData*, const char*) not implemented\n");
abort();
}
void Agent::sendto(int /*sz*/, AppData* /*data*/, const char* /*flags*/)
{
fprintf(stderr,
"Agent::sendmsg(int, AppData*, const char*) not implemented\n");
abort();
}
void Agent::sendmsg(int /*nbytes*/, const char* /*flags*/)
{
}
/*
* This function is a placeholder in case applications want to dynamically
* connect to agents (presently, must be done at configuration time).
*/
void Agent::sendto(int /*nbytes*/, const char /*flags*/[], nsaddr_t /*dst*/)
{
/*
dst_ = dst;
sendmsg(nbytes, flags);
*/
}
void Agent::recv(Packet* p, Handler*)
{
if (app_)
app_->recv(hdr_cmn::access(p)->size());
/*
* didn't expect packet (or we're a null agent?)
*/
Packet::free(p);
}
/*
* initpkt: fill in all the generic fields of a pkt
*/
void
Agent::initpkt(Packet* p) const
{
hdr_cmn* ch = hdr_cmn::access(p);
ch->uid() = uidcnt_++;
ch->ptype() = type_;
ch->size() = size_;
ch->timestamp() = Scheduler::instance().clock();
ch->iface() = UNKN_IFACE.value(); // from packet.h (agent is local)
ch->direction() = hdr_cmn::NONE;
ch->ref_count() = 0; /* reference count */
ch->error() = 0; /* pkt not corrupt to start with */
hdr_ip* iph = hdr_ip::access(p);
iph->saddr() = here_.addr_;
iph->sport() = here_.port_;
iph->daddr() = dst_.addr_;
iph->dport() = dst_.port_;
//DEBUG
//if (dst_ != -1)
// printf("pl break\n");
iph->flowid() = fid_;
iph->prio() = prio_;
iph->ttl() = defttl_;
hdr_flags* hf = hdr_flags::access(p);
hf->ecn_capable_ = 0;
hf->ecn_ = 0;
hf->eln_ = 0;
hf->ecn_to_echo_ = 0;
hf->fs_ = 0;
hf->no_ts_ = 0;
hf->pri_ = 0;
hf->cong_action_ = 0;
}
/*
* allocate a packet and fill in all the generic fields
*/
Packet*
Agent::allocpkt() const
{
Packet* p = Packet::alloc();
initpkt(p);
return (p);
}
/* allocate a packet and fill in all the generic fields and allocate
* a buffer of n bytes for data
*/
Packet*
Agent::allocpkt(int n) const
{
Packet* p = allocpkt();
if (n > 0)
p->allocdata(n);
return(p);
}
alloc-address.cc
/* -*- 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 Daedalus 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.
*/
/* functions invoked to allocate bits to the ns-address space */
#include
#include
#include "config.h"
#include
class AllocAddr : public TclObject {
public:
AllocAddr();
~AllocAddr();
int command(int argc, const char*const* argv);
protected:
void get_mask(nsmask_t *mask, int fieldsize);
void alloc(int n);
bool check_size(int n);
bool find_free(int len, int *pos);
bool test(int which);
void set_field(int offset, int len, nsmask_t *mask, int *shift);
void free_field(int len);
void mark(int i);
int size_;
int *bitmap_;
};
class AllocAddrClass : public TclClass {
public:
AllocAddrClass() : TclClass("AllocAddr") {}
TclObject* create(int, const char*const*) {
return (new AllocAddr());
}
} AllocAddr_class;
int AllocAddr::command(int argc, const char*const* argv)
{
int offset,
addrsize,
shift,
fieldlen;
nsmask_t mask;
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "freebit") == 0) {
fieldlen = atoi(argv[2]);
assert(fieldlen > 0);
free_field(fieldlen);
return (TCL_OK);
}
}
else if (argc == 4) {
if (strcmp(argv[1], "setbit") == 0) {
fieldlen = atoi(argv[2]);
addrsize = atoi(argv[3]);
if (!check_size(addrsize)) {
tcl.result("setbit: Size_ increased: Reallocate bits");
return (TCL_ERROR);
}
if (!find_free(fieldlen, &offset)) {
tcl.result("setbit: no contiguous space found\n");
return (TCL_ERROR);
}
set_field(offset, fieldlen, &mask, &shift);
// TESTING
tcl.resultf("%d %d", mask, shift);
return (TCL_OK);
}
}
else if (argc == 5) {
int oldfldlen;
if (strcmp(argv[1], "expand-port") == 0) {
fieldlen = atoi(argv[2]);
addrsize = atoi(argv[3]);
oldfldlen = atoi(argv[4]);
if (!check_size(addrsize)) {
tcl.result("expand-port: Size_ increased: Reallocate bits");
return (TCL_ERROR);
}
if (!find_free(fieldlen, &offset)) {
tcl.result("expand-port: no contiguous space found\n");
return (TCL_ERROR);
}
int i, k;
for (i = offset, k = 0; k < fieldlen; k++, i--) {
bitmap_[i] = 1;
}
shift = offset - (fieldlen - 1);
get_mask(&mask, fieldlen + oldfldlen);
// TESTING
tcl.resultf("%d %d", mask, shift);
return (TCL_OK);
}
}
return TclObject::command(argc, argv);
}
AllocAddr::AllocAddr()
{
size_ = 0;
bitmap_ = 0;
}
AllocAddr::~AllocAddr()
{
delete [] bitmap_;
}
void AllocAddr::alloc(int n)
{
size_ = n;
bitmap_ = new int[n];
for (int i=0; i < n; i++)
bitmap_[i] = 0;
}
bool AllocAddr::check_size(int n)
{
if (n <= size_)
return 1;
assert (n > 0);
if (size_ == 0) {
alloc(n);
return 1;
}
if (n > size_)
return 0;
return 1;
// this check is no longer needed, as now bits are re-allocated every time
// the size changes.
// int *old = bitmap_;
// int osize = size_;
// alloc(n);
// for (int i = 0; i < osize; i++)
// bitmap_[i] = old[i];
// delete [] old;
}
void AllocAddr::mark(int i)
{
bitmap_[i] = 1;
}
void AllocAddr::get_mask(nsmask_t *mask, int fieldsize)
{
// int temp = (int)(pow(2, (double)fieldsize));
*mask = (1 << fieldsize) - 1;
}
bool AllocAddr::test(int which)
{
assert(which <= size_);
if (bitmap_[which] == 1)
return TRUE;
else
return FALSE;
}
bool AllocAddr::find_free(int len, int *pos)
{
int count = 0;
int temp = 0;
for (int i = (size_ - 1); i >= 0; i--)
if (!test(i)) {
/**** check if n contiguous bits are free ****/
temp = i;
for (int k = 0; (k < len) && (i >=0); k++, i--){
if(test(i)) {
count = 0;
break;
}
count++;
}
if (count == len) {
*pos = temp;
return 1;
}
}
return 0;
}
void AllocAddr::set_field(int offset, int len, nsmask_t *mask, int *shift)
{
int i, k;
for (k = 0, i = offset; k < len; k++, i--) {
bitmap_[i] = 1;
}
*shift = offset - (len-1);
get_mask(mask, len);
}
void AllocAddr::free_field(int len)
{
int count = 0;
for (int i = 0; i < size_; i++) {
if (test(i)) {
bitmap_[i] = 0;
count++;
}
if (count == len)
break;
}
}
antenna.cc
/* -*- 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma.
*
antenna.cc
$Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $
*/
#include
static class AntennaClass : public TclClass {
public:
AntennaClass() : TclClass("Antenna") {}
TclObject* create(int, const char*const*) {
return (new Antenna);
}
} class_Antenna;
Antenna::Antenna()
{
X_ = 0; Y_= 0; Z_= 0;
bind("X_", &X_);
bind("Y_", &Y_);
bind("Z_", &Z_);
}
double
Antenna::getTxGain(double /*dX*/, double /*dY*/, double /*dZ*/,
double /*lambda*/)
{
return 1.0;
}
double
Antenna::getRxGain(double /*dX*/, double /*dY*/, double /*dZ*/,
double /*lambda*/)
{
return 1.0;
}
Antenna *
Antenna::copy()
{
return this;
}
void
Antenna::release()
{
;
}
app.cc
/* -*- 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 Daedalus Research
* Group at the University of California Berkeley.
* 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.
*
* Contributed by the Daedalus Research Group, http://daedalus.cs.berkeley.edu
*
*/
#include "app.h"
#include "agent.h"
static class ApplicationClass : public TclClass {
public:
ApplicationClass() : TclClass("Application") {}
TclObject* create(int, const char*const*) {
return (new Application);
}
} class_application;
Application::Application() : enableRecv_(0), enableResume_(0)
{
}
int Application::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "start") == 0) {
// enableRecv_ only if recv() exists in Tcl
tcl.evalf("[%s info class] info instprocs", name_);
char result[1024];
sprintf(result, " %s ", tcl.result());
enableRecv_ = (strstr(result, " recv ") != 0);
enableResume_ = (strstr(result, " resume ") != 0);
start();
return (TCL_OK);
}
if (strcmp(argv[1], "stop") == 0) {
stop();
return (TCL_OK);
}
if (strcmp(argv[1], "agent") == 0) {
tcl.resultf("%s", agent_->name());
return (TCL_OK);
}
}
else if (argc == 3) {
if (strcmp(argv[1], "attach-agent") == 0) {
agent_ = (Agent*) TclObject::lookup(argv[2]);
if (agent_ == 0) {
tcl.resultf("no such agent %s", argv[2]);
return(TCL_ERROR);
}
agent_->attachApp(this);
return(TCL_OK);
}
if (strcmp(argv[1], "send") == 0) {
send(atoi(argv[2]));
return(TCL_OK);
}
}
return (Process::command(argc, argv));
}
void Application::start()
{
}
void Application::stop()
{
}
void Application::send(int nbytes)
{
agent_->sendmsg(nbytes);
}
void Application::recv(int nbytes)
{
if (! enableRecv_)
return;
Tcl& tcl = Tcl::instance();
tcl.evalf("%s recv %d", name_, nbytes);
}
void Application::resume()
{
if (! enableResume_)
return;
Tcl& tcl = Tcl::instance();
tcl.evalf("%s resume", name_);
}
arp.cc
/*-*- 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma. */
/* arp.cc
basic arp cache and MAC addr resolution
$Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $
Note: code in this file violates the convention that addresses of
type Af_INET stored in nsaddr_t variables are stored in 24/8 format.
Many variables in nsaddr_t's in this file store ip addrs as simple ints.
*/
#include
#include "delay.h"
//#include "debug.h"
#include "mac.h"
#include "arp.h"
#include "topography.h"
#include "cmu-trace.h"
#include "mobilenode.h"
#include "ll.h"
#include "packet.h"
#include
// #define DEBUG
static class ARPTableClass : public TclClass {
public:
ARPTableClass() : TclClass("ARPTable") {}
TclObject* create(int, const char*const* argv) {
return (new ARPTable(argv[4], argv[5]));
}
} class_arptable;
static class ARPHeaderClass : public PacketHeaderClass {
public:
ARPHeaderClass() : PacketHeaderClass("PacketHeader/ARP",
sizeof(hdr_arp)) { }
} class_arphdr;
/* ======================================================================
Address Resolution (ARP) Table
====================================================================== */
ARPTable_List ARPTable::athead_ = { 0 };
void
ARPTable::Terminate()
{
ARPEntry *ll;
for(ll = arphead_.lh_first; ll; ll = ll->arp_link_.le_next) {
if(ll->hold_) {
drop(ll->hold_, DROP_END_OF_SIMULATION);
ll->hold_ = 0;
}
}
}
ARPTable::ARPTable(const char *tclnode, const char *tclmac) : LinkDelay() {
LIST_INIT(&arphead_);
node_ = (MobileNode*) TclObject::lookup(tclnode);
assert(node_);
mac_ = (Mac*) TclObject::lookup(tclmac);
assert(mac_);
off_mac_ = hdr_mac::offset_;
bind("off_ll_", &off_ll_);
//bind("off_mac_", &off_mac_);
bind("off_arp_", &off_arp_);
LIST_INSERT_HEAD(&athead_, this, link_);
}
int
ARPTable::command(int argc, const char*const* argv)
{
if (argc == 2 && strcasecmp(argv[1], "reset") == 0)
{
Terminate();
//FALL-THROUGH to give parents a chance to reset
}
return LinkDelay::command(argc, argv);
}
int
ARPTable::arpresolve(nsaddr_t dst, Packet *p, LL *ll)
{
ARPEntry *llinfo ;
assert(initialized());
llinfo = arplookup(dst);
#ifdef DEBUG
fprintf(stderr, "%d - %s\n", node_->address(), __FUNCTION__);
#endif
if(llinfo && llinfo->up_) {
mac_->hdr_dst((char*) HDR_MAC(p), llinfo->macaddr_);
return 0;
}
if(llinfo == 0) {
/*
* Create a new ARP entry
*/
llinfo = new ARPEntry(&arphead_, dst);
}
if(llinfo->count_ >= ARP_MAX_REQUEST_COUNT) {
/*
* Because there is not necessarily a scheduled event between
* this callback and the point where the callback can return
* to this point in the code, the order of operations is very
* important here so that we don't get into an infinite loop.
* - josh
*/
Packet *t = llinfo->hold_;
llinfo->count_ = 0;
llinfo->hold_ = 0;
hdr_cmn* ch;
if(t) {
ch = HDR_CMN(t);
if (ch->xmit_failure_) {
ch->xmit_reason_ = 0;
ch->xmit_failure_(t, ch->xmit_failure_data_);
}
else {
drop(t, DROP_IFQ_ARP_FULL);
}
}
ch = HDR_CMN(p);
if (ch->xmit_failure_) {
ch->xmit_reason_ = 0;
ch->xmit_failure_(p, ch->xmit_failure_data_);
}
else {
drop(p, DROP_IFQ_ARP_FULL);
}
return EADDRNOTAVAIL;
}
llinfo->count_++;
if(llinfo->hold_)
drop(llinfo->hold_, DROP_IFQ_ARP_FULL);
llinfo->hold_ = p;
/*
* We don't have a MAC address for this node. Send an ARP Request.
*
* XXX: Do I need to worry about the case where I keep ARPing
* for the SAME destination.
*/
int src = node_->address(); // this host's IP addr
arprequest(src, dst, ll);
return EADDRNOTAVAIL;
}
ARPEntry*
ARPTable::arplookup(nsaddr_t dst)
{
ARPEntry *a;
for(a = arphead_.lh_first; a; a = a->nextarp()) {
if(a->ipaddr_ == dst)
return a;
}
return 0;
}
void
ARPTable::arprequest(nsaddr_t src, nsaddr_t dst, LL *ll)
{
Scheduler& s = Scheduler::instance();
Packet *p = Packet::alloc();
hdr_cmn *ch = HDR_CMN(p);
char *mh = (char*) HDR_MAC(p);
hdr_ll *lh = HDR_LL(p);
hdr_arp *ah = HDR_ARP(p);
ch->uid() = 0;
ch->ptype() = PT_ARP;
ch->size() = ARP_HDR_LEN;
ch->iface() = -2;
ch->error() = 0;
mac_->hdr_dst(mh, MAC_BROADCAST);
mac_->hdr_src(mh, ll->mac_->addr());
mac_->hdr_type(mh, ETHERTYPE_ARP);
lh->seqno() = 0;
lh->lltype() = LL_DATA;
ch->direction() = hdr_cmn::DOWN; // send this pkt down
ah->arp_hrd = ARPHRD_ETHER;
ah->arp_pro = ETHERTYPE_IP;
ah->arp_hln = ETHER_ADDR_LEN;
ah->arp_pln = sizeof(nsaddr_t);
ah->arp_op = ARPOP_REQUEST;
ah->arp_sha = ll->mac_->addr();
ah->arp_spa = src;
ah->arp_tha = 0; // what were're looking for
ah->arp_tpa = dst;
s.schedule(ll->downtarget_, p, delay_);
}
void
ARPTable::arpinput(Packet *p, LL *ll)
{
Scheduler& s = Scheduler::instance();
hdr_arp *ah = HDR_ARP(p);
ARPEntry *llinfo;
assert(initialized());
#ifdef DEBUG
fprintf(stderr,
"%d - %s\n\top: %x, sha: %x, tha: %x, spa: %x, tpa: %x\n",
node_->address(), __FUNCTION__, ah->arp_op,
ah->arp_sha, ah->arp_tha, ah->arp_spa, ah->arp_tpa);
#endif
if((llinfo = arplookup(ah->arp_spa)) == 0) {
/*
* Create a new ARP entry
*/
llinfo = new ARPEntry(&arphead_, ah->arp_spa);
}
assert(llinfo);
llinfo->macaddr_ = ah->arp_sha;
llinfo->up_ = 1;
/*
* Can we send whatever's being held?
*/
if(llinfo->hold_) {
hdr_cmn *ch = HDR_CMN(llinfo->hold_);
char *mh = (char*) HDR_MAC(llinfo->hold_);
hdr_ip *ih = HDR_IP(llinfo->hold_);
// XXXHACK for now:
// Future work: separate port-id from IP address ??
int dst = Address::instance().get_nodeaddr(ih->daddr());
if((ch->addr_type() == NS_AF_NONE &&
dst == ah->arp_spa) ||
(NS_AF_INET == ch->addr_type() &&
ch->next_hop() == ah->arp_spa)) {
#ifdef DEBUG
fprintf(stderr, "\tsending HELD packet.\n");
#endif
mac_->hdr_dst(mh, ah->arp_sha);
s.schedule(ll->downtarget_, llinfo->hold_, delay_);
llinfo->hold_ = 0;
}
else {
fprintf(stderr, "\tfatal ARP error...\n");
exit(1);
}
}
if(ah->arp_op == ARPOP_REQUEST &&
ah->arp_tpa == node_->address()) {
hdr_cmn *ch = HDR_CMN(p);
char *mh = (char*)HDR_MAC(p);
hdr_ll *lh = HDR_LL(p);
ch->size() = ARP_HDR_LEN;
ch->error() = 0;
ch->direction() = hdr_cmn::DOWN; // send this pkt down
mac_->hdr_dst(mh, ah->arp_sha);
mac_->hdr_src(mh, ll->mac_->addr());
mac_->hdr_type(mh, ETHERTYPE_ARP);
lh->seqno() = 0;
lh->lltype() = LL_DATA;
// ah->arp_hrd =
// ah->arp_pro =
// ah->arp_hln =
// ah->arp_pln =
ah->arp_op = ARPOP_REPLY;
ah->arp_tha = ah->arp_sha;
ah->arp_sha = ll->mac_->addr();
nsaddr_t t = ah->arp_spa;
ah->arp_spa = ah->arp_tpa;
ah->arp_tpa = t;
s.schedule(ll->downtarget_, p, delay_);
return;
}
Packet::free(p);
}
bi-connector.cc
/* -*- 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.
*/
#include "packet.h"
#include "bi-connector.h"
static class BiConnectorClass : public TclClass {
public:
BiConnectorClass() : TclClass("BiConnector") {}
TclObject* create(int, const char*const*) {
return (new BiConnector);
}
} class_biconnector;
BiConnector::BiConnector() : uptarget_(0), downtarget_(0), drop_(0)
{}
int BiConnector::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
/*XXX*/
if (argc == 2) {
if (strcmp(argv[1], "up-target") == 0) {
if (uptarget_ != 0)
tcl.result(uptarget_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "down-target") == 0) {
if (downtarget_ != 0)
tcl.result(downtarget_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "drop-target") == 0) {
if (drop_ != 0)
tcl.resultf("%s", drop_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "isDynamic") == 0) {
return TCL_OK;
}
}
else if (argc == 3) {
TclObject *obj;
if( (obj = TclObject::lookup(argv[2])) == 0) {
fprintf(stderr, "%s lookup failed\n", argv[1]);
return TCL_ERROR;
}
if (strcmp(argv[1], "up-target") == 0) {
if (*argv[2] == '0') {
uptarget_ = 0;
return (TCL_OK);
}
uptarget_ = (NsObject*) obj;
if (uptarget_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "down-target") == 0) {
if (*argv[2] == '0') {
downtarget_ = 0;
return (TCL_OK);
}
downtarget_ = (NsObject*) obj;
if (downtarget_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "drop-target") == 0) {
drop_ = (NsObject*) obj;
if (drop_ == 0) {
tcl.resultf("no object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (NsObject::command(argc, argv));
}
void BiConnector::recv(Packet* p, Handler* h)
{
hdr_cmn *ch = HDR_CMN(p);
switch (ch->direction()) {
case hdr_cmn::UP :
sendUp(p, h);
break;
case hdr_cmn::DOWN :
sendDown(p, h);
break;
default:
printf("Error: Packet Direction not specified; Using default 'UP' direction\n\n");
sendUp(p, h);
}
}
void BiConnector::drop(Packet* p)
{
if (drop_ != 0)
drop_->recv(p);
else
Packet::free(p);
}
void BiConnector::drop(Packet* p, const char *s)
{
if (drop_ != 0)
drop_->recv(p, s);
else
Packet::free(p);
}
cbq.cc
/* -*- 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$ (LBL)";
#endif
//
// new version of cbq using the ns-2 fine-grain
// objects. Also, re-orginaize CBQ to look more like how
// its description reads in ToN v3n4 and simplify extraneous stuff -KF
//
// there is a 1-1 relationship between classes and queues, except
// that internal nodes in the LS tree don't have queues
//
// Definitions:
// overlimit:
// recently used more than allocated link-sharing bandwidth
// (in bytes/sec averaged over specified interval)
//
// level:
// all leaves are at level 1
// interior nodes are at a level 1 greater than
// the highest level number of any of its children
//
// unsatisfied:
// (leaf): underlimit and has demand
// (interior): underlimit and has some descendant w/demand
// [either a leaf or interior descendant]
//
// formal link-sharing:
// class may continue unregulated if either:
// 1> class is underlimit or at-limit
// 2> class has a under(at)-limit ancestor at level i
// and no unsatisfied classes at any levels < i
//
// ancestors-only link-sharing:
// class may continue unregulated if either:
// 1> class is under/at limit
// 2> class has an UNDER-limit ancestor [at-limit not ok]
//
// top-level link-sharing:
// class may continue unregulated if either:
// 1> class is under/at limit
// 2> class has an UNDER-limit ancestor with level
// <= the value of "top-level"
#include "queue-monitor.h"
#include "queue.h"
#include "delay.h"
#define MAXPRIO 10 /* # priorities in scheduler */
#define MAXLEVEL 32 /* max depth of link-share tree(s) */
#define LEAF_LEVEL 1 /* level# for leaves */
#define POWEROFTWO 16
class CBQClass : public Connector {
public:
friend class CBQueue;
friend class WRR_CBQueue;
CBQClass();
int command(int argc, const char*const* argv);
void recv(Packet*, Handler*); // from upstream classifier
protected:
void newallot(double); // change an allotment
void update(Packet*, double); // update when sending pkt
void delayed(double); // when overlim/can't borrow
int satisfied(double); // satisfied?
int demand(); // do I have demand?
int leaf(); // am I a leaf class?
int ancestor(CBQClass*p); // are we an ancestor of p?
int desc_with_demand(); // any desc has demand?
CBQueue* cbq_; // the CBQueue I'm part of
CBQClass* peer_; // peer at same sched prio level
CBQClass* level_peer_; // peer at same LS level
CBQClass* lender_; // parent I can borrow from
Queue* q_; // underlying queue
QueueMonitor* qmon_; // monitor for the queue
double allotment_; // frac of link bw
double maxidle_; // bound on idle time
double maxrate_; // bound on bytes/sec rate
double extradelay_; // adjustment to delay
double last_time_; // last xmit time this class
double undertime_; // will become unsat/eligible
double avgidle_; // EWMA of idle
int pri_; // priority for scheduler
int level_; // depth in link-sharing tree
int delayed_; // boolean-was I delayed
int bytes_alloc_; // for wrr only
int permit_borrowing_; // ok to borrow?
};
class CBQueue : public Queue {
public:
CBQueue();
void reset();
void enque(Packet*) { abort(); }
void recv(Packet*, Handler*);
LinkDelay* link() const { return (link_); }
CBQClass* level(int n) const { return levels_[n]; }
Packet* deque();
virtual int command(int argc, const char*const* argv);
virtual void addallot(int, double) { }
Packet* pending_pkt() const { return (pending_pkt_); }
void sched();
int toplevel() { // are we using toplevel?
// return (eligible_ == &eligible_toplevel);
return (eligible_ == TOPLEVEL);
}
void toplevel_arrival(CBQClass*, double);
protected:
Event intr_;
int algorithm(const char *);
virtual int insert_class(CBQClass*);
int send_permitted(CBQClass*, double);
CBQClass* find_lender(CBQClass*, double);
void toplevel_departure(CBQClass*, double);
CBQClass* last_lender_;
Packet* pending_pkt_; // queued packet
LinkDelay* link_; // managed link
CBQClass* active_[MAXPRIO]; // classes at prio of index
CBQClass* levels_[MAXLEVEL+1]; // LL of classes per level
int maxprio_; // highest prio# seen
int maxpkt_; // largest pkt (used by WRR)
int maxlevel_; // highest level# seen
int toplevel_; // for top-level LS
// typedef int (CBQueue::*eligible_type_)(CBQClass*, double);
// eligible_type_ eligible_; // eligible function
enum eligible_type_ { NONE, FORMAL, ANCESTORS, TOPLEVEL };
eligible_type_ eligible_;
int eligible_formal(CBQClass*, double);
int eligible_ancestors(CBQClass*, double) { return (1); }
int eligible_toplevel(CBQClass* cl, double) {
return(cl->level_ <= toplevel_);
}
};
static class CBQQueueClass : public TclClass {
public:
CBQQueueClass() : TclClass("Queue/CBQ") { }
TclObject* create(int, const char*const*) {
return (new CBQueue);
}
} class_cbq;
static class CBQClassClass : public TclClass {
public:
CBQClassClass() : TclClass("CBQClass") { }
TclObject* create(int, const char*const*) {
return (new CBQClass);
}
} class_cbqclass;
CBQueue::CBQueue() : last_lender_(NULL), pending_pkt_(NULL), link_(NULL),
maxprio_(-1), maxpkt_(-1), maxlevel_(-1), toplevel_(MAXLEVEL),
// eligible_((eligible_type_)NULL)
eligible_(NONE)
{
bind("maxpkt_", &maxpkt_);
memset(active_, '\0', sizeof(active_));
memset(levels_, '\0', sizeof(levels_));
}
/*
* schedule ourselves, used by CBQClass::recv
*/
void
CBQueue::sched()
{
Scheduler& s = Scheduler::instance();
blocked_ = 1;
s.schedule(&qh_, &intr_, 0);
}
/*
* invoked by passing a packet from one of our managed queues
* basically provides a queue of one packet
*/
void
CBQueue::recv(Packet* p, Handler*)
{
if (pending_pkt_ != NULL)
abort();
blocked_ = 1;
pending_pkt_ = p;
}
void
CBQueue::reset()
{
// don't do anything
// in particular, don't let Queue::reset() call
// our deque() method
}
int
CBQueue::algorithm(const char *arg)
{
if (*arg == '0' || (strcmp(arg, "ancestor-only") == 0)) {
// eligible_ = &eligible_ancestors;
eligible_ = ANCESTORS;
return (1);
} else if (*arg == '1' || (strcmp(arg, "top-level") == 0)) {
// eligible_ = &eligible_toplevel;
eligible_ = TOPLEVEL;
return (1);
} else if (*arg == '2' || (strcmp(arg, "formal") == 0)) {
// eligible_ = &eligible_formal;
eligible_ = FORMAL;
return (1);
} else if (*arg == '3' || (strcmp(arg, "old-formal") == 0)) {
fprintf(stderr, "CBQ: old-formal LS not supported\n");
return (-1);
}
return (-1);
}
/*
*
* toplevel_arrival: called only using TL link sharing on arrival
* toplevel_departure: called only using TL link sharing on departure
*/
void
CBQueue::toplevel_departure(CBQClass *cl, double now)
{
if (toplevel_ >= last_lender_->level_) {
if ((cl->qmon_->pkts() <= 1) ||
last_lender_->undertime_ > now) {
toplevel_ = MAXLEVEL;
} else {
toplevel_ = last_lender_->level_;
}
}
}
void
CBQueue::toplevel_arrival(CBQClass *cl, double now)
{
if (toplevel_ > 1) {
if (cl->undertime_ < now)
toplevel_ = 1;
else if (toplevel_ > 2 && cl->permit_borrowing_ && cl->lender_ != NULL) {
if (cl->lender_->undertime_ < now)
toplevel_ = 2;
}
}
}
/*
* deque: this gets invoked by way of our downstream
* (i.e. linkdelay) neighbor doing a 'resume' on us
* via our handler (by Queue::resume()), or by our upstream
* neighbor when it gives us a packet when we were
* idle
*/
Packet *
CBQueue::deque()
{
Scheduler& s = Scheduler::instance();
double now = s.clock();
CBQClass* first = NULL;
CBQClass* eligible = NULL;
CBQClass* cl;
register int prio;
Packet* rval;
int none_found = 0;
/*
* prio runs from 0 .. maxprio_
*
* round-robin through all the classes at priority 'prio'
* if any class is ok to send, resume it's queue
* go on to next lowest priority (higher prio nuber) and repeat
* [lowest priority number is the highest priority]
*/
for (prio = 0; prio <= maxprio_; prio++) {
// see if there is any class at this prio
if ((cl = active_[prio]) == NULL) {
// nobody at this prio level
continue;
}
// look for underlimit peer with something to send
do {
// anything to send?
if (cl->demand()) {
if (first == NULL && cl->permit_borrowing_ && cl->lender_ != NULL)
first = cl;
if (send_permitted(cl, now)) {
// ok to send
eligible = cl;
goto found;
} else {
// not ok right now
cl->delayed(now);
}
}
cl = cl->peer_; // move to next at same prio
} while (cl != active_[prio]);
}
// did not find anyone so let first go
// eligible will be NULL at this point
if (first != NULL) {
none_found = 1;
eligible = first;
}
found:
if (eligible != NULL) {
active_[eligible->pri_] = eligible->peer_;
// eligible->q_->unblock();
eligible->q_->resume(); // fills in pending
if (pending_pkt_ && !none_found) {
eligible->update(pending_pkt_, now);
if (toplevel())
toplevel_departure(eligible, now);
}
}
rval = pending_pkt_;
pending_pkt_ = NULL;
return (rval);
}
/*
* we are permitted to send if either
* 1> we are not overlimit (ie we are underlimit or at limit)
* 2> one of the varios algorithm-dependent conditions is met
*
* if we are permitted, who did we borrow from? [could be ourselves
* if we were not overlimit]
*/
int CBQueue::send_permitted(CBQClass* cl, double now)
{
if (cl->undertime_ < now) {
cl->delayed_ = 0;
last_lender_ = cl;
return (1);
} else if (cl->permit_borrowing_ &&
(((cl = find_lender(cl, now)) != NULL))) {
last_lender_ = cl;
return (1);
}
return (0);
}
/*
* find_lender(class, time)
*
* find a lender for the provided class according to the
* various algorithms
*
*/
CBQClass*
CBQueue::find_lender(CBQClass* cl, double now)
{
if ((!cl->permit_borrowing_) || ((cl = cl->lender_) == NULL))
return (NULL); // no ancestor to borrow from
while (cl != NULL) {
// skip past overlimit ancestors
// if using TL and we're above the TL limit
// do early out
if (cl->undertime_ > now) {
if (toplevel() && cl->level_ > toplevel_)
return (NULL);
cl = cl->lender_;
continue;
}
// found what may be an eligible
// lender, check using per-algorithm eligibility
// criteria
// XXX we explicitly invoke this indirect method with
// the "this" pointer because MS VC++ can't parse it
// without it...
// if ((this->*eligible_)(cl, now))
// return (cl);
switch (eligible_) {
case TOPLEVEL:
if (eligible_toplevel(cl, now))
return (cl);
break;
case ANCESTORS:
if (eligible_ancestors(cl, now))
return (cl);
break;
case FORMAL:
if (eligible_formal(cl, now))
return (cl);
break;
default:
fprintf(stderr, "Wrong eligible_\n");
abort();
}
cl = cl->lender_;
}
return (cl);
}
/*
* rule #2 for formal link-sharing
* class must have no unsatisfied classes below it
*/
int
CBQueue::eligible_formal(CBQClass *cl, double now)
{
int level;
CBQClass *p;
// check from leaf level to (cl->level - 1)
for (level = LEAF_LEVEL; level < cl->level_; level++) {
p = levels_[level];
while (p != NULL) {
if (!p->satisfied(now))
return (0);
p = p->level_peer_;
}
}
return (1);
}
/*
* insert a class into the cbq object
*/
int
CBQueue::insert_class(CBQClass *p)
{
p->cbq_ = this;
/*
* Add to circularly-linked list "active_"
* of peers for the given priority.
*/
if (p->pri_ < 0 || p->pri_ > (MAXPRIO-1)) {
fprintf(stderr, "CBQ class %s has invalid pri %d\n",
p->name(), p->pri_);
return (-1);
}
if (p->q_ != NULL) {
// only leaf nodes (which have associated queues)
// are scheduled
if (active_[p->pri_] != NULL) {
p->peer_ = active_[p->pri_]->peer_;
active_[p->pri_]->peer_ = p;
} else {
p->peer_ = p;
active_[p->pri_] = p;
}
if (p->pri_ > maxprio_)
maxprio_ = p->pri_;
}
/*
* Compute maxrate from allotment.
* convert to bytes/sec
* and store the highest prio# we've seen
*/
if (p->allotment_ < 0.0 || p->allotment_ > 1.0) {
fprintf(stderr, "CBQ class %s has invalid allot %f\n",
p->name(), p->allotment_);
return (-1);
}
if (link_ == NULL) {
fprintf(stderr, "CBQ obj %s has no link!\n", name());
return (-1);
}
if (link_->bandwidth() <= 0.0) {
fprintf(stderr, "CBQ obj %s has invalid link bw %f on link %s\n",
name(), link_->bandwidth(), link_->name());
return (-1);
}
p->maxrate_ = p->allotment_ * (link_->bandwidth() / 8.0);
addallot(p->pri_, p->allotment_);
/*
* Add to per-level list
* and store the highest level# we've seen
*/
if (p->level_ <= 0 || p->level_ > MAXLEVEL) {
fprintf(stderr, "CBQ class %s has invalid level %d\n",
p->name(), p->level_);
return (-1);
}
p->level_peer_ = levels_[p->level_];
levels_[p->level_] = p;
if (p->level_ > maxlevel_)
maxlevel_ = p->level_;
/*
* Check that parent and borrow linkage are acyclic.
*/
#ifdef notdef
check_for_cycles(CBQClass::parent);
check_for_cycles(CBQClass::borrow);
#endif
return 0;
}
int CBQueue::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "insert-class") == 0) {
CBQClass *cl = (CBQClass*)TclObject::lookup(argv[2]);
if (cl == 0) {
tcl.resultf("CBQ: no class object %s",
argv[2]);
return (TCL_ERROR);
}
if (insert_class(cl) < 0) {
tcl.resultf("CBQ: trouble inserting class %s",
argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "link") == 0) {
LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
if (del == 0) {
tcl.resultf("CBQ: no LinkDelay object %s",
argv[2]);
return(TCL_ERROR);
}
link_ = del;
return (TCL_OK);
}
if (strcmp(argv[1], "algorithm") == 0) {
if (algorithm(argv[2]) < 0)
return (TCL_ERROR);
return (TCL_OK);
}
}
return (Queue::command(argc, argv));
}
class WRR_CBQueue : public CBQueue {
public:
WRR_CBQueue() {
memset(M_, '\0', sizeof(M_));
memset(alloc_, '\0', sizeof(alloc_));
memset(cnt_, '\0', sizeof(cnt_));
}
void addallot(int prio, double diff) {
alloc_[prio] += diff;
setM();
}
protected:
Packet *deque();
int insert_class(CBQClass*);
void setM();
double alloc_[MAXPRIO];
double M_[MAXPRIO];
int cnt_[MAXPRIO]; // # classes at prio of index
int command(int argc, const char*const* argv);
};
static class WRR_CBQQueueClass : public TclClass {
public:
WRR_CBQQueueClass() : TclClass("Queue/CBQ/WRR") { }
TclObject* create(int, const char*const*) {
return (new WRR_CBQueue);
}
} class_wrr_cbq;
int WRR_CBQueue::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (strcmp(argv[1], "insert-class") == 0) {
CBQClass *cl = (CBQClass*)TclObject::lookup(argv[2]);
if (cl == 0) {
tcl.resultf("WRR-CBQ: no class object %s",
argv[2]);
return (TCL_ERROR);
}
if (insert_class(cl) < 0) {
tcl.resultf("WRR-CBQ: trouble inserting class %s",
argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
return (CBQueue::command(argc, argv));
}
Packet *
WRR_CBQueue::deque()
{
double now = Scheduler::instance().clock();
CBQClass* first = NULL;
CBQClass* eligible = NULL;
CBQClass* next_eligible = NULL;
CBQClass* cl;
register int prio;
int deficit, done;
int none_found = 0;
Packet* rval;
/*
* prio runs from 0 .. maxprio_
*
* round-robin through all the classes at priority 'prio'
* if any class is ok to send, resume it's queue
* go on to next lowest priority (higher prio nuber) and repeat
* [lowest priority number is the highest priority]
*/
for (prio = 0; prio <= maxprio_; prio++) {
// see if there is any class at this prio
if ((cl = active_[prio]) == NULL) {
// nobody at this prio level
continue;
}
/*
* The WRR round for this priority level starts at deficit 0.
* The round ends if some class is found that is ready
* to send and has positive "bytes_alloc_".
* Status advances to deficit 1 if some class was found
* that was able to send except for insufficient
* "bytes_alloc_".
* If status was deficit 1 at the end of the first round,
* then status advances to deficit 2.
* Another round of WRR is then begun at deficit 2, looking
* for a class to send even with insufficient "bytes_alloc_".
*/
deficit = done = 0;
while (!done) {
// look for class at this priority level ok to send
do {
// set up "weight" for WRR
if (deficit < 2 && cl->bytes_alloc_ <= 0)
cl->bytes_alloc_ +=
(int)(cl->allotment_ * M_[cl->pri_]);
// anything to send?
if (cl->demand()) {
if (first == NULL && cl->permit_borrowing_ && cl->lender_ != NULL)
first = cl;
if (!send_permitted(cl, now)) {
// not ok to send right now
cl->delayed(now);
} else {
// ok to send, if class has
// enough "weight" for WRR.
int bytes = cl->bytes_alloc_;
if (bytes > 0 || deficit > 1) {
eligible = cl;
goto found;
} else
deficit = 1;
}
}
cl->bytes_alloc_ = 0;
cl = cl->peer_;
} while (cl != active_[prio] && cl != 0);
if (deficit == 1)
deficit = 2;
else
done = 1;
}
}
// did not find anyone so let first go
if ((eligible == NULL) && first != NULL) {
none_found = 1;
eligible = first;
}
found:
// do accounting
if (eligible != NULL) {
next_eligible = eligible->peer_;
eligible->q_->resume();
if (pending_pkt_ != NULL && !none_found) {
// reduce our alloc
// by the packet size. If we're
// still positive, we get to go again
int bytes = eligible->bytes_alloc_;
hdr_cmn* hdr = (hdr_cmn*)pending_pkt_->access(off_cmn_);
if (bytes > 0) {
eligible->bytes_alloc_ -= hdr->size();
}
bytes = eligible->bytes_alloc_;
if (bytes > 0) {
next_eligible = eligible;
}
eligible->update(pending_pkt_, now);
if (toplevel())
toplevel_departure(eligible, now);
}
active_[eligible->pri_] = next_eligible;
}
rval = pending_pkt_;
pending_pkt_ = NULL;
return (rval);
}
int
WRR_CBQueue::insert_class(CBQClass *p)
{
if (CBQueue::insert_class(p) < 0)
return (-1);
++cnt_[p->pri_];
setM();
return (0);
}
void
WRR_CBQueue::setM()
{
int i;
for (i = 0; i <= maxprio_; i++) {
if (alloc_[i] > 0.0)
// allocate "cnt_[i] * maxpkt_" bytes to each
// priority level:
M_[i] = cnt_[i] * maxpkt_ * 1.0 / alloc_[i];
// allocate "alloc_[i] * 2.0 * cnt_[i] * maxpkt_"
// bytes to each priority level:
// M_[i] = 2.0 * cnt_[i] * maxpkt_;
else
M_[i] = 0.0;
if (M_[i] < 0.0) {
fprintf(stderr, "M_[i]: %f, cnt_[i]: %d, maxpkt_: %d, alloc_[i]: %f\n",
M_[i], cnt_[i], maxpkt_, alloc_[i]);
abort();
}
}
return;
}
/******************** CBQClass definitions **********************/
CBQClass::CBQClass() : cbq_(0), peer_(0), level_peer_(0), lender_(0),
q_(0), qmon_(0), allotment_(0.0), maxidle_(-1.0), maxrate_(0.0),
extradelay_(0.0), last_time_(0.0), undertime_(0.0), avgidle_(0.0),
pri_(-1), level_(-1), delayed_(0), bytes_alloc_(0),
permit_borrowing_(1)
{
/* maxidle_ is no longer bound; it is now a method interface */
bind("priority_", &pri_);
bind("level_", &level_);
bind("extradelay_", &extradelay_);
bind_bool("okborrow_", &permit_borrowing_);
if (pri_ < 0 || pri_ > (MAXPRIO-1))
abort();
if (level_ <= 0 || level_ > MAXLEVEL)
abort();
}
// why can't these two be inline (?)
int
CBQClass::demand()
{
return (qmon_->pkts() > 0);
}
int
CBQClass::leaf()
{
return (level_ == LEAF_LEVEL);
}
/*
* we are upstream from the queue
* the queue should be unblocked if the downstream
* cbq is not busy and blocked otherwise
*
* we get our packet from the classifier, because of
* this the handler is NULL. Besides the queue downstream
* from us (Queue::recv) ignores the handler anyhow
*
*/
void
CBQClass::recv(Packet *pkt, Handler *h)
{
if (cbq_->toplevel()) {
Scheduler* s;
if ((s = &Scheduler::instance()) != NULL)
cbq_->toplevel_arrival(this, s->clock());
}
send(pkt, h); // queue packet downstream
if (!cbq_->blocked()) {
cbq_->sched();
}
return;
}
/*
* update a class' statistics and all parent classes
* up to the root
*/
void CBQClass::update(Packet* p, double now)
{
double idle, avgidle;
hdr_cmn* hdr = (hdr_cmn*)p->access(off_cmn_);
int pktsize = hdr->size();
double tx_time = cbq_->link()->txtime(p);
double fin_time = now + tx_time;
idle = (fin_time - last_time_) - (pktsize / maxrate_);
avgidle = avgidle_;
avgidle += (idle - avgidle) / POWEROFTWO;
if (maxidle_ < 0) {
fprintf(stderr,
"CBQClass: warning: maxidle_ not configured!\n");
} else if (avgidle > maxidle_)
avgidle = maxidle_;
avgidle_ = avgidle;
if (avgidle <= 0) {
undertime_ = fin_time + tx_time *
(1.0 / allotment_ - 1.0);
undertime_ += (1-POWEROFTWO) * avgidle;
}
last_time_ = fin_time;
// tail-recurse up to root of tree performing updates
if (lender_)
lender_->update(p, now);
return;
}
/*
* satisfied: is this class satisfied?
*/
int
CBQClass::satisfied(double now)
{
if (leaf()) {
/* leaf is unsat if underlimit with backlog */
if (undertime_ < now && demand())
return (0);
else
return (1);
}
if (undertime_ < now && desc_with_demand())
return (0);
return (1);
}
/*
* desc_with_demand: is there a descendant of this class with demand
* really, is there a leaf which is a descendant of me with
* a backlog
*/
int
CBQClass::desc_with_demand()
{
CBQClass *p = cbq_->level(LEAF_LEVEL);
for (; p != NULL; p = p->level_peer_) {
if (p->demand() && ancestor(p))
return (1);
}
return (0);
}
/*
* happens when a class is unable to send because it
* is being regulated
*/
void CBQClass::delayed(double now)
{
double delay = undertime_ - now + extradelay_;
if (delay > 0 && !delayed_) {
undertime_ += extradelay_;
undertime_ -= (1-POWEROFTWO) * avgidle_;
delayed_ = 1;
}
}
/*
* return 1 if we are an ancestor of p, 0 otherwise
*/
int
CBQClass::ancestor(CBQClass *p)
{
if (!p->permit_borrowing_ || p->lender_ == NULL)
return (0);
else if (p->lender_ == this)
return (1);
return (ancestor(p->lender_));
}
/*
* change an allotment
*/
void
CBQClass::newallot(double bw)
{
if (allotment_ < 0)
allotment_ = 0;
if (bw < 0)
bw = 0;
maxrate_ = bw * ( cbq_->link()->bandwidth() / 8.0 );
double diff = bw - allotment_;
allotment_ = bw;
cbq_->addallot(pri_, diff);
return;
}
/*
* OTcl Interface
*/
/*
* $class1 parent $class2
* $class1 borrow $class2
* $class1 qdisc $queue
* $class1 allot
* $class1 allot new-bw
*/
int CBQClass::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "allot") == 0) {
tcl.resultf("%g", allotment_);
return (TCL_OK);
}
if (strcmp(argv[1], "cbq") == 0) {
if (cbq_ != NULL)
tcl.resultf("%s", cbq_->name());
else
tcl.resultf("");
return(TCL_OK);
}
if (strcmp(argv[1], "qdisc") == 0) {
if (q_ != NULL)
tcl.resultf("%s", q_->name());
else
tcl.resultf("");
return (TCL_OK);
}
if (strcmp(argv[1], "qmon") == 0) {
if (qmon_ != NULL)
tcl.resultf("%s", qmon_->name());
else
tcl.resultf("");
return (TCL_OK);
}
} else if (argc == 3) {
// for now these are the same
if ((strcmp(argv[1], "parent") == 0)) {
if (strcmp(argv[2], "none") == 0) {
lender_ = NULL;
return (TCL_OK);
}
lender_ = (CBQClass*)TclObject::lookup(argv[2]);
if (lender_ != NULL)
return (TCL_OK);
return (TCL_ERROR);
}
if (strcmp(argv[1], "qdisc") == 0) {
q_ = (Queue*) TclObject::lookup(argv[2]);
if (q_ != NULL)
return (TCL_OK);
tcl.resultf("couldn't find object %s",
argv[2]);
return (TCL_ERROR);
}
if (strcmp(argv[1], "qmon") == 0) {
qmon_ = (QueueMonitor*) TclObject::lookup(argv[2]);
if (qmon_ != NULL)
return (TCL_OK);
return (TCL_ERROR);
}
if (strcmp(argv[1], "allot") == 0) {
double bw = atof(argv[2]);
if (bw < 0.0)
return (TCL_ERROR);
if (allotment_ != 0.0) {
tcl.resultf(" class %s already has allotment of %f!",
name(), allotment_);
return (TCL_ERROR);
}
allotment_ = bw;
return (TCL_OK);
}
if (strcmp(argv[1], "newallot") == 0) {
double bw = atof(argv[2]);
if (bw < 0.0)
return (TCL_ERROR);
newallot(bw);
return (TCL_OK);
}
if (strcmp(argv[1], "maxidle") == 0) {
double m = atof(argv[2]);
if (m < 0.0) {
tcl.resultf("invalid maxidle value %s (must be non-negative)",
argv[2]);
return (TCL_ERROR);
}
maxidle_ = m;
return (TCL_OK);
}
}
return (Connector::command(argc, argv));
}
cbr_traffic.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or derivative
* work. Xerox grants no other licenses expressed or implied. The Xerox trade
* name should not be used in any advertising without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this software.
*/
#include
#include "random.h"
#include "trafgen.h"
#include "ranvar.h"
/*
* Constant bit rate traffic source. Parameterized by interval, (optional)
* random noise in the interval, and packet size.
*/
class CBR_Traffic : public TrafficGenerator {
public:
CBR_Traffic();
virtual double next_interval(int&);
//HACK so that udp agent knows interpacket arrival time within a burst
inline double interval() { return (interval_); }
protected:
virtual void start();
void init();
double rate_; /* send rate during on time (bps) */
double interval_; /* packet inter-arrival time during burst (sec) */
double random_;
int seqno_;
int maxpkts_;
};
static class CBRTrafficClass : public TclClass {
public:
CBRTrafficClass() : TclClass("Application/Traffic/CBR") {}
TclObject* create(int, const char*const*) {
return (new CBR_Traffic());
}
} class_cbr_traffic;
CBR_Traffic::CBR_Traffic() : seqno_(0)
{
bind_bw("rate_", &rate_);
bind("random_", &random_);
bind("packetSize_", &size_);
bind("maxpkts_", &maxpkts_);
}
void CBR_Traffic::init()
{
// compute inter-packet interval
interval_ = (double)(size_ << 3)/(double)rate_;
if (agent_)
agent_->set_pkttype(PT_CBR);
}
void CBR_Traffic::start()
{
init();
running_ = 1;
timeout();
}
double CBR_Traffic::next_interval(int& size)
{
// Recompute interval in case rate_ or size_ has changes
interval_ = (double)(size_ << 3)/(double)rate_;
double t = interval_;
if (random_)
t += interval_ * Random::uniform(-0.5, 0.5);
size = size_;
if (++seqno_ < maxpkts_)
return(t);
else
return(-1);
}
channel.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996 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 Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory and the Daedalus
* research group at UC Berkeley.
* 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.
*
* Contributed by Giao Nguyen, http://daedalus.cs.berkeley.edu/~gnguyen
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
//#include "template.h"
#include
#include "trace.h"
#include "delay.h"
#include "object.h"
#include "packet.h"
#include "mac.h"
#include "channel.h"
#include "list.h"
#include "phy.h"
#include "wireless-phy.h"
#include "mobilenode.h"
#include "ip.h"
#include "dsr/hdr_sr.h"
#include "gridkeeper.h"
static class ChannelClass : public TclClass {
public:
ChannelClass() : TclClass("Channel") {}
TclObject* create(int, const char*const*) {
return (new Channel);
}
} class_channel;
/*static class DuplexChannelClass : public TclClass {
public:
DuplexChannelClass() : TclClass("Channel/Duplex") {}
TclObject* create(int, const char*const*) {
return (new DuplexChannel);
}
} class_channel_duplex; */
static class WirelessChannelClass : public TclClass {
public:
WirelessChannelClass() : TclClass("Channel/WirelessChannel") {}
TclObject* create(int, const char*const*) {
return (new WirelessChannel);
}
} class_Wireless_channel;
/* ==================================================================
NS Initialization Functions
=================================================================*/
static int ChannelIndex = 0;
Channel::Channel() : TclObject()
{
index_ = ChannelIndex++;
LIST_INIT(&ifhead_);
bind_time("delay_", &delay_);
}
int Channel::command(int argc, const char*const* argv)
{
if (argc == 3) {
TclObject *obj;
if( (obj = TclObject::lookup(argv[2])) == 0) {
fprintf(stderr, "%s lookup failed\n", argv[1]);
return TCL_ERROR;
}
if (strcmp(argv[1], "trace-target") == 0) {
trace_ = (Trace*) obj;
return (TCL_OK);
}
else if(strcmp(argv[1], "addif") == 0) {
((Phy*) obj)->insertchnl(&ifhead_);
((Phy*) obj)->setchnl(this);
return TCL_OK;
}
// add interface for grid_keeper_
/*else if(strncasecmp(argv[1], "grid_keeper", 5) == 0) {
grid_keeper_ = (GridKeeper*)obj;
return TCL_OK;
}*/
} else if (argc == 2) {
Tcl& tcl = Tcl::instance();
if (strcmp(argv[1], "trace-target") == 0) {
tcl.resultf("%s", trace_->name());
return (TCL_OK);
}
else if(strcmp(argv[1], "id") == 0) {
tcl.resultf("%d", index_);
return TCL_OK;
}
}
return TclObject::command(argc, argv);
}
void Channel::recv(Packet* p, Handler* h)
{
// Scheduler& s = Scheduler::instance();
// hdr_cmn::access(p)->direction() = hdr_cmn::UP;
// s.schedule(target_, p, txstop_ + delay_ - s.clock());
sendUp(p, (Phy*)h);
}
void
Channel::sendUp(Packet* p, Phy *tifp)
{
Scheduler &s = Scheduler::instance();
Phy *rifp = ifhead_.lh_first;
Node *tnode = tifp->node();
Node *rnode = 0;
Packet *newp;
double propdelay = 0.0;
struct hdr_cmn *hdr = HDR_CMN(p);
hdr->direction() = hdr_cmn::UP;
if (GridKeeper::instance()) {
int i;
GridKeeper* gk = GridKeeper::instance();
int size = gk->size_;
MobileNode **outlist = new MobileNode *[size];
// memset(outlist, 0, size * sizeof(MobileNode *));
int out_index = gk->get_neighbors((MobileNode*)tnode,
outlist);
for (i=0; i < out_index; i ++) {
newp = p->copy();
rnode = outlist[i];
propdelay = get_pdelay(tnode, rnode);
rifp = (rnode->ifhead_).lh_first;
for(; rifp; rifp = rifp->nextnode()){
if (rifp->channel() == this){
s.schedule(rifp, newp, propdelay);
break;
}
}
}
delete [] outlist;
} else {
for( ; rifp; rifp = rifp->nextchnl()) {
rnode = rifp->node();
if(rnode == tnode)
continue;
/*
* Each node needs to get their own copy of this packet.
* Since collisions occur at the receiver, we can have
* two nodes canceling and freeing the *same* simulation
* event.
*
*/
newp = p->copy();
propdelay = get_pdelay(tnode, rnode);
/*
* Each node on the channel receives a copy of the
* packet. The propagation delay determines exactly
* when the receiver's interface detects the first
* bit of this packet.
*/
s.schedule(rifp, newp, propdelay);
}
}
Packet::free(p);
}
double
Channel::get_pdelay(Node* /*tnode*/, Node* /*rnode*/)
{
// Dummy function
return delay_;
}
void
Channel::dump(void)
{
Phy *n;
fprintf(stdout, "Network Interface List\n");
for(n = ifhead_.lh_first; n; n = n->nextchnl() )
n->dump();
fprintf(stdout, "--------------------------------------------------\n");
}
// Wireless extensions
class MobileNode;
WirelessChannel::WirelessChannel(void) : Channel() {}
double
WirelessChannel::get_pdelay(Node* tnode, Node* rnode)
{
// Scheduler &s = Scheduler::instance();
MobileNode* tmnode = (MobileNode*)tnode;
MobileNode* rmnode = (MobileNode*)rnode;
double propdelay = 0;
propdelay = tmnode->propdelay(rmnode);
assert(propdelay >= 0.0);
if (propdelay == 0.0) {
/* if the propdelay is 0 b/c two nodes are on top of
each other, move them slightly apart -dam 7/28/98 */
propdelay = 2 * DBL_EPSILON;
//printf ("propdelay 0: %d->%d at %f\n",
// tmnode->address(), rmnode->address(), s.clock());
}
return propdelay;
}
// send():
// The packet occupies the channel for the transmission time, txtime
// If collision occur (>1 pkts overlap), corrupt all pkts involved
// by setting the error bit or discard them
// int Channel::send(Packet* p, Phy *tifp)
// {
// // without collision, return 0
// Scheduler& s = Scheduler::instance();
// double now = s.clock();
// // busy = time when the channel are still busy with earlier tx
// double busy = max(txstop_, cwstop_);
// // txstop = when the channel is no longer busy from this tx
// txstop_ = max(busy, now + txtime);
// // now < busy => collision
// // mark the pkt error bit, EF_COLLISION
// // drop if there is a drop target, drop_
// if (now < busy) {
// // if still transmit earlier packet, pkt_, then corrupt it
// if (pkt_ && pkt_->time_ > now) {
// hdr_cmn::access(pkt_)->error() |= EF_COLLISION;
// if (drop_) {
// s.cancel(pkt_);
// drop(pkt_);
// pkt_ = 0;
// }
// }
// // corrupts the current packet p, and drop if drop_ exists
// hdr_cmn::access(p)->error() |= EF_COLLISION;
// if (drop_) {
// drop(p);
// return 1;
// }
// }
// // if p was not dropped, call recv() or hand it to trace_ if present
// pkt_ = p;
// trace_ ? trace_->recv(p, 0) : recv(p, 0);
// return 0;
// }
// contention():
// The MAC calls this Channel::contention() to enter contention period
// It determines when the contention window is over, cwstop_,
// and schedule a callback to the MAC for the actual send()
// void Channel::contention(Packet* p, Handler* h)
// {
// Scheduler& s = Scheduler::instance();
// double now = s.clock();
// if (now > cwstop_) {
// cwstop_ = now + delay_;
// numtx_ = 0;
// }
// numtx_++;
// s.schedule(h, p, cwstop_ - now);
// }
// jam():
// Jam the channel for a period txtime
// Some MAC protocols use this to let other MAC detect collisions
// int Channel::jam(double txtime)
// {
// // without collision, return 0
// double now = Scheduler::instance().clock();
// if (txstop_ > now) {
// txstop_ = max(txstop_, now + txtime);
// return 1;
// }
// txstop_ = now + txtime;
// return (now < cwstop_);
// }
// int DuplexChannel::send(Packet* p, double txtime)
// {
// double now = Scheduler::instance().clock();
// txstop_ = now + txtime;
// trace_ ? trace_->recv(p, 0) : recv(p, 0);
// return 0;
// }
// void DuplexChannel::contention(Packet* p, Handler* h)
// {
// Scheduler::instance().schedule(h, p, delay_);
// numtx_ = 1;
// }
chost.cc
/* -*- 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 Daedalus 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.
*/
/*
* Functions invoked by TcpSessionAgent
*/
#include "nilist.h"
#include "chost.h"
#include "tcp-int.h"
#include "random.h"
CorresHost::CorresHost() : slink(), TcpFsAgent(),
lastackTS_(0), dontAdjustOwnd_(0), dontIncrCwnd_(0), rexmtSegCount_(0),
connWithPktBeforeFS_(NULL)
{
nActive_ = nTimeout_ = nFastRec_ = 0;
ownd_ = 0;
owndCorrection_ = 0;
closecwTS_ = 0;
connIter_ = new Islist_iter (conns_);
rtt_seg_ = NULL;
}
/*
* Open up the congestion window.
*/
void
CorresHost::opencwnd(int /*size*/, IntTcpAgent *sender)
{
if (cwnd_ < ssthresh_) {
/* slow-start (exponential) */
cwnd_ += 1;
} else {
/* linear */
//double f;
if (!proxyopt_) {
switch (wnd_option_) {
case 0:
if ((count_ = count_ + winInc_) >= cwnd_) {
count_ = 0;
cwnd_ += winInc_;
}
break;
case 1:
/* This is the standard algorithm. */
cwnd_ += winInc_ / cwnd_;
break;
default:
#ifdef notdef
/*XXX*/
error("illegal window option %d", wnd_option_);
#endif
abort();
}
} else { // proxy
switch (wnd_option_) {
case 0:
case 1:
if (sender->highest_ack_ >= sender->wndIncSeqno_) {
cwnd_ += winInc_;
sender->wndIncSeqno_ = 0;
}
break;
default:
#ifdef notdef
/*XXX*/
error("illegal window option %d", wnd_option_);
#endif
abort();
}
}
}
// if maxcwnd_ is set (nonzero), make it the cwnd limit
if (maxcwnd_ && (int(cwnd_) > maxcwnd_))
cwnd_ = maxcwnd_;
return;
}
void
CorresHost::closecwnd(int how, double ts, IntTcpAgent *sender)
{
if (proxyopt_) {
if (!sender || ts > sender->closecwTS_)
closecwnd(how, sender);
}
else {
if (ts > closecwTS_)
closecwnd(how, sender);
}
}
void
CorresHost::closecwnd(int how, IntTcpAgent *sender)
{
int sender_ownd = 0;
if (sender)
sender_ownd = sender->maxseq_ - sender->highest_ack_;
closecwTS_ = Scheduler::instance().clock();
if (proxyopt_) {
if (sender)
sender->closecwTS_ = closecwTS_;
how += 10;
}
switch (how) {
case 0:
case 10:
/* timeouts */
/*
* XXX we use cwnd_ instead of ownd_ here, which may not be
* appropriate if the sender does not fully utilize the
* available congestion window (ownd_ < cwnd_).
*/
ssthresh_ = int(cwnd_ * winMult_);
cwnd_ = int(wndInit_);
break;
case 1:
/* Reno dup acks, or after a recent congestion indication. */
/*
* XXX we use cwnd_ instead of ownd_ here, which may not be
* appropriate if the sender does not fully utilize the
* available congestion window (ownd_ < cwnd_).
*/
cwnd_ *= winMult_;
ssthresh_ = int(cwnd_);
if (ssthresh_ < 2)
ssthresh_ = 2;
break;
case 11:
/* Reno dup acks, or after a recent congestion indication. */
/* XXX fix this -- don't make it dependent on ownd */
cwnd_ = ownd_ - sender_ownd*(1-winMult_);
ssthresh_ = int(cwnd_);
if (ssthresh_ < 2)
ssthresh_ = 2;
break;
case 3:
case 13:
/* idle time >= t_rtxcur_ */
cwnd_ = wndInit_;
break;
default:
abort();
}
fcnt_ = 0.;
count_ = 0;
if (sender)
sender->count_ = 0;
}
Segment*
CorresHost::add_pkts(int /*size*/, int seqno, int sessionSeqno, int daddr, int dport,
int sport, double ts, IntTcpAgent *sender)
{
class Segment *news;
ownd_ += 1;
news = new Segment;
news->seqno_ = seqno;
news->sessionSeqno_ = sessionSeqno;
news->daddr_ = daddr;
news->dport_ = dport;
news->sport_ = sport;
news->ts_ = ts;
news->size_ = 1;
news->dupacks_ = 0;
news->later_acks_ = 0;
news->thresh_dupacks_ = 0;
news->partialack_ = 0;
news->rxmitted_ = 0;
news->sender_ = sender;
seglist_.append(news);
return news;
}
void
CorresHost::adjust_ownd(int size)
{
if (double(owndCorrection_) < size)
ownd_ -= min(double(ownd_), size - double(owndCorrection_));
owndCorrection_ -= min(double(owndCorrection_),size);
if (double(ownd_) < -0.5 || double(owndCorrection_ < -0.5))
printf("In adjust_ownd(): ownd_ = %g owndCorrection_ = %g\n", double(ownd_), double(owndCorrection_));
}
int
CorresHost::clean_segs(int /*size*/, Packet *pkt, IntTcpAgent *sender, int sessionSeqno, int amt_data_acked)
{
Segment *cur, *prev=NULL, *newseg;
int i;
//int rval = -1;
/* remove all acked pkts from list */
int latest_susp_loss = rmv_old_segs(pkt, sender, amt_data_acked);
/*
* XXX If no new data is acked and the last time we shrunk the window
* covers the most recent suspected loss, update the estimate of the amount
* of outstanding data.
*/
if (amt_data_acked == 0 && latest_susp_loss <= recover_ &&
!dontAdjustOwnd_ && last_cwnd_action_ != CWND_ACTION_TIMEOUT) {
owndCorrection_ += min(double(ownd_),1);
ownd_ -= min(double(ownd_),1);
}
/*
* A pkt is a candidate for retransmission if it is the leftmost one in the
* unacked window for the connection AND has at least NUMDUPACKS
* dupacks/later acks AND (at least one dupack OR a later packet also
* with the threshold number of dup/later acks). A pkt is also a candidate
* for immediate retransmission if it has partialack_ set, indicating that
* a partial new ack has been received for it.
*/
for (i=0; i < rexmtSegCount_; i++) {
int remove_flag = 0;
/*
* curArray_ only contains segments that are the first oldest
* unacked segments of their connection (i.e., they are at the left
* edge of their window) and have either received a
* partial ack and/or have received at least NUMDUPACKS
* dupacks/later acks. Thus, segments in curArray_ have a high
* probability (but not certain) of being eligible for
* retransmission. Using curArray_ avoids having to scan
* through all the segments.
*/
cur = curArray_[i];
prev = prevArray_[i];
if (cur->partialack_ || cur->dupacks_ > 0 ||
cur->sender_->num_thresh_dupack_segs_ > 1 ) {
if (cur->thresh_dupacks_) {
cur->thresh_dupacks_ = 0;
cur->sender_->num_thresh_dupack_segs_--;
}
if (cur->sessionSeqno_ <= recover_ &&
last_cwnd_action_ != CWND_ACTION_TIMEOUT /* XXX 2 */)
dontAdjustOwnd_ = 1;
if ((cur->sessionSeqno_ > recover_) ||
(last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)
|| (proxyopt_ && cur->seqno_ > cur->sender_->recover_)
|| (proxyopt_ && cur->sender_->last_cwnd_action_ == CWND_ACTION_TIMEOUT /* XXX 2 */)) {
/* new loss window */
closecwnd(1, cur->ts_, cur->sender_);
recover_ = sessionSeqno - 1;
last_cwnd_action_ = CWND_ACTION_DUPACK /* XXX 1 */;
cur->sender_->recover_ = cur->sender_->maxseq_;
cur->sender_->last_cwnd_action_ =
CWND_ACTION_DUPACK /* XXX 1 */;
dontAdjustOwnd_ = 0;
}
if ((newseg = cur->sender_->rxmit_last(TCP_REASON_DUPACK,
cur->seqno_, cur->sessionSeqno_, cur->ts_))) {
newseg->rxmitted_ = 1;
adjust_ownd(cur->size_);
if (!dontAdjustOwnd_) {
owndCorrection_ +=
min(double(ownd_),cur->dupacks_);
ownd_ -= min(double(ownd_),cur->dupacks_);
}
seglist_.remove(cur, prev);
remove_flag = 1;
delete cur;
}
/*
* if segment just removed used to be the one just previous
* to the next segment in the array, update prev for the
* next segment
*/
if (remove_flag && cur == prevArray_[i+1])
prevArray_[i+1] = prev;
}
}
rexmtSegCount_ = 0;
return(0);
}
int
CorresHost::rmv_old_segs(Packet *pkt, IntTcpAgent *sender, int amt_data_acked)
{
Islist_iter seg_iter(seglist_);
Segment *cur, *prev=0;
int found = 0;
int done = 0;
int new_data_acked = 0;
int partialack = 0;
int latest_susp_loss = -1;
hdr_tcp *tcph = (hdr_tcp*)pkt->access(off_tcp_);
if (tcph->ts_echo() > lastackTS_)
lastackTS_ = tcph->ts_echo();
while (((cur = seg_iter()) != NULL) &&
(!done || tcph->ts_echo() > cur->ts_)) {
int remove_flag = 0;
/* ack for older pkt of another connection */
if (sender != cur->sender_ && tcph->ts_echo() > cur->ts_) {
if (!disableIntLossRecov_)
cur->later_acks_++;
latest_susp_loss =
max(latest_susp_loss,cur->sessionSeqno_);
dontIncrCwnd_ = 1;
}
/* ack for same connection */
else if (sender == cur->sender_) {
/* found packet acked */
if (tcph->seqno() == cur->seqno_ &&
tcph->ts_echo() == cur->ts_)
found = 1;
/* higher ack => clean up acked packets */
if (tcph->seqno() >= cur->seqno_) {
adjust_ownd(cur->size_);
seglist_.remove(cur, prev);
remove_flag = 1;
new_data_acked += cur->size_;
if (new_data_acked >= amt_data_acked)
done = 1;
if (prev == cur)
prev = NULL;
if (cur == rtt_seg_)
rtt_seg_ = NULL;
delete cur;
if (seg_iter.get_cur() && prev)
seg_iter.set_cur(prev);
else if (seg_iter.get_cur())
seg_iter.set_cur(seg_iter.get_last());
}
/* partial new ack => rexmt immediately */
/* XXX should we check recover for session? */
else if (amt_data_acked > 0 &&
tcph->seqno() == cur->seqno_-1 &&
cur->seqno_ <= sender->recover_ &&
sender->last_cwnd_action_ == CWND_ACTION_DUPACK) {
cur->partialack_ = 1;
partialack = 1;
latest_susp_loss =
max(latest_susp_loss,cur->sessionSeqno_);
if (new_data_acked >= amt_data_acked)
done = 1;
dontIncrCwnd_ = 1;
}
/*
* If no new data has been acked AND this segment has
* not been retransmitted before AND the ack indicates
* that this is the next segment to be acked, then
* increment dupack count.
*/
else if (!amt_data_acked && !cur->rxmitted_ &&
tcph->seqno() == cur->seqno_-1) {
cur->dupacks_++;
latest_susp_loss =
max(latest_susp_loss,cur->sessionSeqno_);
done = 1;
dontIncrCwnd_ = 1;
}
}
if (cur->dupacks_+cur->later_acks_ >= NUMDUPACKS &&
!cur->thresh_dupacks_) {
cur->thresh_dupacks_ = 1;
cur->sender_->num_thresh_dupack_segs_++;
}
if (amt_data_acked==0 && tcph->seqno()==cur->seqno_-1)
done = 1;
/* XXX we could check for rexmt candidates here if we ignore
the num_thresh_dupack_segs_ check */
if (!remove_flag &&
cur->seqno_ == cur->sender_->highest_ack_ + 1 &&
(cur->dupacks_ + cur->later_acks_ >= NUMDUPACKS ||
cur->partialack_)) {
curArray_[rexmtSegCount_] = cur;
prevArray_[rexmtSegCount_] = prev;
rexmtSegCount_++;
}
if (!remove_flag)
prev = cur;
}
/* partial ack => terminate fast start mode */
if (partialack && fs_enable_ && fs_mode_) {
timeout(TCP_TIMER_RESET);
rexmtSegCount_ = 0;
}
return latest_susp_loss;
}
void
CorresHost::add_agent(IntTcpAgent *agent, int /*size*/, double winMult,
int winInc, int /*ssthresh*/)
{
if (nActive_ >= MAX_PARALLEL_CONN) {
printf("In add_agent(): reached limit of number of parallel conn (%d); returning\n", nActive_);
return;
}
nActive_++;
if ((!fixedIw_ && nActive_ > 1) || cwnd_ == 0)
cwnd_ += 1; /* XXX should this be done? */
wndInit_ = 1;
winMult_ = winMult;
winInc_ = winInc;
/* ssthresh_ = ssthresh;*/
conns_.append(agent);
}
int
CorresHost::ok_to_snd(int /*size*/)
{
if (ownd_ <= -0.5)
printf("In ok_to_snd(): ownd_ = %g owndCorrection_ = %g\n", double(ownd_), double(owndCorrection_));
return (cwnd_ >= ownd_+1);
}
classifier-addr.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996-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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "classifier-addr.h"
int AddressClassifier::classify(Packet *p) {
hdr_ip* iph = hdr_ip::access(p);
return mshift(iph->daddr());
};
static class AddressClassifierClass : public TclClass {
public:
AddressClassifierClass() : TclClass("Classifier/Addr") {}
TclObject* create(int, const char*const*) {
return (new AddressClassifier());
}
} class_address_classifier;
/* added for mobileip code Ya, 2/99*/
static class ReserveAddressClassifierClass : public TclClass {
public:
ReserveAddressClassifierClass() : TclClass("Classifier/Addr/Reserve") {}
TclObject* create(int, const char*const*) {
return (new ReserveAddressClassifier());
}
} class_reserve_address_classifier;
int ReserveAddressClassifier::command(int argc, const char*const* argv)
{
// Tcl& tcl = Tcl::instance();
if (argc == 3 && strcmp(argv[1],"reserve-port") == 0) {
reserved_ = atoi(argv[2]);
alloc((maxslot_ = reserved_ - 1));
return(TCL_OK);
}
return (AddressClassifier::command(argc, argv));
}
void ReserveAddressClassifier::clear(int slot)
{
slot_[slot] = 0;
if (slot == maxslot_) {
while (--maxslot_ >= reserved_ && slot_[maxslot_] == 0)
;
}
}
int ReserveAddressClassifier::classify(Packet *p) {
hdr_ip* iph = hdr_ip::access(p);
return iph->dport();
};
int ReserveAddressClassifier::getnxt(NsObject *nullagent)
{
int i;
for (i=reserved_; i < nslot_; i++)
if (slot_[i]==0 || slot_[i]==nullagent)
return i;
i=nslot_;
alloc(nslot_);
return i;
}
static class BcastAddressClassifierClass : public TclClass {
public:
BcastAddressClassifierClass() : TclClass("Classifier/Hash/Dest/Bcast") {}
TclObject* create(int, const char*const*) {
return (new BcastAddressClassifier());
}
} class_bcast_address_classifier;
NsObject* BcastAddressClassifier::find(Packet* p)
{
NsObject* node = NULL;
int cl = classify(p);
if (cl < 0 || cl >= nslot_ || (node = slot_[cl]) == 0) {
if (cl == BCAST_ADDR_MASK) {
// limited broadcast; assuming no such packet
// would be delivered back to sender
return bcast_recver_;
}
if (default_target_)
return default_target_;
/*
* Sigh. Can't pass the pkt out to tcl because it's
* not an object.
*/
Tcl::instance().evalf("%s no-slot %d", name(), cl);
/*
* Try again. Maybe callback patched up the table.
*/
cl = classify(p);
if (cl < 0 || cl >= nslot_ || (node = slot_[cl]) == 0)
return (NULL);
}
return (node);
}
int BcastAddressClassifier::command(int argc, const char*const* argv)
{
// Tcl& tcl = Tcl::instance();
if (argc == 3 && strcmp(argv[1],"bcast-receiver") == 0) {
bcast_recver_ = (NsObject*)TclObject::lookup(argv[2]);
return(TCL_OK);
}
return (AddressClassifier::command(argc, argv));
}
classifier-bst.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* classifier-bst.cc
* Copyright (C) 1999 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include
#include
#include
#include "config.h"
#include "packet.h"
#include "ip.h"
#include "classifier.h"
#include "classifier-mcast.h"
#include "address.h"
#include "trace.h"
#include "ump.h"
int hdr_ump::offset_;
struct upstream_info {
int dst;
int node_id;
char* oiflink;
struct upstream_info* next;
};
class MCastBSTClassifier : public MCastClassifier {
public:
MCastBSTClassifier();
~MCastBSTClassifier();
static const char STARSYM[]; //"source" field for shared trees
protected:
virtual int classify(Packet * p);
upstream_info *oif2RP_;
int32_t node_id_;
void insert_upstream_info(int dst);
virtual void recv(Packet *p, Handler *h);
void upstream_add(int dst, char *oif2RP, int node_id);
upstream_info* upstream_find(int dst);
};
const char MCastBSTClassifier::STARSYM[]= "x"; //"source" field for shared trees
static class MCastBSTClassifierClass : public TclClass {
public:
MCastBSTClassifierClass() : TclClass("Classifier/Multicast/BST") {}
TclObject* create(int, const char*const*) {
return (new MCastBSTClassifier());
}
} class_mcast_bidir_classifier;
MCastBSTClassifier::MCastBSTClassifier()
{
oif2RP_ = NULL;
node_id_ = -1;
}
MCastBSTClassifier::~MCastBSTClassifier()
{
clearAll();
}
int MCastBSTClassifier::classify(Packet *pkt)
{
hdr_cmn* h = hdr_cmn::access(pkt);
hdr_ip* ih = hdr_ip::access(pkt);
nsaddr_t src = ih->saddr(); /*XXX*/
nsaddr_t dst = ih->daddr();
int iface = h->iface();
Tcl& tcl = Tcl::instance();
hashnode* p = lookup(src, dst, iface);
//printf("%s, src %d, dst %d, iface %d, p %d\n", name(), src, dst, iface, p);
if (p == 0)
p = lookup_star(dst, iface);
if (p == 0) {
if ((p = lookup(src, dst)) == 0)
p = lookup_star(dst);
if (p == 0) {
// Didn't find an entry.
tcl.evalf("%s new-group %ld %ld %d cache-miss",
name(), src, dst, iface);
// XXX see McastProto.tcl for the return values 0 -
// once, 1 - twice
//printf("cache-miss result= %s\n", tcl.result());
int res= atoi(tcl.result());
if (res)
insert_upstream_info(dst);
return (res)? Classifier::TWICE : Classifier::ONCE;
}
if (p->iif == ANY_IFACE.value()) // || iface == UNKN_IFACE.value())
return p->slot;
tcl.evalf("%s new-group %ld %ld %d wrong-iif",
name(), src, dst, iface);
//printf("wrong-iif result= %s\n", tcl.result());
int res= atoi(tcl.result());
return (res)? Classifier::TWICE : Classifier::ONCE;
}
return p->slot;
}
void MCastBSTClassifier::recv(Packet *p, Handler *h)
{
hdr_cmn* h_cmn = hdr_cmn::access(p);
hdr_ip* ih = hdr_ip::access(p);
hdr_ump* ump = hdr_ump::access(p);
nsaddr_t dst = ih->daddr();
Tcl& tcl = Tcl::instance();
upstream_info *u_info;
if (node_id_ == -1) {
tcl.evalf("[%s set node_] id", name());
sscanf(tcl.result(), "%d", &node_id_);
} // if
nsaddr_t src = ih->saddr(); /*XXX*/
NsObject *node = find(p);
if (node == NULL) {
Packet::free(p);
return;
} // if
if ((node_id_ != src) && (ump->isSet) && (ump->umpID_ != node_id_)) {
// If this node is not the next hop upstream router,
// and if there are no receivers connected to it, then
// we should immediately drop the packet before we
// trigger a chace miss
int rpf_iface;
tcl.evalf("%s check-rpf-link %d %d", name(), node_id_, dst);
sscanf(tcl.result(), "%d", &rpf_iface);
if (rpf_iface != h_cmn->iface()) {
// The RPF check has failed so we have to drop
// the packet. Otherwise, we will create
// duplicate packets on the net.
Packet::free(p);
return;
// The following code demonstrates how we
// could generate duplicates if RPF check is
// ignord. Do not reset the UMP and then we
// will have even more duplicates. Remember
// to comment out the previous two lines
// ih->flowid()++;
} else
ump->isSet = 0;
} // if
if (src == node_id_) {
memset(ump, 0, sizeof(hdr_ump)); // Initialize UMP to 0
// We need to set the UMP option. We need to find the
// next hop router to the source and place it in the
// UMP option.
u_info = upstream_find(dst);
if (!u_info) {
printf("Error: Mcast info does not exist\n");
exit(0);
} // if
ump->isSet = 1;
ump->umpID_ = node_id_;
} // if
// if (ump->isSet) {
// if (ump->umpID_ != node_id_) {
// // By now we are sure that the packet has
// // arrived on an RPF link. So the UMP portion
// // of the packet should be cleared before it
// // is sent downstream
// ump->isSet = 0;
// } // if
// } // if
if (ump->isSet) {
u_info = upstream_find(dst);
if (node_id_ == u_info->node_id)
// If the next hop is the node itself, then we
// are at the RP.
ump->isSet = 0;
else {
ump->umpID_ = u_info->node_id;
ump->oif = strdup(u_info->oiflink);
} // else
} else {
int match;
tcl.evalf("%s match-BST-iif %d %d", name(),
h_cmn->iface(), dst);
sscanf(tcl.result(), "%d", (int *)&match);
if (!match) {
Packet::free(p);
return;
} // else
} // else
node->recv(p, h);
} // MCastBSTClassifier::recv
void MCastBSTClassifier::upstream_add(int dst, char *link, int node_id)
{
struct upstream_info *next,
*current;
if (oif2RP_) {
next = oif2RP_;
do {
current = next;
if (current->dst == dst) {
free(current->oiflink);
current->oiflink = strdup(link);
current->node_id = node_id;
return;
} // if
next = current->next;
} while (next);
next = new(struct upstream_info);
next->dst = dst;
next->oiflink = strdup(link);
next->node_id = node_id;
current->next = next;
} else {
oif2RP_ = new(struct upstream_info);
oif2RP_->dst = dst;
oif2RP_->oiflink = strdup(link);
oif2RP_->node_id = node_id;
oif2RP_->next = NULL;
} // else
} // MCastBSTClassifier::upstream_add
upstream_info* MCastBSTClassifier::upstream_find(int dst)
{
upstream_info *index;
index = oif2RP_;
while (index) {
if (index->dst == dst)
return index;
index = index->next;
} // while
return NULL;
} // MCastBSTClassifier::upstream_find
void MCastBSTClassifier::insert_upstream_info(int dst)
{
char temp_str[100];
int nodeID;
Tcl& tcl = Tcl::instance();
tcl.evalf("%s info class", name());
sscanf(tcl.result(), "%s", temp_str);
tcl.evalf("%s upstream-link %d", name(), dst);
sscanf(tcl.result(), "%s %d", temp_str, &nodeID);
upstream_add(dst, temp_str, nodeID);
} // MCastBSTClassifier::insert_upstream_info
classifier-hash.cc
/* -*- 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$ (LBL)";
#endif
//
// a generalized classifier for mapping (src/dest/flowid) fields
// to a bucket. "buckets_" worth of hash table entries are created
// at init time, and other entries in the same bucket are created when
// needed
//
//
extern "C" {
#include
}
#include
#include "config.h"
#include "packet.h"
#include "ip.h"
#include "classifier.h"
#include "classifier-hash.h"
/****************** HashClassifier Methods ************/
int HashClassifier::classify(Packet * p) {
int slot= lookup(p);
if (slot >= 0 && slot <=maxslot_)
return (slot);
else if (default_ >= 0)
return (default_);
return (unknown(p));
} // HashClassifier::classify
int HashClassifier::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
/*
* $classifier set-hash $hashbucket src dst fid $slot
*/
if (argc == 7) {
if (strcmp(argv[1], "set-hash") == 0) {
//xxx: argv[2] is ignored for now
nsaddr_t src = atoi(argv[3]);
nsaddr_t dst = atoi(argv[4]);
int fid = atoi(argv[5]);
int slot = atoi(argv[6]);
if (0 > set_hash(src, dst, fid, slot))
return TCL_ERROR;
return TCL_OK;
}
} else if (argc == 6) {
/* $classifier lookup $hashbuck $src $dst $fid */
if (strcmp(argv[1], "lookup") == 0) {
nsaddr_t src = atoi(argv[3]);
nsaddr_t dst = atoi(argv[4]);
int fid = atoi(argv[5]);
int slot= get_hash(src, dst, fid);
if (slot>=0 && slot <=maxslot_) {
tcl.resultf("%s", slot_[slot]->name());
return (TCL_OK);
}
tcl.resultf("");
return (TCL_OK);
}
} else if (argc == 5) {
/* $classifier del-hash src dst fid */
if (strcmp(argv[1], "del-hash") == 0) {
nsaddr_t src = atoi(argv[2]);
nsaddr_t dst = atoi(argv[3]);
int fid = atoi(argv[4]);
Tcl_HashEntry *ep= Tcl_FindHashEntry(&ht_,
hashkey(src, dst,
fid));
if (ep) {
int slot= (int)Tcl_GetHashValue(ep);
Tcl_DeleteHashEntry(ep);
tcl.resultf("%u", slot);
return (TCL_OK);
}
return (TCL_ERROR);
}
}
return (Classifier::command(argc, argv));
}
/************** TCL linkage ****************/
static class SrcDestHashClassifierClass : public TclClass {
public:
SrcDestHashClassifierClass() : TclClass("Classifier/Hash/SrcDest") {}
TclObject* create(int, const char*const*) {
return new SrcDestHashClassifier;
}
} class_hash_srcdest_classifier;
static class FidHashClassifierClass : public TclClass {
public:
FidHashClassifierClass() : TclClass("Classifier/Hash/Fid") {}
TclObject* create(int, const char*const*) {
return new FidHashClassifier;
}
} class_hash_fid_classifier;
static class DestHashClassifierClass : public TclClass {
public:
DestHashClassifierClass() : TclClass("Classifier/Hash/Dest") {}
TclObject* create(int, const char*const*) {
return new DestHashClassifier;
}
} class_hash_dest_classifier;
static class SrcDestFidHashClassifierClass : public TclClass {
public:
SrcDestFidHashClassifierClass() : TclClass("Classifier/Hash/SrcDestFid") {}
TclObject* create(int, const char*const*) {
return new SrcDestFidHashClassifier;
}
} class_hash_srcdestfid_classifier;
// DestHashClassifier methods
int DestHashClassifier::classify(Packet *p)
{
int slot= lookup(p);
if (slot >= 0 && slot <=maxslot_)
return (slot);
else if (default_ >= 0)
return (default_);
return -1;
} // HashClassifier::classify
int DestHashClassifier::command(int argc, const char*const* argv)
{
if (argc == 4) {
// $classifier install $dst $node
if (strcmp(argv[1], "install") == 0) {
nsaddr_t dst = atoi(argv[2]);
NsObject *node = (NsObject*)TclObject::lookup(argv[3]);
int slot = getnxt(node);
install(slot, node);
if (set_hash(0, dst, 0, slot) >= 0)
return TCL_OK;
else
return TCL_ERROR;
} // if
}
return(HashClassifier::command(argc, argv));
} // command
classifier-mac.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996-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.
*
* Contributed by Giao Nguyen, http://daedalus.cs.berkeley.edu/~gnguyen
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include "packet.h"
#include "mac.h"
#include "classifier.h"
class MacClassifier : public Classifier {
public:
MacClassifier() : bcast_(0) {
bind("bcast_", &bcast_);
}
void recv(Packet*, Handler*);
int bcast_;
};
static class MacClassifierClass : public TclClass {
public:
MacClassifierClass() : TclClass("Classifier/Mac") {}
TclObject* create(int, const char*const*) {
return (new MacClassifier());
}
} class_mac_classifier;
void MacClassifier::recv(Packet* p, Handler*)
{
Mac* mac;
hdr_mac* mh = HDR_MAC(p);
if (bcast_ || mh->macDA() == BCAST_ADDR || (mac = (Mac *)find(p)) == 0) {
// Replicate packets to all slots (broadcast)
int macSA = mh->macSA();
for (int i = 0; i < maxslot_; ++i) {
if ((mac = (Mac *)slot_[i]) && mac->addr() != macSA)
mac->recv(p->copy(), 0);
}
if (maxslot_ >= 0) {
mac= (Mac *)slot_[maxslot_];
if (mac->addr() != macSA) {
mac->recv(p, 0);
return;
}
}
Packet::free(p);
return;
}
mac->recv(p, 0);
}
classifier-mcast.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996-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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include
#include "config.h"
#include "packet.h"
#include "ip.h"
#include "classifier.h"
#include "classifier-mcast.h"
const char MCastClassifier::STARSYM[]= "x"; //"source" field for shared trees
static class MCastClassifierClass : public TclClass {
public:
MCastClassifierClass() : TclClass("Classifier/Multicast") {}
TclObject* create(int, const char*const*) {
return (new MCastClassifier());
}
} class_mcast_classifier;
MCastClassifier::MCastClassifier()
{
memset(ht_, 0, sizeof(ht_));
memset(ht_star_, 0, sizeof(ht_star_));
}
MCastClassifier::~MCastClassifier()
{
clearAll();
}
void MCastClassifier::clearHash(hashnode* h[], int size)
{
for (int i = 0; i < size; ++i) {
hashnode* p = h[i];
while (p != 0) {
hashnode* n = p->next;
delete p;
p = n;
}
}
memset(h, 0, size * sizeof(hashnode*));
}
void MCastClassifier::clearAll()
{
clearHash(ht_, HASHSIZE);
clearHash(ht_star_, HASHSIZE);
}
MCastClassifier::hashnode*
MCastClassifier::lookup(nsaddr_t src, nsaddr_t dst, int iface) const
{
int h = hash(src, dst);
hashnode* p;
for (p = ht_[h]; p != 0; p = p->next) {
if (p->src == src && p->dst == dst)
if (p->iif == iface ||
//p->iif == UNKN_IFACE.value() ||
iface == ANY_IFACE.value())
break;
}
return (p);
}
MCastClassifier::hashnode*
MCastClassifier::lookup_star(nsaddr_t dst, int iface) const
{
int h = hash(0, dst);
hashnode* p;
for (p = ht_star_[h]; p != 0; p = p->next) {
if (p->dst == dst &&
(iface == ANY_IFACE.value() || p->iif == iface))
break;
}
return (p);
}
int MCastClassifier::classify(Packet *pkt)
{
hdr_cmn* h = hdr_cmn::access(pkt);
hdr_ip* ih = hdr_ip::access(pkt);
nsaddr_t src = ih->saddr();
nsaddr_t dst = ih->daddr();
int iface = h->iface();
Tcl& tcl = Tcl::instance();
hashnode* p = lookup(src, dst, iface);
//printf("%s, src %d, dst %d, iface %d, p %d\n", name(), src, dst, iface, p);
if (p == 0)
p = lookup_star(dst, iface);
if (p == 0) {
if ((p = lookup(src, dst)) == 0)
p = lookup_star(dst);
if (p == 0) {
// Didn't find an entry.
tcl.evalf("%s new-group %ld %ld %d cache-miss",
name(), src, dst, iface);
// XXX see McastProto.tcl for the return values 0 -
// once, 1 - twice
//printf("cache-miss result= %s\n", tcl.result());
int res= atoi(tcl.result());
return (res)? Classifier::TWICE : Classifier::ONCE;
}
if (p->iif == ANY_IFACE.value()) // || iface == UNKN_IFACE.value())
return p->slot;
tcl.evalf("%s new-group %ld %ld %d wrong-iif",
name(), src, dst, iface);
//printf("wrong-iif result= %s\n", tcl.result());
int res= atoi(tcl.result());
return (res)? Classifier::TWICE : Classifier::ONCE;
}
return p->slot;
}
int MCastClassifier::findslot()
{
int i;
for (i = 0; i < nslot_; ++i)
if (slot_[i] == 0)
break;
return (i);
}
void MCastClassifier::set_hash(hashnode* ht[], nsaddr_t src, nsaddr_t dst,
int slot, int iface)
{
int h = hash(src, dst);
hashnode* p = new hashnode;
p->src = src;
p->dst = dst;
p->slot = slot;
p->iif = iface;
p->next = ht[h];
ht[h] = p;
}
int MCastClassifier::command(int argc, const char*const* argv)
{
if (argc == 6) {
if (strcmp(argv[1], "set-hash") == 0) {
// $classifier set-hash $src $group $slot $iif
// $iif can be:(1)
// (2) "*" - matches any interface
// (3) "?" - interface is unknown (usually this means that
// the packet came from a local agent)
nsaddr_t src = strtol(argv[2], (char**)0, 0);
nsaddr_t dst = strtol(argv[3], (char**)0, 0);
int slot = atoi(argv[4]);
int iface = (strcmp(argv[5], ANY_IFACE.name())==0) ? ANY_IFACE.value()
: (strcmp(argv[5], UNKN_IFACE.name())==0) ? UNKN_IFACE.value()
: atoi(argv[5]);
if (strcmp(STARSYM, argv[2]) == 0) {
// install a entry: give 0 as src, but can be anything
set_hash(ht_star_, 0, dst, slot, iface);
} else {
//install a entry
set_hash(ht_, src, dst, slot, iface);
}
return (TCL_OK);
}
if (strcmp(argv[1], "change-iface") == 0) {
// $classifier change-iface $src $dst $olfiif $newiif
nsaddr_t src = strtol(argv[2], (char**)0, 0);
nsaddr_t dst = strtol(argv[3], (char**)0, 0);
int oldiface = atoi(argv[4]);
int newiface = atoi(argv[5]);
if (strcmp(STARSYM, argv[2]) == 0) {
change_iface(dst, oldiface, newiface);
} else {
change_iface(src, dst, oldiface, newiface);
}
return (TCL_OK);
}
} else if (argc == 5) {
if (strcmp(argv[1], "lookup") == 0) {
// $classifier lookup $src $group $iface
// returns name of the object (replicator)
Tcl &tcl = Tcl::instance();
nsaddr_t src = strtol(argv[2], (char**)0, 0);
nsaddr_t dst = strtol(argv[3], (char**)0, 0);
int iface = atoi(argv[4]);
hashnode* p= (strcmp(STARSYM, argv[2]) == 0) ? lookup_star(dst, iface)
: lookup(src, dst, iface);
if ((p == 0) || (slot_[p->slot] == 0))
tcl.resultf("");
else
tcl.resultf("%s", slot_[p->slot]->name());
return (TCL_OK);
}
} else if (argc == 4) {
if (strcmp(argv[1], "lookup-iface") == 0) {
// $classifier lookup-iface $src $group
// returns incoming iface
Tcl &tcl = Tcl::instance();
nsaddr_t src = strtol(argv[2], (char**)0, 0);
nsaddr_t dst = strtol(argv[3], (char**)0, 0);
hashnode* p= (strcmp(argv[2], STARSYM) == 0) ? lookup_star(dst)
: lookup(src, dst);
if (p == 0)
tcl.resultf("");
else
tcl.resultf("%d", p->iif);
return (TCL_OK);
}
} else if (argc == 2) {
if (strcmp(argv[1], "clearAll") == 0) {
clearAll();
return (TCL_OK);
}
}
return (Classifier::command(argc, argv));
}
/* interface look up for the interface code*/
void MCastClassifier::change_iface(nsaddr_t src, nsaddr_t dst, int oldiface, int newiface)
{
hashnode* p = lookup(src, dst, oldiface);
if (p) p->iif = newiface;
}
void MCastClassifier::change_iface(nsaddr_t dst, int oldiface, int newiface)
{
hashnode* p = lookup_star(dst, oldiface);
if (p) p->iif = newiface;
}
classifier-mpath.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* classifier-mpath.cc
*
* Copyright (C) 1997 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (USC/ISI)";
#endif
#include "classifier.h"
class MultiPathForwarder : public Classifier {
public:
MultiPathForwarder() : ns_(0) {}
virtual int classify(Packet*) {
int cl;
int fail = ns_;
do {
cl = ns_++;
ns_ %= (maxslot_ + 1);
} while (slot_[cl] == 0 && ns_ != fail);
return cl;
}
private:
int ns_;
};
static class MultiPathClass : public TclClass {
public:
MultiPathClass() : TclClass("Classifier/MultiPath") {}
TclObject* create(int, const char*const*) {
return (new MultiPathForwarder());
}
} class_multipath;
classifier-port.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* classifier-port.cc
* Copyright (C) 1999 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#) $Header$ (USC/ISI)
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "classifier-port.h"
int PortClassifier::classify(Packet *p) {
// Port classifier returns the destination port. No shifting
// or masking is required since in the 32-bit addressing,
// ports are stored in a seperate variable.
hdr_ip* iph = hdr_ip::access(p);
return iph->dport();
};
static class PortClassifierClass : public TclClass {
public:
PortClassifierClass() : TclClass("Classifier/Port") {}
TclObject* create(int, const char*const*) {
return (new PortClassifier());
}
} class_address_classifier;
static class ReservePortClassifierClass : public TclClass {
public:
ReservePortClassifierClass() : TclClass("Classifier/Port/Reserve") {}
TclObject* create(int, const char*const*) {
return (new ReservePortClassifier());
}
} class_reserve_port_classifier;
int ReservePortClassifier::command(int argc, const char*const* argv)
{
// Tcl& tcl = Tcl::instance();
if (argc == 3 && strcmp(argv[1],"reserve-port") == 0) {
reserved_ = atoi(argv[2]);
alloc((maxslot_ = reserved_ - 1));
return(TCL_OK);
}
return (Classifier::command(argc, argv));
}
void ReservePortClassifier::clear(int slot)
{
slot_[slot] = 0;
if (slot == maxslot_) {
while (--maxslot_ >= reserved_ && slot_[maxslot_] == 0)
;
}
}
int ReservePortClassifier::getnxt(NsObject *nullagent)
{
int i;
for (i=reserved_; i < nslot_; i++)
if (slot_[i]==0 || slot_[i]==nullagent)
return i;
i=nslot_;
alloc(nslot_);
return i;
}
classifier-virtual.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996-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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
extern "C" {
#include
}
#include "config.h"
#include "packet.h"
#include "ip.h"
#include "classifier.h"
#include "route.h"
#include "object.h"
#include "address.h"
#include
class VirtualClassifier : public Classifier {
public:
VirtualClassifier() : routelogic_(0) {
Tcl_InitHashTable(&ht_, TCL_ONE_WORD_KEYS);
}
~VirtualClassifier() {
Tcl_DeleteHashTable(&ht_);
}
protected:
NsObject* next_;
Tcl_HashTable ht_;
RouteLogic *routelogic_;
NsObject* target_;
bool enableHrouting_;
char nodeaddr_[SMALL_LEN];
int classify(Packet *const p) {
hdr_ip* iph = hdr_ip::access(p);
return mshift(iph->daddr());
}
void recv(Packet* p, Handler* h) {
if (!routelogic_) {
Tcl &tcl = Tcl::instance();
tcl.eval("[Simulator instance] get-routelogic");
routelogic_= (RouteLogic*) TclObject::lookup(tcl.result());
//tcl.evalf("%s info class", tcl.result());
//cout << "created..." << tcl.result() << endl;
}
/* first we find the next hop by asking routelogic
* then we use a hash next_hop -> target_object
* thus, the size of the table is at most N-1
*/
Tcl &tcl = Tcl::instance();
hdr_ip* iph = hdr_ip::access(p);
char* adst= Address::instance().print_nodeaddr(iph->daddr());
//adst[strlen(adst)-1]= 0;
target_= 0;
int next_hopIP;
routelogic_->lookup_flat(nodeaddr_, adst, next_hopIP);
delete [] adst;
int newEntry;
Tcl_HashEntry *ep= Tcl_CreateHashEntry(&ht_, (const char*)next_hopIP,
&newEntry);
if (newEntry) {
tcl.evalf("%s find %d", name(), next_hopIP);
Tcl_SetHashValue(ep, target_= (NsObject*)tcl.lookup(tcl.result()));
} else {
target_= (NsObject*)Tcl_GetHashValue(ep);
}
if (!target_) {
/*
* XXX this should be "dropped" somehow. Right now,
* these events aren't traced.
*/
Packet::free(p);
return;
}
target_->recv(p,h);
}
int command(int argc, const char*const* argv) {
if (argc == 3) {
if (strcmp(argv[1], "nodeaddr") == 0) {
strcpy(nodeaddr_, argv[2]);
return(TCL_OK);
}
}
return (NsObject::command(argc, argv));
}
};
static class VirtualClassifierClass : public TclClass {
public:
VirtualClassifierClass() : TclClass("Classifier/Virtual") {}
TclObject* create(int, const char*const*) {
return (new VirtualClassifier());
}
} class_virtual_classifier;
classifier.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include
#include "config.h"
#include "classifier.h"
#include "packet.h"
static class ClassifierClass : public TclClass {
public:
ClassifierClass() : TclClass("Classifier") {}
TclObject* create(int, const char*const*) {
return (new Classifier());
}
} class_classifier;
Classifier::Classifier() : slot_(0), nslot_(0), maxslot_(-1)
, shift_(0), mask_(0xffffffff)
{
default_target_ = 0;
bind("offset_", &offset_);
bind("shift_", &shift_);
bind("mask_", &mask_);
}
int Classifier::classify(Packet *p)
{
return (mshift(*((int*) p->access(offset_))));
}
Classifier::~Classifier()
{
delete [] slot_;
}
void Classifier::alloc(int slot)
{
NsObject** old = slot_;
int n = nslot_;
if (old == 0)
nslot_ = 32;
while (nslot_ <= slot)
nslot_ <<= 1;
slot_ = new NsObject*[nslot_];
memset(slot_, 0, nslot_ * sizeof(NsObject*));
for (int i = 0; i < n; ++i)
slot_[i] = old[i];
delete [] old;
}
void Classifier::install(int slot, NsObject* p)
{
if (slot >= nslot_)
alloc(slot);
slot_[slot] = p;
if (slot >= maxslot_)
maxslot_ = slot;
}
void Classifier::clear(int slot)
{
slot_[slot] = 0;
if (slot == maxslot_) {
while (--maxslot_ >= 0 && slot_[maxslot_] == 0)
;
}
}
int Classifier::getnxt(NsObject *nullagent)
{
int i;
for (i=0; i < nslot_; i++)
if (slot_[i]==0 || slot_[i]==nullagent)
return i;
i=nslot_;
alloc(nslot_);
return i;
}
/*
* objects only ever see "packet" events, which come either
* from an incoming link or a local agent (i.e., packet source).
*/
void Classifier::recv(Packet* p, Handler*h)
{
NsObject* node = find(p);
if (node == NULL) {
/*
* XXX this should be "dropped" somehow. Right now,
* these events aren't traced.
*/
Packet::free(p);
return;
}
node->recv(p,h);
}
/*
* perform the mapping from packet to object
* perform upcall if no mapping
*/
NsObject* Classifier::find(Packet* p)
{
NsObject* node = NULL;
int cl = classify(p);
if (cl < 0 || cl >= nslot_ || (node = slot_[cl]) == 0) {
if (default_target_) return default_target_;
/*
* Sigh. Can't pass the pkt out to tcl because it's
* not an object.
*/
Tcl::instance().evalf("%s no-slot %ld", name(), cl);
if (cl == TWICE) {
/*
* Try again. Maybe callback patched up the table.
*/
cl = classify(p);
if (cl < 0 || cl >= nslot_ || (node = slot_[cl]) == 0)
return (NULL);
}
}
return (node);
}
int Classifier::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if(argc == 2) {
if (strcmp(argv[1], "defaulttarget") == 0) {
if (default_target_ != 0)
tcl.result(default_target_->name());
return (TCL_OK);
}
}
if (argc == 3) {
/*
* $classifier alloc-port nullagent
*/
if (strcmp(argv[1],"alloc-port") == 0) {
int slot;
NsObject* nullagent =(NsObject*)TclObject::lookup(argv[2]);
slot=getnxt(nullagent);
tcl.resultf("%u",slot);
return(TCL_OK);
}
/*
* $classifier clear $slot
*/
if (strcmp(argv[1], "clear") == 0) {
int slot = atoi(argv[2]);
clear(slot);
return (TCL_OK);
}
/*
* $classifier installNext $node
*/
if (strcmp(argv[1], "installNext") == 0) {
int slot = maxslot_ + 1;
NsObject* node = (NsObject*)TclObject::lookup(argv[2]);
if (node == NULL) {
tcl.resultf("Classifier::installNext attempt to install non-object %s into classifier", argv[2]);
return TCL_ERROR;
};
install(slot, node);
tcl.resultf("%u", slot);
return TCL_OK;
}
/*
* $classifier slot snum
* returns the name of the object in slot # snum
*/
if (strcmp(argv[1], "slot") == 0) {
int slot = atoi(argv[2]);
if (slot >= 0 && slot < nslot_ && slot_[slot] != NULL) {
tcl.resultf("%s", slot_[slot]->name());
return TCL_OK;
}
tcl.resultf("Classifier: no object at slot %d", slot);
return (TCL_ERROR);
}
/*
* $classifier findslot $node
* finds the slot containing $node
*/
if (strcmp(argv[1], "findslot") == 0) {
int slot = 0;
NsObject* node = (NsObject*)TclObject::lookup(argv[2]);
if (node == NULL) {
return (TCL_ERROR);
}
while (slot < nslot_) {
if (strcmp(slot_[slot]->name(), argv[2]) == 0) {
tcl.resultf("%u", slot);
return (TCL_OK);
}
slot++;
}
tcl.result("-1");
return (TCL_OK);
}
if(strcmp(argv[1], "defaulttarget") == 0) {
default_target_=(NsObject*)TclObject::lookup(argv[2]);
if(default_target_ == 0)
return TCL_ERROR;
return TCL_OK;
}
} else if (argc == 4) {
/*
* $classifier install $slot $node
*/
if (strcmp(argv[1], "install") == 0) {
int slot = atoi(argv[2]);
NsObject* node = (NsObject*)TclObject::lookup(argv[3]);
install(slot, node);
return (TCL_OK);
}
}
return (NsObject::command(argc, argv));
}
cmu-trace.cc
/* -*- 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*
* Ported from CMU/Monarch's code, appropriate copyright applies.
* nov'98 -Padma.
*
* $Header$
*/
#include
#include
#include
#include
#include
#include // DSR
#include
#include
#include
#include //TORA
#include // IMEP
#include //AODV
#include
#include
//#define LOG_POSITION
//extern char* pt_names[];
static class CMUTraceClass : public TclClass {
public:
CMUTraceClass() : TclClass("CMUTrace") { }
TclObject* create(int, const char*const* argv) {
return (new CMUTrace(argv[4], *argv[5]));
}
} cmutrace_class;
CMUTrace::CMUTrace(const char *s, char t) : Trace(t)
{
bzero(tracename, sizeof(tracename));
strncpy(tracename, s, MAX_ID_LEN);
if(strcmp(tracename, "RTR") == 0) {
tracetype = TR_ROUTER;
}
else if(strcmp(tracename, "TRP") == 0) {
tracetype = TR_ROUTER;
}
else if(strcmp(tracename, "MAC") == 0) {
tracetype = TR_MAC;
}
else if(strcmp(tracename, "IFQ") == 0) {
tracetype = TR_IFQ;
}
else if(strcmp(tracename, "AGT") == 0) {
tracetype = TR_AGENT;
}
else {
fprintf(stderr, "CMU Trace Initialized with invalid type\n");
exit(1);
}
assert(type_ == DROP || type_ == SEND || type_ == RECV);
newtrace_ = 0;
for (int i=0 ; i < MAX_NODE ; i++) nodeColor[i] = 3 ;
node_ = 0;
off_mac_ = hdr_mac::offset_;
//bind("off_mac_", &off_mac_);
bind("off_arp_", &off_arp_);
bind("off_SR_", &off_sr_);
bind("off_TORA_", &off_TORA_);
bind("off_IMEP_", &off_IMEP_);
bind("off_AODV_", &off_AODV_);
}
void
CMUTrace::format_mac(Packet *p, const char *why, int offset)
{
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
struct hdr_mac802_11 *mh = HDR_MAC802_11(p);
double x = 0.0, y = 0.0, z = 0.0;
char op = (char) type_;
Node* thisnode = Node::get_node_by_address(src_);
double energy = -1;
if (thisnode) {
if (thisnode->energy_model()) {
energy = thisnode->energy();
}
}
// hack the IP address to convert pkt format to hostid format
// for now until port ids are removed from IP address. -Padma.
int src = Address::instance().get_nodeaddr(ih->saddr());
if(tracetype == TR_ROUTER && type_ == SEND) {
if(src_ != src)
op = FWRD;
}
// Use new ns trace format to replace the old cmu trace format)
if (newtrace_) {
node_->getLoc(&x, &y, &z);
// consistence
if ( op == DROP ) { op = 'd';}
// basic trace infomation + basic exenstion
sprintf(wrk_ + offset,
"%c -t %.9f -Hs %d -Hd %d -Ni %d -Nx %.2f -Ny %.2f -Nz %.2f -Ne %f -Nl %3s -Nw %s ",
op, // event type
Scheduler::instance().clock(), // time
src_, // this node
ch->next_hop_, // next hop
src_, // this node
x, // x coordinate
y, // y coordinate
z, // z coordinate
energy, // energy, -1 = not existing
tracename, // trace level
why); // reason
// mac layer extension
offset = strlen(wrk_);
sprintf(wrk_ + offset,
"-Ma %x -Md %x -Ms %x -Mt %x ",
mh->dh_duration,
ETHER_ADDR(mh->dh_da),
ETHER_ADDR(mh->dh_sa),
GET_ETHER_TYPE(mh->dh_body));
return;
}
#ifdef LOG_POSITION
double x = 0.0, y = 0.0, z = 0.0;
node_->getLoc(&x, &y, &z);
#endif
sprintf(wrk_ + offset,
#ifdef LOG_POSITION
"%c %.9f %d (%6.2f %6.2f) %3s %4s %d %s %d [%x %x %x %x] ",
#else
"%c %.9f _%d_ %3s %4s %d %s %d [%x %x %x %x] ",
#endif
op,
Scheduler::instance().clock(),
src_, // this node
#ifdef LOG_POSITION
x,
y,
#endif
tracename,
why,
ch->uid(), // identifier for this event
packet_info.name(ch->ptype()),
ch->size(),
//*((u_int16_t*) &mh->dh_fc),
mh->dh_duration,
ETHER_ADDR(mh->dh_da),
ETHER_ADDR(mh->dh_sa),
GET_ETHER_TYPE(mh->dh_body));
offset = strlen(wrk_);
if (thisnode) {
if (thisnode->energy_model()) {
sprintf(wrk_ + offset,
"[energy %f] ",
thisnode->energy());
}
}
}
void
CMUTrace::format_ip(Packet *p, int offset)
{
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
// hack the IP address to convert pkt format to hostid format
// for now until port ids are removed from IP address. -Padma.
int src = Address::instance().get_nodeaddr(ih->saddr());
int dst = Address::instance().get_nodeaddr(ih->daddr());
if (newtrace_) {
sprintf(wrk_ + offset,
"-Is %d.%d -Id %d.%d -It %s -Il %d -If %d -Ii %d -Iv %d ",
src, // packet src
ih->sport(), // src port
dst, // packet dest
ih->dport(), // dst port
packet_info.name(ch->ptype()), // packet type
ch->size(), // packet size
ih->flowid(), // flow id
ch->uid(), // unique id
ih->ttl_); // ttl
} else {
sprintf(wrk_ + offset, "------- [%d:%d %d:%d %d %d] ",
src, ih->sport(),
dst, ih->dport(),
ih->ttl_, (ch->next_hop_ < 0) ? 0 : ch->next_hop_);
}
}
void
CMUTrace::format_arp(Packet *p, int offset)
{
struct hdr_arp *ah = HDR_ARP(p);
if (newtrace_) {
sprintf(wrk_ + offset,
"-P arp -Po %s -Pms %d -Ps %d -Pmd %d -Pd %d ",
ah->arp_op == ARPOP_REQUEST ? "REQUEST" : "REPLY",
ah->arp_sha,
ah->arp_spa,
ah->arp_tha,
ah->arp_tpa);
} else {
sprintf(wrk_ + offset,
"------- [%s %d/%d %d/%d]",
ah->arp_op == ARPOP_REQUEST ? "REQUEST" : "REPLY",
ah->arp_sha,
ah->arp_spa,
ah->arp_tha,
ah->arp_tpa);
}
}
void
CMUTrace::format_dsr(Packet *p, int offset)
{
hdr_sr *srh = (hdr_sr*)p->access(off_sr_);
if (newtrace_) {
sprintf(wrk_ + offset,
"-P dsr -Ph %d -Pq %d -Ps %d -Pp %d -Pn %d -Pl %d -Pe %d->%d -Pw %d -Pm %d -Pc %d -Pb %d->%d ",
srh->num_addrs(), // how many nodes travered
srh->route_request(),
srh->rtreq_seq(),
srh->route_reply(),
srh->rtreq_seq(),
srh->route_reply_len(),
// the dest of the src route
srh->reply_addrs()[0].addr,
srh->reply_addrs()[srh->route_reply_len()-1].addr,
srh->route_error(),
srh->num_route_errors(),
srh->down_links()[srh->num_route_errors() - 1].tell_addr,
srh->down_links()[srh->num_route_errors() - 1].from_addr,
srh->down_links()[srh->num_route_errors() - 1].to_addr);
return;
}
sprintf(wrk_ + offset,
"%d [%d %d] [%d %d %d %d->%d] [%d %d %d %d->%d]",
srh->num_addrs(),
srh->route_request(),
srh->rtreq_seq(),
srh->route_reply(),
srh->rtreq_seq(),
srh->route_reply_len(),
// the dest of the src route
srh->reply_addrs()[0].addr,
srh->reply_addrs()[srh->route_reply_len()-1].addr,
srh->route_error(),
srh->num_route_errors(),
srh->down_links()[srh->num_route_errors() - 1].tell_addr,
srh->down_links()[srh->num_route_errors() - 1].from_addr,
srh->down_links()[srh->num_route_errors() - 1].to_addr);
}
void
CMUTrace::format_msg(Packet *, int)
{
}
void
CMUTrace::format_tcp(Packet *p, int offset)
{
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_tcp *th = HDR_TCP(p);
if( newtrace_ ) {
sprintf(wrk_ + offset,
"-Pn tcp -Ps %d -Pa %d -Pf %d -Po %d ",
th->seqno_,
th->ackno_,
ch->num_forwards(),
ch->opt_num_forwards());
} else {
sprintf(wrk_ + offset,
"[%d %d] %d %d",
th->seqno_,
th->ackno_,
ch->num_forwards(),
ch->opt_num_forwards());
}
}
void
CMUTrace::format_rtp(Packet *p, int offset)
{
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_rtp *rh = HDR_RTP(p);
struct hdr_ip *ih = HDR_IP(p);
Node* thisnode = Node::get_node_by_address(src_);
//hacking, needs to change later,
int dst = Address::instance().get_nodeaddr(ih->daddr());
if (dst == src_){
// I just received a cbr data packet
if (thisnode->powersaving()) {
//thisnode->set_node_sleep(0);
thisnode->set_node_state(INROUTE);
}
}
if (newtrace_) {
sprintf(wrk_ + offset,
"-Pn cbr -Pi %d -Pf %d -Po %d ",
rh->seqno_,
ch->num_forwards(),
ch->opt_num_forwards());
} else {
sprintf(wrk_ + offset,
"[%d] %d %d",
rh->seqno_,
ch->num_forwards(),
ch->opt_num_forwards());
}
}
void
CMUTrace::format_imep(Packet *p, int offset)
{
struct hdr_imep *im = HDR_IMEP(p);
#define U_INT16_T(x) *((u_int16_t*) &(x))
if (newtrace_) {
sprintf(wrk_ + offset,
"-P imep -Pa %c -Ph %c -Po %c -Pl 0x%04x ] ",
(im->imep_block_flags & BLOCK_FLAG_ACK) ? 'A' : '-',
(im->imep_block_flags & BLOCK_FLAG_HELLO) ? 'H' : '-',
(im->imep_block_flags & BLOCK_FLAG_OBJECT) ? 'O' : '-',
U_INT16_T(im->imep_length));
} else {
sprintf(wrk_ + offset,
"[%c %c %c 0x%04x] ",
(im->imep_block_flags & BLOCK_FLAG_ACK) ? 'A' : '-',
(im->imep_block_flags & BLOCK_FLAG_HELLO) ? 'H' : '-',
(im->imep_block_flags & BLOCK_FLAG_OBJECT) ? 'O' : '-',
U_INT16_T(im->imep_length));
}
#undef U_INT16_T
}
void
CMUTrace::format_tora(Packet *p, int offset)
{
struct hdr_tora *th = HDR_TORA(p);
struct hdr_tora_qry *qh = HDR_TORA_QRY(p);
struct hdr_tora_upd *uh = HDR_TORA_UPD(p);
struct hdr_tora_clr *ch = HDR_TORA_CLR(p);
switch(th->th_type) {
case TORATYPE_QRY:
if (newtrace_) {
sprintf(wrk_ + offset,
"-P tora -Pt 0x%x -Pd %d -Pc QUERY ",
qh->tq_type, qh->tq_dst);
} else {
sprintf(wrk_ + offset, "[0x%x %d] (QUERY)",
qh->tq_type, qh->tq_dst);
}
break;
case TORATYPE_UPD:
if (newtrace_) {
sprintf(wrk_ + offset,
"-P tora -Pt 0x%x -Pd %d (%f %d %d %d %d) -Pc UPDATE ",
uh->tu_type,
uh->tu_dst,
uh->tu_tau,
uh->tu_oid,
uh->tu_r,
uh->tu_delta,
uh->tu_id);
} else {
sprintf(wrk_ + offset,
"-Pt 0x%x -Pd %d -Pa %f -Po %d -Pr %d -Pe %d -Pi %d -Pc UPDATE ",
uh->tu_type,
uh->tu_dst,
uh->tu_tau,
uh->tu_oid,
uh->tu_r,
uh->tu_delta,
uh->tu_id);
}
break;
case TORATYPE_CLR:
if (newtrace_) {
sprintf(wrk_ + offset,
"-P tora -Pt 0x%x -Pd %d -Pa %f -Po %d -Pc CLEAR ",
ch->tc_type,
ch->tc_dst,
ch->tc_tau,
ch->tc_oid);
} else {
sprintf(wrk_ + offset, "[0x%x %d %f %d] (CLEAR)",
ch->tc_type,
ch->tc_dst,
ch->tc_tau,
ch->tc_oid);
}
break;
}
}
void
CMUTrace::format_aodv(Packet *p, int offset)
{
struct hdr_aodv *ah = HDR_AODV(p);
struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p);
struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);
switch(ah->ah_type) {
case AODVTYPE_RREQ:
if (newtrace_) {
sprintf(wrk_ + offset,
"-P aodv -Pt 0x%x -Ph %d -Pb %d -Pd %d -Pds %d -Ps %d -Pss %d -Pc REQUEST ",
rq->rq_type,
rq->rq_hop_count,
rq->rq_bcast_id,
rq->rq_dst,
rq->rq_dst_seqno,
rq->rq_src,
rq->rq_src_seqno);
} else {
sprintf(wrk_ + offset,
"[0x%x %d %d [%d %d] [%d %d]] (REQUEST)",
rq->rq_type,
rq->rq_hop_count,
rq->rq_bcast_id,
rq->rq_dst,
rq->rq_dst_seqno,
rq->rq_src,
rq->rq_src_seqno);
}
break;
case AODVTYPE_RREP:
case AODVTYPE_UREP:
case AODVTYPE_HELLO:
if (newtrace_) {
sprintf(wrk_ + offset,
"-P aodv -Pt 0x%x -Ph %d -Pd %d -Pds %d -Pl %d -Pc %s ",
rp->rp_type,
rp->rp_hop_count,
rp->rp_dst,
rp->rp_dst_seqno,
rp->rp_lifetime,
rp->rp_type == AODVTYPE_RREP ? "REPLY" :
(rp->rp_type == AODVTYPE_UREP ? "UNSOLICITED REPLY" :
"HELLO"));
} else {
sprintf(wrk_ + offset,
"[0x%x %d [%d %d] %d] (%s)",
rp->rp_type,
rp->rp_hop_count,
rp->rp_dst,
rp->rp_dst_seqno,
rp->rp_lifetime,
rp->rp_type == AODVTYPE_RREP ? "REPLY" :
(rp->rp_type == AODVTYPE_UREP ? "UNSOLICITED REPLY" :
"HELLO"));
}
break;
default:
#ifdef WIN32
fprintf(stderr,
"CMUTrace::format_aodv: invalid AODV packet type\n");
#else
fprintf(stderr,
"%s: invalid AODV packet type\n", __FUNCTION__);
#endif
abort();
}
}
void
CMUTrace::nam_format(Packet *p, int offset)
{
Node* srcnode = 0 ;
Node* dstnode = 0 ;
Node* nextnode = 0 ;
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
char op = (char) type_;
char colors[32];
int next_hop = -1 ;
int dst = Address::instance().get_nodeaddr(ih->daddr());
nextnode = Node::get_node_by_address(ch->next_hop_);
if (nextnode) next_hop = nextnode->nodeid();
srcnode = Node::get_node_by_address(src_);
dstnode = Node::get_node_by_address(ch->next_hop_);
double distance = 0;
if ((srcnode) && (dstnode)) {
MobileNode* tmnode = (MobileNode*)srcnode;
MobileNode* rmnode = (MobileNode*)dstnode;
distance = tmnode->propdelay(rmnode) * 300000000 ;
}
double energy = -1;
double initenergy = -1;
//default value for changing node color with respect to energy depletion
double l1 = 0.5;
double l2 = 0.2;
if (srcnode) {
if (srcnode->energy_model()) {
energy = srcnode->energy();
initenergy = srcnode->initialenergy();
l1 = srcnode->energy_level1();
l2 = srcnode->energy_level2();
}
}
int energyLevel = 0 ;
double energyLeft = (double)(energy/initenergy) ;
if ((energyLeft <= 1 ) && (energyLeft >= l1 )) energyLevel = 3;
if ((energyLeft >= l2 ) && (energyLeft < l1 )) energyLevel = 2;
if ((energyLeft > 0 ) && (energyLeft < l2 )) energyLevel = 1;
if (energyLevel == 0) strcpy(colors,"-c black -o red");
else if (energyLevel == 1) strcpy(colors,"-c red -o yellow");
else if (energyLevel == 2) strcpy(colors,"-c yellow -o green");
else if (energyLevel == 3) strcpy(colors,"-c green -o black");
// convert to nam format
if (op == 's') op = 'h' ;
if (op == 'D') op = 'd' ;
if (op == 'h') {
sprintf(nwrk_ ,
"+ -t %.9f -s %d -d %d -p %s -e %d -c 2 -a 0 -i %d -k %3s ",
Scheduler::instance().clock(),
src_, // this node
next_hop,
packet_info.name(ch->ptype()),
ch->size(),
ch->uid(),
tracename);
offset = strlen(nwrk_);
namdump();
sprintf(nwrk_ ,
"- -t %.9f -s %d -d %d -p %s -e %d -c 2 -a 0 -i %d -k %3s",
Scheduler::instance().clock(),
src_, // this node
next_hop,
packet_info.name(ch->ptype()),
ch->size(),
ch->uid(),
tracename);
offset = strlen(nwrk_);
namdump();
}
// if nodes are too far from each other
// nam won't dump SEND event 'cuz it's
// gonna be dropped later anyway
// this value 250 is pre-calculated by using
// two-ray ground refelction model with fixed
// transmission power 3.652e-10
// if ((type_ == SEND) && (distance > 250 )) return ;
if(tracetype == TR_ROUTER && type_ == RECV && dst != -1 ) return ;
if(type_ == RECV && dst == -1 )dst = src_ ; //broadcasting event
if (energy != -1) { //energy model being turned on
if (nodeColor[src_] != energyLevel ) { //only dump it when node
sprintf(nwrk_ , //color change
"n -t %.9f -s %d -S COLOR %s",
Scheduler::instance().clock(),
src_, // this node
colors);
offset = strlen(nwrk_);
namdump();
nodeColor[src_] = energyLevel ;
}
}
sprintf(nwrk_ ,
"%c -t %.9f -s %d -d %d -p %s -e %d -c 2 -a 0 -i %d -k %3s",
op,
Scheduler::instance().clock(),
src_, // this node
next_hop,
packet_info.name(ch->ptype()),
ch->size(),
ch->uid(),
tracename);
offset = strlen(nwrk_);
namdump();
}
void CMUTrace::format(Packet* p, const char *why)
{
hdr_cmn *ch = HDR_CMN(p);
int offset = 0;
/*
* Log the MAC Header
*/
format_mac(p, why, offset);
#ifdef NAM_TRACE
if (namChan_) nam_format(p, offset);
#endif
offset = strlen(wrk_);
switch(ch->ptype()) {
case PT_MAC:
break;
case PT_ARP:
format_arp(p, offset);
break;
default:
format_ip(p, offset);
offset = strlen(wrk_);
switch(ch->ptype()) {
case PT_AODV:
format_aodv(p, offset);
break;
case PT_TORA:
format_tora(p, offset);
break;
case PT_IMEP:
format_imep(p, offset);
break;
case PT_DSR:
format_dsr(p, offset);
break;
case PT_MESSAGE:
case PT_UDP:
format_msg(p, offset);
break;
case PT_TCP:
case PT_ACK:
format_tcp(p, offset);
break;
case PT_CBR:
format_rtp(p, offset);
break;
default:
fprintf(stderr, "%s - invalid packet type (%s).\n",
__PRETTY_FUNCTION__, packet_info.name(ch->ptype()));
exit(1);
}
}
}
int
CMUTrace::command(int argc, const char*const* argv)
{
if(argc == 3) {
if(strcmp(argv[1], "node") == 0) {
node_ = (MobileNode*) TclObject::lookup(argv[2]);
if(node_ == 0)
return TCL_ERROR;
return TCL_OK;
}
if (strcmp(argv[1], "newtrace") == 0) {
newtrace_ = atoi(argv[2]);
return TCL_OK;
}
}
return Trace::command(argc, argv);
}
/*ARGSUSED*/
void
CMUTrace::recv(Packet *p, Handler *h)
{
if (!node_energy()) {
Packet::free(p);
return;
}
//struct hdr_ip *ih = HDR_IP(p);
// hack the IP address to convert pkt format to hostid format
// for now until port ids are removed from IP address. -Padma.
// int src = Address::instance().get_nodeaddr(ih->saddr());
assert(initialized());
/*
* Agent Trace "stamp" the packet with the optimal route on
* sending.
*/
if(tracetype == TR_AGENT && type_ == SEND) {
//assert(src_ == src);
God::instance()->stampPacket(p);
}
#if 0
/*
* When the originator of a packet drops the packet, it may or may
* not have been stamped by GOD. Stamp it before logging the
* information.
*/
if(src_ == src && type_ == DROP) {
God::instance()->stampPacket(p);
}
#endif
format(p, "---");
dump();
//namdump();
if(target_ == 0)
Packet::free(p);
else
send(p, h);
}
void
CMUTrace::recv(Packet *p, const char* why)
{
assert(initialized() && type_ == DROP);
if (!node_energy()) {
Packet::free(p);
return;
}
#if 0
/*
* When the originator of a packet drops the packet, it may or may
* not have been stamped by GOD. Stamp it before logging the
* information.
*/
if(src_ == ih->saddr()) {
God::instance()->stampPacket(p);
}
#endif
format(p, why);
dump();
//namdump();
Packet::free(p);
}
int
CMUTrace::node_energy()
{
Node* thisnode = Node::get_node_by_address(src_);
double energy = 1;
if (thisnode) {
if (thisnode->energy_model()) {
energy = thisnode->energy();
}
}
if (energy > 0) return 1;
//printf("DEBUG: node %d dropping pkts due to energy = 0\n", src_);
return 0;
}
codeword.cc
/*
* (c) 1997-98 StarBurst Communications Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE 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 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.
*
* Author: Christoph Haenle, chris@cs.vu.nl
* File: codeword.cc
* Last change: Dec 07, 1998
*
* This software may freely be used only for non-commercial purposes
*/
#include "config.h" // for memcpy...
#include "codeword.h"
#include
#include // due to definition of NULL
#include // due to printf
static unsigned char minbit_array[256];
static unsigned char bitcount_array[256];
// because of the lack of static initialization on class-basis in C++,
// this is a workaround.
static int dummy = initialize_codeword();
// list of primitive polynomials over GF(2).
CW_PATTERN_t Codeword::primitive_polynomial[Codeword::MAX_DEGREE+1] = {
"1", // 1 (group size 1)
"11", // 1+x
"111", // 1+x+x^2
"1011", // 1+x+x^3 (group size 4)
"10011", // 1+x+x^4
"100101", // 1+x^2+x^5
"1100111", // 1+x+x^2+x^5+x^6
"11100101", // 1+x^2+x^5+x^6+x^7 (group size 8)
"101101001", // 1+x^3+x^5+x^6+x^8
"1100010011", // 1+x^1+x^4+x^8+x^9
"11101001101", // 1+x^2+x^3+x^6+x^8+x^9+x^10
"110010011011", // 1+x+x^3+x^4+x^7+x^10+x^11
"1001010111001", // 1+x^3+x^4+x^5+x^7+x^9+x^12
"11000001111001", // 1+x^3+x^4+x^5+x^6+x^12+x^13
"110100100101111", // 1+x+x^2+x^3+x^5+x^8+x^11+x^13+x^14
"1100010011000101", // 1+x^2+x^6+x^7+x^10+x^14+x^15 (group size 16)
"11101010001010101", // 1+x^2+x^4+x^6+x^10+x^12+x^14+x^15+x^16
"101101011001011011", // 1+x+x^3+x^4+x^6+x^9+x^10+x^12+x^14+x^15+x^17
"1101101001010011011", // 1+x+x^3+x^4+x^7+x^9+x^12+x^14+x^15+x^17+x^18
"11100101101010010011",
"101010101101010010011", // 1+x+x^4+x^7+x^9+x^11+x^12+x^14+x^16+x^18+x^20
"1100010101110010011001",
"10100100110001101011001",
"101001011000010110110111",
"1010101010100101110110001",
"11001000110011010101011001",
"100011000010001110100111011", // group size: 27
"1100110100111010101010100011", // 1+x+x^5+x^7+x^9+x^11+x^13+x^15+x^16+x^17+x^20+x^22+x^23+x^26+x^27
"10100110100111010101010100011", // 1+x+x^5+x^7+x^9+x^11+x^13+x^15+x^16+x^17+x^20+x^22+x^23+x^26+x^28
"100110011000111010101010100011", // 1+x+x^5+x^7+x^9+x^11+x^13+x^15+x^16+x^17+x^21+x^22+x^25+x^26+x^29
"1010100101000111010110100100011", // 1+x+x^5+x^8+x^10+x^11+x^13+x^15+x^16+x^17+x^21+x^23+x^26+x^28+x^30
"10110010100101100011010011011011", // 1+x+x^3+x^4+x^6+x^7+x^10+x^12+x^13+x^17+x^18+x^20+x^23+x^25+x^28+x^29+x^31 (group size 32)
"0", // invalid, group size currently not supported
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"1101100011100110100100111001001010110010100101010100100111011011" // 1+x+x^3+x^4+x^6+x^7+x^8+x^11+x^14+x^16+x^18+x^20+x^23+x^25+x^28+x^29+x^31+x^33+x^36+x^39+x^40+x^41+x^44+x^47+x^49+x^50+x^53+x^54+x^55+x^59+x^60+x^62+x^63 (group size 64)
};
// to generate primitive polynomials, see for example
// http://www-kommsys.fernuni-hagen.de/~rieke/primitiv/test.phtml.en
Codeword::Codeword() :
k(1),
n(1),
cw_index(0),
cw_pat(0),
cw_saved(0)
{
}
void Codeword::setSourceWordLen(unsigned long k_)
{
k = k_;
n = ((CW_PATTERN_t) 1) << (k-1);
cw_index = (unsigned long) 0;
cw_pat = 1;
cw_saved = 0;
assert(k <= 8 * sizeof(CW_PATTERN_t));
if(k > MAX_DEGREE + 1 || primitive_polynomial[k-1] == 0) {
fprintf(stderr, "codeword.cc: sorry, the group size %lu is not supported.\n",
(unsigned long) k);
exit(0);
}
if(k > 8 * sizeof(CW_PATTERN_t)) {
fprintf(stderr, "codeword.cc: sorry, the group size %lu that you selected\n",
(unsigned long) k);
fprintf(stderr, "requires a datatype of at least %lu bits. To achieve this,\n",
(unsigned long) k);
fprintf(stderr, "adjust Codeword::size in file \"codeword.h\" accordingly.\n");
exit(0);
}
}
// systematic code, with optimization hack, originally derived from Reed-Muller codes of
// order 1.
CW_PATTERN_t Codeword::getNextCwPat()
{
assert(cw_pat != 0); // or else prior call to setSourceWordLen(...) has not been made
CW_PATTERN_t ret;
CW_PATTERN_t cw_tmp;
// step 1
if(cw_index != 0) {
cw_pat <<= 1;
if(cw_pat >= n) {
cw_pat ^= primitive_polynomial[k-1];
assert(cw_pat < n);
}
}
// step 2
if(cw_index == k) { cw_saved = cw_pat; cw_tmp = n-1; }
else if(cw_pat == n-1) cw_tmp = cw_saved;
else cw_tmp = cw_pat;
// step 3
if(cw_index < k) ret = (CW_PATTERN_t) 1 << cw_index;
else ret = (cw_tmp << 1) | 1;
// step 4
cw_index = (cw_index + 1) & (n-1); // "& (n-1)" is equivalent to "% n" here
return ret;
}
void init_bitcount_array(unsigned char* arr, unsigned int nb_bits)
{
unsigned long bitcount_array_size = ((unsigned long) 1) << nb_bits;
unsigned long i;
unsigned int bit;
int count;
assert(sizeof(unsigned long) == 4); // we need this for the following
assert(0 < nb_bits && nb_bits <= 32); // or else this function must be revised
assert(arr != NULL);
for(i = 0; i < bitcount_array_size; ++i) {
count = 0;
// to avoid warning: unsigned value >= 0 is always 1
// for(bit = 0; 0 <= bit && bit < nb_bits; bit++) {
for(bit = 0; bit < nb_bits; bit++) {
if(i & ((unsigned long) 1 << bit)) {
count++;
}
}
arr[i] = count;
}
}
void init_minbit_array(unsigned char* arr, unsigned int minbits)
{
unsigned int minbit_array_size = (unsigned int) 1 << minbits;
unsigned int i;
unsigned int bit;
assert(minbits == 8); // or else minbit(...) needs a revision!
assert(arr != NULL);
for(i = 0; i < minbit_array_size; ++i) {
// to avoid warning: unsigned value >= 0 is always 1
//for(bit = 0; 0 <= bit && bit < minbits; bit++) {
for(bit = 0; bit < minbits; bit++) {
if(i & ((unsigned int) 1 << bit)) {
arr[i] = (unsigned char) bit;
break;
}
}
}
}
// returns bit position of least significant bit in cw_pat
unsigned int minbit(unsigned long val)
{
unsigned int i;
assert(val);
for(i = 0; val; ++i) {
assert(i < sizeof(CW_PATTERN_t));
if(val & 255) {
return minbit_array[(unsigned int) (val & 255)] + 8*i;
}
val >>= 8;
}
assert(false); // value is 0
return 0; // compiler, be quiet.
}
// counts number of bits in cw_pat
unsigned int bitcount(unsigned long val)
{
unsigned int res = 0;
while(val) {
res += bitcount_array[(unsigned int) (val & 255)];
val >>= 8;
}
return res;
}
/* function to be called once at the beginning */
int initialize_codeword()
{
assert(sizeof(minbit_array) / sizeof(unsigned char) == 256);
init_minbit_array(minbit_array, 8);
init_bitcount_array(bitcount_array, 8);
return 0;
}
// constructor:
ExtraLongUInt::ExtraLongUInt()
{
memset(value, 0, sizeof(value));
}
// constructor: create from "binary-string" (string of 0's and 1's):
ExtraLongUInt::ExtraLongUInt(const char* val)
{
const unsigned int len = strlen(val);
char digit;
assert(len <= 8 * sizeof(value)); // or else overflow
memset(value, 0, sizeof(value));
for(unsigned int i = 0; i < len; ++i) {
digit = val[len - 1 - i];
assert(digit == '0' || digit == '1'); // or else val is not a binary number
if(digit == '1') {
value[i / (8 * sizeof(unsigned long))] |=
(unsigned long) 1 << (i % (8 * sizeof(unsigned long)));
}
}
}
// constructor:
ExtraLongUInt::ExtraLongUInt(int val)
{
assert(val >= 0);
memset(value, 0, sizeof(value));
value[0] = val;
}
// constructor:
ExtraLongUInt::ExtraLongUInt(unsigned int val)
{
memset(value, 0, sizeof(value));
value[0] = val;
}
// constructor:
ExtraLongUInt::ExtraLongUInt(unsigned long val)
{
memset(value, 0, sizeof(value));
value[0] = val;
}
bool ExtraLongUInt::operator == (const ExtraLongUInt& other) const
{
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
if(value[i] != other.value[i]) {
return false;
}
}
return true;
}
bool ExtraLongUInt::operator != (const ExtraLongUInt& other) const
{
return (*this == other) ? false : true;
}
bool ExtraLongUInt::operator < (const ExtraLongUInt& other) const
{
unsigned int i;
for(i = sizeof(value) / sizeof(unsigned long) - 1;
value[i] == other.value[i] && i > 0; --i) {
}
return value[i] < other.value[i] ? true : false;
}
bool ExtraLongUInt::operator > (const ExtraLongUInt& other) const
{
unsigned int i;
for(i = sizeof(value) / sizeof(unsigned long) - 1;
value[i] == other.value[i] && i > 0; --i) {
}
return value[i] > other.value[i] ? true : false;
}
bool ExtraLongUInt::operator <= (const ExtraLongUInt& other) const
{
return (*this > other) ? false : true;
}
bool ExtraLongUInt::operator >= (const ExtraLongUInt& other) const
{
return (*this < other) ? false : true;
}
ExtraLongUInt ExtraLongUInt::operator + (const ExtraLongUInt& other) const
{
ExtraLongUInt res = 0;
unsigned long c = 0;
const int shift = 8 * sizeof(unsigned long) - 1;
const unsigned long msb_mask = (unsigned long) 1 << shift;
const unsigned long lsbs_mask = ~msb_mask;
unsigned long x, y;
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
x = value[i];
y = other.value[i];
res.value[i] = (x & lsbs_mask) + (y & lsbs_mask) + c;
c = ((x >> shift) + (y >> shift) + (res.value[i] >> shift)) >> 1;
res.value[i] ^= (x & msb_mask) ^ (y & msb_mask);
}
return res;
}
ExtraLongUInt ExtraLongUInt::operator - (const ExtraLongUInt& other) const
{
return *this + ~other + 1;
}
ExtraLongUInt ExtraLongUInt::operator & (const ExtraLongUInt& other) const
{
ExtraLongUInt res;
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
res.value[i] = value[i] & other.value[i];
}
return res;
}
ExtraLongUInt ExtraLongUInt::operator | (const ExtraLongUInt& other) const
{
ExtraLongUInt res;
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
res.value[i] = value[i] | other.value[i];
}
return res;
}
ExtraLongUInt ExtraLongUInt::operator ^ (const ExtraLongUInt& other) const
{
ExtraLongUInt res;
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
res.value[i] = value[i] ^ other.value[i];
}
return res;
}
ExtraLongUInt ExtraLongUInt::operator ~() const
{
ExtraLongUInt res;
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
res.value[i] = ~value[i];
}
return res;
}
bool ExtraLongUInt::operator ! () const
{
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
if(value[i]) {
return false;
}
}
return true;
}
ExtraLongUInt ExtraLongUInt::operator << (unsigned int bits) const
{
ExtraLongUInt res = 0;
const int index = bits / (8 * sizeof(unsigned long));
const int shifts = bits % (8 * sizeof(unsigned long));
unsigned int i;
if(sizeof(value) > index * sizeof(unsigned long)) {
if(shifts == 0) { // this is because (1 >> 32) is not 0 (gcc)
memcpy(&res.value[index],
value,
sizeof(value) - index * sizeof(unsigned long));
} else {
const unsigned long mask = (~(unsigned long) 0) >> shifts;
assert(sizeof(value) >= sizeof(unsigned long));
res.value[index] = (value[0] & mask) << shifts;
for(i = index + 1; i < sizeof(value) / sizeof(unsigned long); ++i) {
res.value[i] = ((value[i - index ] & mask) << shifts) |
(value[i - index-1] >> ((8 * sizeof(unsigned long)) - shifts));
}
}
}
return res;
}
ExtraLongUInt ExtraLongUInt::operator >> (unsigned int bits) const
{
ExtraLongUInt res = 0;
const int index = bits / (8 * sizeof(unsigned long));
const int shifts = bits % (8 * sizeof(unsigned long));
unsigned int i;
if(sizeof(value) > index * sizeof(unsigned long)) {
if(shifts == 0) { // this is because (1 >> 32) is not 0 (gcc)
memcpy(res.value,
&value[index],
sizeof(value) - index * sizeof(unsigned long));
} else {
const unsigned long mask = (~(unsigned long) 0) >> (8 * sizeof(unsigned long) - shifts);
assert(sizeof(value) >= sizeof(unsigned long));
for(i = 0; i < sizeof(value) / sizeof(unsigned long) - index - 1; ++i) {
res.value[i] = (value[i+index ] >> shifts) |
((value[i+index+1] & mask) << ((8 * sizeof(unsigned long)) - shifts));
}
res.value[i] = value[i+index] >> shifts;
}
}
return res;
}
ExtraLongUInt ExtraLongUInt::operator << (const ExtraLongUInt& bits) const
{
return *this << bits.value[0];
}
ExtraLongUInt ExtraLongUInt::operator >> (const ExtraLongUInt& bits) const
{
return *this >> bits.value[0];
}
const ExtraLongUInt& ExtraLongUInt::operator <<= (unsigned int bits)
{
*this = *this << bits;
return *this;
}
const ExtraLongUInt& ExtraLongUInt::operator >>= (unsigned int bits)
{
*this = *this >> bits;
return *this;
}
const ExtraLongUInt& ExtraLongUInt::operator &= (const ExtraLongUInt& other)
{
*this = *this & other;
return *this;
}
const ExtraLongUInt& ExtraLongUInt::operator |= (const ExtraLongUInt& other)
{
*this = *this | other;
return *this;
}
const ExtraLongUInt& ExtraLongUInt::operator ^= (const ExtraLongUInt& other)
{
*this = *this ^ other;
return *this;
}
void ExtraLongUInt::print(char* buf) const
{
int i, fin;
for(i = 8 * sizeof(value) - 1; !(value[i / (8 * sizeof(unsigned long))] &
((unsigned long) 1 << (i % (8 * sizeof(unsigned long))))) && i > 0; --i)
;
for(fin = i; i >= 0; --i) {
buf[fin-i] = (value[i / (8 * sizeof(unsigned long))] &
(unsigned long) 1 << (i % (8 * sizeof(unsigned long)))) ?
'1' : '0';
}
buf[fin+1] = '\0';
}
unsigned int ExtraLongUInt::bitcount() const
{
unsigned int res = 0;
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
res += ::bitcount(value[i]);
}
return res;
}
unsigned int ExtraLongUInt::minbit() const
{
for(unsigned int i = 0; i < sizeof(value) / sizeof(unsigned long); ++i) {
if(value[i]) {
return i * 8 * sizeof(unsigned long) + ::minbit(value[i]);
}
}
assert(false); // value is 0
return 0; // compiler, be quiet.
}
// returns bit position of least significant bit in cw_pat
unsigned int minbit(const ExtraLongUInt& val)
{
return val.minbit();
}
// returns bit position of least significant bit in cw_pat
unsigned int bitcount(const ExtraLongUInt& val)
{
return val.bitcount();
}
connector.cc
/* -*- 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ ";
#endif
#include "packet.h"
#include "connector.h"
static class ConnectorClass : public TclClass {
public:
ConnectorClass() : TclClass("Connector") {}
TclObject* create(int, const char*const*) {
return (new Connector);
}
} class_connector;
Connector::Connector() : target_(0), drop_(0)
{
}
int Connector::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
/*XXX*/
if (argc == 2) {
if (strcmp(argv[1], "target") == 0) {
if (target_ != 0)
tcl.result(target_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "drop-target") == 0) {
if (drop_ != 0)
tcl.resultf("%s", drop_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "isDynamic") == 0) {
return TCL_OK;
}
}
else if (argc == 3) {
if (strcmp(argv[1], "target") == 0) {
if (*argv[2] == '0') {
target_ = 0;
return (TCL_OK);
}
target_ = (NsObject*)TclObject::lookup(argv[2]);
if (target_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "drop-target") == 0) {
drop_ = (NsObject*)TclObject::lookup(argv[2]);
if (drop_ == 0) {
tcl.resultf("no object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (NsObject::command(argc, argv));
}
void Connector::recv(Packet* p, Handler* h)
{
send(p, h);
}
void Connector::drop(Packet* p)
{
if (drop_ != 0)
drop_->recv(p);
else
Packet::free(p);
}
void Connector::drop(Packet* p, const char *s)
{
if (drop_ != 0)
drop_->recv(p, s);
else
Packet::free(p);
}
consrcvr.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "agent.h"
#include "config.h"
#include "tclcl.h"
#include "packet.h"
#include "rtp.h"
#include "adaptive-receiver.h"
#ifndef WIN32
// VC 5.0 doesn't have this
#include
#endif
//#define CONS_OFFSET 0.025*SAMPLERATE
#define CONS_OFFSET 200
class ConsRcvr : public AdaptiveRcvr {
public:
ConsRcvr();
protected:
int adapt(Packet *pkt, u_int32_t time);
int offset_;
};
static class ConsRcvrClass : public TclClass {
public:
ConsRcvrClass() : TclClass("Agent/ConsRcvr") {}
TclObject* create(int, const char*const*) {
return (new ConsRcvr());
}
} class_cons_rcvr;
ConsRcvr::ConsRcvr() : offset_(CONS_OFFSET)
{
}
int ConsRcvr::adapt(Packet *pkt, u_int32_t local_clock)
{
int delay;
hdr_cmn* ch = (hdr_cmn*)pkt->access(off_cmn_);
register u_int32_t tstamp = (int)ch->timestamp();
if (((tstamp+offset_) < local_clock) || (offset_ == -1)) {
/*increase the offset */
if (offset_ < (int)(local_clock-(tstamp+offset_)))
offset_ += local_clock -(tstamp+offset_);
else
offset_ += offset_;
}
delay=offset_-(local_clock-tstamp);
return delay;
}
ctrMcast.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* ctrMcast.cc
* Copyright (C) 1997 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang
*
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (USC/ISI)";
#endif
#include "agent.h"
#include "ip.h"
#include "ctrMcast.h"
int hdr_CtrMcast::offset_;
static class CtrMcastHeaderClass : public PacketHeaderClass {
public:
CtrMcastHeaderClass() : PacketHeaderClass("PacketHeader/CtrMcast",
sizeof(hdr_CtrMcast)) {
bind_offset(&hdr_CtrMcast::offset_);
}
} class_CtrMcast_hdr;
class CtrMcastEncap : public Agent {
public:
CtrMcastEncap() : Agent(PT_CtrMcast_Encap) {
bind("off_CtrMcast_", &off_CtrMcast_);
}
int command(int argc, const char*const* argv);
void recv(Packet* p, Handler*);
protected:
int off_CtrMcast_;
};
class CtrMcastDecap : public Agent {
public:
CtrMcastDecap() : Agent(PT_CtrMcast_Decap) {
bind("off_CtrMcast_", &off_CtrMcast_);
}
int command(int argc, const char*const* argv);
void recv(Packet* p, Handler*);
protected:
int off_CtrMcast_;
};
static class CtrMcastEncapclass : public TclClass {
public:
CtrMcastEncapclass() : TclClass("Agent/CtrMcast/Encap") {}
TclObject* create(int, const char*const*) {
return (new CtrMcastEncap);
}
} class_CtrMcastEncap;
static class CtrMcastDecapclass : public TclClass {
public:
CtrMcastDecapclass() : TclClass("Agent/CtrMcast/Decap") {}
TclObject* create(int, const char*const*) {
return (new CtrMcastDecap);
}
} class_CtrMcastDecap;
int CtrMcastEncap::command(int argc, const char*const* argv)
{
return Agent::command(argc, argv);
}
int CtrMcastDecap::command(int argc, const char*const* argv)
{
return Agent::command(argc, argv);
}
void CtrMcastEncap::recv(Packet* p, Handler*)
{
hdr_CtrMcast* ch = (hdr_CtrMcast*)p->access(off_CtrMcast_);
hdr_ip* ih = (hdr_ip*)p->access(off_ip_);
ch->src() = ih->saddr();
ch->group() = ih->daddr();
ch->flowid() = ih->flowid();
ih->saddr() = addr();
ih->sport() = port();
ih->daddr() = daddr();
ih->dport() = dport();
ih->flowid() = fid_;
target_->recv(p);
}
void CtrMcastDecap::recv(Packet* p, Handler*)
{
hdr_CtrMcast* ch = (hdr_CtrMcast*)p->access(off_CtrMcast_);
hdr_ip* ih = (hdr_ip*)p->access(off_ip_);
ih->saddr() = ch->src();
ih->daddr() = ch->group();
ih->flowid() = ch->flowid();
target_->recv(p);
}
delay.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996-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$ (LBL)";
#endif
#include "delay.h"
#include "mcast_ctrl.h"
#include "ctrMcast.h"
static class LinkDelayClass : public TclClass {
public:
LinkDelayClass() : TclClass("DelayLink") {}
TclObject* create(int /* argc */, const char*const* /* argv */) {
return (new LinkDelay);
}
} class_delay_link;
LinkDelay::LinkDelay() : dynamic_(0), itq_(0)
{
bind_bw("bandwidth_", &bandwidth_);
bind_time("delay_", &delay_);
}
int LinkDelay::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "isDynamic") == 0) {
dynamic_ = 1;
itq_ = new PacketQueue();
return TCL_OK;
}
} else if (argc == 6) {
if (strcmp(argv[1], "pktintran") == 0) {
int src = atoi(argv[2]);
int grp = atoi(argv[3]);
int from = atoi(argv[4]);
int to = atoi(argv[5]);
pktintran (src, grp);
Tcl::instance().evalf("%s puttrace %d %d %d %d %d %d %d %d", name(), total_[0], total_[1], total_[2], total_[3], src, grp, from, to);
return TCL_OK;
}
}
return Connector::command(argc, argv);
}
void LinkDelay::recv(Packet* p, Handler* h)
{
double txt = txtime(p);
Scheduler& s = Scheduler::instance();
if (dynamic_) {
Event* e = (Event*)p;
e->time_= txt + delay_;
itq_->enque(p); // for convinience, use a queue to store packets in transit
s.schedule(this, p, txt + delay_);
} else {
s.schedule(target_, p, txt + delay_);
}
s.schedule(h, &intr_, txt);
}
void LinkDelay::send(Packet* p, Handler*)
{
target_->recv(p, (Handler*) NULL);
}
void LinkDelay::reset()
{
Scheduler& s= Scheduler::instance();
if (itq_ && itq_->length()) {
Packet *np;
// walk through packets currently in transit and kill 'em
while ((np = itq_->deque()) != 0) {
s.cancel(np);
drop(np);
}
}
}
void LinkDelay::handle(Event* e)
{
Packet *p = itq_->deque();
assert(p->time_ == e->time_);
send(p, (Handler*) NULL);
}
void LinkDelay::pktintran(int src, int group)
{
int reg = 1;
int prune = 30;
int graft = 31;
int data = 0;
for (int i=0; i<4; i++) {
total_[i] = 0;
}
if (! dynamic_)
return;
int len = itq_->length();
while (len) {
len--;
Packet* p = itq_->lookup(len);
hdr_ip* iph = hdr_ip::access(p);
if (iph->flowid() == prune) {
if (iph->saddr() == src && iph->daddr() == group) {
total_[0]++;
}
} else if (iph->flowid() == graft) {
if (iph->saddr() == src && iph->daddr() == group) {
total_[1]++;
}
} else if (iph->flowid() == reg) {
hdr_CtrMcast* ch = hdr_CtrMcast::access(p);
if (ch->src() == src+1 && ch->group() == group) {
total_[2]++;
}
} else if (iph->flowid() == data) {
if (iph->saddr() == src+1 && iph->daddr() == group) {
total_[3]++;
}
}
}
//printf ("%f %d %d %d %d\n", Scheduler::instance().clock(), total_[0], total_[1], total_[2],total_[3]);
}
delaymodel.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* delaymodel.cc
* Copyright (C) 1997 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang
*
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include "packet.h"
#include "delaymodel.h"
static class DelayModelClass : public TclClass {
public:
DelayModelClass() : TclClass("DelayModel") {}
TclObject* create(int, const char*const*) {
return (new DelayModel);
}
} class_delaymodel;
DelayModel::DelayModel() : Connector(), bandwidth_(0)
{
}
int DelayModel::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "ranvar") == 0) {
ranvar_ = (RandomVariable*) TclObject::lookup(argv[2]);
return (TCL_OK);
} else if (strcmp(argv[1], "bandwidth") == 0) {
bandwidth_ = atof(argv[2]);
return (TCL_OK);
}
} else if (argc == 2) {
if (strcmp(argv[1], "ranvar") == 0) {
tcl.resultf("%s", ranvar_->name());
return (TCL_OK);
}
}
return Connector::command(argc, argv);
}
void DelayModel::recv(Packet* p, Handler*)
{
double delay = ranvar_->value();
//static int tmp = 0;
double txt = txtime(p);
Scheduler& s = Scheduler::instance();
//printf ("trans %f, delay %f\n", txt, delay);
s.schedule(target_, p, txt + delay);
//s.schedule(h, &intr_, txt);
}
dem.cc
/* -*- 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma.*/
#include "config.h"
#include
#include
#include
#include
#include
int
DEMFile::open()
{
if((demfile = fopen(fname, "r")) == 0)
return EINVAL;
else
return 0;
}
int
DEMFile::read_int()
{
read_field();
return (atoi(tempbuf));
}
float
DEMFile::read_float()
{
read_field();
return (atof(tempbuf));
}
void
DEMFile::read_field()
{
int i;
char ch;
bzero(tempbuf, sizeof(tempbuf));
while(! feof(demfile) && isspace((ch = fgetc(demfile))) );
tempbuf[0] = ch;
for(i = 1; ; i++) {
if(feof(demfile)) {
fprintf(stderr, "%s: EOF\n", __PRETTY_FUNCTION__);
exit(1);
}
tempbuf[i] = fgetc(demfile);
if(tempbuf[i] == 'D')
tempbuf[i] = 'E';
if(isspace(tempbuf[i]))
break;
}
}
void
DEMFile::resolution(double &r)
{
r = 5.0;
}
void
DEMFile::range(double &x, double &y)
{
#if 0
int i;
double minx = 0.0, miny = 0.0, maxx = 0.0, maxy = 0.0;
for(i = 0; i < 4; i++) {
if(minx == 0.0 || minx > a.corners[i][0]) {
minx = a.corners[i][0];
miny = a.corners[i][1];
}
else if(minx == a.corners[i][0] && miny > a.corners[i][1]) {
miny = a.corners[i][1];
}
if(maxx == 0.0 || maxx < a.corners[i][0]) {
maxx = a.corners[i][0];
maxy = a.corners[i][1];
}
else if(maxx == a.corners[i][0] && maxy < a.corners[i][1]) {
maxy = a.corners[i][1];
}
}
x = maxx - minx;
y = maxy - miny;
#else
x = y = (double) a.cols - 1;
#endif
}
/* ======================================================================
Returns a pointer to the "grid".
====================================================================== */
int*
DEMFile::process()
{
int i, j, offset = 0;
char ch;
if(fname == 0)
return 0;
if(open())
return 0;
/* ============================================================
A Record
============================================================ */
bzero(a.q_name, sizeof(a.q_name));
for(i = 0; ! feof(demfile) && i < (int) sizeof(a.q_name) - 1; i++) {
ch = fgetc(demfile);
if(! isspace(ch)) {
a.q_name[offset] = ch;
offset++;
}
else {
if(offset && ! isspace(a.q_name[offset-1])) {
a.q_name[offset] = ch;
offset++;
}
}
}
a.dl_code = read_int();
a.p_code = read_int();
a.pr_code = read_int();
a.z_code = read_int();
/* Map Projection Parameters */
for(i = 0; i < 15; i++)
a.p_parm[i] = read_float();
a.g_units = read_int();
a.e_units = read_int();
a.sides = read_int();
for(i = 0; i < 4; i++) {
a.corners[i][0] = read_float();
a.corners[i][1] = read_float();
}
a.min_elevation = read_float();
a.max_elevation = read_float();
a.angle = read_float();
#if 0
a.a_code = read_int();
a.x_res = read_float();
a.y_res = read_float();
a.z_res = read_float();
#else
read_field();
#endif
a.rows = read_int();
a.cols = read_int();
grid = (int*) malloc(sizeof(int) * a.cols * a.cols);
/* ============================================================
B Records
============================================================ */
for(int rows = 0; rows < a.cols; rows++) {
b.row_id = read_int();
b.col_id = read_int();
b.rows = read_int();
b.cols = read_int();
b.x_gpc = read_float();
b.y_gpc = read_float();
b.elevation = read_float();
b.min_elevation = read_float();
b.max_elevation = read_float();
i = rows * a.cols;
for(j = 0; j < b.rows; j++)
grid[i+j] = read_int();
}
return grid;
}
void
DEMFile::dump_ARecord()
{
int i;
fprintf(stdout, "*** A RECORD ***\n");
fprintf(stdout, "Quadrangle name: %s\n", a.q_name);
fprintf(stdout, "DEM Level code: %d\n", a.dl_code);
fprintf(stdout, "Pattern code: %d\n", a.p_code);
fprintf(stdout, "Planimetric reference system code: %d\n", a.pr_code);
fprintf(stdout, "Zone code: %d\n", a.z_code);
fprintf(stdout, "Map Projection Parameters:\n");
for(i = 0; i < 15; i++)
fprintf(stdout, " %f\n",
a.p_parm[i]);
fprintf(stdout, "Ground planimetric coordinates: %d\n", a.g_units);
fprintf(stdout, "Elevation coordinates: %d\n", a.e_units);
fprintf(stdout, "Sides: %d\n", a.sides);
fprintf(stdout, "Corners:\n");
for(i = 0; i < 4; i++)
fprintf(stdout, " %f, %f\n",
a.corners[i][0], a.corners[i][1]);
fprintf(stdout, "Min Elevation: %f\n", a.min_elevation);
fprintf(stdout, "Max Elevation: %f\n", a.max_elevation);
fprintf(stdout, "Clockwise angle: %f\n", a.angle);
fprintf(stdout, "Accuracy code: %d\n", a.a_code);
fprintf(stdout, "Spatial Resolution:\n");
fprintf(stdout, " %f (x)\n", a.x_res);
fprintf(stdout, " %f (y)\n", a.y_res);
fprintf(stdout, " %f (z)\n", a.z_res);
fprintf(stdout, "Rows: %d\n", a.rows);
fprintf(stdout, "Columns: %d\n", a.cols);
}
void
DEMFile::dump_BRecord()
{
fprintf(stdout, "*** B RECORD ***\n");
fprintf(stdout, "Row ID: %d\n", b.row_id);
fprintf(stdout, "Column ID: %d\n", b.col_id);
fprintf(stdout, "Rows: %d\n", b.rows);
fprintf(stdout, "Columns: %d\n", b.cols);
fprintf(stdout, "Ground planimetric coordinates: %f, %f\n",
b.x_gpc, b.y_gpc);
fprintf(stdout, "Elevation: %f\n", b.elevation);
fprintf(stdout, "Min Elevation: %f\n", b.min_elevation);
fprintf(stdout, "Max Elevation: %f\n", b.max_elevation);
}
void
DEMFile::dump_grid()
{
int i, j;
fprintf(stdout, "*** X,Y GRID ***\n");
for(i = 0; i < a.cols; i++) {
fprintf(stdout, "ROW %5d --- ", i);
for(j = 0; j < a.cols; j++) {
fprintf(stdout, "%5d ", grid[i*a.cols + j]);
}
fprintf(stdout, "\n");
}
}
#if 0
void main(int argc, char** argv)
{
DEMFile *F;
if(argc != 2)
exit(1);
F = new DEMFile(argv[1]);
F->process();
F->dump_grid();
}
#endif
drop-tail.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1994 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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$ (LBL)";
#endif
#include "drop-tail.h"
static class DropTailClass : public TclClass {
public:
DropTailClass() : TclClass("Queue/DropTail") {}
TclObject* create(int, const char*const*) {
return (new DropTail);
}
} class_drop_tail;
int
DropTail::command(int argc, const char*const* argv) {
if (argc == 3) {
if (!strcmp(argv[1], "packetqueue-attach")) {
delete q_;
if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))
return (TCL_ERROR);
else {
pq_ = q_;
return (TCL_OK);
}
}
}
return Queue::command(argc, argv);
}
/*
* drop-tail
*/
void DropTail::enque(Packet* p)
{
q_->enque(p);
if (q_->length() >= qlim_) {
if (drop_front_) { /* remove from head of queue */
Packet *pp = q_->deque();
drop(pp);
} else {
q_->remove(p);
drop(p);
}
}
}
Packet* DropTail::deque()
{
return q_->deque();
}
drr.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or derivative
* work. Xerox grants no other licenses expressed or implied. The Xerox trade
* name should not be used in any advertising without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this software.
*
* This file contributed by Sandeep Bajaj , Mar 1997.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (Xerox)";
#endif
#include "config.h" // for string.h
#include
#include "queue.h"
class PacketDRR;
class DRR;
class PacketDRR : public PacketQueue {
PacketDRR(): pkts(0),src(-1),bcount(0),prev(0),next(0),deficitCounter(0),turn(0) {}
friend DRR;
protected :
int pkts;
int src; //to detect collisions keep track of actual src address
int bcount; //count of bytes in each flow to find the max flow;
PacketDRR *prev;
PacketDRR *next;
int deficitCounter;
int turn;
inline PacketDRR * activate(PacketDRR *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 PacketDRR * idle(PacketDRR *head) {
if (head == this) {
if (this->next == this)
return 0;
this->next->prev = this->prev;
this->prev->next = this->next;
return this->next;
}
this->next->prev = this->prev;
this->prev->next = this->next;
return head;
}
};
class DRR : public Queue {
public :
DRR();
virtual int command(int argc, const char*const* argv);
Packet *deque(void);
void enque(Packet *pkt);
int hash(Packet *pkt);
void clear();
protected:
int buckets_ ; //total number of flows allowed
int blimit_; //total number of bytes allowed across all flows
int quantum_; //total number of bytes that a flow can send
int mask_; /*if set hashes on just the node address otherwise on
node+port address*/
int bytecnt ; //cumulative sum of bytes across all flows
int pktcnt ; // cumulative sum of packets across all flows
int flwcnt ; //total number of active flows
PacketDRR *curr; //current active flow
PacketDRR *drr ; //pointer to the entire drr struct
int off_ip_;
inline PacketDRR *getMaxflow (PacketDRR *curr) { //returns flow with max pkts
int i;
PacketDRR *tmp;
PacketDRR *maxflow=curr;
for (i=0,tmp=curr; i < flwcnt; i++,tmp=tmp->next) {
if (maxflow->bcount < tmp->bcount)
maxflow=tmp;
}
return maxflow;
}
public:
//returns queuelength in packets
inline int length () {
return pktcnt;
}
//returns queuelength in bytes
inline int blength () {
return bytecnt;
}
};
static class DRRClass : public TclClass {
public:
DRRClass() : TclClass("Queue/DRR") {}
TclObject* create(int, const char*const*) {
return (new DRR);
}
} class_drr;
DRR::DRR()
{
buckets_=16;
quantum_=250;
drr=0;
curr=0;
flwcnt=0;
bytecnt=0;
pktcnt=0;
mask_=0;
bind("buckets_",&buckets_);
bind("blimit_",&blimit_);
bind("quantum_",&quantum_);
bind("mask_",&mask_);
bind ("off_ip_",&off_ip_);
}
void DRR::enque(Packet* pkt)
{
PacketDRR *q,*remq;
int which;
hdr_cmn *ch=(hdr_cmn*)pkt->access(off_cmn_);
hdr_ip *iph = (hdr_ip*)pkt->access(off_ip_);
if (!drr)
drr=new PacketDRR[buckets_];
which= hash(pkt) % buckets_;
q=&drr[which];
/*detect collisions here */
int compare=(!mask_ ? ((int)iph->saddr()) : ((int)iph->saddr()&0xfff0));
if (q->src ==-1)
q->src=compare;
else
if (q->src != compare)
fprintf(stderr,"Collisions between %d and %d src addresses\n",q->src,(int)iph->saddr());
q->enque(pkt);
++q->pkts;
++pktcnt;
q->bcount += ch->size();
bytecnt +=ch->size();
if (q->pkts==1)
{
curr = q->activate(curr);
q->deficitCounter=0;
++flwcnt;
}
while (bytecnt > blimit_) {
Packet *p;
hdr_cmn *remch;
hdr_ip *remiph;
remq=getMaxflow(curr);
p=remq->deque();
remch=(hdr_cmn*)p->access(off_cmn_);
remiph=(hdr_ip*)p->access(off_ip_);
remq->bcount -= remch->size();
bytecnt -= remch->size();
drop(p);
--remq->pkts;
--pktcnt;
if (remq->pkts==0) {
curr=remq->idle(curr);
--flwcnt;
}
}
}
Packet *DRR::deque(void)
{
hdr_cmn *ch;
hdr_ip *iph;
Packet *pkt=0;
if (bytecnt==0) {
//fprintf (stderr,"No active flow\n");
return(0);
}
while (!pkt) {
if (!curr->turn) {
curr->deficitCounter+=quantum_;
curr->turn=1;
}
pkt=curr->lookup(0);
ch=(hdr_cmn*)pkt->access(off_cmn_);
iph= (hdr_ip*)pkt->access(off_ip_);
if (curr->deficitCounter >= ch->size()) {
curr->deficitCounter -= ch->size();
pkt=curr->deque();
curr->bcount -= ch->size();
--curr->pkts;
--pktcnt;
bytecnt -= ch->size();
if (curr->pkts == 0) {
curr->turn=0;
--flwcnt;
curr->deficitCounter=0;
curr=curr->idle(curr);
}
return pkt;
}
else {
curr->turn=0;
curr=curr->next;
pkt=0;
}
}
return 0; // not reached
}
void DRR::clear()
{
PacketDRR *q =drr;
int i = buckets_;
if (!q)
return;
while (i--) {
if (q->pkts) {
fprintf(stderr, "Changing non-empty bucket from drr\n");
exit(1);
}
++q;
}
delete[](drr);
drr = 0;
}
/*
*Allows one to change blimit_ and bucket_ for a particular drrQ :
*
*
*/
int DRR::command(int argc, const char*const* argv)
{
if (argc==3) {
if (strcmp(argv[1], "blimit") == 0) {
blimit_ = atoi(argv[2]);
if (bytecnt > blimit_)
{
fprintf (stderr,"More packets in buffer than the new limit");
exit (1);
}
return (TCL_OK);
}
if (strcmp(argv[1], "buckets") == 0) {
clear();
buckets_ = atoi(argv[2]);
return (TCL_OK);
}
if (strcmp(argv[1],"quantum") == 0) {
quantum_ = atoi(argv[2]);
return (TCL_OK);
}
if (strcmp(argv[1],"mask")==0) {
mask_= atoi(argv[2]);
return (TCL_OK);
}
}
return (Queue::command(argc, argv));
}
int DRR::hash(Packet* pkt)
{
hdr_ip *iph=(hdr_ip*)pkt->access(off_ip_);
int i;
if (mask_)
i = (int)iph->saddr() & (0xfff0);
else
i = (int)iph->saddr();
return ((i + (i >> 8) + ~(i>>4)) % ((2<<23)-1))+1; // modulo a large prime
}
dynalink.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (C) 1997 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
// Other copyrights might apply to parts of this software and are so
// noted when applicable.
//
// Author: Kannan Varadhan
// Version Date: Mon Jun 30 15:51:33 PDT 1997
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (USC/ISI)";
#endif
#include "connector.h"
// #include "packet.h"
// #include "queue.h"
class DynamicLink : public Connector {
public:
DynamicLink() : down_(0), status_(1) { bind("status_", &status_); }
protected:
int command(int argc, const char*const* argv);
void recv(Packet* p, Handler* h);
NsObject* down_;
int status_;
};
static class DynamicLinkClass : public TclClass {
public:
DynamicLinkClass() : TclClass("DynamicLink") {}
TclObject* create(int, const char*const*) {
return (new DynamicLink);
}
} class_dynamic_link;
int DynamicLink::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "status?") == 0) {
Tcl::instance().result(status_ ? "up" : "down");
return TCL_OK;
}
}
return Connector::command(argc, argv);
}
void DynamicLink::recv(Packet* p, Handler* h)
{
if (status_)
target_->recv(p, h);
else
drop(p);
}
energy-model.cc
// Contributed by Satish Kumar
extern "C" {
#include
#include
};
#include "energy-model.h"
static class EnergyModelClass:public TclClass
{
public:
EnergyModelClass ():TclClass ("EnergyModel") { }
TclObject *create (int, const char *const *argv)
{
return (new EnergyModel (atof(argv[4]),atof(argv[5]),atof(argv[6])));
}
} class_energy_model;
errmodel.cc
/* -*- 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 Daedalus Research
* Group at the University of California Berkeley.
* 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.
*
* Contributed by the Daedalus Research Group, UC Berkeley
* (http://daedalus.cs.berkeley.edu)
*
* Multi-state error model patches contributed by Jianping Pan
* (jpan@bbcr.uwaterloo.ca).
*
* @(#) $Header$ (UCB)
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include "config.h"
#include
#include
#include "packet.h"
#include "flags.h"
#include "mcast_ctrl.h"
#include "errmodel.h"
#include "srm-headers.h" // to get the hdr_srm structure
#include "classifier.h"
static class ErrorModelClass : public TclClass {
public:
ErrorModelClass() : TclClass("ErrorModel") {}
TclObject* create(int, const char*const*) {
return (new ErrorModel);
}
} class_errormodel;
static class TwoStateErrorModelClass : public TclClass {
public:
TwoStateErrorModelClass() : TclClass("ErrorModel/TwoState") {}
TclObject* create(int, const char*const*) {
return (new TwoStateErrorModel);
}
} class_errormodel_twostate;
static class MultiStateErrorModelClass : public TclClass {
public:
MultiStateErrorModelClass() : TclClass("ErrorModel/MultiState") {}
TclObject* create(int, const char*const*) {
return (new MultiStateErrorModel);
}
} class_errormodel_multistate;
static class TraceErrorModelClass : public TclClass {
public:
TraceErrorModelClass() : TclClass("ErrorModel/Trace") {}
TclObject* create(int, const char*const*) {
return (new TraceErrorModel);
}
} class_traceerrormodel;
static char* eu_names[] = { EU_NAMES };
ErrorModel::ErrorModel() : firstTime_(1), unit_(EU_PKT), ranvar_(0)
{
bind("enable_", &enable_);
bind("rate_", &rate_);
bind_bw("bandwidth_", &bandwidth_); // required for EU_TIME
bind_bool("markecn_", &markecn_);
}
int ErrorModel::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
//ErrorModel *em;
if (argc == 3) {
if (strcmp(argv[1], "unit") == 0) {
unit_ = STR2EU(argv[2]);
return (TCL_OK);
}
if (strcmp(argv[1], "ranvar") == 0) {
ranvar_ = (RandomVariable*) TclObject::lookup(argv[2]);
return (TCL_OK);
}
} else if (argc == 2) {
if (strcmp(argv[1], "unit") == 0) {
tcl.resultf("%s", eu_names[unit_]);
return (TCL_OK);
}
if (strcmp(argv[1], "ranvar") == 0) {
tcl.resultf("%s", ranvar_->name());
return (TCL_OK);
}
}
return Connector::command(argc, argv);
}
void ErrorModel::reset()
{
firstTime_ = 1;
}
void ErrorModel::recv(Packet* p, Handler* h)
{
// 1. Determine the error by calling corrupt(p)
// 2. Set the packet's error flag if it is corrupted
// 3. If there is no error, no drop_ target or markecn is true,
// let pkt continue, otherwise hand the corrupted packet to drop_
hdr_cmn* ch = hdr_cmn::access(p);
int error = corrupt(p);
// XXX When we do ECN, the packet is marked but NOT dropped.
// So we don't resume handler here.
if (!markecn_ && (h && ((error && drop_) || !target_))) {
// if we drop or there is no target_, then resume handler
double delay = Random::uniform(8.0 * ch->size() / bandwidth_);
Scheduler::instance().schedule(h, &intr_, delay);
}
if (error) {
ch->error() |= error;
if (markecn_) {
hdr_flags* hf = hdr_flags::access(p);
hf->ce() = 1;
} else if (drop_) {
drop_->recv(p);
return;
}
}
if (target_) {
target_->recv(p, h);
}
}
int ErrorModel::corrupt(Packet* p)
{
if (enable_ == 0)
return 0;
switch (unit_) {
case EU_TIME:
return (CorruptTime(p) != 0);
case EU_BYTE:
return (CorruptByte(p) != 0);
default:
return (CorruptPkt(p) != 0);
}
return 0;
}
double ErrorModel::PktLength(Packet* p)
{
//double now;
if (unit_ == EU_PKT)
return 1;
int byte = hdr_cmn::access(p)->size();
if (unit_ == EU_BYTE)
return byte;
return 8.0 * byte / bandwidth_;
}
int ErrorModel::CorruptPkt(Packet*)
{
// if no random var is specified, assume uniform random variable
double u = ranvar_ ? ranvar_->value() : Random::uniform();
return (u < rate_);
}
int ErrorModel::CorruptByte(Packet* p)
{
// compute pkt error rate, assume uniformly distributed byte error
double per = 1 - pow(1.0 - rate_, PktLength(p));
double u = ranvar_ ? ranvar_->value() : Random::uniform();
return (u < per);
}
int ErrorModel::CorruptTime(Packet *)
{
fprintf(stderr, "Warning: uniform rate error cannot be time-based\n");
return 0;
}
#if 0
/*
* Decide whether or not to corrupt this packet, for a continuous
* time-based error model. The main parameter used is errLength,
* which is the time to the next error, from the last time an error
* occured on the channel. It is dependent on the random variable
* being used internally.
* rate_ is the user-specified mean
*/
int ErrorModel::CorruptTime(Packet *p)
{
/*
* First get MAC header. It has the transmission time (txtime)
* of the packet in one of it's fields. Then, get the time
* interval [t-txtime, t], where t is the current time. The
* goal is to figure out whether the channel would have
* corrupted the packet during that interval.
*/
Scheduler &s = Scheduler::instance();
double now = s.clock(), rv;
int numerrs = 0;
double start = now - hdr_mac::access(p)->txtime();
while (remainLen_ < start) {
rv = ranvar_ ? ranvar_->value() : Random::uniform(rate_);
remainLen_ += rv;
}
while (remainLen_ < now) { /* corrupt the packet */
numerrs++;
rv = ranvar_ ? ranvar_->value() : Random::uniform(rate_);
remainLen_ += rv;
}
return numerrs;
}
#endif
/*
* Two-State: error-free and error
*/
TwoStateErrorModel::TwoStateErrorModel() : remainLen_(0)
{
ranvar_[0] = ranvar_[1] = 0;
}
int TwoStateErrorModel::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (strcmp(argv[1], "ranvar") == 0) {
int i = atoi(argv[2]);
if (i < 0 || i > 1) {
tcl.resultf("%s does not has ranvar_[%d]", name_, i);
return (TCL_ERROR);
}
if (argc == 3) {
tcl.resultf("%s", ranvar_[i]->name());
return (TCL_OK);
}
// else if (argc == 4)
ranvar_[i] = (RandomVariable*)TclObject::lookup(argv[3]);
return (TCL_OK);
}
return ErrorModel::command(argc, argv);
}
int TwoStateErrorModel::corrupt(Packet* p)
{
#define ZERO 0.00000
int error;
if (firstTime_) {
firstTime_ = 0;
state_ = 0;
remainLen_ = ranvar_[state_]->value();
}
// if remainLen_ is outside the range of 0, then error = state_
error = state_ && (remainLen_ > ZERO);
remainLen_ -= PktLength(p);
// state transition until remainLen_ > 0 to covers the packet length
while (remainLen_ <= ZERO) {
state_ ^= 1; // state transition: 0 <-> 1
remainLen_ += ranvar_[state_]->value();
error |= state_;
}
return error;
}
static char * st_names[]={ST_NAMES};
/*
// MultiState ErrorModel:
// corrupt(pkt) invoke Tcl method "corrupt" to do state transition
// Tcl corrupt either:
// - assign em_, the error-model to be use
// - return the status of the packet
// If em_ is assigned, then invoke em_->corrupt(p)
*/
MultiStateErrorModel::MultiStateErrorModel() : em_(0)
{
bind("sttype_", &sttype_);
bind("texpired_", &texpired_);
bind("curperiod_", &curperiod_);
}
int MultiStateErrorModel::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "error-model") == 0) {
em_ = (ErrorModel*) TclObject::lookup(argv[2]);
return TCL_OK;
}
if (strcmp(argv[1], "sttype") == 0) {
sttype_ = STR2ST(argv[2]);
return TCL_OK;
}
} else if (argc == 2) {
if (strcmp(argv[1], "sttype") == 0) {
tcl.resultf("%s", st_names[sttype_]);
return TCL_OK;
}
if (strcmp(argv[1], "error-model") == 0) {
tcl.resultf("%s", (ErrorModel*) em_->name());
return TCL_OK;
}
}
return ErrorModel::command(argc, argv);
}
int MultiStateErrorModel::corrupt(Packet* p)
{
int retval;
double now;
static double prevTime_ = 0.0;
Scheduler & s = Scheduler::instance();
now = s.clock();
if (sttype_ == ST_TIME)
if ((now - prevTime_) >= curperiod_)
texpired_ = 1;
Tcl& tcl = Tcl::instance();
tcl.evalf("%s corrupt", name());
retval = em_ ? em_->corrupt(p) : atoi(tcl.result());
if (firstTime_) {
firstTime_ = 0;
prevTime_ = s.clock();
texpired_ = 0;
}
return (retval);
}
TraceErrorModel::TraceErrorModel() : loss_(0), good_(123456789)
{
bind("good_", &good_);
bind("loss_", &loss_);
}
/* opening and reading the trace file/info is done in OTcl */
int TraceErrorModel::corrupt(Packet* p)
{
Tcl& tcl = Tcl::instance();
if (! match(p))
return 0;
if ((good_ <= 0) && (loss_ <= 0)) {
tcl.evalf("%s read",name());
if (good_ < 0)
good_ = 123456789;
}
if (good_-- > 0)
return 0;
return (loss_-- > 0);
}
int TraceErrorModel::match(Packet*)
{
return 1;
}
/*
* Periodic ErrorModel
*/
static class PeriodicErrorModelClass : public TclClass {
public:
PeriodicErrorModelClass() : TclClass("ErrorModel/Periodic") {}
TclObject* create(int, const char*const*) {
return (new PeriodicErrorModel);
}
} class_periodic_error_model;
PeriodicErrorModel::PeriodicErrorModel() : cnt_(0), last_time_(0.0), first_time_(-1.0)
{
bind("period_", &period_);
bind("offset_", &offset_);
bind("burstlen_", &burstlen_);
}
int PeriodicErrorModel::corrupt(Packet* p)
{
hdr_cmn *ch = hdr_cmn::access(p);
double now = Scheduler::instance().clock();
if (unit_ == EU_TIME) {
if (first_time_ < 0.0) {
if (now >= offset_) {
first_time_ = last_time_ = now;
return 1;
}
} else {
if ((now - last_time_) > period_) {
last_time_ = now;
return 1;
}
if ((now - last_time_) < burstlen_) {
return 1;
}
}
return 0;
}
cnt_ += (unit_ == EU_PKT) ? 1 : ch->size();
if (int(first_time_) < 0) {
if (cnt_ >= int(offset_)) {
last_time_ = first_time_ = 1.0;
cnt_ = 0;
return 1;
}
return 0;
} else {
if (cnt_ >= int(period_)) {
cnt_ = 0;
return 1;
}
if (cnt_ < burstlen_)
return 1;
}
return 0;
}
/*
* List ErrorModel: specify a list of packets/bytes to drop
* can be specified in any order
*/
static class ListErrorModelClass : public TclClass {
public:
ListErrorModelClass() : TclClass("ErrorModel/List") {}
TclObject* create(int, const char*const*) {
return (new ListErrorModel);
}
} class_list_error_model;
int ListErrorModel::corrupt(Packet* p)
{
/* assumes droplist_ is sorted */
int rval = 0; // no drop
if (unit_ == EU_TIME) {
fprintf(stderr,
"ListErrorModel: error, EU_TIME not supported\n");
return 0;
}
if (droplist_ == NULL || dropcnt_ == 0) {
fprintf(stderr, "warning: ListErrorModel: null drop list\n");
return 0;
}
if (unit_ == EU_PKT) {
//printf("TEST: cur_:%d, dropcnt_:%d, droplist_[cur_]:%d, cnt_:%d\n",
//cur_, dropcnt_, droplist_[cur_], cnt_);
if ((cur_ < dropcnt_) && droplist_[cur_] == cnt_) {
rval = 1;
cur_++;
}
cnt_++;
} else if (unit_ == EU_BYTE) {
int sz = hdr_cmn::access(p)->size();
if ((cur_ < dropcnt_) && (cnt_ + sz) >= droplist_[cur_]) {
rval = 1;
cur_++;
}
cnt_ += sz;
}
return (rval);
}
int
ListErrorModel::command(int argc, const char*const* argv)
{
/*
* works for variable args:
* $lem droplist "1 3 4 5"
* and
* $lem droplist 1 3 4 5
*/
Tcl& tcl = Tcl::instance();
if (strcmp(argv[1], "droplist") == 0) {
int cnt;
if ((cnt = parse_droplist(argc-2, argv + 2)) < 0)
return (TCL_ERROR);
tcl.resultf("%u", cnt);
return(TCL_OK);
}
return (ErrorModel::command(argc, argv));
}
int
ListErrorModel::intcomp(const void *p1, const void *p2)
{
int a = *((int*) p1);
int b = *((int*) p2);
return (a - b);
}
/*
* nextval: find the next value in the string
*
* skip white space, update pointer to first non-white-space
* character. Return the number of characters in the next
* token.
*/
int
ListErrorModel::nextval(const char*& p)
{
while (*p && isspace(*p))
++p;
if (!*p) {
/* end of string */
return (0);
}
const char *q = p;
while (*q && !isspace(*q))
++q;
return (q-p);
}
int
ListErrorModel::parse_droplist(int argc, const char *const* argv)
{
int cnt = 0; // counter for argc list
int spaces = 0; // counts # of spaces in an argv entry
int total = 0; // total entries in the drop list
int n; // # of chars in the next drop number
const char *p; // ptr into current string
/*
* loop over argc list: figure out how many numbers
* have been specified
*/
while (cnt < argc) {
p = argv[cnt];
spaces = 0;
while ((n = nextval(p))) {
if (!isdigit(*p)) {
/* problem... */
fprintf(stderr, "ListErrorModel(%s): parse_droplist: unknown drop specifier starting at >>>%s\n",
name(), p);
return (-1);
}
++spaces;
p += n;
}
total += spaces;
cnt++;
}
/*
* parse the numbers, put them in an array (droplist_)
* set dropcnt_ to the total # of drops. Also, free any
* previous drop list.
*/
if ((total == 0) || (dropcnt_ > 0 && droplist_ != NULL)) {
delete[] droplist_;
droplist_ = NULL;
}
if ((dropcnt_ = total) == 0)
return (0);
droplist_ = new int[dropcnt_];
if (droplist_ == NULL) {
fprintf(stderr,
"ListErrorModel(%s): no memory for drop list!\n",
name());
return (-1);
}
int idx = 0;
cnt = 0;
while (cnt < argc) {
p = argv[cnt];
while ((n = nextval(p))) {
/*
* this depends on atoi(s) returning the
* value of the first number in s
*/
droplist_[idx++] = atoi(p);
p += n;
}
cnt++;
}
qsort(droplist_, dropcnt_, sizeof(int), intcomp);
/*
* sanity check the array, looking for (wrong) dups
*/
cnt = 0;
while (cnt < (dropcnt_ - 1)) {
if (droplist_[cnt] == droplist_[cnt+1]) {
fprintf(stderr,
"ListErrorModel: error: dup %d in list\n",
droplist_[cnt]);
total = -1; /* error */
}
++cnt;
}
if (total < 0) {
if (droplist_)
delete[] droplist_;
dropcnt_ = 0;
droplist_ = NULL;
return (-1);
}
#ifdef notdef
printf("sorted list:\n");
{
register i;
for (i =0; i < dropcnt_; i++) {
printf("list[%d] = %d\n", i, droplist_[i]);
}
}
#endif
return dropcnt_;
}
/***** ***/
static class SelectErrorModelClass : public TclClass {
public:
SelectErrorModelClass() : TclClass("SelectErrorModel") {}
TclObject* create(int, const char*const*) {
return (new SelectErrorModel);
}
} class_selecterrormodel;
SelectErrorModel::SelectErrorModel()
{
bind("pkt_type_", (int*)&pkt_type_);
bind("drop_cycle_", &drop_cycle_);
bind("drop_offset_", &drop_offset_);
}
int SelectErrorModel::command(int argc, const char*const* argv)
{
if (strcmp(argv[1], "drop-packet") == 0) {
pkt_type_ = packet_t(atoi(argv[2]));
drop_cycle_ = atoi(argv[3]);
drop_offset_ = atoi(argv[4]);
return TCL_OK;
}
return ErrorModel::command(argc, argv);
}
int SelectErrorModel::corrupt(Packet* p)
{
if (unit_ == EU_PKT) {
hdr_cmn *ch = hdr_cmn::access(p);
// XXX Backward compatibility for cbr agents
if (ch->ptype() == PT_UDP && pkt_type_ == PT_CBR)
pkt_type_ = PT_UDP; // "udp" rather than "cbr"
if (ch->ptype() == pkt_type_ && ch->uid() % drop_cycle_
== drop_offset_) {
//printf ("dropping packet type %d, uid %d\n",
// ch->ptype(), ch->uid());
return 1;
}
}
return 0;
}
/* Error model for srm experiments */
class SRMErrorModel : public SelectErrorModel {
public:
SRMErrorModel();
virtual int corrupt(Packet*);
protected:
int command(int argc, const char*const* argv);
};
static class SRMErrorModelClass : public TclClass {
public:
SRMErrorModelClass() : TclClass("SRMErrorModel") {}
TclObject* create(int, const char*const*) {
return (new SRMErrorModel);
}
} class_srmerrormodel;
SRMErrorModel::SRMErrorModel()
{
}
int SRMErrorModel::command(int argc, const char*const* argv)
{
//int ac = 0;
if (strcmp(argv[1], "drop-packet") == 0) {
pkt_type_ = packet_t(atoi(argv[2]));
drop_cycle_ = atoi(argv[3]);
drop_offset_ = atoi(argv[4]);
return TCL_OK;
}
return ErrorModel::command(argc, argv);
}
int SRMErrorModel::corrupt(Packet* p)
{
if (unit_ == EU_PKT) {
hdr_srm *sh = hdr_srm::access(p);
hdr_cmn *ch = hdr_cmn::access(p);
// XXX Backward compatibility for cbr agents
if (ch->ptype()==PT_UDP && pkt_type_==PT_CBR && sh->type() == SRM_DATA)
pkt_type_ = PT_UDP; // "udp" rather than "cbr"
if ((ch->ptype() == pkt_type_) && (sh->type() == SRM_DATA) &&
(sh->seqnum() % drop_cycle_ == drop_offset_)) {
//printf ("dropping packet type SRM-DATA, seqno %d\n",
//sh->seqnum());
return 1;
}
}
return 0;
}
static class MrouteErrorModelClass : public TclClass {
public:
MrouteErrorModelClass() : TclClass("ErrorModel/Trace/Mroute") {}
TclObject* create(int, const char*const*) {
return (new MrouteErrorModel);
}
} class_mrouteerrormodel;
MrouteErrorModel::MrouteErrorModel() : TraceErrorModel()
{
bind("off_mcast_ctrl_", &off_mcast_ctrl_);
}
int MrouteErrorModel::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "drop-packet") == 0) {
const char* s = argv[2];
int n = strlen(s);
if (n >= this->maxtype()) {
// tcl.result("message type too big");
return (TCL_ERROR);
}
strcpy(msg_type,s);
return(TCL_OK);
}
}
return TraceErrorModel::command(argc, argv);
}
int MrouteErrorModel::match(Packet* p)
{
hdr_mcast_ctrl* ph = (hdr_mcast_ctrl*)p->access(off_mcast_ctrl_);
int indx = strcspn(ph->type(),"/");
if (!strncmp(ph->type(),msg_type,indx)) {
return 1;
}
return 0;
}
static class ErrorModuleClass : public TclClass {
public:
ErrorModuleClass() : TclClass("ErrorModule") {}
TclObject* create(int, const char*const*) {
return (new ErrorModule);
}
} class_errormodule;
void ErrorModule::recv(Packet *p, Handler *h)
{
classifier_->recv(p, h);
}
int ErrorModule::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);
}
} else if (argc == 3) {
if (strcmp(argv[1], "classifier") == 0) {
classifier_ = (Classifier*)
TclObject::lookup(argv[2]);
if (classifier_ == NULL) {
tcl.resultf("Couldn't look up classifier %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (Connector::command(argc, argv));
}
estimator.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "estimator.h"
Estimator::Estimator() : meas_mod_(0),avload_(0.0),est_timer_(this), measload_(0.0), tchan_(0), omeasload_(0), oavload_(0)
{
bind("period_",&period_);
bind("src_", &src_);
bind("dst_", &dst_);
avload_.tracer(this);
avload_.name("\"Estimated Util.\"");
measload_.tracer(this);
measload_.name("\"Measured Util.\"");
}
int Estimator::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc==2) {
if (strcmp(argv[1],"load-est") == 0) {
tcl.resultf("%.3f",double(avload_));
return(TCL_OK);
} else if (strcmp(argv[1],"link-utlzn") == 0) {
tcl.resultf("%.3f",meas_mod_->bitcnt()/period_);
return(TCL_OK);
}
}
if (argc == 3) {
if (strcmp(argv[1], "attach") == 0) {
int mode;
const char* id = argv[2];
tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode);
if (tchan_ == 0) {
tcl.resultf("Estimator: trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "setbuf") == 0) {
/* some sub classes actually do something here */
return(TCL_OK);
}
}
return NsObject::command(argc,argv);
}
void Estimator::setmeasmod (MeasureMod *measmod)
{
meas_mod_=measmod;
}
void Estimator::start()
{
avload_=0;
measload_ = 0;
est_timer_.resched(period_);
}
void Estimator::stop()
{
est_timer_.cancel();
}
void Estimator::timeout(int)
{
estimate();
est_timer_.resched(period_);
}
void Estimator_Timer::expire(Event* /*e*/)
{
est_->timeout(0);
}
void Estimator::trace(TracedVar* v)
{
char wrk[500];
double *p, newval;
/* check for right variable */
if (strcmp(v->name(), "\"Estimated Util.\"") == 0) {
p = &oavload_;
}
else if (strcmp(v->name(), "\"Measured Util.\"") == 0) {
p = &omeasload_;
}
else {
fprintf(stderr, "Estimator: unknown trace var %s\n", v->name());
return;
}
newval = double(*((TracedDouble*)v));
if (tchan_) {
int n;
double t = Scheduler::instance().clock();
/* f -t 0.0 -s 1 -a SA -T v -n Num -v 0 -o 0 */
sprintf(wrk, "f -t %g -s %d -a %s:%d-%d -T v -n %s -v %g -o %g",
t, src_, actype_, src_, dst_, v->name(), newval, *p);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(tchan_, wrk, n+1);
}
*p = newval;
return;
}
void Estimator::setactype(const char* type)
{
actype_ = new char[strlen(type)+1];
strcpy(actype_, type);
return;
}
expavg-est.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include
#include "estimator.h"
class ExpAvg_Est : public Estimator {
public:
ExpAvg_Est() {bind("w_",&w_);};
protected:
void estimate();
double w_;
};
void ExpAvg_Est::estimate()
{
avload_=(1-w_)*avload_+w_*meas_mod_->bitcnt()/period_;
//printf("%f %f %f\n",Scheduler::instance().clock(),avload_,meas_mod_->bitcnt()/period_);
fflush(stdout);
meas_mod_->resetbitcnt();
}
static class ExpAvg_EstClass : public TclClass {
public:
ExpAvg_EstClass() : TclClass ("Est/ExpAvg") {}
TclObject* create(int,const char*const*) {
return (new ExpAvg_Est());
}
}class_expavg_est;
expoo.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or derivative
* work. Xerox grants no other licenses expressed or implied. The Xerox trade
* name should not be used in any advertising without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (Xerox)";
#endif
#include
#include "random.h"
#include "trafgen.h"
#include "ranvar.h"
/* implement an on/off source with exponentially distributed on and
* off times. parameterized by average burst time, average idle time,
* burst rate and packet size.
*/
class EXPOO_Traffic : public TrafficGenerator {
public:
EXPOO_Traffic();
virtual double next_interval(int&);
virtual void timeout();
protected:
void init();
double ontime_; /* average length of burst (sec) */
double offtime_; /* average length of idle time (sec) */
double rate_; /* send rate during on time (bps) */
double interval_; /* packet inter-arrival time during burst (sec) */
unsigned int rem_; /* number of packets left in current burst */
/* new stuff using RandomVariable */
ExponentialRandomVariable burstlen_;
ExponentialRandomVariable Offtime_;
};
static class EXPTrafficClass : public TclClass {
public:
EXPTrafficClass() : TclClass("Application/Traffic/Exponential") {}
TclObject* create(int, const char*const*) {
return (new EXPOO_Traffic());
}
} class_expoo_traffic;
EXPOO_Traffic::EXPOO_Traffic() : burstlen_(0.0), Offtime_(0.0)
{
bind_time("burst_time_", &ontime_);
bind_time("idle_time_", Offtime_.avgp());
bind_bw("rate_", &rate_);
bind("packetSize_", &size_);
}
void EXPOO_Traffic::init()
{
/* compute inter-packet interval during bursts based on
* packet size and burst rate. then compute average number
* of packets in a burst.
*/
interval_ = (double)(size_ << 3)/(double)rate_;
burstlen_.setavg(ontime_/interval_);
rem_ = 0;
if (agent_)
agent_->set_pkttype(PT_EXP);
}
double EXPOO_Traffic::next_interval(int& size)
{
double t = interval_;
if (rem_ == 0) {
/* compute number of packets in next burst */
rem_ = int(burstlen_.value() + .5);
/* make sure we got at least 1 */
if (rem_ == 0)
rem_ = 1;
/* start of an idle period, compute idle time */
t += Offtime_.value();
}
rem_--;
size = size_;
return(t);
}
void EXPOO_Traffic::timeout()
{
if (! running_)
return;
/* send a packet */
// The test tcl/ex/test-rcvr.tcl relies on the "NEW_BURST" flag being
// set at the start of any exponential burst ("talkspurt").
if (nextPkttime_ != interval_ || nextPkttime_ == -1)
agent_->sendmsg(size_, "NEW_BURST");
else
agent_->sendmsg(size_);
/* figure out when to send the next one */
nextPkttime_ = next_interval(size_);
/* schedule it */
if (nextPkttime_ > 0)
timer_.resched(nextPkttime_);
}
filter.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* filter.cc
* Copyright (C) 1998 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /usr/src/mash/repository/vint/ns-2/filter.cc ";
#endif
#include "packet.h"
#include "filter.h"
static class FilterClass : public TclClass {
public:
FilterClass() : TclClass("Filter") {}
TclObject* create(int, const char*const*) {
return (new Filter);
}
} class_filter;
Filter::Filter() : filter_target_(0)
{
}
Filter::filter_e Filter::filter(Packet* /*p*/)
{
return PASS; // As simple connector
}
void Filter::recv(Packet* p, Handler* h)
{
switch(filter(p)) {
case DROP :
if (h) h->handle(p);
drop(p);
break;
case DUPLIC :
if (filter_target_)
filter_target_->recv(p->copy(), h);
/* fallthrough */
case PASS :
send(p, h);
break;
case FILTER :
if (filter_target_)
filter_target_->recv(p, h);
break;
}
}
int Filter::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "filter-target") == 0) {
if (filter_target_ != 0)
tcl.result(target_->name());
return TCL_OK;
}
}
else if (argc == 3) {
if (strcmp(argv[1], "filter-target") == 0) {
filter_target_ = (NsObject*)TclObject::lookup(argv[2]);
return TCL_OK;
}
}
return Connector::command(argc, argv);
}
static class FieldFilterClass : public TclClass {
public:
FieldFilterClass() : TclClass("Filter/Field") {}
TclObject* create(int, const char*const*) {
return (new FieldFilter);
}
} class_filter_field;
FieldFilter::FieldFilter()
{
bind("offset_", &offset_);
bind("match_", &match_);
}
Filter::filter_e FieldFilter::filter(Packet *p)
{
return (*(int *)p->access(offset_) == match_) ? FILTER : PASS;
}
/* 10-5-98, Polly Huang, Filters that filter on multiple fields */
static class MultiFieldFilterClass : public TclClass {
public:
MultiFieldFilterClass() : TclClass("Filter/MultiField") {}
TclObject* create(int, const char*const*) {
return (new MultiFieldFilter);
}
} class_filter_multifield;
MultiFieldFilter::MultiFieldFilter() : field_list_(0)
{
}
void MultiFieldFilter::add_field(fieldobj *p)
{
p->next = field_list_;
field_list_ = p;
}
MultiFieldFilter::filter_e MultiFieldFilter::filter(Packet *p)
{
fieldobj* tmpfield;
tmpfield = field_list_;
while (tmpfield != 0) {
if (*(int *)p->access(tmpfield->offset) == tmpfield->match)
tmpfield = tmpfield->next;
else
return (PASS);
}
return(FILTER);
}
int MultiFieldFilter::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "filter-target") == 0) {
if (filter_target_ != 0)
tcl.result(target_->name());
return TCL_OK;
}
}
else if (argc == 3) {
if (strcmp(argv[1], "filter-target") == 0) {
filter_target_ = (NsObject*)TclObject::lookup(argv[2]);
return TCL_OK;
}
}
else if (argc == 4) {
if (strcmp(argv[1], "filter-field") == 0) {
fieldobj *tmp = new fieldobj;
tmp->offset = atoi(argv[2]);
tmp->match = atoi(argv[3]);
add_field(tmp);
return TCL_OK;
}
}
return Connector::command(argc, argv);
}
flowmon.cc
/* -*- 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$ (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
#include "config.h"
#include "queue-monitor.h"
#include "classifier.h"
#include "ip.h"
// for convenience, we need most of the stuff in a QueueMonitor
// plus some flow info which looks like pkt header info
class Flow : public EDQueueMonitor {
public:
Flow() : src_(-1), dst_(-1), fid_(-1), type_(PT_NTYPE) {
bind("off_ip_" ,&off_ip_);
bind("src_", &src_);
bind("dst_", &dst_);
bind("flowid_", &fid_);
}
nsaddr_t src() const { return (src_); }
nsaddr_t dst() const { return (dst_); }
int flowid() const { return (fid_); }
packet_t ptype() const { return (type_); }
void setfields(Packet *p) {
hdr_ip* hdr = (hdr_ip*)p->access(off_ip_);
hdr_cmn* chdr = (hdr_cmn*)p->access(off_cmn_);
src_ = hdr->saddr();
dst_ = hdr->daddr();
fid_ = hdr->flowid();
type_ = chdr->ptype();
}
protected:
int off_ip_;
nsaddr_t src_;
nsaddr_t dst_;
int fid_;
packet_t type_;
};
/*
* flow monitoring is performed like queue-monitoring with
* a classifier to demux by flow
*/
class FlowMon : public EDQueueMonitor {
public:
FlowMon();
void in(Packet*); // arrivals
void out(Packet*); // departures
void drop(Packet*); // all drops (incl
void edrop(Packet*); // "early" drops
int command(int argc, const char*const* argv);
protected:
void dumpflows();
void dumpflow(Tcl_Channel, Flow*);
void fformat(Flow*);
char* flow_list();
Classifier* classifier_;
Tcl_Channel channel_;
int enable_in_; // enable per-flow arrival state
int enable_out_; // enable per-flow depart state
int enable_drop_; // enable per-flow drop state
int enable_edrop_; // enable per-flow edrop state
char wrk_[2048]; // big enough to hold flow list
};
FlowMon::FlowMon() : classifier_(NULL), channel_(NULL),
enable_in_(1), enable_out_(1), enable_drop_(1), enable_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);
}
}
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",
#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",
#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]
);
};
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) {
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));
}
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;
fq.cc
/* -*- 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (ANS)";
#endif
#include "config.h"
#include
#include "queue.h"
/*XXX*/
#define MAXFLOW 32
class FQ : public Queue {
public:
FQ();
virtual int command(int argc, const char*const* argv);
Packet *deque(void);
void enque(Packet *pkt);
void recv(Packet* p, Handler* h);
protected:
int update();
struct flowState {
Queue* q_;
Packet* hol_; /* head-of-line packet for each flow */
double finishTime_; /* FQ finish time for hol packet */
double delta_;
Handler* handler_;
} fs_[MAXFLOW];
inline double finish(const flowState& fs, int nactive)
{
return (fs.finishTime_ + fs.delta_ * nactive);
}
int maxflow_;
double secsPerByte_;
int off_ip_;
};
static class FQClass : public TclClass {
public:
FQClass() : TclClass("Queue/FQ") {}
TclObject* create(int, const char*const*) {
return (new FQ);
}
} class_fq;
FQ::FQ()
{
for (int i = 0; i < MAXFLOW; ++i) {
fs_[i].q_ = 0;
fs_[i].hol_ = 0;
fs_[i].finishTime_ = 0.;
}
maxflow_ = -1;
secsPerByte_ = 0.;
bind("secsPerByte_", &secsPerByte_);
bind("off_ip_", &off_ip_);
}
int FQ::command(int argc, const char*const* argv)
{
if (argc == 4) {
if (strcmp(argv[1], "install") == 0) {
int flowID = atoi(argv[2]);
fs_[flowID].q_ = (Queue*)TclObject::lookup(argv[3]);
if (flowID > maxflow_)
maxflow_ = flowID;
/*XXX*/
if (flowID >= MAXFLOW)
abort();
return (TCL_OK);
}
}
return (Queue::command(argc, argv));
}
/*XXX this is quite inefficient.*/
int FQ::update()
{
int nactive = 0;
for (int i = 0; i <= maxflow_; ++i) {
Queue* q = fs_[i].q_;
if (q != 0) {
if (fs_[i].hol_ == 0) {
Packet* p = q->deque();
if (p != 0) {
fs_[i].hol_ = p;
++nactive;
}
} else
++nactive;
}
}
return (nactive);
}
Packet* FQ::deque()
{
int nactive = update();
int target = -1;
double best;
for (int i = 0; i <= maxflow_; ++i) {
if (fs_[i].hol_ != 0) {
if (target < 0) {
target = i;
best = finish(fs_[i], nactive);
} else {
double F = finish(fs_[i], nactive);
if (F < best) {
target = i;
best = F;
}
}
}
}
if (target >= 0) {
Packet* p = fs_[target].hol_;
fs_[target].hol_ = 0;
fs_[target].finishTime_ = best;
/* let this upstream queue resume */
Handler* h = fs_[target].handler_;
/*XXX null event okay because queue doesn't use it*/
h->handle(0);
return (p);
}
return (0);
}
/*
* Called when one of our queues is unblocked by us in FQ::deque
* (or gets its first packet).
*/
void FQ::recv(Packet* p, Handler* handler)
{
hdr_ip* h = (hdr_ip*)p->access(off_ip_);
int flowid = h->flowid();
/* shouldn't be called when head-of-line is pending */
if (flowid >= MAXFLOW || fs_[flowid].hol_ != 0)
abort();
/*
* Put this packet at the head-of-line for its queue
* and set up scheduling state according to the
* standard fair-queueing "finish time" equation.
*/
fs_[flowid].hol_ = p;
double now = Scheduler::instance().clock();
if (now > fs_[flowid].finishTime_)
fs_[flowid].finishTime_ = now;
fs_[flowid].handler_ = handler;
int size = ((hdr_cmn*)p->access(off_cmn_))->size();
fs_[flowid].delta_ = size * secsPerByte_;
if (!blocked_) {
/*
* We're not blocked. Get a packet and send it on.
* We perform an extra check because the queue
* might drop the packet even if it was
* previously empty! (e.g., RED can do this.)
*/
p = deque();
if (p != 0) {
blocked_ = 1;
target_->recv(p, &qh_);
}
}
}
void FQ::enque(Packet*)
{
/* should never be called because we override recv */
abort();
}
fsm.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/* fsm.cc
* Copyright (C) 1999 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang
*
* @(#) $Header$ (LBL)
*/
#include "fsm.h"
#include
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
FSM* FSM::instance_;
TahoeAckFSM* TahoeAckFSM::instance_;
RenoAckFSM* RenoAckFSM::instance_;
TahoeDelAckFSM* TahoeDelAckFSM::instance_;
RenoDelAckFSM* RenoDelAckFSM::instance_;
void
FSMState::number_all()
{
if (processed())
return;
static int next_i = 0;
print_i_ = ++next_i;
//
int i;
for (i = 0; i < 17; i++)
if (drop_[i])
drop_[i]->number_all();
}
void
FSMState::reset_all_processed()
{
if (print_i_ == 0)
number_all();
// requires a full traversal always to work
if (!processed())
return;
print_i_ = -print_i_;
int i;
for (i = 0; i < 17; i++)
if (drop_[i])
drop_[i]->reset_all_processed();
}
void
FSMState::print_all(int level)
{
if (processed())
return;
const int SPACES_PER_LEVEL = 2;
printf("#%-2d %*s %d:\n", print_i_, level * SPACES_PER_LEVEL + 1, " ", batch_size_);
int i;
for (i = 0; i <= batch_size_; i++) {
static char *delay_names[] = {"done", "error", "RTT", "timeout" };
assert(transition_[i] >= -1 && transition_[i] <= TIMEOUT);
printf(" %*s %d %s -> #%d\n", level * SPACES_PER_LEVEL + 3, " ",
i,
delay_names[transition_[i]+1],
drop_[i] ? drop_[i]->print_i_ : 0);
if (drop_[i])
drop_[i]->print_all(level + 1);
};
}
static void
report_stat_terminus(int desired_pkts, // # needed
int pkts, // # got so far
int rtts, // # of rtt events
int timeouts, // # of to events
int ps, // # of times taken a prob. p event (pkt received OK)
int qs, // # of times taken a prob. q event (pkt dropped OK)
int num_states, // size of the stack
int num_state_names,
FSMState **states,
char *state_names)
{
// print states and probability
printf("%s: p^%d*q^%d, %d rtt, %d timeouts, %d states:",
(pkts > desired_pkts ? "exceeded-pkts" :
(pkts == desired_pkts ? "desired_pkts" : "unimplemented-qs")),
ps, qs,
rtts, timeouts,
num_states);
char ch = ' ';
int i;
for (i = 0; i < num_states; i++) {
printf ("%c#%d", ch, states[i]->print_i_);
ch = ',';
};
printf(" [%.*s]\n", num_state_names, state_names);
}
/*
* FSMState::print_all_stats:
* Walk through the tcp state table exhaustively.
* Recurse to handle errors.
* Very hairy.
* johnh.
*/
void
FSMState::print_all_stats(int desired_pkts_total, // # needed
int pkts, // # got so far
int rtts, // # of rtt events
int timeouts, // # of to events
int ps, // # of times taken a prob. p event (pkt received OK)
int qs, // # of times taken a prob. q event (pkt dropped OK)
int num_states, // size of the stack
int num_state_names)
{
int i;
#define LARGER_NUMBER_OF_STATES 31 // was 17
static FSMState *states[LARGER_NUMBER_OF_STATES];
static char state_names[LARGER_NUMBER_OF_STATES*4]; // xxx: this is just some random big size :-(
if (pkts >= desired_pkts_total || qs > 5) {
// done; print states and probability
// (give up when we're where we want to be [good],
// or we've taken too many losses [to prevent recursion])
report_stat_terminus(desired_pkts_total, pkts, rtts, timeouts, ps, qs, num_states, num_state_names, states, state_names);
return;
};
// remember us!
states[num_states] = this;
num_states++;
// xxx: doesn't handle TCP tail behavior
//
// first, consider the no-loss case
//
int desired_pkts_remaining = desired_pkts_total - pkts;
int desired_pkts_this_round = MIN(desired_pkts_remaining, batch_size_);
for (i = 0; i< desired_pkts_this_round; i++)
state_names[num_state_names + i] = 's';
if (desired_pkts_remaining > desired_pkts_this_round) {
// more to do? take a rtt hit and keep going
state_names[num_state_names + desired_pkts_this_round] = '.';
drop_[0]->print_all_stats(desired_pkts_total,
pkts + desired_pkts_this_round,
rtts + 1, timeouts,
ps + desired_pkts_this_round, qs,
num_states,
num_state_names + desired_pkts_this_round + 1);
} else {
// no more to do... report out
report_stat_terminus(desired_pkts_total,
pkts + desired_pkts_this_round,
rtts, timeouts,
ps + desired_pkts_this_round, qs,
num_states,
num_state_names + desired_pkts_this_round,
states,
state_names);
};
//
// now consider losses
//
int desired_pkts_with_loss = MAX(desired_pkts_this_round - 1, 0);
// loop through losing the i'th packet for all possible i's.
// Can't loop through more than we could have sent.
for (i = 1; i <= desired_pkts_this_round; i++) {
// keep track of sending patterns
if (i > 1)
state_names[num_state_names + i - 2] = 's';
state_names[num_state_names + i - 1] = 'd';
state_names[num_state_names + desired_pkts_this_round] = (transition_[i] == RTT ? '.' : '-');
// can we even have any?
if (qs) {
// not if we already had one!
report_stat_terminus(desired_pkts_total,
pkts + i - 1,
rtts, timeouts,
ps + i - 1, qs + 1,
num_states,
num_state_names + i,
states,
state_names);
} else {
// recurse... assume the rest made it
drop_[i]->print_all_stats(desired_pkts_total, pkts + desired_pkts_with_loss,
rtts + (transition_[i] == RTT ? 1 : 0),
timeouts + (transition_[i] == TIMEOUT ? 1 : 0),
ps + desired_pkts_with_loss, qs + 1,
num_states,
num_state_names + desired_pkts_this_round + 1);
// 2nd drop somewhere in this round?
int remaining_pkts_this_round = desired_pkts_this_round - i;
if (qs == 0 && remaining_pkts_this_round > 0) {
// yes, generate the probs
int j;
for (j = i+1; j <= desired_pkts_this_round; j++) {
if (j > i+1)
state_names[num_state_names + j - 1] = 's';
state_names[num_state_names + j] = 'd';
report_stat_terminus(desired_pkts_total,
pkts + j - 2,
rtts, timeouts,
ps + j - 2, qs + 2,
num_states,
num_state_names + j,
states,
state_names);
};
};
};
};
}
void
FSM::print_FSM(FSMState* state)
{
#if 0
int i;
if (state != NULL) {
for (i=0; i<17; i++) {
if (state->drop_[i] != NULL) {
if (i==0)
printf("%d->(%d) ", state->transition_[i], state->drop_[i]->batch_size_);
else
printf("\n%d->(%d) ", state->transition_[i], state->drop_[i]->batch_size_);
print_FSM(state->drop_[i]);
}
}
}
#else /* ! 0 */
state->reset_all_processed();
state->print_all(0);
#endif /* 0 */
}
void
FSM::print_FSM_stats(FSMState* state, int n)
{
state->reset_all_processed();
state->print_all_stats(n);
fflush(stdout);
}
static class TahoeAckFSMClass : public TclClass {
public:
TahoeAckFSMClass() : TclClass("FSM/TahoeAck") {}
TclObject* create(int , const char*const*) {
return (new TahoeAckFSM);
}
} class_tahoeackfsm;
static class RenoAckFSMClass : public TclClass {
public:
RenoAckFSMClass() : TclClass("FSM/RenoAck") {}
TclObject* create(int , const char*const*) {
return (new RenoAckFSM);
}
} class_renoackfsm;
static class TahoeDelAckFSMClass : public TclClass {
public:
TahoeDelAckFSMClass() : TclClass("FSM/TahoeDelAck") {}
TclObject* create(int , const char*const*) {
return (new TahoeDelAckFSM);
}
} class_tahoedelackfsm;
static class RenoDelAckFSMClass : public TclClass {
public:
RenoDelAckFSMClass() : TclClass("FSM/RenoDelAck") {}
TclObject* create(int , const char*const*) {
return (new RenoDelAckFSM);
}
} class_renodelackfsm;
// ***********************************************
// Tahoe-Ack TCP Connection Finite State Machine *
// ***********************************************
TahoeAckFSM::TahoeAckFSM() : FSM(), start_state_(NULL)
{
int i;
FSMState* tmp;
instance_ = this;
// (wnd, ssh) == (1, 20)
start_state_ = new FSMState;
//printf("creating Tahoe Ack FSM\n");
for (i=0; i<17; i++) {
start_state_->drop_[i] = NULL;
start_state_->transition_[i] = -1;
}
start_state_->batch_size_ = 1;
// (wnd, ssh) == (2, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0] = tmp;
start_state_->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->transition_[2] = RTT;
// (wnd, ssh) == (4, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[4] = RTT;
//(wnd, ssh) == (8, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[4] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[5] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 10;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[6] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 12;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[7] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 14;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[8] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[8] = RTT;
//(wnd, ssh) == (16, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 16;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
for (i=1; i<17; i++) start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[i] = tmp;
for (i=1; i<14; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = RTT;
for (i=14; i<17; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = TIMEOUT;
//(wnd, ssh) == (1, 2), timeout
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[1] = tmp;
start_state_->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[2]->transition_[0] = TIMEOUT;
start_state_->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[1] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[2]->transition_[0] = RTT;
//(wnd, ssh) == (2, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0] = tmp;
start_state_->drop_[1]->transition_[0] = RTT;
//(wnd, ssh) == (2.5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (6, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (7, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 7;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (7, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 7;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 3)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[4]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 4)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[1] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->transition_[0] = 0;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 5)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->transition_[0] = 0;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 6)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 7)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[8]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[8]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0]->drop_[0]->transition_[0] = RTT;
//print_FSM(start_state_);
//printf("\n");
}
// **********************************************
// Reno-ACK TCP Connection Finite State Machine *
// **********************************************
RenoAckFSM::RenoAckFSM() : FSM(), start_state_(NULL)
{
int i;
FSMState* tmp;
//printf("creating Reno Ack FSM\n");
instance_ = this;
// (wnd, ssh) == (1, 20)
start_state_ = new FSMState;
for (i=0; i<17; i++) {
start_state_->drop_[i] = NULL;
start_state_->transition_[i] = -1;
}
start_state_->batch_size_ = 1;
// (wnd, ssh) == (2, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0] = tmp;
start_state_->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->transition_[2] = RTT;
// (wnd, ssh) == (4, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[4] = RTT;
//(wnd, ssh) == (8, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[4] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[5] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 10;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[6] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 12;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[7] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 14;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[8] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[8] = RTT;
//(wnd, ssh) == (16, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 16;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
for (i=1; i<17; i++) start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[i] = tmp;
for (i=1; i<14; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = RTT;
for (i=14; i<17; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = TIMEOUT;
//(wnd, ssh) == (1, 2), timeout
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[1] = tmp;
start_state_->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[2]->transition_[0] = TIMEOUT;
//(wnd, ssh) == (2, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0] = tmp;
start_state_->drop_[1]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[1] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[2]->transition_[0] = RTT;
//(wnd, ssh) == (2.5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (6, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (7, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 7;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (7.5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 7;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3, 3)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[4]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4, 4)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[1] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (5, 5)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->transition_[0] = 0;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 7;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (6, 6)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->transition_[0] = 0;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[6]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 7;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (7, 7)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 7;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[7]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[8]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[8]->transition_[0] = RTT;
//print_FSM(start_state_);
//printf("\n");
}
// *****************************************************
// Tahoe-Delay Ack TCP Connection Finite State Machine *
// *****************************************************
TahoeDelAckFSM::TahoeDelAckFSM() : FSM(), start_state_(NULL)
{
int i;
FSMState* tmp;
//printf("creating Tahoe DelAck FSM\n");
instance_ = this;
// (wnd, ssh) == (1, 20)
start_state_ = new FSMState;
for (i=0; i<17; i++) {
start_state_->drop_[i] = NULL;
start_state_->transition_[i] = -1;
}
start_state_->batch_size_ = 1;
// (wnd, ssh) == (2, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0] = tmp;
start_state_->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->transition_[2] = RTT;
// (wnd, ssh) == (3, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[3] = RTT;
//(wnd, ssh) == (5, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[4] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[5] = RTT;
//(wnd, ssh) == (8, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[4] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[5] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[5] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[6] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[6] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 9;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[7] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[7] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 11;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[8] = RTT;
//(wnd, ssh) == (12, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 12;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
for (i=1; i<13; i++) start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[i] = tmp;
for (i=1; i<10; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = RTT;
for (i=10; i<13; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = TIMEOUT;
//(wnd, ssh) == (1, 2), timeout
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[1] = tmp;
start_state_->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[2]->transition_[0] = TIMEOUT;
start_state_->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[2]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[1] = RTT;
//(wnd, ssh) == (2, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0] = tmp;
start_state_->drop_[1]->transition_[0] = RTT;
//(wnd, ssh) == (2.5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (2.9, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3.3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4.7, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (6, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 3)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 4)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[1] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[3]->transition_[0] = 0;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 5)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[5]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[6]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[6]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[7]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (1, 6)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8]->drop_[0]->transition_[0] = RTT;
//print_FSM(start_state_);
//printf("\n");
}
// ****************************************************
// Reno-Delay Ack TCP Connection Finite State Machine *
// ****************************************************
RenoDelAckFSM::RenoDelAckFSM() : FSM(), start_state_(NULL)
{
int i;
FSMState* tmp;
//printf("creating Reno DelAck FSM\n");
instance_ = this;
// (wnd, ssh) == (1, 20)
start_state_ = new FSMState;
for (i=0; i<17; i++) {
start_state_->drop_[i] = NULL;
start_state_->transition_[i] = -1;
}
start_state_->batch_size_ = 1;
// (wnd, ssh) == (2, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0] = tmp;
start_state_->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->transition_[2] = RTT;
// (wnd, ssh) == (3, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[3] = RTT;
//(wnd, ssh) == (5, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[4] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[5] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[4]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[5]->transition_[0] = RTT;
//(wnd, ssh) == (8, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[2] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[3] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[3] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[3]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[4] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[5] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[5] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 8;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[6] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[6] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 9;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[7] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[7] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 11;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[8] = RTT;
//(wnd, ssh) == (12, 20)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 12;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
for (i=1; i<13; i++) start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[i] = tmp;
for (i=1; i<10; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = RTT;
for (i=10; i<13; i++)
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[i] = TIMEOUT;
//(wnd, ssh) == (1, 2), timeout
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 1;
start_state_->drop_[1] = tmp;
start_state_->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[2]->transition_[0] = TIMEOUT;
start_state_->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->transition_[1] = TIMEOUT;
start_state_->drop_[0]->drop_[0]->drop_[2]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[2]->transition_[0] = TIMEOUT;
//(wnd, ssh) == (2, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0] = tmp;
start_state_->drop_[1]->transition_[0] = RTT;
//(wnd, ssh) == (2.5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (2.9, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3.3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4.7, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (6, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[1]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (2, 2), rtt
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->transition_[1] = RTT;
//(wnd, ssh) == (2.5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 2;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4.3, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4.7, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (5, 2)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (3.3, 3)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 3;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[3]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (4, 4)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->transition_[1] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 4;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[2]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[1]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (5, 5)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[5]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[5]->transition_[0] = 0;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[6]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[6]->transition_[0] = RTT;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[7]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[7]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->transition_[0] = RTT;
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 5;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[4]->drop_[0]->drop_[0]->transition_[0] = RTT;
//(wnd, ssh) == (6, 6)
tmp = new FSMState;
for (i=0; i<17; i++) {
tmp->drop_[i] = NULL;
tmp->transition_[i] = -1;
}
tmp->batch_size_ = 6;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8]->drop_[0] = tmp;
start_state_->drop_[0]->drop_[0]->drop_[0]->drop_[0]->drop_[8]->transition_[0] = RTT;
//print_FSM(start_state_);
//printf("\n");
}
god.cc
/* -*- 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma.*/
/* god.cc
General Operations Director
perform operations requiring omnipotence in the simulation
NOTE: Tcl node indexs are 0 based, NS C++ node IP addresses (and the
node->index() are 1 based.
$Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $
*/
#include
#include
#include
#include
God* God::instance_;
static class GodClass : public TclClass {
public:
GodClass() : TclClass("God") {}
TclObject* create(int, const char*const*) {
return (new God);
}
} class_God;
God::God()
{
min_hops = 0;
num_nodes = 0;
}
int
God::hops(int i, int j)
{
return min_hops[i * num_nodes + j];
}
void
God::stampPacket(Packet *p)
{
hdr_cmn *ch = HDR_CMN(p);
struct hdr_ip *ih = HDR_IP(p);
nsaddr_t src = ih->saddr();
nsaddr_t dst = ih->daddr();
assert(min_hops);
if (!packet_info.data_packet(ch->ptype())) return;
if (dst > num_nodes || src > num_nodes) return; // broadcast pkt
ch->opt_num_forwards() = min_hops[src * num_nodes + dst];
}
void
God::recv(Packet *, Handler *)
{
abort();
}
int
God::command(int argc, const char* const* argv)
{
Tcl& tcl = Tcl::instance();
if ((instance_ == 0) || (instance_ != this))
instance_ = this;
if (argc == 2) {
if(strcmp(argv[1], "dump") == 0) {
int i, j;
for(i = 1; i < num_nodes; i++) {
fprintf(stdout, "%2d) ", i);
for(j = 1; j < num_nodes; j++)
fprintf(stdout, "%2d ",
min_hops[i * num_nodes + j]);
fprintf(stdout, "\n");
}
return TCL_OK;
}
if(strcmp(argv[1], "num_nodes") == 0) {
tcl.resultf("%d", nodes());
return TCL_OK;
}
}
else if(argc == 3) {
if (strcasecmp(argv[1], "num_nodes") == 0) {
assert(num_nodes == 0);
// allow for 0 based to 1 based conversion
num_nodes = atoi(argv[2]) + 1;
min_hops = new int[num_nodes * num_nodes];
bzero((char*) min_hops,
sizeof(int) * num_nodes * num_nodes);
instance_ = this;
return TCL_OK;
}
}
else if(argc == 5) {
if (strcasecmp(argv[1], "set-dist") == 0) {
int i = atoi(argv[2]);
int j = atoi(argv[3]);
int d = atoi(argv[4]);
assert(i >= 0 && i < num_nodes);
assert(j >= 0 && j < num_nodes);
min_hops[i * num_nodes + j] = d;
min_hops[j * num_nodes + i] = d;
return TCL_OK;
}
}
return BiConnector::command(argc, argv);
}
gridkeeper.cc
/*
* An optimizer for some wireless simulations
*
* Helps most when some nodes are mostly stationary.
* We hope you can share your experience with the gridkeeper with us.
*
* Ported from Sun's mobility code
*/
#include "gridkeeper.h"
static double d2(double x1, double x2, double y1, double y2)
{
return ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
/*
static class GridHandlerClass : public TclClass {
public:
GridHandlerClass() : TclClass("GridHandler") {}
TclObject* create(int, const char*const*){
return (new GridHandler());
}
} class_grid_handler;
*/
GridHandler::GridHandler()
{
}
void GridHandler::handle(Event *e)
{
MoveEvent *me = (MoveEvent *)e;
MobileNode **pptr;
MobileNode * token_ = me->token_;
if ((pptr = me->leave_)) {
while (*pptr) {
if ((*pptr)->address_ == token_->address_) break;
pptr = &((*pptr)->next_);
}
if (!(*pptr)) abort();
else {
*pptr = token_->next_;
token_->next_ = 0;
}
}
if ((pptr = me->enter_)) {
if (token_->next_) abort(); // can't be in more than one grid
token_->next_ = *pptr;
*pptr = token_;
}
delete me;
// dump info in the gridkeeper for debug only
// dump();
}
GridKeeper* GridKeeper::instance_;
static class GridKeeperClass : public TclClass {
public:
GridKeeperClass() : TclClass("GridKeeper") {}
TclObject* create(int, const char*const*) {
return (new GridKeeper);
}
} class_grid_keeper;
GridKeeper::GridKeeper() : size_(0),grid_(NULL), dim_x_(0), dim_y_(0)
{
gh_ = new GridHandler();
}
GridKeeper::~GridKeeper()
{
int i;
for (i = 0; i <= dim_x_; i++) {
delete [] grid_[i];
}
delete [] grid_;
}
int GridKeeper::command(int argc, const char*const* argv)
{
int i, grid_x, grid_y;
Tcl& tcl = Tcl::instance();
MobileNode *mn;
if (argc == 2) {
if (strcmp(argv[1], "dump") == 0) {
dump();
return (TCL_OK);
}
}
if (argc == 3) {
if (strcmp(argv[1], "addnode") == 0) {
mn = (MobileNode *)TclObject::lookup(argv[2]);
grid_x = aligngrid((int)mn->X, dim_x_);
grid_y = aligngrid((int)mn->Y, dim_y_);
mn->next_ = grid_[grid_x][grid_y];
grid_[grid_x][grid_y] = mn;
size_++;
return (TCL_OK);
}
}
if (argc == 4 && strcmp(argv[1], "dimension") == 0) {
if (instance_ == 0) instance_ = this;
dim_x_ = strtol(argv[2], (char**)0, 0);
dim_y_ = strtol(argv[3], (char**)0, 0);
if (dim_x_ <= 0 || dim_y_ <= 0) {
tcl.result("illegal grid dimension");
return (TCL_ERROR);
}
grid_ = new MobileNode **[dim_x_];
for (i = 0; i < dim_x_; i++) {
grid_[i] = new MobileNode *[dim_y_];
bzero((void *)grid_[i], sizeof(MobileNode *)*dim_y_);
}
return (TCL_OK);
}
return (TclObject::command(argc, argv));
}
void GridKeeper::new_moves(MobileNode *mn)
{
double x = mn->X, y = mn->Y;
double ss = mn->speed;
double vx = (mn->dX)*ss, vy = (mn->dY)*ss;
// double interval = mn->position_update_interval;
double endx, endy, pother, tm;
int i, j, endi, gother, grid_x, grid_y;
MoveEvent *me;
Scheduler& s = Scheduler::instance();
endx = mn->destX;
endy = mn->destY;
if (vx > 0) {
endi = min(dim_x_-1, (int)endx);
for (i = (int)x+1; i <= endi; i++) {
tm = (i-x)/vx;
pother = vy*tm + y;
j = (int)pother;
me = new MoveEvent;
if (j == pother && j != 0 && j != dim_y_) {
if (vy > 0) gother = j - 1;
else if (vy < 0) gother = j + 1;
else gother = j;
}
else {
gother = j;
}
me->leave_ = &(grid_[aligngrid(i-1, dim_x_)][aligngrid(gother, dim_y_)]);
me->grid_x_ = grid_x = aligngrid(i, dim_x_);
me->grid_y_ = grid_y = aligngrid(j, dim_y_);
me->enter_ = &(grid_[grid_x][grid_y]);
me->token_ = mn;
s.schedule(gh_, me, tm);
}
}
else if (vx < 0) {
endi = (int)endx;
for (i = (int)x; i > endi; i--) {
if (i == dim_x_) continue;
tm = (i-x)/vx;
pother = vy*tm + y;
j = (int)pother;
me = new MoveEvent;
if (j == pother && j != 0 && j != dim_y_) {
if (vy > 0) gother = j - 1;
else if (vy < 0) gother = j + 1;
else gother = j;
}
else {
gother = j;
}
me->leave_ = &grid_[aligngrid(i, dim_x_)][aligngrid(gother, dim_y_)];
me->grid_x_ = grid_x = aligngrid(i-1, dim_x_);
me->grid_y_ = grid_y = aligngrid(j, dim_y_);
me->enter_ = &grid_[grid_x][grid_y];
me->token_ = mn;
s.schedule(gh_, me, tm);
}
}
if (vy > 0) {
endi = min(dim_y_-1, (int)endy);
for (j = (int)y+1; j <= endi; j++) {
tm = (j-y)/vy;
pother = vx*tm + x;
i = (int)pother;
me = new MoveEvent;
if (i == pother && i != 0 && i != dim_x_ && vx != 0) continue;
me->leave_ = &grid_[aligngrid(i, dim_x_)][aligngrid(j-1, dim_y_)];
me->grid_x_ = grid_x = aligngrid(i, dim_x_);
me->grid_y_ = grid_y = aligngrid(j, dim_y_);
me->enter_ = &grid_[grid_x][grid_y];
me->token_ = mn;
s.schedule(gh_, me, tm);
}
}
else if (vy < 0) {
endi = (int)endy;
for (j = (int)y; j > endi; j--) {
if (j == dim_y_) continue;
tm = (j-y)/vy;
pother = vx*tm + x;
i = (int)pother;
me = new MoveEvent;
if (i == pother && i != 0 && i != dim_x_ && vx != 0) continue;
me->leave_ = &grid_[aligngrid(i, dim_x_)][aligngrid(j, dim_y_)];
me->grid_x_ = grid_x = aligngrid(i, dim_x_);
me->grid_y_ = grid_y = aligngrid(j-1, dim_y_);
me->enter_ = &grid_[grid_x][grid_y];
me->token_ = mn;
s.schedule(gh_, me, tm);
}
}
}
int GridKeeper::get_neighbors(MobileNode* mn, MobileNode **output)
{
int grid_x, grid_y, index = 0, i, j, ulx, uly, lly, adj;
MobileNode *pgd;
double mnx, mny, mnr, sqmnr;
mn->update_position();
mnx = mn->X;
mny = mn->Y;
grid_x = aligngrid((int)mn->X, dim_x_);
grid_y = aligngrid((int)mn->Y, dim_y_);
sqmnr = (mnr = mn->radius_)*mnr;
adj = (int)ceil(mnr);
ulx = min(dim_x_-1, grid_x + adj);
uly = min(dim_y_-1, grid_y + adj);
lly = max(0, grid_y - adj);
for (i = max(0, grid_x - adj); i <= ulx; i++) {
for (j = lly; j <= uly; j++) {
for (pgd = grid_[i][j]; pgd != 0; pgd = pgd->next_) {
if (mn->address_ == pgd->address_) continue;
pgd->update_position();
if (d2(pgd->X, mnx, pgd->Y, mny) < sqmnr)
output[index++] = pgd;
}
}
}
return index;
}
void GridKeeper::dump()
{
int i,j;
MobileNode *pgd;
for (i = 0; i< dim_x_; i++) {
for (j = 0; j < dim_y_; j++) {
if (grid_[i][j] == 0) continue;
printf("grid[%d][%d]: ",i,j);
for (pgd = grid_[i][j]; pgd != 0; pgd = pgd->next_) {
printf("%d ",pgd->address_);
}
printf("\n");
}
}
printf("-------------------------------\n");
}
hackloss.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "connector.h"
#include "packet.h"
#include "queue.h"
class HackLossyLink : public Connector {
public:
HackLossyLink() : down_(0), src_(0), dst_(0), fid_(0), ctr_(0), nth_(0){
bind("off_ip_", &off_ip_);
}
protected:
int command(int argc, const char*const* argv);
void recv(Packet* p, Handler* h);
NsObject* down_;
int src_, dst_, fid_;
int ctr_, nth_;
int off_ip_;
};
static class HackLossyLinkClass : public TclClass {
public:
HackLossyLinkClass() : TclClass("HackLossyLink") {}
TclObject* create(int, const char*const*) {
return (new HackLossyLink);
}
} class_dynamic_link;
int HackLossyLink::command(int argc, const char*const* argv)
{
if (strcmp(argv[1], "down-target") == 0) {
NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
if (p == 0) {
Tcl::instance().resultf("no object %s", argv[2]);
return TCL_ERROR;
}
down_ = p;
return TCL_OK;
}
if (strcmp(argv[1], "show-params") == 0) {
Tcl::instance().resultf("src_ = %d, dst_ = %d, fid_ = %d, nth_ = %d",
src_, dst_, fid_, nth_);
return TCL_OK;
}
if (strcmp(argv[1], "set-params") == 0) {
src_ = atoi(argv[2]);
dst_ = atoi(argv[3]);
fid_ = atoi(argv[4]);
return TCL_OK;
}
if (strcmp(argv[1], "nth") == 0) {
nth_ = atoi(argv[2]);
return TCL_OK;
}
return Connector::command(argc, argv);
}
void HackLossyLink::recv(Packet* p, Handler* h)
{
hdr_ip* iph = (hdr_ip*) p->access(off_ip_);
if (nth_ && (iph->flowid() == fid_) &&
(iph->saddr() == src_) && (iph->daddr() == dst_) &&
((++ctr_ % nth_) == 0))
down_->recv(p); // XXX Why no handler?
else
target_->recv(p, h);
}
hb-adc.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
//Hoeffding Bounds Admission Control
#include "adc.h"
#include
#include
class HB_ADC : public ADC {
public:
HB_ADC();
void teardown_action(int,double,int);
void rej_action(int,double,int);
protected:
int admit_flow(int,double,int);
int rejected_;
double epsilon_;
double sump2_;
};
HB_ADC::HB_ADC() : rejected_(0), sump2_(0)
{
bind("epsilon_", &epsilon_);
type_ = new char[3];
strcpy(type_, "HB");
}
int HB_ADC::admit_flow(int cl,double r,int b)
{
//get peak rate this class of flow
double p=peak_rate(cl,r,b);
if (backoff_) {
if (rejected_)
return 0;
}
//printf("Peak rate: %f Avload: %f Rem %f %f %f\n",p,est_[cl]->avload(),sqrt(log(1/epsilon_)*sump2_/2),log(1/epsilon_),sump2_);
if ((p+est_[cl]->avload()+sqrt(log(1/epsilon_)*sump2_/2)) <= bandwidth_) {
sump2_+= p*p;
est_[cl]->change_avload(p);
return 1;
}
else {
rejected_=1;
return 0;
}
}
void HB_ADC::rej_action(int cl,double r,int b)
{
double p=peak_rate(cl,r,b);
sump2_ -= p*p;
}
void HB_ADC::teardown_action(int cl,double r,int b)
{
rejected_=0;
double p=peak_rate(cl,r,b);
sump2_ -= p*p;
}
static class HB_ADCClass : public TclClass {
public:
HB_ADCClass() : TclClass("ADC/HB") {}
TclObject* create(int,const char*const*) {
return (new HB_ADC());
}
}class_hb_adc;
integrator.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include
#include "integrator.h"
static class IntegratorClass : public TclClass {
public:
IntegratorClass() : TclClass("Integrator") {}
TclObject* create(int, const char*const*) {
return (new Integrator);
}
} integrator_class;
Integrator::Integrator() : lastx_(0.), lasty_(0.), sum_(0.)
{
bind("lastx_", &lastx_);
bind("lasty_", &lasty_);
bind("sum_", &sum_);
}
void Integrator::set(double x, double y)
{
lastx_ = x;
lasty_ = y;
sum_ = 0.;
}
void Integrator::newPoint(double x, double y)
{
sum_ += (x - lastx_) * lasty_;
lastx_ = x;
lasty_ = y;
}
int Integrator::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "reset") == 0) {
set(0., 0.);
return (TCL_OK);
}
} else if (argc == 4) {
if (strcmp(argv[1], "newpoint") == 0) {
double x = atof(argv[2]);
double y = atof(argv[3]);
newPoint(x, y);
return (TCL_OK);
}
}
return (TclObject::command(argc, argv));
}
/*
* interface for the 'Samples' class, will probably want to move
* to some sort of "stats" file at some point
*/
static class SamplesClass : public TclClass {
public:
SamplesClass() : TclClass("Samples") {}
TclObject* create(int, const char*const*) {
return (new Samples);
}
} samples_class;
int Samples::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "mean") == 0) {
if (cnt_ > 0) {
Tcl::instance().resultf("%g", mean());
return (TCL_OK);
}
Tcl::instance().resultf("tried to take mean with no sample points");
return (TCL_ERROR);
}
if (strcmp(argv[1], "cnt") == 0) {
Tcl::instance().resultf("%u", cnt());
return (TCL_OK);
}
if (strcmp(argv[1], "variance") == 0) {
if (cnt_ == 1) {
Tcl::instance().resultf("0.0");
return (TCL_OK);
}
if (cnt_ > 2) {
Tcl::instance().resultf("%g", variance());
return (TCL_OK);
}
return (TCL_ERROR);
}
if (strcmp(argv[1], "reset") == 0) {
reset();
return (TCL_OK);
}
} else if ( argc == 3 ) {
if ( strcmp(argv[1],"newpoint") == 0 ) {
double x = atof(argv[2]);
newPoint(x);
return (TCL_OK);
}
}
return (TclObject::command(argc, argv));
}
ip.cc
/* -*- 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "packet.h"
#include "ip.h"
int hdr_ip::offset_;
static class IPHeaderClass : public PacketHeaderClass {
public:
IPHeaderClass() : PacketHeaderClass("PacketHeader/IP",
sizeof(hdr_ip)) {
bind_offset(&hdr_ip::offset_);
}
void export_offsets() {
field_offset("src_", OFFSET(hdr_ip, src_));
field_offset("dst_", OFFSET(hdr_ip, dst_));
field_offset("ttl_", OFFSET(hdr_ip, ttl_));
field_offset("fid_", OFFSET(hdr_ip, fid_));
field_offset("prio_", OFFSET(hdr_ip, prio_));
}
} class_iphdr;
ivs.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1996-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 Computer Systems
* Engineering Group at Lawrence Berkeley 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$ (LBL)";
#endif
#include
#include
#include "message.h"
#include "trace.h"
#include "agent.h"
/* ivs data packet; ctrl packets are sent back as "messages" */
struct hdr_ivs {
double ts_; /* timestamp sent at source */
u_int8_t S_;
u_int8_t R_;
u_int8_t state_;
u_int8_t rshft_;
u_int8_t kshft_;
u_int16_t key_;
double maxrtt_;
int seqno_;
static int offset_;
inline static int& offset() { return offset_; }
inline static hdr_ivs* access(Packet* p) {
return (hdr_ivs*) p->access(offset_);
}
/* per-field member functions */
double& ts() { return (ts_); }
u_int8_t& S() { return (S_); }
u_int8_t& R() { return (R_); }
u_int8_t& state() { return (state_); }
u_int8_t& rshft() { return (rshft_); }
u_int8_t& kshft() { return (kshft_); }
u_int16_t& key() { return (key_); }
double& maxrtt() { return (maxrtt_); }
int& seqno() { return (seqno_); }
};
int hdr_ivs::offset_;
static class IvsHeaderClass : public PacketHeaderClass {
public:
IvsHeaderClass() : PacketHeaderClass("PacketHeader/IVS",
sizeof(hdr_ivs)) {
bind_offset(&hdr_ivs::offset_);
}
} class_ivshdr;
class IvsSource : public Agent {
public:
IvsSource();
protected:
void reset();
void recv(Packet *pkt, Handler*);
void sendpkt();
int S_;
int R_;
int state_;
#define ST_U 0
#define ST_L 1
#define ST_C 2
int rttShift_;
int keyShift_;
int key_;
double maxrtt_;
int off_ivs_;
int off_msg_;
};
struct Mc_Hole {
int start;
int end;
double time;
Mc_Hole* next;
};
class IvsReceiver : public Agent {
public:
IvsReceiver();
int command(int argc, const char*const* argv);
protected:
void recv(Packet *pkt, Handler*);
void update_ipg(double now);
int lossMeter(double timeDiff, u_int32_t seq, double maxrtt);
void upcall_respond(double ts, int matchS);
void upcall_rtt_solicit(double ts, int rshift);
int state_;
u_int32_t nextSeq_;
double timeMean_;
double timeVar_;
double ipg_; /* interpkt gap (estimator) */
Mc_Hole* head_;
Mc_Hole* tail_;
double lastPktTime_;
int ignoreR_;
double lastTime_; /* last time a resp pkt sent */
int key_;
int off_ivs_;
int off_msg_;
};
static class IvsSourceClass : public TclClass {
public:
IvsSourceClass() : TclClass("Agent/IVS/Source") {}
TclObject* create(int, const char*const*) {
return (new IvsSource());
}
} class_ivs_source;
static class IvsReceiverClass : public TclClass {
public:
IvsReceiverClass() : TclClass("Agent/IVS/Receiver") {}
TclObject* create(int, const char*const*) {
return (new IvsReceiver());
}
} class_ivs_receiver;
IvsSource::IvsSource() : Agent(PT_MESSAGE), S_(0), R_(0), state_(ST_U),
rttShift_(0), keyShift_(0), key_(0), maxrtt_(0)
{
bind("S_", &S_);
bind("R_", &R_);
bind("state_", &state_);
bind("rttShift_", &rttShift_);
bind("keyShift_", &keyShift_);
bind("key_", &key_);
bind("maxrtt_", &maxrtt_);
bind("off_ivs_", &off_ivs_);
bind("off_msg_", &off_msg_);
}
void IvsSource::reset()
{
}
/*
* main reception path - should only see acks, otherwise the
* network connections are misconfigured
*/
void IvsSource::recv(Packet* pkt, Handler*)
{
char wrk[128];/*XXX*/
Tcl& tcl = Tcl::instance();
hdr_msg *q = (hdr_msg*)pkt->access(off_msg_);
sprintf(wrk, "%s handle {%s}", name(), q->msg());
tcl.eval(wrk);
Packet::free(pkt);
}
#ifdef notdef
void IvsSource::probe_timeout()
{
rndStart_ = now;
if (keyShift_ == 15) {
if (key_ == 0) {
if (solicitedResponses_ == 0)
estReceivers_ = 0;
/*
* Got through a round without being LOADED.
* increase send rate.
*/
if (state_ == ST_U)
increase();
/* Reset keys et al */
S_ = 1;
state_ = ST_U;
/*XXX*/
setRttSolicit(mcstate);
solicitedResponses_ = 0;
keyShift_ = startShift_;
/*XXX do all this in tcl? */
setkey();
} else { mcstate->hdr.key = 0; }
} else {
if (probeTimeout_ > 0)
++keyShift_;
}
sched(pktTime + 2 * maxrtt_, IVS_TIMER_PROBE);
}
#endif
void IvsSource::sendpkt()
{
Packet* pkt = allocpkt();
hdr_ivs *p = (hdr_ivs*)pkt->access(off_ivs_);
/*fill in ivs fields */
p->ts() = Scheduler::instance().clock();
p->S() = S_;
p->R() = R_;
p->state() = state_;
p->rshft() = rttShift_;
p->kshft() = keyShift_;
p->key() = key_;
p->maxrtt() = maxrtt_;
target_->recv(pkt, (Handler *)0);
}
IvsReceiver::IvsReceiver() : Agent(PT_MESSAGE), state_(ST_U),
nextSeq_(0),
timeMean_(0.), timeVar_(0.),/*XXX*/
ipg_(0.),
head_(0),
tail_(0),
lastPktTime_(0.),
ignoreR_(0),
lastTime_(0.),
key_(0)
{
bind("ignoreR_", &ignoreR_);
bind("key_", &key_);
bind("state_", &state_);
bind("packetSize_", &size_);
bind("off_ivs_", &off_ivs_);
bind("off_msg_", &off_msg_);
}
inline void IvsReceiver::update_ipg(double v)
{
/* Update the estimated interpacket gap */
ipg_ = (15 * ipg_ + v) / 16;
}
/*
* timestamp comes in milliseconds since start of connection according to
* remote clock
* now is milliseconds since start of connection
* rtt in milliseconds
* This congestion meter is not terribly good at figuring out when the net is
* loaded, since the loss of a packet over a rtt is a transitory event
* Eventually we ought to have a memory thing, that records state once a
* maxrtt, with thresholds to decide current state
*/
int IvsReceiver::lossMeter(double timeDiff, u_int32_t seq, double maxrtt)
{
/*
* The congestion signal is calculated here by measuring the loss in a
* given period of packets - if the threshold for lost packets is
* passed then signal Congested. If there are no lost packets,
* then we are at UNLOADED, else LOADED
*/
/* if sequence number is next, increase expected number */
double now = Scheduler::instance().clock();
if (nextSeq_ == 0)
nextSeq_ = seq + 1;
else if (seq == nextSeq_)
nextSeq_++;
else if (seq > nextSeq_) {
#ifdef notdef
if (trace_ != 0) {
sprintf(trace_->buffer(), "d %g %d",
lastPktTime_, seq - nextSeq_);
trace_->dump();
}
#endif
/* This is definitely a hole */
Mc_Hole* hole = new Mc_Hole;
hole->time = now;
hole->start = nextSeq_;
hole->end = seq - 1;
hole->next = 0;
/* Now add it to the list */
if (head_ == NULL) {
head_ = hole;
tail_ = hole;
} else {
tail_->next = hole;
tail_ = hole;
}
nextSeq_ = seq + 1;
} else {
/* XXX can't happen in current ns simulations */
fprintf(stderr, "ns: ivs rcvr: seq number went backward\n");
abort();
}
/* update the calculation of the variance in the rtt */
/* get the time averaged mean of the difference */
if (timeMean_ == 0)
timeMean_ = timeDiff;
else
timeMean_ = (7 * timeMean_ + timeDiff) / 8;
timeDiff -= timeMean_;
if (timeDiff < 0)
timeDiff = -timeDiff;
timeVar_ = (7 * timeVar_ + timeDiff) / 8;
int lostPkts = 0;
/*
* Check down the list of holes, discarding those that before
* now-rttvar-rtt, counting those that fall within
* now-rttvar to now-rttvar-rtt
*/
if (head_ == 0)
return (ST_U);
Mc_Hole *cur = head_, *prev = NULL;
double validEnd = now - 2 * timeVar_;
double validStart = validEnd - maxrtt;
/* for each hole, if it is older than required, dump it */
/* If it is valid, add the size to the loss count */
/* Go to the next hole */
while (cur != NULL) {
if (cur->time < validStart) {
if (prev == NULL)
head_ = cur->next;
else
prev->next = cur->next;
delete cur;
if (prev == NULL)
cur = head_;
else
cur = prev->next;
} else {
if (cur->time < validEnd)
lostPkts += cur->end - cur->start + 1;
prev = cur;
cur = cur->next;
}
}
/*
* Update the moving average calculation of the number of holes, if
* nowMs is another rtt away
*/
double pps = (ipg_ != 0) ? maxrtt / ipg_ : 0.;
/*XXX*/
#ifdef notdef
if (trace_ != 0) {
double now = Scheduler::instance().clock();
sprintf(trace_->buffer(), "%.17g %g", now,
(double)lostPkts / pps);
trace_->dump();
}
#endif
/*XXX*/
#define LOSSCONGTH 15
#define LOSSLOADTH 5
/* If the rtt is smaller than the ipg, set the thresholds to 0,1,2 */
if ((pps * LOSSCONGTH) / 100 < 2)
pps = 200 / LOSSCONGTH;
if (lostPkts <= (LOSSLOADTH * pps) / 100)
return (ST_U);
else if (lostPkts <= (LOSSCONGTH * pps) / 100)
return (ST_L);
else
return (ST_C);
}
void IvsReceiver::recv(Packet* pkt, Handler*)
{
hdr_ivs *p = (hdr_ivs*)pkt->access(off_ivs_);
double now = Scheduler::instance().clock();
if (lastPktTime_ == 0.) {
lastPktTime_ = now;
Packet::free(pkt);
return;
}
update_ipg(now - lastPktTime_);
double ts = p->ts();
int prevState = state_;
state_ = lossMeter(now - ts, p->seqno(), p->maxrtt());
lastPktTime_ = now;
/* If soliciting rtt */
if (p->R() && !ignoreR_)
/* upcall into tcl */
upcall_rtt_solicit(ts, p->rshft());
/*
* send a response if we're congested and its over an rtt since
* we last sent one OR
* any response is solicited to estimate size and we match the key OR
* we're LOADED and we match the key and its over an rtt since we last
* sent a response
*/
if (now - lastTime_ < p->maxrtt() && state_ <= prevState) {
Packet::free(pkt);
return;
}
int shift = p->kshft();
int match;
if (p->key() == 0)
match = 1;
else
match = (key_ >> shift) == (p->key() >> shift);
int matchS = match ? p->S() : 0;
if (state_ == ST_C || matchS || (match && state_ == ST_L)) {
upcall_respond(ts, matchS);
lastTime_ = now;
}
Packet::free(pkt);
}
void IvsReceiver::upcall_respond(double ts, int matchS)
{
Tcl::instance().evalf("%s respond %.17g %d", name(), ts, matchS);
}
void IvsReceiver::upcall_rtt_solicit(double ts, int rshift)
{
Tcl::instance().evalf("%s solicit-rtt %.17g %d", name(), ts, rshift);
}
int IvsReceiver::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "send") == 0) {
Packet* pkt = allocpkt();
hdr_msg* p = (hdr_msg*)pkt->access(off_msg_);
const char* s = argv[2];
int n = strlen(s);
if (n >= p->maxmsg()) {
tcl.result("message too big");
Packet::free(pkt);
return (TCL_ERROR);
}
strcpy(p->msg(), s);
target_->recv(pkt, (Handler*)0);
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
lanRouter.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* lanRouter.cc
* Copyright (C) 1998 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: /usr/src/mash/repository/vint/ns-2/lanRouter.cc";
#endif
#include
#include
#include "lanRouter.h"
#include "address.h"
#include "ip.h"
static class LanRouterClass : public TclClass {
public:
LanRouterClass() : TclClass("LanRouter") {}
TclObject* create(int, const char*const*) {
return (new LanRouter());
}
} class_mac;
int LanRouter::next_hop(Packet *p) {
if (switch_ && switch_->classify(p)==1) {
return -1;
}
if (!routelogic_) return -1;
hdr_ip* iph= hdr_ip::access(p);
char* adst= Address::instance().print_nodeaddr(iph->daddr());
int next_hopIP;
if (enableHrouting_) {
char* bdst;
routelogic_->lookup_hier(lanaddr_, adst, next_hopIP);
// hacking: get rid of the last "."
bdst = Address::instance().print_nodeaddr(next_hopIP);
// bdst[strlen(bdst)-1] = '\0';
Tcl &tcl = Tcl::instance();
tcl.evalf("[Simulator instance] get-node-id-by-addr %s", bdst);
sscanf(tcl.result(), "%d", &next_hopIP);
delete [] bdst;
} else {
routelogic_->lookup_flat(lanaddr_, adst, next_hopIP);
}
delete [] adst;
return next_hopIP;
}
int LanRouter::command(int argc, const char*const* argv)
{
// Tcl& tcl = Tcl::instance();
if (argc == 3) {
// cmd lanaddr
if (strcmp(argv[1], "lanaddr") == 0) {
strcpy(lanaddr_, argv[2]);
return (TCL_OK);
}
// cmd routing hier|flat
if (strcmp(argv[1], "routing") == 0) {
if (strcmp(argv[2], "hier")==0)
enableHrouting_= true;
else if (strcmp(argv[2], "flat")==0)
enableHrouting_= false;
else return (TCL_ERROR);
return (TCL_OK);
}
// cmd switch
if (strcmp(argv[1], "switch") == 0) {
switch_ = (Classifier*) TclObject::lookup(argv[2]);
return (TCL_OK);
}
// cmd routelogic
if (strcmp(argv[1], "routelogic") == 0) {
routelogic_ = (RouteLogic*) TclObject::lookup(argv[2]);
return (TCL_OK);
}
}
return NsObject::command(argc, argv);
}
ll.cc
/* -*- 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 Daedalus Research
* Group at the University of California Berkeley.
* 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.
*
* Contributed by the Daedalus Research Group, http://daedalus.cs.berkeley.edu
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include
#include
#include
#include
#include
int hdr_ll::offset_;
static class LLHeaderClass : public PacketHeaderClass {
public:
LLHeaderClass() : PacketHeaderClass("PacketHeader/LL",
sizeof(hdr_ll)) {
bind_offset(&hdr_ll::offset_);
}
} class_hdr_ll;
static class LLClass : public TclClass {
public:
LLClass() : TclClass("LL") {}
TclObject* create(int, const char*const*) {
return (new LL);
}
} class_ll;
LL::LL() : LinkDelay(), seqno_(0), ackno_(0), macDA_(0), ifq_(0),
mac_(0), lanrouter_(0), arptable_(0), varp_(0),
downtarget_(0), uptarget_(0)
{
bind("macDA_", &macDA_);
}
int LL::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "ifq") == 0) {
ifq_ = (Queue*) TclObject::lookup(argv[2]);
return (TCL_OK);
}
if(strcmp(argv[1], "arptable") == 0) {
arptable_ = (ARPTable*)TclObject::lookup(argv[2]);
assert(arptable_);
return TCL_OK;
}
if(strcmp(argv[1], "varp") == 0) {
varp_ = (VARPTable*)TclObject::lookup(argv[2]);
assert(varp_);
return TCL_OK;
}
if (strcmp(argv[1], "mac") == 0) {
mac_ = (Mac*) TclObject::lookup(argv[2]);
assert(mac_);
return (TCL_OK);
}
if (strcmp(argv[1], "down-target") == 0) {
downtarget_ = (NsObject*) TclObject::lookup(argv[2]);
return (TCL_OK);
}
if (strcmp(argv[1], "up-target") == 0) {
uptarget_ = (NsObject*) TclObject::lookup(argv[2]);
return (TCL_OK);
}
if (strcmp(argv[1], "lanrouter") == 0) {
lanrouter_ = (LanRouter*) TclObject::lookup(argv[2]);
return (TCL_OK);
}
}
else if (argc == 2) {
if (strcmp(argv[1], "ifq") == 0) {
tcl.resultf("%s", ifq_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "mac") == 0) {
tcl.resultf("%s", mac_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "down-target") == 0) {
tcl.resultf("%s", downtarget_->name());
return (TCL_OK);
}
if (strcmp(argv[1], "up-target") == 0) {
tcl.resultf("%s", uptarget_->name());
return (TCL_OK);
}
}
return LinkDelay::command(argc, argv);
}
void LL::recv(Packet* p, Handler* /*h*/)
{
hdr_cmn *ch = HDR_CMN(p);
//char *mh = (char*) HDR_MAC(p);
//struct hdr_sr *hsr = HDR_SR(p);
/*
* Sanity Check
*/
assert(initialized());
if(p->incoming) {
p->incoming = 0;
}
// If direction = UP, then pass it up the stack
// Otherwise, set direction to DOWN and pass it down the stack
if(ch->direction() == hdr_cmn::UP) {
//if(mac_->hdr_type(mh) == ETHERTYPE_ARP)
if(ch->ptype_ == PT_ARP)
arptable_->arpinput(p, this);
else
uptarget_ ? sendUp(p) : drop(p);
return;
}
ch->direction() = hdr_cmn::DOWN;
sendDown(p);
}
void LL::sendDown(Packet* p)
{
hdr_cmn *ch = HDR_CMN(p);
hdr_ip *ih = HDR_IP(p);
// XXX HACK for now - Padma, 03/99.
nsaddr_t dst = (nsaddr_t)Address::instance().get_nodeaddr(ih->daddr());
//nsaddr_t dst = ih->dst();
hdr_ll *llh = HDR_LL(p);
char *mh = (char*)p->access(hdr_mac::offset_);
llh->seqno_ = ++seqno_;
llh->lltype() = LL_DATA;
mac_->hdr_src(mh, mac_->addr());
mac_->hdr_type(mh, ETHERTYPE_IP);
int tx = 0;
switch(ch->addr_type()) {
case NS_AF_ILINK:
mac_->hdr_dst((char*) HDR_MAC(p), ch->next_hop());
break;
case NS_AF_INET:
dst = ch->next_hop();
/* FALL THROUGH */
case NS_AF_NONE:
if (IP_BROADCAST == (u_int32_t) dst)
{
mac_->hdr_dst((char*) HDR_MAC(p), MAC_BROADCAST);
break;
}
/* Assuming arptable is present, send query */
if (arptable_) {
tx = arptable_->arpresolve(dst, p, this);
break;
}
//if (varp_) {
//tx = varp_->arpresolve(dst, p);
//break;
//}
/* FALL THROUGH */
default:
int IPnh = (lanrouter_) ? lanrouter_->next_hop(p) : -1;
if (IPnh < 0)
mac_->hdr_dst((char*) HDR_MAC(p),macDA_);
else if (varp_)
tx = varp_->arpresolve(IPnh, p);
else
mac_->hdr_dst((char*) HDR_MAC(p), IPnh);
break;
}
if (tx == 0) {
Scheduler& s = Scheduler::instance();
// let mac decide when to take a new packet from the queue.
s.schedule(downtarget_, p, delay_);
}
}
void LL::sendUp(Packet* p)
{
Scheduler& s = Scheduler::instance();
if (hdr_cmn::access(p)->error() > 0)
drop(p);
else
s.schedule(uptarget_, p, delay_);
}
loss-monitor.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1994-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 Computer Systems
* Engineering Group at Lawrence Berkeley 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$ (LBL)";
#endif
#include "agent.h"
#include "config.h"
#include "tclcl.h"
#include "packet.h"
#include "ip.h"
#include "rtp.h"
class LossMonitor : public Agent {
public:
LossMonitor();
int command(int argc, const char*const* argv);
void recv(Packet* pkt, Handler*);
protected:
int nlost_;
int npkts_;
int expected_;
int bytes_;
int seqno_;
double last_packet_time_;
int off_rtp_;
};
static class LossMonitorClass : public TclClass {
public:
LossMonitorClass() : TclClass("Agent/LossMonitor") {}
TclObject* create(int, const char*const*) {
return (new LossMonitor());
}
} class_loss_mon;
LossMonitor::LossMonitor() : Agent(PT_NTYPE)
{
bytes_ = 0;
nlost_ = 0;
npkts_ = 0;
expected_ = -1;
last_packet_time_ = 0.;
seqno_ = 0;
bind("nlost_", &nlost_);
bind("npkts_", &npkts_);
bind("bytes_", &bytes_);
bind("lastPktTime_", &last_packet_time_);
bind("expected_", &expected_);
bind("off_rtp_", &off_rtp_);
}
void LossMonitor::recv(Packet* pkt, Handler*)
{
hdr_rtp* p = (hdr_rtp*)pkt->access(off_rtp_);
seqno_ = p->seqno();
bytes_ += ((hdr_cmn*)pkt->access(off_cmn_))->size();
++npkts_;
/*
* Check for lost packets
*/
if (expected_ >= 0) {
int loss = seqno_ - expected_;
if (loss > 0) {
nlost_ += loss;
Tcl::instance().evalf("%s log-loss", name());
}
}
last_packet_time_ = Scheduler::instance().clock();
expected_ = seqno_ + 1;
Packet::free(pkt);
}
/*
* $proc interval $interval
* $proc size $size
*/
int LossMonitor::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "clear") == 0) {
expected_ = -1;
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
mac-802_11.cc
/* -*- 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma.*/
#include "delay.h"
#include "connector.h"
#include "packet.h"
#include "random.h"
// #define DEBUG
//#include
#include "arp.h"
#include "ll.h"
#include "mac.h"
#include "mac-timers.h"
#include "mac-802_11.h"
#include "cmu-trace.h"
#define CHECK_BACKOFF_TIMER() \
{ \
if(is_idle() && mhBackoff_.paused()) \
mhBackoff_.resume(difs_); \
if(! is_idle() && mhBackoff_.busy() && ! mhBackoff_.paused()) \
mhBackoff_.pause(); \
}
#define TRANSMIT(p, t) \
{ \
tx_active_ = 1; \
\
/* \
* If I'm transmitting without doing CS, such as when \
* sending an ACK, any incoming packet will be "missed" \
* and hence, must be discarded. \
*/ \
if(rx_state_ != MAC_IDLE) { \
struct hdr_mac802_11 *dh = HDR_MAC802_11(p); \
\
assert(dh->dh_fc.fc_type == MAC_Type_Control); \
assert(dh->dh_fc.fc_subtype == MAC_Subtype_ACK); \
\
assert(pktRx_); \
struct hdr_cmn *ch = HDR_CMN(pktRx_); \
\
ch->error() = 1; /* force packet discard */ \
} \
\
/* \
* pass the packet on the "interface" which will in turn \
* place the packet on the channel. \
* \
* NOTE: a handler is passed along so that the Network \
* Interface can distinguish between incoming and \
* outgoing packets. \
*/ \
downtarget_->recv(p->copy(), this); \
\
mhSend_.start(t); \
\
mhIF_.start(TX_Time(p)); \
}
#define SET_RX_STATE(x) \
{ \
rx_state_ = (x); \
\
CHECK_BACKOFF_TIMER(); \
}
#define SET_TX_STATE(x) \
{ \
tx_state_ = (x); \
\
CHECK_BACKOFF_TIMER(); \
}
/* ======================================================================
Global Variables
====================================================================== */
//extern char* pt_names[];
static PHY_MIB PMIB =
{
DSSS_CWMin, DSSS_CWMax, DSSS_SlotTime, DSSS_CCATime,
DSSS_RxTxTurnaroundTime, DSSS_SIFSTime, DSSS_PreambleLength,
DSSS_PLCPHeaderLength
};
static MAC_MIB MMIB =
{
0 /* MAC_RTSThreshold */, MAC_ShortRetryLimit,
MAC_LongRetryLimit, MAC_FragmentationThreshold,
MAC_MaxTransmitMSDULifetime, MAC_MaxReceiveLifetime,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* ======================================================================
TCL Hooks for the simulator
====================================================================== */
static class Mac802_11Class : public TclClass {
public:
Mac802_11Class() : TclClass("Mac/802_11") {}
TclObject* create(int, const char*const*) {
return (new Mac802_11(&PMIB, &MMIB));
}
} class_mac802_11;
/* ======================================================================
Mac Class Functions
====================================================================== */
Mac802_11::Mac802_11(PHY_MIB *p, MAC_MIB *m) : Mac(),
mhIF_(this), mhNav_(this), mhRecv_(this), mhSend_(this),
mhDefer_(this, p->SlotTime), mhBackoff_(this, p->SlotTime)
{
macmib_ = m;
phymib_ = p;
nav_ = 0.0;
tx_state_ = rx_state_ = MAC_IDLE;
tx_active_ = 0;
pktRTS_ = 0;
pktCTRL_ = 0;
cw_ = phymib_->CWMin;
ssrc_ = slrc_ = 0;
sifs_ = phymib_->SIFSTime;
pifs_ = sifs_ + phymib_->SlotTime;
difs_ = sifs_ + 2*phymib_->SlotTime;
eifs_ = sifs_ + difs_ + DATA_Time(ETHER_ACK_LEN +
phymib_->PreambleLength/8 + phymib_->PLCPHeaderLength/8);
tx_sifs_ = sifs_ - phymib_->RxTxTurnaroundTime;
tx_pifs_ = tx_sifs_ + phymib_->SlotTime;
tx_difs_ = tx_sifs_ + 2 * phymib_->SlotTime;
sta_seqno_ = 1;
cache_ = 0;
cache_node_count_ = 0;
}
int
Mac802_11::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "log-target") == 0) {
logtarget_ = (NsObject*) TclObject::lookup(argv[2]);
if(logtarget_ == 0)
return TCL_ERROR;
return TCL_OK;
}
if(strcmp(argv[1], "nodes") == 0) {
if(cache_) return TCL_ERROR;
cache_node_count_ = atoi(argv[2]);
cache_ = new Host[cache_node_count_ + 1];
assert(cache_);
bzero(cache_, sizeof(Host) * (cache_node_count_+1 ));
return TCL_OK;
}
}
return Mac::command(argc, argv);
}
/* ======================================================================
Debugging Routines
====================================================================== */
void
Mac802_11::trace_pkt(Packet *p) {
struct hdr_cmn *ch = HDR_CMN(p);
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
u_int16_t *t = (u_int16_t*) &dh->dh_fc;
fprintf(stderr, "\t[ %2x %2x %2x %2x ] %x %s %d\n",
*t, dh->dh_duration,
ETHER_ADDR(dh->dh_da), ETHER_ADDR(dh->dh_sa),
index_, packet_info.name(ch->ptype()), ch->size());
}
void
Mac802_11::dump(char *fname)
{
fprintf(stderr,
"\n%s --- (INDEX: %d, time: %2.9f)\n",
fname, index_, Scheduler::instance().clock());
fprintf(stderr,
"\ttx_state_: %x, rx_state_: %x, nav: %2.9f, idle: %d\n",
tx_state_, rx_state_, nav_, is_idle());
fprintf(stderr,
"\tpktTx_: %x, pktRx_: %x, pktRTS_: %x, pktCTRL_: %x, callback: %x\n",
(int) pktTx_, (int) pktRx_, (int) pktRTS_,
(int) pktCTRL_, (int) callback_);
fprintf(stderr,
"\tDefer: %d, Backoff: %d (%d), Recv: %d, Timer: %d Nav: %d\n",
mhDefer_.busy(), mhBackoff_.busy(), mhBackoff_.paused(),
mhRecv_.busy(), mhSend_.busy(), mhNav_.busy());
fprintf(stderr,
"\tBackoff Expire: %f\n",
mhBackoff_.expire());
}
/* ======================================================================
Packet Headers Routines
====================================================================== */
inline int
Mac802_11::hdr_dst(char* hdr, int dst )
{
struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr;
//dst = (u_int32_t)(dst);
if(dst > -2)
STORE4BYTE(&dst, (dh->dh_da));
return ETHER_ADDR(dh->dh_da);
}
inline int
Mac802_11::hdr_src(char* hdr, int src )
{
struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr;
//src = (u_int32_t)(src);
if(src > -2)
STORE4BYTE(&src, (dh->dh_sa));
return ETHER_ADDR(dh->dh_sa);
}
inline int
Mac802_11::hdr_type(char* hdr, u_int16_t type)
{
struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr;
if(type)
//*((u_int16_t*) dh->dh_body) = type;
STORE2BYTE(&type,(dh->dh_body));
//return *((u_int16_t*) dh->dh_body);
return GET2BYTE(dh->dh_body);
}
/* ======================================================================
Misc Routines
====================================================================== */
inline int
Mac802_11::is_idle()
{
if(rx_state_ != MAC_IDLE)
return 0;
if(tx_state_ != MAC_IDLE)
return 0;
if(nav_ > Scheduler::instance().clock())
return 0;
return 1;
}
void
Mac802_11::discard(Packet *p, const char* why)
{
hdr_mac802_11* mh = HDR_MAC802_11(p);
hdr_cmn *ch = HDR_CMN(p);
#if 0
/* old logic 8/8/98 -dam */
/*
* If received below the RXThreshold, then just free.
*/
if(p->txinfo_.Pr < p->txinfo_.ant.RXThresh) {
Packet::free(p);
//p = 0;
return;
}
#endif // 0
/* if the rcvd pkt contains errors, a real MAC layer couldn't
necessarily read any data from it, so we just toss it now */
if(ch->error() != 0) {
Packet::free(p);
//p = 0;
return;
}
switch(mh->dh_fc.fc_type) {
case MAC_Type_Management:
drop(p, why);
//drop(p);
return;
case MAC_Type_Control:
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_RTS:
if((u_int32_t)ETHER_ADDR(mh->dh_sa) == \
(u_int32_t)index_) {
drop(p, why);
return;
}
/* fall through - if necessary */
case MAC_Subtype_CTS:
case MAC_Subtype_ACK:
if((u_int32_t)ETHER_ADDR(mh->dh_da) == \
(u_int32_t)index_) {
drop(p, why);
return;
}
break;
default:
fprintf(stderr, "invalid MAC Control subtype\n");
exit(1);
}
break;
case MAC_Type_Data:
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_Data:
if((u_int32_t)ETHER_ADDR(mh->dh_da) == \
(u_int32_t)index_ ||
(u_int32_t)ETHER_ADDR(mh->dh_sa) == \
(u_int32_t)index_ ||
(u_int32_t)ETHER_ADDR(mh->dh_da) == MAC_BROADCAST) {
//if (*(mh->dh_da) == (u_char)index_ ||
// *(mh->dh_sa) == (u_char)index_ ||
// *(mh->dh_sa) == (u_char)MAC_BROADCAST) {
//drop(p, why);
drop(p);
return;
}
break;
default:
fprintf(stderr, "invalid MAC Data subtype\n");
exit(1);
}
break;
default:
fprintf(stderr, "invalid MAC type (%x)\n", mh->dh_fc.fc_type);
trace_pkt(p);
exit(1);
}
Packet::free(p);
//p = 0;
}
void
Mac802_11::capture(Packet *p)
{
/*
* Update the NAV so that this does not screw
* up carrier sense.
*/
set_nav(usec(eifs_ + TX_Time(p)));
Packet::free(p);
//p = 0;
}
void
Mac802_11::collision(Packet *p)
{
switch(rx_state_) {
case MAC_RECV:
SET_RX_STATE(MAC_COLL);
/* fall through */
case MAC_COLL:
assert(pktRx_);
assert(mhRecv_.busy());
/*
* Since a collision has occurred, figure out
* which packet that caused the collision will
* "last" the longest. Make this packet,
* pktRx_ and reset the Recv Timer if necessary.
*/
if(TX_Time(p) > mhRecv_.expire()) {
mhRecv_.stop();
discard(pktRx_, DROP_MAC_COLLISION);
pktRx_ = p;
mhRecv_.start(TX_Time(pktRx_));
}
else {
discard(p, DROP_MAC_COLLISION);
}
break;
default:
assert(0);
}
}
void
Mac802_11::tx_resume()
{
assert(mhSend_.busy() == 0);
assert(mhDefer_.busy() == 0);
if(pktCTRL_) {
/*
* Need to send a CTS or ACK.
*/
mhDefer_.start(sifs_);
}
else if(pktRTS_) {
if(mhBackoff_.busy() == 0)
mhDefer_.start(difs_);
}
else if(pktTx_) {
if(mhBackoff_.busy() == 0)
mhDefer_.start(difs_);
}
else if(callback_) {
Handler *h = callback_;
callback_ = 0;
h->handle((Event*) 0);
}
SET_TX_STATE(MAC_IDLE);
}
void
Mac802_11::rx_resume()
{
assert(pktRx_ == 0);
assert(mhRecv_.busy() == 0);
SET_RX_STATE(MAC_IDLE);
}
/* ======================================================================
Timer Handler Routines
====================================================================== */
void
Mac802_11::backoffHandler()
{
if(pktCTRL_) {
assert(mhSend_.busy() || mhDefer_.busy());
return;
}
if(check_pktRTS() == 0)
return;
if(check_pktTx() == 0)
return;
}
void
Mac802_11::deferHandler()
{
assert(pktCTRL_ || pktRTS_ || pktTx_);
if(check_pktCTRL() == 0)
return;
assert(mhBackoff_.busy() == 0);
//if (mhBackoff_.busy() != 0)
//{
// printf("deferHandler:mhBackoff_ busy!\n");
// return;
//}
if(check_pktRTS() == 0)
return;
if(check_pktTx() == 0)
return;
}
void
Mac802_11::navHandler()
{
if(is_idle() && mhBackoff_.paused())
mhBackoff_.resume(difs_);
}
void
Mac802_11::recvHandler()
{
recv_timer();
}
void
Mac802_11::sendHandler()
{
send_timer();
}
void
Mac802_11::txHandler()
{
tx_active_ = 0;
}
/* ======================================================================
The "real" Timer Handler Routines
====================================================================== */
void
Mac802_11::send_timer()
{
switch(tx_state_) {
/*
* Sent a RTS, but did not receive a CTS.
*/
case MAC_RTS:
RetransmitRTS();
break;
/*
* Sent a CTS, but did not receive a DATA packet.
*/
case MAC_CTS:
assert(pktCTRL_);
Packet::free(pktCTRL_); pktCTRL_ = 0;
break;
/*
* Sent DATA, but did not receive an ACK packet.
*/
case MAC_SEND:
RetransmitDATA();
break;
/*
* Sent an ACK, and now ready to resume transmission.
*/
case MAC_ACK:
assert(pktCTRL_);
Packet::free(pktCTRL_); pktCTRL_ = 0;
break;
case MAC_IDLE:
break;
default:
assert(0);
}
tx_resume();
}
/* ======================================================================
Outgoing Packet Routines
====================================================================== */
int
Mac802_11::check_pktCTRL()
{
struct hdr_mac802_11 *mh;
double timeout;
if(pktCTRL_ == 0)
return -1;
if(tx_state_ == MAC_CTS || tx_state_ == MAC_ACK)
return -1;
mh = HDR_MAC802_11(pktCTRL_);
switch(mh->dh_fc.fc_subtype) {
/*
* If the medium is not IDLE, don't send the CTS.
*/
case MAC_Subtype_CTS:
if(! is_idle()) {
discard(pktCTRL_, DROP_MAC_BUSY); pktCTRL_ = 0;
return 0;
}
SET_TX_STATE(MAC_CTS);
timeout = (mh->dh_duration * 1e-6) + CTS_Time; // XXX
break;
/*
* IEEE 802.11 specs, section 9.2.8
* Acknowledments are sent after an SIFS, without regard to
* the busy/idle state of the medium.
*/
case MAC_Subtype_ACK:
SET_TX_STATE(MAC_ACK);
timeout = ACK_Time;
break;
default:
fprintf(stderr, "check_pktCTRL:Invalid MAC Control subtype\n");
exit(1);
}
TRANSMIT(pktCTRL_, timeout);
return 0;
}
int
Mac802_11::check_pktRTS()
{
struct hdr_mac802_11 *mh;
double timeout;
assert(mhBackoff_.busy() == 0);
if(pktRTS_ == 0)
return -1;
//struct hdr_cmn *ch = HDR_CMN(pktRTS_);
mh = HDR_MAC802_11(pktRTS_);
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_RTS:
if(! is_idle()) {
inc_cw();
mhBackoff_.start(cw_, is_idle());
return 0;
}
SET_TX_STATE(MAC_RTS);
timeout = CTSTimeout;
break;
default:
fprintf(stderr, "check_pktRTS:Invalid MAC Control subtype\n");
exit(1);
}
TRANSMIT(pktRTS_, timeout);
return 0;
}
int
Mac802_11::check_pktTx()
{
struct hdr_mac802_11 *mh;
double timeout;
assert(mhBackoff_.busy() == 0);
if(pktTx_ == 0)
return -1;
mh = HDR_MAC802_11(pktTx_);
int len = HDR_CMN(pktTx_)->size();
switch(mh->dh_fc.fc_subtype) {
case MAC_Subtype_Data:
if(! is_idle()) {
sendRTS(ETHER_ADDR(mh->dh_da));
inc_cw();
mhBackoff_.start(cw_, is_idle());
return 0;
}
SET_TX_STATE(MAC_SEND);
if((u_int32_t)ETHER_ADDR(mh->dh_da) != MAC_BROADCAST)
//timeout = ACKTimeout(netif_->txtime(pktTx_))+5;
// why 10 ? buggy
//timeout = ACKTimeout(len) + 10;
timeout = ACKTimeout(len);
else
timeout = TX_Time(pktTx_);
break;
default:
fprintf(stderr, "check_pktTx:Invalid MAC Control subtype\n");
//printf("pktRTS:%x, pktCTS/ACK:%x, pktTx:%x\n",pktRTS_, pktCTRL_,pktTx_);
exit(1);
}
TRANSMIT(pktTx_, timeout);
return 0;
}
/*
* Low-level transmit functions that actually place the packet onto
* the channel.
*/
void
Mac802_11::sendRTS(int dst)
{
Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_);
//struct hdr_mac802_11 *mh = HDR_MAC802_11(p);
assert(pktTx_);
assert(pktRTS_ == 0);
/*
* If the size of the packet is larger than the
* RTSThreshold, then perform the RTS/CTS exchange.
*
* XXX: also skip if destination is a broadcast
*/
if( (u_int32_t) HDR_CMN(pktTx_)->size() < macmib_->RTSThreshold ||
(u_int32_t) dst == MAC_BROADCAST) {
Packet::free(p);
//p = 0;
return;
}
ch->uid() = 0;
ch->ptype() = PT_MAC;
ch->size() = ETHER_RTS_LEN;
ch->iface() = -2;
ch->error() = 0;
bzero(rf, MAC_HDR_LEN);
rf->rf_fc.fc_protocol_version = MAC_ProtocolVersion;
rf->rf_fc.fc_type = MAC_Type_Control;
rf->rf_fc.fc_subtype = MAC_Subtype_RTS;
rf->rf_fc.fc_to_ds = 0;
rf->rf_fc.fc_from_ds = 0;
rf->rf_fc.fc_more_frag = 0;
rf->rf_fc.fc_retry = 0;
rf->rf_fc.fc_pwr_mgt = 0;
rf->rf_fc.fc_more_data = 0;
rf->rf_fc.fc_wep = 0;
rf->rf_fc.fc_order = 0;
rf->rf_duration = RTS_DURATION(pktTx_);
//ETHER_ADDR(rf->rf_ra) = dst;
STORE4BYTE(&dst, (rf->rf_ra));
//ETHER_ADDR(rf->rf_ta) = index_;
STORE4BYTE(&index_, (rf->rf_ta));
// rf->rf_fcs;
pktRTS_ = p;
}
void
Mac802_11::sendCTS(int dst, double rts_duration)
{
Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct cts_frame *cf = (struct cts_frame*)p->access(hdr_mac::offset_);
//struct hdr_mac802_11 *mh = HDR_MAC802_11(p);
assert(pktCTRL_ == 0);
ch->uid() = 0;
ch->ptype() = PT_MAC;
ch->size() = ETHER_CTS_LEN;
ch->iface() = -2;
ch->error() = 0;
//ch->direction() = hdr_cmn::DOWN;
bzero(cf, MAC_HDR_LEN);
cf->cf_fc.fc_protocol_version = MAC_ProtocolVersion;
cf->cf_fc.fc_type = MAC_Type_Control;
cf->cf_fc.fc_subtype = MAC_Subtype_CTS;
cf->cf_fc.fc_to_ds = 0;
cf->cf_fc.fc_from_ds = 0;
cf->cf_fc.fc_more_frag = 0;
cf->cf_fc.fc_retry = 0;
cf->cf_fc.fc_pwr_mgt = 0;
cf->cf_fc.fc_more_data = 0;
cf->cf_fc.fc_wep = 0;
cf->cf_fc.fc_order = 0;
cf->cf_duration = CTS_DURATION(rts_duration);
//ETHER_ADDR(cf->cf_ra) = dst;
STORE4BYTE(&dst, (cf->cf_ra));
//STORE4BYTE(&dst, (mh->dh_da));
// cf->cf_fcs;
pktCTRL_ = p;
}
void
Mac802_11::sendACK(int dst)
{
Packet *p = Packet::alloc();
hdr_cmn* ch = HDR_CMN(p);
struct ack_frame *af = (struct ack_frame*)p->access(hdr_mac::offset_);
//struct hdr_mac802_11 *mh = HDR_MAC802_11(p);
assert(pktCTRL_ == 0);
ch->uid() = 0;
ch->ptype() = PT_MAC;
ch->size() = ETHER_ACK_LEN;
ch->iface() = -2;
ch->error() = 0;
//ch->direction() = hdr_cmn::DOWN;
bzero(af, MAC_HDR_LEN);
af->af_fc.fc_protocol_version = MAC_ProtocolVersion;
af->af_fc.fc_type = MAC_Type_Control;
af->af_fc.fc_subtype = MAC_Subtype_ACK;
af->af_fc.fc_to_ds = 0;
af->af_fc.fc_from_ds = 0;
af->af_fc.fc_more_frag = 0;
af->af_fc.fc_retry = 0;
af->af_fc.fc_pwr_mgt = 0;
af->af_fc.fc_more_data = 0;
af->af_fc.fc_wep = 0;
af->af_fc.fc_order = 0;
af->af_duration = ACK_DURATION();
//ETHER_ADDR(af->af_ra) = dst;
STORE4BYTE(&dst, (af->af_ra));
// af->af_fcs;
pktCTRL_ = p;
}
void
Mac802_11::sendDATA(Packet *p)
{
hdr_cmn* ch = HDR_CMN(p);
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
assert(pktTx_ == 0);
/*
* Update the MAC header
*/
ch->size() += ETHER_HDR_LEN;
dh->dh_fc.fc_protocol_version = MAC_ProtocolVersion;
dh->dh_fc.fc_type = MAC_Type_Data;
dh->dh_fc.fc_subtype = MAC_Subtype_Data;
//printf(".....p = %x, mac-subtype-%d\n",p,dh->dh_fc.fc_subtype);
dh->dh_fc.fc_to_ds = 0;
dh->dh_fc.fc_from_ds = 0;
dh->dh_fc.fc_more_frag = 0;
dh->dh_fc.fc_retry = 0;
dh->dh_fc.fc_pwr_mgt = 0;
dh->dh_fc.fc_more_data = 0;
dh->dh_fc.fc_wep = 0;
dh->dh_fc.fc_order = 0;
if((u_int32_t)ETHER_ADDR(dh->dh_da) != MAC_BROADCAST)
dh->dh_duration = DATA_DURATION();
else
dh->dh_duration = 0;
pktTx_ = p;
}
/* ======================================================================
Retransmission Routines
====================================================================== */
void
Mac802_11::RetransmitRTS()
{
assert(pktTx_);
assert(pktRTS_);
assert(mhBackoff_.busy() == 0);
macmib_->RTSFailureCount++;
ssrc_ += 1; // STA Short Retry Count
if(ssrc_ >= macmib_->ShortRetryLimit) {
discard(pktRTS_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktRTS_ = 0;
/* tell the callback the send operation failed
before discarding the packet */
hdr_cmn *ch = HDR_CMN(pktTx_);
if (ch->xmit_failure_) {
/*
* Need to remove the MAC header so that
* re-cycled packets don't keep getting
* bigger.
*/
ch->size() -= ETHER_HDR_LEN;
ch->xmit_reason_ = XMIT_REASON_RTS;
ch->xmit_failure_(pktTx_->copy(),
ch->xmit_failure_data_);
}
//printf("(%d)....discarding RTS:%x\n",index_,pktRTS_);
discard(pktTx_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktTx_ = 0;
ssrc_ = 0;
rst_cw();
}
else {
//printf("(%d)...retxing RTS:%x\n",index_,pktRTS_);
struct rts_frame *rf;
rf = (struct rts_frame*)pktRTS_->access(hdr_mac::offset_);
rf->rf_fc.fc_retry = 1;
inc_cw();
mhBackoff_.start(cw_, is_idle());
}
}
void
Mac802_11::RetransmitDATA()
{
struct hdr_cmn *ch;
struct hdr_mac802_11 *mh;
u_int32_t *rcount, *thresh;
assert(mhBackoff_.busy() == 0);
assert(pktTx_);
assert(pktRTS_ == 0);
ch = HDR_CMN(pktTx_);
mh = HDR_MAC802_11(pktTx_);
/*
* Broadcast packets don't get ACKed and therefore
* are never retransmitted.
*/
if((u_int32_t)ETHER_ADDR(mh->dh_da) == MAC_BROADCAST) {
Packet::free(pktTx_); pktTx_ = 0;
/*
* Backoff at end of TX.
*/
rst_cw();
mhBackoff_.start(cw_, is_idle());
return;
}
macmib_->ACKFailureCount++;
if((u_int32_t) ch->size() <= macmib_->RTSThreshold) {
rcount = &ssrc_;
thresh = &macmib_->ShortRetryLimit;
}
else {
rcount = &slrc_;
thresh = &macmib_->LongRetryLimit;
}
(*rcount)++;
if(*rcount > *thresh) {
macmib_->FailedCount++;
/* tell the callback the send operation failed
before discarding the packet */
hdr_cmn *ch = HDR_CMN(pktTx_);
if (ch->xmit_failure_) {
ch->size() -= ETHER_HDR_LEN;
ch->xmit_reason_ = XMIT_REASON_ACK;
ch->xmit_failure_(pktTx_->copy(),
ch->xmit_failure_data_);
}
discard(pktTx_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktTx_ = 0;
//printf("(%d)DATA discarded: count exceeded\n",index_);
*rcount = 0;
rst_cw();
}
else {
struct hdr_mac802_11 *dh;
dh = HDR_MAC802_11(pktTx_);
dh->dh_fc.fc_retry = 1;
sendRTS(ETHER_ADDR(mh->dh_da));
//printf("(%d)retxing data:%x..sendRTS..\n",index_,pktTx_);
inc_cw();
mhBackoff_.start(cw_, is_idle());
}
}
/* ======================================================================
Incoming Packet Routines
====================================================================== */
void
Mac802_11::send(Packet *p, Handler *h)
{
struct hdr_mac802_11* dh = HDR_MAC802_11(p);
/*
* drop the packet if the node is in sleep mode
XXX sleep mode can't stop node from sending packets
*/
if ((netif_->node())->sleep()) {
netif_->node()->set_node_sleep(0);
netif_->node()->set_node_state(INROUTE);
}
callback_ = h;
sendDATA(p);
sendRTS(ETHER_ADDR(dh->dh_da));
/*
* Assign the data packet a sequence number.
*/
dh->dh_scontrol = sta_seqno_++;
/*
* If the medium is IDLE, we must wait for a DIFS
* Space before transmitting.
*/
if(mhBackoff_.busy() == 0) {
if(is_idle()) {
/*
* If we are already deferring, there is no
* need to reset the Defer timer.
*/
if(mhDefer_.busy() == 0)
mhDefer_.start(difs_);
}
/*
* If the medium is NOT IDLE, then we start
* the backoff timer.
*/
else {
mhBackoff_.start(cw_, is_idle());
}
}
}
void
Mac802_11::recv(Packet *p, Handler *h)
{
struct hdr_cmn *hdr = HDR_CMN(p);
//hdr_mac802_11 *mh = HDR_MAC802_11(p);
//u_int32_t dst = ETHER_ADDR(mh->dh_da);
//u_int32_t src = ETHER_ADDR(mh->dh_sa);
/*
* Sanity Check
*/
assert(initialized());
/*
* Handle outgoing packets.
*/
if(hdr->direction() == hdr_cmn::DOWN) {
send(p, h);
return;
}
/*
* Handle incoming packets.
*
* We just received the 1st bit of a packet on the network
* interface.
*
*/
/*
* If the interface is currently in transmit mode, then
* it probably won't even see this packet. However, the
* "air" around me is BUSY so I need to let the packet
* proceed. Just set the error flag in the common header
* to that the packet gets thrown away.
*/
if(tx_active_ && hdr->error() == 0) {
hdr->error() = 1;
}
if(rx_state_ == MAC_IDLE) {
SET_RX_STATE(MAC_RECV);
pktRx_ = p;
/*
* Schedule the reception of this packet, in
* txtime seconds.
*/
mhRecv_.start(TX_Time(p));
}
else {
/*
* If the power of the incoming packet is smaller than the
* power of the packet currently being received by at least
* the capture threshold, then we ignore the new packet.
*/
if(pktRx_->txinfo_.RxPr / p->txinfo_.RxPr >= p->txinfo_.CPThresh) {
capture(p);
}
else {
collision(p);
}
}
}
void
Mac802_11::recv_timer()
{
u_int32_t src;
hdr_cmn *ch = HDR_CMN(pktRx_);
hdr_mac802_11 *mh = HDR_MAC802_11(pktRx_);
u_int32_t dst = ETHER_ADDR(mh->dh_da);
// XXX debug
//struct cts_frame *cf = (struct cts_frame*)pktRx_->access(hdr_mac::offset_);
//u_int32_t src = ETHER_ADDR(mh->dh_sa);
u_int8_t type = mh->dh_fc.fc_type;
u_int8_t subtype = mh->dh_fc.fc_subtype;
assert(pktRx_);
assert(rx_state_ == MAC_RECV || rx_state_ == MAC_COLL);
/*
* If the interface is in TRANSMIT mode when this packet
* "arrives", then I would never have seen it and should
* do a silent discard without adjusting the NAV.
*/
if(tx_active_) {
Packet::free(pktRx_);
goto done;
}
/*
* Handle collisions.
*/
if(rx_state_ == MAC_COLL) {
discard(pktRx_, DROP_MAC_COLLISION);
set_nav(usec(eifs_));
goto done;
}
/*
* Check to see if this packet was received with enough
* bit errors that the current level of FEC still could not
* fix all of the problems - ie; after FEC, the checksum still
* failed.
*/
if( ch->error() ) {
Packet::free(pktRx_);
set_nav(usec(eifs_));
goto done;
}
/*
* IEEE 802.11 specs, section 9.2.5.6
* - update the NAV (Network Allocation Vector)
*/
if(dst != (u_int32_t)index_) {
set_nav(mh->dh_duration);
}
/* tap out - */
if (tap_ && type == MAC_Type_Data &&
MAC_Subtype_Data == subtype )
tap_->tap(pktRx_);
/*
* Adaptive Fidelity Algorithm Support - neighborhood infomation collection
*
* Hacking: Before filter the packet, log the neighbor node
* I can hear the packet, the src is my neighbor
*/
if (netif_->node()->adaptivefidelity()) {
src = ETHER_ADDR(mh->dh_sa);
netif_->node()->add_neighbor(src);
}
/*
* Address Filtering
*/
if(dst != (u_int32_t)index_ && dst != MAC_BROADCAST) {
/*
* We don't want to log this event, so we just free
* the packet instead of calling the drop routine.
*/
discard(pktRx_, "---");
goto done;
}
switch(type) {
case MAC_Type_Management:
discard(pktRx_, DROP_MAC_PACKET_ERROR);
goto done;
break;
case MAC_Type_Control:
switch(subtype) {
case MAC_Subtype_RTS:
recvRTS(pktRx_);
break;
case MAC_Subtype_CTS:
recvCTS(pktRx_);
break;
case MAC_Subtype_ACK:
recvACK(pktRx_);
break;
default:
fprintf(stderr,"recvTimer1:Invalid MAC Control Subtype %x\n",
subtype);
exit(1);
}
break;
case MAC_Type_Data:
switch(subtype) {
case MAC_Subtype_Data:
recvDATA(pktRx_);
break;
default:
fprintf(stderr, "recv_timer2:Invalid MAC Data Subtype %x\n",
subtype);
exit(1);
}
break;
default:
fprintf(stderr, "recv_timer3:Invalid MAC Type %x\n", subtype);
exit(1);
}
done:
pktRx_ = 0;
rx_resume();
}
void
Mac802_11::recvRTS(Packet *p)
{
struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_);
if(tx_state_ != MAC_IDLE) {
discard(p, DROP_MAC_BUSY);
return;
}
/*
* If I'm responding to someone else, discard this RTS.
*/
if(pktCTRL_) {
discard(p, DROP_MAC_BUSY);
return;
}
sendCTS(ETHER_ADDR(rf->rf_ta), rf->rf_duration);
/*
* Stop deferring - will be reset in tx_resume().
*/
if(mhDefer_.busy()) mhDefer_.stop();
tx_resume();
mac_log(p);
}
void
Mac802_11::recvCTS(Packet *p)
{
if(tx_state_ != MAC_RTS) {
discard(p, DROP_MAC_INVALID_STATE);
return;
}
assert(pktRTS_);
Packet::free(pktRTS_); pktRTS_ = 0;
assert(pktTx_);
// debug
//struct hdr_mac802_11 *mh = HDR_MAC802_11(pktTx_);
//printf("(%d):recvCTS:pktTx_-%x,mac-subtype-%d & pktCTS_:%x\n",index_,pktTx_,mh->dh_fc.fc_subtype,p);
mhSend_.stop();
/*
* The successful reception of this CTS packet implies
* that our RTS was successful. Hence, we can reset
* the Short Retry Count and the CW.
*/
ssrc_ = 0;
rst_cw();
tx_resume();
mac_log(p);
}
void
Mac802_11::recvDATA(Packet *p)
{
struct hdr_mac802_11 *dh = HDR_MAC802_11(p);
u_int32_t dst, src, size;
{ struct hdr_cmn *ch = HDR_CMN(p);
dst = ETHER_ADDR(dh->dh_da);
src = ETHER_ADDR(dh->dh_sa);
size = ch->size();
/*
* Adjust the MAC packet size - ie; strip
* off the mac header
*/
ch->size() -= ETHER_HDR_LEN;
ch->num_forwards() += 1;
}
/*
* If we sent a CTS, clean up...
*/
if(dst != MAC_BROADCAST) {
if(size >= macmib_->RTSThreshold) {
if (tx_state_ == MAC_CTS) {
assert(pktCTRL_);
Packet::free(pktCTRL_); pktCTRL_ = 0;
mhSend_.stop();
/*
* Our CTS got through.
*/
//printf("(%d): RECVING DATA!\n",index_);
ssrc_ = 0;
rst_cw();
}
else {
discard(p, DROP_MAC_BUSY);
//printf("(%d)..discard DATA\n",index_);
return;
}
sendACK(src);
tx_resume();
}
/*
* We did not send a CTS and there's no
* room to buffer an ACK.
*/
else {
if(pktCTRL_) {
discard(p, DROP_MAC_BUSY);
return;
}
sendACK(src);
if(mhSend_.busy() == 0)
tx_resume();
}
}
/* ============================================================
Make/update an entry in our sequence number cache.
============================================================ */
if(dst != MAC_BROADCAST) {
Host *h = &cache_[src];
if(h->seqno && h->seqno == dh->dh_scontrol) {
discard(p, DROP_MAC_DUPLICATE);
return;
}
h->seqno = dh->dh_scontrol;
}
/*
* Pass the packet up to the link-layer.
* XXX - we could schedule an event to account
* for this processing delay.
*/
p->incoming = 1;
uptarget_->recv(p, (Handler*) 0);
}
void
Mac802_11::recvACK(Packet *p)
{
struct hdr_cmn *ch = HDR_CMN(p);
if(tx_state_ != MAC_SEND) {
discard(p, DROP_MAC_INVALID_STATE);
return;
}
//printf("(%d)...................recving ACK:%x\n",index_,p);
assert(pktTx_);
Packet::free(pktTx_); pktTx_ = 0;
mhSend_.stop();
/*
* The successful reception of this ACK packet implies
* that our DATA transmission was successful. Hence,
* we can reset the Short/Long Retry Count and the CW.
*/
if((u_int32_t) ch->size() <= macmib_->RTSThreshold)
ssrc_ = 0;
else
slrc_ = 0;
/*
* Backoff before sending again.
*/
rst_cw();
assert(mhBackoff_.busy() == 0);
mhBackoff_.start(cw_, is_idle());
tx_resume();
mac_log(p);
}
mac-802_3.cc
/*
mac-802_3.cc
$Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $
*/
#include
#include
#include
#include
#include
//#define MAC_DEBUG
#ifndef MAC_DEBUG
#define FPRINTF(s, f, t, index, func) do {} while (0)
#else
static double xtime= 0.0;
# define FPRINTF(s, f, t, index, func) \
do { fprintf(s, f, t, index, func); xtime= t; } while (0)
#endif MAC_DEBUG
inline void MacHandler::cancel() {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
Scheduler& s = Scheduler::instance();
assert(busy_);
s.cancel(&intr);
busy_ = 0;
}
inline void Mac8023HandlerSend::cancel() {
assert(busy_);
Scheduler &s= Scheduler::instance();
s.cancel(&intr);
busy_= 0;
p_= 0;
}
inline void MacHandlerRecv::cancel() {
Scheduler& s = Scheduler::instance();
assert(busy_ && p_);
s.cancel(&intr);
busy_ = 0;
Packet::free(p_);
p_= 0;
}
inline void MacHandlerRetx::cancel() {
Scheduler& s = Scheduler::instance();
assert(busy_ && p_);
s.cancel(&intr);
}
inline void MacHandlerIFS::cancel() {
//fprintf (stderr, "cancelled dtime= %.15f\n", intr.time_- Scheduler::instance().clock());
MacHandler::cancel();
}
static class Mac802_3Class : public TclClass {
public:
Mac802_3Class() : TclClass("Mac/802_3") {}
TclObject* create(int, const char*const*) {
return (new Mac802_3);
}
} class_mac802_3;
void Mac8023HandlerSend::handle(Event*) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
assert(p_);
/* Transmission completed successfully */
busy_ = 0;
p_= 0;
mac->mhRetx_.free();
mac->mhRetx_.reset();
mac->mhIFS_.schedule(mac->netif_->txtime(IEEE_8023_IFS_BITS/8.0));
}
void Mac8023HandlerSend::schedule(const Packet *p, double t) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
Scheduler& s = Scheduler::instance();
assert(!busy_);
s.schedule(this, &intr, t);
busy_ = 1;
p_= p;
}
void MacHandlerRecv::handle(Event* ) {
/* Reception Successful */
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
busy_ = 0;
mac->recv_complete(p_);
p_= 0;
}
void MacHandlerRecv::schedule(Packet *p, double t) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
Scheduler& s = Scheduler::instance();
assert(p && !busy_);
s.schedule(this, &intr, t);
busy_ = 1;
p_ = p;
}
bool MacHandlerRetx::schedule(double delta) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
Scheduler& s = Scheduler::instance();
assert(p_ && !busy_);
int k, r;
if(try_ < IEEE_8023_ALIMIT) {
k = min(try_, IEEE_8023_BLIMIT);
r = Random::integer(1 << k);
s.schedule(this, &intr, r * mac->netif_->txtime(IEEE_8023_SLOT_BITS/8.0) + delta);
busy_ = 1;
return true;
}
return false;
}
void MacHandlerRetx::handle(Event *) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
assert(p_);
busy_= 0;
++try_;
mac->transmit(p_);
}
inline void MacHandlerIFS::schedule(double t) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
assert(!busy_);
Scheduler &s= Scheduler::instance();
s.schedule(this, &intr, t);
busy_= 1;
}
inline void MacHandlerIFS::handle(Event*) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__);
busy_= 0;
mac->resume();
}
Mac802_3::Mac802_3() : Mac(),
mhRecv_(this), mhRetx_(this), mhIFS_(this), mhSend_(this) {
}
void Mac802_3::sendUp(Packet *p, Handler *) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__);
/* just received the 1st bit of a packet */
if (state_ != MAC_IDLE && mhIFS_.busy()) {
// this must mean either that
// a. mhIFS_ is about to expire now - concurrent events ordering - or
// b. (txtime + ifs + propdelay) < (propdelay + txtime + ifs) for the prev. packet
// so we assume that IFS is over and resume
#ifdef MAC_DEBUG
#define EPS 1.0e-15
if (mhIFS_.expire() - Scheduler::instance().clock() > EPS) {
fprintf(stderr, "mhIFS_: %.20f, time= %.20f, diff= %e\n",
mhIFS_.expire(), Scheduler::instance().clock(),
mhIFS_.expire() - Scheduler::instance().clock());
assert(0);
}
#undef EPS
#endif
mhIFS_.cancel();
resume();
}
if(state_ == MAC_IDLE) {
state_ = MAC_RECV;
assert(!mhRecv_.busy());
/* the last bit will arrive in txtime seconds */
mhRecv_.schedule(p, netif_->txtime(p));
} else {
collision(p); //received packet while sending or receiving
}
}
void Mac802_3::sendDown(Packet *p, Handler *h) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__);
assert(initialized());
assert(h);
assert(netif_->txtime(IEEE_8023_MINFRAME) >
2*netif_->channel()->maxdelay()); /* max prop. delay is limited by specs:
about 25us for 10Mbps
and 2.5us for 100Mbps
*/
int size= (HDR_CMN(p)->size() += ETHER_HDR_LEN); //XXX also preamble?
hdr_mac *mh= HDR_MAC(p);
mh->padding_= 0;
if (size > IEEE_8023_MAXFRAME) {
static bool warnedMAX= false;
if (!warnedMAX) {
fprintf(stderr, "Mac802_3: frame is too big: %d\n", size);
warnedMAX= true;
}
} else if (size < IEEE_8023_MINFRAME) {
// pad it to fit MINFRAME
mh->padding_= IEEE_8023_MINFRAME - size;
HDR_CMN(p)->size() += mh->padding_;
}
callback_ = h;
mhRetx_.packet(p); //packet's buffered by mhRetx in case of retransmissions
transmit(p);
}
void Mac802_3::transmit(Packet *p) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__);
assert(callback_);
if(mhSend_.packet()) {
fprintf(stderr, "index: %d\n", index_);
fprintf(stderr, "Retx Timer: %d\n", mhRetx_.busy());
fprintf(stderr, "IFS Timer: %d\n", mhIFS_.busy());
fprintf(stderr, "Recv Timer: %d\n", mhRecv_.busy());
fprintf(stderr, "Send Timer: %d\n", mhSend_.busy());
exit(1);
}
/* Perform carrier sense - if we were sending before, never mind state_ */
if (mhIFS_.busy() || (state_ != MAC_IDLE)) {
/* we'll try again when IDLE. It'll happen either when
reception completes, or if collision. Either way,
we call resume() */
return;
}
HDR_CMN(p)->direction()= hdr_cmn::DOWN; //down
double txtime = netif_->txtime(p);
/* Schedule transmission of the packet's last bit */
mhSend_.schedule(p, txtime);
// pass the packet to the PHY: need to send a copy,
// because there may be collision and it may be freed
downtarget_->recv(p->copy());
state_= MAC_SEND;
}
void Mac802_3::collision(Packet *p) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__);
Packet::free(p);
if (mhIFS_.busy()) mhIFS_.cancel();
double ifstime= netif_->txtime((IEEE_8023_JAMSIZE+IEEE_8023_IFS_BITS)/8); //jam time + ifs
mhIFS_.schedule(ifstime);
switch(state_) {
case MAC_SEND:
if (mhSend_.busy()) mhSend_.cancel();
if (!mhRetx_.busy()) {
/* schedule retransmissions */
if (!mhRetx_.schedule(ifstime)) {
p= mhRetx_.packet();
HDR_CMN(p)->size() -= (ETHER_HDR_LEN + HDR_MAC(p)->padding_);
drop(p); // drop if backed off far enough
mhRetx_.reset();
}
}
break;
case MAC_RECV:
// more than 2 packets collisions possible
if (mhRecv_.busy()) mhRecv_.cancel();
break;
default:
assert("SHOULD NEVER HAPPEN" == 0);
}
}
void Mac802_3::recv_complete(Packet *p) {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__);
assert(!mhRecv_.busy());
assert(!mhSend_.busy());
hdr_cmn *ch= HDR_CMN(p);
/* Address Filtering */
hdr_mac *mh= HDR_MAC(p);
int dst= mh->macDA();
if ((dst != BCAST_ADDR) && (dst != index_)) {
Packet::free(p);
goto done;
}
/* Strip off the mac header and padding if any */
ch->size() -= (ETHER_HDR_LEN + mh->padding_);
/* xxx FEC here */
if( ch->error() ) {
drop(p);
goto done;
}
/* we could schedule an event to account for mac-delay */
uptarget_->recv(p, (Handler*) 0);
done:
mhIFS_.schedule(netif_->txtime(IEEE_8023_IFS_BITS/8));// wait for one IFS, then resume
}
/* we call resume() in these cases:
- successful transmission
- whole packet's received
- collision and backoffLimit's exceeded
- collision while receiving */
void Mac802_3::resume() {
FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__);
assert(!mhRecv_.busy());
assert(!mhSend_.busy());
assert(!mhIFS_.busy());
state_= MAC_IDLE;
if (mhRetx_.packet()) {
if (!mhRetx_.busy()) {
// we're not backing off and not sensing carrier right now: send
transmit(mhRetx_.packet());
}
} else {
if (callback_ && !mhRetx_.busy()) {
//WARNING: calling callback_->handle may change the value of callback_
Handler* h= callback_;
callback_= 0;
h->handle(0);
}
}
}
mac-csma.cc
/* -*- 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 Daedalus Research
* Group at the University of California Berkeley.
* 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.
*
* Contributed by Giao Nguyen, http://daedalus.cs.berkeley.edu/~gnguyen
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include "template.h"
#include "random.h"
#include "channel.h"
#include "mac-csma.h"
static class MacCsmaClass : public TclClass {
public:
MacCsmaClass() : TclClass("Mac/Csma") {}
TclObject* create(int, const char*const*) {
return (new MacCsma);
}
} class_mac_csma;
static class MacCsmaCdClass : public TclClass {
public:
MacCsmaCdClass() : TclClass("Mac/Csma/Cd") {}
TclObject* create(int, const char*const*) {
return (new MacCsmaCd);
}
} class_mac_csma_cd;
static class MacCsmaCaClass : public TclClass {
public:
MacCsmaCaClass() : TclClass("Mac/Csma/Ca") {}
TclObject* create(int, const char*const*) {
return (new MacCsmaCa);
}
} class_mac_csma_ca;
void
MacHandlerEoc::handle(Event* e)
{
mac_->endofContention((Packet*)e);
}
MacCsma::MacCsma() : txstart_(0), rtx_(0), csense_(1), hEoc_(this)
{
bind_time("ifs_", &ifs_);
bind_time("slotTime_", &slotTime_);
bind("cwmin_", &cwmin_);
bind("cwmax_", &cwmax_);
bind("rtxLimit_", &rtxLimit_);
bind("csense_", &csense_);
cw_ = cwmin_;
}
void MacCsma::resume(Packet* p)
{
Scheduler& s = Scheduler::instance();
s.schedule(callback_, &intr_, ifs_ + slotTime_ * cwmin_);
if (p != 0)
drop(p);
callback_ = 0;
state(MAC_IDLE);
rtx_ = 0;
cw_ = cwmin_;
}
void MacCsma::send(Packet* p)
{
Scheduler& s = Scheduler::instance();
double delay = channel_->txstop() + ifs_ - s.clock();
// if channel is not ready, then wait
// else content for the channel
/* XXX floating point operations differences have been
observed on the resulting delay value on Pentium II and
SunSparc. E.g.
PentiumII SunSparc
-------------------------------
channel_->txstop_= 0.11665366666666668 0.11665366666666668
binary 0x3fbddd03c34ab4a2 0x3fbddd03c34ab4a2
ifs_= 5.1999999999999997e-05 5.1999999999999997e-05
binary 0x3f0b43526527a205 0x3f0b43526527a205
s.clock_= 0.11670566666666668 0.11670566666666668
binary 0x3fbde06c2d975996 0x3fbde06c2d975996
delay= 3.5033282698437862e-18 0
binary 0x3c50280000000000 0x0000000000000000
Because of that the value of (csense_ && delay > 0) was different. Fixed by
changing 0 to EPS
*/
static const double EPS= 1.0e-12; //seems appropriate (less than nanosec)
if (csense_ && delay > EPS)
s.schedule(&hSend_, p, delay + 0.000001);
else {
txstart_ = s.clock();
channel_->contention(p, &hEoc_);
}
}
void MacCsma::backoff(Handler* h, Packet* p, double delay)
{
Scheduler& s = Scheduler::instance();
double now = s.clock();
// if retransmission time within limit, do exponential backoff
// else drop the packet and resume
if (++rtx_ < rtxLimit_) {
delay += max(channel_->txstop() + ifs_ - now, 0.0);
int slot = Random::integer(cw_);
s.schedule(h, p, delay + slotTime_ * slot);
cw_ = min(2 * cw_, cwmax_);
}
else
resume(p);
}
void MacCsma::endofContention(Packet* p)
{
Scheduler& s = Scheduler::instance();
double txt = txtime(p) - (s.clock() - txstart_);
hdr_mac::access(p)->txtime() = txt;
channel_->send(p, txt);
s.schedule(&hRes_, &eEoc_, txt);
rtx_ = 0;
cw_ = cwmin_;
}
void MacCsmaCd::endofContention(Packet* p)
{
// If there is a collision, backoff
if (channel_->collision()) {
channel_->jam(0);
backoff(&hSend_, p);
}
else
MacCsma::endofContention(p);
}
void MacCsmaCa::send(Packet* p)
{
Scheduler& s = Scheduler::instance();
double delay = channel_->txstop() + ifs_ - s.clock();
if (csense_ && delay > 0)
backoff(&hSend_, p);
else {
txstart_ = s.clock();
channel_->contention(p, &hEoc_);
}
}
mac-multihop.cc
/* -*- 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 Daedalus 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include "template.h"
#include "channel.h"
#include "mac-multihop.h"
/*
* For debugging.
*/
void dump_iphdr(hdr_ip *iph)
{
printf("\tsrc = %d, ", iph->saddr());
printf("\tdst = %d\n", iph->daddr());
}
static class MultihopMacClass : public TclClass {
public:
MultihopMacClass() : TclClass("Mac/Multihop") {}
TclObject* create(int, const char*const*) {
return (new MultihopMac);
}
} class_mac_multihop;
MultihopMac::MultihopMac() : mode_(MAC_IDLE), peer_(0),
pendingPollEvent_(0), pkt_(0),
ph_(this), pah_(this), pnh_(this), pth_(this), bh_(this)
{
/* Bind a bunch of variables to access from Tcl */
bind_time("tx_rx_", &tx_rx_);
bind_time("rx_tx_", &rx_tx_);
bind_time("rx_rx_", &rx_rx_);
bind_time("backoffBase_", &backoffBase_);
backoffTime_ = backoffBase_;
}
/*
* Returns 1 iff the specified MAC is in the prescribed state, AND all
* the other MACs are IDLE.
*/
int MultihopMac::checkInterfaces(int state)
{
MultihopMac *p;
if (!(mode_ & state))
return 0;
else if (macList_ == 0)
return 1;
for (p = (MultihopMac *)macList_; p != this && p != NULL;
p = (MultihopMac *)(p->macList())) {
if (p->mode() != MAC_IDLE) {
return 0;
}
}
return 1;
}
/*
* Poll a peer node prior to a send. There can be at most one POLL
* outstanding from a node at any point in time. This is achieved implicitly
* because there can be at most one packet down from LL (thru IFQ) to this MAC.
*/
void MultihopMac::poll(Packet *p)
{
Scheduler& s = Scheduler::instance();
MultihopMac *pm = (MultihopMac*) getPeerMac(p);
PollEvent *pe = new PollEvent(pm, this);
pendingPollEvent_ = new PollEvent(pm, this);
pkt_ = p->copy(); /* local copy for poll retries */
double timeout = max(pm->rx_tx(), tx_rx_) + 4*pollTxtime(MAC_POLLSIZE);
s.schedule(&bh_, pendingPollEvent_, timeout);
/* If the other interfaces are idle, then go ahead, else not. */
if (checkInterfaces(MAC_IDLE)) {
mode_ = MAC_POLLING;
peer_ = pm;
s.schedule(pm->ph(), (Event *)pe, pollTxtime(MAC_POLLSIZE));
}
}
/*
* Handle a POLL request from a peer node's MAC.
*/
void
PollHandler::handle(Event *e)
{
PollEvent *pe = (PollEvent *) e;
Scheduler& s = Scheduler::instance();
MultihopMac* pm = mac_->peer(); /* sensible val only in MAC_RCV mode */
/*
* Send POLLACK if either IDLE or currently receiving
* from same mac as the poller.
*/
if (mac_->checkInterfaces(MAC_IDLE)) { // all interfaces must be IDLE
mac_->mode(MAC_RCV);
pm = pe->peerMac();
mac_->peer(pm);
PollEvent *pae = new PollEvent(pm, mac_); // POLLACK event
double t = mac_->pollTxtime(MAC_POLLACKSIZE) +
max(mac_->tx_rx(), pm->rx_tx());
s.schedule(pm->pah(), pae, t);
} else {
// printf("ignoring poll %d\n", mac_->label());
// could send NACKPOLL but don't (at least for now)
}
}
/*
* Handle a POLLACK from a peer node's MAC.
*/
void
PollAckHandler::handle(Event *e)
{
PollEvent *pe = (PollEvent *) e;
Scheduler& s = Scheduler::instance();
if (mac_->checkInterfaces(MAC_POLLING | MAC_IDLE)) {
mac_->backoffTime(mac_->backoffBase());
mac_->mode(MAC_SND);
mac_->peer(pe->peerMac());
s.cancel(mac_->pendingPE()); /* cancel pending timeout */
free(mac_->pendingPE());
mac_->pendingPE(NULL);
mac_->send(mac_->pkt()); /* send saved packet */
}
}
void
PollNackHandler::handle(Event *)
{
}
void
BackoffHandler::handle(Event *)
{
Scheduler& s = Scheduler::instance();
if (mac_->mode() == MAC_POLLING)
mac_->mode(MAC_IDLE);
double bTime = mac_->backoffTime(2*mac_->backoffTime());
bTime = (1+Random::integer(MAC_TICK)*1./MAC_TICK)*bTime +
2*mac_->backoffBase();
// printf("backing off %d\n", mac_->label());
s.schedule(mac_->pth(), mac_->pendingPE(), bTime);
}
void
PollTimeoutHandler::handle(Event *)
{
mac_->poll(mac_->pkt());
}
/*
* Actually send the data frame.
*/
void MultihopMac::send(Packet *p)
{
Scheduler& s = Scheduler::instance();
if (mode_ != MAC_SND)
return;
double txt = txtime(p);
hdr_mac::access(p)->txtime() = txt;
channel_->send(p, txt); // target is peer's mac handler
s.schedule(callback_, &intr_, txt); // callback to higher layer (LL)
mode_ = MAC_IDLE;
}
/*
* This is the call from the higher layer of the protocol stack (i.e., LL)
*/
void MultihopMac::recv(Packet* p, Handler *h)
{
if (h == 0) { /* from MAC classifier (pass pkt to LL) */
mode_ = MAC_IDLE;
Scheduler::instance().schedule(target_, p, delay_);
return;
}
callback_ = h;
hdr_mac* mh = hdr_mac::access(p);
mh->macSA() = addr_;
if (mh->ftype() == MF_ACK) {
mode_ = MAC_SND;
send(p);
} else {
mh->ftype() = MF_DATA;
poll(p); /* poll first */
}
}
mac-timers.cc
/* -*- 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 Computer Systems
* Engineering Group at Lawrence Berkeley 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.
*/
/* Ported from CMU/Monarch's code, nov'98 -Padma.*/
#include
#include
#include
#include
// #define DEBUG
//#include
#include
#include
#include
#include
#include
/*
* Force timers to expire on slottime boundries.
*/
// #define USE_SLOT_TIME
#define ROUND_TIME() \
{ \
assert(slottime); \
double rmd = remainder(s.clock() + rtime, slottime); \
if(rmd > 0.0) \
rtime += (slottime - rmd); \
else \
rtime += (-rmd); \
}
/* ======================================================================
Timers
====================================================================== */
void
MacTimer::start(double time)
{
Scheduler &s = Scheduler::instance();
assert(busy_ == 0);
busy_ = 1;
paused_ = 0;
stime = s.clock();
rtime = time;
assert(rtime >= 0.0);
s.schedule(this, &intr, rtime);
}
void
MacTimer::stop(void)
{
Scheduler &s = Scheduler::instance();
assert(busy_);
if(paused_ == 0)
s.cancel(&intr);
busy_ = 0;
paused_ = 0;
stime = 0.0;
rtime = 0.0;
}
/* ======================================================================
Defer Timer
====================================================================== */
void
DeferTimer::start(double time)
{
Scheduler &s = Scheduler::instance();
assert(busy_ == 0);
busy_ = 1;
paused_ = 0;
stime = s.clock();
rtime = time;
#ifdef USE_SLOT_TIME
ROUND_TIME();
#endif
assert(rtime >= 0.0);
s.schedule(this, &intr, rtime);
}
void
DeferTimer::handle(Event *)
{
busy_ = 0;
paused_ = 0;
stime = 0.0;
rtime = 0.0;
mac->deferHandler();
}
/* ======================================================================
NAV Timer
====================================================================== */
void
NavTimer::handle(Event *)
{
busy_ = 0;
paused_ = 0;
stime = 0.0;
rtime = 0.0;
mac->navHandler();
}
/* ======================================================================
Receive Timer
====================================================================== */
void
RxTimer::handle(Event *)
{
busy_ = 0;
paused_ = 0;
stime = 0.0;
rtime = 0.0;
mac->recvHandler();
}
/* ======================================================================
Send Timer
====================================================================== */
void
TxTimer::handle(Event *)
{
busy_ = 0;
paused_ = 0;
stime = 0.0;
rtime = 0.0;
mac->sendHandler();
}
/* ======================================================================
Interface Timer
====================================================================== */
void
IFTimer::handle(Event *)
{
busy_ = 0;
paused_ = 0;
stime = 0.0;
rtime = 0.0;
mac->txHandler();
}
/* ======================================================================
Backoff Timer
====================================================================== */
void
BackoffTimer::handle(Event *)
{
busy_ = 0;
paused_ = 0;
stime = 0.0;
rtime = 0.0;
difs_wait = 0.0;
mac->backoffHandler();
}
void
BackoffTimer::start(int cw, int idle)
{
Scheduler &s = Scheduler::instance();
assert(busy_ == 0);
busy_ = 1;
paused_ = 0;
stime = s.clock();
rtime = (Random::random() % cw) * mac->phymib_->SlotTime;
#ifdef USE_SLOT_TIME
ROUND_TIME();
#endif
difs_wait = 0.0;
if(idle == 0)
paused_ = 1;
else {
assert(rtime >= 0.0);
s.schedule(this, &intr, rtime);
}
}
void
BackoffTimer::pause()
{
Scheduler &s = Scheduler::instance();
//the caculation below make validation pass for linux though it
// looks dummy
double st = s.clock();
double rt = stime + difs_wait;
double sr = st - rt;
double mst = (mac->phymib_->SlotTime);
int slots = int (sr/mst);
//int slots = (int) ((s.clock() - (stime + difs_wait)) / mac->phymib_->SlotTime);
if(slots < 0)
slots = 0;
assert(busy_ && ! paused_);
paused_ = 1;
rtime -= (slots * mac->phymib_->SlotTime);
assert(rtime >= 0.0);
difs_wait = 0.0;
s.cancel(&intr);
}
void
BackoffTimer::resume(double difs)
{
Scheduler &s = Scheduler::instance();
assert(busy_ && paused_);
paused_ = 0;
stime = s.clock();
/*
* The media should be idle for DIFS time before we start
* decrementing the counter, so I add difs time in here.
*/
difs_wait = difs;
/*
#ifdef USE_SLOT_TIME
ROUND_TIME();
#endif
*/
assert(rtime + difs_wait >= 0.0);
s.schedule(this, &intr, rtime + difs_wait);
}
mac.cc
/* -*- 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 Daedalus Research
* Group at the University of California Berkeley.
* 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.
*
* Contributed by Giao Nguyen, http://daedalus.cs.berkeley.edu/~gnguyen
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
//#include "classifier.h"
#include
#include
#include
int hdr_mac::offset_;
static class MacHeaderClass : public PacketHeaderClass {
public:
MacHeaderClass() : PacketHeaderClass("PacketHeader/Mac",
sizeof(hdr_mac)) {
bind_offset(&hdr_mac::offset_);
}
void export_offsets() {
field_offset("macSA_", OFFSET(hdr_mac, macSA_));
field_offset("macDA_", OFFSET(hdr_mac, macDA_));
}
} class_hdr_mac;
static class MacClass : public TclClass {
public:
MacClass() : TclClass("Mac") {}
TclObject* create(int, const char*const*) {
return (new Mac);
}
} class_mac;
void
MacHandlerResume::handle(Event*)
{
mac_->resume();
}
void
MacHandlerSend::handle(Event* e)
{
mac_->sendDown((Packet*)e);
}
/* =================================================================
Mac Class Functions
==================================================================*/
static int MacIndex = 0;
Mac::Mac() : BiConnector(), netif_(0), tap_(0), ll_(0), channel_(0), callback_(0), hRes_(this), hSend_(this), state_(MAC_IDLE), pktRx_(0), pktTx_(0)
{
index_ = MacIndex++;
// bandwidth_ = 2.0 * 1e6;
bind_bw("bandwidth_", &bandwidth_);
off_mac_ = hdr_mac::offset_;
bind_time("delay_", &delay_);
//bind("off_mac_", &off_mac_);
}
int Mac::command(int argc, const char*const* argv)
{
if(argc == 2) {
Tcl& tcl = Tcl::instance();
if(strcmp(argv[1], "id") == 0) {
tcl.resultf("%d", addr());
return TCL_OK;
}
else if (strcmp(argv[1], "channel") == 0) {
tcl.resultf("%s", channel_->name());
return (TCL_OK);
}
/*else if (strcmp(argv[1], "classifier") == 0) {
tcl.resultf("%s", mcl_->name());
return (TCL_OK);
}
else if (strcmp(argv[1], "maclist") == 0) {
tcl.resultf("%s", macList_->name());
return (TCL_OK);
}*/
}
else if (argc == 3) {
TclObject *obj;
if( (obj = TclObject::lookup(argv[2])) == 0) {
fprintf(stderr, "%s lookup failed\n", argv[1]);
return TCL_ERROR;
}
// if (strcmp(argv[1], "channel") == 0) {
// channel_ = (Channel*) obj;
// return (TCL_OK);
// }
else if (strcmp(argv[1], "netif") == 0) {
netif_ = (Phy*) obj;
return TCL_OK;
}
else if (strcmp(argv[1], "log-target") == 0) {
logtarget_ = (NsObject*) obj;
if(logtarget_ == 0)
return TCL_ERROR;
return TCL_OK;
}
// else if (strcmp(argv[1], "up-target") == 0) {
// uptarget_ = (NsObject*) obj;
// return TCL_OK;
//}
/* else if (strcmp(argv[1], "down-target") == 0) {
downtarget_ = (NsObject*) obj;
return TCL_OK;
}*/
/*else if (strcmp(argv[1], "classifier") == 0) {
mcl_ = (Classifier*) obj;
return (TCL_OK);
}*/
/*if (strcmp(argv[1], "maclist") == 0) {
macList_ = (Mac*) obj;
return (TCL_OK);
}*/
}
return BiConnector::command(argc, argv);
}
void Mac::recv(Packet* p, Handler* h)
{
if (hdr_cmn::access(p)->direction() == hdr_cmn::UP) {
sendUp(p);
return;
}
callback_ = h;
hdr_mac* mh = HDR_MAC(p);
mh->set(MF_DATA, index_);
state(MAC_SEND);
sendDown(p);
}
void Mac::sendUp(Packet* p)
{
char* mh = (char*)p->access(hdr_mac::offset_);
int dst = this->hdr_dst(mh);
state(MAC_IDLE);
if (((u_int32_t)dst != MAC_BROADCAST) && (dst != index_)) {
drop(p);
return;
}
Scheduler::instance().schedule(uptarget_, p, \
delay_);
}
void Mac::sendDown(Packet* p)
{
Scheduler& s = Scheduler::instance();
double txt = txtime(p);
downtarget_->recv(p, this);
s.schedule(&hRes_, &intr_, txt);
}
void Mac::resume(Packet* p)
{
if (p != 0)
drop(p);
state(MAC_IDLE);
callback_->handle(&intr_);
}
//Mac* Mac::getPeerMac(Packet* p)
//{
//return (Mac*) mcl_->slot(hdr_mac::access(p)->macDA());
//}
mcast_ctrl.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* mcast_ctrl.cc
* Copyright (C) 1997 by USC/ISI
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation, advertising
* materials, and other materials related to such distribution and use
* acknowledge that the software was developed by the University of
* Southern California, Information Sciences Institute. The name of the
* University may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
#include "agent.h"
#include "packet.h"
#include "mcast_ctrl.h"
class mcastControlAgent : public Agent {
public:
mcastControlAgent() : Agent(PT_NTYPE) {
bind("packetSize_", &size_);
bind("off_mcast_ctrl_", &off_mcast_ctrl_);
}
void recv(Packet* pkt, Handler*) {
hdr_mcast_ctrl* ph = (hdr_mcast_ctrl*)pkt->access(off_mcast_ctrl_);
hdr_cmn* ch = (hdr_cmn*)pkt->access(off_cmn_);
// Agent/Mcast/Control instproc recv type from src group iface
Tcl::instance().evalf("%s recv %s %d %d", name(),
ph->type(), ch->iface(), ph->args());
Packet::free(pkt);
}
/*
* $proc send $type $src $group
*/
#define CASE(c,str,type) \
case (c): if (strcmp(argv[2], (str)) == 0) { \
type_ = (type); \
break; \
} else { \
/*FALLTHROUGH*/ \
}
int command(int argc, const char*const* argv) {
if (argc == 4) {
if (strcmp(argv[1], "send") == 0) {
switch (*argv[2]) {
CASE('p', "prune", PT_PRUNE);
CASE('g', "graft", PT_GRAFT);
CASE('X', "graftAck", PT_GRAFTACK);
CASE('j', "join", PT_JOIN);
CASE('a', "assert", PT_ASSERT);
default:
Tcl& tcl = Tcl::instance();
tcl.result("invalid control message");
return (TCL_ERROR);
}
Packet* pkt = allocpkt();
hdr_mcast_ctrl* ph = (hdr_mcast_ctrl*)pkt->access(off_mcast_ctrl_);
strcpy(ph->type(), argv[2]);
ph->args() = atoi(argv[3]);
send(pkt, 0);
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
protected:
int off_mcast_ctrl_;
};
//
// Now put the standard OTcl linkage templates here
//
static class mcastControlHeaderClass : public PacketHeaderClass {
public:
mcastControlHeaderClass() : PacketHeaderClass("PacketHeader/mcastCtrl",
sizeof(hdr_mcast_ctrl)) {}
} class_mcast_ctrl_hdr;
static class mcastControlClass : public TclClass {
public:
mcastControlClass() : TclClass("Agent/Mcast/Control") {}
TclObject* create(int, const char*const*) {
return (new mcastControlAgent());
}
} class_mcast_ctrl;
measuremod.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Xerox Corporation 1997. All rights reserved.
*
* License is granted to copy, to use, and to make and to use derivative
* works for research and evaluation purposes, provided that Xerox is
* acknowledged in all documentation pertaining to any such copy or
* derivative work. Xerox grants no other licenses expressed or
* implied. The Xerox trade name should not be used in any advertising
* without its written permission.
*
* XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
* MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
* FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
* express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*/
//Basic Measurement block derived from a connector
//measures bits sent and average packet delay in a measurement interval
#include "packet.h"
#include "connector.h"
#include "measuremod.h"
static class MeasureModClass : public TclClass {
public:
MeasureModClass() : TclClass("MeasureMod") {}
TclObject* create(int, const char*const*) {
return (new MeasureMod());
}
}class_measuremod;
MeasureMod::MeasureMod() : nbits_(0),npkts_(0)
{
}
void MeasureMod::recv(Packet *p,Handler *h)
{
hdr_cmn *ch=(hdr_cmn*)p->access(off_cmn_);
nbits_ += ch->size()<<3;
npkts_++;
send(p,h);
}
message.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1994-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 Computer Systems
* Engineering Group at Lawrence Berkeley 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$ (LBL)";
#endif
#include "agent.h"
#include "random.h"
#include "message.h"
int hdr_msg::offset_;
static class MessageHeaderClass : public PacketHeaderClass {
public:
MessageHeaderClass() : PacketHeaderClass("PacketHeader/Message",
sizeof(hdr_msg)) {
bind_offset(&hdr_msg::offset_);
}
} class_msghdr;
class MessageAgent : public Agent {
public:
MessageAgent();
int command(int argc, const char*const* argv);
void recv(Packet*, Handler*);
};
static class MessageClass : public TclClass {
public:
MessageClass() : TclClass("Agent/Message") {}
TclObject* create(int, const char*const*) {
return (new MessageAgent());
}
} class_message;
MessageAgent::MessageAgent() : Agent(PT_MESSAGE)
{
bind("packetSize_", &size_);
}
void MessageAgent::recv(Packet* pkt, Handler*)
{
hdr_msg* mh = hdr_msg::access(pkt);
char wrk[128];/*XXX*/
sprintf(wrk, "%s recv {%s}", name(), mh->msg());
Tcl& tcl = Tcl::instance();
tcl.eval(wrk);
Packet::free(pkt);
}
/*
* $proc handler $handler
* $proc send $msg
*/
int MessageAgent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "send") == 0) {
Packet* pkt = allocpkt();
hdr_msg* mh = hdr_msg::access(pkt);
const char* s = argv[2];
int n = strlen(s);
if (n >= mh->maxmsg()) {
tcl.result("message too big");
Packet::free(pkt);
return (TCL_ERROR);
}
strcpy(mh->msg(), s);
send(pkt, 0);
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
mftp.cc
/*
* (c) 1997-98 StarBurst Communications Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE 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 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.
*
* Author: Christoph Haenle, chris@cs.vu.nl
* File: mftp.cc
* Last change: Dec 07, 1998
*
* This software may freely be used only for non-commercial purposes
*/
// This file contains functionality common to both MFTP sender and receivers.
#include "mftp.h"
MFTPAgent::MFTPAgent() :
Agent(PT_MFTP), FileSize(0), FileDGrams(0),
dtu_size(0), dtus_per_block(0), dtus_per_group(0),
nb_groups(0)
{
bind("dtuSize_", &dtuSize_);
bind("fileSize_", &fileSize_);
bind("dtusPerBlock_", &dtusPerBlock_);
bind("dtusPerGroup_", &dtusPerGroup_);
bind("seekCount_", &seekCount_);
bind("off_mftp_", &off_mftp_);
bind("off_cmn_", &off_cmn_);
};
int MFTPAgent::init()
{
if(dtusPerBlock_ % 8 != 0) {
Tcl& tcl = Tcl::instance();
tcl.resultf("%s: dtusPerBlock_ must be a multiple of 8", name_);
return TCL_ERROR;
}
dtu_size = dtuSize_;
FileSize = fileSize_;
dtus_per_block = dtusPerBlock_;
dtus_per_group = dtusPerGroup_;
seekCount_ = 0;
FileDGrams = (FileSize + dtu_size - 1) / dtu_size;
nb_groups = (FileDGrams + dtus_per_group - 1) / dtus_per_group;
return TCL_OK;
}
mftp_rcv.cc
/*
* (c) 1997-98 StarBurst Communications Inc.
*
* THIS SOFTWARE IS PROVIDED BY THE 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 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.
*
* Author: Christoph Haenle, chris@cs.vu.nl
* File: mftp_rcv.cc
* Last change: Dec 14, 1998
*
* This software may freely be used only for non-commercial purposes
*/
// This file contains functionality specific to an MFTP receiver.
#include
#include "config.h"
#include "tclcl.h"
#include "mftp_rcv.h"
#include "ip.h" // due to declaration of hdr_ip
#define min(a, b) ((a) < (b) ? (a) : (b))
static class MFTPRcvAgentClass : public TclClass {
public:
MFTPRcvAgentClass() : TclClass("Agent/MFTP/Rcv") {}
TclObject* create(int, const char*const*) {
return (new MFTPRcvAgent());
}
} class_mftprcv_agent;
MFTPRcvAgent::MFTPRcvAgent()
: MFTPAgent(),
CurrentPass(0),
CurrentGroup(0),
CwPat(0),
FileDGramsReceived(0),
FseekOffset(0),
cw_matrixline_buf(NULL)
{
bind("reply_addr_", (int*)&reply_.addr_);
bind("reply_port_", (int*)&reply_.port_);
}
// inspect a Tcl command (overloaded function):
int MFTPRcvAgent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if(strcmp(argv[1], "send") == 0) {
if(strcmp(argv[2], "nak") == 0) {
unsigned long pass_nb, block_nb;
int nb_scanned = 0;
nb_scanned += sscanf(argv[3], "%lu", &pass_nb);
nb_scanned += sscanf(argv[4], "%lu", &block_nb);
assert(nb_scanned == 2);
send_nak(pass_nb, block_nb);
return TCL_OK;
}
} else if (strcmp(argv[1], "start") == 0) {
if(dtusPerBlock_ % 8 != 0) {
tcl.resultf("%s: dtusPerBlock_ must be a multiple of 8", name_);
return TCL_ERROR;
}
init();
return TCL_OK;
}
return Agent::command(argc, argv);
}
// process reception of a packet
void MFTPRcvAgent::recv(Packet* p, Handler* h)
{
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
hdr_mftp* mh = (hdr_mftp*) p->access(off_mftp_);
if(ih->daddr() == 0) {
// packet from local agent
fprintf(stderr, "%s: send not allowed with Agent/MFTP/Rcv\n", name_);
assert(false);
} else {
switch(mh->type) {
case hdr_mftp::PDU_DATA_TRANSFER:
recv_data(mh->spec.data);
break;
case hdr_mftp::PDU_STATUS_REQUEST:
recv_status_req(mh->spec.statReq);
break;
case hdr_mftp::PDU_NAK:
// as we are a member of the group as well, we receive all data we have sent.
break;
default:
assert(false); // received unknown packet type
}
Packet::free(p);
}
}
// Destructor:
MFTPRcvAgent::~MFTPRcvAgent()
{
// Note: delete on a NULL-pointer has no effect
delete [] cw_matrixline_buf;
}
void MFTPRcvAgent::init()
{
MFTPAgent::init();
// allocate cw_matrix_line_buf
assert(cw_matrixline_buf == NULL);
cw_matrixline_buf = new CW_MATRIXLINE_t[FileDGrams];
assert(cw_matrixline_buf != NULL); // or else no memory is left!
// should return an error instead of terminating the program
// reset array:
cw_matrixlines_reset();
}
/* process a received status request packet */
void MFTPRcvAgent::recv_status_req(hdr_mftp::Spec::StatReq& statreq)
{
Tcl& tcl = Tcl::instance();
// read the PDU_STATUS_REQUEST-specific fields:
tcl.evalf("%s recv status-req %lu %lu %lu %lf", name_,
(unsigned long) statreq.pass_nb,
(unsigned long) statreq.block_lo,
(unsigned long) statreq.block_hi,
(double) statreq.RspBackoffWindow);
}
// send a nak packet:
void MFTPRcvAgent::send_nak(unsigned long pass_nb, unsigned long block_nb)
{
assert(FileDGrams > 0);
assert(0 <= block_nb && block_nb < nb_blocks());
Tcl& tcl = Tcl::instance();
// start_group_nb corresponds to first bit of NAK-bitmap:
unsigned long start_group_nb = dtus_per_block * block_nb;
// end_group_nb corresponds to last group number of NAK-bitmap plus one
unsigned long end_group_nb = min(nb_groups, dtus_per_block * (block_nb + 1));
// number of valid bits in the outgoing nak-bitmap
unsigned long n = end_group_nb - start_group_nb;
// number of status bytes in pdu
const unsigned long nak_bytes = (n+7) / 8;
unsigned long bit_count = 0;
// allocate (get) new packet and dynamically allocate extra space for nak-bitmap:
Packet* p = Agent::allocpkt((n+7) / 8);
unsigned char* nak_bitmap = (unsigned char*) p->accessdata();
// clear NAK-bitmap first:
memset(nak_bitmap, 0, nak_bytes);
// loop over all groups in rangs of nak and set nak-bit for those that are not still full
for(unsigned long group_nb = start_group_nb, bit = 1 << (start_group_nb % 8);
group_nb < end_group_nb; ++group_nb) {
if(is_group_full(group_nb) == false) {
*nak_bitmap |= bit;
bit_count++;
}
if(bit == 128) {
bit = 1;
nak_bitmap++;
} else {
bit <<= 1;
}
}
if(bit_count > 0) {
hdr_ip* iph = (hdr_ip*)p->access(off_ip_);
hdr_mftp* hdr = (hdr_mftp*) p->access(off_mftp_);
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
// now generate the header
iph->dst() = reply_; // overwrite settings from Agent::allocpkt()
ch->size() = sizeof(hdr_mftp);
hdr->type = hdr_mftp::PDU_NAK;
hdr->spec.nak.pass_nb = pass_nb;
hdr->spec.nak.block_nb = block_nb;
hdr->spec.nak.nak_count = bit_count;
// transmit packet
target_->recv(p);
}
else {
Packet::free(p); // do not transmit NAK-packet if it consists of 0 NAK-bits !!
// HACK: @ requires optimation still!
}
tcl.resultf("%lu", bit_count);
}
// process_packet: decides if a received packet is "useful" and
// stores meta-information for proper decoding
int MFTPRcvAgent::process_packet(CW_PATTERN_t cw_pat,
unsigned long group_nb, unsigned long dtu_nb)
{
CW_PATTERN_t bit;
CW_MATRIXLINE_t new_row;
unsigned long j; // j iterates over the dtus of group "group_nb"
unsigned l