# 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 <brezak@apollo.hp.com>. * January 31, 1996 * * @(#) $Header$ (LBL) */ #ifdef WIN32 #include <assert.h> #include <io.h> #include <process.h> #include <fcntl.h> #include <windows.h> #include <malloc.h> #include <string.h> #include <stdio.h> #include <time.h> #include <winsock.h> #include <tcl.h> #include "config.h" #include <locale.h> /* 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 } }

/* -*- 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 <stdlib.h> #include <math.h> 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;

/* -*- 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 <stdlib.h> #include <math.h> 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

/* -*- 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 <math.h> #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); }

/* -*- 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 <stdlib.h> 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 <stdio.h> #include <stdlib.h> #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) { /* * <address> add-hier <level> <mask> <shift> */ 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 <assert.h> #include <stdlib.h> #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 <stdlib.h> #include <assert.h> #include "config.h" #include <tclcl.h> 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 <antenna.h> 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 <errno.h> #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 <address.h> // #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 <stdlib.h> #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 <float.h> #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<IntTcpAgent> (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<Segment> 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 <iostream.h> #include <assert.h> #include <stdlib.h> #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 <tcl.h> } #include <stdlib.h> #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 <stdlib.h> #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) <number> // (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 <x,G> entry: give 0 as src, but can be anything set_hash(ht_star_, 0, dst, slot, iface); } else { //install a <S,G> 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 <tcl.h> } #include "config.h" #include "packet.h" #include "ip.h" #include "classifier.h" #include "route.h" #include "object.h" #include "address.h" #include <iostream.h> 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 <stdlib.h> #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 <packet.h> #include <ip.h> #include <tcp.h> #include <rtp.h> #include <arp.h> #include <dsr/hdr_sr.h> // DSR #include <mac.h> #include <mac-802_11.h> #include <address.h> #include <tora/tora_packet.h> //TORA #include <imep/imep_spec.h> // IMEP #include <aodv/aodv_packet.h> //AODV #include <cmu-trace.h> #include <mobilenode.h> //#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 <assert.h> #include <stdlib.h> // due to definition of NULL #include <stdio.h> // 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 <sys/time.h> #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 <ctype.h> #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <dem.h> 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 <bajaj@parc.xerox.com>, Mar 1997. */ #ifndef lint static const char rcsid[] = "@(#)$Header$(Xerox)"; #endif #include "config.h" // for string.h #include <stdlib.h> #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 <kannan@isi.edu> // 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 <kkumar@isi.edu> extern "C" { #include <stdarg.h> #include <float.h> }; #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 <stdio.h> #include <ctype.h> #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 <math.h> #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 <stdlib.h> #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 <stdlib.h> #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 <stdlib.h> #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 <assert.h> #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 <object.h> #include <packet.h> #include <ip.h> #include <god.h> 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; */

# 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); }

/* -*- 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 <stdlib.h> #include <math.h> 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

# 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 <stdlib.h> #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 <stdlib.h> #include <math.h> #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

# 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 <math.h> #include <stdlib.h> #include <connector.h> #include <delay.h> #include <packet.h> #include <random.h> //#include <debug.h> #include <arp.h> #include <topography.h> #include <trace.h> #include <address.h> #include <ll.h> #include <mac.h> #include <propagation.h> #include <mobilenode.h> // 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

# 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 <math.h> #include <stdlib.h> #include <random.h> //#include <debug.h> #include <modulation.h> /* ====================================================================== 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; }

/* -*- 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 <stdlib.h> 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_; };

# 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 <stdlib.h> /*#include <unistd.h>*/ #include "nilist.h" template<class T> T Slist<T>::get() { Tlink<T>* lnk = (Tlink<T>*) slist_base::get(); T i = lnk->info; delete lnk; return i; } void

# 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 <phy.h> #include <wired-phy.h> #include <address.h> #include <node.h> #include <random.h> 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

# 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 <stdio.h> #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 <stdlib.h> #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 <stdarg.h> #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 <omni-antenna.h> 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*

/* -*- 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 <stdlib.h> 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); }

# 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 <stdio.h> 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 <sys/time.h> #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 <stdio.h> #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 <math.h> #include <sys/types.h> #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

# 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

# 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 <stdlib.h> #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 <stdlib.h> #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 <assert.h> #include <rtqueue.h> #include <cmu-trace.h> #define CURRENT_TIME Scheduler::instance().clock() #define DEBUG /* ====================================================================== Packet Queue used by TORA and AODV. ===================================================================== */

# 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 <rttable.h> /* ===================================================================== The Routing Table ===================================================================== */

# 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)); }

# 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

# 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 <math.h> 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_; }

/* -*- 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

# 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

# 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 <stdio.h> #include <stdlib.h> #include <math.h> 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 <address.h> 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 <stdio.h> #include <stdlib.h> #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
/* -*- 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 <stdlib.h> #include <limits.h> #include "config.h" #include "scheduler.h" #include "packet.h" #ifdef MEMDEBUG_SIMULATIONS #include "mem-trace.h" #endif #include <iostream.h> 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