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 long finish = get_dtus_per_group(group_nb);
// finish counts the number of dtus in group "group_nb"
new_row.left = cw_pat;
for(j = 0; j < finish; j++) {
CW_PATTERN_t line_pat = cw_matrixline_buf[j * nb_groups + group_nb].left;
if(line_pat != 0) {
bit = new_row.left & ((CW_PATTERN_t) 1 << minbit(line_pat));
if(bit != 0) {
new_row.left ^= line_pat;
}
}
}
if(new_row.left != 0) { // linear independent?
bit = (CW_PATTERN_t) 1 << minbit(new_row.left);
for(j = 0; j < finish; j++) {
if((bit & cw_matrixline_buf[j * nb_groups + group_nb].left) != 0) {
cw_matrixline_buf[j * nb_groups + group_nb].left ^= new_row.left;
}
}
// register pattern of codeword the received packet is composed of (possibly altered).
// must be done at last for that this line gets not erased by XORing with itself
// in the previous loop.
cw_matrixline_buf[dtu_nb * nb_groups + group_nb].left = new_row.left;
return 1; // packet was a "useful" packet (i.e. is linear independent
// from the other ones received so far)
}
else {
return 0; //linear dependent codeword-pattern received, i.e. useless
}
}
int MFTPRcvAgent::findStoreLocation(unsigned long group_nb, unsigned long seek_offset, unsigned long* dtu_nb)
{
unsigned long start_dtu_nb;
assert(0 <= group_nb && group_nb < nb_groups);
assert(seek_offset % dtu_size == 0 ||
seek_offset == FileSize);
if(seek_offset == FileSize) {
*dtu_nb = group_nb; // start over from the beginning
} else {
unsigned long curr_dtu_nb = FseekOffset / dtu_size;
// pay attention to "unsigned" when substracting
*dtu_nb = curr_dtu_nb - curr_dtu_nb % nb_groups;
*dtu_nb += group_nb;
// check if seeking backwards. If yes, increment dtu_nb by nb_groups to
// always seeks forwards (unless end of file is reached):
if(*dtu_nb < curr_dtu_nb) {
*dtu_nb += nb_groups;
}
}
if(*dtu_nb >= FileDGrams) {
// this might happen if some groups have less packets than
// dtus_per_group:
*dtu_nb = group_nb; // start over from the beginning
}
start_dtu_nb = *dtu_nb;
assert(start_dtu_nb < FileDGrams);
do {
if(! cw_matrixline_buf[*dtu_nb].left) {
return 1;
}
*dtu_nb += nb_groups;
if(*dtu_nb >= FileDGrams) {
*dtu_nb = group_nb; // start over from the beginning
}
} while(*dtu_nb != start_dtu_nb);
return 0; // group "group_nb" is already full
}
// initializes all matrix-lines to zero, i.e. no (encoded) packets
// at all are received so far:
void MFTPRcvAgent::cw_matrixlines_reset()
{
assert(0 <= FileDGrams);
memset(cw_matrixline_buf, 0, sizeof(CW_MATRIXLINE_t) * FileDGrams);
}
// returns true if group "group_nb" is full, false if there is at least one packet missing
bool MFTPRcvAgent::is_group_full(unsigned long group_nb)
{
unsigned long nb_dtus = get_dtus_per_group(group_nb);
unsigned long i;
assert(0 <= group_nb && group_nb < nb_groups);
for(i = 0; i < nb_dtus &&
cw_matrixline_buf[i * nb_groups + group_nb].left != 0; ++i)
;
return (i == nb_dtus) ? true : false; // if loop was left before nb_dtus was reached,
// then there is some line in the matrix that is
// all "0", i.e. a packet is still missing.
}
// recv_data: process received data packet;
// takes (received) coded packets and processes them.
int MFTPRcvAgent::recv_data(hdr_mftp::Spec::Data& data)
{
Tcl& tcl = Tcl::instance();
unsigned long seek_offset;
unsigned long dtu_nb; // position (in terms of datagram number) where incoming
// packet is stored in file
// read the PDU_DATA_TRANSFER-specific fields:
CurrentPass = data.pass_nb;
CurrentGroup = data.group_nb;
CwPat = data.cw_pat;
// validate fields:
// (actually, assert should be replaced by just ignoring the packet in case
// the parameters are invalid, as some corrupt packet might reach the receiver
// in real world, i.e. this would not be a bug in the software!)
assert(0 <= CurrentPass);
assert(0 <= CurrentGroup && CurrentGroup < nb_groups);
if(findStoreLocation(CurrentGroup, FseekOffset, &dtu_nb)) {
// arriving packet belongs to a not already full group:
assert(dtu_nb % nb_groups == CurrentGroup);
assert(0 <= dtu_nb && dtu_nb < FileDGrams);
if(process_packet(CwPat,
CurrentGroup,
dtu_nb / nb_groups)) {
cw_matrixline_buf[dtu_nb].right = CwPat;
// arriving packet is useful (i.e. linearly independent from the others
// of the group, thus store packet on disk:
char buf[8 * sizeof(CW_PATTERN_t) + 1];
CwPat.print(buf);
tcl.evalf("%s recv useful %lu %lu %s",
name_,
(unsigned long) CurrentPass,
(unsigned long) CurrentGroup,
(char*) buf);
seek_offset = dtu_nb * dtu_size;
if(dtu_nb == FileDGrams - 1) {
// the last dtu of the file might not fit into the file, as with
// erasure correction, the dtu size must always be the same,
// i.e. dtu_size. So we don't write the packet on disk.
// Rather, we store it in a special place in main memory.
// (ommitted)
} else {
// prepare to write the new packet to the file system:
if(FseekOffset != seek_offset) {
// seek to file-position seek_offset (omitted)
FseekOffset = seek_offset;
seekCount_++;
}
// write data to file here (omitted)
FseekOffset += dtu_size;
} // else
// increment number of good dtus received
FileDGramsReceived++;
// if all packets have been received, decode the file and send a done-message
if (FileDGramsReceived == FileDGrams) {
// decode file here. Involves the file, the cw_matrixline_buf-array and
// the last packet (cached in memory). Additional disk activity for the
// receivers will be required.
// (omitted)
char buf[8 * sizeof(CW_PATTERN_t) + 1];
CwPat.print(buf);
tcl.evalf("%s done-notify %lu %lu %s",
name_,
(unsigned long) CurrentPass,
(unsigned long) CurrentGroup,
(char*) buf);
return(0); // we are ready!
}
} // if(process_packet...)
else {
char buf[8 * sizeof(CW_PATTERN_t) + 1];
CwPat.print(buf);
tcl.evalf("%s recv dependent %lu %lu %s",
name_,
(unsigned long) CurrentPass,
(unsigned long) CurrentGroup,
(char*) buf);
return(0); // we are ready!
}
} // if(findStoreLocation...)
else {
// we received a packet that belongs to an already full group
char buf[8 * sizeof(CW_PATTERN_t) + 1];
CwPat.print(buf);
tcl.evalf("%s recv group-full %lu %lu %s",
name_,
(unsigned long) CurrentPass,
(unsigned long) CurrentGroup,
(char*) buf);
}
return(0);
}
mftp_snd.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_snd.cc
* Last change: Dec 07, 1998
*
* This software may freely be used only for non-commercial purposes
*/
// This file contains functionality specific to the MFTP sender.
#include // strtoul, etc.
#include
#include
#include "config.h"
#include "tclcl.h"
#include "agent.h"
#include "packet.h"
#include "ip.h"
#include "mftp_snd.h"
#include "trace.h"
#include "bitops.h" // due to IS_BITSET, etc.
#define min(a, b) ((a) < (b) ? (a) : (b))
static class MFTPSndAgentClass : public TclClass {
public:
MFTPSndAgentClass() : TclClass("Agent/MFTP/Snd") {}
TclObject* create(int, const char*const*) {
return (new MFTPSndAgent());
}
} class_mftpsnd_agent;
static class MFTPHeaderClass : public PacketHeaderClass {
public:
MFTPHeaderClass() : PacketHeaderClass("PacketHeader/MFTP",
sizeof(hdr_mftp)) {}
} class_mftphdr;
MFTPSndAgent::MFTPSndAgent()
: MFTPAgent(),
naks(0),
retx(0),
fseek_offset(0),
read_ahead_bufsize(0),
CurrentPass(0),
CurrentGroup(0),
CwPat(0),
MinGroupNbInBuf(0),
NbGroupsInBuf(0)
{
bind("readAheadBufsize_", &readAheadBufsize_);
bind_time("txStatusDelay_", &txStatusDelay_);
bind("nakCount_", &nakCount_);
}
MFTPSndAgent::~MFTPSndAgent()
{
delete [] naks; // NOTE: delete on NULL pointer has no effect
delete [] retx;
}
int MFTPSndAgent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if(strcmp(argv[1], "send") == 0) {
if(strcmp(argv[2], "data") == 0) {
return send_data();
} else if(strcmp(argv[2], "statreq") == 0) {
unsigned long pass_nb, block_lo, block_hi;
double rsp_backoff_window=2343.2343;
int nb_scanned = 0;
if(argc == 7) {
nb_scanned += sscanf(argv[3], "%lu", &pass_nb);
nb_scanned += sscanf(argv[4], "%lu", &block_lo);
nb_scanned += sscanf(argv[5], "%lu", &block_hi);
nb_scanned += sscanf(argv[6], "%lf", &rsp_backoff_window);
}
if(nb_scanned != 4) {
tcl.resultf("%s: wrong number of parameters for \"send statreq\"", name_);
return TCL_ERROR;
}
send_status_request(pass_nb, block_lo, block_hi, rsp_backoff_window);
return TCL_OK;
}
}
if(strcmp(argv[1], "start") == 0) {
if(MFTPAgent::init() == TCL_ERROR) {
return TCL_ERROR;
};
init_user_file((unsigned long) readAheadBufsize_);
return TCL_OK;
}
return Agent::command(argc, argv);
}
void MFTPSndAgent::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) {
assert(false); // Packet from local agent.
} else {
switch(mh->type) {
case hdr_mftp::PDU_DATA_TRANSFER:
case hdr_mftp::PDU_STATUS_REQUEST:
// as the sender is a member of the multicast group as well,
// it receives all data it has sent. So just ignore it.
break;
case hdr_mftp::PDU_NAK:
process_nak(mh->spec.nak, p->accessdata(), CurrentPass-1); // -1 because we have
// incremented the pass-number already in send_data.
break;
default:
assert(false); // unknown packet type (also possible: just ignore packet rather than exit)
}
Packet::free(p);
}
}
void MFTPSndAgent::send_status_request(unsigned long pass_nb,
unsigned long block_lo,
unsigned long block_hi,
double rsp_backoff_window)
{
Packet* p = Agent::allocpkt();
hdr_mftp* hdr = (hdr_mftp*) p->access(off_mftp_);
assert(FileDGrams > 0); // we need this requirement here
// initialize the header of the status request packet:
hdr->type = hdr_mftp::PDU_STATUS_REQUEST;
hdr->spec.statReq.pass_nb = pass_nb;
hdr->spec.statReq.block_lo = block_lo;
hdr->spec.statReq.block_hi = block_hi;
hdr->spec.statReq.RspBackoffWindow = rsp_backoff_window;
// transmit packet
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() = sizeof(hdr_mftp);
target_->recv(p);
}
// process incoming nak:
void MFTPSndAgent::process_nak(hdr_mftp::Spec::Nak& nak,
unsigned char* nak_bitmap,
unsigned long currentPass)
{
assert(1 <= nak.nak_count && nak.nak_count <= nb_groups); // or else some receiver is fooling us.
assert(nak.pass_nb <= currentPass); // pass greater than requested? => a receiver is fooling us.
Tcl& tcl = Tcl::instance();
tcl.evalf("%s recv nak %lu %lu %lu", name_,
(unsigned long) nak.pass_nb,
(unsigned long) nak.block_nb,
(unsigned long) nak.nak_count);
assert(dtus_per_block % 8 == 0); // This property is required for the following
// start_group_nb corresponds to first bit of NAK-bitmap:
const unsigned long start_group_nb = dtus_per_block * nak.block_nb;
// end_group_nb corresponds to last group number of NAK-bitmap plus one
const unsigned long end_group_nb = min(nb_groups, dtus_per_block * (nak.block_nb + 1));
// get starting index into naks-array for this block
const unsigned long nak_index = start_group_nb / 8;
// number of status bytes in pdu
const unsigned long nak_bytes = (end_group_nb - start_group_nb + 7) / 8;
// pointer to location in array at which the received nak bitmap must be
// or'd to the sender-bitmap (the bitmap in which the sender collects the naks)
unsigned char* nak_array = naks + nak_index;
// if this nak pdu is from a previous pass (i.e. a delayed nak), ignore the status
// bits for dtu's that we've just retransmitted in the current pass:
if(nak.pass_nb < currentPass) {
unsigned char* retx_array = retx + nak_index;
for(unsigned long i = 0; i < nak_bytes; i++) {
if(*nak_bitmap) {
// "AND out" bits for already transmitted packets and
// "OR in" the result into newly constructed NAK bitmap
*nak_array |= (*nak_bitmap & (~*retx_array));
}
nak_array++;
retx_array++;
nak_bitmap++;
}
}
else {
assert(nak.pass_nb == currentPass); // this nak belongs to the current pass
for(unsigned long i = 0; i < nak_bytes; i++) {
if(*nak_bitmap) {
// "OR in" NAK byte into newly constructed NAK bitmap
*nak_array |= *nak_bitmap;
}
nak_array++;
nak_bitmap++;
}
}
nakCount_++; // increment total number of received nak-packets
}
void MFTPSndAgent::init_user_file(unsigned long readAheadBufsize)
{
read_ahead_bufsize = readAheadBufsize;
fseek_offset = 0;
// initialize codeword pattern
iterator.setSourceWordLen(dtus_per_group);
CwPat = iterator.getNextCwPat();
// free arrays from a possible previous transmission (no effect on NULL pointers)
delete [] naks;
delete [] retx;
// allocate naks bitmap init'd to all nak'd:
naks = new unsigned char[(nb_groups + 7) / 8];
assert(naks != NULL); // or else we ran out of memory
SET_ALL_BITS(naks, nb_groups);
// allocate retransmission bitmap init'd to none retransmitted:
retx = new unsigned char[(nb_groups + 7) / 8];
assert(retx != NULL); // or else we ran out of memory
RESET_ALL_BITS(retx, nb_groups);
CurrentPass = CurrentGroup = MinGroupNbInBuf = NbGroupsInBuf = 0;
}
// reads as many groups into the read-ahead-buffer as there is space, starting with
// group CurrentGroup. The groups that were not not NACK'd by anyone will be
// skipped (and the corresponding areas in the read-ahead-buffer will be skipped
// as well).
void MFTPSndAgent::fill_read_ahead_buf()
{
unsigned int dtu_pos; // loops over [0..dtus_per_group)
unsigned long seek_offset; // where to position the head for disk seeks
unsigned long buf_pos = 0; // position where data is written (into main memory) when
// read from disk, relative to the start of read_ahead_buf
CW_PATTERN_t cw_pat_tmp = CwPat;
unsigned long i;
unsigned long len;
// switch to next group that must be read:
MinGroupNbInBuf = CurrentGroup;
NbGroupsInBuf = min(read_ahead_bufsize / (bitcount(CwPat) * dtu_size),
nb_groups - MinGroupNbInBuf);
while(cw_pat_tmp != 0) {
dtu_pos = minbit(cw_pat_tmp);
assert(0 <= dtu_pos && dtu_pos < dtus_per_group);
assert(MinGroupNbInBuf + NbGroupsInBuf <= nb_groups);
cw_pat_tmp &= ~((CW_PATTERN_t) 1 << dtu_pos); // clear bit at position "dtu_pos"
for(i = MinGroupNbInBuf;
i < MinGroupNbInBuf + NbGroupsInBuf; ++i) {
// continue with for-loop if group i was not NACKed by anyone
if(IS_BIT_CLEARED(naks, i)) {
buf_pos += dtu_size;
continue;
}
// Note: there is never data accessed "outside" the file as the while-loop
// is left as soon as the last (possibly partial) DTU has been read.
seek_offset = (dtu_pos * nb_groups + i) * dtu_size;
if(seek_offset >= FileSize) {
// we can get there if the last group(s) have fewer than
// dtus_per_group packets. If we get here, we are ready.
return; // OK
}
if (fseek_offset != seek_offset) {
// do the fseek here (omitted)
seekCount_++;
fseek_offset = seek_offset;
}
// determine number of bytes to read
len = min(dtu_size, FileSize - fseek_offset);
// read len bytes from file here (omitted)
fseek_offset += len;
buf_pos += len;
if(len < dtu_size) {
// we get here if the last dtu is smaller than dtu_size and if
// we have just read that last dtu
assert(fseek_offset == FileSize); // we must be at EOF
// clear rest of read-ahead-buffer here (omitted)
buf_pos = bitcount(CwPat) * NbGroupsInBuf * dtu_size;
return; // that's it, no more packets to process
}
assert(len == dtu_size);
assert(buf_pos <= bitcount(CwPat) * NbGroupsInBuf * dtu_size);
} // for
} // while
// we get here only if no group was read with less than dtus_per_group packets and
// the if not the last packet was read (in case it is too short)
assert(buf_pos == bitcount(CwPat) * NbGroupsInBuf * dtu_size);
}
// send_data() sends next data packet.
// In tcl's result buffer, return
// 0, if current pass not yet finished
// -1, if reached the end of the current pass
int MFTPSndAgent::send_data()
{
Packet* p = Agent::allocpkt();
hdr_mftp* hdr = (hdr_mftp*) p->access(off_mftp_);
CW_PATTERN_t mask;
Tcl& tcl = Tcl::instance();
assert(0 <= CurrentGroup && CurrentGroup < nb_groups);
assert(NbGroupsInBuf >= 0);
assert(0 <= MinGroupNbInBuf && MinGroupNbInBuf + NbGroupsInBuf <= nb_groups);
// now comes NACK processing: loop until end of file or until
// a nak bit is detected:
while(CurrentGroup < nb_groups && IS_BIT_CLEARED(naks, CurrentGroup)) {
CurrentGroup++; // proceed to next bit of the nak bitmap
}
// do not transmit packet if
// (1) CurrentGroup has reached the total number of groups ("end of pass") or
// (2) CwPat has only bits set that refer to some packets that are cut off in
// the current group (for example, if CurrentGroup has only 5 packets
// with nb_groups=8 and if CwPat=64+32)
if(CurrentGroup != nb_groups &&
((mask = (~(CW_PATTERN_t) 0) >> (8 * sizeof(CW_PATTERN_t) - get_dtus_per_group(CurrentGroup)))
& CwPat) != 0) {
assert(CurrentGroup < nb_groups);
// see if the read-ahead-buffer is exhausted so that we must load new data
// from file. Only groups with a corresponding NAK-bit are read, that is,
// those that were requested for retransmission
assert(MinGroupNbInBuf <= CurrentGroup);
if(CurrentGroup >= MinGroupNbInBuf + NbGroupsInBuf) { // exhausted?
fill_read_ahead_buf(); // load new data from file
}
assert(MinGroupNbInBuf <= CurrentGroup &&
CurrentGroup < MinGroupNbInBuf + NbGroupsInBuf);
// produce an encoded packet here (omitted)
// generate the header
hdr->type = hdr_mftp::PDU_DATA_TRANSFER;
hdr->spec.data.pass_nb = CurrentPass;
hdr->spec.data.group_nb = CurrentGroup;
hdr->spec.data.cw_pat = CwPat & mask;
char buf[8 * sizeof(CW_PATTERN_t) + 1];
(CwPat & mask).print(buf);
tcl.evalf("%s send notify %lu %lu %s",
name_,
(unsigned long) CurrentPass,
(unsigned long) CurrentGroup,
(char*) buf);
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() = sizeof(hdr_mftp) + dtu_size;
// transmit packet
target_->recv(p);
RESET_BIT(naks, CurrentGroup); // reset the dtu status bit in the nak bitmap
SET_BIT(retx, CurrentGroup); // set the dtus status bit in the retransmission bitmap
CurrentGroup++;
} // if
// if last group of the file:
if(CurrentGroup == nb_groups || !(CwPat & mask)) { // end of pass?
do {
CwPat = iterator.getNextCwPat(); // get next codeword for new pass
} while(!(CwPat & ((~(CW_PATTERN_t) 0) >> (8 * sizeof(CW_PATTERN_t) - get_dtus_per_group(0)))));
// } while(!(CwPat & ((((CW_PATTERN_t) 1) << get_dtus_per_group(0)) - 1)));
// prepare a new pas:
MinGroupNbInBuf = 0;
NbGroupsInBuf = 0;
CurrentGroup = 0;
// reset retransmission bitmap for dealing with of latent naks
RESET_ALL_BITS(retx, nb_groups);
// the first dtus_per_group passes must be transmitted "in full"
if(CurrentPass < dtus_per_group - 1) {
SET_ALL_BITS(naks, nb_groups);
}
tcl.evalf("%s pass-finished %lu %lu", name_,
(unsigned long) CurrentPass,
(unsigned long) nb_blocks());
CurrentPass++;
tcl.result("-1"); // return end-of-pass to the caller
return TCL_OK;
}
tcl.result("0"); // end-of-pass not yet reached
return TCL_OK;
}
mip-reg.cc
/*
* Copyright (c) Sun Microsystems, Inc. 1998 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 Sun Microsystems, Inc.
*
* 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* SUN MICROSYSTEMS 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.
*/
// #ident "@(#)mip-reg.cc 1.4 98/08/30 SMI"
#include
#include
#include
#include
#include
#define AGENT_ADS_SIZE 48
#define REG_REQUEST_SIZE 52
static class MIPHeaderClass : public PacketHeaderClass {
public:
MIPHeaderClass() : PacketHeaderClass("PacketHeader/MIP",
sizeof(hdr_mip)) {
}
} class_miphdr;
static class MIPBSAgentClass : public TclClass {
public:
MIPBSAgentClass() : TclClass("Agent/MIPBS") {}
TclObject* create(int, const char*const*) {
return (new MIPBSAgent());
}
} class_mipbsagent;
MIPBSAgent::MIPBSAgent() : Agent(PT_UDP), beacon_(1.0),
bcast_target_(0), ragent_(0), timer_(this), adlftm_(~0)
{
bind("adSize_", &size_);
//bind("shift_", &shift_);
//bind("mask_", &mask_);
bind("ad_lifetime_", &adlftm_);
bind("off_mip_", &off_mip_);
size_ = AGENT_ADS_SIZE;
seqno_ = -1;
}
void MIPBSAgent::recv(Packet* p, Handler *)
{
Tcl& tcl = Tcl::instance();
char *objname = NULL;
NsObject *obj = NULL;
hdr_mip *miph = (hdr_mip *)p->access(off_mip_);
hdr_ip *iph = (hdr_ip *)p->access(off_ip_);
hdr_cmn *ch = (hdr_cmn*)p->access(off_cmn_);
int nodeaddr = Address::instance().get_nodeaddr(addr());
switch (miph->type_) {
case MIPT_REG_REQUEST:
//if (miph->ha_ == (addr_ >> shift_ & mask_)) {
if (miph->ha_ == (Address::instance().get_nodeaddr(addr()))){
if (miph->ha_ == miph->coa_) { // back home
tcl.evalf("%s clear-reg %d", name_,
miph->haddr_);
}
else {
tcl.evalf("%s encap-route %d %d %lf", name_,
miph->haddr_, miph->coa_,
miph->lifetime_);
}
iph->dst() = iph->src();
miph->type_ = MIPT_REG_REPLY;
}
else {
//iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (miph->ha_ & mask_) << shift_;
iph->daddr() = miph->ha_;
iph->dport() = 0;
}
iph->saddr() = addr();
iph->sport() = port();
// by now should be back to normal route
// if dst is the mobile
// also initialise forward counter to 0. otherwise routing
// agent is going to think pkt is looping and drop it!!
ch->num_forwards() = 0;
send(p, 0);
break;
case MIPT_REG_REPLY:
//assert(miph->coa_ == (addr_ >> shift_ & mask_));
assert(miph->coa_ == nodeaddr);
tcl.evalf("%s get-link %d %d", name_, nodeaddr, miph->haddr_);
//
// XXX hacking mobileip. all this should go away
// when mobileIP for sun-wired model is no longer reqd.
//
obj = (NsObject*)tcl.lookup(objname = tcl.result());
if (strlen(objname) == 0)
objname = "XXX";
tcl.evalf("%s decap-route %d %s %lf", name_, miph->haddr_,
objname, miph->lifetime_);
iph->src() = iph->dst();
//iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) |(miph->haddr_ & mask_) << shift_;
iph->daddr() = miph->haddr_;
iph->dport() = 0;
if (obj == NULL)
obj = ragent_;
obj->recv(p, (Handler*)0);
break;
case MIPT_SOL:
//tcl.evalf("%s get-link %d %d", name_, addr_ >> shift_ & mask_,miph->haddr_);
tcl.evalf("%s get-link %d %d",name_,nodeaddr,miph->haddr_);
send_ads(miph->haddr_, (NsObject*)tcl.lookup(tcl.result()));
Packet::free(p);
break;
default:
Packet::free(p);
break;
}
}
void MIPBSAgent::timeout(int )
{
send_ads();
timer_.resched(beacon_);
}
int MIPBSAgent::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "beacon-period") == 0) {
beacon_ = atof(argv[2]);
timer_.resched(Random::uniform(0, beacon_));
return TCL_OK;
}
if (strcmp(argv[1], "bcast-target") == 0) {
bcast_target_ = (NsObject *)TclObject::lookup(argv[2]);
return TCL_OK;
}
if (strcmp(argv[1], "ragent") == 0) {
ragent_ = (NsObject *)TclObject::lookup(argv[2]);
return TCL_OK;
}
}
return (Agent::command(argc, argv));
}
void MIPBSAgent::send_ads(int dst, NsObject *target)
{
Packet *p = allocpkt();
hdr_mip *h = (hdr_mip *)p->access(off_mip_);
hdr_ip *iph = (hdr_ip *)p->access(off_ip_);
h->haddr_ = h->ha_ = -1;
//h->coa_ = addr_ >> shift_ & mask_;
h->coa_ = Address::instance().get_nodeaddr(addr());
h->type_ = MIPT_ADS;
h->lifetime_ = adlftm_;
h->seqno_ = ++seqno_;
if (dst != -1) {
//hdr_ip *iph = (hdr_ip *)p->access(off_ip_);
//iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (dst & mask_) << shift_;
iph->daddr() = dst;
iph->dport() = 0;
}
else {
// if bcast pkt
sendOutBCastPkt(p);
}
if (target == NULL) {
if (bcast_target_) bcast_target_->recv(p, (Handler*) 0);
else if (target_) target_->recv(p, (Handler*) 0);
else Packet::free(p); // drop; may log in future code
}
else target->recv(p, (Handler*)0);
}
void
MIPBSAgent::sendOutBCastPkt(Packet *p)
{
hdr_ip *iph = (hdr_ip*)p->access(off_ip_);
hdr_cmn *hdrc = (hdr_cmn *)p->access (off_cmn_);
hdrc->next_hop_ = IP_BROADCAST;
hdrc->addr_type_ = NS_AF_INET;
iph->daddr() = IP_BROADCAST;
iph->dport() = 0;
}
void AgtListTimer::expire(Event *) {
a_->timeout(MIP_TIMER_AGTLIST);
}
static class MIPMHAgentClass : public TclClass {
public:
MIPMHAgentClass() : TclClass("Agent/MIPMH") {}
TclObject* create(int, const char*const*) {
return (new MIPMHAgent());
}
} class_mipmhagent;
MIPMHAgent::MIPMHAgent() : Agent(PT_UDP), ha_(-1), coa_(-1),
beacon_(1.0),bcast_target_(0),agts_(0),rtx_timer_(this),
agtlist_timer_(this),reglftm_(~0),adlftm_(0.0), node_ (0)
{
bind("home_agent_", &ha_);
bind("rreqSize_", &size_);
bind("reg_rtx_", ®_rtx_);
//bind("shift_", &shift_);
//bind("mask_", &mask_);
bind("reg_lifetime_", ®lftm_);
bind("off_mip_", &off_mip_);
size_ = REG_REQUEST_SIZE;
seqno_ = -1;
}
void MIPMHAgent::recv(Packet* p, Handler *)
{
Tcl& tcl = Tcl::instance();
hdr_mip *miph = (hdr_mip *)p->access(off_mip_);
switch (miph->type_) {
case MIPT_REG_REPLY:
if (miph->coa_ != coa_) break; // not pending
tcl.evalf("%s update-reg %d", name_, coa_);
if (rtx_timer_.status() == TIMER_PENDING)
rtx_timer_.cancel();
break;
case MIPT_ADS:
{
AgentList **ppagts = &agts_, *ptr;
while (*ppagts) {
if ((*ppagts)->node_ == miph->coa_) break;
ppagts = &(*ppagts)->next_;
}
if (*ppagts) {
ptr = *ppagts;
*ppagts = ptr->next_;
ptr->expire_time_ = beacon_ +
Scheduler::instance().clock();
ptr->lifetime_ = miph->lifetime_;
ptr->next_ = agts_;
agts_ = ptr;
if (coa_ == miph->coa_) {
seqno_++;
reg();
}
}
else { // new ads
ptr = new AgentList;
ptr->node_ = miph->coa_;
ptr->expire_time_ = beacon_ +
Scheduler::instance().clock();
ptr->lifetime_ = miph->lifetime_;
ptr->next_ = agts_;
agts_ = ptr;
coa_ = miph->coa_;
// The MHagent now should update the Mobilenode
// about the changed coa_ : node updates its
// base-station to new coa_ accordingly.
if(node_)
node_->set_base_stn(coa_);
adlftm_ = miph->lifetime_;
seqno_++;
reg();
}
}
break;
default:
break;
}
Packet::free(p);
}
void MIPMHAgent::timeout(int tno)
{
switch (tno) {
case MIP_TIMER_SIMPLE:
reg();
break;
case MIP_TIMER_AGTLIST:
{
double now = Scheduler::instance().clock();
AgentList **ppagts = &agts_, *ptr;
int coalost = 0;
while (*ppagts) {
if ((*ppagts)->expire_time_ < now) {
ptr = *ppagts;
*ppagts = ptr->next_;
if (ptr->node_ == coa_) {
coa_ = -1;
coalost = 1;
}
delete ptr;
}
else ppagts = &(*ppagts)->next_;
}
agtlist_timer_.resched(beacon_);
if (coalost) {
seqno_++;
reg();
}
}
break;
default:
break;
}
}
int MIPMHAgent::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "beacon-period") == 0) {
beacon_ = atof(argv[2]);
timeout(MIP_TIMER_AGTLIST);
agtlist_timer_.resched(beacon_);
rtx_timer_.resched(Random::uniform(0, beacon_));
return TCL_OK;
}
else if (strcmp(argv[1], "bcast-target") == 0) {
bcast_target_ = (NsObject *)TclObject::lookup(argv[2]);
return TCL_OK;
}
else if (strcmp (argv[1], "node") == 0) {
node_ = (MobileNode*)TclObject::lookup(argv[2]);
if (node_ == 0) {
fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);
return TCL_ERROR;
}
return TCL_OK;
}
}
// later: agent solicitation (now done!), start of simulation, ...
return (Agent::command(argc, argv));
}
void MIPMHAgent::reg()
{
rtx_timer_.resched(reg_rtx_);
if (agts_ == 0) {
send_sols();
return;
}
if (coa_ < 0) {
coa_ = agts_->node_;
adlftm_ = agts_->lifetime_;
}
Tcl& tcl = Tcl::instance();
Packet *p = allocpkt();
hdr_ip *iph = (hdr_ip *)p->access(off_ip_);
//iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (coa_ & mask_) << shift_;
iph->daddr() = coa_;
iph->dport() = 0;
hdr_mip *h = (hdr_mip *)p->access(off_mip_);
//h->haddr_ = addr_ >> shift_ & mask_;
h->haddr_ = Address::instance().get_nodeaddr(addr());
h->ha_ = ha_;
h->coa_ = coa_;
h->type_ = MIPT_REG_REQUEST;
h->lifetime_ = min(reglftm_, adlftm_);
h->seqno_ = seqno_;
tcl.evalf("%s get-link %d %d", name_, h->haddr_, coa_);
NsObject *target = (NsObject *)tcl.lookup(tcl.result());
if (target != NULL)
((NsObject *)tcl.lookup(tcl.result()))->recv(p, (Handler*) 0);
else
send(p, 0);
}
void MIPMHAgent::send_sols()
{
Packet *p = allocpkt();
hdr_mip *h = (hdr_mip *)p->access(off_mip_);
h->coa_ = -1;
//h->haddr_ = addr_ >> shift_ & mask_;
h->haddr_ = Address::instance().get_nodeaddr(addr());
h->ha_ = ha_;
h->type_ = MIPT_SOL;
h->lifetime_ = reglftm_;
h->seqno_ = seqno_;
sendOutBCastPkt(p);
if (bcast_target_)
bcast_target_->recv(p, (Handler*) 0);
else if (target_)
target_->recv(p, (Handler*) 0);
else
Packet::free(p); // drop; may log in future code
}
void MIPMHAgent::sendOutBCastPkt(Packet *p)
{
hdr_ip *iph = (hdr_ip*)p->access(off_ip_);
hdr_cmn *hdrc = (hdr_cmn *)p->access (off_cmn_);
hdrc->next_hop_ = IP_BROADCAST;
hdrc->addr_type_ = NS_AF_INET;
iph->daddr() = IP_BROADCAST;
iph->dport() = 0;
}
mip.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) Sun Microsystems, Inc. 1998 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 Sun Microsystems, Inc.
*
* 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* SUN MICROSYSTEMS 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.
*/
// #ident "@(#)mip.cc 1.4 98/08/21 SMI"
#include
#include "mip.h"
#define IP_HEADER_SIZE 20
static class IPinIPHeaderClass : public PacketHeaderClass {
public:
IPinIPHeaderClass() : PacketHeaderClass("PacketHeader/IPinIP",
sizeof(hdr_ipinip*)) {
}
} class_ipiniphdr;
static class MIPEncapsulatorClass : public TclClass {
public:
MIPEncapsulatorClass() : TclClass("MIPEncapsulator") {}
TclObject* create(int, const char*const*) {
return (new MIPEncapsulator());
}
} class_mipencapsulator;
MIPEncapsulator::MIPEncapsulator() : Connector(), mask_(0xffffffff),
shift_(8), defttl_(32)
{
bind("addr_", (int*)&(here_.addr_));
bind("port_", (int*)&(here_.port_));
bind("shift_", &shift_);
bind("mask_", &mask_);
bind("off_ip_", &off_ip_);
bind("off_ipinip_", &off_ipinip_);
bind("ttl_", &defttl_);
}
void MIPEncapsulator::recv(Packet* p, Handler *h)
{
Tcl& tcl = Tcl::instance();
hdr_ip* hdr = (hdr_ip*)p->access(off_ip_);
hdr_ipinip **ppinhdr = (hdr_ipinip **)p->access(off_ipinip_);
if (--hdr->ttl_ <= 0) {
/*
* XXX this should be "dropped" somehow. Right now,
* these events aren't traced.
*/
hdr_ipinip *ptr = *ppinhdr, *temp;
while (ptr != NULL) {
temp = ptr;
ptr = ptr->next_;
delete temp;
}
*ppinhdr = NULL;
Packet::free(p);
return;
}
hdr_ipinip *inhdr = new hdr_ipinip;
//int dst = ((hdr->dst() >> shift_) & mask_);
int dst = Address::instance().get_nodeaddr(hdr->daddr());
tcl.evalf("%s tunnel-exit %d", name_, dst);
int te = atoi(tcl.result());
inhdr->next_ = *ppinhdr;
*ppinhdr = inhdr;
inhdr->hdr_ = *hdr;
hdr->saddr() = here_.addr_;
hdr->sport() = here_.port_;
//hdr->dst() = addr_ & ~(~(nsaddr_t)0 << shift_) | (te & mask_) << shift_;;
hdr->daddr() = te;
hdr->dport() = 1;
hdr->ttl() = defttl_;
((hdr_cmn*)p->access(off_cmn_))->size() += IP_HEADER_SIZE;
target_->recv(p,h);
}
static class MIPDecapsulatorClass : public TclClass {
public:
MIPDecapsulatorClass() : TclClass("Classifier/Addr/MIPDecapsulator") {}
TclObject* create(int, const char*const*) {
return (new MIPDecapsulator());
}
} class_mipdecapsulator;
MIPDecapsulator::MIPDecapsulator() : AddressClassifier()
{
//def_target_ = NULL;
bind("off_ipinip_", &off_ipinip_);
bind("off_ip_", &off_ip_);
}
// int MIPDecapsulator::command(int argc, const char*const* argv)
// {
// if (argc == 3) {
// if (strcmp(argv[1], "def-target") == 0) {
// def_target_ = (NsObject *)TclObject::lookup(argv[2]);
// return TCL_OK;
// }
// }
// return (AddressClassifier::command(argc, argv));
// }
void MIPDecapsulator::recv(Packet* p, Handler *h)
{
hdr_ipinip **ppinhdr = (hdr_ipinip **)p->access(off_ipinip_);
// restore inner header
hdr_ip *pouthdr = (hdr_ip *)p->access(off_ip_);
assert(ppinhdr);
hdr_ip *pinhdr = &(*ppinhdr)->hdr_;
*ppinhdr = (*ppinhdr)->next_;
*pouthdr = *pinhdr;
NsObject* link = find(p);
// for mobilenodes use default-target which is probably the
// RA. cannot use node_entry point instead, as hier address
// of MH point to HA. hence hand decapsulated pkt directly
// to RA.
if (link == NULL || pinhdr->ttl_ <= 0) {
/*
* XXX this should be "dropped" somehow. Right now,
* these events aren't traced.
*/
hdr_ipinip *ptr = *ppinhdr, *temp;
while (ptr != NULL) {
temp = ptr;
ptr = ptr->next_;
delete temp;
}
*ppinhdr = NULL;
delete pinhdr;
Packet::free(p);
return;
}
delete pinhdr;
((hdr_cmn*)p->access(off_cmn_))->size() -= IP_HEADER_SIZE;
link->recv(p,h);
}
misc.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.
*
* miscellaneous "ns" commands
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
#include
#include
#ifndef WIN32
#include
#endif
#include
#include "config.h"
#include "scheduler.h"
#include "random.h"
#if defined(HAVE_INT64)
class Add64Command : public TclCommand {
public:
Add64Command() : TclCommand("ns-add64") {}
virtual int command(int argc, const char*const* argv);
};
int Add64Command::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
char res[22]; /* A 64 bit int at most 20 digits */
int64_t d1 = STRTOI64(argv[1], NULL, 0);
int64_t d2 = STRTOI64(argv[2], NULL, 0);
sprintf(res, STRTOI64_FMTSTR, d1+d2);
tcl.resultf("%s", res);
return (TCL_OK);
}
tcl.add_error("ns-add64 requires two arguments.");
return (TCL_ERROR);
}
#endif
class RandomCommand : public TclCommand {
public:
RandomCommand() : TclCommand("ns-random") { }
virtual int command(int argc, const char*const* argv);
};
/*
* ns-random
* ns-random $seed
*/
int RandomCommand::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 1) {
sprintf(tcl.buffer(), "%u", Random::random());
tcl.result(tcl.buffer());
} else if (argc == 2) {
int seed = atoi(argv[1]);
if (seed == 0)
seed = Random::seed_heuristically();
else
Random::seed(seed);
tcl.resultf("%d", seed);
}
return (TCL_OK);
}
extern "C" char version_string[];
class VersionCommand : public TclCommand {
public:
VersionCommand() : TclCommand("ns-version") { }
virtual int command(int, const char*const*) {
Tcl::instance().result(version_string);
return (TCL_OK);
}
};
class TimeAtofCommand : public TclCommand {
public:
TimeAtofCommand() : TclCommand("time_atof") { }
virtual int command(int argc, const char*const* argv) {
if (argc != 2)
return (TCL_ERROR);
char* s = (char*) argv[1];
char wrk[32];
char* cp = wrk;
while (isdigit(*s) || *s == 'e' ||
*s == '+' || *s == '-' || *s == '.')
*cp++ = *s++;
*cp = 0;
double v = atof(wrk);
switch (*s) {
case 'm':
v *= 1e-3;
break;
case 'u':
v *= 1e-6;
break;
case 'n':
v *= 1e-9;
break;
case 'p':
v *= 1e-12;
break;
}
Tcl::instance().resultf("%g", v);
return (TCL_OK);
}
};
void init_misc(void)
{
(void)new VersionCommand;
(void)new RandomCommand;
(void)new TimeAtofCommand;
#if defined(HAVE_INT64)
(void)new Add64Command;
#endif
}
mobilenode.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.
* CMU-Monarch project's Mobility extensions ported by Padma Haldar,
* 11/98.
*/
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
// XXX Must supply the first parameter in the macro otherwise msvc
// is unhappy.
static LIST_HEAD(_dummy_MobileNodeList, MobileNode) nodehead = { 0 };
//static int MobileNodeIndex = 0;
static class MobileNodeClass : public TclClass {
public:
MobileNodeClass() : TclClass("Node/MobileNode") {}
TclObject* create(int, const char*const*) {
return (new MobileNode);
}
} class_mobilenode;
/*
* PositionHandler()
*
* Updates the position of a mobile node every N seconds, where N is
* based upon the speed of the mobile and the resolution of the topography.
*
*/
void
PositionHandler::handle(Event*)
{
Scheduler& s = Scheduler::instance();
#if 0
fprintf(stderr, "*** POSITION HANDLER for node %d (time: %f) ***\n",
node->address(), s.clock());
#endif
/*
* Update current location
*/
node->update_position();
/*
* Choose a new random speed and direction
*/
#ifdef DEBUG
fprintf(stderr, "%d - %s: calling random_destination()\n",
node->address_, __PRETTY_FUNCTION__);
#endif
node->random_destination();
s.schedule(&node->pos_handle, &node->pos_intr,
node->position_update_interval);
}
/* ======================================================================
Mobile Node
====================================================================== */
MobileNode::MobileNode(void) : Node(), pos_handle(this)
#ifdef NAM_TRACE
, namChan_(0)
#endif
{
X = 0.0; Y = 0.0; Z = 0.0; speed = 0.0;
dX=0.0; dY=0.0; dZ=0.0;
destX=0.0; destY=0.0;
// address_ = MobileNodeIndex++;
random_motion_ = 0;
base_stn_ = -1;
T = 0;
position_update_interval = POSITION_UPDATE_INTERVAL;
position_update_time = 0.0;
LIST_INSERT_HEAD(&nodehead, this, link); // node list
LIST_INIT(&ifhead_); // interface list
bind("X_", &X);
bind("Y_", &Y);
bind("Z_", &Z);
bind("speed_", &speed);
// bind("position_update_interval_", &position_update_interval);
}
int
MobileNode::command(int argc, const char*const* argv)
{
if(argc == 2) {
//Tcl& tcl = Tcl::instance();
// if(strcmp(argv[1], "id") == 0) {
// tcl.resultf("%d", address_);
// return TCL_OK;
// }
if(strcmp(argv[1], "start") == 0) {
start();
return TCL_OK;
}
if(strcmp(argv[1], "log-movement") == 0) {
#ifdef DEBUG
fprintf(stderr,
"%d - %s: calling update_position()\n",
address_, __PRETTY_FUNCTION__);
#endif
update_position();
log_movement();
return TCL_OK;
}
if(strcmp(argv[1], "log-energy") == 0) {
log_energy(1);
return TCL_OK;
}
}
else if(argc == 3) {
if(strcmp(argv[1], "radius") == 0) {
radius_ = strtod(argv[2],NULL);
return TCL_OK;
}
if(strcmp(argv[1], "namattach") == 0) {
Tcl& tcl = Tcl::instance();
int mode;
const char* id = argv[2];
namChan_ = Tcl_GetChannel(tcl.interp(), (char*)id,
&mode);
if (namChan_ == 0) {
tcl.resultf("trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
}
if(strcmp(argv[1], "random-motion") == 0) {
random_motion_ = atoi(argv[2]);
return TCL_OK;
}
else if(strcmp(argv[1], "addif") == 0) {
WirelessPhy *n = (WirelessPhy*) TclObject::lookup(argv[2]);
if(n == 0)
return TCL_ERROR;
n->insertnode(&ifhead_);
n->setnode(this);
return TCL_OK;
}
else if(strcmp(argv[1], "topography") == 0) {
T = (Topography*) TclObject::lookup(argv[2]);
if(T == 0)
return TCL_ERROR;
return TCL_OK;
}
else if(strcmp(argv[1], "log-target") == 0) {
log_target = (Trace*) TclObject::lookup(argv[2]);
if(log_target == 0)
return TCL_ERROR;
return TCL_OK;
}
else if (strcmp(argv[1],"base-station") == 0) {
//base_stn_ = (MobileNode*) TclObject::lookup(argv[2]);
base_stn_ = atoi(argv[2]);
if(base_stn_ == -1)
return TCL_ERROR;
return TCL_OK;
}
} else if (argc == 5) {
if (strcmp(argv[1], "setdest") == 0)
{ /* setdest */
#ifdef DEBUG
fprintf(stderr, "%d - %s: calling set_destination()\n",
address_, __FUNCTION__);
#endif
if(set_destination(atof(argv[2]), atof(argv[3]), atof(argv[4])) < 0)
return TCL_ERROR;
return TCL_OK;
}
}
return Node::command(argc, argv);
}
/* ======================================================================
Other class functions
====================================================================== */
void
MobileNode::dump(void)
{
Phy *n;
fprintf(stdout, "Index: %d\n", address_);
fprintf(stdout, "Network Interface List\n");
for(n = ifhead_.lh_first; n; n = n->nextnode() )
n->dump();
fprintf(stdout, "--------------------------------------------------\n");
}
/* ======================================================================
Position Functions
====================================================================== */
void
MobileNode::start()
{
Scheduler& s = Scheduler::instance();
if(random_motion_ == 0) {
log_movement();
return;
}
assert(initialized());
random_position();
#ifdef DEBUG
fprintf(stderr, "%d - %s: calling random_destination()\n",
address_, __PRETTY_FUNCTION__);
#endif
random_destination();
s.schedule(&pos_handle, &pos_intr, position_update_interval);
}
void
MobileNode::log_movement()
{
if (!log_target) return;
Scheduler& s = Scheduler::instance();
sprintf(log_target->buffer(),
"M %.5f %d (%.2f, %.2f, %.2f), (%.2f, %.2f), %.2f",
s.clock(), address_, X, Y, Z, destX, destY, speed);
log_target->dump();
}
void
MobileNode::log_energy(int flag)
{
if(!log_target) return;
Scheduler &s = Scheduler::instance();
if (flag) {
sprintf(log_target->buffer(),"N -t %f -n %d -e %f", s.clock(), address_,energy()); } else {
sprintf(log_target->buffer(),"N -t %f -n %d -e 0 ", s.clock(), address_);
}
log_target->dump();
}
void
MobileNode::idle_energy_patch(float total, float P_idle)
{
float real_idle = total-(total_sndtime_+total_rcvtime_+total_sleeptime_);
//printf("total=%f send=%f rcv=%f, slp=%f\n",total, total_sndtime_,total_rcvtime_,total_sleeptime_);
//printf("real_idle=%f\n",real_idle);
energy_model_-> DecrIdleEnergy(real_idle, P_idle);
//set node energy into zero
if ((this->energy_model())->energy() < 0) {
// saying node died
this->energy_model()->setenergy(0);
this->log_energy(0);
}
}
void
MobileNode::bound_position()
{
double minX;
double maxX;
double minY;
double maxY;
int recheck = 1;
assert(T != 0);
minX = T->lowerX();
maxX = T->upperX();
minY = T->lowerY();
maxY = T->upperY();
while(recheck) {
recheck = 0;
if(X < minX) {
X = minX + (minX - X);
recheck = 1;
}
if(X > maxX) {
X = maxX - (X - maxX);
recheck = 1;
}
if(Y < minY) {
Y = minY + (minY - Y);
recheck = 1;
}
if(Y > maxY) {
Y = maxY- (Y - maxY);
recheck = 1;
}
if(recheck) {
fprintf(stderr, "Adjust position of node %d\n",address_);
}
}
}
int
MobileNode::set_destination(double x, double y, double s)
{
assert(initialized());
if(x >= T->upperX() || x <= T->lowerX())
return -1;
if(y >= T->upperY() || y <= T->lowerY())
return -1;
update_position(); // figure out where we are now
destX = x;
destY = y;
speed = s;
dX = destX - X;
dY = destY - Y;
dZ = 0.0; // this isn't used, since flying isn't allowed
if(destX != X || destY != Y) {
// normalize dx, dy to unit len
double len = sqrt( (dX * dX) + (dY * dY) );
dX /= len;
dY /= len;
}
position_update_time = Scheduler::instance().clock();
#ifdef DEBUG
fprintf(stderr, "%d - %s: calling log_movement()\n", address_, __FUNCTION__);
#endif
log_movement();
/* update gridkeeper */
if (GridKeeper::instance()){
GridKeeper* gp = GridKeeper::instance();
gp-> new_moves(this);
}
#ifdef NAM_TRACE
if (namChan_ != 0) {
sprintf(nwrk_,
"n -t %f -s %d -x %f -y %f -u %f -v %f -T %f",
Scheduler::instance().clock(),
nodeid_,
X,Y,
speed*dX, speed*dY,
((speed*dX) != 0 ) ? (destX-X)/(speed*dX) : speed*dX
);
namdump();
}
#endif
return 0;
}
#ifdef NAM_TRACE
void MobileNode::namdump()
{
int n = 0;
/* Otherwise nwrk_ isn't initialized */
if (namChan_ != 0)
n = strlen(nwrk_);
if ((n > 0) && (namChan_ != 0)) {
/*
* tack on a newline (temporarily) instead
* of doing two writes
*/
nwrk_[n] = '\n';
nwrk_[n + 1] = 0;
(void)Tcl_Write(namChan_, nwrk_, n + 1);
nwrk_[n] = 0;
}
}
#endif
void
MobileNode::update_position()
{
double now = Scheduler::instance().clock();
double interval = now - position_update_time;
if(interval == 0.0)
return;
X += dX * (speed * interval);
Y += dY * (speed * interval);
if ((dX > 0 && X > destX) || (dX < 0 && X < destX))
X = destX; // correct overshoot (slow? XXX)
if ((dY > 0 && Y > destY) || (dY < 0 && Y < destY))
Y = destY; // correct overshoot (slow? XXX)
bound_position();
Z = T->height(X, Y);
#if 0
fprintf(stderr, "Node: %d, X: %6.2f, Y: %6.2f, Z: %6.2f, time: %f\n",
address_, X, Y, Z, now);
#endif
position_update_time = now;
}
void
MobileNode::random_position()
{
if(T == 0) {
fprintf(stderr, "No TOPOLOGY assigned\n");
exit(1);
}
X = Random::uniform() * T->upperX();
Y = Random::uniform() * T->upperY();
Z = T->height(X, Y);
position_update_time = 0.0;
}
void
MobileNode::random_destination()
{
if(T == 0) {
fprintf(stderr, "No TOPOLOGY assigned\n");
exit(1);
}
random_speed();
#ifdef DEBUG
fprintf(stderr, "%d - %s: calling set_destination()\n",
address_, __FUNCTION__);
#endif
(void) set_destination(Random::uniform() * T->upperX(),
Random::uniform() * T->upperY(),
speed);
}
void
MobileNode::random_direction()
{
/* this code isn't used anymore -dam 1/22/98 */
double len;
dX = (double) Random::random();
dY = (double) Random::random();
len = sqrt( (dX * dX) + (dY * dY) );
dX /= len;
dY /= len;
dZ = 0.0; // we're not flying...
/*
* Determine the sign of each component of the
* direction vector.
*/
if(X > (T->upperX() - 2*T->resol())) {
if(dX > 0) dX = -dX;
}
else if(X < (T->lowerX() + 2*T->resol())) {
if(dX < 0) dX = -dX;
}
else if(Random::uniform() <= 0.5) {
dX = -dX;
}
if(Y > (T->upperY() - 2*T->resol())) {
if(dY > 0) dY = -dY;
}
else if(Y < (T->lowerY() + 2*T->resol())) {
if(dY < 0) dY = -dY;
}
else if(Random::uniform() <= 0.5) {
dY = -dY;
}
#if 0
fprintf(stderr, "Location: (%f, %f), Direction: (%f, %f)\n",
X, Y, dX, dY);
#endif
}
void
MobileNode::random_speed()
{
speed = Random::uniform() * MAX_SPEED;
}
double
MobileNode::distance(MobileNode *m)
{
update_position(); // update my position
m->update_position(); // update m's position
double Xpos = (X - m->X) * (X - m->X);
double Ypos = (Y - m->Y) * (Y - m->Y);
double Zpos = (Z - m->Z) * (Z - m->Z);
return sqrt(Xpos + Ypos + Zpos);
}
double
MobileNode::propdelay(MobileNode *m)
{
return distance(m) / SPEED_OF_LIGHT;
}
modulation.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
#include
/* ======================================================================
Binary Phase Shift Keying
====================================================================== */
BPSK::BPSK()
{
Rs = 0;
}
BPSK::BPSK(int S)
{
Rs = S;
}
int
BPSK::BitError(double Pr)
{
double Pe; // probability of error
double x;
int nbit = 0; // number of bit errors tolerated
if(nbit == 0) {
Pe = ProbBitError(Pr);
}
else {
Pe = ProbBitError(Pr, nbit);
}
// quick check
if(Pe == 0.0)
return 0; // no bit errors
// scale the error probabilty
Pe *= 1e3;
x = (double)(((int)Random::uniform()) % 1000);
if(x < Pe)
return 1; // bit error
else
return 0; // no bit errors
}
double
BPSK::ProbBitError(double)
{
double Pe = 0.0;
return Pe;
}
double
BPSK::ProbBitError(double, int)
{
double Pe = 0.0;
return Pe;
}
ms-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
//Measured Sum Admission control
#include "adc.h"
#include
class MS_ADC : public ADC {
public:
MS_ADC();
void rej_action(int, double,int);
protected:
int admit_flow(int,double,int);
inline virtual double get_rate(int /*cl*/, double r,int /*b*/)
{ return r ; };
double utilization_;
};
MS_ADC::MS_ADC()
{
bind("utilization_",&utilization_);
type_ = new char[5];
strcpy(type_, "MSAC");
}
void MS_ADC::rej_action(int cl,double r,int b)
{
double rate = get_rate(cl,r,b);
est_[cl]->change_avload(-rate);
}
int MS_ADC::admit_flow(int cl,double r,int b)
{
double rate = get_rate(cl,r,b);
if (rate+est_[cl]->avload() < utilization_* bandwidth_) {
est_[cl]->change_avload(rate);
return 1;
}
return 0;
}
static class MS_ADCClass : public TclClass {
public:
MS_ADCClass() : TclClass("ADC/MS") {}
TclObject* create(int,const char*const*) {
return (new MS_ADC());
}
}class_ms_adc;
/* a measured sum algorithm that uses peak rather than token rate
*/
class MSPK_ADC : public MS_ADC {
public:
MSPK_ADC() { };
protected:
inline virtual double get_rate(int cl,double r,int b){
return(peak_rate(cl,r,b));};
};
static class MSPK_ADCClass : public TclClass {
public:
MSPK_ADCClass() : TclClass("ADC/MSPK") {}
TclObject* create(int,const char*const*) {
return (new MSPK_ADC());
}
} class_mspk_adc;
net-interface.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* net-interface.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.
*
* Ported by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (USC/ISI)";
#endif
#include "net-interface.h"
int NetworkInterface::command(int argc, const char*const* argv) {
if (argc > 1) {
if (strcmp(argv[1], "label") == 0) {
if (argc == 2) {
Tcl::instance().resultf("%d", intf_label_);
return TCL_OK;
}
if (argc == 3) {
intf_label_ = atoi(argv[2]);
return TCL_OK;
}
}
}
return (Connector::command(argc, argv));
}
void NetworkInterface::recv(Packet* p, Handler* h) {
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
#ifdef LEO_DEBUG
printf("Marking to %d\n", intf_label_);
#endif
ch->iface() = intf_label_;
ch->direction()= hdr_cmn::NONE; //direction: none
send(p, h);
}
static class NetworkInterfaceClass : public TclClass {
public:
NetworkInterfaceClass() : TclClass("NetworkInterface") {}
TclObject* create(int, const char*const*) {
return (new NetworkInterface);
}
} class_networkinterface;
nilist.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.
*/
#include
/*#include */
#include "nilist.h"
template
T Slist::get()
{
Tlink* lnk = (Tlink*) slist_base::get();
T i = lnk->info;
delete lnk;
return i;
}
void slist_base::insert(slink *a)
{
count_++;
if (last_)
a->next_ = last_->next_;
else
last_ = a;
last_->next_ = a;
}
#include
void slist_base::remove(slink *a, slink *prev)
{
remove_count_++; /* XXX */
count_--;
if (prev && prev->next_ != a)
printf("In remove(): Error: prev->next!=a prev=%p a=%p\n", prev, a);
if (last_ == NULL)
return;
if (prev == NULL)
if (last_->next_ == a)
prev = last_;
else
return;
prev->next_ = a->next_;
if (last_ == a) // a was last in list
last_ = prev;
if (last_->next_ == a) // a was only one in list
last_ = NULL;
}
void slist_base::append(slink *a)
{
append_count_++; /* XXX */
count_++;
if (last_) {
a->next_ = last_->next_;
last_ = last_->next_ = a;
}
else
last_ = a->next_ = a;
}
slink *slist_base::get()
{
count_--;
if (last_ == 0) return NULL;
slink * f = last_->next_;
if (f == last_)
last_ = 0;
else
last_->next_ = f->next_;
return f;
}
slink *slist_base::find(int key)
{
slink *cur = last_;
if (last_ == 0) return NULL;
do {
cur = cur->next_;
if (cur->key_ == key)
return cur;
} while (cur != last_);
return NULL;
}
slist_base_iter::slist_base_iter(slist_base &s)
{
cs = &s;
ce = cs->last_;
}
slink *
slist_base_iter::operator() ()
// return 0 to indicate end of iteration
{
slink *ret = ce ? (ce=ce->next_) : 0;
if (ce == cs->last_) ce = 0;
return ret;
}
template T* Slist_iter::operator() ()
{
Tlink *lnk = (Tlink *) slist_base_iter::operator() ();
return lnk ? &lnk->info : 0;
}
node.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.
* CMU-Monarch project's Mobility extensions ported by Padma Haldar,
* 10/98.
*
* $Header$
*/
#include
#include
#include
#include
#include
static class LinkHeadClass : public TclClass {
public:
LinkHeadClass() : TclClass("Connector/LinkHead") {}
TclObject* create(int, const char*const*) {
return (new LinkHead);
}
} class_link_head;
LinkHead::LinkHead() : net_if_(0), node_(0), type_(0) { }
int32_t LinkHead::label() {
if (net_if_)
return net_if_->intf_label();
printf("Configuration error: Network Interface missing\n");
exit(1);
// Make msvc happy
return 0;
}
int LinkHead::command(int argc, const char*const* argv)
{
//Tcl& tcl = Tcl::instance();
if (argc == 2) {
} else if (argc == 3) {
if(strcmp(argv[1], "setnetinf") == 0) {
net_if_ =
(NetworkInterface*) TclObject::lookup(argv[2]);
if (net_if_ == 0)
return TCL_ERROR;
return TCL_OK;
} else if(strcmp(argv[1], "setnode") == 0) {
node_ = (Node*) TclObject::lookup(argv[2]);
if (node_ == 0)
return TCL_ERROR;
return TCL_OK;
}
}
return (Connector::command(argc, argv));
}
static class NodeClass : public TclClass {
public:
NodeClass() : TclClass("Node") {}
TclObject* create(int, const char*const*) {
return (new Node);
}
} class_node;
struct node_head Node::nodehead_ = { 0 }; // replaces LIST_INIT macro
Node::Node(void) : address_(-1), energy_model_(NULL), sleep_mode_(0), total_sleeptime_(0),
total_rcvtime_(0), total_sndtime_(0), adaptivefidelity_(0),
powersavingflag_(0), namDefinedFlag_(0), last_time_gosleep(0),max_inroute_time_(300),
maxttl_(5)
{
LIST_INIT(&ifhead_);
LIST_INIT(&linklisthead_);
insert(&(Node::nodehead_)); // insert self into static list of nodes
neighbor_list.neighbor_cnt_ = 0;
neighbor_list.head = NULL;
}
Node::~Node()
{
LIST_REMOVE(this, entry);
}
int
Node::command(int argc, const char*const* argv)
{
if (argc == 2) {
Tcl& tcl = Tcl::instance();
if(strcmp(argv[1], "address?") == 0) {
tcl.resultf("%d", address_);
return TCL_OK;
} else if(strcmp(argv[1], "powersaving") == 0) {
powersavingflag_ = 1;
start_powersaving();
return TCL_OK;
} else if(strcmp(argv[1], "adaptivefidelity") == 0) {
adaptivefidelity_ = 1;
powersavingflag_ = 1;
start_powersaving();
return TCL_OK;
} else if(strcmp(argv[1], "namDefined") == 0) {
namDefinedFlag_ = 1;
return TCL_OK;
} else if (strcmp(argv[1], "energy") == 0) {
Tcl& tcl = Tcl::instance();
tcl.resultf("%f",this->energy());
return TCL_OK;
} else if (strcmp(argv[1], "adjustenergy") == 0) {
// assume every 10 sec schedule and 1.15 W
// idle energy consumption. needs to be
// parameterized.
idle_energy_patch(10, 1.15);
total_sndtime_ = 0;
total_rcvtime_ = 0;
total_sleeptime_ = 0;
return TCL_OK;
}
}
if (argc == 3) {
if(strcmp(argv[1], "addif") == 0) {
WiredPhy* phyp = (WiredPhy*) TclObject::lookup(argv[2]);
if(phyp == 0)
return TCL_ERROR;
phyp->insertnode(&ifhead_);
phyp->setnode(this);
return TCL_OK;
} else if (strcmp(argv[1], "addr") == 0) {
address_ = Address::instance().\
str2addr(argv[2]);
return TCL_OK;
} else if (strcmp(argv[1], "nodeid") == 0) {
nodeid_ = atoi(argv[2]);
return TCL_OK;
} else if (strcmp(argv[1], "addenergymodel") == 0) {
energy_model_ = (EnergyModel *) TclObject::lookup(argv[2]);
if(!energy_model_)
return TCL_ERROR;
return TCL_OK;
} else if(strcmp(argv[1], "addlinkhead") == 0) {
LinkHead* slhp = (LinkHead*) TclObject::lookup(argv[2]);
if (slhp == 0)
return TCL_ERROR;
slhp->insertlink(&linklisthead_);
return TCL_OK;
} else if (strcmp(argv[1], "setsleeptime") == 0) {
afe_->set_sleeptime(atof(argv[2]));
afe_->set_sleepseed(atof(argv[2]));
return TCL_OK;
} else if (strcmp(argv[1], "setenergy") == 0) {
energy_model_->setenergy(atof(argv[2]));
return TCL_OK;
} else if (strcmp(argv[1], "settalive") == 0) {
max_inroute_time_ = atof(argv[2]);
return TCL_OK;
} else if (strcmp(argv[1], "maxttl") == 0) {
maxttl_ = atoi(argv[2]);
return TCL_OK;
}
}
if (argc == 4) {
if(strcmp(argv[1], "idleenergy") == 0) {
this->idle_energy_patch(atof(argv[2]),atof(argv[3]));
return TCL_OK;
}
}
return TclObject::command(argc,argv);
}
// Given an interface label for a NetworkInterface on this node, we return
// the head of that link
NsObject* Node::intf_to_target(int32_t label)
{
LinkHead *lhp = linklisthead_.lh_first;
for (; lhp; lhp = lhp->nextlinkhead())
if (label == lhp->label())
return ((NsObject*) lhp);
return NULL;
}
void
Node::start_powersaving()
{
snh_ = new SoftNeighborHandler(this);
snh_->start();
afe_ = new AdaptiveFidelityEntity(this);
afe_->start();
state_ = POWERSAVING_STATE;
state_start_time_ = Scheduler::instance().clock();
}
void
Node::set_node_sleep(int status)
{
Tcl& tcl=Tcl::instance();
//static float last_time_gosleep;
// status = 1 to set node into sleep mode
// status = 0 to put node back to idel mode.
// time in the sleep mode should be used as credit to idle time energy consumption
if (status) {
last_time_gosleep = Scheduler::instance().clock();
//printf("id=%d : put node into sleep at %f\n",address_,last_time_gosleep);
sleep_mode_ = status;
if (namDefinedFlag_) tcl.evalf("%s add-mark m1 blue hexagon",name());
} else {
sleep_mode_ = status;
if (namDefinedFlag_) tcl.evalf("%s delete-mark m1",name());
//printf("id= %d last_time_sleep = %f\n",address_,last_time_gosleep);
if (last_time_gosleep) {
total_sleeptime_ += Scheduler::instance().clock()-last_time_gosleep;
last_time_gosleep = 0;
}
}
}
void
Node::set_node_state(int state)
{
switch (state_) {
case POWERSAVING_STATE:
case WAITING:
state_ = state;
state_start_time_ = Scheduler::instance().clock();
break;
case INROUTE:
if (state == POWERSAVING_STATE) {
state_ = state;
}
if (state == INROUTE) {
// a data packet is forwarded, needs to reset state_start_time_
state_start_time_= Scheduler::instance().clock();
}
break;
default:
printf("Wrong state, quit...\n");
exit(1);
}
}
void
Node::idle_energy_patch(float /*total*/, float /*P_idle*/)
{
/*
float real_idle = total-(total_sndtime_+total_rcvtime_+total_sleeptime_);
//printf("real_idle=%f\n",real_idle);
energy_model_-> DecrIdleEnergy(real_idle, P_idle);
//set node energy into zero
if ((this->energy_model())->energy() <= 0) {
// saying node died
this->energy_model()->setenergy(0);
this->log_energy(0);
}
*/
}
void
Node::add_neighbor(u_int32_t nodeid)
{
neighbor_list_item *np;
np = neighbor_list.head;
for (; np; np = np->next) {
if (np->id == nodeid) {
np->ttl = maxttl_;
break;
}
}
if (!np) { // insert this new entry
np = new neighbor_list_item;
np->id = nodeid;
np->ttl = maxttl_;
np->next = neighbor_list.head;
neighbor_list.head = np;
neighbor_list.neighbor_cnt_++;
}
}
void
Node::scan_neighbor()
{
neighbor_list_item *np, *lp;
if (neighbor_list.neighbor_cnt_ > 0) {
lp = neighbor_list.head;
np = lp->next;
for (; np; np = np->next) {
np->ttl--;
if (np->ttl <= 0){
lp->next = np->next;
delete np;
np = lp;
neighbor_list.neighbor_cnt_--;
}
lp = np;
}
// process the first element
np = neighbor_list.head;
np->ttl--;
if (np->ttl <= 0) {
neighbor_list.head = np->next;
delete np;
neighbor_list.neighbor_cnt_--;
}
}
}
void
SoftNeighborHandler::start()
{
Scheduler &s = Scheduler::instance();
s.schedule(this, &intr, CHECKFREQ);
}
void
SoftNeighborHandler::handle(Event *)
{
Scheduler &s = Scheduler::instance();
nid_->scan_neighbor();
s.schedule(this, &intr, CHECKFREQ);
}
void
AdaptiveFidelityEntity::start()
{
float start_idletime;
Scheduler &s = Scheduler::instance();
sleep_time_ = 2;
sleep_seed_ = 2;
idle_time_ = 10;
start_idletime = Random::uniform(0, idle_time_);
//printf("node id_ = %d starttime=%f\n", nid_, start_idletime);
nid_->set_node_sleep(0);
s.schedule(this, &intr, start_idletime);
}
void
AdaptiveFidelityEntity::handle(Event *)
{
Scheduler &s = Scheduler::instance();
int node_state = nid_->state();
//printf("Node %d at State %d at time %f is in sleep %d \n", nid_->address(), node_state, s.clock(), nid_->sleep());
//printf("node id = %d: sleep_time=%f\n",nid_->address(),sleep_time_);
switch (node_state) {
case POWERSAVING_STATE:
if (nid_->sleep()) {
// node is in sleep mode, wake it up
nid_->set_node_sleep(0);
adapt_it();
s.schedule(this, &intr, idle_time_);
} else {
// node is in idle mode, put it into sleep
nid_->set_node_sleep(1);
adapt_it();
s.schedule(this, &intr, sleep_time_);
}
break;
case INROUTE:
// 100s is the maximum INROUTE time.
if (s.clock()-(nid_->state_start_time()) < nid_->max_inroute_time()) {
s.schedule(this, &intr, idle_time_);
} else {
nid_->set_node_state(POWERSAVING_STATE);
adapt_it();
nid_->set_node_sleep(1);
s.schedule(this, &intr, sleep_time_);
}
break;
case WAITING:
// 10s is the maximum WAITING time
if (s.clock()-(nid_->state_start_time()) < MAX_WAITING_TIME) {
s.schedule(this, &intr, idle_time_);
} else {
nid_->set_node_state(POWERSAVING_STATE);
adapt_it();
nid_->set_node_sleep(1);
s.schedule(this, &intr, sleep_time_);
}
break;
default:
fprintf(stderr, "Illegal Node State!");
abort();
}
}
void
AdaptiveFidelityEntity::adapt_it()
{
float delay;
// use adaptive fidelity
if (nid_->adaptivefidelity()) {
int neighbors = nid_->getneighbors();
if (!neighbors) neighbors=1;
delay = sleep_seed_*Random::uniform(1,neighbors);
this->set_sleeptime(delay);
}
}
// return the node instance from the static node list
Node * Node::get_node_by_address (nsaddr_t id)
{
Node * tnode = nodehead_.lh_first;
for (; tnode; tnode = tnode->nextnode()) {
if (tnode->address_ == id ) {
return (tnode);
}
}
return NULL;
}
#ifdef zero
static class HierNodeClass : public TclClass {
public:
HierNodeClass() : TclClass("HierNode") {}
TclObject* create(int, const char*const*) {
return (new HierNode);
}
} class_hier_node;
static class ManualRtNodeClass : public TclClass {
public:
ManualRtNodeClass() : TclClass("ManualRtNode") {}
TclObject* create(int, const char*const*) {
return (new ManualRtNode);
}
} class_ManualRt_node;
static class VirtualClassifierNodeClass : public TclClass {
public:
VirtualClassifierNodeClass() : TclClass("VirtualClassifierNode") {}
TclObject* create(int, const char*const*) {
return (new VirtualClassifierNode);
}
} class_VirtualClassifier_node;
#endif
ns-process.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
//
// Copyright (c) 1997 by the University of Southern California
// All rights reserved.
//
// Permission to use, copy, modify, and distribute this software and its
// documentation in source and binary forms for non-commercial purposes
// and without fee is hereby granted, provided that the above copyright
// notice appear in all copies and that both the copyright notice and
// this permission notice appear in supporting documentation. 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.
//
// THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
// the suitability of this software for any purpose. 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.
//
// ADU and ADU processor
//
// $Header$
#include "ns-process.h"
static class ProcessClass : public TclClass {
public:
ProcessClass() : TclClass("Process") {}
TclObject* create(int, const char*const*) {
return (new Process);
}
} class_process;
void Process::process_data(int, AppData*)
{
abort();
}
AppData* Process::get_data(int&, AppData*)
{
abort();
/* NOTREACHED */
return NULL; // Make msvc happy
}
int Process::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (strcmp(argv[1], "target") == 0) {
if (argc == 2) {
tcl.resultf("%s", target()->name());
return TCL_OK;
} else if (argc == 3) {
Process *p = (Process *)TclObject::lookup(argv[2]);
if (p == NULL) {
fprintf(stderr, "Non-existent media app %s\n",
argv[2]);
abort();
}
target() = p;
return TCL_OK;
}
}
return TclObject::command(argc, argv);
}
ns_tclsh.cc
/*
*
* Provides a default version of the Tcl_AppInit procedure for
* use in wish and similar Tk-based applications.
*
* Copyright (c) 1993 The Regents of the University of California.
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include
#include "config.h"
extern init_misc();
extern "C" {
int
Tcl_AppInit(Tcl_Interp *interp)
{
if (Tcl_Init(interp) == TCL_ERROR ||
Otcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
Tcl_SetVar(interp, "tcl_rcFileName", "~/.ns.tcl", TCL_GLOBAL_ONLY);
Tcl::init(interp, "ns");
extern EmbeddedTcl et_ns_lib;
et_ns_lib.load();
init_misc();
return (TCL_OK);
}
int
main(int argc, char** argv)
{
Tcl_Main(argc, argv, Tcl_AppInit);
return 0; /* Needed only to prevent compiler warning. */
}
}
null-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
/* Dummy estimator that only measures actual utilization */
#include
#include "estimator.h"
class Null_Est : public Estimator {
public:
Null_Est();
protected:
void estimate();
};
Null_Est::Null_Est()
{
}
void Null_Est::estimate() {
measload_ = meas_mod_->bitcnt()/period_;
meas_mod_->resetbitcnt();
}
static class Null_EstClass : public TclClass {
public:
Null_EstClass() : TclClass ("Est/Null") {}
TclObject* create(int,const char*const*) {
return (new Null_Est());
}
}class_null_est;
object.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
#include "object.h"
#include "packet.h"
#include "flags.h"
NsObject::~NsObject()
{
}
NsObject::NsObject()
{
#ifdef OFF_HDR
#else
off_cmn_ = hdr_cmn::offset();
off_flags_ = hdr_flags::offset();
#endif
// Turn off debug by default
debug_ = 0;
}
void
NsObject::delay_bind_init_all()
{
#ifdef OFF_HDR
delay_bind_init_one("off_cmn_");
delay_bind_init_one("off_flags_");
#endif
delay_bind_init_one("debug_");
}
int
NsObject::delay_bind_dispatch(const char *varName, const char *localName, TclObject *tracer)
{
#ifdef OFF_HDR
if (delay_bind(varName, localName, "off_cmn_", &off_cmn_, tracer))
return TCL_OK;
if (delay_bind(varName, localName, "off_flags_", &off_flags_, tracer))
return TCL_OK;
#endif
if (delay_bind_bool(varName, localName, "debug_", &debug_, tracer))
return TCL_OK;
return TclObject::delay_bind_dispatch(varName, localName, tracer);
}
void NsObject::reset()
{
}
int NsObject::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "reset") == 0) {
reset();
return (TCL_OK);
}
}
return (TclObject::command(argc, argv));
}
/*
* Packets may be handed to NsObjects at sheduled points
* in time since a node is an event handler and a packet
* is an event. Packets should be the only type of event
* scheduled on a node so we can carry out the cast below.
*/
void NsObject::handle(Event* e)
{
recv((Packet*)e);
}
void NsObject::recv(Packet *p, const char*)
{
Packet::free(p);
}
// Debugging output for all TclObjects. By default, print to stdout
void NsObject::debug(const char *fmt, ...)
{
if (!debug_)
return;
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
}
omni-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 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.
* Ported from CMU/Monarch's code, nov'98 -Padma.
omni-antenna.cc
$Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $
*/
#include
static class OmniAntennaClass : public TclClass {
public:
OmniAntennaClass() : TclClass("Antenna/OmniAntenna") {}
TclObject* create(int, const char*const*) {
return (new OmniAntenna);
}
} class_OmniAntenna;
OmniAntenna::OmniAntenna() {
Gt_ = 1.0;
Gr_ = 1.0;
bind("Gt_", &Gt_);
bind("Gr_", &Gr_);
}
packet.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 "packet.h"
#include "flags.h"
p_info packet_info;
char* p_info::name_[PT_NTYPE+1];
int Packet::hdrlen_ = 0; // size of a packet's header
Packet* Packet::free_; // free list
int hdr_cmn::offset_; // static offset of common header
int hdr_flags::offset_; // static offset of flags header
PacketHeaderClass::PacketHeaderClass(const char* classname, int hdrlen) :
TclClass(classname), hdrlen_(hdrlen), offset_(0)
{
}
TclObject* PacketHeaderClass::create(int, const char*const*)
{
return (0);
}
void PacketHeaderClass::bind()
{
TclClass::bind();
Tcl& tcl = Tcl::instance();
tcl.evalf("%s set hdrlen_ %d", classname_, hdrlen_);
export_offsets();
add_method("offset");
}
void PacketHeaderClass::export_offsets()
{
}
void PacketHeaderClass::field_offset(const char* fieldname, int offset)
{
Tcl& tcl = Tcl::instance();
tcl.evalf("%s set offset_(%s) %d", classname_, fieldname, offset);
}
int PacketHeaderClass::method(int ac, const char*const* av)
{
Tcl& tcl = Tcl::instance();
int argc = ac - 2;
const char*const* argv = av + 2;
if (argc == 3) {
if (strcmp(argv[1], "offset") == 0) {
if (offset_) {
*offset_ = atoi(argv[2]);
return TCL_OK;
}
tcl.resultf("Warning: cannot set offset_ for %s",
classname_);
return TCL_OK;
}
}
else if (argc == 2) {
if (strcmp(argv[1], "offset") == 0) {
if (offset_) {
tcl.resultf("%d", *offset_);
return TCL_OK;
}
}
}
return TclClass::method(argc, argv);
}
class CommonHeaderClass : public PacketHeaderClass {
public:
CommonHeaderClass() : PacketHeaderClass("PacketHeader/Common",
sizeof(hdr_cmn)) {
bind_offset(&hdr_cmn::offset_);
}
void export_offsets() {
field_offset("ptype_", OFFSET(hdr_cmn, ptype_));
field_offset("size_", OFFSET(hdr_cmn, size_));
field_offset("uid_", OFFSET(hdr_cmn, uid_));
field_offset("error_", OFFSET(hdr_cmn, error_));
};
} class_cmnhdr;
class FlagsHeaderClass : public PacketHeaderClass {
public:
FlagsHeaderClass() : PacketHeaderClass("PacketHeader/Flags",
sizeof(hdr_flags)) {
bind_offset(&hdr_flags::offset_);
}
} class_flagshdr;
/* manages active packet header types */
class PacketHeaderManager : public TclObject {
public:
PacketHeaderManager() {
bind("hdrlen_", &Packet::hdrlen_);
}
};
static class PacketHeaderManagerClass : public TclClass {
public:
PacketHeaderManagerClass() : TclClass("PacketHeaderManager") {}
TclObject* create(int, const char*const*) {
return (new PacketHeaderManager);
}
} class_packethdr_mgr;
param-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
/* Parameter-based admission control. Admission decisions are
* based on the sum of reserved rates.
*/
#include "adc.h"
#include
class Param_ADC : public ADC {
public:
Param_ADC();
void teardown_action(int,double,int);
void rej_action(int,double,int);
void trace(TracedVar* v);
protected:
int admit_flow(int,double,int);
double utilization_;
TracedDouble resv_rate_;
double oresv_rate_;
};
Param_ADC::Param_ADC() : resv_rate_(0), oresv_rate_(0)
{
bind("utilization_",&utilization_);
type_ = new char[5];
strcpy(type_, "PBAC");
resv_rate_.tracer(this);
resv_rate_.name("\"Reserved Rate\"");
}
void Param_ADC::rej_action(int /*cl*/,double p,int /*r*/)
{
resv_rate_-=p;
}
void Param_ADC::teardown_action(int /*cl*/,double p,int /*r*/)
{
resv_rate_-=p;
}
int Param_ADC::admit_flow(int /*cl*/,double r,int /*b*/)
{
if (resv_rate_ + r <= utilization_ * bandwidth_) {
resv_rate_ +=r;
return 1;
}
return 0;
}
static class Param_ADCClass : public TclClass {
public:
Param_ADCClass() : TclClass("ADC/Param") {}
TclObject* create(int,const char*const*) {
return (new Param_ADC());
}
}class_param_adc;
void Param_ADC::trace(TracedVar* v)
{
char wrk[500];
double *p, newval;
/* check for right variable */
if (strcmp(v->name(), "\"Reserved Rate\"") == 0) {
p = &oresv_rate_;
}
else {
fprintf(stderr, "PBAC: 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_, type_, 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;
}
pareto.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 "random.h"
#include "trafgen.h"
/* implement an on/off source with average on and off times taken
* from a pareto distribution. (enough of these sources multiplexed
* produces aggregate traffic that is LRD). It is parameterized
* by the average burst time, average idle time, burst rate, and
* pareto shape parameter and packet size.
*/
class POO_Traffic : public TrafficGenerator {
public:
POO_Traffic();
virtual double next_interval(int&);
int on() { return on_ ; }
protected:
void init();
double ontime_; /* average length of burst (sec) */
double offtime_; /* average idle period (sec) */
double rate_; /* send rate during burst (bps) */
double interval_; /* inter-packet time at burst rate */
double burstlen_; /* average # packets/burst */
double shape_; /* pareto shape parameter */
unsigned int rem_; /* number of packets remaining in current burst */
double p1_; /* parameter for pareto distribution to compute
* number of packets in burst.
*/
double p2_; /* parameter for pareto distribution to compute
* length of idle period.
*/
int on_; /* denotes whether in the on or off state */
};
static class POOTrafficClass : public TclClass {
public:
POOTrafficClass() : TclClass("Application/Traffic/Pareto") {}
TclObject* create(int, const char*const*) {
return (new POO_Traffic());
}
} class_poo_traffic;
POO_Traffic::POO_Traffic()
{
bind_time("burst_time_", &ontime_);
bind_time("idle_time_", &offtime_);
bind_bw("rate_", &rate_);
bind("shape_", &shape_);
bind("packetSize_", &size_);
}
void POO_Traffic::init()
{
interval_ = (double)(size_ << 3)/(double)rate_;
burstlen_ = ontime_/interval_;
rem_ = 0;
on_ = 0;
p1_ = burstlen_ * (shape_ - 1.0)/shape_;
p2_ = offtime_ * (shape_ - 1.0)/shape_;
if (agent_)
agent_->set_pkttype(PT_PARETO);
}
double POO_Traffic::next_interval(int& size)
{
double t = interval_;
on_ = 1;
if (rem_ == 0) {
/* compute number of packets in next burst */
rem_ = int(Random::pareto(p1_, shape_) + .5);
/* make sure we got at least 1 */
if (rem_ == 0)
rem_ = 1;
/* start of an idle period, compute idle time */
t += Random::pareto(p2_, shape_);
on_ = 0;
}
rem_--;
size = size_;
return(t);
}
phy.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.
*
* @(#) $Header:
*
* Ported from CMU/Monarch's code, nov'98 -Padma Haldar.
* phy.cc
*/
#include
#include "config.h"
#include
#include
#include
class Mac;
static int InterfaceIndex = 0;
Phy::Phy() : BiConnector() {
index_ = InterfaceIndex++;
bandwidth_ = 0.0;
channel_ = 0;
node_ = 0;
head_ = 0;
}
int
Phy::command(int argc, const char*const* argv) {
if (argc == 2) {
Tcl& tcl = Tcl::instance();
if(strcmp(argv[1], "id") == 0) {
tcl.resultf("%d", index_);
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) {
assert(channel_ == 0);
channel_ = (Channel*) obj;
downtarget_ = (NsObject*) obj;
// LIST_INSERT_HEAD() is done by Channel
return TCL_OK;
}
else if (strcmp(argv[1], "node") == 0) {
assert(node_ == 0);
node_ = (Node*) obj;
// LIST_INSERT_HEAD() is done by Node
return TCL_OK;
}
else if (strcmp(argv[1], "linkhead") == 0) {
head_ = (LinkHead*) obj;
return (TCL_OK);
}
}
return BiConnector::command(argc, argv);
}
void
Phy::recv(Packet* p, Handler*)
{
struct hdr_cmn *hdr = HDR_CMN(p);
//struct hdr_sr *hsr = HDR_SR(p);
/*
* Handle outgoing packets
*/
switch(hdr->direction()) {
case hdr_cmn::DOWN :
/*
* The MAC schedules its own EOT event so we just
* ignore the handler here. It's only purpose
* it distinguishing between incoming and outgoing
* packets.
*/
sendDown(p);
return;
case hdr_cmn::UP :
if (sendUp(p) == 0) {
/*
* XXX - This packet, even though not detected,
* contributes to the Noise floor and hence
* may affect the reception of other packets.
*/
Packet::free(p);
return;
} else {
uptarget_->recv(p, (Handler*) 0);
}
break;
default:
printf("Direction for pkt-flow not specified; Sending pkt up the stack on default.\n\n");
if (sendUp(p) == 0) {
/*
* XXX - This packet, even though not detected,
* contributes to the Noise floor and hence
* may affect the reception of other packets.
*/
Packet::free(p);
return;
} else {
uptarget_->recv(p, (Handler*) 0);
}
}
}
/* NOTE: this might not be the best way to structure the relation
between the actual interfaces subclassed from net-if(phy) and
net-if(phy).
It's fine for now, but if we were to decide to have the interfaces
themselves properly handle multiple incoming packets (they currently
require assistance from the mac layer to do this), then it's not as
generic as I'd like. The way it is now, each interface will have to
have it's own logic to keep track of the packets that are arriving.
Seems like this is general service that net-if could provide.
Ok. A fair amount of restructuring is going to have to happen here
when/if net-if keep track of the noise floor at their location. I'm
gonna punt on it for now.
Actually, this may be all wrong. Perhaps we should keep a separate
noise floor per antenna, which would mean the particular interface types
would have to track noise floor themselves, since only they know what
kind of antenna diversity they have. -dam 8/7/98 */
// double
// Phy::txtime(Packet *p) const
// {
// hdr_cmn *hdr = HDR_CMN(p);
// return hdr->size() * 8.0 / Rb_;
// }
void
Phy::dump(void) const
{
fprintf(stdout, "\tINDEX: %d\n",
index_);
fprintf(stdout, "\tuptarget: %x, channel: %x",
(u_int32_t) uptarget_, (u_int32_t) channel_);
}
ping.cc
/*
* File: Code for a new 'Ping' Agent Class for the ns
* network simulator
* Author: Marc Greis (greis@cs.uni-bonn.de), May 1998
*
* IMPORTANT: Incase of any changes made to this file ,
* tutorial/examples/ping.cc file (used in Greis' tutorial) should
* be updated as well.
*/
#include "ping.h"
static class PingHeaderClass : public PacketHeaderClass {
public:
PingHeaderClass() : PacketHeaderClass("PacketHeader/Ping",
sizeof(hdr_ping)) {}
} class_pinghdr;
static class PingClass : public TclClass {
public:
PingClass() : TclClass("Agent/Ping") {}
TclObject* create(int, const char*const*) {
return (new PingAgent());
}
} class_ping;
PingAgent::PingAgent() : Agent(PT_PING)
{
bind("packetSize_", &size_);
bind("off_ping_", &off_ping_);
}
int PingAgent::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "send") == 0) {
// Create a new packet
Packet* pkt = allocpkt();
// Access the Ping header for the new packet:
hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_);
// Set the 'ret' field to 0, so the receiving node knows
// that it has to generate an echo packet
hdr->ret = 0;
// Store the current time in the 'send_time' field
hdr->send_time = Scheduler::instance().clock();
// Send the packet
send(pkt, 0);
// return TCL_OK, so the calling function knows that the
// command has been processed
return (TCL_OK);
}
}
// If the command hasn't been processed by PingAgent()::command,
// call the command() function for the base class
return (Agent::command(argc, argv));
}
void PingAgent::recv(Packet* pkt, Handler*)
{
// Access the IP header for the received packet:
hdr_ip* hdrip = (hdr_ip*)pkt->access(off_ip_);
// Access the Ping header for the received packet:
hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_);
// Is the 'ret' field = 0 (i.e. the receiving node is being pinged)?
if (hdr->ret == 0) {
// Send an 'echo'. First save the old packet's send_time
double stime = hdr->send_time;
// Discard the packet
Packet::free(pkt);
// Create a new packet
Packet* pktret = allocpkt();
// Access the Ping header for the new packet:
hdr_ping* hdrret = (hdr_ping*)pktret->access(off_ping_);
// Set the 'ret' field to 1, so the receiver won't send another echo
hdrret->ret = 1;
// Set the send_time field to the correct value
hdrret->send_time = stime;
// Send the packet
send(pktret, 0);
} else {
// A packet was received. Use tcl.eval to call the Tcl
// interpreter with the ping results.
// Note: In the Tcl code, a procedure 'Agent/Ping recv {from rtt}'
// has to be defined which allows the user to react to the ping
// result.
char out[100];
// Prepare the output to the Tcl interpreter. Calculate the round
// trip time
sprintf(out, "%s recv %d %3.1f", name(),
hdrip->src_.addr_ >> Address::instance().NodeShift_[1],
(Scheduler::instance().clock()-hdr->send_time) * 1000);
Tcl& tcl = Tcl::instance();
tcl.eval(out);
// Discard the packet
Packet::free(pkt);
}
}
pkt-counter.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* pkt-counter.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.
*
* Ported by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang
*
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (USC/ISI)";
#endif
#include "connector.h"
class PktCounter : public Connector {
public:
PktCounter() : count_(0) {
}
int command(int argc, const char*const* argv);
void recv(Packet* pkt, Handler* h) {
count_++;
send(pkt, h);
}
protected:
int count_;
};
static class PktCounterClass : public TclClass {
public:
PktCounterClass() : TclClass("PktCounter") {}
TclObject* create(int, const char*const*) {
return (new PktCounter);
}
} class_pktcounter;
int PktCounter::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "reset") == 0) {
count_ = 0;
return (TCL_OK);
}
if (strcmp(argv[1], "value") == 0) {
Tcl& tcl = Tcl::instance();
tcl.resultf("%d", count_);
return (TCL_OK);
}
}
return (Connector::command(argc, argv));
}
pointsample-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 "estimator.h"
#include
#include
class PointSample_Est : public Estimator {
public:
PointSample_Est() {};
protected:
void estimate();
};
void PointSample_Est::estimate()
{
avload_=meas_mod_->bitcnt()/period_;
//printf("%f %f\n",Scheduler::instance().clock(),avload_);
fflush(stdout);
meas_mod_->resetbitcnt();
}
static class PointSample_EstClass : public TclClass {
public:
PointSample_EstClass() : TclClass ("Est/PointSample") {}
TclObject* create(int,const char*const*) {
return (new PointSample_Est());
}
}class_pointsample_est;
priqueue.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.*/
/* -*- c++ -*-
priqueue.cc
A simple priority queue with a remove packet function
$Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $
*/
#include
#include
#include
#include
//#include
#include "priqueue.h"
typedef int (*PacketFilter)(Packet *, void *);
PriQueue_List PriQueue::prhead = { 0 };
static class PriQueueClass : public TclClass {
public:
PriQueueClass() : TclClass("Queue/DropTail/PriQueue") {}
TclObject* create(int, const char*const*) {
return (new PriQueue);
}
} class_PriQueue;
PriQueue::PriQueue() : DropTail()
{
bind("Prefer_Routing_Protocols", &Prefer_Routing_Protocols);
LIST_INSERT_HEAD(&prhead, this, link);
}
int
PriQueue::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 DropTail::command(argc, argv);
}
void
PriQueue::recv(Packet *p, Handler *h)
{
struct hdr_cmn *ch = HDR_CMN(p);
if(Prefer_Routing_Protocols) {
switch(ch->ptype()) {
case PT_DSR:
case PT_MESSAGE:
case PT_TORA:
case PT_AODV:
recvHighPriority(p, h);
break;
default:
Queue::recv(p, h);
}
}
else {
Queue::recv(p, h);
}
}
void
PriQueue::recvHighPriority(Packet *p, Handler *)
// insert packet at front of queue
{
q_->enqueHead(p);
if (q_->length() >= qlim_)
{
Packet *to_drop = q_->lookup(q_->length()-1);
q_->remove(to_drop);
drop(to_drop);
}
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
PriQueue::filter(PacketFilter filter, void * data)
// apply filter to each packet in queue,
// - if filter returns 0 leave packet in queue
// - if filter returns 1 remove packet from queue
{
int i = 0;
while (i < q_->length())
{
Packet *p = q_->lookup(i);
if (filter(p,data))
{
q_->remove(p); // decrements q len
}
else i++;
}
}
Packet*
PriQueue::filter(nsaddr_t id)
{
Packet *p = 0;
Packet *pp = 0;
struct hdr_cmn *ch;
for(p = q_->head(); p; p = p->next_) {
ch = HDR_CMN(p);
if(ch->next_hop() == id)
break;
pp = p;
}
/*
* Deque Packet
*/
if(p) {
if(pp == 0)
q_->remove(p);
else
q_->remove(p, pp);
}
return p;
}
/*
* Called at the end of the simulation to purge the IFQ.
*/
void
PriQueue::Terminate()
{
Packet *p;
while((p = deque())) {
//drop(p, DROP_END_OF_SIMULATION);
drop(p);
}
}
propagation.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.
*
propagation.cc
$Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $
*/
#include
#include
#include
#include
class PacketStamp;
int
Propagation::command(int argc, const char*const* argv)
{
TclObject *obj;
if(argc == 3)
{
if( (obj = TclObject::lookup(argv[2])) == 0)
{
fprintf(stderr, "Propagation: %s lookup of %s failed\n", argv[1],
argv[2]);
return TCL_ERROR;
}
if (strcasecmp(argv[1], "topography") == 0)
{
topo = (Topography*) obj;
return TCL_OK;
}
}
return TclObject::command(argc,argv);
}
/* As new network-intefaces are added, add a default method here */
double
Propagation::Pr(PacketStamp *, PacketStamp *, Phy *)
{
fprintf(stderr,"Propagation model %s not implemented for generic NetIF\n",
name);
abort();
return 0; // Make msvc happy
}
double
Propagation::Pr(PacketStamp *, PacketStamp *, WirelessPhy *)
{
fprintf(stderr,
"Propagation model %s not implemented for SharedMedia interface\n",
name);
abort();
return 0; // Make msvc happy
}
ptypes2tcl.cc
#include
#include
#include "packet.h"
// The following copied from ~tclcl/tcl2c++.c
/*
* Define TCL2C_INT if your compiler has problems with long strings.
*/
#if defined(WIN32) || defined(_WIN32) || defined(__alpha__) || defined(__hpux)
#define TCL2C_INT
#endif
char* p_info::name_[PT_NTYPE+1];
void
printLine(char *s) {
#ifdef TCL2C_INT
for (unsigned int i = 0; i < strlen(s); i++)
if ((i > 0) && ((i % 20) == 0))
printf("%u,\n", s[i]);
else
printf("%u,", s[i]);
printf("%u,%u,\n", '\\', '\n');
#else
printf("%s\\n\\\n", s);
#endif
}
char *
lcase(const char *s) {
static char charbuf[512];
char* to = charbuf;
while ((*to++ = tolower(*s++)))
/* NOTHING */;
*to = '\0';
return charbuf;
}
int main() {
p_info pinfo;
#ifdef TCL2C_INT
printf("static const char code[] = {\n");
#else
printLine("static const char code[] = \"");
#endif
printLine("global ptype pvals");
printLine("set ptype(error) -1");
printLine("set pvals(-1) error");
char strbuf[512];
for (int i = 0; i < PT_NTYPE; i++) {
sprintf(strbuf, "set ptype(%s) %d", lcase(pinfo.name(packet_t(i))), i);
printLine(strbuf);
sprintf(strbuf, "set pvals(%d) %s", i, pinfo.name(packet_t(i)));
printLine(strbuf);
}
printLine("proc ptype2val {str} {");
printLine("global ptype");
printLine("set str [string tolower $str]");
printLine("if ![info exists ptype($str)] {");
printLine("set str error");
printLine("}");
printLine("set ptype($str)");
printLine("}");
printLine("proc pval2type {val} {");
printLine("global pvals");
printLine("if ![info exists pvals($val)] {");
printLine("set val -1");
printLine("}");
printLine("set pvals($val)");
printLine("}");
#ifdef TCL2C_INT
printf("0 };\n");
#else
printf("\";\n");
#endif
printf("#include \"config.h\"\n");
printf("EmbeddedTcl et_ns_ptypes(code);\n");
return 0;
}
queue-monitor.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 "queue-monitor.h"
int QueueMonitor::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "get-bytes-integrator") == 0) {
if (bytesInt_)
tcl.resultf("%s", bytesInt_->name());
else
tcl.resultf("");
return (TCL_OK);
}
if (strcmp(argv[1], "get-pkts-integrator") == 0) {
if (pktsInt_)
tcl.resultf("%s", pktsInt_->name());
else
tcl.resultf("");
return (TCL_OK);
}
if (strcmp(argv[1], "get-delay-samples") == 0) {
if (delaySamp_)
tcl.resultf("%s", delaySamp_->name());
else
tcl.resultf("");
return (TCL_OK);
}
}
if (argc == 3) {
if (strcmp(argv[1], "set-bytes-integrator") == 0) {
bytesInt_ = (Integrator *)
TclObject::lookup(argv[2]);
if (bytesInt_ == NULL)
return (TCL_ERROR);
return (TCL_OK);
}
if (strcmp(argv[1], "set-pkts-integrator") == 0) {
pktsInt_ = (Integrator *)
TclObject::lookup(argv[2]);
if (pktsInt_ == NULL)
return (TCL_ERROR);
return (TCL_OK);
}
if (strcmp(argv[1], "set-delay-samples") == 0) {
delaySamp_ = (Samples*)
TclObject::lookup(argv[2]);
if (delaySamp_ == NULL)
return (TCL_ERROR);
return (TCL_OK);
}
if (strcmp(argv[1], "trace") == 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);
}
}
if (argc == 4) {
if (strcmp(argv[1], "set-src-dst") == 0) {
srcId_ = atoi(argv[2]);
dstId_ = atoi(argv[3]);
return (TCL_OK);
}
}
return TclObject::command(argc, argv); // else control reaches end of
// non-void function, see? :-)
}
static class QueueMonitorClass : public TclClass {
public:
QueueMonitorClass() : TclClass("QueueMonitor") {}
TclObject* create(int, const char*const*) {
return (new QueueMonitor());
}
} queue_monitor_class;
void
QueueMonitor::printStats() {
char wrk[500];
int n;
double now = Scheduler::instance().clock();
sprintf(wrk, "%-6.3f %d %d %d %d", now, srcId_, dstId_, size_, pkts_);
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(channel_, wrk, n+1);
wrk[n] = 0;
}
// packet arrival to a queue
void QueueMonitor::in(Packet* p)
{
hdr_cmn* hdr = (hdr_cmn*)p->access(off_cmn_);
double now = Scheduler::instance().clock();
int pktsz = hdr->size();
barrivals_ += pktsz;
parrivals_++;
size_ += pktsz;
pkts_++;
if (bytesInt_)
bytesInt_->newPoint(now, double(size_));
if (pktsInt_)
pktsInt_->newPoint(now, double(pkts_));
if (delaySamp_)
hdr->timestamp() = now;
if (channel_)
printStats();
}
void QueueMonitor::out(Packet* p)
{
hdr_cmn* hdr = (hdr_cmn*)p->access(off_cmn_);
double now = Scheduler::instance().clock();
int pktsz = hdr->size();
size_ -= pktsz;
pkts_--;
bdepartures_ += pktsz;
pdepartures_++;
if (bytesInt_)
bytesInt_->newPoint(now, double(size_));
if (pktsInt_)
pktsInt_->newPoint(now, double(pkts_));
if (delaySamp_)
delaySamp_->newPoint(now - hdr->timestamp());
if (channel_)
printStats();
}
void QueueMonitor::drop(Packet* p)
{
hdr_cmn* hdr = (hdr_cmn*)p->access(off_cmn_);
double now = Scheduler::instance().clock();
int pktsz = hdr->size();
size_ -= pktsz;
pkts_--;
bdrops_ += pktsz;
pdrops_++;
if (bytesInt_)
bytesInt_->newPoint(now, double(size_));
if (pktsInt_)
pktsInt_->newPoint(now, double(pkts_));
if (channel_)
printStats();
}
static class SnoopQueueInClass : public TclClass {
public:
SnoopQueueInClass() : TclClass("SnoopQueue/In") {}
TclObject* create(int, const char*const*) {
return (new SnoopQueueIn());
}
} snoopq_in_class;
static class SnoopQueueOutClass : public TclClass {
public:
SnoopQueueOutClass() : TclClass("SnoopQueue/Out") {}
TclObject* create(int, const char*const*) {
return (new SnoopQueueOut());
}
} snoopq_out_class;
static class SnoopQueueDropClass : public TclClass {
public:
SnoopQueueDropClass() : TclClass("SnoopQueue/Drop") {}
TclObject* create(int, const char*const*) {
return (new SnoopQueueDrop());
}
} snoopq_drop_class;
static class SnoopQueueEDropClass : public TclClass {
public:
SnoopQueueEDropClass() : TclClass("SnoopQueue/EDrop") {}
TclObject* create(int, const char*const*) {
return (new SnoopQueueEDrop);
}
} snoopq_edrop_class;
static class QueueMonitorEDClass : public TclClass {
public:
QueueMonitorEDClass() : TclClass("QueueMonitor/ED") {}
TclObject* create(int, const char*const*) {
return (new EDQueueMonitor);
}
} queue_monitor_ed_class;
/*
* a 'QueueMonitorCompat', which is used by the compat
* code to produce the link statistics used available in ns-1
*
* in ns-1, the counters are the number of departures
*/
#include "ip.h"
QueueMonitorCompat::QueueMonitorCompat()
{
bind("off_ip_", &off_ip_);
memset(pkts_, 0, sizeof(pkts_));
memset(bytes_, 0, sizeof(bytes_));
memset(drops_, 0, sizeof(drops_));
memset(flowstats_, 0, sizeof(flowstats_));
}
/*
* create an entry in the flowstats_ array.
*/
void
QueueMonitorCompat::flowstats(int flowid)
{
Tcl& tcl = Tcl::instance();
/*
* here is the deal. we are in C code. we'd like to do
* flowstats_[flowid] = new Samples;
* but, we want to create an object that can be
* referenced via tcl. (in particular, we want ->name_
* to be valid.)
*
* so, how do we do this?
*
* well, the answer is, call tcl to create it. then,
* do a lookup on the result from tcl!
*/
tcl.evalf("new Samples");
flowstats_[flowid] = (Samples*)TclObject::lookup(tcl.result());
if (flowstats_[flowid] == 0) {
abort();
/*NOTREACHED*/
}
}
void QueueMonitorCompat::out(Packet* pkt)
{
hdr_cmn* hdr = (hdr_cmn*)pkt->access(off_cmn_);
hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_);
double now = Scheduler::instance().clock();
int fid = iph->flowid();
if (fid >= MAXFLOW) {
abort();
/*NOTREACHED*/
}
// printf("QueueMonitorCompat::out(), fid=%d\n", fid);
bytes_[fid] += ((hdr_cmn*)pkt->access(off_cmn_))->size();
pkts_[fid]++;
if (flowstats_[fid] == 0) {
flowstats(fid);
}
flowstats_[fid]->newPoint(now - hdr->timestamp());
QueueMonitor::out(pkt);
}
void QueueMonitorCompat::in(Packet* pkt)
{
hdr_cmn* hdr = (hdr_cmn*)pkt->access(off_cmn_);
double now = Scheduler::instance().clock();
// QueueMonitor::in() *may* do this, but we always need it...
hdr->timestamp() = now;
QueueMonitor::in(pkt);
}
void QueueMonitorCompat::drop(Packet* pkt)
{
hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_);
int fid = iph->flowid();
if (fid >= MAXFLOW) {
abort();
/*NOTREACHED*/
}
++drops_[fid];
QueueMonitor::drop(pkt);
}
int QueueMonitorCompat::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
int fid;
if (argc == 3) {
fid = atoi(argv[2]);
if (strcmp(argv[1], "bytes") == 0) {
if (fid >= MAXFLOW) {
abort();
/*NOTREACHED*/
}
tcl.resultf("%d", bytes_[fid]);
return TCL_OK;
} else if (strcmp(argv[1], "pkts") == 0) {
if (fid >= MAXFLOW) {
abort();
/*NOTREACHED*/
}
tcl.resultf("%d", pkts_[fid]);
return TCL_OK;
} else if (strcmp(argv[1], "drops") == 0) {
if (fid >= MAXFLOW) {
abort();
/*NOTREACHED*/
}
tcl.resultf("%d", drops_[fid]);
return TCL_OK;
} else if (strcmp(argv[1], "get-class-delay-samples") == 0) {
if (fid >= MAXFLOW) {
abort();
/*NOTREACHED*/
}
if (flowstats_[fid] == 0) {
/*
* instantiate one if user actually
* cares enough to ask for it!
*
* (otherwise, need to return "",
* and then special-case caller to
* handle this null return.)
*/
flowstats(fid);
}
tcl.resultf("%s", flowstats_[fid]->name());
return TCL_OK;
}
}
return (QueueMonitor::command(argc, argv));
}
static class QueueMonitorCompatClass : public TclClass {
public:
QueueMonitorCompatClass() : TclClass("QueueMonitor/Compat") {}
TclObject* create(int, const char*const*) {
return (new QueueMonitorCompat);
}
} queue_monitor_compat_class;
queue.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 "queue.h"
#include
void PacketQueue::remove(Packet* target)
{
for (Packet *pp= 0, *p= head_; p; pp= p, p= p->next_) {
if (p == target) {
if (!pp) deque();
else {
if (p == tail_)
tail_= pp;
pp->next_= p->next_;
--len_;
}
return;
}
}
fprintf(stderr, "PacketQueue:: remove() couldn't find target\n");
abort();
}
/*
* Remove packet pkt located after packet prev on the queue. Either p or prev
* could be NULL. If prev is NULL then pkt must be the head of the queue.
*/
void PacketQueue::remove(Packet* pkt, Packet *prev) //XXX: screwy
{
if (pkt) {
if (head_ == pkt)
PacketQueue::deque(); /* decrements len_ internally */
else {
prev->next_ = pkt->next_;
if (tail_ == pkt)
tail_ = prev;
--len_;
}
}
return;
}
void QueueHandler::handle(Event*)
{
queue_.resume();
}
Queue::Queue() : Connector(), blocked_(0), unblock_on_resume_(1), qh_(*this),
pq_(0) /* temporarily NULL */
{
bind("limit_", &qlim_);
bind_bool("blocked_", &blocked_);
bind_bool("unblock_on_resume_", &unblock_on_resume_);
}
void Queue::recv(Packet* p, Handler*)
{
enque(p);
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 Queue::resume()
{
Packet* p = deque();
if (p != 0) {
target_->recv(p, &qh_);
} else {
if (unblock_on_resume_)
blocked_ = 0;
else
blocked_ = 1;
}
}
void Queue::reset()
{
Packet* p;
while ((p = deque()) != 0)
drop(p);
}
random.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1995 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$ (LBL)";
*/
#ifndef WIN32
#include
#include "config.h"
#include "random.h"
RANDOM_RETURN_TYPE
random()
{
printf("random() called in ns.\nRandom is not portable, please use Random::uniform() instead.\n");
abort();
}
#endif /* !WIN32 */
ranvar.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 "ranvar.h"
RandomVariable::RandomVariable()
{
rng_ = RNG::defaultrng();
}
int RandomVariable::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "value") == 0) {
tcl.resultf("%6e", value());
return(TCL_OK);
}
}
if (argc == 3) {
if (strcmp(argv[1], "use-rng") == 0) {
rng_ = (RNG*)TclObject::lookup(argv[2]);
if (rng_ == 0) {
tcl.resultf("no such RNG %s", argv[2]);
return(TCL_ERROR);
}
return(TCL_OK);
}
}
return(TclObject::command(argc, argv));
}
static class UniformRandomVariableClass : public TclClass {
public:
UniformRandomVariableClass() : TclClass("RandomVariable/Uniform"){}
TclObject* create(int, const char*const*) {
return(new UniformRandomVariable());
}
} class_uniformranvar;
UniformRandomVariable::UniformRandomVariable()
{
bind("min_", &min_);
bind("max_", &max_);
}
UniformRandomVariable::UniformRandomVariable(double min, double max)
{
min_ = min;
max_ = max;
}
double UniformRandomVariable::value()
{
return(rng_->uniform(min_, max_));
}
static class ExponentialRandomVariableClass : public TclClass {
public:
ExponentialRandomVariableClass() : TclClass("RandomVariable/Exponential") {}
TclObject* create(int, const char*const*) {
return(new ExponentialRandomVariable());
}
} class_exponentialranvar;
ExponentialRandomVariable::ExponentialRandomVariable()
{
bind("avg_", &avg_);
}
ExponentialRandomVariable::ExponentialRandomVariable(double avg)
{
avg_ = avg;
}
double ExponentialRandomVariable::value()
{
return(rng_->exponential(avg_));
}
static class ParetoRandomVariableClass : public TclClass {
public:
ParetoRandomVariableClass() : TclClass("RandomVariable/Pareto") {}
TclObject* create(int, const char*const*) {
return(new ParetoRandomVariable());
}
} class_paretoranvar;
ParetoRandomVariable::ParetoRandomVariable()
{
bind("avg_", &avg_);
bind("shape_", &shape_);
}
ParetoRandomVariable::ParetoRandomVariable(double avg, double shape)
{
avg_ = avg;
shape_ = shape;
}
double ParetoRandomVariable::value()
{
/* yuck, user wants to specify shape and avg, but the
* computation here is simpler if we know the 'scale'
* parameter. right thing is to probably do away with
* the use of 'bind' and provide an API such that we
* can update the scale everytime the user updates shape
* or avg.
*/
return(rng_->pareto(avg_ * (shape_ -1)/shape_, shape_));
}
/* Pareto distribution of the second kind, aka. Lomax distribution */
static class ParetoIIRandomVariableClass : public TclClass {
public:
ParetoIIRandomVariableClass() : TclClass("RandomVariable/ParetoII") {}
TclObject* create(int, const char*const*) {
return(new ParetoIIRandomVariable());
}
} class_paretoIIranvar;
ParetoIIRandomVariable::ParetoIIRandomVariable()
{
bind("avg_", &avg_);
bind("shape_", &shape_);
}
ParetoIIRandomVariable::ParetoIIRandomVariable(double avg, double shape)
{
avg_ = avg;
shape_ = shape;
}
double ParetoIIRandomVariable::value()
{
return(rng_->paretoII(avg_ * (shape_ - 1), shape_));
}
static class NormalRandomVariableClass : public TclClass {
public:
NormalRandomVariableClass() : TclClass("RandomVariable/Normal") {}
TclObject* create(int, const char*const*) {
return(new NormalRandomVariable());
}
} class_normalranvar;
NormalRandomVariable::NormalRandomVariable()
{
bind("avg_", &avg_);
bind("std_", &std_);
}
double NormalRandomVariable::value()
{
return(rng_->normal(avg_, std_));
}
static class LogNormalRandomVariableClass : public TclClass {
public:
LogNormalRandomVariableClass() : TclClass("RandomVariable/LogNormal") {}
TclObject* create(int, const char*const*) {
return(new LogNormalRandomVariable());
}
} class_lognormalranvar;
LogNormalRandomVariable::LogNormalRandomVariable()
{
bind("avg_", &avg_);
bind("std_", &std_);
}
double LogNormalRandomVariable::value()
{
return(rng_->lognormal(avg_, std_));
}
static class ConstantRandomVariableClass : public TclClass {
public:
ConstantRandomVariableClass() : TclClass("RandomVariable/Constant"){}
TclObject* create(int, const char*const*) {
return(new ConstantRandomVariable());
}
} class_constantranvar;
ConstantRandomVariable::ConstantRandomVariable()
{
bind("val_", &val_);
}
ConstantRandomVariable::ConstantRandomVariable(double val)
{
val_ = val;
}
double ConstantRandomVariable::value()
{
return(val_);
}
/* Hyperexponential distribution code adapted from code provided
* by Ion Stoica.
*/
static class HyperExponentialRandomVariableClass : public TclClass {
public:
HyperExponentialRandomVariableClass() :
TclClass("RandomVariable/HyperExponential") {}
TclObject* create(int, const char*const*) {
return(new HyperExponentialRandomVariable());
}
} class_hyperexponentialranvar;
HyperExponentialRandomVariable::HyperExponentialRandomVariable()
{
bind("avg_", &avg_);
bind("cov_", &cov_);
alpha_ = .95;
}
HyperExponentialRandomVariable::HyperExponentialRandomVariable(double avg, double cov)
{
alpha_ = .95;
avg_ = avg;
cov_ = cov;
}
double HyperExponentialRandomVariable::value()
{
double temp, res;
double u = Random::uniform();
temp = sqrt((cov_ * cov_ - 1.0)/(2.0 * alpha_ * (1.0 - alpha_)));
if (u < alpha_)
res = Random::exponential(avg_ - temp * (1.0 - alpha_) * avg_);
else
res = Random::exponential(avg_ + temp * (alpha_) * avg_);
return(res);
}
/*
// Empirical Random Variable:
// CDF input from file with the following column
// 1. Possible values in a distrubutions
// 2. Number of occurances for those values
// 3. The CDF for those value
// code provided by Giao Nguyen
*/
static class EmpiricalRandomVariableClass : public TclClass {
public:
EmpiricalRandomVariableClass() : TclClass("RandomVariable/Empirical"){}
TclObject* create(int, const char*const*) {
return(new EmpiricalRandomVariable());
}
} class_empiricalranvar;
EmpiricalRandomVariable::EmpiricalRandomVariable() : minCDF_(0), maxCDF_(1), maxEntry_(32), table_(0)
{
bind("minCDF_", &minCDF_);
bind("maxCDF_", &maxCDF_);
bind("interpolation_", &interpolation_);
bind("maxEntry_", &maxEntry_);
}
int EmpiricalRandomVariable::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "loadCDF") == 0) {
if (loadCDF(argv[2]) == 0) {
tcl.resultf("%s loadCDF %s: invalid file",
name(), argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return RandomVariable::command(argc, argv);
}
int EmpiricalRandomVariable::loadCDF(const char* filename)
{
FILE* fp;
char line[256];
CDFentry* e;
fp = fopen(filename, "r");
if (fp == 0)
return 0;
if (table_ == 0)
table_ = new CDFentry[maxEntry_];
for (numEntry_=0; fgets(line, 256, fp); numEntry_++) {
if (numEntry_ >= maxEntry_) { // resize the CDF table
maxEntry_ *= 2;
e = new CDFentry[maxEntry_];
for (int i=numEntry_-1; i >= 0; i--)
e[i] = table_[i];
delete table_;
table_ = e;
}
e = &table_[numEntry_];
// Use * and l together raises a warning
sscanf(line, "%lf %*f %lf", &e->val_, &e->cdf_);
}
return numEntry_;
}
double EmpiricalRandomVariable::value()
{
if (numEntry_ <= 0)
return 0;
double u = rng_->uniform(minCDF_, maxCDF_);
int mid = lookup(u);
if (mid && interpolation_ && u < table_[mid].cdf_)
return interpolate(u, table_[mid-1].cdf_, table_[mid-1].val_,
table_[mid].cdf_, table_[mid].val_);
return table_[mid].val_;
}
double EmpiricalRandomVariable::interpolate(double x, double x1, double y1, double x2, double y2)
{
double value = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
if (interpolation_ == INTER_INTEGRAL) // round up
return ceil(value);
return value;
}
int EmpiricalRandomVariable::lookup(double u)
{
// always return an index whose value is >= u
int lo, hi, mid;
if (u <= table_[0].cdf_)
return 0;
for (lo=1, hi=numEntry_-1; lo < hi; ) {
mid = (lo + hi) / 2;
if (u > table_[mid].cdf_)
lo = mid + 1;
else hi = mid;
}
return lo;
}
red.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.
*
*
* Here is one set of parameters from one of Sally's simulations
* (this is from tcpsim, the older simulator):
*
* ed [ q_weight=0.002 thresh=5 linterm=30 maxthresh=15
* mean_pktsize=500 dropmech=random-drop queue-size=60
* plot-file=none bytes=false doubleq=false dqthresh=50
* wait=true ]
*
* 1/"linterm" is the max probability of dropping a packet.
* There are different options that make the code
* more messy that it would otherwise be. For example,
* "doubleq" and "dqthresh" are for a queue that gives priority to
* small (control) packets,
* "bytes" indicates whether the queue should be measured in bytes
* or in packets,
* "dropmech" indicates whether the drop function should be random-drop
* or drop-tail when/if the queue overflows, and
* the commented-out Holt-Winters method for computing the average queue
* size can be ignored.
* "wait" indicates whether the gateway should wait between dropping
* packets.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
#include
#include
#include "config.h"
#include "template.h"
#include "random.h"
#include "flags.h"
#include "delay.h"
#include "red.h"
static class REDClass : public TclClass {
public:
REDClass() : TclClass("Queue/RED") {}
TclObject* create(int, const char*const*) {
return (new REDQueue);
}
} class_red;
REDQueue::REDQueue() : link_(NULL), bcount_(0), de_drop_(NULL),
tchan_(0), idle_(1)
{
bind_bool("bytes_", &edp_.bytes); // boolean: use bytes?
bind_bool("queue_in_bytes_", &qib_); // boolean: q in bytes?
// _RENAMED("queue-in-bytes_", "queue_in_bytes_");
bind("thresh_", &edp_.th_min); // minthresh
bind("maxthresh_", &edp_.th_max); // maxthresh
bind("mean_pktsize_", &edp_.mean_pktsize); // avg pkt size
bind("q_weight_", &edp_.q_w); // for EWMA
bind_bool("wait_", &edp_.wait);
bind("linterm_", &edp_.max_p_inv);
bind_bool("setbit_", &edp_.setbit); // mark instead of drop
bind_bool("gentle_", &edp_.gentle); // increase the packet
// drop prob. slowly
// when ave queue
// exceeds maxthresh
bind_bool("drop_tail_", &drop_tail_); // drop last pkt
// _RENAMED("drop-tail_", "drop_tail_");
bind_bool("drop_front_", &drop_front_); // drop first pkt
// _RENAMED("drop-front_", "drop_front_");
bind_bool("drop_rand_", &drop_rand_); // drop pkt at random
// _RENAMED("drop-rand_", "drop_rand_");
bind_bool("ns1_compat_", &ns1_compat_); // ns-1 compatibility
// _RENAMED("ns1-compat_", "ns1_compat_");
bind("ave_", &edv_.v_ave); // average queue sie
bind("prob1_", &edv_.v_prob1); // dropping probability
bind("curq_", &curq_); // current queue size
q_ = new PacketQueue(); // underlying queue
pq_ = q_;
reset();
#ifdef notdef
print_edp();
print_edv();
#endif
}
void REDQueue::reset()
{
/*
* If queue is measured in bytes, scale min/max thresh
* by the size of an average packet (which is specified by user).
*/
if (qib_) {
edp_.th_min *= edp_.mean_pktsize;
edp_.th_max *= edp_.mean_pktsize;
}
/*
* Compute the "packet time constant" if we know the
* link bandwidth. The ptc is the max number of (avg sized)
* pkts per second which can be placed on the link.
* The link bw is given in bits/sec, so scale mean psize
* accordingly.
*/
if (link_)
edp_.ptc = link_->bandwidth() /
(8. * edp_.mean_pktsize);
edv_.v_ave = 0.0;
edv_.v_slope = 0.0;
edv_.count = 0;
edv_.count_bytes = 0;
edv_.old = 0;
edv_.v_a = 1 / (edp_.th_max - edp_.th_min);
edv_.v_b = - edp_.th_min / (edp_.th_max - edp_.th_min);
if (edp_.gentle) {
edv_.v_c = ( 1.0 - 1 / edp_.max_p_inv ) / edp_.th_max;
edv_.v_d = 2 / edp_.max_p_inv - 1.0;
}
idle_ = 1;
if (&Scheduler::instance() != NULL)
idletime_ = Scheduler::instance().clock();
else
idletime_ = 0.0; /* sched not instantiated yet */
Queue::reset();
bcount_ = 0;
}
/*
* Compute the average queue size.
* The code contains two alternate methods for this, the plain EWMA
* and the Holt-Winters method.
* nqueued can be bytes or packets
*/
void REDQueue::run_estimator(int nqueued, int m)
{
float f, f_sl, f_old;
f = (float)edv_.v_ave;
f_sl = (float)edv_.v_slope;
#define RED_EWMA
#ifdef RED_EWMA
while (--m >= 1) {
f_old = f;
f *= 1.0 - (float)edp_.q_w;
}
f_old = f;
f *= 1.0 - (float)edp_.q_w;
f += (float)edp_.q_w * nqueued;
#endif
#ifdef RED_HOLT_WINTERS
while (--m >= 1) {
f_old = f;
f += f_sl;
f *= 1.0 - edp_.q_w;
f_sl *= 1.0 - 0.5 * edp_.q_w;
f_sl += 0.5 * edp_.q_w * (f - f_old);
}
f_old = f;
f += f_sl;
f *= 1.0 - edp_.q_w;
f += edp_.q_w * nqueued;
f_sl *= 1.0 - 0.5 * edp_.q_w;
f_sl += 0.5 * edp_.q_w * (f - f_old);
#endif
edv_.v_ave = f;
edv_.v_slope = f_sl;
}
/*
* Return the next packet in the queue for transmission.
*/
Packet* REDQueue::deque()
{
Packet *p;
p = q_->deque();
if (p != 0) {
idle_ = 0;
bcount_ -= ((hdr_cmn*)p->access(off_cmn_))->size();
} else {
idle_ = 1;
// deque() may invoked by Queue::reset at init
// time (before the scheduler is instantiated).
// deal with this case
if (&Scheduler::instance() != NULL)
idletime_ = Scheduler::instance().clock();
else
idletime_ = 0.0;
}
return (p);
}
/*
* should the packet be dropped/marked due to a probabilistic drop?
*/
int
REDQueue::drop_early(Packet* pkt)
{
double p;
int no_ecn = 0;
hdr_cmn* ch = (hdr_cmn*)pkt->access(off_cmn_);
if (edp_.gentle && edv_.v_ave >= edp_.th_max) {
// p ranges from max_p to 1 as the average queue
// size ranges from th_max to twice th_max
p = edv_.v_c * edv_.v_ave + edv_.v_d;
no_ecn = 1;
} else {
// p ranges from 0 to max_p as the average queue
// size ranges from th_min to th_max
p = edv_.v_a * edv_.v_ave + edv_.v_b;
p /= edp_.max_p_inv;
}
edv_.v_prob1 = p;
if (edv_.v_prob1 > 1.0)
edv_.v_prob1 = 1.0;
double count1 = edv_.count;
if (edp_.bytes)
count1 = (double) (edv_.count_bytes/edp_.mean_pktsize);
if (edp_.wait) {
if (count1 * p < 1.0)
p = 0.0;
else if (count1 * p < 2.0)
p /= (2 - count1 * p);
else
p = 1.0;
} else {
if (count1 * p < 1.0)
p /= (1.0 - count1 * p);
else
p = 1.0;
}
if (edp_.bytes && p < 1.0) {
p = p * ch->size() / edp_.mean_pktsize;
}
if (p > 1.0)
p = 1.0;
edv_.v_prob = p;
// drop probability is computed, pick random number and act
double u = Random::uniform();
if (u <= edv_.v_prob) {
// DROP or MARK
edv_.count = 0;
edv_.count_bytes = 0;
hdr_flags* hf = (hdr_flags*)pickPacketForECN(pkt)->access(off_flags_);
if (edp_.setbit && hf->ect() && no_ecn==0) {
hf->ce() = 1; // mark Congestion Experienced bit
return (0); // no drop
} else {
return (1); // drop
}
}
return (0); // no DROP/mark
}
/*
* Pick packet for early congestion notification (ECN). This packet is then
* marked or dropped. Having a separate function do this is convenient for
* supporting derived classes that use the standard RED algorithm to compute
* average queue size but use a different algorithm for choosing the packet for
* ECN notification.
*/
Packet*
REDQueue::pickPacketForECN(Packet* pkt)
{
return pkt; /* pick the packet that just arrived */
}
/*
* Pick packet to drop. Having a separate function do this is convenient for
* supporting derived classes that use the standard RED algorithm to compute
* average queue size but use a different algorithm for choosing the victim.
*/
Packet*
REDQueue::pickPacketToDrop()
{
int victim;
if (drop_front_)
victim = min(1, q_->length()-1);
else if (drop_rand_)
victim = Random::integer(q_->length());
else /* default is drop_tail_ */
victim = q_->length() - 1;
return(q_->lookup(victim));
}
/*
* Receive a new packet arriving at the queue.
* The average queue size is computed. If the average size
* exceeds the threshold, then the dropping probability is computed,
* and the newly-arriving packet is dropped with that probability.
* The packet is also dropped if the maximum queue size is exceeded.
*
* "Forced" drops mean a packet arrived when the underlying queue was
* full or when the average q size exceeded maxthresh.
* "Unforced" means a RED random drop.
*
* For forced drops, either the arriving packet is dropped or one in the
* queue is dropped, depending on the setting of drop_tail_.
* For unforced drops, the arriving packet is always the victim.
*/
#define DTYPE_NONE 0 /* ok, no drop */
#define DTYPE_FORCED 1 /* a "forced" drop */
#define DTYPE_UNFORCED 2 /* an "unforced" (random) drop */
void REDQueue::enque(Packet* pkt)
{
/*
* if we were idle, we pretend that m packets arrived during
* the idle period. m is set to be the ptc times the amount
* of time we've been idle for
*/
int m = 0;
if (idle_) {
// A packet that arrives to an idle queue will never
// be dropped.
double now = Scheduler::instance().clock();
/* To account for the period when the queue was empty. */
idle_ = 0;
m = int(edp_.ptc * (now - idletime_));
}
/*
* Run the estimator with either 1 new packet arrival, or with
* the scaled version above [scaled by m due to idle time]
* (bcount_ maintains the byte count in the underlying queue).
* If the underlying queue is able to delete packets without
* us knowing, then bcount_ will not be maintained properly!
*/
run_estimator(qib_ ? bcount_ : q_->length(), m + 1);
/*
* count and count_bytes keeps a tally of arriving traffic
* that has not been dropped (i.e. how long, in terms of traffic,
* it has been since the last early drop)
*/
hdr_cmn* ch = (hdr_cmn*)pkt->access(off_cmn_);
++edv_.count;
edv_.count_bytes += ch->size();
/*
* DROP LOGIC:
* q = current q size, ~q = averaged q size
* 1> if ~q > maxthresh, this is a FORCED drop
* 2> if minthresh < ~q < maxthresh, this may be an UNFORCED drop
* 3> if (q+1) > hard q limit, this is a FORCED drop
*/
register double qavg = edv_.v_ave;
int droptype = DTYPE_NONE;
int qlen = qib_ ? bcount_ : q_->length();
int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_;
curq_ = qlen; // helps to trace queue during arrival, if enabled
if (qavg >= edp_.th_min && qlen > 1) {
if ((!edp_.gentle && qavg >= edp_.th_max) ||
(edp_.gentle && qavg >= 2 * edp_.th_max)) {
droptype = DTYPE_FORCED;
} else if (edv_.old == 0) {
/*
* The average queue size has just crossed the
* threshold from below to above "minthresh", or
* from above "minthresh" with an empty queue to
* above "minthresh" with a nonempty queue.
*/
edv_.count = 1;
edv_.count_bytes = ch->size();
edv_.old = 1;
} else if (drop_early(pkt)) {
droptype = DTYPE_UNFORCED;
}
} else {
/* No packets are being dropped. */
edv_.v_prob = 0.0;
edv_.old = 0;
}
if (qlen >= qlim) {
// see if we've exceeded the queue size
droptype = DTYPE_FORCED;
}
if (droptype == DTYPE_UNFORCED) {
/* pick packet for ECN, which is dropping in this case */
Packet *pkt_to_drop = pickPacketForECN(pkt);
/*
* If the packet picked is different that the one that just arrived,
* add it to the queue and remove the chosen packet.
*/
if (pkt_to_drop != pkt) {
q_->enque(pkt);
bcount_ += ch->size();
q_->remove(pkt_to_drop);
bcount_ -= ((hdr_cmn*)pkt_to_drop->access(off_cmn_))->size();
pkt = pkt_to_drop; /* XXX okay because pkt is not needed anymore */
}
// deliver to special "edrop" target, if defined
if (de_drop_ != NULL)
de_drop_->recv(pkt);
else
drop(pkt);
} else {
/* forced drop, or not a drop: first enqueue pkt */
q_->enque(pkt);
bcount_ += ch->size();
/* drop a packet if we were told to */
if (droptype == DTYPE_FORCED) {
/* drop random victim or last one */
pkt = pickPacketToDrop();
q_->remove(pkt);
bcount_ -= ((hdr_cmn*)pkt->access(off_cmn_))->size();
drop(pkt);
if (!ns1_compat_) {
// bug-fix from Philip Liu,
edv_.count = 0;
edv_.count_bytes = 0;
}
}
}
return;
}
int REDQueue::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "reset") == 0) {
reset();
return (TCL_OK);
}
if (strcmp(argv[1], "early-drop-target") == 0) {
if (de_drop_ != NULL)
tcl.resultf("%s", de_drop_->name());
return (TCL_OK);
}
} else if (argc == 3) {
// attach a file for variable tracing
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("RED: trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
}
// tell RED about link stats
if (strcmp(argv[1], "link") == 0) {
LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]);
if (del == 0) {
tcl.resultf("RED: no LinkDelay object %s",
argv[2]);
return(TCL_ERROR);
}
// set ptc now
link_ = del;
edp_.ptc = link_->bandwidth() /
(8. * edp_.mean_pktsize);
return (TCL_OK);
}
if (strcmp(argv[1], "early-drop-target") == 0) {
NsObject* p = (NsObject*)TclObject::lookup(argv[2]);
if (p == 0) {
tcl.resultf("no object %s", argv[2]);
return (TCL_ERROR);
}
de_drop_ = p;
return (TCL_OK);
}
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));
}
/*
* Routine called by TracedVar facility when variables change values.
* Currently used to trace values of avg queue size, drop probability,
* and the instantaneous queue size seen by arriving packets.
* Note that the tracing of each var must be enabled in tcl to work.
*/
void
REDQueue::trace(TracedVar* v)
{
char wrk[500], *p;
if (((p = strstr(v->name(), "ave")) == NULL) &&
((p = strstr(v->name(), "prob")) == NULL) &&
((p = strstr(v->name(), "curq")) == NULL)) {
fprintf(stderr, "RED:unknown trace var %s\n",
v->name());
return;
}
if (tchan_) {
int n;
double t = Scheduler::instance().clock();
// XXX: be compatible with nsv1 RED trace entries
if (*p == 'c') {
sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v)));
} else {
sprintf(wrk, "%c %g %g", *p, t,
double(*((TracedDouble*) v)));
}
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(tchan_, wrk, n+1);
}
return;
}
/* for debugging help */
void REDQueue::print_edp()
{
printf("mean_pktsz: %d\n", edp_.mean_pktsize);
printf("bytes: %d, wait: %d, setbit: %d\n",
edp_.bytes, edp_.wait, edp_.setbit);
printf("minth: %f, maxth: %f\n", edp_.th_min, edp_.th_max);
printf("max_p_inv: %f, qw: %f, ptc: %f\n",
edp_.max_p_inv, edp_.q_w, edp_.ptc);
printf("qlim: %d, idletime: %f\n", qlim_, idletime_);
printf("=========\n");
}
void REDQueue::print_edv()
{
printf("v_a: %f, v_b: %f\n", edv_.v_a, edv_.v_b);
}
replicator.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 "classifier.h"
#include "packet.h"
#include "ip.h"
/*
* A replicator is not really a packet classifier but
* we simply find convenience in leveraging its slot table.
* (this object used to implement fan-out on a multicast
* router as well as broadcast LANs)
*/
class Replicator : public Classifier {
public:
Replicator();
void recv(Packet*, Handler* h = 0);
virtual int classify(Packet*) {/*NOTREACHED*/ return -1;};
protected:
virtual int command(int argc, const char*const* argv);
int ignore_;
};
static class ReplicatorClass : public TclClass {
public:
ReplicatorClass() : TclClass("Classifier/Replicator") {}
TclObject* create(int, const char*const*) {
return (new Replicator());
}
} class_replicator;
Replicator::Replicator() : ignore_(0)
{
bind("ignore_", &ignore_);
}
void Replicator::recv(Packet* p, Handler*)
{
hdr_ip* iph = hdr_ip::access(p);
hdr_cmn* ch = hdr_cmn::access(p);
if (maxslot_ < 0) {
if (!ignore_)
Tcl::instance().evalf("%s drop %ld %ld %d", name(),
iph->saddr(), iph->daddr(), ch->iface());
Packet::free(p);
return;
}
for (int i = 0; i < maxslot_; ++i) {
NsObject* o = slot_[i];
if (o != 0)
o->recv(p->copy());
}
/* we know that maxslot is non-null */
slot_[maxslot_]->recv(p);
}
int Replicator::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
/*
* $replicator slot
*/
if (strcmp(argv[1], "slots") == 0) {
if (maxslot_ < 0) {
tcl.result("");
return (TCL_OK);
}
for (int i = 0; i <= maxslot_; i++) {
if (slot_[i] == 0)
continue;
tcl.resultf("%s %s", tcl.result(),
slot_[i]->name());
}
return (TCL_OK);
}
}
return Classifier::command(argc, argv);
}
resv.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 "packet.h"
#include "resv.h"
int hdr_resv::offset_;
static class ResvHeaderClass : public PacketHeaderClass {
public:
ResvHeaderClass() : PacketHeaderClass("PacketHeader/Resv",
sizeof(hdr_resv)) {
bind_offset(&hdr_resv::offset_);
}
void export_offsets() {
field_offset("rate_", OFFSET(hdr_resv, rate_));
field_offset("bucket_", OFFSET(hdr_resv, bucket_));
field_offset("decision_", OFFSET(hdr_resv, decision_));
}
} class_resvhdr;
rlm.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 char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
#include "agent.h"
#include "node.h"
struct srcpkt {
double off;
int level;
int size;
srcpkt* next;
};
class RLM_Sender : public Agent {
public:
RLM_Sender();
~RLM_Sender();
int command(int argc, const char*const* argv);
protected:
virtual void timeout(int);
void start();
void stop();
void sched_next();
void sendpkt(int size, int level);
void addpkt(double off, int size, int level);
int running_;
double interval_;
srcpkt* pkt_;
srcpkt* allpkt_;
/*XXX make size dynamic*/
#define MAXLEVEL 32
int seqno_[MAXLEVEL];
int blkno_;
};
static class RLMMatcher : public Matcher {
public:
RLMMatcher() : Matcher("agent") {}
TclObject* match(const char* id) {
if (strcmp(id, "rlm-sender") == 0)
return (new RLM_Sender());
return (0);
}
} matcher_rlm;
RLM_Sender::RLM_Sender() : Agent(PT_CBR), pkt_(0), allpkt_(0)
{
Tcl& tcl = Tcl::instance();
link_time("ns_rlm", "interval", &interval_, 0);
link_int("ns_rlm", "packet-size", &size_, 0);
running_ = 0;
memset(seqno_, 0, sizeof(seqno_));
blkno_ = 0;
}
RLM_Sender::~RLM_Sender()
{
/*XXX free allpkt_ */
}
void RLM_Sender::start()
{
if (allpkt_ != 0) {
running_ = 1;
pkt_ = allpkt_;
sched(pkt_->off, 0);
}
}
void RLM_Sender::stop()
{
running_ = 0;
}
void RLM_Sender::sched_next()
{
srcpkt* p = pkt_;
srcpkt* n = p->next;
double t;
if (n == 0) {
t = interval_;
n = allpkt_;
++blkno_;
blkitem_ = 0;
} else
t = 0.;
t += n->off - p->off;
pkt_ = n;
sched(t, 0);
}
void RLM_Sender::timeout(int)
{
if (running_) {
sendpkt(pkt_->size, pkt_->level);
sched_next();
}
}
void RLM_Sender::sendpkt(int size, int level)
{
Packet* p = allocpkt(seqno_[level]++);
IPHeader *iph = IPHeader::access(p->bits());
RLMHeader *rh = RLMHeader::access(p->bits());
rh->blkno() = blkno_;
rh->blkitem() = blkitem_++;
iph->size() = size;
iph->daddr() += level;
#ifdef notdef
iph->class() += level;/*XXX*/
#endif
node_->transmit(p);
}
extern double time_atof(const char*);
void RLM_Sender::addpkt(double off, int size, int level)
{
srcpkt* sp = new srcpkt;
sp->next = 0;
sp->off = off;
sp->size = size;
sp->level = level;
srcpkt** p;
for (p = &allpkt_; *p != 0; p = &(*p)->next)
if (sp->off < (*p)->off)
break;
*p = sp;
}
/*
* $obj start
* $obj stop
* $obj packet $off $size $level
*/
int RLM_Sender::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "start") == 0) {
start();
return (TCL_OK);
}
if (strcmp(argv[1], "stop") == 0) {
stop();
return (TCL_OK);
}
}
if (argc == 5) {
if (strcmp(argv[1], "packet") == 0) {
double off = time_atof(argv[2]);
int size = atoi(argv[3]);
int level = atoi(argv[4]);
addpkt(off, size, level);
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
class RLM_Receiver : public Agent {
public:
RLM_Receiver();
int command(int argc, const char*const* argv);
void recv(Packet* pkt);
protected:
char* proc_;
int loss_;
int expected_;
int bytes_;
int pblk_;
int pseq_[MAXLEVEL];
};
static class RLM_ReceiverMatcher : public Matcher {
public:
RLM_ReceiverMatcher() : Matcher("agent") {}
TclObject* match(const char* id) {
if (strcmp(id, "rlm-receiver") == 0)
return (new RLM_Receiver());
return (0);
}
} matcher_cbr;
RLM_Receiver::RLM_Receiver() : Agent(-1), proc_(0), expected_(-1)
{
bytes_ = 0;
loss_ = 0;
link_int(0, "loss", &loss_, 1);
link_int(0, "bytes", &bytes_, 1);
}
void RLM_Receiver::recv(Packet* pkt)
{
IPHeader *iph = IPHeader::access(pkt->bits());
SequenceHeader *sh = SequenceHeader::access(pkt->bits());
bytes_ += iph->size();
int seqno = sh->seqno();
int blkno = seqno >> 16;
seqno &= 0xffff;
/*
* Check for lost packets
*/
if (expected_ >= 0) {
int loss = sh->seqno() - expected_;
if (loss > 0) {
loss_ += loss;
if (proc_ != 0)
Tcl::instance().eval(proc_);
}
}
expected_ = sh->seqno() + 1;
Packet::free(pkt);
}
/*
* $proc interval $interval
* $proc size $size
*/
int RLM_Receiver::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "clear") == 0) {
expected_ = -1;
return (TCL_OK);
}
} else if (argc == 3) {
if (strcmp(argv[1], "proc") == 0) {
const char* proc = argv[2];
int n = strlen(proc) + 1;
delete proc_;
proc_ = new char[n];
strcpy(proc_, proc);
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
rng.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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
/* new random number generator */
#ifndef WIN32
#include // for gettimeofday
#include
#endif
#include
#include "rng.h"
#include "config.h" // for gettimeofday
#ifndef MAXINT
#define MAXINT 2147483647 // XX [for now]
#endif
/*
* RNGImplementation
*/
/*
* Generate a periodic sequence of pseudo-random numbers with
* a period of 2^31 - 2. The generator is the "minimal standard"
* multiplicative linear congruential generator of Park, S.K. and
* Miller, K.W., "Random Number Generators: Good Ones are Hard to Find,"
* CACM 31:10, Oct. 88, pp. 1192-1201.
*
* The algorithm implemented is: Sn = (a*s) mod m.
* The modulus m can be approximately factored as: m = a*q + r,
* where q = m div a and r = m mod a.
*
* Then Sn = g(s) + m*d(s)
* where g(s) = a(s mod q) - r(s div q)
* and d(s) = (s div q) - ((a*s) div m)
*
* Observations:
* - d(s) is either 0 or 1.
* - both terms of g(s) are in 0, 1, 2, . . ., m - 1.
* - |g(s)| <= m - 1.
* - if g(s) > 0, d(s) = 0, else d(s) = 1.
* - s mod q = s - k*q, where k = s div q.
*
* Thus Sn = a(s - k*q) - r*k,
* if (Sn <= 0), then Sn += m.
*
* To test an implementation for A = 16807, M = 2^31-1, you should
* get the following sequences for the given starting seeds:
*
* s0, s1, s2, s3, . . . , s10000, . . . , s551246
* 1, 16807, 282475249, 1622650073, . . . , 1043618065, . . . , 1003
* 1973272912, 1207871363, 531082850, 967423018
*
* It is important to check for s10000 and s551246 with s0=1, to guard
* against overflow.
*/
/*
* The sparc assembly code [no longer here] is based on Carta, D.G., "Two Fast
* Implementations of the 'Minimal Standard' Random Number
* Generator," CACM 33:1, Jan. 90, pp. 87-88.
*
* ASSUME that "the product of two [signed 32-bit] integers (a, sn)
* will occupy two [32-bit] registers (p, q)."
* Thus: a*s = (2^31)p + q
*
* From the observation that: x = y mod z is but
* x = z * the fraction part of (y/z),
* Let: sn = m * Frac(as/m)
*
* For m = 2^31 - 1,
* sn = (2^31 - 1) * Frac[as/(2^31 -1)]
* = (2^31 - 1) * Frac[as(2^-31 + 2^-2(31) + 2^-3(31) + . . .)]
* = (2^31 - 1) * Frac{[(2^31)p + q] [2^-31 + 2^-2(31) + 2^-3(31) + . .
.]}
* = (2^31 - 1) * Frac[p+(p+q)2^-31+(p+q)2^-2(31)+(p+q)3^(-31)+ . . .]
*
* if p+q < 2^31:
* sn = (2^31 - 1) * Frac[p + a fraction + a fraction + a fraction + . . .]
* = (2^31 - 1) * [(p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .]
* = p + q
*
* otherwise:
* sn = (2^31 - 1) * Frac[p + 1.frac . . .]
* = (2^31 - 1) * (-1 + 1.frac . . .)
* = (2^31 - 1) * [-1 + (p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .]
* = p + q - 2^31 + 1
*/
#define A 16807L /* multiplier, 7**5 */
#define M 2147483647L /* modulus, 2**31 - 1; both used in random */
#define INVERSE_M ((double)4.656612875e-10) /* (1.0/(double)M) */
long
RNGImplementation::next()
{
long L, H;
L = A * (seed_ & 0xffff);
H = A * (seed_ >> 16);
seed_ = ((H & 0x7fff) << 16) + L;
seed_ -= 0x7fffffff;
seed_ += H >> 15;
if (seed_ <= 0) {
seed_ += 0x7fffffff;
}
return(seed_);
}
double
RNGImplementation::next_double()
{
long i = next();
return i * INVERSE_M;
}
/*
* RNG implements a nice front-end around RNGImplementation
*/
#ifndef stand_alone
static class RNGClass : public TclClass {
public:
RNGClass() : TclClass("RNG") {}
TclObject* create(int, const char*const*) {
return(new RNG());
}
} class_rng;
#endif /* stand_alone */
/* default RNG */
RNG* RNG::default_ = NULL;
double
RNG::normal(double avg, double std)
{
static int parity = 0;
static double nextresult;
double sam1, sam2, rad;
if (std == 0) return avg;
if (parity == 0) {
sam1 = 2*uniform() - 1;
sam2 = 2*uniform() - 1;
while ((rad = sam1*sam1 + sam2*sam2) >= 1) {
sam1 = 2*uniform() - 1;
sam2 = 2*uniform() - 1;
}
rad = sqrt((-2*log(rad))/rad);
nextresult = sam2 * rad;
parity = 1;
return (sam1 * rad * std + avg);
}
else {
parity = 0;
return (nextresult * std + avg);
}
}
#ifndef stand_alone
int
RNG::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "testint") == 0) {
int n = atoi(argv[2]);
tcl.resultf("%d", uniform(n));
return (TCL_OK);
}
if (strcmp(argv[1], "testdouble") == 0) {
double d = atof(argv[2]);
tcl.resultf("%6e", uniform(d));
return (TCL_OK);
}
if (strcmp(argv[1], "seed") == 0) {
int s = atoi(argv[2]);
// NEEDSWORK: should be a way to set seed to PRDEF_SEED_SORUCE
if (s) {
if (s <= 0 || (unsigned int)s >= MAXINT) {
tcl.resultf("Setting random number seed to known bad value.");
return TCL_ERROR;
};
set_seed(RAW_SEED_SOURCE, s);
} else set_seed(HEURISTIC_SEED_SOURCE, 0);
return(TCL_OK);
}
} else if (argc == 2) {
if (strcmp(argv[1], "next-random") == 0) {
tcl.resultf("%u", uniform_positive_int());
return(TCL_OK);
}
if (strcmp(argv[1], "seed") == 0) {
tcl.resultf("%u", stream_.seed());
return(TCL_OK);
}
if (strcmp(argv[1], "default") == 0) {
default_ = this;
return(TCL_OK);
}
#if 0
if (strcmp(argv[1], "test") == 0) {
if (test())
tcl.resultf("RNG test failed");
else
tcl.resultf("RNG test passed");
return(TCL_OK);
}
#endif
} else if (argc == 4) {
if (strcmp(argv[1], "normal") == 0) {
double avg = strtod(argv[2], NULL);
double std = strtod(argv[3], NULL);
tcl.resultf("%g", normal(avg, std));
return (TCL_OK);
} else if (strcmp(argv[1], "lognormal") == 0) {
double avg = strtod(argv[2], NULL);
double std = strtod(argv[3], NULL);
tcl.resultf("%g", lognormal(avg, std));
return (TCL_OK);
}
}
return(TclObject::command(argc, argv));
}
#endif /* stand_alone */
void
RNG::set_seed(RNGSources source, int seed)
{
/* The following predefined seeds are evenly spaced around
* the 2^31 cycle. Each is approximately 33,000,000 elements
* apart.
*/
#define N_SEEDS_ 64
static long predef_seeds[N_SEEDS_] = {
1973272912L, 188312339L, 1072664641L, 694388766L,
2009044369L, 934100682L, 1972392646L, 1936856304L,
1598189534L, 1822174485L, 1871883252L, 558746720L,
605846893L, 1384311643L, 2081634991L, 1644999263L,
773370613L, 358485174L, 1996632795L, 1000004583L,
1769370802L, 1895218768L, 186872697L, 1859168769L,
349544396L, 1996610406L, 222735214L, 1334983095L,
144443207L, 720236707L, 762772169L, 437720306L,
939612284L, 425414105L, 1998078925L, 981631283L,
1024155645L, 822780843L, 701857417L, 960703545L,
2101442385L, 2125204119L, 2041095833L, 89865291L,
898723423L, 1859531344L, 764283187L, 1349341884L,
678622600L, 778794064L, 1319566104L, 1277478588L,
538474442L, 683102175L, 999157082L, 985046914L,
722594620L, 1695858027L, 1700738670L, 1995749838L,
1147024708L, 346983590L, 565528207L, 513791680L
};
static long heuristic_sequence = 0;
switch (source) {
case RAW_SEED_SOURCE:
// use it as it is
break;
case PREDEF_SEED_SOURCE:
if (seed < 0 || seed >= N_SEEDS_)
abort();
seed = predef_seeds[seed];
break;
case HEURISTIC_SEED_SOURCE:
timeval tv;
gettimeofday(&tv, 0);
heuristic_sequence++; // Always make sure we're different than last time.
seed = (tv.tv_sec ^ tv.tv_usec ^ (heuristic_sequence << 8)) & 0x7fffffff;
break;
};
// set it
// NEEDSWORK: should we throw out known bad seeds?
// (are there any?)
if (seed < 0)
seed = -seed;
stream_.set_seed(seed);
// Toss away the first few values of heuristic seed.
// In practice this makes sequential heuristic seeds
// generate different first values.
//
// How many values to throw away should be the subject
// of careful analysis. Until then, I just throw away
// ``a bunch''. --johnh
if (source == HEURISTIC_SEED_SOURCE) {
int i;
for (i = 0; i < 128; i++) {
stream_.next();
};
};
}
/*
* RNGTest:
* Make sure the RNG makes known values.
* Optionally, print out some stuff.
*
* Simple test program:
* #include "rng.h"
* void main() { RNGTest test; test.verbose(); }
*/
#ifdef rng_test
RNGTest::RNGTest()
{
RNG rng(RNG::RAW_SEED_SOURCE, 1L);
int i;
long r;
for (i = 0; i < 10000; i++)
r = rng.uniform_positive_int();
if (r != 1043618065L)
abort();
for (i = 10000; i < 551246; i++)
r = rng.uniform_positive_int();
if (r != 1003L)
abort();
}
void
RNGTest::first_n(RNG::RNGSources source, long seed, int n)
{
RNG rng(source, seed);
for (int i = 0; i < n; i++) {
int r = rng.uniform_positive_int();
printf("%10d ", r);
};
printf("\n");
}
void
RNGTest::verbose()
{
printf ("default: ");
first_n(RNG::RAW_SEED_SOURCE, 1L, 5);
int i;
for (i = 0; i < 64; i++) {
printf ("predef source %2d: ", i);
first_n(RNG::PREDEF_SEED_SOURCE, i, 5);
};
printf("heuristic seeds should be different from each other and on each run.\n");
for (i = 0; i < 64; i++) {
printf ("heuristic source %2d: ", i);
first_n(RNG::HEURISTIC_SEED_SOURCE, i, 5);
};
}
#endif /* rng_test */
route.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1991-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 University of
* California, Berkeley and the Network Research 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.
*
* Routing code for general topologies based on min-cost routing algorithm in
* Bertsekas' book. Written originally by S. Keshav, 7/18/88
* (his work covered by identical UC Copyright)
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
#include
#include
#include "config.h"
#include "route.h"
#include "address.h"
class RouteLogicClass : public TclClass {
public:
RouteLogicClass() : TclClass("RouteLogic") {}
TclObject* create(int, const char*const*) {
return (new RouteLogic());
}
} routelogic_class;
void RouteLogic::reset_all()
{
delete[] adj_;
delete[] route_;
adj_ = 0;
route_ = 0;
size_ = 0;
}
int RouteLogic::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "compute") == 0) {
if (adj_ == 0) {
//fprintf(stderr, "No adjacency info; Probably a disconnected topology! Route not computed..\n");
return (TCL_OK);
}
compute_routes();
return (TCL_OK);
}
if (strcmp(argv[1], "hier-compute") == 0) {
if (hadj_ == 0) {
return (TCL_OK);
}
hier_compute();
return (TCL_OK);
}
if (strcmp(argv[1], "hier-print") == 0) {
hier_print_hadj();
return (TCL_OK);
}
if (strcmp(argv[1], "hier-print-route") == 0) {
hier_print_route();
return (TCL_OK);
}
if (strcmp(argv[1], "reset") == 0) {
reset_all();
return (TCL_OK);
}
}
else if (argc > 2) {
if (strcmp(argv[1], "insert") == 0) {
int src = atoi(argv[2]) + 1;
int dst = atoi(argv[3]) + 1;
if (src <= 0 || dst <= 0) {
tcl.result("negative node number");
return (TCL_ERROR);
}
double cost = (argc == 5 ? atof(argv[4]) : 1);
insert(src, dst, cost);
return (TCL_OK);
}
if (strcmp(argv[1], "hlevel-is") == 0) {
level_ = atoi(argv[2]);
if (level_ < 1) {
tcl.result("send-hlevel: # hierarchy levels should be non-zero");
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "send-num-of-domains") == 0) {
D_ = atoi(argv[2]) + 1;
if (D_ <= 1) {
tcl.result("send-num-of-domains: # domains should be non-zero");
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "send-num-of-clusters") == 0) {
if (argc != D_ + 1) {
tcl.result("send-num-of-clusters: # args do not match as expected\n");
return (TCL_ERROR);
}
C_ = new int[D_];
int i, j = 2;
for (i = 1; i < D_; i++) {
C_[i] = atoi(argv[j]) + 1;
j++;
}
hier_init();
return (TCL_OK);
}
if(strcmp(argv[1], "send-num-of-nodes") == 0) {
int i, j, k=2, Ctotal=0 ;
for (i=1; i < D_; i++)
Ctotal = Ctotal + (C_[i]-1);
if (argc != (Ctotal + 2)) {
tcl.result("send-hlastdata: # args do not match");
return (TCL_ERROR);
}
for (i=1; i < D_; i++)
for (j=1; (j < C_[i]); j++) {
cluster_size_[INDEX(i, j, Cmax_)] = atoi(argv[k]);
k++;
}
return (TCL_OK);
}
if (strcmp(argv[1], "hier-insert") == 0) {
if(Cmax_== 0 || D_== 0) {
tcl.result("Required Hier_data not sent");
return (TCL_ERROR);
}
int i;
int src_addr[SMALL_LEN], dst_addr[SMALL_LEN];
/* initializing src and dst addr */
// for (i=0; i < SMALL_LEN; i++){
// src_addr[i] = 0;
// dst_addr[i] = 0;
// }
str2address(argv, src_addr, dst_addr);
// for (i=0; i < HIER_LEVEL; i++)
for (i=0; i < level_; i++)
if (src_addr[i]<=0 || dst_addr[i]<=0){
tcl.result ("negative node number");
return (TCL_ERROR);
}
int cost = (argc == 5 ? atoi(argv[4]) : 1);
hier_insert(src_addr, dst_addr, cost);
return (TCL_OK);
}
if (strcmp(argv[1], "hier-reset") == 0) {
int i;
int src_addr[SMALL_LEN], dst_addr[SMALL_LEN];
str2address(argv, src_addr, dst_addr);
// assuming node-node addresses (instead of node-cluster or node-domain pair)
// are sent for hier_reset
// for (i=0; i < HIER_LEVEL; i++)
for (i=0; i < level_; i++)
if (src_addr[i]<=0 || dst_addr[i]<=0){
tcl.result ("negative node number");
return (TCL_ERROR);
}
hier_reset(src_addr, dst_addr);
}
if (strcmp(argv[1], "hier-lookup") == 0) {
int nh;
int res = lookup_hier((char*)argv[2], (char*)argv[3],
nh);
return res;
}
if (strcmp(argv[1], "reset") == 0) {
int src = atoi(argv[2]) + 1;
int dst = atoi(argv[3]) + 1;
if (src <= 0 || dst <= 0) {
tcl.result("negative node number");
return (TCL_ERROR);
}
reset(src, dst);
return (TCL_OK);
}
if (strcmp(argv[1], "lookup") == 0) {
int nh;
int res = lookup_flat((char*)argv[2], (char*)argv[3],
nh);
if (res == TCL_OK)
tcl.resultf("%d", nh);
return res;
}
}
return (TclObject::command(argc, argv));
}
// xxx: using references as in this result is bogus---use pointers!
int RouteLogic::lookup_flat(char* asrc, char* adst, int& result) {
Tcl& tcl = Tcl::instance();
int src = atoi(asrc) + 1;
int dst = atoi(adst) + 1;
if (route_ == 0) {
// routes are computed only after the simulator is running
// ($ns run).
tcl.result("routes not yet computed");
return (TCL_ERROR);
}
if (src >= size_ || dst >= size_) {
tcl.result("node out of range");
return (TCL_ERROR);
}
result = route_[INDEX(src, dst, size_)].next_hop - 1;
return TCL_OK;
}
// xxx: using references as in this result is bogus---use pointers!
int RouteLogic::lookup_hier(char* asrc, char* adst, int& result) {
int i;
int src[SMALL_LEN], dst[SMALL_LEN];
Tcl& tcl = Tcl::instance();
if ( hroute_ == 0) {
tcl.result("Required Hier_data not sent");
return TCL_ERROR;
}
ns_strtok(asrc, src);
ns_strtok(adst, dst);
for (i=0; i < level_; i++)
if (src[i] <= 0) {
tcl.result("negative src node number");
return TCL_ERROR;
}
if (dst[0] <= 0) {
tcl.result("negative dst domain number");
return TCL_ERROR;
}
int d = src[0];
int index = INDEX(src[0], src[1], Cmax_);
int size = cluster_size_[index];
if (hsize_[index] == 0) {
tcl.result("Routes not computed");
return TCL_ERROR;
}
if ((src[0] < D_) || (dst[0] < D_)) {
if((src[1] < C_[d]) || (dst[1] < C_[dst[0]]))
if((src[2] <= size) ||
(dst[2] <= cluster_size_[INDEX(dst[0], dst[1], Cmax_)]))
;
}
else {
tcl.result("node out of range");
return TCL_ERROR;
}
int next_hop = 0;
/* if node-domain lookup */
if (((dst[1] <= 0) && (dst[2] <= 0)) ||
(src[0] != dst[0])){
next_hop = hroute_[index][N_D_INDEX(src[2], dst[0], size, C_[d], D_)];
}
/* if node-cluster lookup */
else if ((dst[2] <= 0) || (src[1] != dst[1])) {
next_hop = hroute_[index][N_C_INDEX(src[2], dst[1], size, C_[d], D_)];
}
/* if node-node lookup */
else {
next_hop = hroute_[index][N_N_INDEX(src[2], dst[2], size, C_[d], D_)];
}
char target[SMALL_LEN];
if (next_hop > 0) {
get_address(target, next_hop, index, d, size, src);
tcl.result(target);
result= Address::instance().str2addr(target);
} else {
tcl.result("-1");
result = -1;
}
return TCL_OK;
}
RouteLogic::RouteLogic()
{
size_ = 0;
adj_ = 0;
route_ = 0;
/* additions for hierarchical routing extension */
C_ = 0;
D_ = 0;
Cmax_ = 0;
level_ = 0;
hsize_ = 0;
hadj_ = 0;
hroute_ = 0;
hconnect_ = 0;
cluster_size_ = 0;
}
RouteLogic::~RouteLogic()
{
delete[] adj_;
delete[] route_;
for (int i = 0; i < (Cmax_ * D_); i++) {
for (int j = 0; j < (Cmax_ + D_) * (cluster_size_[i]+1); j++) {
if (hconnect_[i][j] != NULL)
delete [] hconnect_[i][j];
}
delete [] hconnect_[i];
}
for (int n =0; n < (Cmax_ * D_); n++) {
if (hadj_[n] != NULL)
delete [] hadj_[n];
if (hroute_[n] != NULL)
delete [] hroute_[n];
}
delete [] C_;
delete [] hsize_;
delete [] cluster_size_;
delete hadj_;
delete hroute_;
delete hconnect_;
}
void RouteLogic::alloc(int n)
{
size_ = n;
n *= n;
adj_ = new adj_entry[n];
for (int i = 0; i < n; ++i) {
adj_[i].cost = INFINITY;
adj_[i].entry = 0;
}
}
/*
* Check that we have enough storage in the adjacency array
* to hold a node numbered "n"
*/
void RouteLogic::check(int n)
{
if (n < size_)
return;
adj_entry* old = adj_;
int osize = size_;
int m = osize;
if (m == 0)
m = 16;
while (m <= n)
m <<= 1;
alloc(m);
for (int i = 0; i < osize; ++i) {
for (int j = 0; j < osize; ++j)
adj_[INDEX(i, j, m)].cost =old[INDEX(i, j, osize)].cost;
}
size_ = m;
delete[] old;
}
void RouteLogic::insert(int src, int dst, double cost)
{
check(src);
check(dst);
adj_[INDEX(src, dst, size_)].cost = cost;
}
void RouteLogic::insert(int src, int dst, double cost, void* entry_)
{
check(src);
check(dst);
adj_[INDEX(src, dst, size_)].cost = cost;
adj_[INDEX(src, dst, size_)].entry = entry_;
}
void RouteLogic::reset(int src, int dst)
{
assert(src < size_);
assert(dst < size_);
adj_[INDEX(src, dst, size_)].cost = INFINITY;
}
void RouteLogic::compute_routes()
{
int n = size_;
int* parent = new int[n];
double* hopcnt = new double[n];
#define ADJ(i, j) adj_[INDEX(i, j, size_)].cost
#define ADJ_ENTRY(i, j) adj_[INDEX(i, j, size_)].entry
#define ROUTE(i, j) route_[INDEX(i, j, size_)].next_hop
#define ROUTE_ENTRY(i, j) route_[INDEX(i, j, size_)].entry
delete[] route_;
route_ = new route_entry[n * n];
memset((char *)route_, 0, n * n * sizeof(route_[0]));
/* do for all the sources */
int k;
for (k = 1; k < n; ++k) {
int v;
for (v = 0; v < n; v++)
parent[v] = v;
/* set the route for all neighbours first */
for (v = 1; v < n; ++v) {
if (parent[v] != k) {
hopcnt[v] = ADJ(k, v);
if (hopcnt[v] != INFINITY) {
ROUTE(k, v) = v;
ROUTE_ENTRY(k, v) = ADJ_ENTRY(k, v);
}
}
}
for (v = 1; v < n; ++v) {
/*
* w is the node that is the nearest to the subtree
* that has been routed
*/
int o = 0;
/* XXX */
hopcnt[0] = INFINITY;
int w;
for (w = 1; w < n; w++)
if (parent[w] != k && hopcnt[w] < hopcnt[o])
o = w;
parent[o] = k;
/*
* update distance counts for the nodes that are
* adjacent to o
*/
if (o == 0)
continue;
for (w = 1; w < n; w++) {
if (parent[w] != k &&
hopcnt[o] + ADJ(o, w) < hopcnt[w]) {
ROUTE(k, w) = ROUTE(k, o);
ROUTE_ENTRY(k, w) =
ROUTE_ENTRY(k, o);
hopcnt[w] = hopcnt[o] + ADJ(o, w);
}
}
}
}
/*
* The route to yourself is yourself.
*/
for (k = 1; k < n; ++k) {
ROUTE(k, k) = k;
ROUTE_ENTRY(k, k) = 0; // This should not matter
}
delete[] hopcnt;
delete[] parent;
}
/* hierarchical routing support */
/* This function creates adjacency matrix for each cluster at the lowest level of the hierarchy for every node in the cluster, for every other cluster in the domain, and every other domain. can be extended from 3-level hierarchy to n-level along similar lines*/
void RouteLogic::hier_alloc(int i)
{
hsize_[i] = cluster_size_[i]+ Cmax_+ D_ ;
hsize_[i] *= hsize_[i];
hadj_[i] = new int[hsize_[i]];
hroute_[i] = new int[hsize_[i]];
hconnect_[i] = new char*[(Cmax_ + D_) * (cluster_size_[i]+1)];
for (int n = 0; n < hsize_[i]; n++){
hadj_[i][n] = INFINITY;
hroute_[i][n] = INFINITY;
}
}
void RouteLogic::hier_check(int i)
{
if(hsize_[i] > 0)
return;
else
hier_alloc(i);
}
void RouteLogic::hier_init(void)
{
int i;
for (i = 1; i < D_; i++) {
Cmax_ = C_[i] > Cmax_ ? C_[i]: Cmax_;
}
int arr_size = Cmax_ * D_ ;
cluster_size_ = new int[arr_size];
hsize_ = new int[arr_size];
for (i = 0; i < arr_size; i++)
hsize_[i] = 0;
hadj_ = new int*[arr_size];
hroute_ = new int*[arr_size];
hconnect_ = new char**[arr_size];
}
void RouteLogic::str2address(const char*const* argv, int *src_addr, int *dst_addr)
{
char src[SMALL_LEN];
char dst[SMALL_LEN];
strcpy(src, argv[2]);
strcpy(dst, argv[3]);
ns_strtok(src, src_addr);
ns_strtok(dst, dst_addr);
}
void RouteLogic::ns_strtok(char *addr, int *addrstr)
{
int i;
char tmpstr[SMALL_LEN];
char *next, *index;
i = 0;
strcpy(tmpstr, addr);
next = tmpstr;
while(*next){
index = strstr(next, ".");
if (index != NULL){
next[index - next] = '\0';
addrstr[i] = atoi(next) + 1;
next = index + 1;
i++;
}
else {
if (*next != '\0') //damn that ending point
addrstr[i] = atoi(next) + 1;
break;
}
}
}
void RouteLogic::get_address(char *address, int next_hop, int index, int d, int size, int *src)
{
if (next_hop <= size) {
sprintf(address,"%d.%d.%d", src[0]-1, src[1]-1, next_hop-1);
}
else if ((next_hop > size) && (next_hop < (size + C_[d]))) {
int temp = next_hop - size;
int I = src[2] * (C_[d] + D_) + temp;
strcpy(address, hconnect_[index][I]);
}
else {
int temp = next_hop - size - (C_[d] - 1);
int I = src[2] * (C_[d] + D_) + (C_[d] - 1 + temp);
strcpy(address,hconnect_[index][I]);
}
}
void RouteLogic::hier_reset(int *src, int *dst)
{
int i, d, n;
d = src[0];
if (src[0] == dst[0])
if (src[1] == dst[1]) {
i = INDEX(src[0], src[1], Cmax_);
n = cluster_size_[i];
hadj_[i][N_N_INDEX(src[2], dst[2], n, C_[d], D_)] = INFINITY;
}
else {
for (int y=1; y < C_[d]; y++) {
i = INDEX(src[0], y, Cmax_);
n = cluster_size_[i];
hadj_[i][C_C_INDEX(src[1], dst[1], n, C_[d], D_)] = INFINITY;
if (y == src[1])
hadj_[i][N_C_INDEX(src[2], dst[1], n, C_[d], D_)] = INFINITY;
}
}
else {
for (int x=1; x < D_; x++)
for (int y=1; y < C_[x]; y++) {
i = INDEX(x, y, Cmax_);
n = cluster_size_[i];
hadj_[i][D_D_INDEX(src[0], dst[0], n, C_[x], D_)] = INFINITY;
if ( x == src[0] ){
hadj_[i][C_D_INDEX(src[1], dst[0], n, C_[x], D_)] = INFINITY;
if (y == src[1])
hadj_[i][N_D_INDEX(src[2], dst[0], n, C_[x], D_)] = INFINITY;
}
}
}
}
void RouteLogic::hier_insert(int *src_addr, int *dst_addr, int cost)
{
int X1 = src_addr[0];
int Y1 = src_addr[1];
int Z1 = src_addr[2];
int X2 = dst_addr[0];
int Y2 = dst_addr[1];
int Z2 = dst_addr[2];
int n, i;
if ( X1 == X2)
if (Y1 == Y2){
/*
* For the same domain & cluster
*/
i = INDEX(X1, Y1, Cmax_);
n = cluster_size_[i];
hier_check(i);
hadj_[i][N_N_INDEX(Z1, Z2, n, C_[X1], D_)] = cost;
}
else {
/*
* For the same domain but diff clusters
*/
for (int y=1; y < C_[X1]; y++) { /* insert cluster connectivity */
i = INDEX(X1, y, Cmax_);
n = cluster_size_[i];
hier_check(i);
hadj_[i][C_C_INDEX(Y1, Y2, n, C_[X1], D_)] = cost;
if (y == Y1) { /* insert node conn. */
hadj_[i][N_C_INDEX(Z1, Y2, n, C_[X1], D_)] = cost;
int I = Z1 * (C_[X1]+ D_) + Y2;
hconnect_[i][I] = new char[SMALL_LEN];
sprintf(hconnect_[i][I],"%d.%d.%d",X2-1,Y2-1,Z2-1);
}
}
}
else {
/*
* For different domains
*/
for (int x=1; x < D_; x++) { /* inset domain connectivity */
for (int y=1; y < C_[x]; y++) {
i = INDEX(x, y, Cmax_);
n = cluster_size_[i];
hier_check(i);
hadj_[i][D_D_INDEX(X1, X2, n, C_[x], D_)] = cost;
}
}
for (int y=1; y < C_[X1]; y++) { /* insert cluster connectivity */
i = INDEX(X1, y, Cmax_);
n = cluster_size_[i];
hier_check(i);
hadj_[i][C_D_INDEX(Y1, X2, n, C_[X1], D_)] = cost;
}
/* insert node connectivity */
i = INDEX(X1, Y1, Cmax_);
n = cluster_size_[i];
hadj_[i][N_D_INDEX(Z1, X2, n, C_[X1], D_)] = cost;
int I = Z1 * (C_[X1] + D_) + (C_[X1] - 1 + X2);
hconnect_[i][I] = new char[SMALL_LEN];
sprintf(hconnect_[i][I],"%d.%d.%d",X2-1,Y2-1,Z2-1);
}
}
void RouteLogic::hier_compute_routes(int i, int j)
{
int size = (cluster_size_[i] + C_[j] + D_);
int n = size ;
double* hopcnt = new double[n];
#define HADJ(i, j) adj_[INDEX(i, j, size)].cost
#define HROUTE(i, j) route_[INDEX(i, j, size)].next_hop
delete[] route_;
route_ = new route_entry[n * n];
int* parent = new int[n];
memset((char *)route_, 0, n * n * sizeof(route_[0]));
/* do for all the sources */
int k;
for (k = 1; k < n; ++k) {
int v;
for (v = 0; v < n; v++)
parent[v] = v;
/* set the route for all neighbours first */
for (v = 1; v < n; ++v) {
if (parent[v] != k) {
hopcnt[v] = HADJ(k, v);
if (hopcnt[v] != INFINITY)
HROUTE(k, v) = v;
}
}
for (v = 1; v < n; ++v) {
/*
* w is the node that is the nearest to the subtree
* that has been routed
*/
int o = 0;
/* XXX */
hopcnt[0] = INFINITY;
int w;
for (w = 1; w < n; w++)
if (parent[w] != k && hopcnt[w] < hopcnt[o])
o = w;
parent[o] = k;
/*
* update distance counts for the nodes that are
* adjacent to o
*/
if (o == 0)
continue;
for (w = 1; w < n; w++) {
if (parent[w] != k &&
hopcnt[o] + HADJ(o, w) < hopcnt[w]) {
HROUTE(k, w) = HROUTE(k, o);
hopcnt[w] = hopcnt[o] + HADJ(o, w);
}
}
}
}
/*
* The route to yourself is yourself.
*/
for (k = 1; k < n; ++k)
HROUTE(k, k) = k;
delete[] hopcnt;
delete[] parent;
}
/* function to check the adjacency matrices created */
void RouteLogic::hier_print_hadj() {
int i, j, k;
for (j=1; j < D_; j++)
for (k=1; k < C_[j]; k++) {
i = INDEX(j, k, Cmax_);
int s = (cluster_size_[i] + C_[j] + D_);
printf("ADJ MATRIX[%d] for cluster %d.%d :\n",i,j,k);
int temp = 1;
printf(" ");
while(temp < s){
printf(" %d",temp);
temp++;
}
printf("\n");
for(int n=1; n < s;n++){
printf("%d ",n);
for(int m=1;m < s;m++){
if(hadj_[i][INDEX(n,m,s)] == INFINITY)
printf("~ ");
else
printf("%d ",hadj_[i][INDEX(n,m,s)]);
}
printf("\n");
}
printf("\n\n");
}
}
void RouteLogic::hier_compute()
{
int i, j, k, m, n;
for (j=1; j < D_; j++)
for (k=1; k < C_[j]; k++) {
i = INDEX(j, k, Cmax_);
int s = (cluster_size_[i] + C_[j] + D_);
adj_ = new adj_entry[(s * s)];
memset((char *)adj_, 0, s * s * sizeof(adj_[0]));
for (n=0; n < s; n++)
for(m=0; m < s; m++)
adj_[INDEX(n, m, s)].cost = hadj_[i][INDEX(n, m, s)];
hier_compute_routes(i, j);
for (n=0; n < s; n++)
for(m=0; m < s; m++)
hroute_[i][INDEX(n, m, s)] = route_[INDEX(n, m, s)].next_hop;
delete [] adj_;
}
}
/*
* Prints routing table - debugging function
*/
void RouteLogic::hier_print_route()
{
for (int j=1; j < D_; j++)
for (int k=1; k < C_[j]; k++) {
int i = INDEX(j, k, Cmax_);
int s = (cluster_size_[i]+C_[j]+D_);
printf("ROUTE_TABLE[%d] for cluster %d.%d :\n",i,j,k);
int temp = 1;
printf(" ");
while(temp < s){
printf(" %d",temp);
temp++;
}
printf("\n");
for(int n=1; n < s; n++){
printf("%d ",n);
for(int m=1; m < s; m++)
printf("%d ",hroute_[i][INDEX(n, m, s)]);
printf("\n");
}
printf("\n\n");
}
}
static class RouteLogicAlgoClass : public TclClass {
public:
RouteLogicAlgoClass() : TclClass("RouteLogic/Algorithmic") {}
TclObject* create(int, const char*const*) {
return (new RouteLogicAlgo);
}
} class_routelogic_algo;
rtProtoDV.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* rtProtoDV.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 "agent.h"
#include "rtProtoDV.h"
int hdr_DV::offset_;
static class rtDVHeaderClass : public PacketHeaderClass {
public:
rtDVHeaderClass() : PacketHeaderClass("PacketHeader/rtProtoDV",
sizeof(hdr_DV)) {
bind_offset(&hdr_DV::offset_);
}
} class_rtProtoDV_hdr;
static class rtProtoDVclass : public TclClass {
public:
rtProtoDVclass() : TclClass("Agent/rtProto/DV") {}
TclObject* create(int, const char*const*) {
return (new rtProtoDV);
}
} class_rtProtoDV;
int rtProtoDV::command(int argc, const char*const* argv)
{
if (strcmp(argv[1], "send-update") == 0) {
ns_addr_t dst;
dst.addr_ = atoi(argv[2]);
dst.port_ = atoi(argv[3]);
u_int32_t mtvar = atoi(argv[4]);
u_int32_t size = atoi(argv[5]);
sendpkt(dst, mtvar, size);
return TCL_OK;
}
return Agent::command(argc, argv);
}
void rtProtoDV::sendpkt(ns_addr_t dst, u_int32_t mtvar, u_int32_t size)
{
daddr() = dst.addr_;
dport() = dst.port_;
size_ = size;
Packet* p = Agent::allocpkt();
hdr_DV *rh = (hdr_DV*)p->access(off_DV_);
rh->metricsVar() = mtvar;
target_->recv(p);
}
void rtProtoDV::recv(Packet* p, Handler*)
{
hdr_DV* rh = (hdr_DV*)p->access(off_DV_);
hdr_ip* ih = (hdr_ip*)p->access(off_ip_);
Tcl::instance().evalf("%s recv-update %d %d", name(),
ih->saddr(), rh->metricsVar());
Packet::free(p);
}
rtcp.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
#include "config.h"
#include "agent.h"
#include "random.h"
#include "rtp.h"
class RTCPAgent;
class RTCP_Timer : public TimerHandler {
public:
RTCP_Timer(RTCPAgent *a) : TimerHandler() { a_ = a; }
protected:
virtual void expire(Event *e);
RTCPAgent *a_;
};
class RTCPAgent : public Agent {
public:
RTCPAgent();
virtual void timeout(int);
virtual void recv(Packet* p, Handler* h);
int command(int argc, const char*const* argv);
protected:
void start();
void stop();
void sendpkt();
int running_;
int random_;
int seqno_;
double interval_;
RTPSession* session_;
int off_rtp_;
RTCP_Timer rtcp_timer_;
};
static class RTCPAgentClass : public TclClass {
public:
RTCPAgentClass() : TclClass("Agent/RTCP") {}
TclObject* create(int, const char*const*) {
return (new RTCPAgent());
}
} class_rtcp_agent;
/* XXX Could perhaps derive this from CBR. If so, use cbr_timer_ */
RTCPAgent::RTCPAgent()
: Agent(PT_RTCP), session_(0), rtcp_timer_(this)
{
size_ = 128;
bind_time("interval_", &interval_);
bind("random_", &random_);
bind("seqno_", &seqno_);
bind("off_rtp_", &off_rtp_);
running_ = 0;
}
void RTCPAgent::start()
{
running_ = 1;
rtcp_timer_.resched(interval_);
}
void RTCPAgent::stop()
{
rtcp_timer_.cancel();
running_ = 0;
}
void RTCPAgent::recv(Packet* p, Handler*)
{
session_->recv_ctrl(p);
}
void RTCPAgent::sendpkt()
{
Packet* p = allocpkt();
hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);
/* Fill in srcid_ and seqno */
rh->seqno() = seqno_++;
rh->srcid() = session_->srcid();
target_->recv(p);
}
void RTCPAgent::timeout(int)
{
if (running_) {
size_ = session_->build_report(0);
sendpkt();
double t = interval_;
if (random_)
/* add some zero-mean white noise */
t += interval_ * Random::uniform(-0.5, 0.5);
rtcp_timer_.resched(t);
/* XXX */
Tcl::instance().evalf("%s rtcp_timeout", session_->name());
}
}
int RTCPAgent::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "start") == 0) {
start();
return (TCL_OK);
}
if (strcmp(argv[1], "stop") == 0) {
stop();
return (TCL_OK);
}
if (strcmp(argv[1], "bye") == 0) {
size_ = session_->build_report(1);
sendpkt();
stop();
return (TCL_OK);
}
} else if (argc == 3) {
if (strcmp(argv[1], "session") == 0) {
session_ = (RTPSession*)TclObject::lookup(argv[2]);
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
void RTCP_Timer::expire(Event* /*e*/) {
a_->timeout(0);
}
rtp.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
#include "config.h"
#include "agent.h"
#include "random.h"
#include "rtp.h"
int hdr_rtp::offset_;
class RTPHeaderClass : public PacketHeaderClass {
public:
RTPHeaderClass() : PacketHeaderClass("PacketHeader/RTP",
sizeof(hdr_rtp)) {
bind_offset(&hdr_rtp::offset_);
}
} class_rtphdr;
static class RTPAgentClass : public TclClass {
public:
RTPAgentClass() : TclClass("Agent/RTP") {}
TclObject* create(int, const char*const*) {
return (new RTPAgent());
}
} class_rtp_agent;
RTPAgent::RTPAgent() : Agent(PT_RTP), session_(0), lastpkttime_(-1e6),
running_(0), rtp_timer_(this)
{
bind("seqno_", &seqno_);
bind("off_rtp_", &off_rtp_);
bind_time("interval_", &interval_);
bind("packetSize_", &size_);
bind("maxpkts_", &maxpkts_);
bind("random_", &random_);
}
void RTPAgent::start()
{
running_ = 1;
sendpkt();
rtp_timer_.resched(interval_);
}
void RTPAgent::stop()
{
rtp_timer_.force_cancel();
finish();
}
void RTPAgent::sendmsg(int nbytes, const char* /*flags*/)
{
Packet *p;
int n;
if (++seqno_ < maxpkts_) {
if (size_)
n = nbytes / size_;
else
printf("Error: RTPAgent size = 0\n");
if (nbytes == -1) {
start();
return;
}
while (n-- > 0) {
p = allocpkt();
hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);
rh->seqno() = seqno_;
target_->recv(p);
}
n = nbytes % size_;
if (n > 0) {
p = allocpkt();
hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);
rh->seqno() = seqno_;
target_->recv(p);
}
idle();
} else {
finish();
// xxx: should we deschedule the timer here? */
};
}
void RTPAgent::timeout(int)
{
if (running_) {
sendpkt();
if (session_)
session_->localsrc_update(size_);
double t = interval_;
if (random_)
/* add some zero-mean white noise */
t += interval_ * Random::uniform(-0.5, 0.5);
rtp_timer_.resched(t);
}
}
/*
* finish() is called when we must stop (either by request or because
* we're out of packets to send.
*/
void RTPAgent::finish()
{
running_ = 0;
Tcl::instance().evalf("%s done", this->name());
}
void RTPAgent::advanceby(int delta)
{
maxpkts_ += delta;
if (seqno_ < maxpkts_ && !running_)
start();
}
void RTPAgent::recv(Packet* p, Handler*)
{
if (session_)
session_->recv(p, 0);
else
Packet::free(p);
}
int RTPAgent::command(int argc, const char*const* argv)
{
if (argc == 2) {
if (strcmp(argv[1], "rate-change") == 0) {
rate_change();
return (TCL_OK);
} else if (strcmp(argv[1], "start") == 0) {
start();
return (TCL_OK);
} else if (strcmp(argv[1], "stop") == 0) {
stop();
return (TCL_OK);
}
} else if (argc == 3) {
if (strcmp(argv[1], "session") == 0) {
session_ = (RTPSession*)TclObject::lookup(argv[2]);
return (TCL_OK);
} else if (strcmp(argv[1], "advance") == 0) {
int newseq = atoi(argv[2]);
advanceby(newseq - seqno_);
return (TCL_OK);
} else if (strcmp(argv[1], "advanceby") == 0) {
advanceby(atoi(argv[2]));
return (TCL_OK);
}
}
return (Agent::command(argc, argv));
}
/*
* We modify the rate in this way to get a faster reaction to the a rate
* change since a rate change from a very low rate to a very fast rate may
* take an undesireably long time if we have to wait for timeout at the old
* rate before we can send at the new (faster) rate.
*/
void RTPAgent::rate_change()
{
rtp_timer_.force_cancel();
double t = lastpkttime_ + interval_;
double now = Scheduler::instance().clock();
if ( t > now)
rtp_timer_.resched(t - now);
else {
sendpkt();
rtp_timer_.resched(interval_);
}
}
void RTPAgent::sendpkt()
{
Packet* p = allocpkt();
lastpkttime_ = Scheduler::instance().clock();
makepkt(p);
target_->recv(p, (Handler*)0);
}
void RTPAgent::makepkt(Packet* p)
{
hdr_rtp *rh = (hdr_rtp*)p->access(off_rtp_);
/* Fill in srcid_ and seqno */
rh->seqno() = seqno_++;
rh->srcid() = session_ ? session_->srcid() : 0;
}
void RTPTimer::expire(Event* /*e*/) {
a_->timeout(0);
}
rtqueue.cc
#include
#include
#include
#define CURRENT_TIME Scheduler::instance().clock()
#define DEBUG
/* ======================================================================
Packet Queue used by TORA and AODV.
===================================================================== */
rtqueue::rtqueue()
{
head_ = tail_ = 0;
len_ = 0;
limit_ = RTQ_MAX_LEN;
timeout_ = RTQ_TIMEOUT;
}
void
rtqueue::enque(Packet *p)
{
struct hdr_cmn *ch = HDR_CMN(p);
p->next_ = 0;
ch->ts_ = CURRENT_TIME + timeout_;
if (len_ == limit_) {
Packet *p0 = remove_head(); // decrements len_
assert(p0);
if(HDR_CMN(p0)->ts_ > CURRENT_TIME) {
drop(p0, DROP_RTR_QFULL);
}
else {
drop(p0, DROP_RTR_QTIMEOUT);
}
}
if(head_ == 0) {
head_ = tail_ = p;
}
else {
tail_->next_ = p;
tail_ = p;
}
len_++;
#ifdef DEBUG
verifyQueue();
#endif
}
Packet*
rtqueue::deque()
{
Packet *p;
/*
* Purge any packets that have timed out.
*/
purge();
p = remove_head();
#ifdef DEBUG
verifyQueue();
#endif
return p;
}
Packet*
rtqueue::deque(nsaddr_t dst)
{
Packet *p, *prev;
/*
* Purge any packets that have timed out.
*/
purge();
findPacketWithDst(dst, p, prev);
assert(p == 0 || (p == head_ && prev == 0) || (prev->next_ == p));
if(p == 0) return 0;
if (p == head_) {
p = remove_head();
}
else if (p == tail_) {
prev->next_ = 0;
tail_ = prev;
len_--;
}
else {
prev->next_ = p->next_;
len_--;
}
#ifdef DEBUG
verifyQueue();
#endif
return p;
}
char
rtqueue::find(nsaddr_t dst)
{
Packet *p, *prev;
findPacketWithDst(dst, p, prev);
if (0 == p)
return 0;
else
return 1;
}
/* ======================================================================
Private Routines
====================================================================== */
Packet*
rtqueue::remove_head()
{
Packet *p = head_;
if(head_ == tail_) {
head_ = tail_ = 0;
}
else {
head_ = head_->next_;
}
if(p) len_--;
return p;
}
void
rtqueue::purge()
{
Packet *p;
while((p = head_) && HDR_CMN(p)->ts_ < CURRENT_TIME) {
assert(p == remove_head());
drop(p, DROP_RTR_QTIMEOUT);
}
}
void
rtqueue::findPacketWithDst(nsaddr_t dst, Packet*& p, Packet*& prev)
{
p = prev = 0;
for(p = head_; p; p = p->next_) {
// if(HDR_IP(p)->dst() == dst) {
if(HDR_IP(p)->daddr() == dst) {
return;
}
prev = p;
}
if(p == 0) prev = 0; // not found
}
void
rtqueue::verifyQueue()
{
Packet *p, *prev = 0;
int cnt = 0;
for(p = head_; p; p = p->next_) {
cnt++;
prev = p;
}
assert(cnt == len_);
assert(prev == tail_);
}
rttable.cc
/* The AODV code developed by the CMU/MONARCH group was optimized
* and tuned by Samir Das (UTSA) and Mahesh Marina (UTSA). The
* work was partially done in Sun Microsystems.
*
* The original CMU copyright is below.
*/
/*
Copyright (c) 1997, 1998 Carnegie Mellon University. All Rights
Reserved.
Permission to use, copy, modify, and distribute this
software and its documentation is hereby granted (including for
commercial or for-profit use), provided that both the copyright notice
and this permission notice appear in all copies of the software,
derivative works, or modified versions, and any portions thereof, and
that both notices appear in supporting documentation, and that credit
is given to Carnegie Mellon University in all publications reporting
on direct or indirect use of this code or its derivatives.
ALL CODE, SOFTWARE, PROTOCOLS, AND ARCHITECTURES DEVELOPED BY THE CMU
MONARCH PROJECT ARE EXPERIMENTAL AND ARE KNOWN TO HAVE BUGS, SOME OF
WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS
SOFTWARE OR OTHER INTELLECTUAL PROPERTY IN ITS ``AS IS'' CONDITION,
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 CARNEGIE MELLON UNIVERSITY
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 OR
INTELLECTUAL PROPERTY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
Carnegie Mellon encourages (but does not require) users of this
software or intellectual property to return any improvements or
extensions that they make, and to grant Carnegie Mellon the rights to
redistribute these changes without encumbrance.
*/
/* ported into VINT ns by Ya Xu, Sept. 1999 */
#include
/* =====================================================================
The Routing Table
===================================================================== */
rt_entry::rt_entry()
{
int i;
rt_dst = 0;
rt_seqno = 0;
rt_nexthop = 0;
rt_expire = 0.0;
rt_hops = INFINITY2;
rt_flags = RTF_DOWN;
rt_errors = 0;
rt_error_time = 0.0;
rt_req_timeout = 0.0;
rt_req_cnt = 0;
rt_req_last_ttl = 0;
hist_indx = 0;
for (i=0; i < MAX_HISTORY; i++) {
// rt_length[i] = 0;
rt_disc_latency[i] = 0.0;
}
error_propagate_counter = 0;
LIST_INIT(&rt_nblist);
};
rt_entry::~rt_entry()
{
Neighbor *nb;
while((nb = rt_nblist.lh_first)) {
LIST_REMOVE(nb, nb_link);
delete nb;
}
}
void
rt_entry::nb_insert(nsaddr_t id)
{
Neighbor *nb = new Neighbor(id);
assert(nb);
nb->nb_expire = 0;
LIST_INSERT_HEAD(&rt_nblist, nb, nb_link);
}
Neighbor*
rt_entry::nb_lookup(nsaddr_t id)
{
Neighbor *nb = rt_nblist.lh_first;
for(; nb; nb = nb->nb_link.le_next) {
if(nb->nb_addr == id)
break;
}
return nb;
}
/* =====================================================================
The Routing Table
===================================================================== */
rt_entry*
rttable::rt_lookup(nsaddr_t id)
{
rt_entry *rt = rthead.lh_first;
for(; rt; rt = rt->rt_link.le_next) {
if(rt->rt_dst == id)
break;
}
return rt;
}
void
rttable::rt_delete(nsaddr_t id)
{
rt_entry *rt = rt_lookup(id);
if(rt) {
LIST_REMOVE(rt, rt_link);
delete rt;
}
}
rt_entry*
rttable::rt_add(nsaddr_t id)
{
rt_entry *rt;
assert(rt_lookup(id) == 0);
rt = new rt_entry;
assert(rt);
rt->rt_dst = id;
LIST_INSERT_HEAD(&rthead, rt, rt_link);
return rt;
}
sa.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.
*/
//packets after it succeeds in a3-way handshake from the receiver
// should be connected with Agent/SignalAck class
#include "udp.h"
#include "sa.h"
#include "ip.h"
#include "random.h"
#define SAMPLERATE 8000
SA_Agent::SA_Agent() : Agent(PT_UDP), trafgen_(0), rtd_(0), callback_(0),
sa_timer_(this), nextPkttime_(-1), running_(0), seqno_(-1)
{
bind ("off_resv_",&off_resv_);
bind("off_rtp_", &off_rtp_);
bind_bw("rate_",&rate_);
bind("bucket_",&bucket_);
bind("packetSize_", &size_);
}
SA_Agent::~SA_Agent()
{
if (callback_)
delete[] callback_;
}
static class SA_AgentClass : public TclClass {
public:
SA_AgentClass() : TclClass("Agent/SA") {}
TclObject* create(int, const char*const*) {
return (new SA_Agent());
}
} class_signalsource_agent;
int SA_Agent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc==3) {
if (strcmp(argv[1], "target") == 0) {
target_ = (NsObject*)TclObject::lookup(argv[2]);
if (target_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
ctrl_target_=target_;
return (TCL_OK);
}
else if (strcmp(argv[1],"ctrl-target")== 0) {
ctrl_target_=(NsObject*)TclObject::lookup(argv[2]);
if (ctrl_target_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
if (strcmp(argv[1], "stoponidle") == 0) {
stoponidle(argv[2]);
return(TCL_OK);
}
if (strcmp(argv[1], "attach-traffic") == 0) {
trafgen_ =(TrafficGenerator*)TclObject::lookup(argv[2]);
if (trafgen_ == 0) {
tcl.resultf("no such node %s", argv[2]);
return(TCL_ERROR);
}
return(TCL_OK);
}
}
if (argc == 2) {
if (strcmp(argv[1], "start") == 0) {
start();
return(TCL_OK);
} else if (strcmp(argv[1], "stop") == 0) {
stop();
return(TCL_OK);
}
}
return (Agent::command(argc,argv));
}
void SA_Agent::start()
{
//send the request packet
if (trafgen_) {
trafgen_->init();
//running_=1;
sendreq();
}
}
void SA_Agent::stop()
{
sendteardown();
if (running_ != 0) {
sa_timer_.cancel();
running_ =0;
}
}
void SA_Agent::sendreq()
{
Packet *p = allocpkt();
hdr_cmn* ch= (hdr_cmn*)p->access(off_cmn_);
ch->ptype()=PT_REQUEST;
ch->size()=20;
//also put in the r,b parameters for the flow in the packet
hdr_resv* rv=(hdr_resv*)p->access(off_resv_);
rv->decision() =1;
rv->rate()=rate_;
rv->bucket()=bucket_;
ctrl_target_->recv(p);
}
void SA_Agent::sendteardown()
{
Packet *p = allocpkt();
hdr_cmn* ch= (hdr_cmn*)p->access(off_cmn_);
ch->ptype()=PT_TEARDOWN;
ch->size()=20;
//also put in the r,b parameters for the flow in the packet
hdr_resv* rv=(hdr_resv*)p->access(off_resv_);
rv->decision() =1;
rv->rate()=rate_;
rv->bucket()=bucket_;
ctrl_target_->recv(p);
}
void SA_Agent::recv(Packet *p, Handler *)
{
hdr_cmn *ch= (hdr_cmn *)p->access(off_cmn_);
hdr_resv *rv=(hdr_resv *)p->access(off_resv_);
hdr_ip * iph = (hdr_ip*)p->access(off_ip_);
if ( ch->ptype() == PT_ACCEPT || ch->ptype() == PT_REJECT ) {
ch->ptype() = PT_CONFIRM;
// turn the packet around by swapping src and dst
// (address and port)
ns_addr_t tmp;
tmp = iph->src();
iph->src() = iph->dst();
iph->dst() = tmp;
ctrl_target_->recv(p);
}
// put an additional check here to see if admission was granted
if (rv->decision()) {
//printf("Flow %d accepted @ %f\n",iph->flowid(),Scheduler::instance().clock());
fflush(stdout);
double t = trafgen_->next_interval(size_);
running_=1;
sa_timer_.resched(t);
}
else {
//printf("Flow %d rejected @ %f\n",iph->flowid(),Scheduler::instance().clock());
fflush(stdout);
//Currently the flow is stopped if rejected
running_=0;
}
//make an upcall to sched a stoptime for this flow from now
Tcl::instance().evalf("%s sched-stop %d",name(),rv->decision());
}
void SA_Agent::stoponidle(const char *s)
{
callback_ = new char[strlen(s)+1];
strcpy(callback_, s);
if (trafgen_->on()) {
// Tcl::instance().evalf("puts \"%s waiting for burst at %f\"", name(), Scheduler::instance().clock());
rtd_ = 1;
}
else {
stop();
Tcl::instance().evalf("%s %s", name(), callback_);
}
}
void SA_Timer::expire(Event* /*e*/) {
a_->timeout(0);
}
void SA_Agent::timeout(int)
{
if (running_) {
/* send a packet */
sendpkt();
/* figure out when to send the next one */
nextPkttime_ = trafgen_->next_interval(size_);
/* schedule it */
sa_timer_.resched(nextPkttime_);
/* hack: if we are waiting for a current burst to end
* before stopping . . .
*/
if (rtd_) {
if (trafgen_->on() == 0) {
stop();
//Tcl::instance().evalf("puts \"%s burst over at %f\"",
// name(), Scheduler::instance().clock());
Tcl::instance().evalf("%s sched-stop %d", name(), 0);
}
}
}
}
void SA_Agent::sendpkt()
{
Packet* p = allocpkt();
hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);
rh->seqno() = ++seqno_;
rh->flags()=0;
double local_time=Scheduler::instance().clock();
/*put in "rtp timestamps" and begining of talkspurt labels */
hdr_cmn* ch = (hdr_cmn*)p->access(off_cmn_);
ch->timestamp()=(u_int32_t)(SAMPLERATE*local_time);
ch->size()=size_;
if ((nextPkttime_ != trafgen_->interval()) || (nextPkttime_ == -1))
rh->flags() |= RTP_M;
target_->recv(p);
}
void SA_Agent::sendmsg(int nbytes, const char* /*flags*/)
{
Packet *p;
int n;
if (size_)
n = nbytes / size_;
else
printf("Error: SA_Agent size = 0\n");
if (nbytes == -1) {
start();
return;
}
while (n-- > 0) {
p = allocpkt();
hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);
rh->seqno() = seqno_;
target_->recv(p);
}
n = nbytes % size_;
if (n > 0) {
p = allocpkt();
hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);
rh->seqno() = seqno_;
target_->recv(p);
}
idle();
}
saack.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.
*/
//SignalAckClass
//Null receiver agent which merely acknowledges a request
#include "agent.h"
#include "ip.h"
#include "resv.h"
class SAack_Agent : public Agent {
public:
SAack_Agent();
protected:
void recv(Packet *, Handler *);
int command(int,const char* const*);
int off_resv_;
};
SAack_Agent::SAack_Agent(): Agent(PT_TCP)
{
bind("off_resv_",&off_resv_);
}
static class SAackClass : public TclClass {
public:
SAackClass() : TclClass("Agent/SAack") {}
TclObject* create(int, const char*const*) {
return (new SAack_Agent());
}
} class_saack;
void SAack_Agent::recv(Packet *p, Handler *h)
{
hdr_cmn *ch = (hdr_cmn*)p->access(off_cmn_);
if (ch->ptype() == PT_REQUEST) {
Packet *newp =allocpkt();
hdr_cmn *newch=(hdr_cmn*)newp->access(off_cmn_);
newch->size()=ch->size();
// turn the packet around by swapping src and dst
hdr_ip * iph = (hdr_ip*)p->access(off_ip_);
hdr_ip * newiph = (hdr_ip*)newp->access(off_ip_);
newiph->dst()=iph->src();
newiph->flowid()=iph->flowid();
newiph->prio()=iph->prio();
hdr_resv* rv=(hdr_resv*)p->access(off_resv_);
hdr_resv* newrv=(hdr_resv*)newp->access(off_resv_);
newrv->decision()=rv->decision();
newrv->rate()=rv->rate();
newrv->bucket()=rv->bucket();
if (rv->decision())
newch->ptype() = PT_ACCEPT;
else
newch->ptype() = PT_REJECT;
target_->recv(newp);
Packet::free(p);
return;
}
Agent::recv(p,h);
}
int SAack_Agent::command(int argc, const char*const* argv)
{
return (Agent::command(argc,argv));
}
salink.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 "packet.h"
#include "ip.h"
#include "resv.h"
#include "connector.h"
#include "adc.h"
#include "salink.h"
static class SALinkClass : public TclClass {
public:
SALinkClass() : TclClass("SALink") {}
TclObject* create(int, const char*const*) {
return (new SALink());
}
}class_salink;
SALink::SALink() : adc_(0), numfl_(-1), tchan_(0), onumfl_(0), last_(-1)
{
int i;
for (i=0;iSALink::recv(Packet *p, Handler *h)
{
int decide;
int j;
hdr_cmn *ch=(hdr_cmn*)p->access(off_cmn_);
hdr_ip *iph=(hdr_ip*)p->access(off_ip_);
hdr_resv *rv=(hdr_resv*)p->access(off_resv_);
//CLEAN THIS UP
int cl=(iph->flowid())?1:0;
switch(ch->ptype()) {
case PT_REQUEST:
decide=adc_->admit_flow(cl,rv->rate(),rv->bucket());
if (tchan_)
if (last_ != decide) {
int n;
char wrk[50];
double t = Scheduler::instance().clock();
sprintf(wrk, "l -t %g -s %d -d %d -S COLOR -c %s",
t, src_, dst_, decide ? "MediumBlue" : "red" );
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(tchan_, wrk, n+1);
last_ = decide;
}
//put decide in the packet
rv->decision() &= decide;
if (decide) {
j=get_nxt();
pending_[j].flowid=iph->flowid();
//pending_[j].status=decide;
numfl_++;
}
break;
case PT_ACCEPT:
case PT_REJECT:
break;
case PT_CONFIRM:
{
j=lookup(iph->flowid());
if (j!=-1) {
if (!rv->decision()) {
//decrease the avload for this class
adc_->rej_action(cl,rv->rate(),rv->bucket());
numfl_--;
}
pending_[j].flowid=-1;
}
break;
}
case PT_TEARDOWN:
{
adc_->teardown_action(cl,rv->rate(),rv->bucket());
numfl_--;
break;
}
default:
#ifdef notdef
error("unknown signalling message type : %d",ch->ptype());
abort();
#endif
break;
}
send(p,h);
}
int SALink::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
char wrk[500];
if (argc ==3) {
if (strcmp(argv[1],"attach-adc") == 0 ) {
adc_=(ADC *)TclObject::lookup(argv[2]);
if (adc_ ==0 ) {
tcl.resultf("no such node %s", argv[2]);
return(TCL_ERROR);
}
return(TCL_OK);
}
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("SALink: trace: can't attach %s for writing", id);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
if (argc == 2) {
if (strcmp(argv[1], "add-trace") == 0) {
if (tchan_) {
sprintf(wrk, "a -t * -n %s:%d-%d -s %d",
adc_->type(), src_, dst_, src_);
int n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(tchan_, wrk, n+1);
numfl_ = 0;
}
return (TCL_OK);
}
}
return Connector::command(argc,argv);
}
int SALink::lookup(int flowid)
{
int i;
for (i=0;iSALink::get_nxt()
{
int i;
for (i=0;iSALink::trace(TracedVar* v)
{
char wrk[500];
int *p, newval;
if (strcmp(v->name(), "\"Admitted Flows\"") == 0) {
p = &onumfl_;
}
else {
fprintf(stderr, "SALink: unknown trace var %s\n", v->name());
return;
}
newval = int(*((TracedInt*)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 %d -o %d",
t, src_, adc_->type(), 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;
}
satgeometry.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999 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 Tom Henderson, UCB Daedalus Research Group, June 1999
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "satgeometry.h"
#include "satposition.h"
static class SatGeometryClass : public TclClass {
public:
SatGeometryClass() : TclClass("SatGeometry") {}
TclObject* create(int, const char*const*) {
return (new SatGeometry());
}
} class_sat_geometry;
// Returns the distance in km between points a and b
double SatGeometry::distance(coordinate a, coordinate b)
{
double a_x, a_y, a_z, b_x, b_y, b_z; // cartesian
spherical_to_cartesian(a.r, a.theta, a.phi, a_x, a_y, a_z);
spherical_to_cartesian(b.r, b.theta, b.phi, b_x, b_y, b_z);
return (Trace::round(DISTANCE(a_x, a_y, a_z, b_x, b_y, b_z), 1.0E+8));
}
void SatGeometry::spherical_to_cartesian(double R, double Theta,
double Phi, double &X, double &Y, double &Z)
{
X = R * sin(Theta) * cos (Phi);
Y = R * sin(Theta) * sin (Phi);
Z = R * cos(Theta);
}
// Propagation delay is the distance divided by the speed of light
double SatGeometry::propdelay(coordinate a, coordinate b)
{
double delay = distance(a, b)/LIGHT;
return (Trace::round(delay, 1.0E+8));
}
double SatGeometry::get_altitude(coordinate a)
{
return (a.r - EARTH_RADIUS);
}
// Returns latitude in radians, in the range from -PI/2 to PI/2
double SatGeometry::get_latitude(coordinate a)
{
return (PI/2 - a.theta);
}
// Returns (earth-centric) longitude corresponding to the position of the node
// (the input coordinate corresponds to fixed coordinate system, through
// which the Earth rotates, so we have to scale back the effects of rotation).
// The return value ranges from -PI to PI.
double SatGeometry::get_longitude(coordinate coord_)
{
double period = EARTH_PERIOD; // period of earth in seconds
// adjust longitude so that it is earth-centric (i.e., account
// for earth rotating beneath).
double earth_longitude = fmod((coord_.phi -
(fmod(NOW + SatPosition::time_advance_,period)/period) * 2*PI),
2*PI);
// Bring earth_longitude to be within (-PI, PI)
if (earth_longitude < (-1*PI))
earth_longitude = 2*PI + earth_longitude;
if (earth_longitude > PI)
earth_longitude = (-(2*PI - earth_longitude));
if (fabs(earth_longitude) < 0.0001)
return 0; // To avoid trace output of "-0.00"
else
return (earth_longitude);
}
// If the satellite is above the elevation mask of the terminal, returns
// the elevation mask in radians; otherwise, returns 0.
double SatGeometry::check_elevation(coordinate satellite,
coordinate terminal, double elev_mask_)
{
double S = satellite.r; // satellite radius
double S_2 = satellite.r * satellite.r; // satellite radius^2
double E = EARTH_RADIUS;
double E_2 = E * E;
double d, theta, alpha;
d = distance(satellite, terminal);
if (d < sqrt(S_2 - E_2)) {
// elevation angle > 0
theta = acos((E_2+S_2-(d*d))/(2*E*S));
alpha = acos(sin(theta) * S/d);
return ( (alpha > elev_mask_) ? alpha : 0);
} else
return 0;
}
// This function determines whether two satellites are too far apart
// to establish an ISL between them, due to Earth atmospheric grazing
// (or shadowing by the Earth itself). Assumes that both satellites nodes
// are at the same altitude. The line between the two satellites can be
// bisected, and a perpendicular from that point to the Earth's center will
// form a right triangle. If the length of this perpendicular is less than
// EARTH_RADIUS + ATMOS_MARGIN, the link cannot be established.
//
int SatGeometry::are_satellites_mutually_visible(coordinate first, coordinate second)
{
// if we drop a perpendicular from the ISL to the Earth's surface,
// we have a right triangle. The atmospheric margin is the minimum
// ISL grazing altitude.
double c, d, min_radius, grazing_radius;
double radius = get_radius(first); // could just use first.r here.
double distance_ = distance(first, second);
c = radius * radius;
d = (distance_/2) * (distance_/2);
grazing_radius = (EARTH_RADIUS + ATMOS_MARGIN);
min_radius = sqrt(c - d);
if (min_radius >= grazing_radius) {
return TRUE;
} else {
return FALSE;
}
}
sathandoff.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999 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 Tom Henderson, UCB Daedalus Research Group, June 1999
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "random.h"
#include "sathandoff.h"
#include "satlink.h"
#include "satroute.h"
#include "satposition.h"
#include "satnode.h"
#include "satgeometry.h"
#include
static class LinkHandoffMgrClass : public TclClass {
public:
LinkHandoffMgrClass() : TclClass("HandoffManager") {}
TclObject* create(int, const char*const*) {
return (new LinkHandoffMgr());
}
} class_link_handoff_manager;
static class SatLinkHandoffMgrClass : public TclClass {
public:
SatLinkHandoffMgrClass() : TclClass("HandoffManager/Sat") {}
TclObject* create(int, const char*const*) {
return (new SatLinkHandoffMgr());
}
} class_sat_link_handoff_manager;
static class TermLinkHandoffMgrClass : public TclClass {
public:
TermLinkHandoffMgrClass() : TclClass("HandoffManager/Term") {}
TclObject* create(int, const char*const*) {
return (new TermLinkHandoffMgr());
}
} class_term_link_handoff_manager;
void SatHandoffTimer::expire(Event*)
{
a_->handoff();
}
void TermHandoffTimer::expire(Event*)
{
a_->handoff();
}
//////////////////////////////////////////////////////////////////////////////
// class LinkHandoffMgr
//////////////////////////////////////////////////////////////////////////////
RNG LinkHandoffMgr::handoff_rng_;
int LinkHandoffMgr::handoff_randomization_ = 0;
LinkHandoffMgr::LinkHandoffMgr()
{
bind_bool("handoff_randomization_", &handoff_randomization_);
}
int LinkHandoffMgr::command(int argc, const char*const* argv)
{
if (argc == 2) {
} else if (argc == 3) {
if(strcmp(argv[1], "setnode") == 0) {
node_ = (Node*) TclObject::lookup(argv[2]);
if (node_ == 0)
return TCL_ERROR;
return TCL_OK;
}
}
return (TclObject::command(argc, argv));
}
// Each crossseam satellite will have two net stacks-- at most one will
// be occupied. This procedure finds an unoccupied stack on the node.
SatLinkHead* LinkHandoffMgr::get_peer_next_linkhead(SatNode* np)
{
LinkHead* lhp;
SatLinkHead* slhp;
for (lhp = np->linklisthead_.lh_first; lhp;
lhp = lhp->nextlinkhead() ) {
slhp = (SatLinkHead*) lhp;
if (slhp->type() == LINK_ISL_CROSSSEAM) {
if (!slhp->phy_tx()->channel() &&
!slhp->phy_rx()->channel() )
return slhp;
}
}
printf("Error, couldn't find an empty crossseam stack for handoff\n");
return 0;
}
// This helper function assumes that the channel to which the link interface
// is attached has one peer node (i.e., no other receive infs on channel)
SatLinkHead* LinkHandoffMgr::get_peer_linkhead(SatLinkHead* slhp)
{
SatChannel *schan_;
Phy *remote_phy_;
Node *remote_node_;
schan_ = (SatChannel*) slhp->phy_tx()->channel();
if (schan_ == 0) {
printf("Error: get_peer_linkhead called for a non-");
printf("connected link on node %d\n", slhp->node()->address());
return 0; // Link is not currently connected
}
remote_phy_ = schan_->ifhead_.lh_first;
if (remote_phy_ == 0) {
printf("Error: node %d's tx phy ", slhp->node()->address());
printf("connected to channel with no receivers\n");
return 0;
}
remote_node_ = remote_phy_->head()->node();
if (remote_phy_->nextchnl()) {
printf("Error: This ISL channel has more than one target\n");
return 0;
}
return ( (SatLinkHead*) remote_phy_->head());
}
// This helper function assumes that the channel to which the link interface
// is attached has one peer node (i.e., no other receive infs on channel)
SatNode* LinkHandoffMgr::get_peer(SatLinkHead* slhp)
{
SatChannel *schan_;
Phy *remote_phy_;
schan_ = (SatChannel*) slhp->phy_tx()->channel();
if (schan_ == 0)
return 0; // Link is not currently connected
remote_phy_ = schan_->ifhead_.lh_first;
if (remote_phy_ == 0) {
printf("Error: node %d's tx phy ", slhp->node()->address());
printf("connected to channel with no receivers\n");
return 0;
}
if (remote_phy_->nextchnl()) {
printf("Error: This ISL channel has more than one target\n");
return 0;
}
return ( (SatNode*) remote_phy_->head()->node());
}
//////////////////////////////////////////////////////////////////////////
// class TermLinkHandoffMgr
//////////////////////////////////////////////////////////////////////////
double TermLinkHandoffMgr::elevation_mask_ = 0;
int TermLinkHandoffMgr::term_handoff_int_ = 10;
TermLinkHandoffMgr::TermLinkHandoffMgr() : timer_(this)
{
bind("elevation_mask_", &elevation_mask_);
bind("term_handoff_int_", &term_handoff_int_);
}
//
// This is called each time the node checks to see if its link to a
// polar satellite needs to be handed off.
// There are two cases:
// i) current link is up; check to see if it stays up or is handed off
// ii) current link is down; check to see if it can go up
// If there are any changes, call for rerouting. Finally, restart the timer.
//
int TermLinkHandoffMgr::handoff()
{
coordinate sat_coord, earth_coord;
SatLinkHead* slhp;
SatNode *peer_; // Polar satellite at opposite end of the GSL
SatNode *best_peer_; // Best found peer for handoff
Node *nodep; // Pointer used in searching the list of nodes
PolarSatPosition *nextpos_;
int link_changes_flag_ = FALSE; // Flag indicating change took place
int restart_timer_flag_ = FALSE; // Restart timer only if polar links
double found_elev_ = 0; //``Flag'' indicates whether handoff can occur
double best_found_elev_ = 0;
double mask_ = DEG_TO_RAD(TermLinkHandoffMgr::elevation_mask_);
earth_coord = ((SatNode *)node_)->position()->coord();
// Traverse the linked list of link interfaces
for (slhp = (SatLinkHead*) node_->linklisthead_.lh_first; slhp;
slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
if (slhp->type() == LINK_GSL_GEO ||
slhp->type() == LINK_GENERIC)
continue;
if (slhp->type() != LINK_GSL_POLAR) {
printf("Error: Terminal link type ");
printf("not valid %d NOW %f\n", slhp->type(), NOW);
exit(1);
}
// The link is a GSL_POLAR link-- should be one receive
// interface on it
restart_timer_flag_ = TRUE;
peer_ = get_peer(slhp);
if (peer_) {
sat_coord = peer_->position()->coord();
if (!SatGeometry::check_elevation(sat_coord,
earth_coord, mask_) && slhp->linkup_) {
slhp->linkup_ = FALSE;
link_changes_flag_ = TRUE;
// Detach receive link interface from channel
slhp->phy_rx()->removechnl();
// Set channel pointers to NULL
slhp->phy_tx()->setchnl(0);
slhp->phy_rx()->setchnl(0);
}
}
if (!slhp->linkup_) {
// If link is down, see if we can use another satellite
//
// As an optimization, first check the next satellite
// coming over the horizon. Next, consider all
// remaining satellites.
//
if (peer_) {
// Next satellite
nextpos_ = ((PolarSatPosition*)
peer_->position())->next();
if (nextpos_) {
sat_coord = nextpos_->coord();
found_elev_ = SatGeometry::check_elevation(sat_coord, earth_coord, mask_);
if (found_elev_)
peer_ = (SatNode*) nextpos_->node();
}
}
// Next, check all remaining satellites if not found
if (!found_elev_) {
for (nodep=Node::nodehead_.lh_first; nodep;
nodep = nodep->nextnode()) {
peer_ = (SatNode*) nodep;
if (peer_->position() &&
(peer_->position()->type() !=
POSITION_SAT_POLAR))
continue;
sat_coord =
peer_->position()->coord();
found_elev_ = SatGeometry::check_elevation(sat_coord, earth_coord, mask_);
if (found_elev_ > best_found_elev_) {
best_peer_ = peer_;
best_found_elev_ = found_elev_;
}
}
if (best_found_elev_) {
peer_ = best_peer_;
found_elev_ = best_found_elev_;
}
}
if (found_elev_) {
slhp->linkup_ = TRUE;
link_changes_flag_ = TRUE;
// Point slhp->phy_tx to peer_'s inlink
slhp->phy_tx()->setchnl(peer_->uplink());
// Point slhp->phy_rx to peer_'s outlink and
// add phy_rx to the channels list of phy's
slhp->phy_rx()->setchnl(peer_->downlink());
slhp->phy_rx()->insertchnl(&(peer_->downlink()->ifhead_));
}
}
}
if (link_changes_flag_) {
SatRouteObject::instance().recompute();
}
if (restart_timer_flag_) {
// If we don't have polar GSLs, don't reset the timer
if (handoff_randomization_) {
timer_.resched(term_handoff_int_ +
handoff_rng_.uniform(-1 * term_handoff_int_/2,
term_handoff_int_/2));
} else
timer_.resched(term_handoff_int_);
}
return link_changes_flag_;
}
//////////////////////////////////////////////////////////////////////////
// class SatLinkHandoffMgr
//////////////////////////////////////////////////////////////////////////
double SatLinkHandoffMgr::latitude_threshold_ = 0;
double SatLinkHandoffMgr::longitude_threshold_ = 0;
int SatLinkHandoffMgr::sat_handoff_int_ = 10;
SatLinkHandoffMgr::SatLinkHandoffMgr() : timer_(this)
{
bind("sat_handoff_int_", &sat_handoff_int_);
bind("latitude_threshold_", &latitude_threshold_);
bind("longitude_threshold_", &longitude_threshold_);
}
//
// This function is responsible for activating, deactivating, and handing off
// satellite ISLs. If the ISL is an intraplane link,
// do nothing. If the ISL is an interplane link, it will be taken down
// when _either_ of the connected satellites are above lat_threshold_
// degrees, and brought back up when _both_ satellites move below
// lat_threshold_ again. If an ISL is a cross-seam link, it must also be
// handed off periodically while the satellite is below lat_threshold_.
//
// Finally, optimizations that avoid going through the linked lists unless
// the satellite is ``close'' to lat_threshold_ are employed.
//
int SatLinkHandoffMgr::handoff()
{
SatLinkHead *slhp, *peer_slhp, *peer_next_slhp;
SatNode *local_, *peer_, *peer_next_;
PolarSatPosition *pos_, *peer_pos_, *peer_next_pos_;
double dist_to_peer, dist_to_next;
Channel *tx_channel_, *rx_channel_;
double sat_latitude_, sat_longitude_, peer_latitude_, peer_longitude_;
int link_down_flag_;
double lat_threshold_ = DEG_TO_RAD(latitude_threshold_);
double cross_long_threshold_ = DEG_TO_RAD(longitude_threshold_);
int link_changes_flag_ = FALSE; // Flag indicating change took place
coordinate local_coord_, peer_coord_;
local_ = (SatNode*) node_;
local_coord_ = local_->position()->coord();
sat_latitude_ = SatGeometry::get_latitude(local_->position()->coord());
sat_longitude_= SatGeometry::get_longitude(local_->position()->coord());
// First go through crossseam ISLs to search for handoffs
for (slhp = (SatLinkHead*) local_->linklisthead_.lh_first; slhp;
slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
if (slhp->type() != LINK_ISL_CROSSSEAM)
continue;
peer_ = get_peer(slhp);
if (peer_ == 0)
continue; // this link interface is not attached
// If this is a crossseam link, first see if the link must
// be physically handed off to the next satellite.
// Handoff is needed if the satellite at the other end of
// the link is further away than the ``next'' satellite
// in the peer's orbital plane.
pos_ = (PolarSatPosition*)slhp->node()->position();
peer_slhp = get_peer_linkhead(slhp);
peer_pos_ = (PolarSatPosition*) peer_->position();
peer_coord_ = peer_pos_->coord();
if (fabs(sat_latitude_) > lat_threshold_)
link_down_flag_ = TRUE;
else
link_down_flag_ = FALSE;
if (peer_pos_->plane() < pos_->plane()) {
// Crossseam handoff is controlled by satellites
// in the plane with a lower index
break;
}
peer_next_pos_ = peer_pos_->next();
if (!peer_next_pos_) {
printf("Error: crossseam handoffs require ");
printf("setting the ``next'' field\n");
exit(1);
}
peer_next_ = (SatNode*) peer_next_pos_->node();
dist_to_peer = SatGeometry::distance(peer_coord_, local_coord_);
dist_to_next = SatGeometry::distance(peer_next_pos_->coord(),
local_coord_);
if (dist_to_next < dist_to_peer) {
// Handoff -- the "next" satellite should have a
// currently unused network stack. Find this
// unused stack and handoff the channels to it.
//
// Remove peer's tx/rx interface from channel
peer_slhp->phy_rx()->removechnl();
peer_slhp->phy_tx()->setchnl(0);
peer_slhp->phy_rx()->setchnl(0);
// Add peer_next's tx/rx interfaces to our channels
peer_next_slhp = get_peer_next_linkhead(peer_next_);
tx_channel_ = slhp->phy_tx()->channel();
rx_channel_ = slhp->phy_rx()->channel();
peer_next_slhp->phy_tx()->setchnl(rx_channel_);
peer_next_slhp->phy_rx()->setchnl(tx_channel_);
peer_next_slhp->phy_rx()->insertchnl(&(tx_channel_->ifhead_));
link_changes_flag_ = TRUE;
// Now reset the peer_ variables to point to next
peer_ = peer_next_;
peer_slhp = peer_next_slhp;
peer_coord_ = peer_->position()->coord();
}
// Next, see if the link needs to be taken down.
peer_latitude_ =
SatGeometry::get_latitude(peer_coord_);
peer_longitude_ = SatGeometry::get_longitude(peer_coord_);
if (fabs(peer_latitude_) > lat_threshold_)
link_down_flag_ = TRUE;
// If the two satellites are too close to each other in
// longitude, the link should be down
if ((fabs(peer_longitude_ - sat_longitude_) <
cross_long_threshold_) ||
fabs(peer_longitude_ - sat_longitude_) >
(2 * PI - cross_long_threshold_))
link_down_flag_ = TRUE;
// Check to see if link grazes atmosphere at an altitude
// below the atmospheric margin
link_down_flag_ |= !(SatGeometry::are_satellites_mutually_visible(peer_coord_, local_coord_));
// Evaluate whether a change in link status is needed
if ((slhp->linkup_ || peer_slhp->linkup_) && link_down_flag_) {
slhp->linkup_ = FALSE;
peer_slhp->linkup_ = FALSE;
link_changes_flag_ = TRUE;
} else if ((!slhp->linkup_ || !peer_slhp->linkup_) &&
!link_down_flag_) {
slhp->linkup_ = TRUE;
peer_slhp->linkup_ = TRUE;
link_changes_flag_ = TRUE;
}
}
// Now, work on interplane ISLs (intraplane ISLs are not handed off)
// Now search for interplane ISLs
for (slhp = (SatLinkHead*) local_->linklisthead_.lh_first; slhp;
slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
if (slhp->type() != LINK_ISL_INTERPLANE)
continue;
if (fabs(sat_latitude_) > lat_threshold_)
link_down_flag_ = TRUE;
else
link_down_flag_ = FALSE;
peer_ = get_peer(slhp);
peer_slhp = get_peer_linkhead(slhp);
peer_coord_ = peer_->position()->coord();
peer_latitude_ = SatGeometry::get_latitude(peer_coord_);
if (fabs(peer_latitude_) > lat_threshold_)
link_down_flag_ = TRUE;
link_down_flag_ |= !(SatGeometry::are_satellites_mutually_visible(peer_coord_, local_coord_));
if (slhp->linkup_ && link_down_flag_) {
// Take links down if either satellite at high latitude
slhp->linkup_ = FALSE;
peer_slhp->linkup_ = FALSE;
link_changes_flag_ = TRUE;
} else if (!slhp->linkup_ && !link_down_flag_) {
slhp->linkup_ = TRUE;
peer_slhp->linkup_ = TRUE;
link_changes_flag_ = TRUE;
}
}
if (link_changes_flag_) {
SatRouteObject::instance().recompute();
}
if (handoff_randomization_) {
timer_.resched(sat_handoff_int_ +
handoff_rng_.uniform(-1 * sat_handoff_int_/2,
sat_handoff_int_/2));
} else
timer_.resched(sat_handoff_int_);
return link_changes_flag_;
}
satlink.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999 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 Tom Henderson, UCB Daedalus Research Group, June 1999
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
/*
* Contains source code for:
* SatLinkHead
* SatLL
* SatMac
* SatPhy
* SatChannel
*/
#include "satlink.h"
#include "sattrace.h"
#include "satposition.h"
#include "satgeometry.h"
#include "satnode.h"
#include "errmodel.h"
/*==========================================================================*/
/*
* _SatLinkHead
*/
static class SatLinkHeadClass : public TclClass {
public:
SatLinkHeadClass() : TclClass("Connector/LinkHead/Sat") {}
TclObject* create(int, const char*const*) {
return (new SatLinkHead);
}
} class_sat_link_head;
SatLinkHead::SatLinkHead() : linkup_(1), phy_tx_(0), phy_rx_(0), mac_(0), satll_(0), queue_(0), errmodel_(0)
{
}
int SatLinkHead::command(int argc, const char*const* argv)
{
if (argc == 2) {
} else if (argc == 3) {
if (strcmp(argv[1], "set_type") == 0) {
if (strcmp(argv[2], "geo") == 0) {
type_ = LINK_GSL_GEO;
return TCL_OK;
} else if (strcmp(argv[2], "polar") == 0) {
type_ = LINK_GSL_POLAR;
return TCL_OK;
} else if (strcmp(argv[2], "gsl") == 0) {
type_ = LINK_GSL;
return TCL_OK;
} else if (strcmp(argv[2], "gsl-repeater") == 0) {
type_ = LINK_GSL_REPEATER;
return TCL_OK;
} else if (strcmp(argv[2], "interplane") == 0) {
type_ = LINK_ISL_INTERPLANE;
return TCL_OK;
} else if (strcmp(argv[2], "intraplane") == 0) {
type_ = LINK_ISL_INTRAPLANE;
return TCL_OK;
} else if (strcmp(argv[2], "crossseam") == 0) {
type_ = LINK_ISL_CROSSSEAM;
return TCL_OK;
} else {
printf("Unknown link type: %s\n", argv[2]);
exit(1);
}
}
if (strcmp(argv[1], "setll") == 0) {
satll_ = (SatLL*) TclObject::lookup(argv[2]);
if (satll_ == 0)
return TCL_ERROR;
return TCL_OK;
} else if(strcmp(argv[1], "setphytx") == 0) {
phy_tx_ = (SatPhy*) TclObject::lookup(argv[2]);
if (phy_tx_ == 0)
return TCL_ERROR;
return TCL_OK;
} else if(strcmp(argv[1], "setphyrx") == 0) {
phy_rx_ = (SatPhy*) TclObject::lookup(argv[2]);
if (phy_rx_ == 0)
return TCL_ERROR;
return TCL_OK;
} else if(strcmp(argv[1], "setmac") == 0) {
mac_ = (SatMac*) TclObject::lookup(argv[2]);
if (mac_ == 0)
return TCL_ERROR;
return TCL_OK;
} else if(strcmp(argv[1], "setqueue") == 0) {
queue_ = (Queue*) TclObject::lookup(argv[2]);
if (queue_ == 0)
return TCL_ERROR;
return TCL_OK;
} else if(strcmp(argv[1], "seterrmodel") == 0) {
errmodel_ = (ErrorModel*) TclObject::lookup(argv[2]);
if (errmodel_ == 0)
return TCL_ERROR;
return TCL_OK;
}
}
return (LinkHead::command(argc, argv));
}
/*==========================================================================*/
/*
* _SatLL
*/
static class SatLLClass : public TclClass {
public:
SatLLClass() : TclClass("LL/Sat") {}
TclObject* create(int, const char*const*) {
return (new SatLL);
}
} sat_class_ll;
void SatLL::recv(Packet* p, Handler* /*h*/)
{
hdr_cmn *ch = HDR_CMN(p);
/*
* Sanity Check
*/
assert(initialized());
// 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) {
uptarget_ ? sendUp(p) : drop(p);
return;
}
ch->direction() = hdr_cmn::DOWN;
sendDown(p);
}
// Encode link layer sequence number, type, and mac address fields
void SatLL::sendDown(Packet* p)
{
hdr_cmn *ch = HDR_CMN(p);
hdr_ll *llh = HDR_LL(p);
char *mh = (char*)p->access(hdr_mac::offset_);
int peer_mac_;
SatChannel* satchannel_;
llh->seqno_ = ++seqno_;
llh->lltype() = LL_DATA;
// Set mac src, type, and dst
mac_->hdr_src(mh, mac_->addr());
mac_->hdr_type(mh, ETHERTYPE_IP); // We'll just use ETHERTYPE_IP
nsaddr_t dst = ch->next_hop();
// a value of -1 is IP_BROADCAST
if (dst < -1) {
printf("Error: next_hop_ field not set by routing agent\n");
exit(1);
}
switch(ch->addr_type()) {
case NS_AF_INET:
case NS_AF_NONE:
if (IP_BROADCAST == (u_int32_t) dst)
{
mac_->hdr_dst((char*) HDR_MAC(p), MAC_BROADCAST);
break;
}
/*
* Here is where arp would normally occur. In the satellite
* case, we don't arp (for now). Instead, use destination
* address to find the mac address corresponding to the
* peer connected to this channel. If someone wants to
* add arp, look at how the wireless code does it.
*/
// Cache latest value used
if (dst == arpcachedst_) {
mac_->hdr_dst((char*) HDR_MAC(p), arpcache_);
break;
}
// Search for peer's mac address (this is the pseudo-ARP)
satchannel_ = (SatChannel*) channel();
peer_mac_ = satchannel_->find_peer_mac_addr(dst);
if (peer_mac_ < 0 ) {
printf("Error: couldn't find dest mac on channel ");
printf("NOW %f\n", NOW);
exit(1);
} else {
mac_->hdr_dst((char*) HDR_MAC(p), peer_mac_);
arpcachedst_ = dst;
arpcache_ = peer_mac_;
break;
}
default:
printf("Error: addr_type not set to NS_AF_INET or NS_AF_NONE\n");
exit(1);
}
// let mac decide when to take a new packet from the queue.
Scheduler& s = Scheduler::instance();
s.schedule(downtarget_, p, delay_);
}
void SatLL::sendUp(Packet* p)
{
Scheduler& s = Scheduler::instance();
if (hdr_cmn::access(p)->error() > 0)
drop(p);
else
s.schedule(uptarget_, p, delay_);
}
// Helper function
Channel* SatLL::channel()
{
Phy* phy_ = (Phy*) mac_->downtarget();
return phy_->channel();
}
/*==========================================================================*/
/*
* _SatMac
*/
static class SatMacClass : public TclClass {
public:
SatMacClass() : TclClass("Mac/Sat") {}
TclObject* create(int, const char*const*) {
return (new SatMac);
}
} sat_class_mac;
void MacSendTimer::expire(Event*)
{
a_->send_timer();
}
void MacRecvTimer::expire(Event*)
{
a_->recv_timer();
}
int SatMac::command(int argc, const char*const* argv)
{
if(argc == 2) {
}
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);
}
}
return Mac::command(argc, argv);
}
void SatMac::sendUp(Packet* p)
{
hdr_mac* mh = HDR_MAC(p);
int dst = this->hdr_dst((char*)mh); // mac destination address
if (((u_int32_t)dst != MAC_BROADCAST) && (dst != index_)) {
drop(p);
return;
}
// First bit of packet has arrived-- wait for
// (txtime + delay_) before sending up
Scheduler::instance().schedule(uptarget_, p, delay_ + mh->txtime());
}
void SatMac::sendDown(Packet* p)
{
Scheduler& s = Scheduler::instance();
double txt;
// LINK_HDRSIZE is defined in satlink.h. This is the size of header
// information for all layers below IP. Alternatively, one could
// derive this information dynamically from packet headers.
int packetsize_ = HDR_CMN(p)->size() + LINK_HDRSIZE;
if (bandwidth_ != 0)
txt = txtime(packetsize_);
// For convenience, we encode the transmit time in the Mac header
// The packet will be held (for collision detection) for txtime
// at the receiving mac.
HDR_MAC(p)->txtime() = txt;
downtarget_->recv(p, this);
// Callback for when this packet's transmission will be done
s.schedule(&hRes_, &intr_, txt);
}
static class UnslottedAlohaMacClass : public TclClass {
public:
UnslottedAlohaMacClass() : TclClass("Mac/Sat/UnslottedAloha") {}
TclObject* create(int, const char*const*) {
return (new UnslottedAlohaMac());
}
} sat_class_unslottedalohamac;
/*==========================================================================*/
/*
* _UnslottedAlohaMac
*/
UnslottedAlohaMac::UnslottedAlohaMac() : SatMac(), tx_state_(MAC_IDLE),
rx_state_(MAC_IDLE), rtx_(0), end_of_contention_(0)
{
bind_time("mean_backoff_", &mean_backoff_);
bind("rtx_limit_", &rtx_limit_);
bind_time("send_timeout_", &send_timeout_);
}
void UnslottedAlohaMac::send_timer()
{
switch (tx_state_) {
case MAC_SEND:
// We've timed out on send-- back off
backoff();
break;
case MAC_COLL:
// Our backoff timer has expired-- resend
sendDown(snd_pkt_);
break;
default:
printf("Error: wrong tx_state in unslotted aloha: %d\n",
tx_state_);
break;
}
}
void UnslottedAlohaMac::recv_timer()
{
switch (rx_state_) {
case MAC_RECV:
// We've successfully waited out the reception
end_of_contention(rcv_pkt_);
break;
default:
printf("Error: wrong rx_state in unslotted aloha: %d\n",
rx_state_);
break;
}
}
void UnslottedAlohaMac::sendUp(Packet* p)
{
hdr_mac* mh = HDR_MAC(p);
if (rx_state_ == MAC_IDLE) {
// First bit of packet has arrived-- wait for
// txtime to make sure no collisions occur
rcv_pkt_ = p;
end_of_contention_ = NOW + mh->txtime();
rx_state_ = MAC_RECV;
recv_timer_.resched(mh->txtime());
} else {
// Collision: figure out if contention phase must be lengthened
double temp = NOW + mh->txtime();
if (temp > end_of_contention_) {
recv_timer_.resched(temp - NOW);
}
drop(p);
if (rcv_pkt_)
drop(rcv_pkt_);
rcv_pkt_ = 0;
}
}
void UnslottedAlohaMac::sendDown(Packet* p)
{
double txt;
// compute transmission delay:
int packetsize_ = HDR_CMN(p)->size() + LINK_HDRSIZE;
if (bandwidth_ != 0)
txt = txtime(packetsize_);
HDR_MAC(p)->txtime() = txt;
// Send the packet down
tx_state_ = MAC_SEND;
snd_pkt_ = p->copy(); // save a copy in case it gets retransmitted
downtarget_->recv(p, this);
// Set a timer-- if we do not hear our own transmission within this
// interval (and cancel the timer), the send_timer will expire and
// we will backoff and retransmit.
send_timer_.resched(send_timeout_ + txt);
}
// Called when contention period ends
void UnslottedAlohaMac::end_of_contention(Packet* p)
{
rx_state_ = MAC_IDLE;
if (!p)
return; // No packet to free or send up.
hdr_mac* mh = HDR_MAC(p);
int dst = this->hdr_dst((char*)mh); // mac destination address
int src = this->hdr_src((char*)mh); // mac source address
if (((u_int32_t)dst != MAC_BROADCAST) && (dst != index_) &&
(src != index_)) {
drop(p);
return;
}
if (src == index_) {
// received our own packet: free up transmit side, drop this
// packet, and perform callback to queue which is blocked
if (!callback_) {
printf("Error, queue callback_ is not valid\n");
exit(1);
}
send_timer_.force_cancel();
tx_state_ = MAC_IDLE;
rtx_ = 0;
drop(snd_pkt_); // Free the packet cached for retransmission
resume(p);
} else {
// wait for processing delay (delay_) to send packet upwards
Scheduler::instance().schedule(uptarget_, p, delay_);
}
}
void UnslottedAlohaMac::backoff(double delay)
{
double backoff_ = Random::exponential(mean_backoff_);
// if number of retransmissions is within limit, do exponential backoff
// else drop the packet and resume
if (++rtx_ <= rtx_limit_) {
tx_state_ = MAC_COLL;
delay += backoff_;
send_timer_.resched(delay);
} else {
tx_state_ = MAC_IDLE;
rtx_ = 0;
resume(snd_pkt_);
}
}
/*==========================================================================*/
/*
* _SatPhy
*/
static class SatPhyClass: public TclClass {
public:
SatPhyClass() : TclClass("Phy/Sat") {}
TclObject* create(int, const char*const*) {
return (new SatPhy);
}
} class_SatPhy;
void SatPhy::sendDown(Packet *p)
{
if (channel_)
channel_->recv(p, this);
else {
// it is possible for routing to change (and a channel to
// be disconnected) while a packet
// is moving down the stack. Therefore, just log a drop
// if there is no channel
if ( ((SatNode*) head()->node())->trace() )
((SatNode*) head()->node())->trace()->traceonly(p);
Packet::free(p);
}
}
// Note that this doesn't do that much right now. If you want to incorporate
// an error model, you could insert a "propagation" object like in the
// wireless case.
int SatPhy::sendUp(Packet * /* pkt */)
{
return TRUE;
}
int
SatPhy::command(int argc, const char*const* argv) {
if (argc == 2) {
} else if (argc == 3) {
TclObject *obj;
if( (obj = TclObject::lookup(argv[2])) == 0) {
fprintf(stderr, "%s lookup failed\n", argv[1]);
return TCL_ERROR;
}
}
return Phy::command(argc, argv);
}
static class RepeaterPhyClass: public TclClass {
public:
RepeaterPhyClass() : TclClass("Phy/Repeater") {}
TclObject* create(int, const char*const*) {
return (new RepeaterPhy);
}
} class_RepeaterPhy;
void RepeaterPhy::recv(Packet* p, Handler*)
{
struct hdr_cmn *hdr = HDR_CMN(p);
if (hdr->direction() == hdr_cmn::UP) {
// change direction and send to uptarget (which is
// really a Phy_tx that is also a RepeaterPhy)
hdr->direction() = hdr_cmn::DOWN;
uptarget_->recv(p, (Handler*) 0);
} else {
sendDown(p);
}
}
void RepeaterPhy::sendDown(Packet *p)
{
struct hdr_cmn *hdr = HDR_CMN(p);
hdr->direction() = hdr_cmn::DOWN;
if (channel_)
channel_->recv(p, this);
else {
printf("Error, no channel on repeater\n");
exit(1);
}
}
/*==========================================================================*/
/*
* _SatChannel
*/
static class SatChannelClass : public TclClass {
public:
SatChannelClass() : TclClass("Channel/Sat") {}
TclObject* create(int, const char*const*) {
return (new SatChannel);
}
} class_Sat_channel;
SatChannel::SatChannel(void) : Channel() {
}
double
SatChannel::get_pdelay(Node* tnode, Node* rnode)
{
coordinate a = ((SatNode*)tnode)->position()->coord();
coordinate b = ((SatNode*)rnode)->position()->coord();
return (SatGeometry::propdelay(a, b));
}
// This is a helper function that attaches a SatChannel to a Phy
void SatChannel::add_interface(Phy* phy_)
{
phy_->setchnl(this); // Attach phy to this channel
phy_->insertchnl(&ifhead_); // Add phy_ to list of phys on the channel
}
// Remove a phy from a channel
void SatChannel::remove_interface(Phy* phy_)
{
phy_->setchnl(NULL); // Set phy_'s channel pointer to NULL
phy_->removechnl(); // Remove phy_ to list of phys on the channel
}
// Search for destination mac address on this channel. Look through list
// of phys on the channel. If the channel connects to a geo repeater, look
// for the destination on the corresponding downlink channel.
int SatChannel::find_peer_mac_addr(int dst)
{
Phy *n;
Channel* chan_;
chan_ = this;
n = ifhead_.lh_first;
if (n->head()->type() == LINK_GSL_REPEATER) {
SatLinkHead* slh = (SatLinkHead*) n->head();
chan_ = slh->phy_tx()->channel();
}
for(n = chan_->ifhead_.lh_first; n; n = n->nextchnl() ) {
if (n->node()->address() == dst) {
return (((SatMac*) n->uptarget())->addr());
}
}
return -1;
}
satnode.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999 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 Tom Henderson, UCB Daedalus Research Group, June 1999
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "satnode.h"
#include "satlink.h"
#include "sattrace.h"
#include "sathandoff.h"
#include "satposition.h"
static class SatNodeClass : public TclClass {
public:
SatNodeClass() : TclClass("Node/SatNode") {}
TclObject* create(int , const char*const* ) {
return (new SatNode);
}
} class_satnode;
int SatNode::dist_routing_ = 0;
SatNode::SatNode() : ragent_(0), trace_(0), hm_(0)
{
bind_bool("dist_routing_", &dist_routing_);
}
int SatNode::command(int argc, const char*const* argv) {
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "set_downlink") == 0) {
if (downlink_ != NULL) {
tcl.result(downlink_->name());
return (TCL_OK);
}
} else if (strcmp(argv[1], "set_uplink") == 0) {
if (downlink_ != NULL) {
tcl.result(uplink_->name());
return (TCL_OK);
}
} else if (strcmp(argv[1], "start_handoff") == 0) {
if (hm_)
hm_->start();
else {
printf("Error: starting non-existent ");
printf("handoff mgr\n");
exit(1);
}
return (TCL_OK);
} else if (strcmp(argv[1], "dump_sats") == 0) {
dumpSats();
return (TCL_OK);
}
}
if (argc == 3) {
if (strcmp(argv[1], "set_uplink") == 0) {
uplink_ = (SatChannel *) TclObject::lookup(argv[2]);
if (uplink_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
} else if (strcmp(argv[1], "set_downlink") == 0) {
downlink_ = (SatChannel *) TclObject::lookup(argv[2]);
if (downlink_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
} else if (strcmp(argv[1], "set_trace") == 0) {
trace_ = (SatTrace *) TclObject::lookup(argv[2]);
if (trace_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
} else if (strcmp(argv[1], "set_ragent") == 0) {
ragent_ = (SatRouteAgent *) TclObject::lookup(argv[2]);
if (ragent_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
} else if(strcmp(argv[1], "addif") == 0) {
SatPhy* n = (SatPhy*) TclObject::lookup(argv[2]);
if(n == 0)
return TCL_ERROR;
n->insertnode(&ifhead_);
n->setnode(this);
return TCL_OK;
} else if (strcmp(argv[1], "set_position") == 0) {
pos_ = (SatPosition*) TclObject::lookup(argv[2]);
if (pos_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
} else if (strcmp(argv[1], "set_handoff_mgr") == 0) {
hm_ = (LinkHandoffMgr*) TclObject::lookup(argv[2]);
if (hm_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (Node::command(argc, argv));
}
// debugging method for dumping out all of the satellite and ISL locations
// on demand from OTcl.
void SatNode::dumpSats()
{
SatNode *snodep, *peer_snodep;
SatPosition *sposp, *peer_sposp;
SatLinkHead *slhp;
printf("Dumping satellites at time %.2f\n", NOW);
for (snodep= (SatNode*) Node::nodehead_.lh_first; snodep;
snodep = (SatNode*) snodep->nextnode()) {
// XXX Need check to see if node is a SatNode
sposp = snodep->position();
printf("%d\t%.2f\t%.2f\n", snodep->address(),
RAD_TO_DEG(SatGeometry::get_latitude(sposp->coord())),
RAD_TO_DEG(SatGeometry::get_longitude(sposp->coord())));
}
printf("\n");
// Dump satellite links
// There is a static list of address classifiers //QQQ
printf("Links:\n");
for (snodep= (SatNode*) Node::nodehead_.lh_first; snodep;
snodep = (SatNode*) snodep->nextnode()) {
// XXX Not all links necessarily satlinks
for (slhp = (SatLinkHead*) snodep->linklisthead_.lh_first;
slhp; slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
if (slhp->type() != LINK_ISL_CROSSSEAM &&
slhp->type() != LINK_ISL_INTERPLANE &&
slhp->type() != LINK_ISL_INTRAPLANE)
continue;
if (!slhp->linkup_)
continue;
// Link is up. Print out source lat point and dest
// lat point.
sposp = snodep->position();
peer_snodep = hm_->get_peer(slhp);
if (peer_snodep == 0)
continue; // this link interface is not attached
peer_sposp = peer_snodep->position();
printf("%.2f\t%.2f\t%.2f\t%.2f\n",
RAD_TO_DEG(SatGeometry::get_latitude(sposp->coord())),
RAD_TO_DEG(SatGeometry::get_longitude(sposp->coord())),
RAD_TO_DEG(SatGeometry::get_latitude(peer_sposp->coord())),
RAD_TO_DEG(SatGeometry::get_longitude(peer_sposp->coord())));
}
}
}
satposition.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999 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 Tom Henderson, UCB Daedalus Research Group, June 1999
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "satposition.h"
#include "satgeometry.h"
#include
#include
#include
static class TermSatPositionClass : public TclClass {
public:
TermSatPositionClass() : TclClass("Position/Sat/Term") {}
TclObject* create(int argc, const char*const* argv) {
if (argc == 5) {
float a, b;
sscanf(argv[4], "%f %f", &a, &b);
return (new TermSatPosition(a, b));
} else
return (new TermSatPosition);
}
} class_term_sat_position;
static class PolarSatPositionClass : public TclClass {
public:
PolarSatPositionClass() : TclClass("Position/Sat/Polar") {}
TclObject* create(int argc, const char*const* argv) {
if (argc == 5) {
float a = 0, b = 0, c = 0, d = 0, e = 0;
sscanf(argv[4], "%f %f %f %f %f", &a, &b, &c, &d, &e);
return (new PolarSatPosition(a, b, c, d, e));
}
else {
return (new PolarSatPosition);
}
}
} class_polarsatposition;
static class GeoSatPositionClass : public TclClass {
public:
GeoSatPositionClass() : TclClass("Position/Sat/Geo") {}
TclObject* create(int argc, const char*const* argv) {
if (argc == 5)
return (new GeoSatPosition(double(atof(argv[4]))));
else
return (new GeoSatPosition);
}
} class_geosatposition;
static class SatPositionClass : public TclClass {
public:
SatPositionClass() : TclClass("Position/Sat") {}
TclObject* create(int, const char*const*) {
printf("Error: do not instantiate Position/Sat\n");
return (0);
}
} class_satposition;
double SatPosition::time_advance_ = 0;
SatPosition::SatPosition() : node_(0)
{
bind("time_advance_", &time_advance_);
}
int SatPosition::command(int argc, const char*const* argv) {
//Tcl& tcl = Tcl::instance();
if (argc == 2) {
}
if (argc == 3) {
if(strcmp(argv[1], "setnode") == 0) {
node_ = (Node*) TclObject::lookup(argv[2]);
if (node_ == 0)
return TCL_ERROR;
return TCL_OK;
}
}
return (TclObject::command(argc, argv));
}
/////////////////////////////////////////////////////////////////////
// class TermSatPosition
/////////////////////////////////////////////////////////////////////
// Specify initial coordinates. Default coordinates place the terminal
// on the Earth's surface at 0 deg lat, 0 deg long.
TermSatPosition::TermSatPosition(double Theta, double Phi) {
initial_.r = EARTH_RADIUS;
set(Theta, Phi);
type_ = POSITION_SAT_TERM;
}
//
// Convert user specified latitude and longitude to our spherical coordinates
// Latitude is in the range (-90, 90) with neg. values -> south
// Initial_.theta is stored from 0 to PI (spherical)
// Longitude is in the range (-180, 180) with neg. values -> west
// Initial_.phi is stored from 0 to 2*PI (spherical)
//
void TermSatPosition::set(double latitude, double longitude)
{
if (latitude < -90 || latitude > 90)
fprintf(stderr, "TermSatPosition: latitude out of bounds %f\n",
latitude);
if (longitude < -180 || longitude > 180)
fprintf(stderr, "TermSatPosition: longitude out of bounds %f\n",
longitude);
initial_.theta = DEG_TO_RAD(90 - latitude);
if (longitude < 0)
initial_.phi = DEG_TO_RAD(360 + longitude);
else
initial_.phi = DEG_TO_RAD(longitude);
}
coordinate TermSatPosition::coord()
{
coordinate current;
double period = EARTH_PERIOD; // seconds
current.r = initial_.r;
current.theta = initial_.theta;
current.phi = fmod((initial_.phi +
(fmod(NOW + time_advance_,period)/period) * 2*PI), 2*PI);
#ifdef POINT_TEST
current = initial_; // debug option to stop earth's rotation
#endif
return current;
}
/////////////////////////////////////////////////////////////////////
// class PolarSatPosition
/////////////////////////////////////////////////////////////////////
PolarSatPosition::PolarSatPosition(double altitude, double Inc, double Lon,
double Alpha, double Plane) : next_(0), plane_(0) {
set(altitude, Lon, Alpha, Inc);
bind("plane_", &plane_);
if (Plane)
plane_ = int(Plane);
type_ = POSITION_SAT_POLAR;
}
//
// Since it is easier to compute instantaneous orbit position based on a
// coordinate system centered on the orbit itself, we keep initial coordinates
// specified in terms of the satellite orbit, and convert to true spherical
// coordinates in coord().
// Initial satellite position is specified as follows:
// initial_.theta specifies initial angle with respect to "ascending node"
// i.e., zero is at equator (ascending)-- this is the $alpha parameter in Otcl
// initial_.phi specifies East longitude of "ascending node"
// -- this is the $lon parameter in OTcl
// Note that with this system, only theta changes with time
//
void PolarSatPosition::set(double Altitude, double Lon, double Alpha, double Incl)
{
if (Altitude < 0) {
fprintf(stderr, "PolarSatPosition: altitude out of \
bounds: %f\n", Altitude);
exit(1);
}
initial_.r = Altitude + EARTH_RADIUS; // Altitude in km above the earth
if (Alpha < 0 || Alpha >= 360) {
fprintf(stderr, "PolarSatPosition: alpha out of bounds: %f\n",
Alpha);
exit(1);
}
initial_.theta = DEG_TO_RAD(Alpha);
if (Lon < -180 || Lon > 180) {
fprintf(stderr, "PolarSatPosition: lon out of bounds: %f\n",
Lon);
exit(1);
}
if (Lon < 0)
initial_.phi = DEG_TO_RAD(360 + Lon);
else
initial_.phi = DEG_TO_RAD(Lon);
if (Incl < 0 || Incl > 180) {
// retrograde orbits = (90 < Inclination < 180)
fprintf(stderr, "PolarSatPosition: inclination out of \
bounds: %f\n", Incl);
exit(1);
}
inclination_ = DEG_TO_RAD(Incl);
}
//
// The initial coordinate has the following properties:
// theta: 0 < theta < 2 * PI (essentially, this specifies initial position)
// phi: 0 < phi < 2 * PI (longitude of ascending node)
// Return a coordinate with the following properties (i.e. convert to a true
// spherical coordinate):
// theta: 0 < theta < PI
// phi: 0 < phi < 2 * PI
//
coordinate PolarSatPosition::coord()
{
coordinate current;
double partial; // fraction of orbit period completed
// XXX: can't use "num = pow(initial_.r,3)" here because of linux lib
double num = initial_.r * initial_.r * initial_.r;
double period = 2 * PI * sqrt(num/MU); // seconds
partial =
(fmod(NOW + time_advance_, period)/period) * 2*PI; //rad
double theta_cur, phi_cur, theta_new, phi_new;
// Compute current orbit-centric coordinates:
// theta_cur adds effects of time (orbital rotation) to initial_.theta
theta_cur = fmod(initial_.theta + partial, 2*PI);
phi_cur = initial_.phi;
// Reminder: theta_cur and phi_cur are temporal translations of
// initial parameters and are NOT true spherical coordinates.
//
// Now generate actual spherical coordinates,
// with 0 < theta_new < PI and 0 < phi_new < 360
if (inclination_ < PI) {
// asin returns value between -PI/2 and PI/2, so
// theta_new guaranteed to be between 0 and PI
theta_new = PI/2 - asin(sin(inclination_) * sin(theta_cur));
// if theta_new is between PI/2 and 3*PI/2, must correct
// for return value of atan()
if (theta_cur > PI/2 && theta_cur < 3*PI/2)
phi_new = atan(cos(inclination_) * tan(theta_cur)) +
phi_cur + PI;
else
phi_new = atan(cos(inclination_) * tan(theta_cur)) +
phi_cur;
phi_new = fmod(phi_new + 2*PI, 2*PI);
} else
printf("ERROR: inclination_ > PI\n");
current.r = initial_.r;
current.theta = theta_new;
current.phi = phi_new;
return current;
}
int PolarSatPosition::command(int argc, const char*const* argv) {
Tcl& tcl = Tcl::instance();
if (argc == 2) {
}
if (argc == 3) {
if (strcmp(argv[1], "set_next") == 0) {
next_ = (PolarSatPosition *) TclObject::lookup(argv[2]);
if (next_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (SatPosition::command(argc, argv));
}
/////////////////////////////////////////////////////////////////////
// class GeoSatPosition
/////////////////////////////////////////////////////////////////////
GeoSatPosition::GeoSatPosition(double longitude)
{
initial_.r = EARTH_RADIUS + GEO_ALTITUDE;
initial_.theta = PI/2;
set(longitude);
type_ = POSITION_SAT_GEO;
}
coordinate GeoSatPosition::coord()
{
coordinate current;
current.r = initial_.r;
current.theta = initial_.theta;
double fractional =
(fmod(NOW + time_advance_, EARTH_PERIOD)/EARTH_PERIOD) *2*PI; // rad
current.phi = fmod(initial_.phi + fractional, 2*PI);
return current;
}
//
// Longitude is in the range (0, 180) with negative values -> west
//
void GeoSatPosition::set(double longitude)
{
if (longitude < -180 || longitude > 180)
fprintf(stderr, "GeoSatPosition: longitude out of bounds %f\n",
longitude);
if (longitude < 0)
initial_.phi = DEG_TO_RAD(360 + longitude);
else
initial_.phi = DEG_TO_RAD(longitude);
}
satroute.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999 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 Tom Henderson, UCB Daedalus Research Group, June 1999
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include "satroute.h"
#include "sattrace.h"
#include "satnode.h"
#include "satlink.h"
#include "route.h"
#include
static class SatRouteClass:public TclClass
{
public:
SatRouteClass ():TclClass ("Agent/SatRoute") { }
TclObject *create (int, const char *const *) {
return (new SatRouteAgent ());
}
} class_satroute;
SatRouteAgent::SatRouteAgent (): Agent (PT_MESSAGE), maxslot_(0), nslot_(0), slot_(0)
{
bind ("myaddr_", &myaddr_);
}
SatRouteAgent::~SatRouteAgent()
{
if (slot_)
delete [] slot_;
}
void SatRouteAgent::alloc(int slot)
{
slot_entry *old = slot_;
int n = nslot_;
if (old == 0)
nslot_ = 32;
while (nslot_ <= slot)
nslot_ <<= 1;
slot_ = new slot_entry[nslot_];
memset(slot_, 0, nslot_ * sizeof(slot_entry));
for (int i = 0; i < n; ++i) {
slot_[i].next_hop = old[i].next_hop;
slot_[i].entry = old[i].entry;
}
delete [] old;
}
void SatRouteAgent::install(int slot, int nh, NsObject* p)
{
if (slot >= nslot_)
alloc(slot);
slot_[slot].next_hop = nh;
slot_[slot].entry = p;
if (slot >= maxslot_)
maxslot_ = slot;
}
void SatRouteAgent::clear_slots()
{
if (slot_)
delete [] slot_;
slot_ = 0;
nslot_ = 0;
maxslot_ = -1;
}
int SatRouteAgent::command (int argc, const char *const *argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
}
if (argc == 3) {
if (strcmp(argv[1], "set_node") == 0) {
node_ = (SatNode *) TclObject::lookup(argv[2]);
if (node_ == 0) {
tcl.resultf("no such object %s", argv[2]);
return (TCL_ERROR);
}
return (TCL_OK);
}
}
return (Agent::command (argc, argv));
}
/*
* Find a target for the received packet
*/
void SatRouteAgent::forwardPacket(Packet * p)
{
hdr_ip *iph = (hdr_ip *) p->access (off_ip_);
hdr_cmn *hdrc = HDR_CMN (p);
NsObject *link_entry_;
hdrc->direction() = hdr_cmn::DOWN; // send it down the stack
int dst = Address::instance().get_nodeaddr(iph->daddr());
// Here we need to have an accurate encoding of the next hop routing
// information
if (myaddr_ == iph->daddr()) {
printf("Error: trying to forward a packet destined to self: %d\n", myaddr_);
Packet::free(p);
}
hdrc->addr_type_ = NS_AF_INET;
hdrc->last_hop_ = myaddr_; // for tracing purposes
if (SatRouteObject::instance().data_driven_computation())
SatRouteObject::instance().recompute_node(myaddr_);
if (SatNode::dist_routing_ == 0) {
if (slot_ == 0) { // No routes to anywhere
if (node_->trace())
node_->trace()->traceonly(p);
Packet::free(p);
return;
}
link_entry_ = slot_[dst].entry;
if (link_entry_ == 0) {
if (node_->trace())
node_->trace()->traceonly(p);
Packet::free(p);
return;
}
hdrc->next_hop_ = slot_[dst].next_hop;
link_entry_->recv(p, (Handler *)0);
return;
} else {
// DISTRIBUTED ROUTING LOOKUP COULD GO HERE
printf("Error: distributed routing not available\n");
exit(1);
}
}
void SatRouteAgent::recv (Packet * p, Handler *)
{
hdr_ip *iph = (hdr_ip *) p->access (off_ip_);
hdr_cmn *cmh = (hdr_cmn *) p->access (off_cmn_);
if (iph->saddr() == myaddr_ && cmh->num_forwards() == 0) {
// Must be a packet I'm originating... add the IP header
iph->ttl_ = IP_DEF_TTL;
} else if (iph->saddr() == myaddr_) {
// I received a packet that I sent. Probably a routing loop.
Packet::free(p);
return;
} else {
// Packet I'm forwarding...
// Check the TTL. If it is zero, then discard.
if(--iph->ttl_ == 0) {
Packet::free(p);
return;
}
}
if ((iph->saddr() != myaddr_) && (iph->dport() == ROUTER_PORT)) {
// DISTRIBUTED ROUTING PROTOCOL COULD GO HERE
printf("Error: distributed routing not available\n");
exit(1);
} else {
forwardPacket(p);
}
}
//###########################################################################
static class SatRouteObjectClass:public TclClass
{
public:
SatRouteObjectClass ():TclClass ("SatRouteObject") { }
TclObject *create (int, const char *const *) {
return (new SatRouteObject ());
}
} class_satrouteobject;
SatRouteObject* SatRouteObject::instance_;
SatRouteObject::SatRouteObject() : suppress_initial_computation_(0)
{
bind_bool("metric_delay_", &metric_delay_);
bind_bool("data_driven_computation_", &data_driven_computation_);
}
int SatRouteObject::command (int argc, const char *const *argv)
{
if (instance_ == 0)
instance_ = this;
if (argc == 2) {
// While suppress_initial_computation_ may seem more
// appropriate as a bound variable, it is useful to
// implement the setting of this variable this way so that
// the ``instance_ = this'' assignment is made at the
// start of simulation.
if (strcmp(argv[1], "suppress_initial_computation") == 0) {
suppress_initial_computation_ = 1;
return (TCL_OK);
}
if (strcmp(argv[1], "compute_routes") == 0) {
recompute();
return (TCL_OK);
}
}
return (RouteLogic::command(argc, argv));
}
void SatRouteObject::recompute_node(int node)
{
compute_topology();
node_compute_routes(node);
populate_routing_tables(node);
}
void SatRouteObject::recompute()
{
// For very large topologies (e.g., Teledesic), we don't want to
// waste a lot of time computing routes at the beginning of the
// simulation. This first if() clause suppresses route computations.
if (data_driven_computation_ ||
(NOW < 0.001 && suppress_initial_computation_) )
return;
else {
compute_topology();
compute_routes(); // calls base class function
populate_routing_tables();
}
}
// Derives link adjacency information from the nodes and gives the current
// topology information to the RouteLogic.
void SatRouteObject::compute_topology()
{
Node *nodep;
Phy *phytxp, *phyrxp, *phytxp2, *phyrxp2;
SatLinkHead *slhp;
Channel *channelp, *channelp2;
int src, dst;
double delay;
reset_all();
// Compute adjacencies. Traverse linked list of nodes
for (nodep=Node::nodehead_.lh_first; nodep; nodep = nodep->nextnode()) {
// Cycle through the linked list of linkheads
for (slhp = (SatLinkHead*) nodep->linklisthead_.lh_first; slhp;
slhp = (SatLinkHead*) slhp->nextlinkhead()) {
if (slhp->type() == LINK_GSL_REPEATER)
continue;
if (!slhp->linkup_)
continue;
phytxp = (Phy *) slhp->phy_tx();
assert(phytxp);
channelp = phytxp->channel();
if (!channelp)
continue; // Not currently connected to channel
// Next, look for receive interfaces on this channel
phyrxp = channelp->ifhead_.lh_first;
for (; phyrxp; phyrxp = phyrxp->nextchnl()) {
if (phyrxp == phytxp) {
printf("Configuration error: a transmit interface \
is a channel target\n");
exit(1);
}
if (phyrxp->head()->type() == LINK_GSL_REPEATER) {
double delay_firsthop = ((SatChannel*)
channelp)->get_pdelay(phytxp->node(),
phyrxp->node());
if (!((SatLinkHead*)phyrxp->head())->linkup_)
continue;
phytxp2 = ((SatLinkHead*)phyrxp->head())->phy_tx();
channelp2 = phytxp2->channel();
if (!channelp2)
continue; // Not currently connected to channel
phyrxp2 = channelp2->ifhead_.lh_first;
for (; phyrxp2; phyrxp2 = phyrxp2->nextchnl()) {
if (phyrxp2 == phytxp2) {
printf("Config error: a transmit interface \
is a channel target\n");
exit(1);
}
// Found an adjacency relationship.
// Add this link to the RouteLogic
src = phytxp->node()->address() + 1;
dst = phyrxp2->node()->address() + 1;
if (src == dst)
continue;
if (metric_delay_)
delay = ((SatChannel*)
channelp2)->get_pdelay(phytxp2->node(),
phyrxp2->node());
else {
delay = 1;
delay_firsthop = 0;
}
insert(src, dst, delay+delay_firsthop, (void*)slhp);
}
} else {
// Found an adjacency relationship.
// Add this link to the RouteLogic
src = phytxp->node()->address() + 1;
dst = phyrxp->node()->address() + 1;
if (metric_delay_)
delay = ((SatChannel*)
channelp)->get_pdelay(phytxp->node(),
phyrxp->node());
else
delay = 1;
insert(src, dst, delay, (void*)slhp);
}
}
}
}
//dump();
}
void SatRouteObject::populate_routing_tables(int node)
{
SatNode *snodep = (SatNode*) Node::nodehead_.lh_first;
SatNode *snodep2;
int next_hop, src, dst;
NsObject *target;
for (; snodep; snodep = (SatNode*) snodep->nextnode()) {
// First, clear slots of the current routing table
if (snodep->ragent())
snodep->ragent()->clear_slots();
src = snodep->address();
if (node != -1 && node != src)
continue;
snodep2 = (SatNode*) Node::nodehead_.lh_first;
for (; snodep2; snodep2 = (SatNode*) snodep2->nextnode()) {
dst = snodep2->address();
next_hop = lookup(src, dst);
if (next_hop != -1 && src != dst) {
// Here need to insert target into slot table
target = (NsObject*) lookup_entry(src, dst);
if (target == 0) {
printf("Error, routelogic target ");
printf("not populated %f\n", NOW);
exit(1);
}
((SatNode*)snodep)->ragent()->install(dst,
next_hop, target);
}
}
}
}
int SatRouteObject::lookup(int s, int d)
{
int src = s + 1;
int dst = d + 1;
if (src >= size_ || dst >= size_) {
return (-1); // Next hop = -1
}
return (route_[INDEX(src, dst, size_)].next_hop - 1);
}
void* SatRouteObject::lookup_entry(int s, int d)
{
int src = s + 1;
int dst = d + 1;
if (src >= size_ || dst >= size_) {
return (0); // Null pointer
}
return (route_[INDEX(src, dst, size_)].entry);
}
// This method is used for debugging only
void SatRouteObject::dump()
{
int i, src, dst;
for (i = 0; i < (size_ * size_); i++) {
if (adj_[i].cost != INFINITY) {
src = i / size_ - 1;
dst = i % size_ - 1;
printf("Found a link from %d to %d with cost %f\n", src, dst, adj_[i].cost);
}
/*
if (route_[i].next_hop) {
src = i / size_ - 1;
dst = i % size_ - 1;
printf("Found a route from %d to %d through %d\n", src, dst, route_[i].next_hop - 1);
}
*/
}
}
void SatRouteObject::node_compute_routes(int node)
{
int n = size_;
int* parent = new int[n];
double* hopcnt = new double[n];
#define ADJ(i, j) adj_[INDEX(i, j, size_)].cost
#define ADJ_ENTRY(i, j) adj_[INDEX(i, j, size_)].entry
#define ROUTE(i, j) route_[INDEX(i, j, size_)].next_hop
#define ROUTE_ENTRY(i, j) route_[INDEX(i, j, size_)].entry
delete[] route_;
route_ = new route_entry[n * n];
memset((char *)route_, 0, n * n * sizeof(route_[0]));
/* compute routes only for node "node" */
int k = node + 1; // must add one to get the right offset in tables
int v;
for (v = 0; v < n; v++)
parent[v] = v;
/* set the route for all neighbours first */
for (v = 1; v < n; ++v) {
if (parent[v] != k) {
hopcnt[v] = ADJ(k, v);
if (hopcnt[v] != INFINITY) {
ROUTE(k, v) = v;
ROUTE_ENTRY(k, v) = ADJ_ENTRY(k, v);
}
}
}
for (v = 1; v < n; ++v) {
/*
* w is the node that is the nearest to the subtree
* that has been routed
*/
int o = 0;
/* XXX */
hopcnt[0] = INFINITY;
int w;
for (w = 1; w < n; w++)
if (parent[w] != k && hopcnt[w] < hopcnt[o])
o = w;
parent[o] = k;
/*
* update distance counts for the nodes that are
* adjacent to o
*/
if (o == 0)
continue;
for (w = 1; w < n; w++) {
if (parent[w] != k &&
hopcnt[o] + ADJ(o, w) < hopcnt[w]) {
ROUTE(k, w) = ROUTE(k, o);
ROUTE_ENTRY(k, w) =
ROUTE_ENTRY(k, o);
hopcnt[w] = hopcnt[o] + ADJ(o, w);
}
}
}
/*
* The route to yourself is yourself.
*/
ROUTE(k, k) = k;
ROUTE_ENTRY(k, k) = 0; // This should not matter
delete[] hopcnt;
delete[] parent;
}
sattrace.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* Copyright (c) 1999 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 Tom Henderson, UCB Daedalus Research Group, June 1999
* speedup hack from Lloyd Wood, 11 October 1999 */
#ifndef lint
static const char rcsid[] =
"@(#) $Header$";
#endif
#include
#include
#include "packet.h"
#include "ip.h"
#include "tcp.h"
#include "rtp.h"
#include "srm.h"
#include "flags.h"
#include "address.h"
#include "trace.h"
#include "sattrace.h"
#include "satposition.h"
#include "satnode.h"
class SatTraceClass : public TclClass {
public:
SatTraceClass() : TclClass("Trace/Sat") { }
TclObject* create(int argc, const char*const* argv) {
if (argc >= 5) {
return (new SatTrace(*argv[4]));
}
return 0;
}
} sat_trace_class;
// XXX this should be moved from trace.cc to trace.h
char* srm_names_[] = {
SRM_NAMES
};
void SatTrace::format(int tt, int s, int d, Packet* p)
{
#ifdef OFF_HDR
hdr_cmn *th = (hdr_cmn*)p->access(off_cmn_);
hdr_ip *iph = (hdr_ip*)p->access(off_ip_);
hdr_tcp *tcph = (hdr_tcp*)p->access(off_tcp_);
hdr_rtp *rh = (hdr_rtp*)p->access(off_rtp_);
hdr_srm *sh = (hdr_srm*)p->access(off_srm_);
#else
hdr_cmn *th = hdr_cmn::access(p);
hdr_ip *iph = hdr_ip::access(p);
hdr_tcp *tcph = hdr_tcp::access(p);
hdr_rtp *rh = hdr_rtp::access(p);
hdr_srm *sh = hdr_srm::access(p);
#endif
const char* sname = "null";
int lasth, nexth, snadd;
Node* n;
packet_t t = th->ptype();
const char* name = packet_info.name(t);
/* SRM-specific */
if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) {
if ( sh->type() < 5 && sh->type() > 0 ) {
sname = srm_names_[sh->type()];
}
}
if (name == 0)
abort();
int seqno;
/* UDP's now have seqno's too */
if (t == PT_RTP || t == PT_CBR || t == PT_UDP || t == PT_EXP ||
t == PT_PARETO)
seqno = rh->seqno();
else if (t == PT_TCP || t == PT_ACK || t == PT_HTTP || t == PT_FTP ||
t == PT_TELNET)
seqno = tcph->seqno();
else
seqno = -1;
/*
* When new flags are added, make sure to change NUMFLAGS
* in trace.h
*/
char flags[NUMFLAGS+1];
for (int i = 0; i < NUMFLAGS; i++)
flags[i] = '-';
flags[NUMFLAGS] = 0;
#ifdef OFF_HDR
hdr_flags* hf = (hdr_flags*)p->access(off_flags_);
#else
hdr_flags* hf = hdr_flags::access(p);
#endif
flags[0] = hf->ecn_ ? 'C' : '-'; // Ecn Echo
flags[1] = hf->pri_ ? 'P' : '-';
flags[2] = '-';
flags[3] = hf->cong_action_ ? 'A' : '-'; // Congestion Action
flags[4] = hf->ecn_to_echo_ ? 'E' : '-'; // Congestion Experienced
flags[5] = hf->fs_ ? 'F' : '-';
flags[6] = hf->ecn_capable_ ? 'N' : '-';
#ifdef notdef
flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-';
flags[2] = (iph->flags() & PF_USR1) ? '1' : '-';
flags[3] = (iph->flags() & PF_USR2) ? '2' : '-';
flags[5] = 0;
#endif
char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr());
char *src_portaddr = Address::instance().print_portaddr(iph->sport());
char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr());
char *dst_portaddr = Address::instance().print_portaddr(iph->dport());
// Find position of previous hop and next hop
double s_lat = -999, s_lon = -999, d_lat = -999, d_lon = -999;
n = Node::nodehead_.lh_first;
// XXX what if n is not a SatNode?? Need a dynamic cast here, or make sure that
// only sat tracing elements go between sat nodes.
// SatNode *sn = dynamic_cast(n);
if (n) {
lasth = th->last_hop_;
nexth = th->next_hop_;
for (; n; n = n->nextnode() ) {
SatNode *sn = (SatNode*) n;
snadd = sn->address();
if (lasth == snadd) {
s_lat = RAD_TO_DEG(SatGeometry::get_latitude(sn->position()->coord()));
s_lon = RAD_TO_DEG(SatGeometry::get_longitude(sn->position()->coord()));
if (d_lat != -999)
break; // Have now found both s and d
}
if (nexth == snadd) {
d_lat = RAD_TO_DEG(SatGeometry::get_latitude(sn->position()->coord()));
d_lon = RAD_TO_DEG(SatGeometry::get_longitude(sn->position()->coord()));
if (s_lat != -999)
break; // Have now found both s and d
}
}
}
if (!show_tcphdr_) {
sprintf(wrk_, "%c %.4f %d %d %s %d %s %d %s.%s %s.%s %d %d %.2f %.2f %.2f %.2f",
tt,
round(Scheduler::instance().clock()),
lasth,
nexth,
name,
th->size(),
flags,
iph->flowid() /* was p->class_ */,
// iph->src() >> (Address::instance().NodeShift_[1]),
// iph->src() & (Address::instance().PortMask_),
// iph->dst() >> (Address::instance().NodeShift_[1]),
// iph->dst() & (Address::instance().PortMask_),
src_nodeaddr,
src_portaddr,
dst_nodeaddr,
dst_portaddr,
seqno,
th->uid(), /* was p->uid_ */
s_lat,
s_lon,
d_lat,
d_lon);
} else {
sprintf(wrk_,
"%c %.4f %d %d %s %d %s %d %s.%s %s.%s %d %d %d 0x%x %d %d %.2f %.2f %.2f %.2f",
tt,
round(Scheduler::instance().clock()),
lasth,
nexth,
name,
th->size(),
flags,
iph->flowid(), /* was p->class_ */
// iph->src() >> (Address::instance().NodeShift_[1]),
// iph->src() & (Address::instance().PortMask_),
// iph->dst() >> (Address::instance().NodeShift_[1]),
// iph->dst() & (Address::instance().PortMask_),
src_nodeaddr,
src_portaddr,
dst_nodeaddr,
dst_portaddr,
seqno,
th->uid(), /* was p->uid_ */
tcph->ackno(),
tcph->flags(),
tcph->hlen(),
tcph->sa_length(),
s_lat,
s_lon,
d_lat,
d_lon);
}
#ifdef NAM_TRACE
if (namChan_ != 0)
sprintf(nwrk_,
"%c -t %g -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
tt,
Scheduler::instance().clock(),
s,
d,
name,
th->size(),
iph->flowid(),
th->uid(),
iph->flowid(),
src_nodeaddr,
src_portaddr,
dst_nodeaddr,
dst_portaddr,
seqno,flags,sname);
#endif
delete [] src_nodeaddr;
delete [] src_portaddr;
delete [] dst_nodeaddr;
delete [] dst_portaddr;
}
void SatTrace::traceonly(Packet* p)
{
format(type_, src_, dst_, p);
dump();
}
//
// we need a DequeTraceClass here because a 'h' event need to go together
// with the '-' event. It's possible to use a postprocessing script, but
// seems that's inconvient.
//
static class SatDequeTraceClass : public TclClass {
public:
SatDequeTraceClass() : TclClass("Trace/Sat/Deque") { }
TclObject* create(int args, const char*const* argv) {
if (args >= 5)
return (new SatDequeTrace(*argv[4]));
return NULL;
}
} sat_dequetrace_class;
void
SatDequeTrace::recv(Packet* p, Handler* h)
{
// write the '-' event first
format(type_, src_, dst_, p);
dump();
namdump();
#ifdef NAM_TRACE
if (namChan_ != 0) {
#ifdef OFF_HDR
hdr_cmn *th = (hdr_cmn*)p->access(off_cmn_);
hdr_ip *iph = (hdr_ip*)p->access(off_ip_);
hdr_srm *sh = (hdr_srm*)p->access(off_srm_);
#else
hdr_cmn *th = hdr_cmn::access(p);
hdr_ip *iph = hdr_ip::access(p);
hdr_srm *sh = hdr_srm::access(p);
#endif
const char* sname = "null";
packet_t t = th->ptype();
const char* name = packet_info.name(t);
if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) {
if ( sh->type() < 5 && sh->type() > 0 ) {
sname = srm_names_[sh->type()];
}
}
char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr());
char *src_portaddr = Address::instance().print_portaddr(iph->sport());
char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr());
char *dst_portaddr = Address::instance().print_portaddr(iph->dport());
char flags[NUMFLAGS+1];
for (int i = 0; i < NUMFLAGS; i++)
flags[i] = '-';
flags[NUMFLAGS] = 0;
#ifdef OFF_HDR
hdr_flags* hf = (hdr_flags*)p->access(off_flags_);
#else
hdr_flags* hf = hdr_flags::access(p);
#endif
flags[0] = hf->ecn_ ? 'C' : '-'; // Ecn Echo
flags[1] = hf->pri_ ? 'P' : '-';
flags[2] = '-';
flags[3] = hf->cong_action_ ? 'A' : '-'; // Congestion Action
flags[4] = hf->ecn_to_echo_ ? 'E' : '-'; // Congestion Experienced
flags[5] = hf->fs_ ? 'F' : '-';
flags[6] = hf->ecn_capable_ ? 'N' : '-';
#ifdef notdef
flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-';
flags[2] = (iph->flags() & PF_USR1) ? '1' : '-';
flags[3] = (iph->flags() & PF_USR2) ? '2' : '-';
flags[5] = 0;
#endif
sprintf(nwrk_,
"%c -t %g -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}",
'h',
Scheduler::instance().clock(),
src_,
dst_,
name,
th->size(),
iph->flowid(),
th->uid(),
iph->flowid(),
src_nodeaddr,
src_portaddr,
dst_nodeaddr,
dst_portaddr,
-1, flags, sname);
namdump();
delete [] src_nodeaddr;
delete [] src_portaddr;
delete [] dst_nodeaddr;
delete [] dst_portaddr;
}
#endif
/* hack: if trace object not attached to anything free packet */
if (target_ == 0)
Packet::free(p);
else
send(p, h);
}
scheduler.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.
*
* @(#) $Header$
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
#include
#include
#include "config.h"
#include "scheduler.h"
#include "packet.h"
#ifdef MEMDEBUG_SIMULATIONS
#include "mem-trace.h"
#endif
#include
Scheduler* Scheduler::instance_;
int Scheduler::uid_ = 1;
// class AtEvent : public Event {
// public:
// char* proc_;
// };
Scheduler::Scheduler() : clock_(SCHED_START), halted_(0)
{
}
/*
* Schedule an event delay time units into the future.
* The event will be dispatched to the specified handler.
* We use a relative time to avoid the problem of scheduling
* something in the past.
*/
void Scheduler::schedule(Handler* h, Event* e, double delay)
{
if (e->uid_ > 0) {
printf("Scheduler: Event UID not valid!\n\n");
abort();
}
if (delay < 0) {
// You probably don't want to do this
// (it probably represents a bug in your simulation).
fprintf(stderr, "warning: ns Scheduler::schedule: scheduling event\n\twith negative delay (%f) at time %f.\n", delay, clock_);
}
if (uid_ < 0 || uid_ >= INT_MAX) {
fprintf(stderr, "Scheduler: UID space exhausted!\n");
abort();
}
e->uid_ = uid_++;
e->handler_ = h;
double t = clock_ + delay;
e->time_ = t;
insert(e);
}
void
Scheduler::run()
{
instance_ = this;
Event *p;
while ((p = deque()) && !halted_) {
dispatch(p);
}
}
/*
* dispatch a single simulator event by setting the system
* virtul clock to the event's timestamp and calling its handler.
* Note that the event may have side effects of placing other items
* in the scheduling queue
*/
void
Scheduler::dispatch(Event* p, double t)
{
if (t < clock_) {
fprintf(stderr, "ns: scheduler going backwards in time from %f to %f.\n", clock_, t);
}
clock_ = t;
p->uid_ = -p->uid_; // being dispatched
p->handler_->handle(p); // dispatch
}
void
Scheduler::dispatch(Event* p)
{
dispatch(p, p->time_);
}
class AtEvent : public Event {
public:
AtEvent() : proc_(0) {
}
~AtEvent() {
if (proc_) delete [] proc_;
}
char* proc_;
};
class AtHandler : public Handler {
public:
void handle(Event* event);
} at_handler;
void AtHandler::handle(Event* e)
{
AtEvent* at = (AtEvent*)e;
Tcl::instance().eval(at->proc_);
delete at;
}
void
Scheduler::reset()
{
clock_ = SCHED_START;
}
int Scheduler::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (instance_ == 0)
instance_ = this;
if (argc == 2) {
if (strcmp(argv[1], "run") == 0) {
/* set global to 0 before calling object reset methods */
reset(); // sets clock to zero
run();
return (TCL_OK);
} else if (strcmp(argv[1], "now") == 0) {
sprintf(tcl.buffer(), "%.17g", clock());
tcl.result(tcl.buffer());
return (TCL_OK);
} else if (strcmp(argv[1], "resume") == 0) {
halted_ = 0;
run();
return (TCL_OK);
} else if (strcmp(argv[1], "halt") == 0) {
halted_ = 1;
return (TCL_OK);
} else if (strcmp(argv[1], "clearMemTrace") == 0) {
#ifdef MEMDEBUG_SIMULATIONS
extern MemTrace *globalMemTrace;
if (globalMemTrace)
globalMemTrace->diff("Sim.");
#endif
return (TCL_OK);
} else if (strcmp(argv[1], "is-running") == 0) {
sprintf(tcl.buffer(), "%d", !halted_);
return (TCL_OK);
} else if (strcmp(argv[1], "dumpq") == 0) {
if (!halted_) {
fprintf(stderr, "Scheduler: dumpq only allowed while halted\n");
tcl.result("0");
return (TCL_ERROR);
}
dumpq();
return (TCL_OK);
}
} else if (argc == 3) {
if (strcmp(argv[1], "at") == 0 ||
strcmp(argv[1], "cancel") == 0) {
Event* p = lookup(atoi(argv[2]));
if (p != 0) {
/*XXX make sure it really is an atevent*/
cancel(p);
AtEvent* ae = (AtEvent*)p;
delete ae;
}
} else if (strcmp(argv[1], "at-now") == 0) {
const char* proc = argv[2];
// "at [$ns now]" may not work because of tcl's
// string number resolution
AtEvent* e = new AtEvent;
int n = strlen(proc);
e->proc_ = new char[n + 1];
strcpy(e->proc_, proc);
schedule(&at_handler, e, 0);
sprintf(tcl.buffer(), "%u", e->uid_);
tcl.result(tcl.buffer());
}
return (TCL_OK);
} else if (argc == 4) {
if (strcmp(argv[1], "at") == 0) {
/* t < 0 means relative time: delay = -t */
double delay, t = atof(argv[2]);
const char* proc = argv[3];
AtEvent* e = new AtEvent;
int n = strlen(proc);
e->proc_ = new char[n + 1];
strcpy(e->proc_, proc);
delay = (t < 0) ? -t : t - clock();
if (delay < 0) {
tcl.result("can't schedule command in past");
return (TCL_ERROR);
}
schedule(&at_handler, e, delay);
sprintf(tcl.buffer(), "%u", e->uid_);
tcl.result(tcl.buffer());
return (TCL_OK);
}
}
return (TclObject::command(argc, argv));
}
void
Scheduler::dumpq()
{
Event *p;
printf("Contents of scheduler queue (events) [cur time: %f]---\n",
clock());
while ((p = deque()) != NULL) {
printf("t:%f uid: %d handler: %p\n",
p->time_, p->uid_, p->handler_);
}
}
static class ListSchedulerClass : public TclClass {
public:
ListSchedulerClass() : TclClass("Scheduler/List") {}
TclObject* create(int /* argc */, const char*const* /* argv */) {
return (new ListScheduler);
}
} class_list_sched;
void ListScheduler::insert(Event* e)
{
double t = e->time_;
Event** p;
for (p = &queue_; *p != 0; p = &(*p)->next_)
if (t < (*p)->time_)
break;
e->next_ = *p;
*p = e;
}
/*
* Cancel an event. It is an error to call this routine
* when the event is not actually in the queue. The caller
* must free the event if necessary; this routine only removes
* it from the scheduler queue.
*/
void ListScheduler::cancel(Event* e)
{
Event** p;
if (e->uid_ <= 0) // event not in queue
return;
for (p = &queue_; *p != e; p = &(*p)->next_)
if (*p == 0)
abort();
*p = (*p)->next_;
e->uid_ = - e->uid_;
}
Event* ListScheduler::lookup(int uid)
{
Event* e;
for (e = queue_; e != 0; e = e->next_)
if (e->uid_ == uid)
break;
return (e);
}
Event*
ListScheduler::deque()
{
Event* e = queue_;
if (e)
queue_ = e->next_;
return (e);
}
#include "heap.h"
Heap::Heap(int size)
: h_s_key(0), h_size(0), h_maxsize(size), h_iter(0)
{
h_elems = new Heap_elem[h_maxsize];
memset(h_elems, 0, h_maxsize*sizeof(Heap_elem));
//for (unsigned int i = 0; i < h_maxsize; i++)
// h_elems[i].he_elem = 0;
}
Heap::~Heap()
{
delete [] h_elems;
}
/*
* int heap_member(Heap *h, void *elem): O(n) algorithm.
*
* Returns index(elem \in h->he_elems[]) + 1,
* if elem \in h->he_elems[],
* 0, otherwise.
* External callers should just test for zero, or non-zero.
* heap_delete() uses this routine to find an element in the heap.
*/
int
Heap::heap_member(void* elem)
{
unsigned int i;
Heap::Heap_elem* he;
for (i = 0, he = h_elems; i < h_size; i++, he++)
if (he->he_elem == elem)
return ++i;
return 0;
}
/*
* int heap_delete(Heap *h, void *elem): O(n) algorithm
*
* Returns 1 for success, 0 otherwise.
*
* find elem in h->h_elems[] using heap_member()
*
* To actually remove the element from the tree, first swap it to the
* root (similar to the procedure applied when inserting a new
* element, but no key comparisons--just get it to the root).
*
* Then call heap_extract_min() to remove it & fix the tree.
* This process is not the most efficient, but we do not
* particularily care about how fast heap_delete() is.
* Besides, heap_member() is already O(n),
* and is the dominating cost.
*
* Actually remove the element by calling heap_extract_min().
* The key that is now at the root is not necessarily the
* minimum, but heap_extract_min() does not care--it just
* removes the root.
*/
int
Heap::heap_delete(void* elem)
{
int i;
if ((i = heap_member(elem)) == 0)
return 0;
for (--i; i; i = parent(i)) {
swap(i, parent(i));
}
(void) heap_extract_min();
return 1;
}
/*
* void heap_insert(Heap *h, heap_key_t *key, void *elem)
*
* Insert into heap h.
* Adjust heap_size if we hit the limit.
*
* i := heap_size(h)
* heap_size := heap_size + 1
* while (i > 0 and key < h[Parent(i)])
* do h[i] := h[Parent(i)]
* i := Parent(i)
* h[i] := key
*/
void
Heap::heap_insert(heap_key_t key, void* elem)
{
unsigned int i, par;
if (h_maxsize == h_size) { /* Adjust heap_size */
unsigned int osize = h_maxsize;
Heap::Heap_elem *he_old = h_elems;
h_maxsize *= 2;
h_elems = new Heap::Heap_elem[h_maxsize];
memcpy(h_elems, he_old, osize*sizeof(Heap::Heap_elem));
//for (i = 0; i < osize; i++)
// h_elems[i] = he_old[i];
//delete he_old;
}
i = h_size++;
par = parent(i);
while ((i > 0) &&
(KEY_LESS_THAN(key, h_s_key,
h_elems[par].he_key, h_elems[par].he_s_key))) {
h_elems[i] = h_elems[par];
i = par;
par = parent(i);
}
h_elems[i].he_key = key;
h_elems[i].he_s_key= h_s_key++;
h_elems[i].he_elem = elem;
return;
};
/*
* void *heap_extract_min(Heap *h)
*
* Returns the smallest element in the heap, if it exists.
* NULL otherwise.
*
* if heap_size[h] == 0
* return NULL
* min := h[0]
* heap_size[h] := heap_size[h] - 1 # C array indices start at 0
* h[0] := h[heap_size[h]]
* Heapify:
* i := 0
* while (i < heap_size[h])
* do l = HEAP_LEFT(i)
* r = HEAP_RIGHT(i)
* if (r < heap_size[h])
* # right child exists =>
* # left child exists
* then if (h[l] < h[r])
* then try := l
* else try := r
* else
* if (l < heap_size[h])
* then try := l
* else try := i
* if (h[try] < h[i])
* then HEAP_SWAP(h[i], h[try])
* i := try
* else break
* done
*/
void*
Heap::heap_extract_min()
{
void* min; /* return value */
unsigned int i;
unsigned int l, r, x;
if (h_size == 0)
return 0;
min = h_elems[0].he_elem;
h_elems[0] = h_elems[--h_size];
// Heapify:
i = 0;
while (i < h_size) {
l = left(i);
r = right(i);
if (r < h_size) {
if (KEY_LESS_THAN(h_elems[l].he_key, h_elems[l].he_s_key,
h_elems[r].he_key, h_elems[r].he_s_key))
x= l;
else
x= r;
} else
x = (l < h_size ? l : i);
if ((x != i) &&
(KEY_LESS_THAN(h_elems[x].he_key, h_elems[x].he_s_key,
h_elems[i].he_key, h_elems[i].he_s_key))) {
swap(i, x);
i = x;
} else {
break;
}
}
return min;
}
static class HeapSchedulerClass : public TclClass {
public:
HeapSchedulerClass() : TclClass("Scheduler/Heap") {}
TclObject* create(int /* argc */, const char*const* /* argv */) {
return (new HeapScheduler);
}
} class_heap_sched;
Event* HeapScheduler::lookup(int uid)
{
Event* e;
for (e = (Event*) hp_->heap_iter_init(); e;
e = (Event*) hp_->heap_iter())
if (e->uid_ == uid)
break;
return e;
}
Event*
HeapScheduler::deque()
{
return ((Event*) hp_->heap_extract_min());
}
/*
* Calendar queue scheduler contributed by
* David Wetherall
* March 18, 1997.
*
* A calendar queue basically hashes events into buckets based on
* arrival time.
*
* See R.Brown. "Calendar queues: A fast O(1) priority queue implementation
* for the simulation event set problem."
* Comm. of ACM, 31(10):1220-1227, Oct 1988
*/
static class CalendarSchedulerClass : public TclClass {
public:
CalendarSchedulerClass() : TclClass("Scheduler/Calendar") {}
TclObject* create(int /* argc */, const char*const* /* argv */) {
return (new CalendarScheduler);
}
} class_calendar_sched;
CalendarScheduler::CalendarScheduler() {
reinit(2, 1.0, 0.0);
resizeenabled_ = 1;
max_ = 0.0;
}
CalendarScheduler::~CalendarScheduler() {
delete [] buckets_;
qsize_ = 0;
}
void CalendarScheduler::insert(Event* e)
{
/* (e->time_ * oneonwidth) needs to be less than the
* largest integer on the machine for the mapping
* of time to bucket to work properly. if it is not
* we need to re-calculate the width.
*/
if (e->time_ > max_) {
max_ = e->time_;
if (e->time_ * oneonwidth_ > ULONG_MAX) {
resize(nbuckets_);
}
}
// bucket number and address
int i = (int)(((long)(e->time_ * oneonwidth_)) & buckbits_);
Event** p = buckets_ + i;
// insert event in stable time sorted order
while ((*p != NULL) && (e->time_ >= (*p)->time_))
p = &(*p)->next_;
e->next_ = *p;
*p = e;
if (++qsize_ > top_threshold_)
resize(nbuckets_<<1);
}
Event*
CalendarScheduler::deque()
{
if (qsize_ == 0)
return NULL;
for (;;) {
int i = lastbucket_;
// check for an event this `year'
do {
Event* e = buckets_[i];
if ((e != NULL) && (e->time_ < buckettop_)) {
buckets_[i] = e->next_;
lastbucket_ = i;
last_clock_ = e->time_;
if (--qsize_ < bot_threshold_)
resize(nbuckets_>>1);
return e;
} else {
if (++i == nbuckets_) {
i = 0;
/* Brad Karp, karp@eecs.harvard.edu:
at the end of each year, eliminate roundoff
error in buckettop_ */
buckettop_ = prevtop_ + nbuckets_ * width_;
prevtop_ = buckettop_;
} else {
buckettop_+= width_;
}
}
} while (i != lastbucket_);
// or direct search for the minimum event
int pos = 0;
Event* min;
do {
min = buckets_[pos++];
} while (min == NULL);
pos--;
int k;
for (k = pos+1; k < nbuckets_; k++) {
Event* e = buckets_[k];
if ((e != NULL) && (e->time_ < min->time_)) {
min = e; pos = k;
}
}
// adjust year and resume
lastbucket_ = pos;
last_clock_ = min->time_;
unsigned long n = (unsigned long)(min->time_ * oneonwidth_);
buckettop_ = width_*(n+1.5);
prevtop_ = buckettop_ - lastbucket_ * width_;
}
//return deque();
}
void CalendarScheduler::reinit(int nbuck, double bwidth, double start)
{
buckets_ = new Event*[nbuck];
memset(buckets_, 0, sizeof(Event*)*nbuck);
width_ = bwidth;
oneonwidth_ = 1.0 / width_;
nbuckets_ = nbuck;
buckbits_ = nbuck-1;
qsize_ = 0;
last_clock_ = start;
long n = (long)(start * oneonwidth_);
lastbucket_ = n & buckbits_;
buckettop_ = width_*(n+1.5);
prevtop_ = buckettop_ - lastbucket_ * width_;
bot_threshold_ = (nbuck >> 1) - 2;
top_threshold_ = (nbuck << 1);
}
void CalendarScheduler::resize(int newsize)
{
if (!resizeenabled_) return;
double bwidth = newwidth();
Event** oldb = buckets_;
int oldn = nbuckets_;
// copy events to new buckets
reinit(newsize, bwidth, clock_);
int i;
for (i = oldn-1; i >= 0; i--) {
Event* e = oldb[i];
while (e != NULL) {
Event* en = e->next_;
insert(e);
e = en;
}
}
delete [] oldb;
}
#define MIN_WIDTH (1.0e-6)
#define MAX_HOLD 25
double
CalendarScheduler::newwidth()
{
static Event* hold[MAX_HOLD];
int nsamples;
if (qsize_ < 2) return 1.0;
if (qsize_ < 5) nsamples = qsize_;
else nsamples = 5 + qsize_ / 10;
if (nsamples > MAX_HOLD) nsamples = MAX_HOLD;
// dequue and requeue sample events to gauge width
double olp = clock_;
double olt = buckettop_;
int olb = lastbucket_;
double olbt = prevtop_;
resizeenabled_ = 0;
for (int i = 0; i < nsamples; i++) hold[i] = deque();
// insert in the inverse order and using insert2 to take care of same-time events.
for (int j = nsamples-1; j >= 0; j--) insert2(hold[j]);
resizeenabled_ = 1;
clock_ = olp;
buckettop_ = olt;
prevtop_ = olbt;
lastbucket_ = olb;
// try to work out average cluster separation
double asep = (hold[nsamples-1]->time_ - hold[0]->time_) / (nsamples-1);
double asep2 = 0.0;
double min = (clock_ + 1.0) * MIN_WIDTH;
int count = 0;
for (int k = 1; k < nsamples; k++) {
double diff = hold[k]->time_ - hold[k-1]->time_;
if (diff < 2.0*asep) { asep2 += diff; count++; }
}
// but don't let things get too small for numerical stability
double nw = count ? 3.0*(asep2/count) : asep;
if (nw < min) nw = min;
/* need to make sure that time_/width_ can be represented as
* an int. see the comment at the start of insert().
*/
if (max_/nw > ULONG_MAX) {
nw = max_/ULONG_MAX;
}
return nw;
}
/*
* Cancel an event. It is an error to call this routine
* when the event is not actually in the queue. The caller
* must free the event if necessary; this routine only removes
* it from the scheduler queue.
*
* xxx: we may cancel the last event and invalidate the value of max_
* xxx: thus using wider buckets than really necessary
*/
void CalendarScheduler::cancel(Event* e)
{
int i = (int)(((long)(e->time_ * oneonwidth_)) & buckbits_);
if (e->uid_ <= 0) // event not in queue
return;
for (Event** p = buckets_ + i; (*p) != NULL; p = &(*p)->next_)
if ((*p) == e) {
(*p) = (*p)->next_;
e->uid_ = - e->uid_;
qsize_--;
return;
}
abort();
}
Event* CalendarScheduler::lookup(int uid)
{
for (int i = 0; i < nbuckets_; i++)
for (Event* p = buckets_[i]; p != NULL; p = p->next_)
if (p->uid_== uid) return p;
return NULL;
}
void CalendarScheduler::insert2(Event* e)
{
// Same as insert, but for inserts e *before* any same-time-events, if
// there should be any. Since it is used only by CalendarScheduler::newwidth(),
// some important checks present in insert() need not be performed.
// bucket number and address
int i = (int)(((long)(e->time_ * oneonwidth_)) & buckbits_);
Event** p = buckets_ + i;
// insert event in stable time sorted order
while ((*p != NULL) && (e->time_ > (*p)->time_)) // > instead of >=!
p = &(*p)->next_;
e->next_ = *p;
*p = e;
++qsize_;
}
#ifndef WIN32
#include
#endif
/*
* Really should instance the list/calendar/heap discipline
* inside a RealTimeScheduler or VirtualTimeScheduler
*/
#ifdef notyet
class RealTimeScheduler : public CalendarScheduler {
#endif
class RealTimeScheduler : public ListScheduler {
public:
RealTimeScheduler();
virtual void run();
double start() const { return start_; }
virtual void reset();
protected:
void sync() { clock_ = tod(); }
int rwait(double); // sleep
double tod();
double slop_; // allowed drift between real-time and virt time
double start_; // starting time
};
static class RealTimeSchedulerClass : public TclClass {
public:
RealTimeSchedulerClass() : TclClass("Scheduler/RealTime") {}
TclObject* create(int /* argc */, const char*const* /* argv */) {
return (new RealTimeScheduler);
}
} class_realtime_sched;
RealTimeScheduler::RealTimeScheduler() : start_(0.0)
{
bind("maxslop_", &slop_);
}
double
RealTimeScheduler::tod()
{
timeval tv;
gettimeofday(&tv, 0);
double s = tv.tv_sec;
s += (1e-6 * tv.tv_usec);
return (s - start_);
}
// XXX not used?
// static void nullTimer(ClientData)
// {
// }
void
RealTimeScheduler::reset()
{
clock_ = SCHED_START;
start_ = tod();
}
void RealTimeScheduler::run()
{
Event *p;
double now;
/*XXX*/
instance_ = this;
while (!halted_) {
now = tod();
//if ((clock_ - now) > slop_) {
if ((now - clock_) > slop_) {
fprintf(stderr,
"RealTimeScheduler: warning: slop %f exceeded limit %f [now:%f, clock_:%f\n",
now - clock_, slop_, now, clock_);
}
//
// first handle any "old events"
//
while ((p = deque()) != NULL && (p->time_ <= now)) {
dispatch(p);
}
//
// now handle a "future event", if there is one
//
if (p != NULL) {
int rval = rwait(p->time_);
if (rval < 0) {
fprintf(stderr, "RTScheduler: wait problem\n");
abort();
} else if (rval == 0) {
//
// proper time to dispatch sim event... do so
//
dispatch(p, clock_);
} else {
//
// there was a simulator event which fired, and
// may have added something to the queue, which
// could cause our event p to not be the next,
// so put p back into the event queue and cont
//
insert(p);
}
continue;
}
//
// no sim events to handle at all, check with tcl
//
sync();
Tcl_DoOneEvent(TCL_DONT_WAIT);
}
return; // we reach here only if halted
}
/*
* wait until the specified amount has elapsed, or a tcl event has happened,
* whichever comes first. Return 1 if a tcl event happened, 0 if the
* deadline has been reached, or -1 on error (shouldn't happen).
*/
int
RealTimeScheduler::rwait(double deadline)
{
while (1) {
sync();
if (Tcl_DoOneEvent(TCL_DONT_WAIT) == 1)
return (1);
if (deadline <= tod())
return 0;
}
return -1;
}
scoreboard.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* 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.
*/
/* 9/96 Pittsburgh Supercomputing Center
* UpdateScoreBoard, CheckSndNxt, MarkRetran modified for fack
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (LBL)";
#endif
/* A quick hack version of the scoreboard */
#include
#include
#include
#include
#include "packet.h"
#include "scoreboard.h"
#include "tcp.h"
#define ASSERT(x) if (!(x)) {printf ("Assert SB failed\n"); exit(1);}
#define ASSERT1(x) if (!(x)) {printf ("Assert1 SB (length)\n"); exit(1);}
#define SBNI SBN[i%SBSIZE]
// last_ack = TCP last ack
int ScoreBoard::UpdateScoreBoard (int last_ack, hdr_tcp* tcph)
{
int i, sack_index, sack_left, sack_right;
int retran_decr = 0;
// If there is no scoreboard, create one.
if (length_ == 0) {
i = last_ack+1;
SBNI.seq_no_ = i;
SBNI.ack_flag_ = 0;
SBNI.sack_flag_ = 0;
SBNI.retran_ = 0;
SBNI.snd_nxt_ = 0;
first_ = i%SBSIZE;
length_++;
if (length_ >= SBSIZE) {
printf ("Error, scoreboard too large (increase SBSIZE for more space)\n");
exit(1);
}
}
for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) {
sack_left = tcph->sa_left(sack_index);
sack_right = tcph->sa_right(sack_index);
// Create new entries off the right side.
if (sack_right > SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_) {
// Create new entries
for (i = SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_+1; i= SBSIZE) {
printf ("Error, scoreboard too large (increase SBSIZE for more space)\n");
exit(1);
}
}
}
// Advance the left edge of the block.
if (SBN[first_].seq_no_ <= last_ack) {
for (i=SBN[(first_)%SBSIZE].seq_no_; i<=last_ack; i++) {
// Advance the ACK
if (SBNI.seq_no_ <= last_ack) {
ASSERT(first_ == i%SBSIZE);
first_ = (first_+1)%SBSIZE;
length_--;
ASSERT1(length_ >= 0);
SBNI.ack_flag_ = 1;
SBNI.sack_flag_ = 1;
if (SBNI.retran_) {
SBNI.retran_ = 0;
SBNI.snd_nxt_ = 0;
retran_decr++;
}
if (length_==0)
break;
}
}
}
for (i=SBN[(first_)%SBSIZE].seq_no_; i= sack_left && SBNI.seq_no_ < sack_right) {
if (! SBNI.sack_flag_) {
SBNI.sack_flag_ = 1;
}
if (SBNI.retran_) {
SBNI.retran_ = 0;
retran_decr++;
}
}
}
}
return (retran_decr);
}
int ScoreBoard::CheckSndNxt (hdr_tcp* tcph)
{
int i, sack_index, sack_left, sack_right;
int force_timeout = 0;
for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) {
sack_left = tcph->sa_left(sack_index);
sack_right = tcph->sa_right(sack_index);
for (i=SBN[(first_)%SBSIZE].seq_no_; iScoreBoard::ClearScoreBoard()
{
length_ = 0;
}
/*
* GetNextRetran() returns "-1" if there is no packet that is
* not acked and not sacked and not retransmitted.
*/
int ScoreBoard::GetNextRetran() // Returns sequence number of next pkt...
{
int i;
if (length_) {
for (i=SBN[(first_)%SBSIZE].seq_no_;
iScoreBoard::MarkRetran (int retran_seqno, int snd_nxt)
{
SBN[retran_seqno%SBSIZE].retran_ = 1;
SBN[retran_seqno%SBSIZE].snd_nxt_ = snd_nxt;
}
void ScoreBoard::MarkRetran (int retran_seqno)
{
SBN[retran_seqno%SBSIZE].retran_ = 1;
}
semantic-packetqueue.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.
*
* semantic-packetqueue.cc: contributed by the Daedalus Research Group,
* UC Berkeley (http://daedalus.cs.berkeley.edu).
*/
#include "ip.h"
#include "tcp.h"
#include "template.h"
#include "semantic-packetqueue.h"
#include "ack-recons.h"
static class SemanticPacketQueueClass : public TclClass {
public:
SemanticPacketQueueClass() : TclClass("PacketQueue/Semantic") {}
TclObject* create(int , const char*const*) {
return (new SemanticPacketQueue());
}
} class_semanticpacketqueue;
SemanticPacketQueue::SemanticPacketQueue() : ack_count(0), data_count(0),
acks_to_send(0), marked_count_(0), unmarked_count_(0)
{
bind("off_cmn_", &off_cmn_);
bind("off_flags_", &off_flags_);
bind("off_ip_", &off_ip_);
bind("off_tcp_", &off_tcp_);
bind("off_flags_", &off_flags_);
bind_bool("acksfirst_", &acksfirst_);
bind_bool("filteracks_", &filteracks_);
bind_bool("reconsAcks_", &reconsAcks_);
bind_bool("replace_head_", &replace_head_);
bind_bool("priority_drop_", &priority_drop_);
bind_bool("random_drop_", &random_drop_);
bind_bool("random_ecn_", &random_ecn_);
}
int
SemanticPacketQueue::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "ackrecons") == 0) {
if ((reconsCtrl_ = (AckReconsController *)
TclObject::lookup(argv[2]))) {
reconsCtrl_->spq_ = this;
reconsAcks_ = 1;
}
}
return (TCL_OK);
}
return (TclObject::command(argc, argv));
}
/*
* Deque TCP acks before any other type of packet.
*/
Packet*
SemanticPacketQueue::deque_acksfirst() {
Packet* p = head_;
Packet* pp = NULL;
packet_t type;
if (ack_count > 0) {
while (p) {
type = ((hdr_cmn*)p->access(off_cmn_))->ptype_;
if (type == PT_ACK)
break;
pp = p;
p = p->next_;
}
if (!p)
fprintf(stderr, "In deque_acksfirst(): ack_count: %d but no acks in queue, length = %d\n", ack_count, length());
PacketQueue::remove(p, pp);
} else {
p = PacketQueue::deque();
}
return p;
}
/*
* Purge the queue of acks that are older (i.e., have a smaller sequence
* number) than the most recent ack. If replace_head is set, the most recent
* ack (pointed to by pkt) takes the place of the oldest ack that is purged.
* Otherwise, it remains at the tail of the queue. pkt must be an ACK -- this
* is checked by the caller.
*/
void
SemanticPacketQueue::filterAcks(Packet *pkt, int replace_head)
{
int done_replacement = 0;
Packet *p, *pp, *new_p;
hdr_tcp *tcph = (hdr_tcp*) pkt->access(off_tcp_);
int &ack = tcph->seqno();
hdr_ip *iph = (hdr_ip*) pkt->access(off_ip_);
for (p = head(), pp = p; p != 0; ) {
/*
* Check if packet in the queue belongs to the
* same connection as the most recent ack
*/
if (compareFlows((hdr_ip*) p->access(off_ip_), iph)) {
/* check if queued packet is an ack */
if (((hdr_cmn*)p->access(off_cmn_))->ptype_==PT_ACK) {
hdr_tcp *th = (hdr_tcp*) p->access(off_tcp_);
/* is this ack older than the current one? */
if ((th->seqno() < ack) ||
(replace_head && th->seqno() == ack)) {
/*
* If we haven't yet replaced the ack
* closest to the head with the most
* recent ack, do so now.
*/
if (replace_head && pkt != p &&
!done_replacement) {
PacketQueue::remove(pkt);
ack_count--; /* XXX */
pkt->next_ = p;
if (pp)
pp->next_ = pkt;
pp = pkt;
done_replacement = 1;
continue;
} else if (done_replacement||pkt != p){
new_p = p->next_;
/*
* If p is in scheduler queue,
* cancel the event. Also,
* print out a warning because
* this should never happen.
*/
Scheduler &s = Scheduler::instance();
if (s.lookup(p->uid_)) {
s.cancel(p);
fprintf(stderr, "Warning: In filterAcks(): packet being dropped from queue is in scheduler queue\n");
}
PacketQueue::remove(p, pp);
/* XXX should drop, but we
don't have access to q */
Packet::free(p);
ack_count--;
p = new_p;
continue;
}
if (ack_count <= 0)
fprintf(stderr,
"oops! ackcount %d\n",
ack_count);
}
}
}
pp = p;
p = p->next_;
}
}
/* check if packet is marked */
int
SemanticPacketQueue::isMarked(Packet *p)
{
return(((hdr_flags*)p->access(off_flags_))->fs_);
}
/* pick out the index'th of the appropriate kind (marked/unmarked) depending on markedFlag */
Packet*
SemanticPacketQueue::lookup(int index, int markedFlag)
{
if (index < 0) {
fprintf(stderr, "In SemanticPacketQueue::lookup(): index = %d\n", index);
return (NULL);
}
for (Packet* p = head_; p != 0; p = p->next_) {
if (isMarked(p) == markedFlag)
if (--index < 0)
return (p);
}
return (NULL);
}
/*
* If random_ecn_ is set, pick out the packet for ECN at random from among the
* packets in the queue and the packet that just arrived ('pkt'). Otherwise, just
* pick the packet that just arrived.
*/
Packet*
SemanticPacketQueue::pickPacketForECN(Packet* pkt)
{
Packet *victim;
int victimIndex;
if (random_ecn_) {
victimIndex = Random::integer(length()+1);
if (victimIndex == length())
victim = pkt;
else
victim = PacketQueue::lookup(victimIndex);
}
else
victim = pkt;
return (victim);
}
/*
* If priority_drop_ is set, drop marked packets before unmarked ones.
* If in addition or separately random_drop_ is set, use randomization in
* picking out the victim. XXX not used at present
*/
Packet*
SemanticPacketQueue::pickPacketToDrop()
{
Packet *victim;
int victimIndex, victimMarked;
if (!priority_drop_) {
if (random_drop_)
victim=PacketQueue::lookup(Random::integer(length()));
else
victim = PacketQueue::lookup(length() - 1);
} else {
/* if there are marked (low priority) packets */
if (marked_count_) {
victimMarked = 1;
if (!random_drop_)
victimIndex = marked_count_ - 1;
else
victimIndex = Random::integer(marked_count_);
}
else {
victimMarked = 0;
if (!random_drop_)
victimIndex = unmarked_count_ - 1;
else
victimIndex = Random::integer(unmarked_count_);
}
victim = lookup(victimIndex, victimMarked);
}
return (victim);
}
void
SemanticPacketQueue::enque(Packet *pkt)
{
if (reconsAcks_&&(((hdr_cmn*)pkt->access(off_cmn_))->ptype_==PT_ACK)) {
reconsCtrl_->recv(pkt);
return;
}
if (((hdr_cmn*)pkt->access(off_cmn_))->ptype_ == PT_ACK)
ack_count++;
else
data_count++;
if (isMarked(pkt))
marked_count_++;
else
unmarked_count_++;
PacketQueue::enque(pkt); /* actually enqueue the packet */
if (filteracks_ && (((hdr_cmn*)pkt->access(off_cmn_))->ptype_==PT_ACK))
filterAcks(pkt, replace_head_);
}
Packet *
SemanticPacketQueue::deque()
{
Packet *pkt;
if (acksfirst_)
pkt = deque_acksfirst();
else
pkt = PacketQueue::deque();
if (pkt) {
if (((hdr_cmn*)pkt->access(off_cmn_))->ptype_ == PT_ACK)
ack_count--;
else
data_count--;
if (isMarked(pkt))
marked_count_--;
else
unmarked_count_--;
}
return pkt;
}
void
SemanticPacketQueue::remove(Packet *pkt)
{
PacketQueue::remove(pkt);
if (pkt) {
if (((hdr_cmn*)pkt->access(off_cmn_))->ptype_ == PT_ACK)
ack_count--;
else
data_count--;
if (isMarked(pkt))
marked_count_--;
else
unmarked_count_--;
}
}
semantic-red.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* A RED queue that allows certain operations to be done in a way
* that depends on higher-layer semantics. The only such operation
* at present is pickPacketToDrop(), which invokes the corresponding
* member function in SemanticPacketQueue.
*/
#include "red.h"
#include "semantic-packetqueue.h"
class SemanticREDQueue : public REDQueue {
public:
SemanticREDQueue() : REDQueue() {}
Packet* pickPacketToDrop() {
return(((SemanticPacketQueue*) pq_)->pickPacketToDrop());
}
Packet* pickPacketForECN(Packet *pkt) {
return(((SemanticPacketQueue*) pq_)->pickPacketForECN(pkt));
}
};
static class SemanticREDClass : public TclClass {
public:
SemanticREDClass() : TclClass("Queue/RED/Semantic") {}
TclObject* create(int, const char*const*) {
return (new SemanticREDQueue);
}
} class_semantic_red;
session-rtp.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
#include "packet.h"
#include "ip.h"
#include "rtp.h"
static class RTPSourceClass : public TclClass {
public:
RTPSourceClass() : TclClass("RTPSource") {}
TclObject* create(int argc, const char*const* argv) {
if (argc >= 5)
return (new RTPSource(atoi(argv[4])));
return 0;
}
} class_rtp_source;
static class RTPSessionClass : public TclClass {
public:
RTPSessionClass() : TclClass("Session/RTP") {}
TclObject* create(int, const char*const*) {
return (new RTPSession());
}
} class_rtp_session;
RTPSession::RTPSession()
: allsrcs_(0), localsrc_(0), last_np_(0)
{
bind("off_rtp_", &off_rtp_);
}
RTPSession::~RTPSession()
{
while (allsrcs_ != 0) {
RTPSource* p = allsrcs_;
allsrcs_ = allsrcs_->next;
delete p;
}
delete localsrc_;
}
void RTPSession::localsrc_update(int)
{
localsrc_->np(1);
}
#define RTCP_HDRSIZE 8
#define RTCP_SR_SIZE 20
#define RTCP_RR_SIZE 48
int RTPSession::build_report(int bye)
{
int nsrc = 0;
int nrr = 0;
int len = RTCP_HDRSIZE;
int we_sent = 0;
if (localsrc_->np() != last_np_) {
last_np_ = localsrc_->np();
we_sent = 1;
len += RTCP_SR_SIZE;
}
for (RTPSource* sp = allsrcs_; sp != 0; sp = sp->next) {
++nsrc;
int received = sp->np() - sp->snp();
if (received == 0) {
continue;
}
sp->snp(sp->np());
len += RTCP_RR_SIZE;
if (++nrr >= 31)
break;
}
if (bye)
len += build_bye();
else
len += build_sdes();
Tcl::instance().evalf("%s adapt-timer %d %d %d", name(),
nsrc, nrr, we_sent);
Tcl::instance().evalf("%s sample-size %d", name(), len);
return (len);
}
int RTPSession::build_bye()
{
return (8);
}
int RTPSession::build_sdes()
{
/* XXX We'll get to this later... */
return (20);
}
void RTPSession::recv(Packet* p, Handler*)
{
hdr_rtp *rh = (hdr_rtp*)p->access(off_rtp_);
u_int32_t srcid = rh->srcid();
RTPSource* s = lookup(srcid);
if (s == 0) {
Tcl& tcl = Tcl::instance();
tcl.evalf("%s new-source %d", name(), srcid);
s = (RTPSource*)TclObject::lookup(tcl.result());
}
s->np(1);
s->ehsr(rh->seqno());
Packet::free(p);
}
void RTPSession::recv_ctrl(Packet* p)
{
hdr_cmn* ch = (hdr_cmn*)p->access(off_cmn_);
Tcl::instance().evalf("%s sample-size %d", name(), ch->size());
Packet::free(p);
}
/* XXX Should hash this... */
RTPSource* RTPSession::lookup(u_int32_t srcid)
{
RTPSource *p;
for (p = allsrcs_; p != 0; p = p->next)
if (p->srcid() == srcid)
return (p);
return (0);
}
void RTPSession::enter(RTPSource* s)
{
s->next = allsrcs_;
allsrcs_ = s;
}
int RTPSession::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "enter") == 0) {
RTPSource* s = (RTPSource*)TclObject::lookup(argv[2]);
enter(s);
return (TCL_OK);
}
if (strcmp(argv[1], "localsrc") == 0) {
localsrc_ = (RTPSource*)TclObject::lookup(argv[2]);
enter(localsrc_);
return (TCL_OK);
}
}
return (TclObject::command(argc, argv));
}
RTPSource::RTPSource(u_int32_t srcid)
: next(0), np_(0), snp_(0), ehsr_(-1)
{
bind("srcid_", (int*)&srcid_);
srcid_ = srcid;
}
sessionhelper.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* sessionhelper.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 "config.h"
#include "tclcl.h"
#include "ip.h"
#include "packet.h"
#include "connector.h"
#include "errmodel.h"
//Definitions for special reference count events
class RcEvent : public Event {
public:
Packet* packet_;
Handler* real_handler_;
};
class RcHandler : public Handler {
public:
void handle(Event* event);
} rc_handler;
void RcHandler::handle(Event* e)
{
RcEvent* rc = (RcEvent*)e;
rc->real_handler_->handle(rc->packet_);
delete rc;
}
struct dstobj {
double bw;
double delay;
double prev_arrival;
int ttl;
int dropped;
nsaddr_t addr;
NsObject *obj;
dstobj *next;
};
struct rcv_depobj {
dstobj *obj;
rcv_depobj *next;
};
struct loss_depobj {
ErrorModel *obj;
loss_depobj *loss_dep;
rcv_depobj *rcv_dep;
loss_depobj *next;
};
class SessionHelper : public Connector {
public:
SessionHelper();
int command(int, const char*const*);
void recv(Packet*, Handler*);
protected:
void get_dropped(loss_depobj*, Packet*);
void mark_dropped(loss_depobj*);
void clear_dropped();
dstobj* find_dstobj(NsObject*);
void delete_dstobj(NsObject*);
loss_depobj* find_loss_depobj(ErrorModel*);
void show_dstobj();
void show_loss_depobj(loss_depobj*);
nsaddr_t src_;
dstobj *dstobj_;
loss_depobj *loss_dependency_;
int off_ip_;
int ndst_;
int rc_; //enable reference count
};
static class SessionHelperClass : public TclClass {
public:
SessionHelperClass() : TclClass("SessionHelper") {}
TclObject* create(int, const char*const*) {
return (new SessionHelper());
}
} class_sessionhelper;
SessionHelper::SessionHelper() : dstobj_(0), ndst_(0), rc_(0)
{
bind("off_ip_", &off_ip_);
bind("rc_", &rc_);
loss_dependency_ = new loss_depobj;
loss_dependency_->obj = 0;
loss_dependency_->loss_dep = 0;
loss_dependency_->rcv_dep = 0;
loss_dependency_->next = 0;
}
void SessionHelper::recv(Packet* pkt, Handler*)
{
dstobj *tmpdst = dstobj_;
Scheduler& s = Scheduler::instance();
hdr_cmn* th = (hdr_cmn*)pkt->access(off_cmn_);
hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_);
double tmp_arrival;
//printf ("src %d, size %d, iface %d\n", src_, th->size(), th->iface());
clear_dropped();
get_dropped(loss_dependency_->loss_dep, pkt);
if (rc_) {
th->ref_count() = ndst_;
}
while (tmpdst != 0) {
if (!(tmpdst->dropped)) {
int ttl = iph->ttl() - tmpdst->ttl;
if (ttl > 0) {
if (tmpdst->bw == 0) {
tmp_arrival = tmpdst->delay;
} else {
tmp_arrival = th->size()*8/tmpdst->bw + tmpdst->delay;
}
if (tmpdst->prev_arrival >= tmp_arrival) {
tmp_arrival = tmpdst->prev_arrival + 0.000001;
/* Assume 1 ns process delay; just to maintain the causality */
}
tmpdst->prev_arrival = tmp_arrival;
if (rc_) {
// reference count
//s.rc_schedule(tmpdst->obj, pkt, tmp_arrival);
RcEvent* rc = new RcEvent;
rc->packet_ = pkt;
rc->real_handler_ = tmpdst->obj;
s.schedule(&rc_handler, rc, tmp_arrival);
} else {
Packet* tmppkt = pkt->copy();
hdr_ip* tmpiph = (hdr_ip*)tmppkt->access(off_ip_);
tmpiph->ttl() = ttl;
s.schedule(tmpdst->obj, tmppkt, tmp_arrival);
}
} else {
if (rc_) th->ref_count() -= 1;
}
} else {
if (rc_) th->ref_count() -= 1;
}
tmpdst = tmpdst->next;
}
Packet::free(pkt);
}
void SessionHelper::get_dropped(loss_depobj* loss_dep, Packet* pkt)
{
if (loss_dep != 0)
if (loss_dep->obj != 0) {
if (loss_dep->obj->corrupt(pkt)) {
mark_dropped(loss_dep);
} else {
get_dropped(loss_dep->loss_dep, pkt);
}
get_dropped(loss_dep->next, pkt);
}
}
void SessionHelper::mark_dropped(loss_depobj* loss_dep)
{
if (loss_dep != 0) {
rcv_depobj *tmprcv_dep = loss_dep->rcv_dep;
loss_depobj *tmploss_dep = loss_dep->loss_dep;
while (tmprcv_dep != 0) {
tmprcv_dep->obj->dropped = 1;
tmprcv_dep = tmprcv_dep->next;
}
while (tmploss_dep != 0) {
mark_dropped(tmploss_dep);
tmploss_dep = tmploss_dep->next;
}
}
}
void SessionHelper::clear_dropped()
{
dstobj *tmpdst = dstobj_;
while (tmpdst != 0) {
tmpdst->dropped = 0;
tmpdst = tmpdst->next;
}
}
dstobj* SessionHelper::find_dstobj(NsObject* obj) {
dstobj *tmpdst = dstobj_;
while (tmpdst != 0) {
if (tmpdst->obj == obj) return (tmpdst);
tmpdst = tmpdst->next;
}
return 0;
}
loss_depobj* SessionHelper::find_loss_depobj(ErrorModel* err) {
struct stackobj {
loss_depobj *loss_obj;
stackobj *next;
};
if (!loss_dependency_) return 0;
stackobj *top = new stackobj;
top->loss_obj = loss_dependency_;
top->next = 0;
while (top != 0) {
if (top->loss_obj->obj == err) {
loss_depobj *tmp_loss_obj = top->loss_obj;
while (top != 0) {
stackobj *befreed = top;
top = top->next;
free(befreed);
}
return (tmp_loss_obj);
}
loss_depobj *tmploss = top->loss_obj->loss_dep;
stackobj *befreed = top;
top = top->next;
free(befreed);
while (tmploss != 0) {
stackobj *new_element = new stackobj;
new_element->loss_obj = tmploss;
new_element->next = top;
top = new_element;
tmploss = tmploss->next;
}
}
return 0;
}
void SessionHelper::show_dstobj() {
dstobj *tmpdst = dstobj_;
while (tmpdst != 0) {
printf("bw:%.2f, delay:%.2f, ttl:%d, dropped:%d, addr:%d, obj:%s\n", tmpdst->bw, tmpdst->delay, tmpdst->ttl, tmpdst->dropped, tmpdst->addr, tmpdst->obj->name());
tmpdst = tmpdst->next;
}
}
void SessionHelper::delete_dstobj(NsObject *obj) {
dstobj *tmpdst = dstobj_;
dstobj *tmpprev = 0;
while (tmpdst != 0) {
if (tmpdst->obj == obj) {
if (tmpprev == 0) dstobj_ = tmpdst->next;
else tmpprev->next = tmpdst->next;
free(tmpdst);
return;
}
tmpprev = tmpdst;
tmpdst = tmpdst->next;
}
}
void SessionHelper::show_loss_depobj(loss_depobj *loss_obj) {
loss_depobj *tmploss = loss_obj->loss_dep;
rcv_depobj *tmprcv = loss_obj->rcv_dep;
while (tmprcv != 0) {
printf("%d ", tmprcv->obj->addr);
tmprcv = tmprcv->next;
}
while (tmploss != 0) {
printf("(%s: ", tmploss->obj->name());
show_loss_depobj(tmploss);
tmploss = tmploss->next;
}
if (loss_obj == loss_dependency_) {
printf("\n");
} else {
printf(")");
}
}
int SessionHelper::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (argc == 2) {
if (strcmp(argv[1], "list-mbr") == 0) {
dstobj *tmp = dstobj_;
while (tmp != 0) {
tcl.resultf("%s %s", tcl.result(),
tmp->obj->name());
tmp = tmp->next;
}
return (TCL_OK);
}
if (strcmp(argv[1], "show-loss-depobj") == 0) {
show_loss_depobj(loss_dependency_);
return (TCL_OK);
}
if (strcmp(argv[1], "show-dstobj") == 0) {
show_dstobj();
return (TCL_OK);
}
} else if (argc == 3) {
if (strcmp(argv[1], "set-node") == 0) {
int src = atoi(argv[2]);
src_ = src;
//printf("set node %d\n", src_);
return (TCL_OK);
}
if (strcmp(argv[1], "update-loss-top") == 0) {
loss_depobj *tmploss = (loss_depobj*)(atoi(argv[2]));
tmploss->next = loss_dependency_->loss_dep;
loss_dependency_->loss_dep = tmploss;
return (TCL_OK);
}
} else if (argc == 4) {
if (strcmp(argv[1], "update-loss-rcv") == 0) {
ErrorModel *tmperr = (ErrorModel*)TclObject::lookup(argv[2]);
NsObject *tmpobj = (NsObject*)TclObject::lookup(argv[3]);
//printf("errmodel %s, agent %s\n", tmperr->name(), tmpobj->name());
loss_depobj *tmploss = find_loss_depobj(tmperr);
//printf ("%d, loss_dependency_ %d\n", tmploss, loss_dependency_);
if (!tmploss) {
tmploss = new loss_depobj;
tmploss->obj = tmperr;
tmploss->next = 0;
tmploss->rcv_dep = 0;
tmploss->loss_dep = 0;
tcl.resultf("%d", tmploss);
} else {
tcl.result("0");
}
rcv_depobj *tmprcv = new rcv_depobj;
tmprcv->obj = find_dstobj(tmpobj);
tmprcv->next = tmploss->rcv_dep;
tmploss->rcv_dep = tmprcv;
return (TCL_OK);
}
if (strcmp(argv[1], "update-loss-loss") == 0) {
ErrorModel *tmperrparent = (ErrorModel*)TclObject::lookup(argv[2]);
loss_depobj *tmplossparent = find_loss_depobj(tmperrparent);
loss_depobj *tmplosschild = (loss_depobj*)(atoi(argv[3]));
if (!tmplossparent) {
tmplossparent = new loss_depobj;
tmplossparent->obj = tmperrparent;
tmplossparent->next = 0;
tmplossparent->loss_dep = 0;
tmplossparent->rcv_dep = 0;
tcl.resultf("%d", tmplossparent);
} else {
tcl.result("0");
}
tmplosschild->next = tmplossparent->loss_dep;
tmplossparent->loss_dep = tmplosschild;
return (TCL_OK);
}
if (strcmp(argv[1], "delete-dst") == 0) {
int tmpaddr = atoi(argv[2]);
//NsObject *tmpobj = (NsObject*)TclObject::lookup(argv[3]);
printf ("addr = %d\n", tmpaddr);
return (TCL_OK);
}
} else if (argc == 7) {
if (strcmp(argv[1], "add-dst") == 0) {
dstobj *tmp = new dstobj;
tmp->bw = atof(argv[2]);
tmp->delay = atof(argv[3]);
tmp->prev_arrival = 0;
tmp->ttl = atoi(argv[4]);
tmp->addr = atoi(argv[5]);
tmp->obj = (NsObject*)TclObject::lookup(argv[6]);
//printf ("addr = %d, argv3 = %s, obj = %d, ttl=%d\n", tmp->addr, argv[3], tmp->obj, tmp->ttl);
tmp->next = dstobj_;
dstobj_ = tmp;
ndst_ += 1;
return (TCL_OK);
}
}
return (Connector::command(argc, argv));
}
sfq.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.
*
* This file contributed by Curtis Villamizar < curtis@ans.net >, Feb 1997.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (ANS)";
#endif
#include
#include "config.h"
#include "queue.h"
class PacketSFQ; // one queue
class SFQ; // a set of SFQ queues
class PacketSFQ : public PacketQueue {
PacketSFQ() : pkts(0), prev(0), next(0) {}
friend SFQ;
protected:
void sfqdebug();
int pkts;
PacketSFQ *prev;
PacketSFQ *next;
inline PacketSFQ * activate(PacketSFQ *head) {
if (head) {
this->prev = head->prev;
this->next = head;
head->prev->next = this;
head->prev = this;
return head;
}
this->prev = this;
this->next = this;
return this;
}
inline PacketSFQ * idle(PacketSFQ *head) {
if (head == this) {
if (this->next == this)
return 0;
this->next->prev = this->prev;
this->prev->next = this->next;
return this->next;
}
return head;
}
};
class SFQ : public Queue {
public:
SFQ();
virtual int command(int argc, const char*const* argv);
Packet *deque(void);
void enque(Packet *pkt);
protected:
int maxqueue_; // max queue size in packets
int buckets_; // number of queues
PacketSFQ *bucket;
void initsfq();
void clear();
int hash(Packet *);
PacketSFQ *active;
int occupied;
int fairshare;
int off_ip_;
};
static class SFQClass : public TclClass {
public:
SFQClass() : TclClass("Queue/SFQ") {}
TclObject* create(int, const char*const*) {
return (new SFQ);
}
} class_sfq;
SFQ::SFQ()
{
maxqueue_ = 40;
buckets_ = 16;
bucket = 0;
active = 0;
bind("maxqueue_", &maxqueue_);
bind("buckets_", &buckets_);
bind("off_ip_", &off_ip_);
}
void SFQ::clear()
{
PacketSFQ *q = bucket;
int i = buckets_;
if (!q)
return;
while (i) {
if (q->pkts) {
fprintf(stderr, "SFQ changed while queue occupied\n");
exit(1);
}
++q;
}
delete[](bucket);
bucket = 0;
}
void SFQ::initsfq()
{
bucket = new PacketSFQ[buckets_];
active = 0;
occupied = 0;
fairshare = maxqueue_ / buckets_;
// fprintf(stderr, "SFQ initsfq: %d %d\n", maxqueue_, buckets_);
}
/*
* This implements the following tcl commands:
* $sfq limit $size
* $sfq buckets $num
*/
int SFQ::command(int argc, const char*const* argv)
{
if (argc == 3) {
if (strcmp(argv[1], "limit") == 0) {
maxqueue_ = atoi(argv[2]);
fairshare = maxqueue_ / buckets_;
return (TCL_OK);
}
if (strcmp(argv[1], "buckets") == 0) {
clear();
buckets_ = atoi(argv[2]);
return (TCL_OK);
}
}
return (Queue::command(argc, argv));
}
void PacketSFQ::sfqdebug()
{
PacketSFQ *q = this;
fprintf(stderr, "sfq: ");
while (q) {
fprintf(stderr, " 0x%p(%d)", q, q->pkts);
q = q->next;
if (q == this)
break;
}
fprintf(stderr, "\n");
}
Packet* SFQ::deque(void)
{
Packet* pkt;
if (!bucket)
initsfq();
if (!active) {
// fprintf(stderr, " dequeue: empty\n");
return (0);
}
--active->pkts;
--occupied;
pkt = active->deque();
// fprintf(stderr, "dequeue 0x%x(%d): 0x%x\n",
// (int)active, active->pkts, (int)pkt);
// active->sfqdebug();
if (active->pkts == 0)
active = active->idle(active);
else
active = active->next;
return pkt;
}
void SFQ::enque(Packet* pkt)
{
int which;
PacketSFQ *q;
int used, left;
if (!bucket)
initsfq();
which = hash(pkt) % buckets_;
q = &bucket[which];
// log_packet_arrival(pkt);
used = q->pkts;
left = maxqueue_ - occupied;
// note: if maxqueue_ is changed while running left can be < 0
if ((used >= (left >> 1))
|| (left < buckets_ && used > fairshare)
|| (left <= 0)) {
// log_packet_drop(pkt);
drop(pkt);
// fprintf(stderr, " drop: 0x%x\n", (int)pkt);
return;
}
q->enque(pkt);
++occupied;
++q->pkts;
if (q->pkts == 1)
active = q->activate(active);
// fprintf(stderr, " enqueue(%d=%d): 0x%x\n", which, q->pkts, (int)pkt);
// active->sfqdebug();
}
int SFQ::hash(Packet* pkt)
{
hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_);
int i = (int)iph->saddr();
int j = (int)iph->daddr();
int k = i + j;
return (k + (k >> 8) + ~(k >> 4)) % ((2<<19)-1); // modulo a large prime
}
simple-intserv-sched.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.
*/
/*
* 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
//Simple scheduler with 2 service priority levels and protects signalling
//ctrl packets
#include "config.h"
#include "queue.h"
#define CLASSES 2
class SimpleIntServ : public Queue {
public:
SimpleIntServ() {
int i;
char buf[10];
for (i=0;iSimpleIntServ::enque(Packet* p)
{
hdr_ip* iph=(hdr_ip*)p->access(off_ip_);
int cl=(iph->flowid()) ? 1:0;
if (q_[cl]->length() >= (qlimit_[cl]-1)) {
hdr_cmn* ch=(hdr_cmn*)p->access(off_cmn_);
packet_t ptype = ch->ptype();
if ( (ptype != PT_REQUEST) && (ptype != PT_REJECT) && (ptype != PT_ACCEPT) && (ptype != PT_CONFIRM) && (ptype != PT_TEARDOWN) ) {
drop(p);
}
else {
q_[cl]->enque(p);
}
}
else {
q_[cl]->enque(p);
}
}
Packet *SimpleIntServ::deque()
{
int i;
for (i=CLASSES-1;i>=0;i--)
if (q_[i]->length())
return q_[i]->deque();
return 0;
}
snoop.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 "snoop.h"
int hdr_snoop::offset_;
class SnoopHeaderClass : public PacketHeaderClass {
public:
SnoopHeaderClass() : PacketHeaderClass("PacketHeader/Snoop",
sizeof(hdr_snoop)) {
bind_offset(&hdr_snoop::offset_);
}
} class_snoophdr;
static class LLSnoopClass : public TclClass {
public:
LLSnoopClass() : TclClass("LL/LLSnoop") {}
TclObject* create(int, const char*const*) {
return (new LLSnoop());
}
} llsnoop_class;
static class SnoopClass : public TclClass {
public:
SnoopClass() : TclClass("Snoop") {}
TclObject* create(int, const char*const*) {
return (new Snoop());
}
} snoop_class;
Snoop::Snoop() : NsObject(),
fstate_(0), lastSeen_(-1), lastAck_(-1),
expNextAck_(0), expDupacks_(0), bufhead_(0),
toutPending_(0), buftail_(0),
wl_state_(SNOOP_WLEMPTY), wl_lastSeen_(-1), wl_lastAck_(-1),
wl_bufhead_(0), wl_buftail_(0)
{
bind("snoopDisable_", &snoopDisable_);
bind_time("srtt_", &srtt_);
bind_time("rttvar_", &rttvar_);
bind("maxbufs_", &maxbufs_);
bind("snoopTick_", &snoopTick_);
bind("g_", &g_);
bind("tailTime_", &tailTime_);
bind("rxmitStatus_", &rxmitStatus_);
bind("lru_", &lru_);
rxmitHandler_ = new SnoopRxmitHandler(this);
int i;
for (i = 0; i < SNOOP_MAXWIND; i++) /* data from wired->wireless */
pkts_[i] = 0;
for (i = 0; i < SNOOP_WLSEQS; i++) {/* data from wireless->wired */
wlseqs_[i] = (hdr_seq *) malloc(sizeof(hdr_seq));
wlseqs_[i]->seq = wlseqs_[i]->num = 0;
}
if (maxbufs_ == 0)
maxbufs_ = SNOOP_MAXWIND;
}
void
Snoop::reset()
{
// printf("%x resetting\n", this);
fstate_ = 0;
lastSeen_ = -1;
lastAck_ = -1;
expNextAck_ = 0;
expDupacks_ = 0;
bufhead_ = buftail_ = 0;
if (toutPending_)
Scheduler::instance().cancel(toutPending_);
toutPending_ = 0;
for (int i = 0; i < SNOOP_MAXWIND; i++) {
if (pkts_[i]) {
Packet::free(pkts_[i]);
pkts_[i] = 0;
}
}
}
void
Snoop::wlreset()
{
wl_state_ = SNOOP_WLEMPTY;
wl_bufhead_ = wl_buftail_ = 0;
for (int i = 0; i < SNOOP_WLSEQS; i++) {
wlseqs_[i]->seq = wlseqs_[i]->num = 0;
}
}
int
Snoop::command(int argc, const char*const* argv)
{
//Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "llsnoop") == 0) {
parent_ = (LLSnoop *) TclObject::lookup(argv[2]);
if (parent_)
recvtarget_ = parent_->uptarget();
return (TCL_OK);
}
if (strcmp(argv[1], "check-rxmit") == 0) {
if (empty_()) {
rxmitStatus_ = SNOOP_PROPAGATE;
return (TCL_OK);
}
Packet *p = pkts_[buftail_];
hdr_snoop *sh = hdr_snoop::access(p);
if (sh->sndTime()!=-1 && sh->sndTime()numRxmit() == 0)
/* candidate for retransmission */
rxmitStatus_ = snoop_rxmit(p);
else
rxmitStatus_ = SNOOP_PROPAGATE;
return (TCL_OK);
}
}
return NsObject::command(argc, argv);
}
void LLSnoop::recv(Packet *p, Handler *h)
{
Tcl &tcl = Tcl::instance();
hdr_ip *iph = hdr_ip::access(p);
/* get-snoop creates a snoop object if none currently exists */
if (h == 0)
/* In ns, addresses have ports embedded in them. */
tcl.evalf("%s get-snoop %d %d", name(), iph->daddr(),
iph->saddr());
else
tcl.evalf("%s get-snoop %d %d", name(), iph->saddr(),
iph->daddr());
Snoop *snoop = (Snoop *) TclObject::lookup(tcl.result());
snoop->recv(p, h);
if (integrate_)
tcl.evalf("%s integrate %d %d", name(), iph->saddr(),
iph->daddr());
if (h) /* resume higher layer (queue) */
Scheduler::instance().schedule(h, &intr_, 0.000001);
return;
}
/*
* Receive a packet from higher layer or from the network.
* Call snoop_data() if TCP packet and forward it on if it's an ack.
*/
void
Snoop::recv(Packet* p, Handler* h)
{
if (h == 0) { // from MAC classifier
handle((Event *) p);
return;
}
packet_t type = hdr_cmn::access(p)->ptype();
/* Put packet (if not ack) in cache after checking, and send it on */
if (type == PT_TCP)
snoop_data(p);
else if (type == PT_ACK)
snoop_wired_ack(p);
parent_->sendDown(p); /* vector to LLSnoop's sendto() */
}
/*
* Handle a packet received from peer across wireless link. Check first
* for packet errors, then call snoop_ack() or pass it up as necessary.
*/
void
Snoop::handle(Event *e)
{
Packet *p = (Packet *) e;
packet_t type = hdr_cmn::access(p)->ptype();
//int seq = hdr_tcp::access(p)->seqno();
int prop = SNOOP_PROPAGATE; // by default; propagate ack or packet
Scheduler& s = Scheduler::instance();
//hdr_ll *llh = hdr_ll::access(p);
if (hdr_cmn::access(p)->error()) {
parent_->drop(p); // drop packet if it's been corrupted
return;
}
if (type == PT_ACK)
prop = snoop_ack(p);
else if (type == PT_TCP) /* XXX what about TELNET? */
snoop_wless_data(p);
if (prop == SNOOP_PROPAGATE)
s.schedule(recvtarget_, e, parent_->delay());
else { // suppress ack
/* printf("---- %f suppressing ack %d\n", s.clock(), seq);*/
Packet::free(p);
}
}
/*
* Data packet processing. p is guaranteed to be of type PT_TCP when
* this function is called.
*/
void
Snoop::snoop_data(Packet *p)
{
Scheduler &s = Scheduler::instance();
int seq = hdr_tcp::access(p)->seqno();
int resetPending = 0;
// printf("%x snoop_data: %f sending packet %d\n", this, s.clock(), seq);
if (fstate_ & SNOOP_ALIVE && seq == 0)
reset();
fstate_ |= SNOOP_ALIVE;
if ((fstate_ & SNOOP_FULL) && !lru_) {
// printf("snoop full, fwd'ing\n t %d h %d", buftail_, bufhead_);
if (seq > lastSeen_)
lastSeen_ = seq;
return;
}
/*
* Only if the ifq is NOT full do we insert, since otherwise we want
* congestion control to kick in.
*/
if (parent_->ifq()->length() < parent_->ifq()->limit()-1)
resetPending = snoop_insert(p);
if (toutPending_ && resetPending == SNOOP_TAIL) {
s.cancel(toutPending_);
toutPending_ = 0;
}
if (!toutPending_ && !empty_()) {
toutPending_ = (Event *) (pkts_[buftail_]);
s.schedule(rxmitHandler_, toutPending_, timeout());
}
return;
}
/*
* snoop_insert() does all the hard work for snoop_data(). It traverses the
* snoop cache and looks for the right place to insert this packet (or
* determines if its already been cached). It then decides whether
* this is a packet in the normal increasing sequence, whether it
* is a sender-rexmitted-but-lost-due-to-congestion (or network
* out-of-order) packet, or if it is a sender-rexmitted packet that
* was buffered by us before.
*/
int
Snoop::snoop_insert(Packet *p)
{
int i, seq = hdr_tcp::access(p)->seqno(), retval=0;
if (seq <= lastAck_)
return retval;
if (fstate_ & SNOOP_FULL) {
/* free tail and go on */
printf("snoop full, making room\n");
Packet::free(pkts_[buftail_]);
pkts_[buftail_] = 0;
buftail_ = next(buftail_);
fstate_ |= ~SNOOP_FULL;
}
if (seq > lastSeen_ || pkts_[buftail_] == 0) { // in-seq or empty cache
i = bufhead_;
bufhead_ = next(bufhead_);
} else if (seq < hdr_snoop::access(pkts_[buftail_])->seqno()) {
buftail_ = prev(buftail_);
i = buftail_;
} else {
for (i = buftail_; i != bufhead_; i = next(i)) {
hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
if (sh->seqno() == seq) {
sh->numRxmit() = 0;
sh->senderRxmit() = 1;
sh->sndTime() = Scheduler::instance().clock();
return SNOOP_TAIL;
} else if (sh->seqno() > seq) {
Packet *temp = pkts_[prev(buftail_)];
for (int j = buftail_; j != i; j = next(j))
pkts_[prev(j)] = pkts_[j];
i = prev(i);
pkts_[i] = temp;
buftail_ = prev(buftail_);
break;
}
}
if (i == bufhead_)
bufhead_ = next(bufhead_);
}
savepkt_(p, seq, i);
if (bufhead_ == buftail_)
fstate_ |= SNOOP_FULL;
/*
* If we have one of the following packets:
* 1. a network-out-of-order packet, or
* 2. a fast rxmit packet, or 3. a sender retransmission
* AND it hasn't already been buffered,
* then seq will be < lastSeen_.
* We mark this packet as having been due to a sender rexmit
* and use this information in snoop_ack(). We let the dupacks
* for this packet go through according to expDupacks_.
*/
if (seq < lastSeen_) { /* not in-order -- XXX should it be <= ? */
if (buftail_ == i) {
hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
sh->senderRxmit() = 1;
sh->numRxmit() = 0;
}
expNextAck_ = buftail_;
retval = SNOOP_TAIL;
} else
lastSeen_ = seq;
return retval;
}
void
Snoop::savepkt_(Packet *p, int seq, int i)
{
pkts_[i] = p->copy();
Packet *pkt = pkts_[i];
hdr_snoop *sh = hdr_snoop::access(pkt);
sh->seqno() = seq;
sh->numRxmit() = 0;
sh->senderRxmit() = 0;
sh->sndTime() = Scheduler::instance().clock();
}
/*
* Ack processing in snoop protocol. We know for sure that this is an ack.
* Return SNOOP_SUPPRESS if ack is to be suppressed and SNOOP_PROPAGATE o.w.
*/
int
Snoop::snoop_ack(Packet *p)
{
Packet *pkt;
int ack = hdr_tcp::access(p)->seqno();
/*
* There are 3 cases:
* 1. lastAck_ > ack. In this case what has happened is
* that the acks have come out of order, so we don't
* do any local processing but forward it on.
* 2. lastAck_ == ack. This is a duplicate ack. If we have
* the packet we resend it, and drop the dupack.
* Otherwise we never got it from the fixed host, so we
* need to let the dupack get through.
* Set expDupacks_ to number of packets already sent
* This is the number of dup acks to ignore.
* 3. lastAck_ < ack. Set lastAck_ = ack, and update
* the head of the buffer queue. Also clean up ack'd packets.
*/
if (fstate_ & SNOOP_CLOSED || lastAck_ > ack)
return SNOOP_PROPAGATE; // send ack onward
if (lastAck_ == ack) {
/* A duplicate ack; pure window updates don't occur in ns. */
pkt = pkts_[buftail_];
if (pkt == 0)
return SNOOP_PROPAGATE;
hdr_snoop *sh = hdr_snoop::access(pkt);
if (pkt == 0 || sh->seqno() > ack + 1)
/* don't have packet, letting thru' */
return SNOOP_PROPAGATE;
/*
* We have the packet: one of 3 possibilities:
* 1. We are not expecting any dupacks (expDupacks_ == 0)
* 2. We are expecting dupacks (expDupacks_ > 0)
* 3. We are in an inconsistent state (expDupacks_ == -1)
*/
if (expDupacks_ == 0) { // not expecting it
#define RTX_THRESH 1
static int thresh = 0;
if (thresh++ < RTX_THRESH) {
/* no action if under RTX_THRESH */
return SNOOP_PROPAGATE;
}
thresh = 0;
if (sh->senderRxmit())
return SNOOP_PROPAGATE;
/*
* Otherwise, not triggered by sender. If this is
* the first dupack recd., we must determine how many
* dupacks will arrive that must be ignored, and also
* rexmit the desired packet. Note that expDupacks_
* will be -1 if we miscount for some reason.
*/
expDupacks_ = bufhead_ - expNextAck_;
if (expDupacks_ < 0)
expDupacks_ += SNOOP_MAXWIND;
expDupacks_ -= RTX_THRESH + 1;
expNextAck_ = next(buftail_);
if (sh->numRxmit() == 0)
return snoop_rxmit(pkt);
} else if (expDupacks_ > 0) {
expDupacks_--;
return SNOOP_SUPPRESS;
} else if (expDupacks_ == -1) {
if (sh->numRxmit() < 2) {
return snoop_rxmit(pkt);
}
} else // let sender deal with it
return SNOOP_PROPAGATE;
} else { // a new ack
fstate_ &= ~SNOOP_NOACK; // have seen at least 1 new ack
/* free buffers */
double sndTime = snoop_cleanbufs_(ack);
if (sndTime != -1)
snoop_rtt(sndTime);
expDupacks_ = 0;
expNextAck_ = buftail_;
lastAck_ = ack;
}
return SNOOP_PROPAGATE;
}
/*
* Handle data packets that arrive from a wireless link, and we're not
* the end recipient. See if there are any holes in the transmission, and
* if there are, mark them as candidates for wireless loss. Then, when
* (dup)acks troop back for this loss, set the ELN bit in their header, to
* help the sender (or a snoop agent downstream) retransmit.
*/
void
Snoop::snoop_wless_data(Packet *p)
{
hdr_tcp *th = hdr_tcp::access(p);
int i, seq = th->seqno();
if (wl_state_ & SNOOP_WLALIVE && seq == 0)
wlreset();
wl_state_ |= SNOOP_WLALIVE;
if (wl_state_ & SNOOP_WLEMPTY && seq >= wl_lastAck_) {
wlseqs_[wl_bufhead_]->seq = seq;
wlseqs_[wl_bufhead_]->num = 1;
wl_buftail_ = wl_bufhead_;
wl_bufhead_ = wl_next(wl_bufhead_);
wl_lastSeen_ = seq;
wl_state_ &= ~SNOOP_WLEMPTY;
return;
}
/* WL data list definitely not empty at this point. */
if (seq >= wl_lastSeen_) {
wl_lastSeen_ = seq;
i = wl_prev(wl_bufhead_);
if (wlseqs_[i]->seq + wlseqs_[i]->num == seq) {
wlseqs_[i]->num++;
return;
}
i = wl_bufhead_;
wl_bufhead_ = wl_next(wl_bufhead_);
} else if (seq == wlseqs_[i = wl_buftail_]->seq - 1) {
} else
return;
wlseqs_[i]->seq = seq;
wlseqs_[i]->num++;
/* Ignore network out-of-ordering and retransmissions for now */
return;
}
/*
* Ack from wired side (for sender on "other" side of wireless link.
*/
void
Snoop::snoop_wired_ack(Packet *p)
{
hdr_tcp *th = hdr_tcp::access(p);
int ack = th->seqno();
int i;
if (ack == wl_lastAck_ && snoop_wlessloss(ack)) {
hdr_flags::access(p)->eln_ = 1;
} else if (ack > wl_lastAck_) {
/* update info about unack'd data */
for (i = wl_buftail_; i != wl_bufhead_; i = wl_next(i)) {
hdr_seq *t = wlseqs_[i];
if (t->seq + t->num - 1 <= ack) {
t->seq = t->num = 0;
} else if (ack < t->seq) {
break;
} else if (ack < t->seq + t->num - 1) {
/* ack for part of a block */
t->num -= ack - t->seq +1;
t->seq = ack + 1;
break;
}
}
wl_buftail_ = i;
if (wl_buftail_ == wl_bufhead_)
wl_state_ |= SNOOP_WLEMPTY;
wl_lastAck_ = ack;
/* Even a new ack could cause an ELN to be set. */
if (wl_bufhead_ != wl_buftail_ && snoop_wlessloss(ack))
hdr_flags::access(p)->eln_ = 1;
}
}
/*
* Return 1 if we think this packet loss was not congestion-related, and
* 0 otherwise. This function simply implements the lookup into the table
* that maintains this info; most of the hard work is done in
* snoop_wless_data() and snoop_wired_ack().
*/
int
Snoop::snoop_wlessloss(int ack)
{
if ((wl_bufhead_ == wl_buftail_) || wlseqs_[wl_buftail_]->seq > ack+1)
return 1;
return 0;
}
/*
* clean snoop cache of packets that have been acked.
*/
double
Snoop::snoop_cleanbufs_(int ack)
{
Scheduler &s = Scheduler::instance();
double sndTime = -1;
if (toutPending_)
s.cancel(toutPending_);
toutPending_ = 0;
if (empty_())
return sndTime;
int i = buftail_;
do {
hdr_snoop *sh = hdr_snoop::access(pkts_[i]);
int seq = hdr_tcp::access(pkts_[i])->seqno();
if (seq <= ack) {
sndTime = sh->sndTime();
Packet::free(pkts_[i]);
pkts_[i] = 0;
fstate_ &= ~SNOOP_FULL; /* XXX redundant? */
} else if (seq > ack)
break;
i = next(i);
} while (i != bufhead_);
if ((i != buftail_) || (bufhead_ != buftail_)) {
fstate_ &= ~SNOOP_FULL;
buftail_ = i;
}
if (!empty_()) {
toutPending_ = (Event *) (pkts_[buftail_]);
s.schedule(rxmitHandler_, toutPending_, timeout());
hdr_snoop *sh = hdr_snoop::access(pkts_[buftail_]);
tailTime_ = sh->sndTime();
}
return sndTime;
}
/*
* Calculate smoothed rtt estimate and linear deviation.
*/
void
Snoop::snoop_rtt(double sndTime)
{
double rtt = Scheduler::instance().clock() - sndTime;
if (parent_->integrate()) {
parent_->snoop_rtt(sndTime);
return;
}
if (rtt > 0) {
srtt_ = g_*srtt_ + (1-g_)*rtt;
double delta = rtt - srtt_;
if (delta < 0)
delta = -delta;
if (rttvar_ != 0)
rttvar_ = g_*delta + (1-g_)*rttvar_;
else
rttvar_ = delta;
}
}
/*
* Calculate smoothed rtt estimate and linear deviation.
*/
void
LLSnoop::snoop_rtt(double sndTime)
{
double rtt = Scheduler::instance().clock() - sndTime;
if (rtt > 0) {
srtt_ = g_*srtt_ + (1-g_)*rtt;
double delta = rtt - srtt_;
if (delta < 0)
delta = -delta;
if (rttvar_ != 0)
rttvar_ = g_*delta + (1-g_)*rttvar_;
else
rttvar_ = delta;
}
}
/*
* Returns 1 if recent queue length is <= half the maximum and 0 otherwise.
*/
int
Snoop::snoop_qlong()
{
/* For now only instantaneous lengths */
if (parent_->ifq()->length() <= 3*parent_->ifq()->limit()/4)
return 1;
return 0;
}
/*
* Ideally, would like to schedule snoop retransmissions at higher priority.
*/
int
Snoop::snoop_rxmit(Packet *pkt)
{
Scheduler& s = Scheduler::instance();
if (pkt != 0) {
hdr_snoop *sh = hdr_snoop::access(pkt);
if (sh->numRxmit() < SNOOP_MAX_RXMIT && snoop_qlong()) {
/* && sh->seqno() == lastAck_+1) */
#if 0
printf("%f Rxmitting packet %d\n", s.clock(),
hdr_tcp::access(pkt)->seqno());
#endif
sh->sndTime() = s.clock();
sh->numRxmit() = sh->numRxmit() + 1;
Packet *p = pkt->copy();
parent_->sendDown(p);
} else
return SNOOP_PROPAGATE;
}
/* Reset timeout for later time. */
if (toutPending_)
s.cancel(toutPending_);
toutPending_ = (Event *)pkt;
s.schedule(rxmitHandler_, toutPending_, timeout());
return SNOOP_SUPPRESS;
}
void
Snoop::snoop_cleanup()
{
}
void
SnoopRxmitHandler::handle(Event *)
{
Packet *p = snoop_->pkts_[snoop_->buftail_];
snoop_->toutPending_ = 0;
if (p == 0)
return;
hdr_snoop *sh = hdr_snoop::access(p);
if (sh->seqno() != snoop_->lastAck_ + 1)
return;
if ((snoop_->bufhead_ != snoop_->buftail_) ||
(snoop_->fstate_ & SNOOP_FULL)) {
/* printf("%f timeout\n", Scheduler::instance().clock());*/
if (snoop_->snoop_rxmit(p) == SNOOP_SUPPRESS)
snoop_->expNextAck_ = snoop_->next(snoop_->buftail_);
}
}
srm-ssm.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
//
// Copyright (c) 1997 by the University of Southern California
// All rights reserved.
//
// Permission to use, copy, modify, and distribute this software and its
// documentation in source and binary forms for non-commercial purposes
// and without fee is hereby granted, provided that the above copyright
// notice appear in all copies and that both the copyright notice and
// this permission notice appear in supporting documentation. 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.
//
// THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
// the suitability of this software for any purpose. 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.
//
// Maintainer:
// Version Date: Tue Jul 22 15:41:16 PDT 1997
// The code implements scalable session message. See
// http://catarina.usc.edu/estrin/papers/infocom98/ssession.ps
//
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (USC/ISI)";
#endif
#include
#include
#include
#include "config.h"
#include "tclcl.h"
#include "agent.h"
#include "packet.h"
#include "ip.h"
#include "srm.h"
#include "srm-ssm.h"
#include "trace.h"
int hdr_srm_ext::offset_;
static class SRMEXTHeaderClass : public PacketHeaderClass {
public:
SRMEXTHeaderClass() : PacketHeaderClass("PacketHeader/SRMEXT",
sizeof(hdr_srm_ext)) {
bind_offset(&hdr_srm_ext::offset_);
}
} class_srmexthdr;
static class SSMSRMAgentClass : public TclClass {
public:
SSMSRMAgentClass() : TclClass("Agent/SRM/SSM") {}
TclObject* create(int, const char*const*) {
return (new SSMSRMAgent());
}
} class_srm_ssm_agent;
SSMSRMAgent::SSMSRMAgent()
: SRMAgent(), glb_sessCtr_(-1), loc_sessCtr_(-1), rep_sessCtr_(-1)
{
bind("group_scope_",&groupScope_);
bind("local_scope_",&localScope_);
bind("scope_flag_",&scopeFlag_);
bind("rep_id_", &repid_);
bind("off_srm_ext_", &off_srm_ext_);
}
int SSMSRMAgent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (strcmp(argv[1], "send") == 0) {
if (strcmp(argv[2], "session") == 0) {
send_sess();
return TCL_OK;
}
if (strcmp(argv[2], "request") == 0) {
int round = atoi(argv[3]);
int sender = atoi(argv[4]);
int msgid = atoi(argv[5]);
send_ctrl(SRM_RQST, round, sender, msgid, 0);
return TCL_OK;
}
if (strcmp(argv[2], "repair") == 0) {
int round = atoi(argv[3]);
int sender = atoi(argv[4]);
int msgid = atoi(argv[5]);
send_ctrl(SRM_REPR, round, sender, msgid, packetSize_);
return TCL_OK;
}
tcl.resultf("%s: invalid send request %s", name_, argv[2]);
return TCL_ERROR;
/*
#if 0
fprintf(stdout,"%s: send request %s passed to srm_agent",
name_, argv[2]);
#endif
return SRMAgent::command(argc, argv);
*/
}
if (argc == 2) {
if (strcmp(argv[1], "start") == 0) {
sip_->sender_ = addr();
sip_->distance_ = 0.0;
/* sip_->repid_ = addr_;
sip_->scopeFlag_ = SRM_GLOBAL;
repid_ = addr_;
scopeFlag_ = SRM_GLOBAL;
*/
groupScope_ = 32;
senderFlag_ = 0;
printf("%s is %d and rep-status %d\n", name_, addr(), scopeFlag_);
return TCL_OK;
}
if (strcmp(argv[1], "ch-rep") == 0) {
if(scopeFlag_ == SRM_GLOBAL) {
sip_->repid_ = repid_ = addr();
sip_->scopeFlag_ = SRM_GLOBAL;
} else {
sip_->repid_ = repid_;
sip_->scopeFlag_ = SRM_LOCAL;
}
return TCL_OK;
}
if (strcmp(argv[1], "distances?") == 0) {
if (sip_->sender_ < 0) { // i.e. this agent is not
tcl.result(""); // yet active.
return TCL_OK;
}
for (SRMinfo* sp = sip_; sp; sp = sp->next_) {
if((sp->distanceFlag_ == REP_DISTANCE) ||
(sp->distanceFlag_ == SELF_DISTANCE)) {
tcl.resultf("%s %d %f", tcl.result(),
sp->sender_, sp->distance_);
} else { /* Return reps distance */
SRMinfo* rsp = get_state(sp->repid_);
tcl.resultf("%s %d %f", tcl.result(),
sp->sender_, rsp->distance_);
}
}
return TCL_OK;
}
}
if (argc == 3) {
if (strcmp(argv[1], "distance?") == 0) {
int sender = atoi(argv[2]);
SRMinfo* sp = get_state(sender);
if((sp->distanceFlag_ == REP_DISTANCE) ||
(sp->distanceFlag_ == SELF_DISTANCE)) {
tcl.resultf("%f", sp->distance_);
} else { /* Return reps distance */
SRMinfo* rsp = get_state(sp->repid_);
tcl.resultf("%f", rsp->distance_);
}
return TCL_OK;
}
}
return SRMAgent::command(argc, argv);
}
void SSMSRMAgent::recv(Packet* p, Handler* h)
{
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_);
if (ih->daddr() == 0) {
// Packet from local agent. Add srm headers, set dst, and fwd
sh->type() = SRM_DATA;
sh->sender() = addr();
sh->seqnum() = ++dataCtr_;
seh->repid() = repid_;
ih->dst() = dst_;
ih->src() = here_;
target_->recv(p, h);
} else {
#if 0
static char *foo[] = {"NONE", "DATA", "SESS", "RQST", "REPR"};
fprintf(stdout, "%7.4f %s %d recvd SRM_%s <%d, %d> from %d\n",
Scheduler::instance().clock(), name_, addr_, foo[sh->type()],
sh->sender(), sh->seqnum(), ih->src());
fflush(stdout);
#endif
switch (sh->type()) {
case SRM_DATA:
recv_data(sh->sender(), sh->seqnum(), seh->repid(), p->accessdata());
Packet::free(p);
break;
case SRM_RQST:
recv_rqst(ih->saddr(), sh->round(), sh->sender(), sh->seqnum(),
seh->repid());
Packet::free(p);
break;
case SRM_REPR:
recv_repr(sh->round(), sh->sender(), sh->seqnum(), p->accessdata());
Packet::free(p);
break;
case SRM_SESS:
// This seqnum() is the session sequence number,
// not the data packet sequence numbers seen before.
// Send the whole pkt for ttl etc..
recv_sess(sh->seqnum(), (int*) p->accessdata(), p);
break;
}
}
}
void SSMSRMAgent::recv_data(int sender, int id, int repid, u_char* data)
{
SRMinfo* sp = get_state(sender);
/* Just store the repid and call srmagent recv_data */
sp->repid_ = repid;
SRMAgent::recv_data(sender,id,data);
}
void SSMSRMAgent::send_ctrl(int type, int round, int sender, int msgid, int size)
{
Packet* p = Agent::allocpkt();
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_);
sh->type() = type;
sh->sender() = sender;
sh->seqnum() = msgid;
sh->round() = round;
seh->repid() = repid_; /* For ctrl messages this is your own repid */
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() = sizeof(hdr_srm) + size;
target_->recv(p, (Handler*)NULL);
}
void SSMSRMAgent::recv_rqst(int requestor, int round, int sender,
int msgid, int repid)
{
//Tcl& tcl = Tcl::instance();
SRMinfo* rsp = get_state(requestor);
rsp->repid_ = repid;
SRMAgent::recv_rqst(requestor,round, sender,msgid);
}
void SSMSRMAgent::send_sess()
{
if (scopeFlag_ == SRM_GLOBAL) {
send_glb_sess();
send_rep_sess();
} else {
send_loc_sess();
}
// timeout_info();
}
#define SESSINFO_SIZE 5
#define SESS_CONST 2
void SSMSRMAgent::send_glb_sess()
{
int size = (SESS_CONST + groupSize_ * SESSINFO_SIZE) * sizeof(int);
/* Currently do extra allocation, later change */
int num_entries;
Packet* p = Agent::allocpkt(size);
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_);
#if 0
printf("sending global session message\n");
#endif
sh->type() = SRM_SESS;
sh->sender() = addr();
sh->seqnum() = ++glb_sessCtr_;
seh->repid() = repid_;
int* data = (int*) p->accessdata();
*data++ = groupSize_;
*data++ = SRM_GLOBAL;
num_entries = 0;
for (SRMinfo* sp = sip_; sp; sp = sp->next_) {
/* Global Session Message has information about Senders/reps */
if ((sp->senderFlag_ ||
(sp->scopeFlag_ == SRM_GLOBAL) ||
(sp->sender_ == addr()))
&& (is_active(sp))) {
*data++ = sp->sender_;
*data++ = sp->ldata_;
*data++ = sp->recvTime_;
*data++ = sp->sendTime_;
*data++ = sp->repid_;
num_entries++;
}
}
data = (int*) p->accessdata();
data[0] = num_entries;
data[1] = SRM_GLOBAL;
size = (SESS_CONST + num_entries * SESSINFO_SIZE) * sizeof(int);
data[5] = (int) (Scheduler::instance().clock()*1000);
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() += size+ sizeof(hdr_srm); /* Add size of srm_hdr_ext */
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
ih->ttl() = groupScope_;
// Currently put this to distinguish various session messages
ih->flowid() = SRM_GLOBAL;
seh->ottl() = groupScope_;
target_->recv(p, (Handler*)NULL);
}
void SSMSRMAgent::send_loc_sess()
{
int size = (SESS_CONST + groupSize_ * SESSINFO_SIZE) * sizeof(int);
/* Currently do extra allocation, later change */
int num_entries;
Packet* p = Agent::allocpkt(size);
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_);
sh->type() = SRM_SESS;
sh->sender() = addr();
sh->seqnum() = ++loc_sessCtr_;
seh->repid() = repid_;
#if 0
printf("sending local session message\n");
#endif
int* data = (int*) p->accessdata();
//int* tmp_data = (int*) p->accessdata();
*data++ = groupSize_;
*data++ = SRM_LOCAL;
num_entries = 0;
for (SRMinfo* sp = sip_; sp; sp = sp->next_) {
/* Local Session Message has information
about Senders/other locals */
if ((sp->senderFlag_ ||
(sp->scopeFlag_ == SRM_LOCAL) ||
(sp->distanceFlag_ = SELF_DISTANCE) ||
/* For the reps that I am hearing from */
(sp->sender_ == addr()) ||
// just in case, I have not set the flags properly,
// one entry has to be there
(repid_ == sp->sender_))
&& (is_active(sp))) {
*data++ = sp->sender_;
*data++ = sp->ldata_;
*data++ = sp->recvTime_;
*data++ = sp->sendTime_;
*data++ = sp->repid_;
num_entries++;
}
}
data = (int*) p->accessdata();
data[0] = num_entries;
data[1] = SRM_LOCAL;
size = (SESS_CONST + num_entries * SESSINFO_SIZE) * sizeof(int);
data[5] = (int) (Scheduler::instance().clock()*1000);
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() += size+ sizeof(hdr_srm);
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
ih->ttl() = localScope_;
// Currently put this to distinguish various session messages
ih->flowid() = SRM_LOCAL;
seh->ottl() = localScope_;
target_->recv(p, (Handler*)NULL);
}
void SSMSRMAgent::send_rep_sess()
{
int size = (SESS_CONST + groupSize_ * SESSINFO_SIZE) * sizeof(int);
/* Currently do extra allocation, later change */
int num_entries, num_local_members;
Packet* p = Agent::allocpkt(size);
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_);
sh->type() = SRM_SESS;
sh->sender() = addr();
sh->seqnum() = ++rep_sessCtr_;
seh->repid() = repid_;
#if 0
printf("sending rep_info session message\n");
#endif
int* data = (int*) p->accessdata();
*data++ = groupSize_;
*data++ = SRM_RINFO;
num_entries = 0;
num_local_members = 0;
for (SRMinfo* sp = sip_; sp; sp = sp->next_) {
if (sp->activeFlag_ == ACTIVE) {
/* Rep info has distance to others reps and
timestamps for everyone */
*data++ = sp->sender_;
*data++ = sp->ldata_;
if (sp->scopeFlag_ == SRM_GLOBAL) {
*data++ = (int) (sp->distance_*1000);
data++;
} else {
// Put a check here for only people I have heard from.??
*data++ = sp->recvTime_;
*data++ = sp->sendTime_;
num_local_members++;
}
*data++ = sp->repid_;
num_entries++;
}
}
if (num_local_members <= 0) {
Packet::free(p);
return;
}
data = (int*) p->accessdata();
data[0] = num_entries;
data[1] = SRM_RINFO;
size = (SESS_CONST + num_entries * SESSINFO_SIZE) * sizeof(int);
data[5] = (int) (Scheduler::instance().clock()*1000);
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() += size+ sizeof(hdr_srm);
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
ih->ttl() = localScope_;
// Currently put this to distinguish various session messages
ih->flowid() = SRM_RINFO;
seh->ottl() = localScope_;
target_->recv(p, (Handler*)NULL);
}
#define GET_SESSION_INFO \
sender = *data++; \
dataCnt = *data++; \
rtime = *data++; \
stime = *data++; \
repid = *data++; \
// printf("s:%d, d:%d, rt:%d, st:%d, rep:%d\n",sender,
// dataCnt,rtime,stime,repid)
void SSMSRMAgent::recv_sess(int sessCtr, int* data, Packet* p)
{
int type = data[1];
switch (type) {
case SRM_GLOBAL :
recv_glb_sess(sessCtr,data,p);
break;
case SRM_LOCAL :
recv_loc_sess(sessCtr,data,p);
break;
case SRM_RINFO :
if (scopeFlag_ == SRM_GLOBAL) return;
recv_rep_sess(sessCtr,data,p);
break;
}
Packet::free(p);
}
void SSMSRMAgent::recv_glb_sess(int sessCtr, int* data, Packet* p)
{
Tcl& tcl = Tcl::instance();
SRMinfo* sp;
int ttl;
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
//hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_);
ttl = seh->ottl() - ih->ttl();
int sender, dataCnt, rtime, stime,repid;
int now, sentAt, sentBy;
int cnt = *data++;
//int type = *data++;
int i;
// data = data + SESS_CONST;
/* As as included type of session message also */
/* The first block contains the sender's own state */
GET_SESSION_INFO;
if (sender == addr())
// sender's own session message
return;
if (seh->repid() != repid) {
fprintf(stdout,"%f Recvd a glb-sess with diff header(%d) != inside(%d)\n",
Scheduler::instance().clock(),seh->repid(),repid);
/* abort(); */
return;
}
if (sender != repid) {
fprintf(stdout,"%f Recvd a glb-sess with repid(%d) != address(%d)\n",
Scheduler::instance().clock(),repid,sender);
/* abort(); */
return;
}
sp = get_state(sender);
if (sp->lglbsess_ > sessCtr) // older session message recd.
return;
#if 0
fprintf(stdout,"%s recv-gsess from %d\n",name_,sender);
#endif
tcl.evalf("%s recv-gsess %d %d", name_, sender, ttl);
if (sp->scopeFlag_ != SRM_GLOBAL) {
sp->scopeFlag_ = SRM_GLOBAL;
}
sp->repid_ = repid;
now = (int) (Scheduler::instance().clock() * 1000);
sentBy = sender; // to later compute rtt
sentAt = stime;
sp->lglbsess_ = sessCtr;
sp->recvTime_ = now;
sp->sendTime_ = stime;
for (i = sp->ldata_ + 1; i <= dataCnt; i++)
if (! sp->ifReceived(i))
tcl.evalf("%s request %d %d", name_, sender, i, sp->repid_);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
for (i = 1; i < cnt; i++) {
GET_SESSION_INFO;
if (sender == addr() && now) {
int rtt = (now - sentAt) + (rtime - stime);
sp = get_state(sentBy);
sp->distance_ = (double) rtt / 2 / 1000;
sp->distanceFlag_ = SELF_DISTANCE;
#if 0
fprintf(stderr,
"%7.4f %s compute distance to %d: %f\n",
Scheduler::instance().clock(), name_,
sentBy, sp->distance_);
#endif
continue;
}
sp = get_state(sender);
for (int j = sp->ldata_ + 1; j <= dataCnt; j++)
if (! sp->ifReceived(j))
tcl.evalf("%s request %d %d", name_, sender, j, sp->repid_);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
}
}
void SSMSRMAgent::recv_loc_sess(int sessCtr, int* data, Packet* p)
{
Tcl& tcl = Tcl::instance();
SRMinfo* sp;
int ttl;
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
//hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_);
ttl = seh->ottl() - ih->ttl();
int sender, dataCnt, rtime, stime,repid;
int now, sentAt, sentBy;
int cnt = *data++;
/*int type = * */data++;
int i;
// data = data + SESS_CONST;
/* As as included type of session message also */
/* The first block contains the sender's own state */
GET_SESSION_INFO;
if (sender == addr()) // sender's own session message
return;
sp = get_state(sender);
if (sp->llocsess_ > sessCtr) // older session message recd.
return;
if (sp->scopeFlag_ != SRM_LOCAL) {
sp->scopeFlag_ = SRM_LOCAL;
// Also put a check if this is my child
}
sp->repid_ = repid;
#if 0
fprintf(stdout,"%s recv-lsess from %d\n",name_,sender);
#endif
tcl.evalf("%s recv-lsess %d %d %d", name_, sender, repid, ttl);
now = (int) (Scheduler::instance().clock() * 1000);
sentBy = sender; // to later compute rtt
sentAt = stime;
sp->llocsess_ = sessCtr;
sp->recvTime_ = now;
sp->sendTime_ = stime;
for (i = sp->ldata_ + 1; i <= dataCnt; i++)
if (! sp->ifReceived(i))
tcl.evalf("%s request %d %d", name_, sender, i, sp->repid_);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
for (i = 1; i < cnt; i++) {
GET_SESSION_INFO;
if (sender == addr() && now) {
int rtt = (now - sentAt) + (rtime - stime);
sp = get_state(sentBy);
sp->distance_ = (double) rtt / 2 / 1000;
sp->distanceFlag_ = SELF_DISTANCE;
#if 0
fprintf(stderr,
"%7.4f %s compute distance to %d: %f\n",
Scheduler::instance().clock(), name_,
sentBy, sp->distance_);
#endif
continue;
}
sp = get_state(sender);
for (int j = sp->ldata_ + 1; j <= dataCnt; j++)
if (! sp->ifReceived(j))
tcl.evalf("%s request %d %d", name_, sender, j, sp->repid_);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
}
}
// For the global members the repid == addr
void SSMSRMAgent::recv_rep_sess(int sessCtr, int* data, Packet*)
{
Tcl& tcl = Tcl::instance();
SRMinfo* sp;
int sender, dataCnt, rtime, stime,repid;
int now, sentAt, sentBy;
int cnt = *data++;
/*int type = **/data++;
int i;
//data = data + SESS_CONST;
/* As as included type of session message also */
/* The first block contains the sender's own state */
GET_SESSION_INFO;
if (sender == addr()) // sender's own session message
return;
if (sender != repid_) // not from my rep
return;
if (sender != repid) {
fprintf(stdout,"Recvd a rep-sess with repid(%d) != address(%d)\n",
repid,sender);
abort();
}
sp = get_state(sender);
if (sp->lrepsess_ > sessCtr) // older session message recd.
return;
if (sp->scopeFlag_ != SRM_GLOBAL) // Should I change the repid also??
sp->scopeFlag_ = SRM_GLOBAL;
now = (int) (Scheduler::instance().clock() * 1000);
sentBy = sender; // to later compute rtt
sentAt = stime;
sp->lrepsess_ = sessCtr;
sp->recvTime_ = now;
sp->sendTime_ = stime;
for (i = sp->ldata_ + 1; i <= dataCnt; i++)
if (! sp->ifReceived(i))
tcl.evalf("%s request %d %d", name_, sender, i, sp->repid_);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
for (i = 1; i < cnt; i++) {
GET_SESSION_INFO;
if (sender == addr() && now) {
int rtt = (now - sentAt) + (rtime - stime);
sp = get_state(sentBy);
sp->distance_ = (double) rtt / 2 / 1000;
sp->distanceFlag_ = SELF_DISTANCE;
#if 0
fprintf(stderr,
"%7.4f %s compute distance to %d: %f\n",
Scheduler::instance().clock(), name_,
sentBy, sp->distance_);
#endif
continue;
}
if ((sender == repid) && (sender != sentBy)) {
sp = get_state(sender);
if (!(is_active(sp) && (sp->distanceFlag_ == SELF_DISTANCE))) {
sp->distance_ = (double) rtime/1000;
/* As for global members this is distance */
sp->distanceFlag_ = REP_DISTANCE;
/* ?? What if I am hearing from this guy already */
}
}
sp = get_state(sender);
for (int j = sp->ldata_ + 1; j <= dataCnt; j++)
if (! sp->ifReceived(j))
tcl.evalf("%s request %d %d", name_, sender, j, sp->repid_);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
}
}
#define sessionDelay 1000
void SSMSRMAgent::timeout_info()
{
int now;
now = (int) (Scheduler::instance().clock() * 1000);
for (SRMinfo* sp = sip_->next_; sp; sp = sp->next_) {
if ((now - sp->recvTime_) >= 3*sessionDelay) {
sp->activeFlag_ = INACTIVE;
groupSize_--;
}
}
}
int SSMSRMAgent::is_active(SRMinfo *sp)
{
int now;
now = (int) (Scheduler::instance().clock() * 1000);
if ((sp->sender_ != addr()) && ((now - sp->recvTime_) >= 3*sessionDelay)) {
return 0;
} else {
return 1;
}
}
srm-topo.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 Suchitra Raman , June 1997.
*/
#include
#include
#include "config.h"
#include "tclcl.h"
#include "srm-topo.h"
#include "scheduler.h"
#define SRM_DEBUG
Topology::Topology(int nn, int src) : idx_(nn), src_(src)
{
node_ = new SrmNode[nn];
for (int i = 0; i < nn; i ++)
node_[i].id(i);
bind("src_", &src_);
bind("delay_", &delay_);
bind("D_", &D_);
bind("frac_", &frac_);
/* D_ (ms) is the delay of node 1 from node 0 */
bind("det_", &det_);
bind("rtt_est_", &rtt_est_);
bind("rand_", &rand_);
}
Topology::~Topology() {
delete [] node_;
}
int Topology::command(int argc, const char*const* argv)
{
//Tcl& tcl = Tcl::instance();
if (argc == 3) {
if (strcmp(argv[1], "flood") == 0) {
flood(0, atoi(argv[2]));
return (TCL_OK);
}
}
return (TclObject::command(argc, argv));
}
SrmNode* Topology::node(int nn)
{
if (nn < 0 || nn >= idx_) return 0;
return &(node_[nn]);
}
static class LineClass : public TclClass {
public:
LineClass() : TclClass("Topology/Line") {}
TclObject* create(int, const char*const* argv) {
int nn = atoi(argv[4]);
return (new Line(nn, 0));
}
} class_line_topo;
double Line::backoff(int dst)
{
double rtt;
if (topology->rtt_estimated() == 1)
rtt = delay(dst, 0);
else rtt = D_ * frac_;
double b;
double sqroot = sqrt(rtt);
double r = Random::uniform(0.0, 1.0);
switch(c2func_) {
case LOG :
b = rtt * (det_ + rand_ * r * log(rtt)/log(D_));
break;
case SQRT :
b = rtt * (det_ + rand_ * r * sqroot/sqrt(D_));
break;
case LINEAR :
b = rtt * (det_ + rand_ * r * rtt/D_);
break;
case CONSTANT :
b = rtt * (det_ + rand_ * r * 1.);
break;
}
return b;
}
#ifdef SRM_BIMODAL
double Line::backoff(int dst)
{
double rtt;
if (topology->rtt_estimated() == 1)
rtt = delay(dst, 0);
else rtt = D_ * frac_;
double rbackoff;
double p = Random::uniform(0.0, 1.0);
int bin = 0;
int copies = c_;
int size = topology->idx();
if (p <= copies * 1./size) {
rbackoff = Random::uniform(0.0, alpha_);
bin = 0;
} else {
rbackoff = Random::uniform(beta_, 1.0 + beta_);
bin = 1;
}
return (rtt * (det_ + rand_ * rbackoff));
}
#endif
Interface_List* Line::oif(int node, int iif=SRM_NOIF)
{
//int oif;
Interface_List *ilist = new Interface_List;
/* If there are no more nodes downstream, return -1 */
if ((iif <= node && node >= idx_ - 1) || (iif > node && node == 0))
return 0;
if (iif == SRM_NOIF)
{
ilist->append(node + 1);
ilist->append(node - 1);
} else if (iif <= node)
ilist->append(node + 1);
else
ilist->append(node - 1);
return (ilist);
}
double Line::delay(int src, int dst)
{
if (src == 0 || dst == 0)
return D_ + delay_ * abs(dst - src - 1);
else
return delay_ * abs(dst - src);
}
double Star::delay(int src, int dst)
{
if (src == 0 || dst == 0)
return D_;
else
return delay_;
}
/*
* Very simple now, can only send to direct ancestor/descendant
*/
double BTree::delay(int src, int dst)
{
double src_ht = 0;
double dst_ht = 0;
if (src > 0)
src_ht = 1 + floor(log(src)/log(2));
if (dst > 0)
dst_ht = 1 + floor(log(dst)/log(2));
if (src == 0 || dst == 0)
return D_ + delay_ * abs(int (dst_ht - src_ht - 1));
else
return delay_ * abs(int (dst_ht - src_ht));
}
/*
* There is always an outbound interface. We should not
* start a flood() from a leaf node.
* Change it for other topologies.
*/
void Line::flood(int start, int seqno)
{
SRM_Event *se = new SRM_Event(seqno, SRM_DATA, start);
node_[start].send(se);
}
/*
* BTree -
*/
static class BTreeClass : public TclClass {
public:
BTreeClass() : TclClass("Topology/BTree") {}
TclObject* create(int, const char*const* argv) {
int nn = atoi(argv[4]);
return (new BTree(nn, 0));
}
} class_btree_topo;
/*
* The ranges of the different distributions
* must be normalized to 1.
*/
double BTree::backoff(int id)
{
double rtt;
if (topology->rtt_estimated())
rtt = delay(id, 0);
else rtt = D_ * frac_;
double r = Random::uniform(0.0, 1.0);
double b;
double sqroot = sqrt(rtt);
double D = topology->D();
switch(c2func_) {
case LOG :
b = rtt * (det_ + rand_ * r * log(rtt)/log(D));
break;
case SQRT :
b = rtt * (det_ + rand_ * r * sqroot/sqrt(D));
break;
case LINEAR :
b = rtt * (det_ + rand_ * r * rtt/D);
break;
case CONSTANT :
b = rtt * (det_ + rand_ * r * 1.);
break;
}
return b;
}
Interface_List* BTree::oif(int node, int iif=SRM_NOIF)
{
//int oif;
Interface_List *ilist = new Interface_List;
/*
* If the packet comes from the source,
* there is only 1 outgoing link.
* We make the assumption that source = 0 always (YUCK!)
*/
if (iif == SRM_NOIF) {
if (node == 0) {
ilist->append(1);
}
else {
ilist->append(2 * node + 1);
ilist->append(2 * node);
int k = (int)floor(.5 * node);
ilist->append(k);
}
} else if (iif <= node) {
ilist->append(2 * node + 1);
ilist->append(2 * node);
}
// Packet came along 2n + 1 or 2n + 2
else if (iif == 2 * node + 1) {
if (node == 0)
return ilist;
ilist->append(2 * node);
ilist->append((int) floor(.5 * node));
} else if (iif == 2 * node) {
ilist->append(2 * node + 1);
ilist->append((int)floor(.5 * node));
}
return (ilist);
}
/*
* Star -
*/
static class StarClass : public TclClass {
public:
StarClass() : TclClass("Topology/Star") {}
TclObject* create(int, const char*const* argv) {
int nn = atoi(argv[4]);
return (new Star(nn, 0));
}
} class_star_topo;
/*
* SrmNode -
*/
void SrmNode::dump_packet(SRM_Event *e)
{
#ifdef SRM_DEBUG
tprintf(("(type %d) (in %d) -- @ %d --> \n", e->type(), e->iif(), id_));
#endif
}
/* This forwards an event by making multiple copies of the
* event 'e'. Does NOT free event 'e'.
*/
void SrmNode::send(SRM_Event *e)
{
/*
* Copy the packet and send it over to
* all the outbound interfaces
*/
int nn;
Scheduler& s = Scheduler::instance();
SRM_Event *copy;
Interface *p;
Interface_List *ilist = topology->oif(id_, e->iif());
if (e->iif() < 0)
e->iif(id_);
if (ilist) {
for (p=ilist->head_; p; p=p->next_) {
nn = p->in_;
int t = e->type();
//int i = id_;
int snum = e->seqno();
SrmNode *next = topology->node(nn);
if (next) {
copy = new SRM_Event(snum, t, id_);
s.schedule(next, copy,
topology->delay(id_, nn));
}
}
}
delete ilist;
delete e;
}
/*
* Demux the two types of events depending on
* the type field.
*/
void SrmNode::handle(Event* event)
{
SRM_Event *srm_event = (SRM_Event *) event;
int type = srm_event->type();
int seqno = srm_event->seqno();
//int iif = srm_event->iif();
//Scheduler& s = Scheduler::instance();
switch (type) {
case SRM_DATA :
if (seqno != expected_)
sched_nack(seqno);
expected_ = seqno;
break;
case SRM_PENDING_RREQ :
tprintf(("Fired RREQ (node %d)\n", id_));
remove(seqno, SRM_NO_SUPPRESS);
srm_event->type(SRM_RREQ);
break;
case SRM_RREQ :
remove(seqno, SRM_SUPPRESS);
break;
default :
tprintf(("panic: node(%d) Unexpected type %d\n", id_, type));
return;
}
#ifdef SRM_STAR
if (type == SRM_RREQ || type == SRM_DATA) {
delete srm_event;
return;
}
#endif
send(srm_event);
return;
}
/*
* XXX Should take two sequence numbers. The iif field is a dummy. We should be
* careful not to use it for NACKs
*/
void SrmNode::sched_nack(int seqno)
{
double backoff, time;
Scheduler& s = Scheduler::instance();
SRM_Event *event = new SRM_Event(seqno,
SRM_PENDING_RREQ, SRM_NOIF);
append(event);
backoff = topology->backoff(id_);
time = backoff + s.clock();
// tprintf(("node(%d) schd rrq after %f s\n", id_, backoff));
s.schedule(this, event, backoff);
}
void SrmNode::append(SRM_Event *e)
{
SRM_Request *req = new SRM_Request(e);
req->next_ = pending_;
pending_ = req;
}
/* If an event identical to e exists, cancel it */
void SrmNode::remove(int seqno, int flag)
{
SRM_Request *curr, *prev;
SRM_Event *ev;
if (!pending_)
return;
for (curr=pending_, prev=0; curr; curr=curr->next_)
{
ev = curr->event_;
if (ev->seqno() == seqno) {
if (!prev)
pending_ = curr->next_;
else {
prev->next_ = curr->next_;
prev = curr;
}
if (flag == SRM_SUPPRESS) {
curr->cancel_timer();
}
delete curr;
}
}
}
SRM_Event::SRM_Event(SRM_Event *e)
{
seqno_ = e->seqno();
type_ = e->type();
iif_ = e->iif();
}
SRM_Request::~SRM_Request() {}
void SRM_Request::cancel_timer()
{
if (event_) {
Scheduler& s = Scheduler::instance();
s.cancel(event_);
}
}
void Interface_List::append(int in)
{
Interface *i = new Interface(in);
i->next_ = head_;
head_ = i;
}
Interface_List::~Interface_List()
{
Interface *p, *next;
for (p=head_; p; p=next)
{
next = p->next_;
delete p;
}
}
void BTree::flood(int start, int seqno)
{
SRM_Event *se = new SRM_Event(seqno, SRM_DATA, SRM_NOIF);
node_[start].send(se);
}
void Star::flood(int start, int seqno)
{
SRM_Event *se = new SRM_Event(seqno, SRM_DATA, start);
node_[start].send(se);
}
Interface_List* Star::oif(int node, int iif=SRM_NOIF)
{
int i;
Interface_List *ilist = new Interface_List;
/* Make a list with every node except myself */
for (i = 0; i < topology->idx(); i ++)
{
if (i != node && i != iif) {
ilist->append(i);
}
}
return (ilist);
}
/*
* Distance of source to cluster = D_
*/
double Star::backoff(int id)
{
double rtt = topology->delay(id, 0);
double rbackoff;
double p = Random::uniform(0.0, 1.0);
static int bin = 0;
int copies = c_;
int size = topology->idx();
if (p <= copies * 1./size) {
rbackoff = Random::uniform(0.0, alpha_);
bin ++;
} else {
rbackoff = Random::uniform(beta_, 1.0 + beta_);
}
return (rtt * (det_ + rand_ * rbackoff));
}
#ifdef SRM_BIMODAL
double BTree::backoff(int dst)
{
double height = floor(log(dst)/log(2));
double D = topology->D();
double rtt = delay_ * height + D;
double p = Random::uniform(0.0, 1.0);
double rbackoff;
static int bin = 0;
int copies = c_;
int size = topology->idx();
if (p <= copies * 1./size) {
rbackoff = Random::uniform(0.0, alpha_);
bin ++;
} else {
rbackoff = Random::uniform(1.0 + alpha_, 2.0);
}
return (rtt * (det_ + rand_ * rbackoff));
}
#endif
srm.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
//
// Copyright (c) 1997 by the University of Southern California
// All rights reserved.
//
// Permission to use, copy, modify, and distribute this software and its
// documentation in source and binary forms for non-commercial purposes
// and without fee is hereby granted, provided that the above copyright
// notice appear in all copies and that both the copyright notice and
// this permission notice appear in supporting documentation. 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.
//
// THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about
// the suitability of this software for any purpose. 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.
//
// Maintainer: Kannan Varadhan
// Version Date: Tue Jul 22 15:41:16 PDT 1997
//
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (USC/ISI)";
#endif
#include
#include
#include "config.h"
#include "agent.h"
#include "ip.h"
#include "srm.h"
#include "trace.h"
#include "rtp.h"
int hdr_srm::offset_;
int hdr_asrm::offset_;
static class SRMHeaderClass : public PacketHeaderClass {
public:
SRMHeaderClass() : PacketHeaderClass("PacketHeader/SRM",
sizeof(hdr_srm)) {
bind_offset(&hdr_srm::offset_);
}
} class_srmhdr;
static class ASRMHeaderClass : public PacketHeaderClass {
public:
ASRMHeaderClass() : PacketHeaderClass("PacketHeader/aSRM",
sizeof(hdr_asrm)) {
bind_offset(&hdr_asrm::offset_);
}
} class_adaptive_srmhdr;
static class SRMAgentClass : public TclClass {
public:
SRMAgentClass() : TclClass("Agent/SRM") {}
TclObject* create(int, const char*const*) {
return (new SRMAgent());
}
} class_srm_agent;
static class ASRMAgentClass : public TclClass {
public:
ASRMAgentClass() : TclClass("Agent/SRM/Adaptive") {}
TclObject* create(int, const char*const*) {
return (new ASRMAgent());
}
} class_adaptive_srm_agent;
SRMAgent::SRMAgent()
: Agent(PT_SRM), dataCtr_(-1), sessCtr_(-1), siphash_(0), seqno_(-1),
app_type_(PT_NTYPE)
{
sip_ = new SRMinfo(-1);
bind("off_srm_", &off_srm_);
bind("off_cmn_", &off_cmn_);
bind("off_rtp_", &off_rtp_);
bind("packetSize_", &packetSize_);
bind("groupSize_", &groupSize_);
bind("app_fid_", &app_fid_);
}
SRMAgent::~SRMAgent()
{
cleanup();
}
int SRMAgent::command(int argc, const char*const* argv)
{
Tcl& tcl = Tcl::instance();
if (strcmp(argv[1], "send") == 0) {
if (strcmp(argv[2], "session") == 0) {
send_sess();
return TCL_OK;
}
if (strcmp(argv[2], "request") == 0) {
int round = atoi(argv[3]);
int sender = atoi(argv[4]);
int msgid = atoi(argv[5]);
send_ctrl(SRM_RQST, round, sender, msgid, 0);
return TCL_OK;
}
if (strcmp(argv[2], "repair") == 0) {
int round = atoi(argv[3]);
int sender = atoi(argv[4]);
int msgid = atoi(argv[5]);
send_ctrl(SRM_REPR, round, sender, msgid, packetSize_);
return TCL_OK;
}
tcl.resultf("%s: invalid send request %s", name_, argv[2]);
return TCL_ERROR;
}
if (argc == 2) {
if (strcmp(argv[1], "distances?") == 0) {
tcl.result("");
if (sip_->sender_ >= 0) { // i.e. this agent is active
for (SRMinfo* sp = sip_; sp; sp = sp->next_) {
tcl.resultf("%s %d %f", tcl.result(),
sp->sender_,
sp->distance_);
}
}
return TCL_OK;
}
if (strcmp(argv[1], "start") == 0) {
start();
return TCL_OK;
}
}
if (argc == 3) {
if (strcmp(argv[1], "distance?") == 0) {
int sender = atoi(argv[2]);
SRMinfo* sp = get_state(sender);
tcl.resultf("%lf", sp->distance_);
return TCL_OK;
}
}
return Agent::command(argc, argv);
}
void SRMAgent::recv(Packet* p, Handler* h)
{
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
if (ih->daddr() == -1) {
// Packet from local agent. Add srm headers, set dst, and fwd
sh->type() = SRM_DATA;
sh->sender() = addr();
sh->seqnum() = ++dataCtr_;
addExtendedHeaders(p);
ih->dst() = dst_;
target_->recv(p, h);
} else {
#if 0
static char *foo[] = {"NONE", "DATA", "SESS", "RQST", "REPR"};
fprintf(stderr, "%7.4f %s %d recvd SRM_%s <%d, %d> from %d\n",
Scheduler::instance().clock(), name_, addr_,
foo[sh->type()],
sh->sender(), sh->seqnum(), ih->src());
#endif
parseExtendedHeaders(p);
switch (sh->type()) {
case SRM_DATA:
recv_data(sh->sender(), sh->seqnum(), p->accessdata());
break;
case SRM_RQST:
recv_rqst(ih->saddr(),
sh->round(), sh->sender(), sh->seqnum());
break;
case SRM_REPR:
recv_repr(sh->round(), sh->sender(), sh->seqnum(),
p->accessdata());
break;
case SRM_SESS:
// This seqnum() is the session sequence number,
// not the data packet sequence numbers seen before.
recv_sess(p, sh->seqnum(), (int*) p->accessdata());
break;
}
Packet::free(p);
}
}
void SRMAgent::sendmsg(int nbytes, const char* /*flags*/)
{
if (nbytes == -1) {
printf("Error: sendmsg() for SRM should not be -1\n");
return;
}
// The traffic generator may have reset our payload type when it
// initialized. If so, save the current payload type as app_type_,
// and set type_ to PT_SRM. Use app_type_ for all app. packets
//
if (type_ != PT_SRM) {
app_type_ = type_;
type_ = PT_SRM;
}
size_ = nbytes;
Packet *p;
p = allocpkt();
hdr_ip* ih = (hdr_ip*) p->access(off_ip_);
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_);
hdr_cmn* ch = (hdr_cmn*)p->access(off_cmn_);
//hdr_cmn* ch = hdr_cmn::access(p);
ch->ptype() = app_type_;
ch->size() = size_;
ih->flowid() = app_fid_;
rh->seqno() = ++seqno_;
// Add srm headers, set dst, and fwd
sh->type() = SRM_DATA;
sh->sender() = addr();
sh->seqnum() = ++dataCtr_;
addExtendedHeaders(p);
ih->dst() = dst_;
target_->recv(p);
}
void SRMAgent::send_ctrl(int type, int round, int sender, int msgid, int size)
{
Packet* p = Agent::allocpkt();
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
sh->type() = type;
sh->sender() = sender;
sh->seqnum() = msgid;
sh->round() = round;
addExtendedHeaders(p);
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() = sizeof(hdr_srm) + size;
target_->recv(p);
}
void SRMAgent::recv_data(int sender, int msgid, u_char*)
{
Tcl& tcl = Tcl::instance();
SRMinfo* sp = get_state(sender);
if (msgid > sp->ldata_) {
(void) request(sp, msgid - 1);
sp->setReceived(msgid);
sp->ldata_ = msgid;
} else {
tcl.evalf("%s recv data %d %d", name_, sender, msgid);
}
}
void SRMAgent::recv_rqst(int requestor, int round, int sender, int msgid)
{
Tcl& tcl = Tcl::instance();
SRMinfo* sp = get_state(sender);
if (msgid > sp->ldata_) {
(void) request(sp, msgid); // request upto msgid
sp->ldata_ = msgid;
} else {
tcl.evalf("%s recv request %d %d %d %d", name_,
requestor, round, sender, msgid);
}
}
void SRMAgent::recv_repr(int round, int sender, int msgid, u_char*)
{
Tcl& tcl = Tcl::instance();
SRMinfo* sp = get_state(sender);
if (msgid > sp->ldata_) {
(void) request(sp, msgid - 1); // request upto msgid - 1
sp->setReceived(msgid);
sp->ldata_ = msgid;
} else {
tcl.evalf("%s recv repair %d %d %d", name_,
round, sender, msgid);
}
// Notice that we currently make no provisions for a listener
// agent to receive the data.
}
void SRMAgent::send_sess()
{
int size = (1 + groupSize_ * 4) * sizeof(int);
Packet* p = Agent::allocpkt(size);
hdr_srm* sh = (hdr_srm*) p->access(off_srm_);
sh->type() = SRM_SESS;
sh->sender() = addr();
sh->seqnum() = ++sessCtr_;
addExtendedHeaders(p);
int* data = (int*) p->accessdata();
*data++ = groupSize_;
for (SRMinfo* sp = sip_; sp; sp = sp->next_) {
*data++ = sp->sender_;
*data++ = sp->ldata_;
*data++ = sp->recvTime_;
*data++ = sp->sendTime_;
}
data = (int*) p->accessdata();
data[4] = (int) (Scheduler::instance().clock()*1000);
hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_);
ch->size() = size+ sizeof(hdr_srm);
target_->recv(p, (Handler*)NULL);
}
#define GET_SESSION_INFO \
sender = *data++; \
dataCnt = *data++; \
rtime = *data++; \
stime = *data++
void SRMAgent::recv_sess(Packet*, int sessCtr, int* data)
{
SRMinfo* sp;
int sender, dataCnt, rtime, stime;
int now, sentAt, sentBy;
int cnt = *data++;
int i;
/* The first block contains the sender's own state */
GET_SESSION_INFO;
if (sender == addr()) // sender's own session message
return;
sp = get_state(sender);
if (sp->lsess_ > sessCtr) // older session message recd.
return;
now = (int) (Scheduler::instance().clock() * 1000);
sentBy = sender; // to later compute rtt
sentAt = stime;
sp->lsess_ = sessCtr;
sp->recvTime_ = now;
sp->sendTime_ = stime;
(void) request(sp, dataCnt);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
for (i = 1; i < cnt; i++) {
GET_SESSION_INFO;
if (sender == addr() && now) {
//
// This session message from sender sentBy:
// vvvvv
// now <=======+ sentAt
// | |
// stime +=======> rtime
// ^^^^^
// Earlier session message sent by ``this'' agent
//
int rtt = (now - sentAt) + (rtime - stime);
sp = get_state(sentBy);
sp->distance_ = (double) rtt / 2 / 1000;
#if 0
fprintf(stderr,
"%7.4f %s compute distance to %d: %f\n",
Scheduler::instance().clock(), name_,
sentBy, sp->distance_);
#endif
continue;
}
sp = get_state(sender);
(void) request(sp, dataCnt);
if (sp->ldata_ < dataCnt)
sp->ldata_ = dataCnt;
}
}
tbf.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.
*/
/* Token Bucket filter which has 3 parameters :
a. Token Generation rate
b. Token bucket depth
c. Max. Queue Length (a finite length would allow this to be used as policer as packets are dropped after queue gets full)
*/
#include "connector.h"
#include "packet.h"
#include "queue.h"
#include "tbf.h"
TBF::TBF() :tokens_(0),tbf_timer_(this), init_(1)
{
q_=new PacketQueue();
bind_bw("rate_",&rate_);
bind("bucket_",&bucket_);
bind("qlen_",&qlen_);
}
TBF::~TBF()
{
if (q_->length() != 0) {
//Clear all pending timers
tbf_timer_.cancel();
//Free up the packetqueue
for (Packet *p=q_->head();p!=0;p=p->next_)
Packet::free(p);
}
delete q_;
}
void TBF::recv(Packet *p, Handler *)
{
//start with a full bucket
if (init_) {
tokens_=bucket_;
lastupdatetime_ = Scheduler::instance().clock();
init_=0;
}
hdr_cmn *ch=(hdr_cmn *)p->access(off_cmn_);
//enque packets appropriately if a non-zero q already exists
if (q_->length() !=0) {
if (q_->length() < qlen_) {
q_->enque(p);
return;
}
drop(p);
return;
}
double tok;
tok = getupdatedtokens();
int pktsize = ch->size()<<3;
if (tokens_ >=pktsize) {
target_->recv(p);
tokens_-=pktsize;
}
else {
if (qlen_!=0) {
q_->enque(p);
tbf_timer_.resched((pktsize-tokens_)/rate_);
}
else {
drop(p);
}
}
}
double TBF::getupdatedtokens(void)
{
double now=Scheduler::instance().clock();
tokens_ += (now-lastupdatetime_)*rate_;
if (tokens_ > bucket_)
tokens_=bucket_;
lastupdatetime_ = Scheduler::instance().clock();
return tokens_;
}
void TBF::timeout(int)
{
if (q_->length() == 0) {
fprintf (stderr,"ERROR in tbf\n");
abort();
}
Packet *p=q_->deque();
double tok;
tok = getupdatedtokens();
hdr_cmn *ch=(hdr_cmn *)p->access(off_cmn_);
int pktsize = ch->size()<<3;
//We simply send the packet here without checking if we have enough tokens
//because the timer is supposed to fire at the right time
target_->recv(p);
tokens_-=pktsize;
if (q_->length() !=0 ) {
p=q_->head();
hdr_cmn *ch=(hdr_cmn *)p->access(off_cmn_);
pktsize = ch->size()<<3;
tbf_timer_.resched((pktsize-tokens_)/rate_);
}
}
void TBF_Timer::expire(Event* /*e*/)
{
tbf_->timeout(0);
}
static class TBFClass : public TclClass {
public:
TBFClass() : TclClass ("TBF") {}
TclObject* create(int,const char*const*) {
return (new TBF());
}
}class_tbf;
tclAppInit.cc
/*
* tclAppInit.c --
*
* Provides a default version of the main program and Tcl_AppInit
* procedure for Tcl applications (without Tk).
*
* Copyright (c) 1993 The Regents of the University of California.
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tclAppInit.c 1.17 96/03/26 12:45:29
*/
#include "config.h"
extern void init_misc(void);
extern EmbeddedTcl et_ns_lib;
extern EmbeddedTcl et_ns_ptypes;
/* MSVC requires this global var declaration to be outside of 'extern "C"' */
#ifdef MEMDEBUG_SIMULATIONS
#include "mem-trace.h"
MemTrace *globalMemTrace;
#endif
extern "C" {
/*
* The following variable is a special hack that is needed in order for
* Sun shared libraries to be used for Tcl.
*/
#ifdef TCL_TEST
EXTERN int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
#endif /* TCL_TEST */
/*
*----------------------------------------------------------------------
*
* main --
*
* This is the main program for the application.
*
* Results:
* None: Tcl_Main never returns here, so this procedure never
* returns either.
*
* Side effects:
* Whatever the application does.
*
*----------------------------------------------------------------------
*/
int
main(int argc, char **argv)
{
Tcl_Main(argc, argv, Tcl_AppInit);
return 0; /* Needed only to prevent compiler warning. */
}
/*
*----------------------------------------------------------------------
*
* Tcl_AppInit --
*
* This procedure performs application-specific initialization.
* Most applications, especially those that incorporate additional
* packages, will have their own version of this procedure.
*
* Results:
* Returns a standard Tcl completion code, and leaves an error
* message in interp->result if an error occurs.
*
* Side effects:
* Depends on the startup script.
*
*----------------------------------------------------------------------
*/
int
Tcl_AppInit(Tcl_Interp *interp)
{
#ifdef MEMDEBUG_SIMULATIONS
extern MemTrace *globalMemTrace;
globalMemTrace = new MemTrace;
#endif
if (Tcl_Init(interp) == TCL_ERROR ||
Otcl_Init(interp) == TCL_ERROR)
return TCL_ERROR;
#ifdef HAVE_LIBTCLDBG
extern int Tcldbg_Init(Tcl_Interp *); // hackorama
if (Tcldbg_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
#endif
Tcl_SetVar(interp, "tcl_rcFileName", "~/.ns.tcl", TCL_GLOBAL_ONLY);
Tcl::init(interp, "ns");
et_ns_ptypes.load();
et_ns_lib.load();
init_misc();
#ifdef TCL_TEST
if (Tcltest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init,
(Tcl_PackageInitProc *) NULL);
#endif /* TCL_TEST */
return TCL_OK;
}
#ifndef WIN32
void
abort()
{
Tcl& tcl = Tcl::instance();
tcl.evalc("[Simulator instance] flush-trace");
#ifdef abort
#undef abort
abort();
#else
exit(1);
#endif /*abort*/
/*NOTREACHED*/
}
#endif
}
tcp-abs.cc
/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/* tcp-abs.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 "ip.h"
#include "tcp.h"
#include "tcp-abs.h"
//AbsTcp
AbsTcpAgent::AbsTcpAgent() : Agent(PT_TCP), rtt_(0), current_(NULL),offset_(0), seqno_lb_(-1), connection_size_(0), timer_(this), rescheduled_(0)
{
size_ = 1000;
}
void AbsTcpAgent::timeout()
{
if (rescheduled_ == 0 && current_->transition_[offset_]!= current_->transition_[0]) {
set_timer(2*rtt_);
rescheduled_ = 1;
} else {
rescheduled_ = 0;
seqno_lb_ += current_->batch_size_;
if (current_->drop_[offset_] == NULL) {
printf("Error: This fsm can't handle multi losses per connection\n");
exit(0);
}
current_ = current_->drop_[offset_];
send_batch();
}
}
void AbsTcpAgent::sendmsg(int pktcnt)
{
connection_size_ = pktcnt;
start();
}
void AbsTcpAgent::advanceby(int pktcnt)
{
connection_size_ = pktcnt;
start();
}
void AbsTcpAgent::start()
{
//printf("starting fsm tcp, %d\n", connection_size_);
send_batch();
}
void AbsTcpAgent::send_batch()
{
int seqno = seqno_lb_;
offset_ = 0;
//printf("sending batch, %d\n", current_->batch_size_);
for (int i=0; ibatch_size_ && seqno < connection_size_-1; i++) {
seqno++;
output(seqno);
}
if (seqno == connection_size_-1) {
finish();
}
else if (seqno < connection_size_-1) {
if (current_->drop_[offset_] == NULL) {
printf("Error: current fsm can't handle this tcp connection flow id %d (possibly too long)\n", fid_);
exit(0);
}
//printf("start timer %d\n", current_->transition_[offset_]);
if (current_->transition_[offset_] == 0) {
current_ = current_->drop_[offset_];
send_batch();
} else if (current_->transition_[offset_] == RTT) {
set_timer(rtt_);
} else if (current_->transition_[offset_] == TIMEOUT) {
set_timer(rtt_ * 3);
} else {
printf("Error: weird transition timer\n");
exit(0);
}
} else {
printf("Error: sending more than %d packets\n", connection_size_);
exit(0);
}
}
void AbsTcpAgent::drop(int seqno)
{
//printf("dropped: %d\n", seqno);
if (offset_ != 0) {
printf("Error: Sorry, can't handle multiple drops per batch\n");
exit(0);
}
offset_ = seqno - seqno_lb_;
connection_size_++;
}
void AbsTcpAgent::finish()
{
//printf("finish: sent %d\n", seqno_lb_+1);
cancel_timer();
}
void AbsTcpAgent::output(int seqno)
{
Packet* p = allocpkt();
hdr_tcp *tcph = hdr_tcp::access(p);
tcph->seqno() = seqno;
send(p, 0);
}
void AbsTcpAgent::recv(Packet* pkt, Handler*)
{
Packet::free(pkt);
}
int AbsTcpAgent::command(int argc, const char*const* argv)
{
if (argc == 3 ) {
if (strcmp(argv[1], "rtt") == 0) {
rtt_ = atof(argv[2]);
//printf("rtt %f\n", rtt_);
return (TCL_OK);
}
if (strcmp(argv[1], "advance") == 0) {
advanceby(atoi(argv[2]));
return (TCL_OK);
}
if (strcmp(argv[1], "advanceby") == 0) {
advanceby(atoi(argv[2]));
return (TCL_OK);
}
if(strcmp(argv[1], "print-stats") == 0) {
// xxx: works best if invoked on a new fsm
// (otherwise you don't get the whole thing).
int n = atoi(argv[2]);
if (n < 0 || n >= 17)
return TCL_ERROR;
FSM::print_FSM_stats(current_, n);
return (TCL_OK);
};
} else if (argc == 2) {
if (strcmp(argv[1], "print") == 0) {
// xxx: works best if invoked on a new fsm
// (otherwise you don't get the whole thing).
FSM::print_FSM(current_);
return (TCL_OK);
};
};
return (Agent::command(argc, argv));
}
void AbsTcpTimer::expire(Event*)
{
a_->timeout();
}
//AbsTCP/TahoeAck
static class AbsTcpTahoeAckClass : public TclClass {
public:
AbsTcpTahoeAckClass() : TclClass("Agent/AbsTCP/TahoeAck") {}
TclObject* create(int, const char*const*) {
return (new AbsTcpTahoeAckAgent());
}
} class_abstcptahoeack;
AbsTcpTahoeAckAgent::AbsTcpTahoeAckAgent() : AbsTcpAgent()
{
size_ = 1000;
current_ = TahoeAckFSM::instance().start_state();
DropTargetAgent::instance().insert_tcp(this);
}
//AbsTCP/RenoAck
static class AbsTcpRenoAckClass : public TclClass {
public:
AbsTcpRenoAckClass() : TclClass("Agent/AbsTCP/RenoAck") {}
TclObject* create(int, const char*const*) {
return (new AbsTcpRenoAckAgent());
}
} class_abstcprenoack;
AbsTcpRenoAckAgent::AbsTcpRenoAckAgent() : AbsTcpAgent()
{
size_ = 1000;
current_ = RenoAckFSM::instance().start_state();
DropTargetAgent::instance().insert_tcp(this);
}
//AbsTCP/TahoeDelAck
static class AbsTcpTahoeDelAckClass : public TclClass {
public:
AbsTcpTahoeDelAckClass() : TclClass("Agent/AbsTCP/TahoeDelAck") {}
TclObject* create(int, const char*const*) {
return (new AbsTcpTahoeDelAckAgent());
}
} class_abstcptahoedelack;
AbsTcpTahoeDelAckAgent::AbsTcpTahoeDelAckAgent() : AbsTcpAgent()
{
size_ = 1000;
current_ = TahoeDelAckFSM::instance().start_state();
DropTargetAgent::instance().insert_tcp(this);
}
//AbsTCP/RenoDelAck
static class AbsTcpRenoDelAckClass : public TclClass {
public:
AbsTcpRenoDelAckClass() : TclClass("Agent/AbsTCP/RenoDelAck") {}
TclObject* create(int, const char*const*) {
return (new AbsTcpRenoDelAckAgent());
}
} class_abstcprenodelack;
AbsTcpRenoDelAckAgent::AbsTcpRenoDelAckAgent() : AbsTcpAgent()
{
size_ = 1000;
current_ = RenoDelAckFSM::instance().start_state();
DropTargetAgent::instance().insert_tcp(this);
}
//AbsTcpSink
static class AbsTcpSinkClass : public TclClass {
public:
AbsTcpSinkClass() : TclClass("Agent/AbsTCPSink") {}
TclObject* create(int, const char*const*) {
return (new AbsTcpSink());
}
} class_abstcpsink;
AbsTcpSink::AbsTcpSink() : Agent(PT_ACK)
{
size_ = 40;
}
void AbsTcpSink::recv(Packet* pkt, Handler*)
{
Packet* p = allocpkt();
send(p, 0);
Packet::free(pkt);
}
static class AbsDelAckSinkClass : public TclClass {
public:
AbsDelAckSinkClass() : TclClass("Agent/AbsTCPSink/DelAck") {}
TclObject* create(int, const char*const*) {
return (new AbsDelAckSink());
}
} class_absdelacksink;
AbsDelAckSink::AbsDelAckSink() : AbsTcpSink(), delay_timer_(this)
{
size_ = 40;
interval_ = 0.1;
}
void AbsDelAckSink::recv(Packet* pkt, Handler*)
{
if (delay_timer_.status() != TIMER_PENDING) {
delay_timer_.resched(interval_);
} else {
delay_timer_.cancel();
Packet* p = allocpkt();
send(p, 0);
}
Packet::free(pkt);
}
void AbsDelAckSink::timeout()
{
/*
* The timer expired so we ACK the last packet seen.
* (shouldn't this check for a particular time out#? -kf)
*/
Packet* p = allocpkt();
send(p, 0);
}
void AbsDelayTimer::expire(Event */*e*/) {
a_->timeout();
}
//Special drop target agent
DropTargetAgent* DropTargetAgent::instance_;
static class DropTargetClass : public TclClass {
public:
DropTargetClass() : TclClass("DropTargetAgent") {}
TclObject* create(int, const char*const*) {
return (new DropTargetAgent());
}
} class_droptarget;
DropTargetAgent::DropTargetAgent(): Connector(), dropper_list_(NULL)
{
instance_ = this;
}
void DropTargetAgent::recv(Packet* pkt, Handler*)
{
Dropper* tmp = dropper_list_;
hdr_tcp *tcph = hdr_tcp::access(pkt);
hdr_ip *iph = hdr_ip::access(pkt);
//printf("flow %d dropping seqno %d\n", iph->flowid(),tcph->seqno());
while(tmp != NULL) {
if(tmp->agent_->flowid() == iph->flowid())
tmp->agent_->drop(tcph->seqno());
tmp = tmp->next_;
}
Packet::free(pkt);
}
void DropTargetAgent::insert_tcp(AbsTcpAgent* tcp)
{
Dropper* dppr = new Dropper;
dppr->agent_=tcp;
dppr->next_ = dropper_list_;
dropper_list_ = dppr;
}
tcp-asym-fs.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, U.C.Berkeley
* http://daedalus.cs.berkeley.edu
*/
/*
* tcp-asym-fs: TCP mods for asymmetric networks (tcp-asym) with fast start
* (tcp-fs).
*
* Contributed by Venkat Padmanabhan (padmanab@cs.berkeley.edu),
* Daedalus Research Group, U.C.Berkeley
*/
#include "tcp-asym.h"
#include "tcp-fs.h"
/* TCP-FS with NewReno */
class NewRenoTcpAsymFsAgent : public NewRenoTcpAsymAgent, public NewRenoTcpFsAgent {
public:
NewRenoTcpAsymFsAgent() : NewRenoTcpAsymAgent(), NewRenoTcpFsAgent() {count_bytes_acked_= 1;}
/* helper functions */
virtual void output_helper(Packet* pkt) {NewRenoTcpAsymAgent::output_helper(pkt); NewRenoTcpFsAgent::output_helper(pkt);}
virtual void recv_helper(Packet* pkt) {NewRenoTcpAsymAgent::recv_helper(pkt); NewRenoTcpFsAgent::recv_helper(pkt);}
virtual void send_helper(int maxburst) {NewRenoTcpFsAgent::send_helper(maxburst);}
virtual void send_idle_helper() {NewRenoTcpFsAgent::send_idle_helper();}
virtual void recv_newack_helper(Packet* pkt) {printf("count_bytes_acked_=%d\n", count_bytes_acked_); NewRenoTcpFsAgent::recv_newack_helper(pkt); NewRenoTcpAsymAgent::t_exact_srtt_ = NewRenoTcpFsAgent::t_exact_srtt_;}
virtual void partialnewack_helper(Packet* pkt) {NewRenoTcpFsAgent::partialnewack_helper(pkt);}
virtual void set_rtx_timer() {NewRenoTcpFsAgent::set_rtx_timer();}
virtual void timeout_nonrtx(int tno) {NewRenoTcpFsAgent::timeout_nonrtx(tno);}
virtual void timeout_nonrtx_helper(int tno) {NewRenoTcpFsAgent::timeout_nonrtx_helper(tno);}
};
static class NewRenoTcpAsymFsClass : public TclClass {
public:
NewRenoTcpAsymFsClass() : TclClass("Agent/TCP/Newreno/Asym/FS") {}
TclObject* create(int, const char*const*) {
return (new NewRenoTcpAsymFsAgent());
}
} class_newrenotcpasymfs;
tcp-asym-sink.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, U.C.Berkeley
* http://daedalus.cs.berkeley.edu
*
* @(#) $Header:
*/
/*
* tcp-asym includes modifications to several flavors of TCP to enhance
* performance over asymmetric networks, where the ack channel is
* constrained. Types of asymmetry we have studied and used these mods
* include bandwidth asymmetry and latency asymmetry (where variable
* latencies cause problems to TCP, e.g., in packet radio networks.
* The receiver-side code in this file is derived from the regular
* TCP sink code. The main additional functionality is that the sink responds
* to ECN by performing ack congestion control, i.e. it multiplicatively backs
* off the frequency with which it sends acks (up to a limit). For each
* subsequent round-trip period during which it does not receive an ECN,
* it gradually increases the frequency of acks (up to a maximum of 1
* per data packet).
*
* For questions/comments, please contact:
* Venkata N. Padmanabhan (padmanab@cs.berkeley.edu)
* http://www.cs.berkeley.edu/~padmanab
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include "template.h"
#include "flags.h"
#include "tcp-sink.h"
#include "tcp-asym.h"
class TcpAsymSink : public DelAckSink {
public:
TcpAsymSink(Acker*);
virtual void recv(Packet* pkt, Handler* h);
virtual void timeout(int tno);
protected:
virtual void add_to_ack(Packet* pkt);
int delackcount_; /* the number of consecutive packets that have
not been acked yet */
int maxdelack_; /* the maximum extent to which acks can be
delayed */
int delackfactor_; /* the dynamically varying limit on the extent
to which acks can be delayed */
int delacklim_; /* limit on the extent of del ack based on the
sender's window */
double ts_ecn_; /* the time when an ECN was received last */
double ts_decrease_; /* the time when delackfactor_ was decreased last */
double highest_ts_echo_;/* the highest timestamp echoed by the peer */
};
static class TcpAsymSinkClass : public TclClass {
public:
TcpAsymSinkClass() : TclClass("Agent/TCPSink/Asym") {}
TclObject* create(int, const char*const*) {
return (new TcpAsymSink(new Acker));
}
} class_tcpasymsink;
TcpAsymSink::TcpAsymSink(Acker* acker) : DelAckSink(acker), delackcount_(0),
delackfactor_(1), delacklim_(0), ts_ecn_(0), ts_decrease_(0)
{
bind("maxdelack_", &maxdelack_);
}
/* Add fields to the ack. Not needed? */
void TcpAsymSink::add_to_ack(Packet* pkt)
{
hdr_tcpasym *tha = hdr_tcpasym::access(pkt);
tha->ackcount() = delackcount_;
}
void TcpAsymSink::recv(Packet* pkt, Handler*)
{
int olddelackfactor = delackfactor_;
int olddelacklim = delacklim_;
int max_sender_can_send = 0;
hdr_flags *fh = hdr_flags::access(pkt);
hdr_tcp *th = hdr_tcp::access(pkt);
hdr_tcpasym *tha = hdr_tcpasym::access(pkt);
double now = Scheduler::instance().clock();
int numBytes = hdr_cmn::access(pkt)->size();
acker_->update_ts(th->seqno(),th->ts());
acker_->update(th->seqno(), numBytes);
#if 0 // johnh
int numToDeliver;
/* XXX if the #if 0 is removed, delete the call to acker_->update() above */
numToDeliver = acker_->update(th->seqno(), numBytes);
if (numToDeliver)
recvBytes(numToDeliver);
#endif /* 0 */
/* determine the highest timestamp the sender has echoed */
highest_ts_echo_ = max(highest_ts_echo_, th->ts_echo());
/*
* if we receive an ECN and haven't received one in the past
* round-trip, double delackfactor_ (and consequently halve
* the frequency of acks) subject to a maximum
*/
if (fh->ecnecho() && highest_ts_echo_ >= ts_ecn_) {
delackfactor_ = min(2*delackfactor_, maxdelack_);
ts_ecn_ = now;
}
/*
* else if we haven't received an ECN in the past round trip and
* haven't (linearly) decreased delackfactor_ in the past round
* trip, we decrease delackfactor_ by 1 (and consequently increase
* the frequency of acks) subject to a minimum
*/
else if (highest_ts_echo_ >= ts_ecn_ && highest_ts_echo_ >= ts_decrease_) {
delackfactor_ = max(delackfactor_ - 1, 1);
ts_decrease_ = now;
}
/*
* if this is the next packet in sequence, we can consider delaying the ack.
* Set delacklim_ based on how much data the sender can send if we don't
* send back any more acks. The idea is to avoid stalling the sender because
* of a lack of acks.
*/
if (th->seqno() == acker_->Seqno()) {
max_sender_can_send = (int) min(tha->win()+acker_->Seqno()-tha->highest_ack(), tha->max_left_to_send());
/* XXXX we use a safety factor 2 */
delacklim_ = min(maxdelack_, max_sender_can_send/2);
}
else
delacklim_ = 0;
if (delackfactor_ < delacklim_)
delacklim_ = delackfactor_;
/*
* Log values of variables of interest. Since this is the only place
* where this is done, we decided against using a more general method
* as used for logging TCP sender state variables.
*/
if (channel_ && (olddelackfactor != delackfactor_ || olddelacklim != delacklim_)) {
char wrk[500];
int n;
/* we print src and dst in reverse order to conform to sender side */
sprintf(wrk, "time: %-6.3f saddr: %-2d sport: %-2d daddr:"
" %-2d dport: %-2d dafactor: %2d dalim: %2d max_scs:"
" %4d win: %4d\n", now, addr(), port(),
daddr(), dport(), delackfactor_,
delacklim_,max_sender_can_send, tha->win());
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
(void)Tcl_Write(channel_, wrk, n+1);
wrk[n] = 0;
}
delackcount_++;
/* check if we have waited long enough that we should send an ack */
if (delackcount_ < delacklim_) { /* it is not yet time to send an ack */
/* if the delayed ack timer is not set, set it now */
if (!(delay_timer_.status() == TIMER_PENDING)) {
save_ = pkt;
delay_timer_.resched(interval_);
}
else {
hdr_tcp *sth = hdr_tcp::access(save_);
/* save the pkt with the more recent timestamp */
if (th->ts() > sth->ts()) {
Packet::free(save_);
save_ = pkt;
}
}
return;
}
else { /* send back an ack now */
if (delay_timer_.status() == TIMER_PENDING) {
delay_timer_.cancel();
Packet::free(save_);
save_ = 0;
}
hdr_flags* hf = hdr_flags::access(pkt);
hf->ect() = 1;
ack(pkt);
delackcount_ = 0;
Packet::free(pkt);
}
}
void TcpAsymSink::timeout(int /*tno*/)
{
/*
* The timer expired so we ACK the last packet seen.
*/
Packet* pkt = save_;
delackcount_ = 0;
ack(pkt);
save_ = 0;
Packet::free(pkt);
}
tcp-asym.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, U.C.Berkeley
* http://daedalus.cs.berkeley.edu
*
* @(#) $Header:
*/
/*
* tcp-asym includes modifications to several flavors of TCP to enhance
* performance over asymmetric networks, where the ack channel is
* constrained. Types of asymmetry we have studied and used these mods
* include bandwidth asymmetry and latency asymmetry (where variable
* latencies cause problems to TCP, e.g., in packet radio networks.
* The sender-side modifications in this file are structured as helper
* functions that are invoked from various points in the TCP code. The main
* additional functionality is (a) the sender increases its congestion window
* in proportion to the amount of data acked rather than the number of acks
* received, (b) it breaks up potentially large bursts into smaller ones
* when acks are few and far between by rate-based pacing, and
* (c) it copies the ecn_to_echo_ bit from acks into subsequent data packets,
* using which the sink can perform ack congestion control (tcp-asym-sink.cc).
* The tcp-asym source is usually used in conjunction with a tcp-asym sink, or
* with a router/end-host implementing ack filtering (semantic-packetqueue.cc).
*
* For questions/comments, please contact:
* Venkata N. Padmanabhan (padmanab@cs.berkeley.edu)
* http://www.cs.berkeley.edu/~padmanab
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (UCB)";
#endif
#include "tcp-asym.h"
int hdr_tcpasym::offset_;
static class TCPAHeaderClass : public PacketHeaderClass {
public:
TCPAHeaderClass() : PacketHeaderClass("PacketHeader/TCPA",
sizeof(hdr_tcpasym)) {
bind_offset(&hdr_tcpasym::offset_);
}
} class_tcpahdr;
static class TcpAsymClass : public TclClass {
public:
TcpAsymClass() : TclClass("Agent/TCP/Asym") {}
TclObject* create(int, const char*const*) {
return (new TcpAsymAgent());
}
} class_tcpasym;
TcpAsymAgent::TcpAsymAgent() : TcpAgent(), ecn_to_echo_(0), t_exact_srtt_(0)
{
/* bind("exact_srtt_", &t_exact_srtt_);*/
bind("g_", &g_);
/* bind("avg_win_", &avg_win_);*/
/* bind("damp_", &damp_);*/
}
static class TcpRenoAsymClass : public TclClass {
public:
TcpRenoAsymClass() : TclClass("Agent/TCP/Reno/Asym") {}
TclObject* create(int, const char*const*) {
return (new TcpRenoAsymAgent());
}
} class_tcprenoasym;
static class NewRenoTcpAsymClass : public TclClass {
public:
NewRenoTcpAsymClass() : TclClass("Agent/TCP/Newreno/Asym") {}
TclObject* create(int, const char*const*) {
return (new NewRenoTcpAsymAgent());
}
} class_newrenotcpasym;
/* The helper functions */
/* fill in the TCP asym header before packet is sent out */
void TcpAsymAgent::output_helper(Packet* p)
{
hdr_tcpasym *tcpha = hdr_tcpasym::access(p);
hdr_flags *flagsh = hdr_flags::access(p);
tcpha->win() = min(highest_ack_+window(), curseq_) - t_seqno_;
tcpha->highest_ack() = highest_ack_;
tcpha->max_left_to_send() = curseq_ - highest_ack_; /* XXXX not needed? */
flagsh->ecnecho() = ecn_to_echo_;
ecn_to_echo_ = 0;
}
/* schedule the next burst of data (of size at most maxburst) */
void TcpAsymAgent::send_helper(int maxburst)
{
/*
* If there is still data to be sent and there is space in the
* window, set a timer to schedule the next burst. Note that
* we wouldn't get here if TCP_TIMER_BURSTSEND were pending,
* so we do not need an explicit check here.
*/
if (t_seqno_ <= highest_ack_ + window() && t_seqno_ < curseq_) {
burstsnd_timer_.resched(t_exact_srtt_*maxburst/window());
}
}
/* check if the received ack has an ECN that needs to be echoed back to the sink */
void TcpAsymAgent::recv_helper(Packet *pkt)
{
if (hdr_flags::access(pkt)->ce())
ecn_to_echo_ = 1;
}
/* open cwnd in proportion to the amount of data acked */
void TcpAsymAgent::recv_newack_helper(Packet *pkt)
{
int i;
hdr_tcp *tcph = hdr_tcp::access(pkt);
int ackcount = tcph->seqno() - last_ack_;
double tao = Scheduler::instance().clock() - tcph->ts_echo();
newack(pkt);
/* update our fine-grained estimate of the smoothed RTT */
if (t_exact_srtt_ != 0)
t_exact_srtt_ = g_*tao + (1-g_)*t_exact_srtt_;
else
t_exact_srtt_ = tao;
/* avg_win_ = g_*window() + (1-g_)*avg_win_;*/
/* grow cwnd */
for (i=0; i= curseq_-1) && !closed_) {
closed_ = 1;
finish();
}
}
/* Print out if tcp-asym-specific variables have been modified */
void TcpAsymAgent::traceVar(TracedVar* v) {
Scheduler& s = Scheduler::instance();
char wrk[500];
double curtime = &s ? s.clock() : 0;
if (!strcmp(v->name(), "exact_srtt_"))
sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f",
curtime, addr(), port(), daddr(), dport(),
v->name(), double(*((TracedDouble*) v)));
else if (!strcmp(v->name(), "avg_win_"))
sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f",
curtime, addr(), port(), daddr(), dport(),
v->name(), double(*((TracedDouble*) v)));
else {
TcpAgent::traceVar(v);
return;
}
int n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
if (channel_)
(void)Tcl_Write(channel_, wrk, n+1);
wrk[n] = 0;
return;
}
/* Print out all the traced variables whenever any one is changed */
void
TcpAsymAgent::traceAll() {
double curtime;
Scheduler& s = Scheduler::instance();
char wrk[500];
int n;
TcpAgent::traceAll();
curtime = &s ? s.clock() : 0;
sprintf(wrk, "time: %-8.5f saddr: %-2d sport: %-2d daddr: %-2d dport:"
" %-2d exact_srtt %d", curtime, addr(), port(),
daddr(), dport(), (int(t_exact_srtt_)));
n = strlen(wrk);
wrk[n] = '\n';
wrk[n+1] = 0;
if (channel_)
(void)Tcl_Write(channel_, wrk, n+1);
wrk[n] = 0;
return;
}
tcp-fack.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 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 California, Lawrence Berkeley Laboratory,
* Berkeley, CA. 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header$ (PSC)";
#endif
#include
#include
#include
#include "ip.h"
#include "tcp.h"
#include "flags.h"
#include "scoreboard.h"
#include "random.h"
#include "tcp-fack.h"
#include "template.h"
static class FackTcpClass : public TclClass {
public:
FackTcpClass() : TclClass("Agent/TCP/Fack") {}
TclObject* create(int, const char*const*) {
return (new FackTcpAgent());
}
} class_fack;
FackTcpAgent::FackTcpAgent() : timeout_(FALSE), wintrim_(0),
wintrimmult_(.5), rampdown_(0), fack_(-1), retran_data_(0),
ss_div4_(0) // What about fastrecov_ and scb_
{
bind_bool("ss-div4_", &ss_div4_);
bind_bool("rampdown_", &rampdown_);
}
int FackTcpAgent::window()
{
int win;
win = int((cwnd_ < wnd_ ? (double) cwnd_ : (double) wnd_) + wintrim_);
return (win);
}
void FackTcpAgent::reset ()
{
scb_.ClearScoreBoard();
TcpAgent::reset ();
}
/*
* Process a dupack.
*/
void FackTcpAgent::oldack(Packet* pkt)
{
hdr_tcp *tcph = (hdr_tcp*)pkt->access(off_tcp_);
last_ack_ = tcph->seqno();
highest_ack_ = last_ack_;
fack_ = max(fack_,highest_ack_);
/*
* There are conditions under which certain versions of TCP (e.g., tcp-fs)
* retract maxseq_. The following line of code helps in those cases. For
* versions of TCP, it is a NOP.
*/
maxseq_ = max(maxseq_, highest_ack_);
if (t_seqno_ < last_ack_ + 1)
t_seqno_ = last_ack_ + 1;
newtimer(pkt);
if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
rtt_active_ = 0;
t_backoff_ = 1;
}
/* with timestamp option */
double tao = Scheduler::instance().clock() - tcph->ts_echo();
rtt_update(tao);
/* update average window */
awnd_ *= 1.0 - wnd_th_;
awnd_ += wnd_th_ * cwnd_;
/* if the connection is done, call finish() */
if ((highest_ack_ >= curseq_-1) && !closed_) {
closed_ = 1;
finish();
}
}
int FackTcpAgent::maxsack(Packet *pkt)
{
hdr_tcp *tcph = (hdr_tcp*)pkt->access(off_tcp_);
int maxsack=-1,