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 } }

acto-adc.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif //Acceptance region Tangent at Origin Admission Control #include "adc.h" #include <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;

actp-adc.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif //Acceptance region Tangent at Peak Admission Control #include "adc.h" #include <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
ACTP_ADC::admit_flow(int cl,double r,int b) { //get peak rate this class of flow double p=peak_rate(cl,r,b); if (backoff_) { if (rejected_) return 0; } //fprintf (stderr,"%f %f %f\n",sump_*(1-exp(-p*s_)),exp(-p*s_)*est_[cl]->avload(),est_[cl]->avload()); if (sump_*(1-exp(-p*s_))+exp(-p*s_)*est_[cl]->avload() <= bandwidth_) { sump_+= p; if (dobump_) { est_[cl]->change_avload(p); } return 1; } else { rejected_=1; return 0; } } void ACTP_ADC::rej_action(int cl,double r,int b) { double p=peak_rate(cl,r,b); sump_ -= p; } void ACTP_ADC::teardown_action(int cl,double r,int b) { rejected_=0; double p=peak_rate(cl,r,b); sump_ -= p; } static class ACTP_ADCClass : public TclClass { public: ACTP_ADCClass() : TclClass("ADC/ACTP") {} TclObject* create(int,const char*const*) { return (new ACTP_ADC()); } }class_actp_adc;

adaptive-receiver.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "config.h" #include "agent.h" #include "tclcl.h" #include "packet.h" #include "ip.h" #include "rtp.h" #include "adaptive-receiver.h" #include <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); }

adc.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "adc.h" #include <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; */
GridHandler::GridHandler() { } void GridHandler::handle(Event *e) { MoveEvent *me = (MoveEvent *)e; MobileNode **pptr; MobileNode * token_ = me->token_; if ((pptr = me->leave_)) { while (*pptr) { if ((*pptr)->address_ == token_->address_) break; pptr = &((*pptr)->next_); } if (!(*pptr)) abort(); else { *pptr = token_->next_; token_->next_ = 0; } } if ((pptr = me->enter_)) { if (token_->next_) abort(); // can't be in more than one grid token_->next_ = *pptr; *pptr = token_; } delete me; // dump info in the gridkeeper for debug only // dump(); } GridKeeper* GridKeeper::instance_; static class GridKeeperClass : public TclClass { public: GridKeeperClass() : TclClass("GridKeeper") {} TclObject* create(int, const char*const*) { return (new GridKeeper); } } class_grid_keeper; GridKeeper::GridKeeper() : size_(0),grid_(NULL), dim_x_(0), dim_y_(0) { gh_ = new GridHandler(); } GridKeeper::~GridKeeper() { int i; for (i = 0; i <= dim_x_; i++) { delete [] grid_[i]; } delete [] grid_; } int GridKeeper::command(int argc, const char*const* argv) { int i, grid_x, grid_y; Tcl& tcl = Tcl::instance(); MobileNode *mn; if (argc == 2) { if (strcmp(argv[1], "dump") == 0) { dump(); return (TCL_OK); } } if (argc == 3) { if (strcmp(argv[1], "addnode") == 0) { mn = (MobileNode *)TclObject::lookup(argv[2]); grid_x = aligngrid((int)mn->X, dim_x_); grid_y = aligngrid((int)mn->Y, dim_y_); mn->next_ = grid_[grid_x][grid_y]; grid_[grid_x][grid_y] = mn; size_++; return (TCL_OK); } } if (argc == 4 && strcmp(argv[1], "dimension") == 0) { if (instance_ == 0) instance_ = this; dim_x_ = strtol(argv[2], (char**)0, 0); dim_y_ = strtol(argv[3], (char**)0, 0); if (dim_x_ <= 0 || dim_y_ <= 0) { tcl.result("illegal grid dimension"); return (TCL_ERROR); } grid_ = new MobileNode **[dim_x_]; for (i = 0; i < dim_x_; i++) { grid_[i] = new MobileNode *[dim_y_]; bzero((void *)grid_[i], sizeof(MobileNode *)*dim_y_); } return (TCL_OK); } return (TclObject::command(argc, argv)); } void GridKeeper::new_moves(MobileNode *mn) { double x = mn->X, y = mn->Y; double ss = mn->speed; double vx = (mn->dX)*ss, vy = (mn->dY)*ss; // double interval = mn->position_update_interval; double endx, endy, pother, tm; int i, j, endi, gother, grid_x, grid_y; MoveEvent *me; Scheduler& s = Scheduler::instance(); endx = mn->destX; endy = mn->destY; if (vx > 0) { endi = min(dim_x_-1, (int)endx); for (i = (int)x+1; i <= endi; i++) { tm = (i-x)/vx; pother = vy*tm + y; j = (int)pother; me = new MoveEvent; if (j == pother && j != 0 && j != dim_y_) { if (vy > 0) gother = j - 1; else if (vy < 0) gother = j + 1; else gother = j; } else { gother = j; } me->leave_ = &(grid_[aligngrid(i-1, dim_x_)][aligngrid(gother, dim_y_)]); me->grid_x_ = grid_x = aligngrid(i, dim_x_); me->grid_y_ = grid_y = aligngrid(j, dim_y_); me->enter_ = &(grid_[grid_x][grid_y]); me->token_ = mn; s.schedule(gh_, me, tm); } } else if (vx < 0) { endi = (int)endx; for (i = (int)x; i > endi; i--) { if (i == dim_x_) continue; tm = (i-x)/vx; pother = vy*tm + y; j = (int)pother; me = new MoveEvent; if (j == pother && j != 0 && j != dim_y_) { if (vy > 0) gother = j - 1; else if (vy < 0) gother = j + 1; else gother = j; } else { gother = j; } me->leave_ = &grid_[aligngrid(i, dim_x_)][aligngrid(gother, dim_y_)]; me->grid_x_ = grid_x = aligngrid(i-1, dim_x_); me->grid_y_ = grid_y = aligngrid(j, dim_y_); me->enter_ = &grid_[grid_x][grid_y]; me->token_ = mn; s.schedule(gh_, me, tm); } } if (vy > 0) { endi = min(dim_y_-1, (int)endy); for (j = (int)y+1; j <= endi; j++) { tm = (j-y)/vy; pother = vx*tm + x; i = (int)pother; me = new MoveEvent; if (i == pother && i != 0 && i != dim_x_ && vx != 0) continue; me->leave_ = &grid_[aligngrid(i, dim_x_)][aligngrid(j-1, dim_y_)]; me->grid_x_ = grid_x = aligngrid(i, dim_x_); me->grid_y_ = grid_y = aligngrid(j, dim_y_); me->enter_ = &grid_[grid_x][grid_y]; me->token_ = mn; s.schedule(gh_, me, tm); } } else if (vy < 0) { endi = (int)endy; for (j = (int)y; j > endi; j--) { if (j == dim_y_) continue; tm = (j-y)/vy; pother = vx*tm + x; i = (int)pother; me = new MoveEvent; if (i == pother && i != 0 && i != dim_x_ && vx != 0) continue; me->leave_ = &grid_[aligngrid(i, dim_x_)][aligngrid(j, dim_y_)]; me->grid_x_ = grid_x = aligngrid(i, dim_x_); me->grid_y_ = grid_y = aligngrid(j-1, dim_y_); me->enter_ = &grid_[grid_x][grid_y]; me->token_ = mn; s.schedule(gh_, me, tm); } } } int GridKeeper::get_neighbors(MobileNode* mn, MobileNode **output) { int grid_x, grid_y, index = 0, i, j, ulx, uly, lly, adj; MobileNode *pgd; double mnx, mny, mnr, sqmnr; mn->update_position(); mnx = mn->X; mny = mn->Y; grid_x = aligngrid((int)mn->X, dim_x_); grid_y = aligngrid((int)mn->Y, dim_y_); sqmnr = (mnr = mn->radius_)*mnr; adj = (int)ceil(mnr); ulx = min(dim_x_-1, grid_x + adj); uly = min(dim_y_-1, grid_y + adj); lly = max(0, grid_y - adj); for (i = max(0, grid_x - adj); i <= ulx; i++) { for (j = lly; j <= uly; j++) { for (pgd = grid_[i][j]; pgd != 0; pgd = pgd->next_) { if (mn->address_ == pgd->address_) continue; pgd->update_position(); if (d2(pgd->X, mnx, pgd->Y, mny) < sqmnr) output[index++] = pgd; } } } return index; } void GridKeeper::dump() { int i,j; MobileNode *pgd; for (i = 0; i< dim_x_; i++) { for (j = 0; j < dim_y_; j++) { if (grid_[i][j] == 0) continue; printf("grid[%d][%d]: ",i,j); for (pgd = grid_[i][j]; pgd != 0; pgd = pgd->next_) { printf("%d ",pgd->address_); } printf("\n"); } } printf("-------------------------------\n"); }

hackloss.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "connector.h" #include "packet.h" #include "queue.h" class HackLossyLink : public Connector { public: HackLossyLink() : down_(0), src_(0), dst_(0), fid_(0), ctr_(0), nth_(0){ bind("off_ip_", &off_ip_); } protected: int command(int argc, const char*const* argv); void recv(Packet* p, Handler* h); NsObject* down_; int src_, dst_, fid_; int ctr_, nth_; int off_ip_; }; static class HackLossyLinkClass : public TclClass { public: HackLossyLinkClass() : TclClass("HackLossyLink") {} TclObject* create(int, const char*const*) { return (new HackLossyLink); } } class_dynamic_link; int
HackLossyLink::command(int argc, const char*const* argv) { if (strcmp(argv[1], "down-target") == 0) { NsObject* p = (NsObject*)TclObject::lookup(argv[2]); if (p == 0) { Tcl::instance().resultf("no object %s", argv[2]); return TCL_ERROR; } down_ = p; return TCL_OK; } if (strcmp(argv[1], "show-params") == 0) { Tcl::instance().resultf("src_ = %d, dst_ = %d, fid_ = %d, nth_ = %d", src_, dst_, fid_, nth_); return TCL_OK; } if (strcmp(argv[1], "set-params") == 0) { src_ = atoi(argv[2]); dst_ = atoi(argv[3]); fid_ = atoi(argv[4]); return TCL_OK; } if (strcmp(argv[1], "nth") == 0) { nth_ = atoi(argv[2]); return TCL_OK; } return Connector::command(argc, argv); } void HackLossyLink::recv(Packet* p, Handler* h) { hdr_ip* iph = (hdr_ip*) p->access(off_ip_); if (nth_ && (iph->flowid() == fid_) && (iph->saddr() == src_) && (iph->daddr() == dst_) && ((++ctr_ % nth_) == 0)) down_->recv(p); // XXX Why no handler? else target_->recv(p, h); }

hb-adc.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif //Hoeffding Bounds Admission Control #include "adc.h" #include <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
HB_ADC::admit_flow(int cl,double r,int b) { //get peak rate this class of flow double p=peak_rate(cl,r,b); if (backoff_) { if (rejected_) return 0; } //printf("Peak rate: %f Avload: %f Rem %f %f %f\n",p,est_[cl]->avload(),sqrt(log(1/epsilon_)*sump2_/2),log(1/epsilon_),sump2_); if ((p+est_[cl]->avload()+sqrt(log(1/epsilon_)*sump2_/2)) <= bandwidth_) { sump2_+= p*p; est_[cl]->change_avload(p); return 1; } else { rejected_=1; return 0; } } void HB_ADC::rej_action(int cl,double r,int b) { double p=peak_rate(cl,r,b); sump2_ -= p*p; } void HB_ADC::teardown_action(int cl,double r,int b) { rejected_=0; double p=peak_rate(cl,r,b); sump2_ -= p*p; } static class HB_ADCClass : public TclClass { public: HB_ADCClass() : TclClass("ADC/HB") {} TclObject* create(int,const char*const*) { return (new HB_ADC()); } }class_hb_adc;

integrator.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1996 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include <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
IvsSource::reset() { } /* * main reception path - should only see acks, otherwise the * network connections are misconfigured */ void IvsSource::recv(Packet* pkt, Handler*) { char wrk[128];/*XXX*/ Tcl& tcl = Tcl::instance(); hdr_msg *q = (hdr_msg*)pkt->access(off_msg_); sprintf(wrk, "%s handle {%s}", name(), q->msg()); tcl.eval(wrk); Packet::free(pkt); } #ifdef notdef void IvsSource::probe_timeout() { rndStart_ = now; if (keyShift_ == 15) { if (key_ == 0) { if (solicitedResponses_ == 0) estReceivers_ = 0; /* * Got through a round without being LOADED. * increase send rate. */ if (state_ == ST_U) increase(); /* Reset keys et al */ S_ = 1; state_ = ST_U; /*XXX*/ setRttSolicit(mcstate); solicitedResponses_ = 0; keyShift_ = startShift_; /*XXX do all this in tcl? */ setkey(); } else { mcstate->hdr.key = 0; } } else { if (probeTimeout_ > 0) ++keyShift_; } sched(pktTime + 2 * maxrtt_, IVS_TIMER_PROBE); } #endif void IvsSource::sendpkt() { Packet* pkt = allocpkt(); hdr_ivs *p = (hdr_ivs*)pkt->access(off_ivs_); /*fill in ivs fields */ p->ts() = Scheduler::instance().clock(); p->S() = S_; p->R() = R_; p->state() = state_; p->rshft() = rttShift_; p->kshft() = keyShift_; p->key() = key_; p->maxrtt() = maxrtt_; target_->recv(pkt, (Handler *)0); } IvsReceiver::IvsReceiver() : Agent(PT_MESSAGE), state_(ST_U), nextSeq_(0), timeMean_(0.), timeVar_(0.),/*XXX*/ ipg_(0.), head_(0), tail_(0), lastPktTime_(0.), ignoreR_(0), lastTime_(0.), key_(0) { bind("ignoreR_", &ignoreR_); bind("key_", &key_); bind("state_", &state_); bind("packetSize_", &size_); bind("off_ivs_", &off_ivs_); bind("off_msg_", &off_msg_); } inline void IvsReceiver::update_ipg(double v) { /* Update the estimated interpacket gap */ ipg_ = (15 * ipg_ + v) / 16; } /* * timestamp comes in milliseconds since start of connection according to * remote clock * now is milliseconds since start of connection * rtt in milliseconds * This congestion meter is not terribly good at figuring out when the net is * loaded, since the loss of a packet over a rtt is a transitory event * Eventually we ought to have a memory thing, that records state once a * maxrtt, with thresholds to decide current state */ int IvsReceiver::lossMeter(double timeDiff, u_int32_t seq, double maxrtt) { /* * The congestion signal is calculated here by measuring the loss in a * given period of packets - if the threshold for lost packets is * passed then signal Congested. If there are no lost packets, * then we are at UNLOADED, else LOADED */ /* if sequence number is next, increase expected number */ double now = Scheduler::instance().clock(); if (nextSeq_ == 0) nextSeq_ = seq + 1; else if (seq == nextSeq_) nextSeq_++; else if (seq > nextSeq_) { #ifdef notdef if (trace_ != 0) { sprintf(trace_->buffer(), "d %g %d", lastPktTime_, seq - nextSeq_); trace_->dump(); } #endif /* This is definitely a hole */ Mc_Hole* hole = new Mc_Hole; hole->time = now; hole->start = nextSeq_; hole->end = seq - 1; hole->next = 0; /* Now add it to the list */ if (head_ == NULL) { head_ = hole; tail_ = hole; } else { tail_->next = hole; tail_ = hole; } nextSeq_ = seq + 1; } else { /* XXX can't happen in current ns simulations */ fprintf(stderr, "ns: ivs rcvr: seq number went backward\n"); abort(); } /* update the calculation of the variance in the rtt */ /* get the time averaged mean of the difference */ if (timeMean_ == 0) timeMean_ = timeDiff; else timeMean_ = (7 * timeMean_ + timeDiff) / 8; timeDiff -= timeMean_; if (timeDiff < 0) timeDiff = -timeDiff; timeVar_ = (7 * timeVar_ + timeDiff) / 8; int lostPkts = 0; /* * Check down the list of holes, discarding those that before * now-rttvar-rtt, counting those that fall within * now-rttvar to now-rttvar-rtt */ if (head_ == 0) return (ST_U); Mc_Hole *cur = head_, *prev = NULL; double validEnd = now - 2 * timeVar_; double validStart = validEnd - maxrtt; /* for each hole, if it is older than required, dump it */ /* If it is valid, add the size to the loss count */ /* Go to the next hole */ while (cur != NULL) { if (cur->time < validStart) { if (prev == NULL) head_ = cur->next; else prev->next = cur->next; delete cur; if (prev == NULL) cur = head_; else cur = prev->next; } else { if (cur->time < validEnd) lostPkts += cur->end - cur->start + 1; prev = cur; cur = cur->next; } } /* * Update the moving average calculation of the number of holes, if * nowMs is another rtt away */ double pps = (ipg_ != 0) ? maxrtt / ipg_ : 0.; /*XXX*/ #ifdef notdef if (trace_ != 0) { double now = Scheduler::instance().clock(); sprintf(trace_->buffer(), "%.17g %g", now, (double)lostPkts / pps); trace_->dump(); } #endif /*XXX*/ #define LOSSCONGTH 15 #define LOSSLOADTH 5 /* If the rtt is smaller than the ipg, set the thresholds to 0,1,2 */ if ((pps * LOSSCONGTH) / 100 < 2) pps = 200 / LOSSCONGTH; if (lostPkts <= (LOSSLOADTH * pps) / 100) return (ST_U); else if (lostPkts <= (LOSSCONGTH * pps) / 100) return (ST_L); else return (ST_C); } void IvsReceiver::recv(Packet* pkt, Handler*) { hdr_ivs *p = (hdr_ivs*)pkt->access(off_ivs_); double now = Scheduler::instance().clock(); if (lastPktTime_ == 0.) { lastPktTime_ = now; Packet::free(pkt); return; } update_ipg(now - lastPktTime_); double ts = p->ts(); int prevState = state_; state_ = lossMeter(now - ts, p->seqno(), p->maxrtt()); lastPktTime_ = now; /* If soliciting rtt */ if (p->R() && !ignoreR_) /* upcall into tcl */ upcall_rtt_solicit(ts, p->rshft()); /* * send a response if we're congested and its over an rtt since * we last sent one OR * any response is solicited to estimate size and we match the key OR * we're LOADED and we match the key and its over an rtt since we last * sent a response */ if (now - lastTime_ < p->maxrtt() && state_ <= prevState) { Packet::free(pkt); return; } int shift = p->kshft(); int match; if (p->key() == 0) match = 1; else match = (key_ >> shift) == (p->key() >> shift); int matchS = match ? p->S() : 0; if (state_ == ST_C || matchS || (match && state_ == ST_L)) { upcall_respond(ts, matchS); lastTime_ = now; } Packet::free(pkt); } void IvsReceiver::upcall_respond(double ts, int matchS) { Tcl::instance().evalf("%s respond %.17g %d", name(), ts, matchS); } void IvsReceiver::upcall_rtt_solicit(double ts, int rshift) { Tcl::instance().evalf("%s solicit-rtt %.17g %d", name(), ts, rshift); } int IvsReceiver::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "send") == 0) { Packet* pkt = allocpkt(); hdr_msg* p = (hdr_msg*)pkt->access(off_msg_); const char* s = argv[2]; int n = strlen(s); if (n >= p->maxmsg()) { tcl.result("message too big"); Packet::free(pkt); return (TCL_ERROR); } strcpy(p->msg(), s); target_->recv(pkt, (Handler*)0); return (TCL_OK); } } return (Agent::command(argc, argv)); }

lanRouter.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * lanRouter.cc * Copyright (C) 1998 by USC/ISI * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint static const char rcsid[] = "@(#) $Header: /usr/src/mash/repository/vint/ns-2/lanRouter.cc"; #endif #include <tcl.h> #include <iostream.h> #include "lanRouter.h" #include "address.h" #include "ip.h" static class LanRouterClass : public TclClass { public: LanRouterClass() : TclClass("LanRouter") {} TclObject* create(int, const char*const*) { return (new LanRouter()); } } class_mac; int
LanRouter::next_hop(Packet *p) { if (switch_ && switch_->classify(p)==1) { return -1; } if (!routelogic_) return -1; hdr_ip* iph= hdr_ip::access(p); char* adst= Address::instance().print_nodeaddr(iph->daddr()); int next_hopIP; if (enableHrouting_) { char* bdst; routelogic_->lookup_hier(lanaddr_, adst, next_hopIP); // hacking: get rid of the last "." bdst = Address::instance().print_nodeaddr(next_hopIP); // bdst[strlen(bdst)-1] = '\0'; Tcl &tcl = Tcl::instance(); tcl.evalf("[Simulator instance] get-node-id-by-addr %s", bdst); sscanf(tcl.result(), "%d", &next_hopIP); delete [] bdst; } else { routelogic_->lookup_flat(lanaddr_, adst, next_hopIP); } delete [] adst; return next_hopIP; } int LanRouter::command(int argc, const char*const* argv) { // Tcl& tcl = Tcl::instance(); if (argc == 3) { // cmd lanaddr <addr> if (strcmp(argv[1], "lanaddr") == 0) { strcpy(lanaddr_, argv[2]); return (TCL_OK); } // cmd routing hier|flat if (strcmp(argv[1], "routing") == 0) { if (strcmp(argv[2], "hier")==0) enableHrouting_= true; else if (strcmp(argv[2], "flat")==0) enableHrouting_= false; else return (TCL_ERROR); return (TCL_OK); } // cmd switch <switch> if (strcmp(argv[1], "switch") == 0) { switch_ = (Classifier*) TclObject::lookup(argv[2]); return (TCL_OK); } // cmd routelogic <routelogic> if (strcmp(argv[1], "routelogic") == 0) { routelogic_ = (RouteLogic*) TclObject::lookup(argv[2]); return (TCL_OK); } } return NsObject::command(argc, argv); }

ll.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by the Daedalus Research Group, http://daedalus.cs.berkeley.edu */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (UCB)"; #endif #include <errmodel.h> #include <mac.h> #include <ll.h> #include <address.h> #include <dsr/hdr_sr.h> int hdr_ll::offset_; static class LLHeaderClass : public PacketHeaderClass { public: LLHeaderClass() : PacketHeaderClass("PacketHeader/LL", sizeof(hdr_ll)) { bind_offset(&hdr_ll::offset_); } } class_hdr_ll; static class LLClass : public TclClass { public: LLClass() : TclClass("LL") {} TclObject* create(int, const char*const*) { return (new LL); } } class_ll; LL::LL() : LinkDelay(), seqno_(0), ackno_(0), macDA_(0), ifq_(0), mac_(0), lanrouter_(0), arptable_(0), varp_(0), downtarget_(0), uptarget_(0) { bind("macDA_", &macDA_); } int
LL::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "ifq") == 0) { ifq_ = (Queue*) TclObject::lookup(argv[2]); return (TCL_OK); } if(strcmp(argv[1], "arptable") == 0) { arptable_ = (ARPTable*)TclObject::lookup(argv[2]); assert(arptable_); return TCL_OK; } if(strcmp(argv[1], "varp") == 0) { varp_ = (VARPTable*)TclObject::lookup(argv[2]); assert(varp_); return TCL_OK; } if (strcmp(argv[1], "mac") == 0) { mac_ = (Mac*) TclObject::lookup(argv[2]); assert(mac_); return (TCL_OK); } if (strcmp(argv[1], "down-target") == 0) { downtarget_ = (NsObject*) TclObject::lookup(argv[2]); return (TCL_OK); } if (strcmp(argv[1], "up-target") == 0) { uptarget_ = (NsObject*) TclObject::lookup(argv[2]); return (TCL_OK); } if (strcmp(argv[1], "lanrouter") == 0) { lanrouter_ = (LanRouter*) TclObject::lookup(argv[2]); return (TCL_OK); } } else if (argc == 2) { if (strcmp(argv[1], "ifq") == 0) { tcl.resultf("%s", ifq_->name()); return (TCL_OK); } if (strcmp(argv[1], "mac") == 0) { tcl.resultf("%s", mac_->name()); return (TCL_OK); } if (strcmp(argv[1], "down-target") == 0) { tcl.resultf("%s", downtarget_->name()); return (TCL_OK); } if (strcmp(argv[1], "up-target") == 0) { tcl.resultf("%s", uptarget_->name()); return (TCL_OK); } } return LinkDelay::command(argc, argv); } void LL::recv(Packet* p, Handler* /*h*/) { hdr_cmn *ch = HDR_CMN(p); //char *mh = (char*) HDR_MAC(p); //struct hdr_sr *hsr = HDR_SR(p); /* * Sanity Check */ assert(initialized()); if(p->incoming) { p->incoming = 0; } // If direction = UP, then pass it up the stack // Otherwise, set direction to DOWN and pass it down the stack if(ch->direction() == hdr_cmn::UP) { //if(mac_->hdr_type(mh) == ETHERTYPE_ARP) if(ch->ptype_ == PT_ARP) arptable_->arpinput(p, this); else uptarget_ ? sendUp(p) : drop(p); return; } ch->direction() = hdr_cmn::DOWN; sendDown(p); } void LL::sendDown(Packet* p) { hdr_cmn *ch = HDR_CMN(p); hdr_ip *ih = HDR_IP(p); // XXX HACK for now - Padma, 03/99. nsaddr_t dst = (nsaddr_t)Address::instance().get_nodeaddr(ih->daddr()); //nsaddr_t dst = ih->dst(); hdr_ll *llh = HDR_LL(p); char *mh = (char*)p->access(hdr_mac::offset_); llh->seqno_ = ++seqno_; llh->lltype() = LL_DATA; mac_->hdr_src(mh, mac_->addr()); mac_->hdr_type(mh, ETHERTYPE_IP); int tx = 0; switch(ch->addr_type()) { case NS_AF_ILINK: mac_->hdr_dst((char*) HDR_MAC(p), ch->next_hop()); break; case NS_AF_INET: dst = ch->next_hop(); /* FALL THROUGH */ case NS_AF_NONE: if (IP_BROADCAST == (u_int32_t) dst) { mac_->hdr_dst((char*) HDR_MAC(p), MAC_BROADCAST); break; } /* Assuming arptable is present, send query */ if (arptable_) { tx = arptable_->arpresolve(dst, p, this); break; } //if (varp_) { //tx = varp_->arpresolve(dst, p); //break; //} /* FALL THROUGH */ default: int IPnh = (lanrouter_) ? lanrouter_->next_hop(p) : -1; if (IPnh < 0) mac_->hdr_dst((char*) HDR_MAC(p),macDA_); else if (varp_) tx = varp_->arpresolve(IPnh, p); else mac_->hdr_dst((char*) HDR_MAC(p), IPnh); break; } if (tx == 0) { Scheduler& s = Scheduler::instance(); // let mac decide when to take a new packet from the queue. s.schedule(downtarget_, p, delay_); } } void LL::sendUp(Packet* p) { Scheduler& s = Scheduler::instance(); if (hdr_cmn::access(p)->error() > 0) drop(p); else s.schedule(uptarget_, p, delay_); }

loss-monitor.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1994-1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include "agent.h" #include "config.h" #include "tclcl.h" #include "packet.h" #include "ip.h" #include "rtp.h" class LossMonitor : public Agent { public: LossMonitor(); int command(int argc, const char*const* argv); void recv(Packet* pkt, Handler*); protected: int nlost_; int npkts_; int expected_; int bytes_; int seqno_; double last_packet_time_; int off_rtp_; }; static class LossMonitorClass : public TclClass { public: LossMonitorClass() : TclClass("Agent/LossMonitor") {} TclObject* create(int, const char*const*) { return (new LossMonitor()); } } class_loss_mon; LossMonitor::LossMonitor() : Agent(PT_NTYPE) { bytes_ = 0; nlost_ = 0; npkts_ = 0; expected_ = -1; last_packet_time_ = 0.; seqno_ = 0; bind("nlost_", &nlost_); bind("npkts_", &npkts_); bind("bytes_", &bytes_); bind("lastPktTime_", &last_packet_time_); bind("expected_", &expected_); bind("off_rtp_", &off_rtp_); } void
LossMonitor::recv(Packet* pkt, Handler*) { hdr_rtp* p = (hdr_rtp*)pkt->access(off_rtp_); seqno_ = p->seqno(); bytes_ += ((hdr_cmn*)pkt->access(off_cmn_))->size(); ++npkts_; /* * Check for lost packets */ if (expected_ >= 0) { int loss = seqno_ - expected_; if (loss > 0) { nlost_ += loss; Tcl::instance().evalf("%s log-loss", name()); } } last_packet_time_ = Scheduler::instance().clock(); expected_ = seqno_ + 1; Packet::free(pkt); } /* * $proc interval $interval * $proc size $size */ int LossMonitor::command(int argc, const char*const* argv) { if (argc == 2) { if (strcmp(argv[1], "clear") == 0) { expected_ = -1; return (TCL_OK); } } return (Agent::command(argc, argv)); }

mac-802_11.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Ported from CMU/Monarch's code, nov'98 -Padma.*/ #include "delay.h" #include "connector.h" #include "packet.h" #include "random.h" // #define DEBUG //#include <debug.h> #include "arp.h" #include "ll.h" #include "mac.h" #include "mac-timers.h" #include "mac-802_11.h" #include "cmu-trace.h" #define CHECK_BACKOFF_TIMER() \ { \ if(is_idle() && mhBackoff_.paused()) \ mhBackoff_.resume(difs_); \ if(! is_idle() && mhBackoff_.busy() && ! mhBackoff_.paused()) \ mhBackoff_.pause(); \ } #define TRANSMIT(p, t) \ { \ tx_active_ = 1; \ \ /* \ * If I'm transmitting without doing CS, such as when \ * sending an ACK, any incoming packet will be "missed" \ * and hence, must be discarded. \ */ \ if(rx_state_ != MAC_IDLE) { \ struct hdr_mac802_11 *dh = HDR_MAC802_11(p); \ \ assert(dh->dh_fc.fc_type == MAC_Type_Control); \ assert(dh->dh_fc.fc_subtype == MAC_Subtype_ACK); \ \ assert(pktRx_); \ struct hdr_cmn *ch = HDR_CMN(pktRx_); \ \ ch->error() = 1; /* force packet discard */ \ } \ \ /* \ * pass the packet on the "interface" which will in turn \ * place the packet on the channel. \ * \ * NOTE: a handler is passed along so that the Network \ * Interface can distinguish between incoming and \ * outgoing packets. \ */ \ downtarget_->recv(p->copy(), this); \ \ mhSend_.start(t); \ \ mhIF_.start(TX_Time(p)); \ } #define SET_RX_STATE(x) \ { \ rx_state_ = (x); \ \ CHECK_BACKOFF_TIMER(); \ } #define SET_TX_STATE(x) \ { \ tx_state_ = (x); \ \ CHECK_BACKOFF_TIMER(); \ } /* ====================================================================== Global Variables ====================================================================== */ //extern char* pt_names[]; static PHY_MIB PMIB = { DSSS_CWMin, DSSS_CWMax, DSSS_SlotTime, DSSS_CCATime, DSSS_RxTxTurnaroundTime, DSSS_SIFSTime, DSSS_PreambleLength, DSSS_PLCPHeaderLength }; static MAC_MIB MMIB = { 0 /* MAC_RTSThreshold */, MAC_ShortRetryLimit, MAC_LongRetryLimit, MAC_FragmentationThreshold, MAC_MaxTransmitMSDULifetime, MAC_MaxReceiveLifetime, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* ====================================================================== TCL Hooks for the simulator ====================================================================== */ static class Mac802_11Class : public TclClass { public: Mac802_11Class() : TclClass("Mac/802_11") {} TclObject* create(int, const char*const*) { return (new Mac802_11(&PMIB, &MMIB)); } } class_mac802_11; /* ====================================================================== Mac Class Functions ====================================================================== */ Mac802_11::Mac802_11(PHY_MIB *p, MAC_MIB *m) : Mac(), mhIF_(this), mhNav_(this), mhRecv_(this), mhSend_(this), mhDefer_(this, p->SlotTime), mhBackoff_(this, p->SlotTime) { macmib_ = m; phymib_ = p; nav_ = 0.0; tx_state_ = rx_state_ = MAC_IDLE; tx_active_ = 0; pktRTS_ = 0; pktCTRL_ = 0; cw_ = phymib_->CWMin; ssrc_ = slrc_ = 0; sifs_ = phymib_->SIFSTime; pifs_ = sifs_ + phymib_->SlotTime; difs_ = sifs_ + 2*phymib_->SlotTime; eifs_ = sifs_ + difs_ + DATA_Time(ETHER_ACK_LEN + phymib_->PreambleLength/8 + phymib_->PLCPHeaderLength/8); tx_sifs_ = sifs_ - phymib_->RxTxTurnaroundTime; tx_pifs_ = tx_sifs_ + phymib_->SlotTime; tx_difs_ = tx_sifs_ + 2 * phymib_->SlotTime; sta_seqno_ = 1; cache_ = 0; cache_node_count_ = 0; } int
Mac802_11::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "log-target") == 0) { logtarget_ = (NsObject*) TclObject::lookup(argv[2]); if(logtarget_ == 0) return TCL_ERROR; return TCL_OK; } if(strcmp(argv[1], "nodes") == 0) { if(cache_) return TCL_ERROR; cache_node_count_ = atoi(argv[2]); cache_ = new Host[cache_node_count_ + 1]; assert(cache_); bzero(cache_, sizeof(Host) * (cache_node_count_+1 )); return TCL_OK; } } return Mac::command(argc, argv); } /* ====================================================================== Debugging Routines ====================================================================== */ void Mac802_11::trace_pkt(Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); struct hdr_mac802_11* dh = HDR_MAC802_11(p); u_int16_t *t = (u_int16_t*) &dh->dh_fc; fprintf(stderr, "\t[ %2x %2x %2x %2x ] %x %s %d\n", *t, dh->dh_duration, ETHER_ADDR(dh->dh_da), ETHER_ADDR(dh->dh_sa), index_, packet_info.name(ch->ptype()), ch->size()); } void Mac802_11::dump(char *fname) { fprintf(stderr, "\n%s --- (INDEX: %d, time: %2.9f)\n", fname, index_, Scheduler::instance().clock()); fprintf(stderr, "\ttx_state_: %x, rx_state_: %x, nav: %2.9f, idle: %d\n", tx_state_, rx_state_, nav_, is_idle()); fprintf(stderr, "\tpktTx_: %x, pktRx_: %x, pktRTS_: %x, pktCTRL_: %x, callback: %x\n", (int) pktTx_, (int) pktRx_, (int) pktRTS_, (int) pktCTRL_, (int) callback_); fprintf(stderr, "\tDefer: %d, Backoff: %d (%d), Recv: %d, Timer: %d Nav: %d\n", mhDefer_.busy(), mhBackoff_.busy(), mhBackoff_.paused(), mhRecv_.busy(), mhSend_.busy(), mhNav_.busy()); fprintf(stderr, "\tBackoff Expire: %f\n", mhBackoff_.expire()); } /* ====================================================================== Packet Headers Routines ====================================================================== */ inline int Mac802_11::hdr_dst(char* hdr, int dst ) { struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr; //dst = (u_int32_t)(dst); if(dst > -2) STORE4BYTE(&dst, (dh->dh_da)); return ETHER_ADDR(dh->dh_da); } inline int Mac802_11::hdr_src(char* hdr, int src ) { struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr; //src = (u_int32_t)(src); if(src > -2) STORE4BYTE(&src, (dh->dh_sa)); return ETHER_ADDR(dh->dh_sa); } inline int Mac802_11::hdr_type(char* hdr, u_int16_t type) { struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr; if(type) //*((u_int16_t*) dh->dh_body) = type; STORE2BYTE(&type,(dh->dh_body)); //return *((u_int16_t*) dh->dh_body); return GET2BYTE(dh->dh_body); } /* ====================================================================== Misc Routines ====================================================================== */ inline int Mac802_11::is_idle() { if(rx_state_ != MAC_IDLE) return 0; if(tx_state_ != MAC_IDLE) return 0; if(nav_ > Scheduler::instance().clock()) return 0; return 1; } void Mac802_11::discard(Packet *p, const char* why) { hdr_mac802_11* mh = HDR_MAC802_11(p); hdr_cmn *ch = HDR_CMN(p); #if 0 /* old logic 8/8/98 -dam */ /* * If received below the RXThreshold, then just free. */ if(p->txinfo_.Pr < p->txinfo_.ant.RXThresh) { Packet::free(p); //p = 0; return; } #endif // 0 /* if the rcvd pkt contains errors, a real MAC layer couldn't necessarily read any data from it, so we just toss it now */ if(ch->error() != 0) { Packet::free(p); //p = 0; return; } switch(mh->dh_fc.fc_type) { case MAC_Type_Management: drop(p, why); //drop(p); return; case MAC_Type_Control: switch(mh->dh_fc.fc_subtype) { case MAC_Subtype_RTS: if((u_int32_t)ETHER_ADDR(mh->dh_sa) == \ (u_int32_t)index_) { drop(p, why); return; } /* fall through - if necessary */ case MAC_Subtype_CTS: case MAC_Subtype_ACK: if((u_int32_t)ETHER_ADDR(mh->dh_da) == \ (u_int32_t)index_) { drop(p, why); return; } break; default: fprintf(stderr, "invalid MAC Control subtype\n"); exit(1); } break; case MAC_Type_Data: switch(mh->dh_fc.fc_subtype) { case MAC_Subtype_Data: if((u_int32_t)ETHER_ADDR(mh->dh_da) == \ (u_int32_t)index_ || (u_int32_t)ETHER_ADDR(mh->dh_sa) == \ (u_int32_t)index_ || (u_int32_t)ETHER_ADDR(mh->dh_da) == MAC_BROADCAST) { //if (*(mh->dh_da) == (u_char)index_ || // *(mh->dh_sa) == (u_char)index_ || // *(mh->dh_sa) == (u_char)MAC_BROADCAST) { //drop(p, why); drop(p); return; } break; default: fprintf(stderr, "invalid MAC Data subtype\n"); exit(1); } break; default: fprintf(stderr, "invalid MAC type (%x)\n", mh->dh_fc.fc_type); trace_pkt(p); exit(1); } Packet::free(p); //p = 0; } void Mac802_11::capture(Packet *p) { /* * Update the NAV so that this does not screw * up carrier sense. */ set_nav(usec(eifs_ + TX_Time(p))); Packet::free(p); //p = 0; } void Mac802_11::collision(Packet *p) { switch(rx_state_) { case MAC_RECV: SET_RX_STATE(MAC_COLL); /* fall through */ case MAC_COLL: assert(pktRx_); assert(mhRecv_.busy()); /* * Since a collision has occurred, figure out * which packet that caused the collision will * "last" the longest. Make this packet, * pktRx_ and reset the Recv Timer if necessary. */ if(TX_Time(p) > mhRecv_.expire()) { mhRecv_.stop(); discard(pktRx_, DROP_MAC_COLLISION); pktRx_ = p; mhRecv_.start(TX_Time(pktRx_)); } else { discard(p, DROP_MAC_COLLISION); } break; default: assert(0); } } void Mac802_11::tx_resume() { assert(mhSend_.busy() == 0); assert(mhDefer_.busy() == 0); if(pktCTRL_) { /* * Need to send a CTS or ACK. */ mhDefer_.start(sifs_); } else if(pktRTS_) { if(mhBackoff_.busy() == 0) mhDefer_.start(difs_); } else if(pktTx_) { if(mhBackoff_.busy() == 0) mhDefer_.start(difs_); } else if(callback_) { Handler *h = callback_; callback_ = 0; h->handle((Event*) 0); } SET_TX_STATE(MAC_IDLE); } void Mac802_11::rx_resume() { assert(pktRx_ == 0); assert(mhRecv_.busy() == 0); SET_RX_STATE(MAC_IDLE); } /* ====================================================================== Timer Handler Routines ====================================================================== */ void Mac802_11::backoffHandler() { if(pktCTRL_) { assert(mhSend_.busy() || mhDefer_.busy()); return; } if(check_pktRTS() == 0) return; if(check_pktTx() == 0) return; } void Mac802_11::deferHandler() { assert(pktCTRL_ || pktRTS_ || pktTx_); if(check_pktCTRL() == 0) return; assert(mhBackoff_.busy() == 0); //if (mhBackoff_.busy() != 0) //{ // printf("deferHandler:mhBackoff_ busy!\n"); // return; //} if(check_pktRTS() == 0) return; if(check_pktTx() == 0) return; } void Mac802_11::navHandler() { if(is_idle() && mhBackoff_.paused()) mhBackoff_.resume(difs_); } void Mac802_11::recvHandler() { recv_timer(); } void Mac802_11::sendHandler() { send_timer(); } void Mac802_11::txHandler() { tx_active_ = 0; } /* ====================================================================== The "real" Timer Handler Routines ====================================================================== */ void Mac802_11::send_timer() { switch(tx_state_) { /* * Sent a RTS, but did not receive a CTS. */ case MAC_RTS: RetransmitRTS(); break; /* * Sent a CTS, but did not receive a DATA packet. */ case MAC_CTS: assert(pktCTRL_); Packet::free(pktCTRL_); pktCTRL_ = 0; break; /* * Sent DATA, but did not receive an ACK packet. */ case MAC_SEND: RetransmitDATA(); break; /* * Sent an ACK, and now ready to resume transmission. */ case MAC_ACK: assert(pktCTRL_); Packet::free(pktCTRL_); pktCTRL_ = 0; break; case MAC_IDLE: break; default: assert(0); } tx_resume(); } /* ====================================================================== Outgoing Packet Routines ====================================================================== */ int Mac802_11::check_pktCTRL() { struct hdr_mac802_11 *mh; double timeout; if(pktCTRL_ == 0) return -1; if(tx_state_ == MAC_CTS || tx_state_ == MAC_ACK) return -1; mh = HDR_MAC802_11(pktCTRL_); switch(mh->dh_fc.fc_subtype) { /* * If the medium is not IDLE, don't send the CTS. */ case MAC_Subtype_CTS: if(! is_idle()) { discard(pktCTRL_, DROP_MAC_BUSY); pktCTRL_ = 0; return 0; } SET_TX_STATE(MAC_CTS); timeout = (mh->dh_duration * 1e-6) + CTS_Time; // XXX break; /* * IEEE 802.11 specs, section 9.2.8 * Acknowledments are sent after an SIFS, without regard to * the busy/idle state of the medium. */ case MAC_Subtype_ACK: SET_TX_STATE(MAC_ACK); timeout = ACK_Time; break; default: fprintf(stderr, "check_pktCTRL:Invalid MAC Control subtype\n"); exit(1); } TRANSMIT(pktCTRL_, timeout); return 0; } int Mac802_11::check_pktRTS() { struct hdr_mac802_11 *mh; double timeout; assert(mhBackoff_.busy() == 0); if(pktRTS_ == 0) return -1; //struct hdr_cmn *ch = HDR_CMN(pktRTS_); mh = HDR_MAC802_11(pktRTS_); switch(mh->dh_fc.fc_subtype) { case MAC_Subtype_RTS: if(! is_idle()) { inc_cw(); mhBackoff_.start(cw_, is_idle()); return 0; } SET_TX_STATE(MAC_RTS); timeout = CTSTimeout; break; default: fprintf(stderr, "check_pktRTS:Invalid MAC Control subtype\n"); exit(1); } TRANSMIT(pktRTS_, timeout); return 0; } int Mac802_11::check_pktTx() { struct hdr_mac802_11 *mh; double timeout; assert(mhBackoff_.busy() == 0); if(pktTx_ == 0) return -1; mh = HDR_MAC802_11(pktTx_); int len = HDR_CMN(pktTx_)->size(); switch(mh->dh_fc.fc_subtype) { case MAC_Subtype_Data: if(! is_idle()) { sendRTS(ETHER_ADDR(mh->dh_da)); inc_cw(); mhBackoff_.start(cw_, is_idle()); return 0; } SET_TX_STATE(MAC_SEND); if((u_int32_t)ETHER_ADDR(mh->dh_da) != MAC_BROADCAST) //timeout = ACKTimeout(netif_->txtime(pktTx_))+5; // why 10 ? buggy //timeout = ACKTimeout(len) + 10; timeout = ACKTimeout(len); else timeout = TX_Time(pktTx_); break; default: fprintf(stderr, "check_pktTx:Invalid MAC Control subtype\n"); //printf("pktRTS:%x, pktCTS/ACK:%x, pktTx:%x\n",pktRTS_, pktCTRL_,pktTx_); exit(1); } TRANSMIT(pktTx_, timeout); return 0; } /* * Low-level transmit functions that actually place the packet onto * the channel. */ void Mac802_11::sendRTS(int dst) { Packet *p = Packet::alloc(); hdr_cmn* ch = HDR_CMN(p); struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_); //struct hdr_mac802_11 *mh = HDR_MAC802_11(p); assert(pktTx_); assert(pktRTS_ == 0); /* * If the size of the packet is larger than the * RTSThreshold, then perform the RTS/CTS exchange. * * XXX: also skip if destination is a broadcast */ if( (u_int32_t) HDR_CMN(pktTx_)->size() < macmib_->RTSThreshold || (u_int32_t) dst == MAC_BROADCAST) { Packet::free(p); //p = 0; return; } ch->uid() = 0; ch->ptype() = PT_MAC; ch->size() = ETHER_RTS_LEN; ch->iface() = -2; ch->error() = 0; bzero(rf, MAC_HDR_LEN); rf->rf_fc.fc_protocol_version = MAC_ProtocolVersion; rf->rf_fc.fc_type = MAC_Type_Control; rf->rf_fc.fc_subtype = MAC_Subtype_RTS; rf->rf_fc.fc_to_ds = 0; rf->rf_fc.fc_from_ds = 0; rf->rf_fc.fc_more_frag = 0; rf->rf_fc.fc_retry = 0; rf->rf_fc.fc_pwr_mgt = 0; rf->rf_fc.fc_more_data = 0; rf->rf_fc.fc_wep = 0; rf->rf_fc.fc_order = 0; rf->rf_duration = RTS_DURATION(pktTx_); //ETHER_ADDR(rf->rf_ra) = dst; STORE4BYTE(&dst, (rf->rf_ra)); //ETHER_ADDR(rf->rf_ta) = index_; STORE4BYTE(&index_, (rf->rf_ta)); // rf->rf_fcs; pktRTS_ = p; } void Mac802_11::sendCTS(int dst, double rts_duration) { Packet *p = Packet::alloc(); hdr_cmn* ch = HDR_CMN(p); struct cts_frame *cf = (struct cts_frame*)p->access(hdr_mac::offset_); //struct hdr_mac802_11 *mh = HDR_MAC802_11(p); assert(pktCTRL_ == 0); ch->uid() = 0; ch->ptype() = PT_MAC; ch->size() = ETHER_CTS_LEN; ch->iface() = -2; ch->error() = 0; //ch->direction() = hdr_cmn::DOWN; bzero(cf, MAC_HDR_LEN); cf->cf_fc.fc_protocol_version = MAC_ProtocolVersion; cf->cf_fc.fc_type = MAC_Type_Control; cf->cf_fc.fc_subtype = MAC_Subtype_CTS; cf->cf_fc.fc_to_ds = 0; cf->cf_fc.fc_from_ds = 0; cf->cf_fc.fc_more_frag = 0; cf->cf_fc.fc_retry = 0; cf->cf_fc.fc_pwr_mgt = 0; cf->cf_fc.fc_more_data = 0; cf->cf_fc.fc_wep = 0; cf->cf_fc.fc_order = 0; cf->cf_duration = CTS_DURATION(rts_duration); //ETHER_ADDR(cf->cf_ra) = dst; STORE4BYTE(&dst, (cf->cf_ra)); //STORE4BYTE(&dst, (mh->dh_da)); // cf->cf_fcs; pktCTRL_ = p; } void Mac802_11::sendACK(int dst) { Packet *p = Packet::alloc(); hdr_cmn* ch = HDR_CMN(p); struct ack_frame *af = (struct ack_frame*)p->access(hdr_mac::offset_); //struct hdr_mac802_11 *mh = HDR_MAC802_11(p); assert(pktCTRL_ == 0); ch->uid() = 0; ch->ptype() = PT_MAC; ch->size() = ETHER_ACK_LEN; ch->iface() = -2; ch->error() = 0; //ch->direction() = hdr_cmn::DOWN; bzero(af, MAC_HDR_LEN); af->af_fc.fc_protocol_version = MAC_ProtocolVersion; af->af_fc.fc_type = MAC_Type_Control; af->af_fc.fc_subtype = MAC_Subtype_ACK; af->af_fc.fc_to_ds = 0; af->af_fc.fc_from_ds = 0; af->af_fc.fc_more_frag = 0; af->af_fc.fc_retry = 0; af->af_fc.fc_pwr_mgt = 0; af->af_fc.fc_more_data = 0; af->af_fc.fc_wep = 0; af->af_fc.fc_order = 0; af->af_duration = ACK_DURATION(); //ETHER_ADDR(af->af_ra) = dst; STORE4BYTE(&dst, (af->af_ra)); // af->af_fcs; pktCTRL_ = p; } void Mac802_11::sendDATA(Packet *p) { hdr_cmn* ch = HDR_CMN(p); struct hdr_mac802_11* dh = HDR_MAC802_11(p); assert(pktTx_ == 0); /* * Update the MAC header */ ch->size() += ETHER_HDR_LEN; dh->dh_fc.fc_protocol_version = MAC_ProtocolVersion; dh->dh_fc.fc_type = MAC_Type_Data; dh->dh_fc.fc_subtype = MAC_Subtype_Data; //printf(".....p = %x, mac-subtype-%d\n",p,dh->dh_fc.fc_subtype); dh->dh_fc.fc_to_ds = 0; dh->dh_fc.fc_from_ds = 0; dh->dh_fc.fc_more_frag = 0; dh->dh_fc.fc_retry = 0; dh->dh_fc.fc_pwr_mgt = 0; dh->dh_fc.fc_more_data = 0; dh->dh_fc.fc_wep = 0; dh->dh_fc.fc_order = 0; if((u_int32_t)ETHER_ADDR(dh->dh_da) != MAC_BROADCAST) dh->dh_duration = DATA_DURATION(); else dh->dh_duration = 0; pktTx_ = p; } /* ====================================================================== Retransmission Routines ====================================================================== */ void Mac802_11::RetransmitRTS() { assert(pktTx_); assert(pktRTS_); assert(mhBackoff_.busy() == 0); macmib_->RTSFailureCount++; ssrc_ += 1; // STA Short Retry Count if(ssrc_ >= macmib_->ShortRetryLimit) { discard(pktRTS_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktRTS_ = 0; /* tell the callback the send operation failed before discarding the packet */ hdr_cmn *ch = HDR_CMN(pktTx_); if (ch->xmit_failure_) { /* * Need to remove the MAC header so that * re-cycled packets don't keep getting * bigger. */ ch->size() -= ETHER_HDR_LEN; ch->xmit_reason_ = XMIT_REASON_RTS; ch->xmit_failure_(pktTx_->copy(), ch->xmit_failure_data_); } //printf("(%d)....discarding RTS:%x\n",index_,pktRTS_); discard(pktTx_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktTx_ = 0; ssrc_ = 0; rst_cw(); } else { //printf("(%d)...retxing RTS:%x\n",index_,pktRTS_); struct rts_frame *rf; rf = (struct rts_frame*)pktRTS_->access(hdr_mac::offset_); rf->rf_fc.fc_retry = 1; inc_cw(); mhBackoff_.start(cw_, is_idle()); } } void Mac802_11::RetransmitDATA() { struct hdr_cmn *ch; struct hdr_mac802_11 *mh; u_int32_t *rcount, *thresh; assert(mhBackoff_.busy() == 0); assert(pktTx_); assert(pktRTS_ == 0); ch = HDR_CMN(pktTx_); mh = HDR_MAC802_11(pktTx_); /* * Broadcast packets don't get ACKed and therefore * are never retransmitted. */ if((u_int32_t)ETHER_ADDR(mh->dh_da) == MAC_BROADCAST) { Packet::free(pktTx_); pktTx_ = 0; /* * Backoff at end of TX. */ rst_cw(); mhBackoff_.start(cw_, is_idle()); return; } macmib_->ACKFailureCount++; if((u_int32_t) ch->size() <= macmib_->RTSThreshold) { rcount = &ssrc_; thresh = &macmib_->ShortRetryLimit; } else { rcount = &slrc_; thresh = &macmib_->LongRetryLimit; } (*rcount)++; if(*rcount > *thresh) { macmib_->FailedCount++; /* tell the callback the send operation failed before discarding the packet */ hdr_cmn *ch = HDR_CMN(pktTx_); if (ch->xmit_failure_) { ch->size() -= ETHER_HDR_LEN; ch->xmit_reason_ = XMIT_REASON_ACK; ch->xmit_failure_(pktTx_->copy(), ch->xmit_failure_data_); } discard(pktTx_, DROP_MAC_RETRY_COUNT_EXCEEDED); pktTx_ = 0; //printf("(%d)DATA discarded: count exceeded\n",index_); *rcount = 0; rst_cw(); } else { struct hdr_mac802_11 *dh; dh = HDR_MAC802_11(pktTx_); dh->dh_fc.fc_retry = 1; sendRTS(ETHER_ADDR(mh->dh_da)); //printf("(%d)retxing data:%x..sendRTS..\n",index_,pktTx_); inc_cw(); mhBackoff_.start(cw_, is_idle()); } } /* ====================================================================== Incoming Packet Routines ====================================================================== */ void Mac802_11::send(Packet *p, Handler *h) { struct hdr_mac802_11* dh = HDR_MAC802_11(p); /* * drop the packet if the node is in sleep mode XXX sleep mode can't stop node from sending packets */ if ((netif_->node())->sleep()) { netif_->node()->set_node_sleep(0); netif_->node()->set_node_state(INROUTE); } callback_ = h; sendDATA(p); sendRTS(ETHER_ADDR(dh->dh_da)); /* * Assign the data packet a sequence number. */ dh->dh_scontrol = sta_seqno_++; /* * If the medium is IDLE, we must wait for a DIFS * Space before transmitting. */ if(mhBackoff_.busy() == 0) { if(is_idle()) { /* * If we are already deferring, there is no * need to reset the Defer timer. */ if(mhDefer_.busy() == 0) mhDefer_.start(difs_); } /* * If the medium is NOT IDLE, then we start * the backoff timer. */ else { mhBackoff_.start(cw_, is_idle()); } } } void Mac802_11::recv(Packet *p, Handler *h) { struct hdr_cmn *hdr = HDR_CMN(p); //hdr_mac802_11 *mh = HDR_MAC802_11(p); //u_int32_t dst = ETHER_ADDR(mh->dh_da); //u_int32_t src = ETHER_ADDR(mh->dh_sa); /* * Sanity Check */ assert(initialized()); /* * Handle outgoing packets. */ if(hdr->direction() == hdr_cmn::DOWN) { send(p, h); return; } /* * Handle incoming packets. * * We just received the 1st bit of a packet on the network * interface. * */ /* * If the interface is currently in transmit mode, then * it probably won't even see this packet. However, the * "air" around me is BUSY so I need to let the packet * proceed. Just set the error flag in the common header * to that the packet gets thrown away. */ if(tx_active_ && hdr->error() == 0) { hdr->error() = 1; } if(rx_state_ == MAC_IDLE) { SET_RX_STATE(MAC_RECV); pktRx_ = p; /* * Schedule the reception of this packet, in * txtime seconds. */ mhRecv_.start(TX_Time(p)); } else { /* * If the power of the incoming packet is smaller than the * power of the packet currently being received by at least * the capture threshold, then we ignore the new packet. */ if(pktRx_->txinfo_.RxPr / p->txinfo_.RxPr >= p->txinfo_.CPThresh) { capture(p); } else { collision(p); } } } void Mac802_11::recv_timer() { u_int32_t src; hdr_cmn *ch = HDR_CMN(pktRx_); hdr_mac802_11 *mh = HDR_MAC802_11(pktRx_); u_int32_t dst = ETHER_ADDR(mh->dh_da); // XXX debug //struct cts_frame *cf = (struct cts_frame*)pktRx_->access(hdr_mac::offset_); //u_int32_t src = ETHER_ADDR(mh->dh_sa); u_int8_t type = mh->dh_fc.fc_type; u_int8_t subtype = mh->dh_fc.fc_subtype; assert(pktRx_); assert(rx_state_ == MAC_RECV || rx_state_ == MAC_COLL); /* * If the interface is in TRANSMIT mode when this packet * "arrives", then I would never have seen it and should * do a silent discard without adjusting the NAV. */ if(tx_active_) { Packet::free(pktRx_); goto done; } /* * Handle collisions. */ if(rx_state_ == MAC_COLL) { discard(pktRx_, DROP_MAC_COLLISION); set_nav(usec(eifs_)); goto done; } /* * Check to see if this packet was received with enough * bit errors that the current level of FEC still could not * fix all of the problems - ie; after FEC, the checksum still * failed. */ if( ch->error() ) { Packet::free(pktRx_); set_nav(usec(eifs_)); goto done; } /* * IEEE 802.11 specs, section 9.2.5.6 * - update the NAV (Network Allocation Vector) */ if(dst != (u_int32_t)index_) { set_nav(mh->dh_duration); } /* tap out - */ if (tap_ && type == MAC_Type_Data && MAC_Subtype_Data == subtype ) tap_->tap(pktRx_); /* * Adaptive Fidelity Algorithm Support - neighborhood infomation collection * * Hacking: Before filter the packet, log the neighbor node * I can hear the packet, the src is my neighbor */ if (netif_->node()->adaptivefidelity()) { src = ETHER_ADDR(mh->dh_sa); netif_->node()->add_neighbor(src); } /* * Address Filtering */ if(dst != (u_int32_t)index_ && dst != MAC_BROADCAST) { /* * We don't want to log this event, so we just free * the packet instead of calling the drop routine. */ discard(pktRx_, "---"); goto done; } switch(type) { case MAC_Type_Management: discard(pktRx_, DROP_MAC_PACKET_ERROR); goto done; break; case MAC_Type_Control: switch(subtype) { case MAC_Subtype_RTS: recvRTS(pktRx_); break; case MAC_Subtype_CTS: recvCTS(pktRx_); break; case MAC_Subtype_ACK: recvACK(pktRx_); break; default: fprintf(stderr,"recvTimer1:Invalid MAC Control Subtype %x\n", subtype); exit(1); } break; case MAC_Type_Data: switch(subtype) { case MAC_Subtype_Data: recvDATA(pktRx_); break; default: fprintf(stderr, "recv_timer2:Invalid MAC Data Subtype %x\n", subtype); exit(1); } break; default: fprintf(stderr, "recv_timer3:Invalid MAC Type %x\n", subtype); exit(1); } done: pktRx_ = 0; rx_resume(); } void Mac802_11::recvRTS(Packet *p) { struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_); if(tx_state_ != MAC_IDLE) { discard(p, DROP_MAC_BUSY); return; } /* * If I'm responding to someone else, discard this RTS. */ if(pktCTRL_) { discard(p, DROP_MAC_BUSY); return; } sendCTS(ETHER_ADDR(rf->rf_ta), rf->rf_duration); /* * Stop deferring - will be reset in tx_resume(). */ if(mhDefer_.busy()) mhDefer_.stop(); tx_resume(); mac_log(p); } void Mac802_11::recvCTS(Packet *p) { if(tx_state_ != MAC_RTS) { discard(p, DROP_MAC_INVALID_STATE); return; } assert(pktRTS_); Packet::free(pktRTS_); pktRTS_ = 0; assert(pktTx_); // debug //struct hdr_mac802_11 *mh = HDR_MAC802_11(pktTx_); //printf("(%d):recvCTS:pktTx_-%x,mac-subtype-%d & pktCTS_:%x\n",index_,pktTx_,mh->dh_fc.fc_subtype,p); mhSend_.stop(); /* * The successful reception of this CTS packet implies * that our RTS was successful. Hence, we can reset * the Short Retry Count and the CW. */ ssrc_ = 0; rst_cw(); tx_resume(); mac_log(p); } void Mac802_11::recvDATA(Packet *p) { struct hdr_mac802_11 *dh = HDR_MAC802_11(p); u_int32_t dst, src, size; { struct hdr_cmn *ch = HDR_CMN(p); dst = ETHER_ADDR(dh->dh_da); src = ETHER_ADDR(dh->dh_sa); size = ch->size(); /* * Adjust the MAC packet size - ie; strip * off the mac header */ ch->size() -= ETHER_HDR_LEN; ch->num_forwards() += 1; } /* * If we sent a CTS, clean up... */ if(dst != MAC_BROADCAST) { if(size >= macmib_->RTSThreshold) { if (tx_state_ == MAC_CTS) { assert(pktCTRL_); Packet::free(pktCTRL_); pktCTRL_ = 0; mhSend_.stop(); /* * Our CTS got through. */ //printf("(%d): RECVING DATA!\n",index_); ssrc_ = 0; rst_cw(); } else { discard(p, DROP_MAC_BUSY); //printf("(%d)..discard DATA\n",index_); return; } sendACK(src); tx_resume(); } /* * We did not send a CTS and there's no * room to buffer an ACK. */ else { if(pktCTRL_) { discard(p, DROP_MAC_BUSY); return; } sendACK(src); if(mhSend_.busy() == 0) tx_resume(); } } /* ============================================================ Make/update an entry in our sequence number cache. ============================================================ */ if(dst != MAC_BROADCAST) { Host *h = &cache_[src]; if(h->seqno && h->seqno == dh->dh_scontrol) { discard(p, DROP_MAC_DUPLICATE); return; } h->seqno = dh->dh_scontrol; } /* * Pass the packet up to the link-layer. * XXX - we could schedule an event to account * for this processing delay. */ p->incoming = 1; uptarget_->recv(p, (Handler*) 0); } void Mac802_11::recvACK(Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); if(tx_state_ != MAC_SEND) { discard(p, DROP_MAC_INVALID_STATE); return; } //printf("(%d)...................recving ACK:%x\n",index_,p); assert(pktTx_); Packet::free(pktTx_); pktTx_ = 0; mhSend_.stop(); /* * The successful reception of this ACK packet implies * that our DATA transmission was successful. Hence, * we can reset the Short/Long Retry Count and the CW. */ if((u_int32_t) ch->size() <= macmib_->RTSThreshold) ssrc_ = 0; else slrc_ = 0; /* * Backoff before sending again. */ rst_cw(); assert(mhBackoff_.busy() == 0); mhBackoff_.start(cw_, is_idle()); tx_resume(); mac_log(p); }

mac-802_3.cc


/* mac-802_3.cc $Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $ */ #include <packet.h> #include <random.h> #include <arp.h> #include <ll.h> #include <mac-802_3.h> //#define MAC_DEBUG #ifndef MAC_DEBUG #define FPRINTF(s, f, t, index, func) do {} while (0) #else static double xtime= 0.0; # define FPRINTF(s, f, t, index, func) \ do { fprintf(s, f, t, index, func); xtime= t; } while (0) #endif MAC_DEBUG inline void
MacHandler::cancel() { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); Scheduler& s = Scheduler::instance(); assert(busy_); s.cancel(&intr); busy_ = 0; } inline void Mac8023HandlerSend::cancel() { assert(busy_); Scheduler &s= Scheduler::instance(); s.cancel(&intr); busy_= 0; p_= 0; } inline void MacHandlerRecv::cancel() { Scheduler& s = Scheduler::instance(); assert(busy_ && p_); s.cancel(&intr); busy_ = 0; Packet::free(p_); p_= 0; } inline void MacHandlerRetx::cancel() { Scheduler& s = Scheduler::instance(); assert(busy_ && p_); s.cancel(&intr); } inline void MacHandlerIFS::cancel() { //fprintf (stderr, "cancelled dtime= %.15f\n", intr.time_- Scheduler::instance().clock()); MacHandler::cancel(); } static class Mac802_3Class : public TclClass { public: Mac802_3Class() : TclClass("Mac/802_3") {} TclObject* create(int, const char*const*) { return (new Mac802_3); } } class_mac802_3; void Mac8023HandlerSend::handle(Event*) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); assert(p_); /* Transmission completed successfully */ busy_ = 0; p_= 0; mac->mhRetx_.free(); mac->mhRetx_.reset(); mac->mhIFS_.schedule(mac->netif_->txtime(IEEE_8023_IFS_BITS/8.0)); } void Mac8023HandlerSend::schedule(const Packet *p, double t) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); Scheduler& s = Scheduler::instance(); assert(!busy_); s.schedule(this, &intr, t); busy_ = 1; p_= p; } void MacHandlerRecv::handle(Event* ) { /* Reception Successful */ FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); busy_ = 0; mac->recv_complete(p_); p_= 0; } void MacHandlerRecv::schedule(Packet *p, double t) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); Scheduler& s = Scheduler::instance(); assert(p && !busy_); s.schedule(this, &intr, t); busy_ = 1; p_ = p; } bool MacHandlerRetx::schedule(double delta) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); Scheduler& s = Scheduler::instance(); assert(p_ && !busy_); int k, r; if(try_ < IEEE_8023_ALIMIT) { k = min(try_, IEEE_8023_BLIMIT); r = Random::integer(1 << k); s.schedule(this, &intr, r * mac->netif_->txtime(IEEE_8023_SLOT_BITS/8.0) + delta); busy_ = 1; return true; } return false; } void MacHandlerRetx::handle(Event *) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); assert(p_); busy_= 0; ++try_; mac->transmit(p_); } inline void MacHandlerIFS::schedule(double t) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); assert(!busy_); Scheduler &s= Scheduler::instance(); s.schedule(this, &intr, t); busy_= 1; } inline void MacHandlerIFS::handle(Event*) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), mac->index_, __PRETTY_FUNCTION__); busy_= 0; mac->resume(); } Mac802_3::Mac802_3() : Mac(), mhRecv_(this), mhRetx_(this), mhIFS_(this), mhSend_(this) { } void Mac802_3::sendUp(Packet *p, Handler *) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__); /* just received the 1st bit of a packet */ if (state_ != MAC_IDLE && mhIFS_.busy()) { // this must mean either that // a. mhIFS_ is about to expire now - concurrent events ordering - or // b. (txtime + ifs + propdelay) < (propdelay + txtime + ifs) for the prev. packet // so we assume that IFS is over and resume #ifdef MAC_DEBUG #define EPS 1.0e-15 if (mhIFS_.expire() - Scheduler::instance().clock() > EPS) { fprintf(stderr, "mhIFS_: %.20f, time= %.20f, diff= %e\n", mhIFS_.expire(), Scheduler::instance().clock(), mhIFS_.expire() - Scheduler::instance().clock()); assert(0); } #undef EPS #endif mhIFS_.cancel(); resume(); } if(state_ == MAC_IDLE) { state_ = MAC_RECV; assert(!mhRecv_.busy()); /* the last bit will arrive in txtime seconds */ mhRecv_.schedule(p, netif_->txtime(p)); } else { collision(p); //received packet while sending or receiving } } void Mac802_3::sendDown(Packet *p, Handler *h) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__); assert(initialized()); assert(h); assert(netif_->txtime(IEEE_8023_MINFRAME) > 2*netif_->channel()->maxdelay()); /* max prop. delay is limited by specs: about 25us for 10Mbps and 2.5us for 100Mbps */ int size= (HDR_CMN(p)->size() += ETHER_HDR_LEN); //XXX also preamble? hdr_mac *mh= HDR_MAC(p); mh->padding_= 0; if (size > IEEE_8023_MAXFRAME) { static bool warnedMAX= false; if (!warnedMAX) { fprintf(stderr, "Mac802_3: frame is too big: %d\n", size); warnedMAX= true; } } else if (size < IEEE_8023_MINFRAME) { // pad it to fit MINFRAME mh->padding_= IEEE_8023_MINFRAME - size; HDR_CMN(p)->size() += mh->padding_; } callback_ = h; mhRetx_.packet(p); //packet's buffered by mhRetx in case of retransmissions transmit(p); } void Mac802_3::transmit(Packet *p) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__); assert(callback_); if(mhSend_.packet()) { fprintf(stderr, "index: %d\n", index_); fprintf(stderr, "Retx Timer: %d\n", mhRetx_.busy()); fprintf(stderr, "IFS Timer: %d\n", mhIFS_.busy()); fprintf(stderr, "Recv Timer: %d\n", mhRecv_.busy()); fprintf(stderr, "Send Timer: %d\n", mhSend_.busy()); exit(1); } /* Perform carrier sense - if we were sending before, never mind state_ */ if (mhIFS_.busy() || (state_ != MAC_IDLE)) { /* we'll try again when IDLE. It'll happen either when reception completes, or if collision. Either way, we call resume() */ return; } HDR_CMN(p)->direction()= hdr_cmn::DOWN; //down double txtime = netif_->txtime(p); /* Schedule transmission of the packet's last bit */ mhSend_.schedule(p, txtime); // pass the packet to the PHY: need to send a copy, // because there may be collision and it may be freed downtarget_->recv(p->copy()); state_= MAC_SEND; } void Mac802_3::collision(Packet *p) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__); Packet::free(p); if (mhIFS_.busy()) mhIFS_.cancel(); double ifstime= netif_->txtime((IEEE_8023_JAMSIZE+IEEE_8023_IFS_BITS)/8); //jam time + ifs mhIFS_.schedule(ifstime); switch(state_) { case MAC_SEND: if (mhSend_.busy()) mhSend_.cancel(); if (!mhRetx_.busy()) { /* schedule retransmissions */ if (!mhRetx_.schedule(ifstime)) { p= mhRetx_.packet(); HDR_CMN(p)->size() -= (ETHER_HDR_LEN + HDR_MAC(p)->padding_); drop(p); // drop if backed off far enough mhRetx_.reset(); } } break; case MAC_RECV: // more than 2 packets collisions possible if (mhRecv_.busy()) mhRecv_.cancel(); break; default: assert("SHOULD NEVER HAPPEN" == 0); } } void Mac802_3::recv_complete(Packet *p) { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__); assert(!mhRecv_.busy()); assert(!mhSend_.busy()); hdr_cmn *ch= HDR_CMN(p); /* Address Filtering */ hdr_mac *mh= HDR_MAC(p); int dst= mh->macDA(); if ((dst != BCAST_ADDR) && (dst != index_)) { Packet::free(p); goto done; } /* Strip off the mac header and padding if any */ ch->size() -= (ETHER_HDR_LEN + mh->padding_); /* xxx FEC here */ if( ch->error() ) { drop(p); goto done; } /* we could schedule an event to account for mac-delay */ uptarget_->recv(p, (Handler*) 0); done: mhIFS_.schedule(netif_->txtime(IEEE_8023_IFS_BITS/8));// wait for one IFS, then resume } /* we call resume() in these cases: - successful transmission - whole packet's received - collision and backoffLimit's exceeded - collision while receiving */ void Mac802_3::resume() { FPRINTF(stderr, "%.15f : %d : %s\n", Scheduler::instance().clock(), index_, __PRETTY_FUNCTION__); assert(!mhRecv_.busy()); assert(!mhSend_.busy()); assert(!mhIFS_.busy()); state_= MAC_IDLE; if (mhRetx_.packet()) { if (!mhRetx_.busy()) { // we're not backing off and not sensing carrier right now: send transmit(mhRetx_.packet()); } } else { if (callback_ && !mhRetx_.busy()) { //WARNING: calling callback_->handle may change the value of callback_ Handler* h= callback_; callback_= 0; h->handle(0); } } }

mac-csma.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by Giao Nguyen, http://daedalus.cs.berkeley.edu/~gnguyen */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (UCB)"; #endif #include "template.h" #include "random.h" #include "channel.h" #include "mac-csma.h" static class MacCsmaClass : public TclClass { public: MacCsmaClass() : TclClass("Mac/Csma") {} TclObject* create(int, const char*const*) { return (new MacCsma); } } class_mac_csma; static class MacCsmaCdClass : public TclClass { public: MacCsmaCdClass() : TclClass("Mac/Csma/Cd") {} TclObject* create(int, const char*const*) { return (new MacCsmaCd); } } class_mac_csma_cd; static class MacCsmaCaClass : public TclClass { public: MacCsmaCaClass() : TclClass("Mac/Csma/Ca") {} TclObject* create(int, const char*const*) { return (new MacCsmaCa); } } class_mac_csma_ca; void
MacHandlerEoc::handle(Event* e) { mac_->endofContention((Packet*)e); } MacCsma::MacCsma() : txstart_(0), rtx_(0), csense_(1), hEoc_(this) { bind_time("ifs_", &ifs_); bind_time("slotTime_", &slotTime_); bind("cwmin_", &cwmin_); bind("cwmax_", &cwmax_); bind("rtxLimit_", &rtxLimit_); bind("csense_", &csense_); cw_ = cwmin_; } void MacCsma::resume(Packet* p) { Scheduler& s = Scheduler::instance(); s.schedule(callback_, &intr_, ifs_ + slotTime_ * cwmin_); if (p != 0) drop(p); callback_ = 0; state(MAC_IDLE); rtx_ = 0; cw_ = cwmin_; } void MacCsma::send(Packet* p) { Scheduler& s = Scheduler::instance(); double delay = channel_->txstop() + ifs_ - s.clock(); // if channel is not ready, then wait // else content for the channel /* XXX floating point operations differences have been observed on the resulting delay value on Pentium II and SunSparc. E.g. PentiumII SunSparc ------------------------------- channel_->txstop_= 0.11665366666666668 0.11665366666666668 binary 0x3fbddd03c34ab4a2 0x3fbddd03c34ab4a2 ifs_= 5.1999999999999997e-05 5.1999999999999997e-05 binary 0x3f0b43526527a205 0x3f0b43526527a205 s.clock_= 0.11670566666666668 0.11670566666666668 binary 0x3fbde06c2d975996 0x3fbde06c2d975996 delay= 3.5033282698437862e-18 0 binary 0x3c50280000000000 0x0000000000000000 Because of that the value of (csense_ && delay > 0) was different. Fixed by changing 0 to EPS */ static const double EPS= 1.0e-12; //seems appropriate (less than nanosec) if (csense_ && delay > EPS) s.schedule(&hSend_, p, delay + 0.000001); else { txstart_ = s.clock(); channel_->contention(p, &hEoc_); } } void MacCsma::backoff(Handler* h, Packet* p, double delay) { Scheduler& s = Scheduler::instance(); double now = s.clock(); // if retransmission time within limit, do exponential backoff // else drop the packet and resume if (++rtx_ < rtxLimit_) { delay += max(channel_->txstop() + ifs_ - now, 0.0); int slot = Random::integer(cw_); s.schedule(h, p, delay + slotTime_ * slot); cw_ = min(2 * cw_, cwmax_); } else resume(p); } void MacCsma::endofContention(Packet* p) { Scheduler& s = Scheduler::instance(); double txt = txtime(p) - (s.clock() - txstart_); hdr_mac::access(p)->txtime() = txt; channel_->send(p, txt); s.schedule(&hRes_, &eEoc_, txt); rtx_ = 0; cw_ = cwmin_; } void MacCsmaCd::endofContention(Packet* p) { // If there is a collision, backoff if (channel_->collision()) { channel_->jam(0); backoff(&hSend_, p); } else MacCsma::endofContention(p); } void MacCsmaCa::send(Packet* p) { Scheduler& s = Scheduler::instance(); double delay = channel_->txstop() + ifs_ - s.clock(); if (csense_ && delay > 0) backoff(&hSend_, p); else { txstart_ = s.clock(); channel_->contention(p, &hEoc_); } }

mac-multihop.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the research group may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (UCB)"; #endif #include "template.h" #include "channel.h" #include "mac-multihop.h" /* * For debugging. */ void dump_iphdr(hdr_ip *iph) { printf("\tsrc = %d, ", iph->saddr()); printf("\tdst = %d\n", iph->daddr()); } static class MultihopMacClass : public TclClass { public: MultihopMacClass() : TclClass("Mac/Multihop") {} TclObject* create(int, const char*const*) { return (new MultihopMac); } } class_mac_multihop; MultihopMac::MultihopMac() : mode_(MAC_IDLE), peer_(0), pendingPollEvent_(0), pkt_(0), ph_(this), pah_(this), pnh_(this), pth_(this), bh_(this) { /* Bind a bunch of variables to access from Tcl */ bind_time("tx_rx_", &tx_rx_); bind_time("rx_tx_", &rx_tx_); bind_time("rx_rx_", &rx_rx_); bind_time("backoffBase_", &backoffBase_); backoffTime_ = backoffBase_; } /* * Returns 1 iff the specified MAC is in the prescribed state, AND all * the other MACs are IDLE. */ int
MultihopMac::checkInterfaces(int state) { MultihopMac *p; if (!(mode_ & state)) return 0; else if (macList_ == 0) return 1; for (p = (MultihopMac *)macList_; p != this && p != NULL; p = (MultihopMac *)(p->macList())) { if (p->mode() != MAC_IDLE) { return 0; } } return 1; } /* * Poll a peer node prior to a send. There can be at most one POLL * outstanding from a node at any point in time. This is achieved implicitly * because there can be at most one packet down from LL (thru IFQ) to this MAC. */ void MultihopMac::poll(Packet *p) { Scheduler& s = Scheduler::instance(); MultihopMac *pm = (MultihopMac*) getPeerMac(p); PollEvent *pe = new PollEvent(pm, this); pendingPollEvent_ = new PollEvent(pm, this); pkt_ = p->copy(); /* local copy for poll retries */ double timeout = max(pm->rx_tx(), tx_rx_) + 4*pollTxtime(MAC_POLLSIZE); s.schedule(&bh_, pendingPollEvent_, timeout); /* If the other interfaces are idle, then go ahead, else not. */ if (checkInterfaces(MAC_IDLE)) { mode_ = MAC_POLLING; peer_ = pm; s.schedule(pm->ph(), (Event *)pe, pollTxtime(MAC_POLLSIZE)); } } /* * Handle a POLL request from a peer node's MAC. */ void PollHandler::handle(Event *e) { PollEvent *pe = (PollEvent *) e; Scheduler& s = Scheduler::instance(); MultihopMac* pm = mac_->peer(); /* sensible val only in MAC_RCV mode */ /* * Send POLLACK if either IDLE or currently receiving * from same mac as the poller. */ if (mac_->checkInterfaces(MAC_IDLE)) { // all interfaces must be IDLE mac_->mode(MAC_RCV); pm = pe->peerMac(); mac_->peer(pm); PollEvent *pae = new PollEvent(pm, mac_); // POLLACK event double t = mac_->pollTxtime(MAC_POLLACKSIZE) + max(mac_->tx_rx(), pm->rx_tx()); s.schedule(pm->pah(), pae, t); } else { // printf("ignoring poll %d\n", mac_->label()); // could send NACKPOLL but don't (at least for now) } } /* * Handle a POLLACK from a peer node's MAC. */ void PollAckHandler::handle(Event *e) { PollEvent *pe = (PollEvent *) e; Scheduler& s = Scheduler::instance(); if (mac_->checkInterfaces(MAC_POLLING | MAC_IDLE)) { mac_->backoffTime(mac_->backoffBase()); mac_->mode(MAC_SND); mac_->peer(pe->peerMac()); s.cancel(mac_->pendingPE()); /* cancel pending timeout */ free(mac_->pendingPE()); mac_->pendingPE(NULL); mac_->send(mac_->pkt()); /* send saved packet */ } } void PollNackHandler::handle(Event *) { } void BackoffHandler::handle(Event *) { Scheduler& s = Scheduler::instance(); if (mac_->mode() == MAC_POLLING) mac_->mode(MAC_IDLE); double bTime = mac_->backoffTime(2*mac_->backoffTime()); bTime = (1+Random::integer(MAC_TICK)*1./MAC_TICK)*bTime + 2*mac_->backoffBase(); // printf("backing off %d\n", mac_->label()); s.schedule(mac_->pth(), mac_->pendingPE(), bTime); } void PollTimeoutHandler::handle(Event *) { mac_->poll(mac_->pkt()); } /* * Actually send the data frame. */ void MultihopMac::send(Packet *p) { Scheduler& s = Scheduler::instance(); if (mode_ != MAC_SND) return; double txt = txtime(p); hdr_mac::access(p)->txtime() = txt; channel_->send(p, txt); // target is peer's mac handler s.schedule(callback_, &intr_, txt); // callback to higher layer (LL) mode_ = MAC_IDLE; } /* * This is the call from the higher layer of the protocol stack (i.e., LL) */ void MultihopMac::recv(Packet* p, Handler *h) { if (h == 0) { /* from MAC classifier (pass pkt to LL) */ mode_ = MAC_IDLE; Scheduler::instance().schedule(target_, p, delay_); return; } callback_ = h; hdr_mac* mh = hdr_mac::access(p); mh->macSA() = addr_; if (mh->ftype() == MF_ACK) { mode_ = MAC_SND; send(p); } else { mh->ftype() = MF_DATA; poll(p); /* poll first */ } }

mac-timers.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Ported from CMU/Monarch's code, nov'98 -Padma.*/ #include <delay.h> #include <connector.h> #include <packet.h> #include <random.h> // #define DEBUG //#include <debug.h> #include <arp.h> #include <ll.h> #include <mac.h> #include <mac-timers.h> #include <mac-802_11.h> /* * Force timers to expire on slottime boundries. */ // #define USE_SLOT_TIME #define ROUND_TIME() \ { \ assert(slottime); \ double rmd = remainder(s.clock() + rtime, slottime); \ if(rmd > 0.0) \ rtime += (slottime - rmd); \ else \ rtime += (-rmd); \ } /* ====================================================================== Timers ====================================================================== */ void
MacTimer::start(double time) { Scheduler &s = Scheduler::instance(); assert(busy_ == 0); busy_ = 1; paused_ = 0; stime = s.clock(); rtime = time; assert(rtime >= 0.0); s.schedule(this, &intr, rtime); } void MacTimer::stop(void) { Scheduler &s = Scheduler::instance(); assert(busy_); if(paused_ == 0) s.cancel(&intr); busy_ = 0; paused_ = 0; stime = 0.0; rtime = 0.0; } /* ====================================================================== Defer Timer ====================================================================== */ void DeferTimer::start(double time) { Scheduler &s = Scheduler::instance(); assert(busy_ == 0); busy_ = 1; paused_ = 0; stime = s.clock(); rtime = time; #ifdef USE_SLOT_TIME ROUND_TIME(); #endif assert(rtime >= 0.0); s.schedule(this, &intr, rtime); } void DeferTimer::handle(Event *) { busy_ = 0; paused_ = 0; stime = 0.0; rtime = 0.0; mac->deferHandler(); } /* ====================================================================== NAV Timer ====================================================================== */ void NavTimer::handle(Event *) { busy_ = 0; paused_ = 0; stime = 0.0; rtime = 0.0; mac->navHandler(); } /* ====================================================================== Receive Timer ====================================================================== */ void RxTimer::handle(Event *) { busy_ = 0; paused_ = 0; stime = 0.0; rtime = 0.0; mac->recvHandler(); } /* ====================================================================== Send Timer ====================================================================== */ void TxTimer::handle(Event *) { busy_ = 0; paused_ = 0; stime = 0.0; rtime = 0.0; mac->sendHandler(); } /* ====================================================================== Interface Timer ====================================================================== */ void IFTimer::handle(Event *) { busy_ = 0; paused_ = 0; stime = 0.0; rtime = 0.0; mac->txHandler(); } /* ====================================================================== Backoff Timer ====================================================================== */ void BackoffTimer::handle(Event *) { busy_ = 0; paused_ = 0; stime = 0.0; rtime = 0.0; difs_wait = 0.0; mac->backoffHandler(); } void BackoffTimer::start(int cw, int idle) { Scheduler &s = Scheduler::instance(); assert(busy_ == 0); busy_ = 1; paused_ = 0; stime = s.clock(); rtime = (Random::random() % cw) * mac->phymib_->SlotTime; #ifdef USE_SLOT_TIME ROUND_TIME(); #endif difs_wait = 0.0; if(idle == 0) paused_ = 1; else { assert(rtime >= 0.0); s.schedule(this, &intr, rtime); } } void BackoffTimer::pause() { Scheduler &s = Scheduler::instance(); //the caculation below make validation pass for linux though it // looks dummy double st = s.clock(); double rt = stime + difs_wait; double sr = st - rt; double mst = (mac->phymib_->SlotTime); int slots = int (sr/mst); //int slots = (int) ((s.clock() - (stime + difs_wait)) / mac->phymib_->SlotTime); if(slots < 0) slots = 0; assert(busy_ && ! paused_); paused_ = 1; rtime -= (slots * mac->phymib_->SlotTime); assert(rtime >= 0.0); difs_wait = 0.0; s.cancel(&intr); } void BackoffTimer::resume(double difs) { Scheduler &s = Scheduler::instance(); assert(busy_ && paused_); paused_ = 0; stime = s.clock(); /* * The media should be idle for DIFS time before we start * decrementing the counter, so I add difs time in here. */ difs_wait = difs; /* #ifdef USE_SLOT_TIME ROUND_TIME(); #endif */ assert(rtime + difs_wait >= 0.0); s.schedule(this, &intr, rtime + difs_wait); }

mac.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by Giao Nguyen, http://daedalus.cs.berkeley.edu/~gnguyen */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (UCB)"; #endif //#include "classifier.h" #include <channel.h> #include <mac.h> #include <address.h> int hdr_mac::offset_; static class MacHeaderClass : public PacketHeaderClass { public: MacHeaderClass() : PacketHeaderClass("PacketHeader/Mac", sizeof(hdr_mac)) { bind_offset(&hdr_mac::offset_); } void export_offsets() { field_offset("macSA_", OFFSET(hdr_mac, macSA_)); field_offset("macDA_", OFFSET(hdr_mac, macDA_)); } } class_hdr_mac; static class MacClass : public TclClass { public: MacClass() : TclClass("Mac") {} TclObject* create(int, const char*const*) { return (new Mac); } } class_mac; void
MacHandlerResume::handle(Event*) { mac_->resume(); } void MacHandlerSend::handle(Event* e) { mac_->sendDown((Packet*)e); } /* ================================================================= Mac Class Functions ==================================================================*/ static int MacIndex = 0; Mac::Mac() : BiConnector(), netif_(0), tap_(0), ll_(0), channel_(0), callback_(0), hRes_(this), hSend_(this), state_(MAC_IDLE), pktRx_(0), pktTx_(0) { index_ = MacIndex++; // bandwidth_ = 2.0 * 1e6; bind_bw("bandwidth_", &bandwidth_); off_mac_ = hdr_mac::offset_; bind_time("delay_", &delay_); //bind("off_mac_", &off_mac_); } int Mac::command(int argc, const char*const* argv) { if(argc == 2) { Tcl& tcl = Tcl::instance(); if(strcmp(argv[1], "id") == 0) { tcl.resultf("%d", addr()); return TCL_OK; } else if (strcmp(argv[1], "channel") == 0) { tcl.resultf("%s", channel_->name()); return (TCL_OK); } /*else if (strcmp(argv[1], "classifier") == 0) { tcl.resultf("%s", mcl_->name()); return (TCL_OK); } else if (strcmp(argv[1], "maclist") == 0) { tcl.resultf("%s", macList_->name()); return (TCL_OK); }*/ } else if (argc == 3) { TclObject *obj; if( (obj = TclObject::lookup(argv[2])) == 0) { fprintf(stderr, "%s lookup failed\n", argv[1]); return TCL_ERROR; } // if (strcmp(argv[1], "channel") == 0) { // channel_ = (Channel*) obj; // return (TCL_OK); // } else if (strcmp(argv[1], "netif") == 0) { netif_ = (Phy*) obj; return TCL_OK; } else if (strcmp(argv[1], "log-target") == 0) { logtarget_ = (NsObject*) obj; if(logtarget_ == 0) return TCL_ERROR; return TCL_OK; } // else if (strcmp(argv[1], "up-target") == 0) { // uptarget_ = (NsObject*) obj; // return TCL_OK; //} /* else if (strcmp(argv[1], "down-target") == 0) { downtarget_ = (NsObject*) obj; return TCL_OK; }*/ /*else if (strcmp(argv[1], "classifier") == 0) { mcl_ = (Classifier*) obj; return (TCL_OK); }*/ /*if (strcmp(argv[1], "maclist") == 0) { macList_ = (Mac*) obj; return (TCL_OK); }*/ } return BiConnector::command(argc, argv); } void Mac::recv(Packet* p, Handler* h) { if (hdr_cmn::access(p)->direction() == hdr_cmn::UP) { sendUp(p); return; } callback_ = h; hdr_mac* mh = HDR_MAC(p); mh->set(MF_DATA, index_); state(MAC_SEND); sendDown(p); } void Mac::sendUp(Packet* p) { char* mh = (char*)p->access(hdr_mac::offset_); int dst = this->hdr_dst(mh); state(MAC_IDLE); if (((u_int32_t)dst != MAC_BROADCAST) && (dst != index_)) { drop(p); return; } Scheduler::instance().schedule(uptarget_, p, \ delay_); } void Mac::sendDown(Packet* p) { Scheduler& s = Scheduler::instance(); double txt = txtime(p); downtarget_->recv(p, this); s.schedule(&hRes_, &intr_, txt); } void Mac::resume(Packet* p) { if (p != 0) drop(p); state(MAC_IDLE); callback_->handle(&intr_); } //Mac* Mac::getPeerMac(Packet* p) //{ //return (Mac*) mcl_->slot(hdr_mac::access(p)->macDA()); //}

mcast_ctrl.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * mcast_ctrl.cc * Copyright (C) 1997 by USC/ISI * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include "agent.h" #include "packet.h" #include "mcast_ctrl.h" class mcastControlAgent : public Agent { public: mcastControlAgent() : Agent(PT_NTYPE) { bind("packetSize_", &size_); bind("off_mcast_ctrl_", &off_mcast_ctrl_); } void recv(Packet* pkt, Handler*) { hdr_mcast_ctrl* ph = (hdr_mcast_ctrl*)pkt->access(off_mcast_ctrl_); hdr_cmn* ch = (hdr_cmn*)pkt->access(off_cmn_); // Agent/Mcast/Control instproc recv type from src group iface Tcl::instance().evalf("%s recv %s %d %d", name(), ph->type(), ch->iface(), ph->args()); Packet::free(pkt); } /* * $proc send $type $src $group */ #define CASE(c,str,type) \ case (c): if (strcmp(argv[2], (str)) == 0) { \ type_ = (type); \ break; \ } else { \ /*FALLTHROUGH*/ \ } int command(int argc, const char*const* argv) { if (argc == 4) { if (strcmp(argv[1], "send") == 0) { switch (*argv[2]) { CASE('p', "prune", PT_PRUNE); CASE('g', "graft", PT_GRAFT); CASE('X', "graftAck", PT_GRAFTACK); CASE('j', "join", PT_JOIN); CASE('a', "assert", PT_ASSERT); default: Tcl& tcl = Tcl::instance(); tcl.result("invalid control message"); return (TCL_ERROR); } Packet* pkt = allocpkt(); hdr_mcast_ctrl* ph = (hdr_mcast_ctrl*)pkt->access(off_mcast_ctrl_); strcpy(ph->type(), argv[2]); ph->args() = atoi(argv[3]); send(pkt, 0); return (TCL_OK); } } return (Agent::command(argc, argv)); } protected: int off_mcast_ctrl_; }; // // Now put the standard OTcl linkage templates here // static class mcastControlHeaderClass : public PacketHeaderClass { public: mcastControlHeaderClass() : PacketHeaderClass("PacketHeader/mcastCtrl", sizeof(hdr_mcast_ctrl)) {} } class_mcast_ctrl_hdr; static class mcastControlClass : public TclClass { public: mcastControlClass() : TclClass("Agent/Mcast/Control") {} TclObject* create(int, const char*const*) { return (new mcastControlAgent()); } } class_mcast_ctrl;

measuremod.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ //Basic Measurement block derived from a connector //measures bits sent and average packet delay in a measurement interval #include "packet.h" #include "connector.h" #include "measuremod.h" static class MeasureModClass : public TclClass { public: MeasureModClass() : TclClass("MeasureMod") {} TclObject* create(int, const char*const*) { return (new MeasureMod()); } }class_measuremod; MeasureMod::MeasureMod() : nbits_(0),npkts_(0) { } void
MeasureMod::recv(Packet *p,Handler *h) { hdr_cmn *ch=(hdr_cmn*)p->access(off_cmn_); nbits_ += ch->size()<<3; npkts_++; send(p,h); }

message.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1994-1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include "agent.h" #include "random.h" #include "message.h" int hdr_msg::offset_; static class MessageHeaderClass : public PacketHeaderClass { public: MessageHeaderClass() : PacketHeaderClass("PacketHeader/Message", sizeof(hdr_msg)) { bind_offset(&hdr_msg::offset_); } } class_msghdr; class MessageAgent : public Agent { public: MessageAgent(); int command(int argc, const char*const* argv); void recv(Packet*, Handler*); }; static class MessageClass : public TclClass { public: MessageClass() : TclClass("Agent/Message") {} TclObject* create(int, const char*const*) { return (new MessageAgent()); } } class_message; MessageAgent::MessageAgent() : Agent(PT_MESSAGE) { bind("packetSize_", &size_); } void
MessageAgent::recv(Packet* pkt, Handler*) { hdr_msg* mh = hdr_msg::access(pkt); char wrk[128];/*XXX*/ sprintf(wrk, "%s recv {%s}", name(), mh->msg()); Tcl& tcl = Tcl::instance(); tcl.eval(wrk); Packet::free(pkt); } /* * $proc handler $handler * $proc send $msg */ int MessageAgent::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "send") == 0) { Packet* pkt = allocpkt(); hdr_msg* mh = hdr_msg::access(pkt); const char* s = argv[2]; int n = strlen(s); if (n >= mh->maxmsg()) { tcl.result("message too big"); Packet::free(pkt); return (TCL_ERROR); } strcpy(mh->msg(), s); send(pkt, 0); return (TCL_OK); } } return (Agent::command(argc, argv)); }

mftp.cc


/* * (c) 1997-98 StarBurst Communications Inc. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Author: Christoph Haenle, chris@cs.vu.nl * File: mftp.cc * Last change: Dec 07, 1998 * * This software may freely be used only for non-commercial purposes */ // This file contains functionality common to both MFTP sender and receivers. #include "mftp.h" MFTPAgent::MFTPAgent() : Agent(PT_MFTP), FileSize(0), FileDGrams(0), dtu_size(0), dtus_per_block(0), dtus_per_group(0), nb_groups(0) { bind("dtuSize_", &dtuSize_); bind("fileSize_", &fileSize_); bind("dtusPerBlock_", &dtusPerBlock_); bind("dtusPerGroup_", &dtusPerGroup_); bind("seekCount_", &seekCount_); bind("off_mftp_", &off_mftp_); bind("off_cmn_", &off_cmn_); }; int
MFTPAgent::init() { if(dtusPerBlock_ % 8 != 0) { Tcl& tcl = Tcl::instance(); tcl.resultf("%s: dtusPerBlock_ must be a multiple of 8", name_); return TCL_ERROR; } dtu_size = dtuSize_; FileSize = fileSize_; dtus_per_block = dtusPerBlock_; dtus_per_group = dtusPerGroup_; seekCount_ = 0; FileDGrams = (FileSize + dtu_size - 1) / dtu_size; nb_groups = (FileDGrams + dtus_per_group - 1) / dtus_per_group; return TCL_OK; }

mftp_rcv.cc


/* * (c) 1997-98 StarBurst Communications Inc. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Author: Christoph Haenle, chris@cs.vu.nl * File: mftp_rcv.cc * Last change: Dec 14, 1998 * * This software may freely be used only for non-commercial purposes */ // This file contains functionality specific to an MFTP receiver. #include <assert.h> #include "config.h" #include "tclcl.h" #include "mftp_rcv.h" #include "ip.h" // due to declaration of hdr_ip #define min(a, b) ((a) < (b) ? (a) : (b)) static class MFTPRcvAgentClass : public TclClass { public: MFTPRcvAgentClass() : TclClass("Agent/MFTP/Rcv") {} TclObject* create(int, const char*const*) { return (new MFTPRcvAgent()); } } class_mftprcv_agent; MFTPRcvAgent::MFTPRcvAgent() : MFTPAgent(), CurrentPass(0), CurrentGroup(0), CwPat(0), FileDGramsReceived(0), FseekOffset(0), cw_matrixline_buf(NULL) { bind("reply_addr_", (int*)&reply_.addr_); bind("reply_port_", (int*)&reply_.port_); } // inspect a Tcl command (overloaded function): int
MFTPRcvAgent::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if(strcmp(argv[1], "send") == 0) { if(strcmp(argv[2], "nak") == 0) { unsigned long pass_nb, block_nb; int nb_scanned = 0; nb_scanned += sscanf(argv[3], "%lu", &pass_nb); nb_scanned += sscanf(argv[4], "%lu", &block_nb); assert(nb_scanned == 2); send_nak(pass_nb, block_nb); return TCL_OK; } } else if (strcmp(argv[1], "start") == 0) { if(dtusPerBlock_ % 8 != 0) { tcl.resultf("%s: dtusPerBlock_ must be a multiple of 8", name_); return TCL_ERROR; } init(); return TCL_OK; } return Agent::command(argc, argv); } // process reception of a packet void MFTPRcvAgent::recv(Packet* p, Handler* h) { hdr_ip* ih = (hdr_ip*) p->access(off_ip_); hdr_mftp* mh = (hdr_mftp*) p->access(off_mftp_); if(ih->daddr() == 0) { // packet from local agent fprintf(stderr, "%s: send not allowed with Agent/MFTP/Rcv\n", name_); assert(false); } else { switch(mh->type) { case hdr_mftp::PDU_DATA_TRANSFER: recv_data(mh->spec.data); break; case hdr_mftp::PDU_STATUS_REQUEST: recv_status_req(mh->spec.statReq); break; case hdr_mftp::PDU_NAK: // as we are a member of the group as well, we receive all data we have sent. break; default: assert(false); // received unknown packet type } Packet::free(p); } } // Destructor: MFTPRcvAgent::~MFTPRcvAgent() { // Note: delete on a NULL-pointer has no effect delete [] cw_matrixline_buf; } void MFTPRcvAgent::init() { MFTPAgent::init(); // allocate cw_matrix_line_buf assert(cw_matrixline_buf == NULL); cw_matrixline_buf = new CW_MATRIXLINE_t[FileDGrams]; assert(cw_matrixline_buf != NULL); // or else no memory is left! // should return an error instead of terminating the program // reset array: cw_matrixlines_reset(); } /* process a received status request packet */ void MFTPRcvAgent::recv_status_req(hdr_mftp::Spec::StatReq& statreq) { Tcl& tcl = Tcl::instance(); // read the PDU_STATUS_REQUEST-specific fields: tcl.evalf("%s recv status-req %lu %lu %lu %lf", name_, (unsigned long) statreq.pass_nb, (unsigned long) statreq.block_lo, (unsigned long) statreq.block_hi, (double) statreq.RspBackoffWindow); } // send a nak packet: void MFTPRcvAgent::send_nak(unsigned long pass_nb, unsigned long block_nb) { assert(FileDGrams > 0); assert(0 <= block_nb && block_nb < nb_blocks()); Tcl& tcl = Tcl::instance(); // start_group_nb corresponds to first bit of NAK-bitmap: unsigned long start_group_nb = dtus_per_block * block_nb; // end_group_nb corresponds to last group number of NAK-bitmap plus one unsigned long end_group_nb = min(nb_groups, dtus_per_block * (block_nb + 1)); // number of valid bits in the outgoing nak-bitmap unsigned long n = end_group_nb - start_group_nb; // number of status bytes in pdu const unsigned long nak_bytes = (n+7) / 8; unsigned long bit_count = 0; // allocate (get) new packet and dynamically allocate extra space for nak-bitmap: Packet* p = Agent::allocpkt((n+7) / 8); unsigned char* nak_bitmap = (unsigned char*) p->accessdata(); // clear NAK-bitmap first: memset(nak_bitmap, 0, nak_bytes); // loop over all groups in rangs of nak and set nak-bit for those that are not still full for(unsigned long group_nb = start_group_nb, bit = 1 << (start_group_nb % 8); group_nb < end_group_nb; ++group_nb) { if(is_group_full(group_nb) == false) { *nak_bitmap |= bit; bit_count++; } if(bit == 128) { bit = 1; nak_bitmap++; } else { bit <<= 1; } } if(bit_count > 0) { hdr_ip* iph = (hdr_ip*)p->access(off_ip_); hdr_mftp* hdr = (hdr_mftp*) p->access(off_mftp_); hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); // now generate the header iph->dst() = reply_; // overwrite settings from Agent::allocpkt() ch->size() = sizeof(hdr_mftp); hdr->type = hdr_mftp::PDU_NAK; hdr->spec.nak.pass_nb = pass_nb; hdr->spec.nak.block_nb = block_nb; hdr->spec.nak.nak_count = bit_count; // transmit packet target_->recv(p); } else { Packet::free(p); // do not transmit NAK-packet if it consists of 0 NAK-bits !! // HACK: @ requires optimation still! } tcl.resultf("%lu", bit_count); } // process_packet: decides if a received packet is "useful" and // stores meta-information for proper decoding int MFTPRcvAgent::process_packet(CW_PATTERN_t cw_pat, unsigned long group_nb, unsigned long dtu_nb) { CW_PATTERN_t bit; CW_MATRIXLINE_t new_row; unsigned long j; // j iterates over the dtus of group "group_nb" unsigned long finish = get_dtus_per_group(group_nb); // finish counts the number of dtus in group "group_nb" new_row.left = cw_pat; for(j = 0; j < finish; j++) { CW_PATTERN_t line_pat = cw_matrixline_buf[j * nb_groups + group_nb].left; if(line_pat != 0) { bit = new_row.left & ((CW_PATTERN_t) 1 << minbit(line_pat)); if(bit != 0) { new_row.left ^= line_pat; } } } if(new_row.left != 0) { // linear independent? bit = (CW_PATTERN_t) 1 << minbit(new_row.left); for(j = 0; j < finish; j++) { if((bit & cw_matrixline_buf[j * nb_groups + group_nb].left) != 0) { cw_matrixline_buf[j * nb_groups + group_nb].left ^= new_row.left; } } // register pattern of codeword the received packet is composed of (possibly altered). // must be done at last for that this line gets not erased by XORing with itself // in the previous loop. cw_matrixline_buf[dtu_nb * nb_groups + group_nb].left = new_row.left; return 1; // packet was a "useful" packet (i.e. is linear independent // from the other ones received so far) } else { return 0; //linear dependent codeword-pattern received, i.e. useless } } int MFTPRcvAgent::findStoreLocation(unsigned long group_nb, unsigned long seek_offset, unsigned long* dtu_nb) { unsigned long start_dtu_nb; assert(0 <= group_nb && group_nb < nb_groups); assert(seek_offset % dtu_size == 0 || seek_offset == FileSize); if(seek_offset == FileSize) { *dtu_nb = group_nb; // start over from the beginning } else { unsigned long curr_dtu_nb = FseekOffset / dtu_size; // pay attention to "unsigned" when substracting *dtu_nb = curr_dtu_nb - curr_dtu_nb % nb_groups; *dtu_nb += group_nb; // check if seeking backwards. If yes, increment dtu_nb by nb_groups to // always seeks forwards (unless end of file is reached): if(*dtu_nb < curr_dtu_nb) { *dtu_nb += nb_groups; } } if(*dtu_nb >= FileDGrams) { // this might happen if some groups have less packets than // dtus_per_group: *dtu_nb = group_nb; // start over from the beginning } start_dtu_nb = *dtu_nb; assert(start_dtu_nb < FileDGrams); do { if(! cw_matrixline_buf[*dtu_nb].left) { return 1; } *dtu_nb += nb_groups; if(*dtu_nb >= FileDGrams) { *dtu_nb = group_nb; // start over from the beginning } } while(*dtu_nb != start_dtu_nb); return 0; // group "group_nb" is already full } // initializes all matrix-lines to zero, i.e. no (encoded) packets // at all are received so far: void MFTPRcvAgent::cw_matrixlines_reset() { assert(0 <= FileDGrams); memset(cw_matrixline_buf, 0, sizeof(CW_MATRIXLINE_t) * FileDGrams); } // returns true if group "group_nb" is full, false if there is at least one packet missing bool MFTPRcvAgent::is_group_full(unsigned long group_nb) { unsigned long nb_dtus = get_dtus_per_group(group_nb); unsigned long i; assert(0 <= group_nb && group_nb < nb_groups); for(i = 0; i < nb_dtus && cw_matrixline_buf[i * nb_groups + group_nb].left != 0; ++i) ; return (i == nb_dtus) ? true : false; // if loop was left before nb_dtus was reached, // then there is some line in the matrix that is // all "0", i.e. a packet is still missing. } // recv_data: process received data packet; // takes (received) coded packets and processes them. int MFTPRcvAgent::recv_data(hdr_mftp::Spec::Data& data) { Tcl& tcl = Tcl::instance(); unsigned long seek_offset; unsigned long dtu_nb; // position (in terms of datagram number) where incoming // packet is stored in file // read the PDU_DATA_TRANSFER-specific fields: CurrentPass = data.pass_nb; CurrentGroup = data.group_nb; CwPat = data.cw_pat; // validate fields: // (actually, assert should be replaced by just ignoring the packet in case // the parameters are invalid, as some corrupt packet might reach the receiver // in real world, i.e. this would not be a bug in the software!) assert(0 <= CurrentPass); assert(0 <= CurrentGroup && CurrentGroup < nb_groups); if(findStoreLocation(CurrentGroup, FseekOffset, &dtu_nb)) { // arriving packet belongs to a not already full group: assert(dtu_nb % nb_groups == CurrentGroup); assert(0 <= dtu_nb && dtu_nb < FileDGrams); if(process_packet(CwPat, CurrentGroup, dtu_nb / nb_groups)) { cw_matrixline_buf[dtu_nb].right = CwPat; // arriving packet is useful (i.e. linearly independent from the others // of the group, thus store packet on disk: char buf[8 * sizeof(CW_PATTERN_t) + 1]; CwPat.print(buf); tcl.evalf("%s recv useful %lu %lu %s", name_, (unsigned long) CurrentPass, (unsigned long) CurrentGroup, (char*) buf); seek_offset = dtu_nb * dtu_size; if(dtu_nb == FileDGrams - 1) { // the last dtu of the file might not fit into the file, as with // erasure correction, the dtu size must always be the same, // i.e. dtu_size. So we don't write the packet on disk. // Rather, we store it in a special place in main memory. // (ommitted) } else { // prepare to write the new packet to the file system: if(FseekOffset != seek_offset) { // seek to file-position seek_offset (omitted) FseekOffset = seek_offset; seekCount_++; } // write data to file here (omitted) FseekOffset += dtu_size; } // else // increment number of good dtus received FileDGramsReceived++; // if all packets have been received, decode the file and send a done-message if (FileDGramsReceived == FileDGrams) { // decode file here. Involves the file, the cw_matrixline_buf-array and // the last packet (cached in memory). Additional disk activity for the // receivers will be required. // (omitted) char buf[8 * sizeof(CW_PATTERN_t) + 1]; CwPat.print(buf); tcl.evalf("%s done-notify %lu %lu %s", name_, (unsigned long) CurrentPass, (unsigned long) CurrentGroup, (char*) buf); return(0); // we are ready! } } // if(process_packet...) else { char buf[8 * sizeof(CW_PATTERN_t) + 1]; CwPat.print(buf); tcl.evalf("%s recv dependent %lu %lu %s", name_, (unsigned long) CurrentPass, (unsigned long) CurrentGroup, (char*) buf); return(0); // we are ready! } } // if(findStoreLocation...) else { // we received a packet that belongs to an already full group char buf[8 * sizeof(CW_PATTERN_t) + 1]; CwPat.print(buf); tcl.evalf("%s recv group-full %lu %lu %s", name_, (unsigned long) CurrentPass, (unsigned long) CurrentGroup, (char*) buf); } return(0); }

mftp_snd.cc


/* * (c) 1997-98 StarBurst Communications Inc. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Author: Christoph Haenle, chris@cs.vu.nl * File: mftp_snd.cc * Last change: Dec 07, 1998 * * This software may freely be used only for non-commercial purposes */ // This file contains functionality specific to the MFTP sender. #include <stdlib.h> // strtoul, etc. #include <assert.h> #include <stdio.h> #include "config.h" #include "tclcl.h" #include "agent.h" #include "packet.h" #include "ip.h" #include "mftp_snd.h" #include "trace.h" #include "bitops.h" // due to IS_BITSET, etc. #define min(a, b) ((a) < (b) ? (a) : (b)) static class MFTPSndAgentClass : public TclClass { public: MFTPSndAgentClass() : TclClass("Agent/MFTP/Snd") {} TclObject* create(int, const char*const*) { return (new MFTPSndAgent()); } } class_mftpsnd_agent; static class MFTPHeaderClass : public PacketHeaderClass { public: MFTPHeaderClass() : PacketHeaderClass("PacketHeader/MFTP", sizeof(hdr_mftp)) {} } class_mftphdr; MFTPSndAgent::MFTPSndAgent() : MFTPAgent(), naks(0), retx(0), fseek_offset(0), read_ahead_bufsize(0), CurrentPass(0), CurrentGroup(0), CwPat(0), MinGroupNbInBuf(0), NbGroupsInBuf(0) { bind("readAheadBufsize_", &readAheadBufsize_); bind_time("txStatusDelay_", &txStatusDelay_); bind("nakCount_", &nakCount_); } MFTPSndAgent::~MFTPSndAgent() { delete [] naks; // NOTE: delete on NULL pointer has no effect delete [] retx; } int
MFTPSndAgent::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if(strcmp(argv[1], "send") == 0) { if(strcmp(argv[2], "data") == 0) { return send_data(); } else if(strcmp(argv[2], "statreq") == 0) { unsigned long pass_nb, block_lo, block_hi; double rsp_backoff_window=2343.2343; int nb_scanned = 0; if(argc == 7) { nb_scanned += sscanf(argv[3], "%lu", &pass_nb); nb_scanned += sscanf(argv[4], "%lu", &block_lo); nb_scanned += sscanf(argv[5], "%lu", &block_hi); nb_scanned += sscanf(argv[6], "%lf", &rsp_backoff_window); } if(nb_scanned != 4) { tcl.resultf("%s: wrong number of parameters for \"send statreq\"", name_); return TCL_ERROR; } send_status_request(pass_nb, block_lo, block_hi, rsp_backoff_window); return TCL_OK; } } if(strcmp(argv[1], "start") == 0) { if(MFTPAgent::init() == TCL_ERROR) { return TCL_ERROR; }; init_user_file((unsigned long) readAheadBufsize_); return TCL_OK; } return Agent::command(argc, argv); } void MFTPSndAgent::recv(Packet* p, Handler* h) { hdr_ip* ih = (hdr_ip*) p->access(off_ip_); hdr_mftp* mh = (hdr_mftp*) p->access(off_mftp_); if(ih->daddr() == 0) { assert(false); // Packet from local agent. } else { switch(mh->type) { case hdr_mftp::PDU_DATA_TRANSFER: case hdr_mftp::PDU_STATUS_REQUEST: // as the sender is a member of the multicast group as well, // it receives all data it has sent. So just ignore it. break; case hdr_mftp::PDU_NAK: process_nak(mh->spec.nak, p->accessdata(), CurrentPass-1); // -1 because we have // incremented the pass-number already in send_data. break; default: assert(false); // unknown packet type (also possible: just ignore packet rather than exit) } Packet::free(p); } } void MFTPSndAgent::send_status_request(unsigned long pass_nb, unsigned long block_lo, unsigned long block_hi, double rsp_backoff_window) { Packet* p = Agent::allocpkt(); hdr_mftp* hdr = (hdr_mftp*) p->access(off_mftp_); assert(FileDGrams > 0); // we need this requirement here // initialize the header of the status request packet: hdr->type = hdr_mftp::PDU_STATUS_REQUEST; hdr->spec.statReq.pass_nb = pass_nb; hdr->spec.statReq.block_lo = block_lo; hdr->spec.statReq.block_hi = block_hi; hdr->spec.statReq.RspBackoffWindow = rsp_backoff_window; // transmit packet hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() = sizeof(hdr_mftp); target_->recv(p); } // process incoming nak: void MFTPSndAgent::process_nak(hdr_mftp::Spec::Nak& nak, unsigned char* nak_bitmap, unsigned long currentPass) { assert(1 <= nak.nak_count && nak.nak_count <= nb_groups); // or else some receiver is fooling us. assert(nak.pass_nb <= currentPass); // pass greater than requested? => a receiver is fooling us. Tcl& tcl = Tcl::instance(); tcl.evalf("%s recv nak %lu %lu %lu", name_, (unsigned long) nak.pass_nb, (unsigned long) nak.block_nb, (unsigned long) nak.nak_count); assert(dtus_per_block % 8 == 0); // This property is required for the following // start_group_nb corresponds to first bit of NAK-bitmap: const unsigned long start_group_nb = dtus_per_block * nak.block_nb; // end_group_nb corresponds to last group number of NAK-bitmap plus one const unsigned long end_group_nb = min(nb_groups, dtus_per_block * (nak.block_nb + 1)); // get starting index into naks-array for this block const unsigned long nak_index = start_group_nb / 8; // number of status bytes in pdu const unsigned long nak_bytes = (end_group_nb - start_group_nb + 7) / 8; // pointer to location in array at which the received nak bitmap must be // or'd to the sender-bitmap (the bitmap in which the sender collects the naks) unsigned char* nak_array = naks + nak_index; // if this nak pdu is from a previous pass (i.e. a delayed nak), ignore the status // bits for dtu's that we've just retransmitted in the current pass: if(nak.pass_nb < currentPass) { unsigned char* retx_array = retx + nak_index; for(unsigned long i = 0; i < nak_bytes; i++) { if(*nak_bitmap) { // "AND out" bits for already transmitted packets and // "OR in" the result into newly constructed NAK bitmap *nak_array |= (*nak_bitmap & (~*retx_array)); } nak_array++; retx_array++; nak_bitmap++; } } else { assert(nak.pass_nb == currentPass); // this nak belongs to the current pass for(unsigned long i = 0; i < nak_bytes; i++) { if(*nak_bitmap) { // "OR in" NAK byte into newly constructed NAK bitmap *nak_array |= *nak_bitmap; } nak_array++; nak_bitmap++; } } nakCount_++; // increment total number of received nak-packets } void MFTPSndAgent::init_user_file(unsigned long readAheadBufsize) { read_ahead_bufsize = readAheadBufsize; fseek_offset = 0; // initialize codeword pattern iterator.setSourceWordLen(dtus_per_group); CwPat = iterator.getNextCwPat(); // free arrays from a possible previous transmission (no effect on NULL pointers) delete [] naks; delete [] retx; // allocate naks bitmap init'd to all nak'd: naks = new unsigned char[(nb_groups + 7) / 8]; assert(naks != NULL); // or else we ran out of memory SET_ALL_BITS(naks, nb_groups); // allocate retransmission bitmap init'd to none retransmitted: retx = new unsigned char[(nb_groups + 7) / 8]; assert(retx != NULL); // or else we ran out of memory RESET_ALL_BITS(retx, nb_groups); CurrentPass = CurrentGroup = MinGroupNbInBuf = NbGroupsInBuf = 0; } // reads as many groups into the read-ahead-buffer as there is space, starting with // group CurrentGroup. The groups that were not not NACK'd by anyone will be // skipped (and the corresponding areas in the read-ahead-buffer will be skipped // as well). void MFTPSndAgent::fill_read_ahead_buf() { unsigned int dtu_pos; // loops over [0..dtus_per_group) unsigned long seek_offset; // where to position the head for disk seeks unsigned long buf_pos = 0; // position where data is written (into main memory) when // read from disk, relative to the start of read_ahead_buf CW_PATTERN_t cw_pat_tmp = CwPat; unsigned long i; unsigned long len; // switch to next group that must be read: MinGroupNbInBuf = CurrentGroup; NbGroupsInBuf = min(read_ahead_bufsize / (bitcount(CwPat) * dtu_size), nb_groups - MinGroupNbInBuf); while(cw_pat_tmp != 0) { dtu_pos = minbit(cw_pat_tmp); assert(0 <= dtu_pos && dtu_pos < dtus_per_group); assert(MinGroupNbInBuf + NbGroupsInBuf <= nb_groups); cw_pat_tmp &= ~((CW_PATTERN_t) 1 << dtu_pos); // clear bit at position "dtu_pos" for(i = MinGroupNbInBuf; i < MinGroupNbInBuf + NbGroupsInBuf; ++i) { // continue with for-loop if group i was not NACKed by anyone if(IS_BIT_CLEARED(naks, i)) { buf_pos += dtu_size; continue; } // Note: there is never data accessed "outside" the file as the while-loop // is left as soon as the last (possibly partial) DTU has been read. seek_offset = (dtu_pos * nb_groups + i) * dtu_size; if(seek_offset >= FileSize) { // we can get there if the last group(s) have fewer than // dtus_per_group packets. If we get here, we are ready. return; // OK } if (fseek_offset != seek_offset) { // do the fseek here (omitted) seekCount_++; fseek_offset = seek_offset; } // determine number of bytes to read len = min(dtu_size, FileSize - fseek_offset); // read len bytes from file here (omitted) fseek_offset += len; buf_pos += len; if(len < dtu_size) { // we get here if the last dtu is smaller than dtu_size and if // we have just read that last dtu assert(fseek_offset == FileSize); // we must be at EOF // clear rest of read-ahead-buffer here (omitted) buf_pos = bitcount(CwPat) * NbGroupsInBuf * dtu_size; return; // that's it, no more packets to process } assert(len == dtu_size); assert(buf_pos <= bitcount(CwPat) * NbGroupsInBuf * dtu_size); } // for } // while // we get here only if no group was read with less than dtus_per_group packets and // the if not the last packet was read (in case it is too short) assert(buf_pos == bitcount(CwPat) * NbGroupsInBuf * dtu_size); } // send_data() sends next data packet. // In tcl's result buffer, return // 0, if current pass not yet finished // -1, if reached the end of the current pass int MFTPSndAgent::send_data() { Packet* p = Agent::allocpkt(); hdr_mftp* hdr = (hdr_mftp*) p->access(off_mftp_); CW_PATTERN_t mask; Tcl& tcl = Tcl::instance(); assert(0 <= CurrentGroup && CurrentGroup < nb_groups); assert(NbGroupsInBuf >= 0); assert(0 <= MinGroupNbInBuf && MinGroupNbInBuf + NbGroupsInBuf <= nb_groups); // now comes NACK processing: loop until end of file or until // a nak bit is detected: while(CurrentGroup < nb_groups && IS_BIT_CLEARED(naks, CurrentGroup)) { CurrentGroup++; // proceed to next bit of the nak bitmap } // do not transmit packet if // (1) CurrentGroup has reached the total number of groups ("end of pass") or // (2) CwPat has only bits set that refer to some packets that are cut off in // the current group (for example, if CurrentGroup has only 5 packets // with nb_groups=8 and if CwPat=64+32) if(CurrentGroup != nb_groups && ((mask = (~(CW_PATTERN_t) 0) >> (8 * sizeof(CW_PATTERN_t) - get_dtus_per_group(CurrentGroup))) & CwPat) != 0) { assert(CurrentGroup < nb_groups); // see if the read-ahead-buffer is exhausted so that we must load new data // from file. Only groups with a corresponding NAK-bit are read, that is, // those that were requested for retransmission assert(MinGroupNbInBuf <= CurrentGroup); if(CurrentGroup >= MinGroupNbInBuf + NbGroupsInBuf) { // exhausted? fill_read_ahead_buf(); // load new data from file } assert(MinGroupNbInBuf <= CurrentGroup && CurrentGroup < MinGroupNbInBuf + NbGroupsInBuf); // produce an encoded packet here (omitted) // generate the header hdr->type = hdr_mftp::PDU_DATA_TRANSFER; hdr->spec.data.pass_nb = CurrentPass; hdr->spec.data.group_nb = CurrentGroup; hdr->spec.data.cw_pat = CwPat & mask; char buf[8 * sizeof(CW_PATTERN_t) + 1]; (CwPat & mask).print(buf); tcl.evalf("%s send notify %lu %lu %s", name_, (unsigned long) CurrentPass, (unsigned long) CurrentGroup, (char*) buf); hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() = sizeof(hdr_mftp) + dtu_size; // transmit packet target_->recv(p); RESET_BIT(naks, CurrentGroup); // reset the dtu status bit in the nak bitmap SET_BIT(retx, CurrentGroup); // set the dtus status bit in the retransmission bitmap CurrentGroup++; } // if // if last group of the file: if(CurrentGroup == nb_groups || !(CwPat & mask)) { // end of pass? do { CwPat = iterator.getNextCwPat(); // get next codeword for new pass } while(!(CwPat & ((~(CW_PATTERN_t) 0) >> (8 * sizeof(CW_PATTERN_t) - get_dtus_per_group(0))))); // } while(!(CwPat & ((((CW_PATTERN_t) 1) << get_dtus_per_group(0)) - 1))); // prepare a new pas: MinGroupNbInBuf = 0; NbGroupsInBuf = 0; CurrentGroup = 0; // reset retransmission bitmap for dealing with of latent naks RESET_ALL_BITS(retx, nb_groups); // the first dtus_per_group passes must be transmitted "in full" if(CurrentPass < dtus_per_group - 1) { SET_ALL_BITS(naks, nb_groups); } tcl.evalf("%s pass-finished %lu %lu", name_, (unsigned long) CurrentPass, (unsigned long) nb_blocks()); CurrentPass++; tcl.result("-1"); // return end-of-pass to the caller return TCL_OK; } tcl.result("0"); // end-of-pass not yet reached return TCL_OK; }

mip-reg.cc


/* * Copyright (c) Sun Microsystems, Inc. 1998 All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sun Microsystems, Inc. * * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS * SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is provided "as is" * without express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this software. */ // #ident "@(#)mip-reg.cc 1.4 98/08/30 SMI" #include <template.h> #include <mip.h> #include <random.h> #include <address.h> #include <mobilenode.h> #define AGENT_ADS_SIZE 48 #define REG_REQUEST_SIZE 52 static class MIPHeaderClass : public PacketHeaderClass { public: MIPHeaderClass() : PacketHeaderClass("PacketHeader/MIP", sizeof(hdr_mip)) { } } class_miphdr; static class MIPBSAgentClass : public TclClass { public: MIPBSAgentClass() : TclClass("Agent/MIPBS") {} TclObject* create(int, const char*const*) { return (new MIPBSAgent()); } } class_mipbsagent; MIPBSAgent::MIPBSAgent() : Agent(PT_UDP), beacon_(1.0), bcast_target_(0), ragent_(0), timer_(this), adlftm_(~0) { bind("adSize_", &size_); //bind("shift_", &shift_); //bind("mask_", &mask_); bind("ad_lifetime_", &adlftm_); bind("off_mip_", &off_mip_); size_ = AGENT_ADS_SIZE; seqno_ = -1; } void
MIPBSAgent::recv(Packet* p, Handler *) { Tcl& tcl = Tcl::instance(); char *objname = NULL; NsObject *obj = NULL; hdr_mip *miph = (hdr_mip *)p->access(off_mip_); hdr_ip *iph = (hdr_ip *)p->access(off_ip_); hdr_cmn *ch = (hdr_cmn*)p->access(off_cmn_); int nodeaddr = Address::instance().get_nodeaddr(addr()); switch (miph->type_) { case MIPT_REG_REQUEST: //if (miph->ha_ == (addr_ >> shift_ & mask_)) { if (miph->ha_ == (Address::instance().get_nodeaddr(addr()))){ if (miph->ha_ == miph->coa_) { // back home tcl.evalf("%s clear-reg %d", name_, miph->haddr_); } else { tcl.evalf("%s encap-route %d %d %lf", name_, miph->haddr_, miph->coa_, miph->lifetime_); } iph->dst() = iph->src(); miph->type_ = MIPT_REG_REPLY; } else { //iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (miph->ha_ & mask_) << shift_; iph->daddr() = miph->ha_; iph->dport() = 0; } iph->saddr() = addr(); iph->sport() = port(); // by now should be back to normal route // if dst is the mobile // also initialise forward counter to 0. otherwise routing // agent is going to think pkt is looping and drop it!! ch->num_forwards() = 0; send(p, 0); break; case MIPT_REG_REPLY: //assert(miph->coa_ == (addr_ >> shift_ & mask_)); assert(miph->coa_ == nodeaddr); tcl.evalf("%s get-link %d %d", name_, nodeaddr, miph->haddr_); // // XXX hacking mobileip. all this should go away // when mobileIP for sun-wired model is no longer reqd. // obj = (NsObject*)tcl.lookup(objname = tcl.result()); if (strlen(objname) == 0) objname = "XXX"; tcl.evalf("%s decap-route %d %s %lf", name_, miph->haddr_, objname, miph->lifetime_); iph->src() = iph->dst(); //iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) |(miph->haddr_ & mask_) << shift_; iph->daddr() = miph->haddr_; iph->dport() = 0; if (obj == NULL) obj = ragent_; obj->recv(p, (Handler*)0); break; case MIPT_SOL: //tcl.evalf("%s get-link %d %d", name_, addr_ >> shift_ & mask_,miph->haddr_); tcl.evalf("%s get-link %d %d",name_,nodeaddr,miph->haddr_); send_ads(miph->haddr_, (NsObject*)tcl.lookup(tcl.result())); Packet::free(p); break; default: Packet::free(p); break; } } void MIPBSAgent::timeout(int ) { send_ads(); timer_.resched(beacon_); } int MIPBSAgent::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "beacon-period") == 0) { beacon_ = atof(argv[2]); timer_.resched(Random::uniform(0, beacon_)); return TCL_OK; } if (strcmp(argv[1], "bcast-target") == 0) { bcast_target_ = (NsObject *)TclObject::lookup(argv[2]); return TCL_OK; } if (strcmp(argv[1], "ragent") == 0) { ragent_ = (NsObject *)TclObject::lookup(argv[2]); return TCL_OK; } } return (Agent::command(argc, argv)); } void MIPBSAgent::send_ads(int dst, NsObject *target) { Packet *p = allocpkt(); hdr_mip *h = (hdr_mip *)p->access(off_mip_); hdr_ip *iph = (hdr_ip *)p->access(off_ip_); h->haddr_ = h->ha_ = -1; //h->coa_ = addr_ >> shift_ & mask_; h->coa_ = Address::instance().get_nodeaddr(addr()); h->type_ = MIPT_ADS; h->lifetime_ = adlftm_; h->seqno_ = ++seqno_; if (dst != -1) { //hdr_ip *iph = (hdr_ip *)p->access(off_ip_); //iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (dst & mask_) << shift_; iph->daddr() = dst; iph->dport() = 0; } else { // if bcast pkt sendOutBCastPkt(p); } if (target == NULL) { if (bcast_target_) bcast_target_->recv(p, (Handler*) 0); else if (target_) target_->recv(p, (Handler*) 0); else Packet::free(p); // drop; may log in future code } else target->recv(p, (Handler*)0); } void MIPBSAgent::sendOutBCastPkt(Packet *p) { hdr_ip *iph = (hdr_ip*)p->access(off_ip_); hdr_cmn *hdrc = (hdr_cmn *)p->access (off_cmn_); hdrc->next_hop_ = IP_BROADCAST; hdrc->addr_type_ = NS_AF_INET; iph->daddr() = IP_BROADCAST; iph->dport() = 0; } void AgtListTimer::expire(Event *) { a_->timeout(MIP_TIMER_AGTLIST); } static class MIPMHAgentClass : public TclClass { public: MIPMHAgentClass() : TclClass("Agent/MIPMH") {} TclObject* create(int, const char*const*) { return (new MIPMHAgent()); } } class_mipmhagent; MIPMHAgent::MIPMHAgent() : Agent(PT_UDP), ha_(-1), coa_(-1), beacon_(1.0),bcast_target_(0),agts_(0),rtx_timer_(this), agtlist_timer_(this),reglftm_(~0),adlftm_(0.0), node_ (0) { bind("home_agent_", &ha_); bind("rreqSize_", &size_); bind("reg_rtx_", &reg_rtx_); //bind("shift_", &shift_); //bind("mask_", &mask_); bind("reg_lifetime_", &reglftm_); bind("off_mip_", &off_mip_); size_ = REG_REQUEST_SIZE; seqno_ = -1; } void MIPMHAgent::recv(Packet* p, Handler *) { Tcl& tcl = Tcl::instance(); hdr_mip *miph = (hdr_mip *)p->access(off_mip_); switch (miph->type_) { case MIPT_REG_REPLY: if (miph->coa_ != coa_) break; // not pending tcl.evalf("%s update-reg %d", name_, coa_); if (rtx_timer_.status() == TIMER_PENDING) rtx_timer_.cancel(); break; case MIPT_ADS: { AgentList **ppagts = &agts_, *ptr; while (*ppagts) { if ((*ppagts)->node_ == miph->coa_) break; ppagts = &(*ppagts)->next_; } if (*ppagts) { ptr = *ppagts; *ppagts = ptr->next_; ptr->expire_time_ = beacon_ + Scheduler::instance().clock(); ptr->lifetime_ = miph->lifetime_; ptr->next_ = agts_; agts_ = ptr; if (coa_ == miph->coa_) { seqno_++; reg(); } } else { // new ads ptr = new AgentList; ptr->node_ = miph->coa_; ptr->expire_time_ = beacon_ + Scheduler::instance().clock(); ptr->lifetime_ = miph->lifetime_; ptr->next_ = agts_; agts_ = ptr; coa_ = miph->coa_; // The MHagent now should update the Mobilenode // about the changed coa_ : node updates its // base-station to new coa_ accordingly. if(node_) node_->set_base_stn(coa_); adlftm_ = miph->lifetime_; seqno_++; reg(); } } break; default: break; } Packet::free(p); } void MIPMHAgent::timeout(int tno) { switch (tno) { case MIP_TIMER_SIMPLE: reg(); break; case MIP_TIMER_AGTLIST: { double now = Scheduler::instance().clock(); AgentList **ppagts = &agts_, *ptr; int coalost = 0; while (*ppagts) { if ((*ppagts)->expire_time_ < now) { ptr = *ppagts; *ppagts = ptr->next_; if (ptr->node_ == coa_) { coa_ = -1; coalost = 1; } delete ptr; } else ppagts = &(*ppagts)->next_; } agtlist_timer_.resched(beacon_); if (coalost) { seqno_++; reg(); } } break; default: break; } } int MIPMHAgent::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "beacon-period") == 0) { beacon_ = atof(argv[2]); timeout(MIP_TIMER_AGTLIST); agtlist_timer_.resched(beacon_); rtx_timer_.resched(Random::uniform(0, beacon_)); return TCL_OK; } else if (strcmp(argv[1], "bcast-target") == 0) { bcast_target_ = (NsObject *)TclObject::lookup(argv[2]); return TCL_OK; } else if (strcmp (argv[1], "node") == 0) { node_ = (MobileNode*)TclObject::lookup(argv[2]); if (node_ == 0) { fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]); return TCL_ERROR; } return TCL_OK; } } // later: agent solicitation (now done!), start of simulation, ... return (Agent::command(argc, argv)); } void MIPMHAgent::reg() { rtx_timer_.resched(reg_rtx_); if (agts_ == 0) { send_sols(); return; } if (coa_ < 0) { coa_ = agts_->node_; adlftm_ = agts_->lifetime_; } Tcl& tcl = Tcl::instance(); Packet *p = allocpkt(); hdr_ip *iph = (hdr_ip *)p->access(off_ip_); //iph->dst() = iph->dst() & ~(~(nsaddr_t)0 << shift_) | (coa_ & mask_) << shift_; iph->daddr() = coa_; iph->dport() = 0; hdr_mip *h = (hdr_mip *)p->access(off_mip_); //h->haddr_ = addr_ >> shift_ & mask_; h->haddr_ = Address::instance().get_nodeaddr(addr()); h->ha_ = ha_; h->coa_ = coa_; h->type_ = MIPT_REG_REQUEST; h->lifetime_ = min(reglftm_, adlftm_); h->seqno_ = seqno_; tcl.evalf("%s get-link %d %d", name_, h->haddr_, coa_); NsObject *target = (NsObject *)tcl.lookup(tcl.result()); if (target != NULL) ((NsObject *)tcl.lookup(tcl.result()))->recv(p, (Handler*) 0); else send(p, 0); } void MIPMHAgent::send_sols() { Packet *p = allocpkt(); hdr_mip *h = (hdr_mip *)p->access(off_mip_); h->coa_ = -1; //h->haddr_ = addr_ >> shift_ & mask_; h->haddr_ = Address::instance().get_nodeaddr(addr()); h->ha_ = ha_; h->type_ = MIPT_SOL; h->lifetime_ = reglftm_; h->seqno_ = seqno_; sendOutBCastPkt(p); if (bcast_target_) bcast_target_->recv(p, (Handler*) 0); else if (target_) target_->recv(p, (Handler*) 0); else Packet::free(p); // drop; may log in future code } void MIPMHAgent::sendOutBCastPkt(Packet *p) { hdr_ip *iph = (hdr_ip*)p->access(off_ip_); hdr_cmn *hdrc = (hdr_cmn *)p->access (off_cmn_); hdrc->next_hop_ = IP_BROADCAST; hdrc->addr_type_ = NS_AF_INET; iph->daddr() = IP_BROADCAST; iph->dport() = 0; }

mip.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Sun Microsystems, Inc. 1998 All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sun Microsystems, Inc. * * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or * promote products derived from this software without specific prior * written permission. * * SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS * SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is provided "as is" * without express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this software. */ // #ident "@(#)mip.cc 1.4 98/08/21 SMI" #include <address.h> #include "mip.h" #define IP_HEADER_SIZE 20 static class IPinIPHeaderClass : public PacketHeaderClass { public: IPinIPHeaderClass() : PacketHeaderClass("PacketHeader/IPinIP", sizeof(hdr_ipinip*)) { } } class_ipiniphdr; static class MIPEncapsulatorClass : public TclClass { public: MIPEncapsulatorClass() : TclClass("MIPEncapsulator") {} TclObject* create(int, const char*const*) { return (new MIPEncapsulator()); } } class_mipencapsulator; MIPEncapsulator::MIPEncapsulator() : Connector(), mask_(0xffffffff), shift_(8), defttl_(32) { bind("addr_", (int*)&(here_.addr_)); bind("port_", (int*)&(here_.port_)); bind("shift_", &shift_); bind("mask_", &mask_); bind("off_ip_", &off_ip_); bind("off_ipinip_", &off_ipinip_); bind("ttl_", &defttl_); } void
MIPEncapsulator::recv(Packet* p, Handler *h) { Tcl& tcl = Tcl::instance(); hdr_ip* hdr = (hdr_ip*)p->access(off_ip_); hdr_ipinip **ppinhdr = (hdr_ipinip **)p->access(off_ipinip_); if (--hdr->ttl_ <= 0) { /* * XXX this should be "dropped" somehow. Right now, * these events aren't traced. */ hdr_ipinip *ptr = *ppinhdr, *temp; while (ptr != NULL) { temp = ptr; ptr = ptr->next_; delete temp; } *ppinhdr = NULL; Packet::free(p); return; } hdr_ipinip *inhdr = new hdr_ipinip; //int dst = ((hdr->dst() >> shift_) & mask_); int dst = Address::instance().get_nodeaddr(hdr->daddr()); tcl.evalf("%s tunnel-exit %d", name_, dst); int te = atoi(tcl.result()); inhdr->next_ = *ppinhdr; *ppinhdr = inhdr; inhdr->hdr_ = *hdr; hdr->saddr() = here_.addr_; hdr->sport() = here_.port_; //hdr->dst() = addr_ & ~(~(nsaddr_t)0 << shift_) | (te & mask_) << shift_;; hdr->daddr() = te; hdr->dport() = 1; hdr->ttl() = defttl_; ((hdr_cmn*)p->access(off_cmn_))->size() += IP_HEADER_SIZE; target_->recv(p,h); } static class MIPDecapsulatorClass : public TclClass { public: MIPDecapsulatorClass() : TclClass("Classifier/Addr/MIPDecapsulator") {} TclObject* create(int, const char*const*) { return (new MIPDecapsulator()); } } class_mipdecapsulator; MIPDecapsulator::MIPDecapsulator() : AddressClassifier() { //def_target_ = NULL; bind("off_ipinip_", &off_ipinip_); bind("off_ip_", &off_ip_); } // int MIPDecapsulator::command(int argc, const char*const* argv) // { // if (argc == 3) { // if (strcmp(argv[1], "def-target") == 0) { // def_target_ = (NsObject *)TclObject::lookup(argv[2]); // return TCL_OK; // } // } // return (AddressClassifier::command(argc, argv)); // } void MIPDecapsulator::recv(Packet* p, Handler *h) { hdr_ipinip **ppinhdr = (hdr_ipinip **)p->access(off_ipinip_); // restore inner header hdr_ip *pouthdr = (hdr_ip *)p->access(off_ip_); assert(ppinhdr); hdr_ip *pinhdr = &(*ppinhdr)->hdr_; *ppinhdr = (*ppinhdr)->next_; *pouthdr = *pinhdr; NsObject* link = find(p); // for mobilenodes use default-target which is probably the // RA. cannot use node_entry point instead, as hier address // of MH point to HA. hence hand decapsulated pkt directly // to RA. if (link == NULL || pinhdr->ttl_ <= 0) { /* * XXX this should be "dropped" somehow. Right now, * these events aren't traced. */ hdr_ipinip *ptr = *ppinhdr, *temp; while (ptr != NULL) { temp = ptr; ptr = ptr->next_; delete temp; } *ppinhdr = NULL; delete pinhdr; Packet::free(p); return; } delete pinhdr; ((hdr_cmn*)p->access(off_cmn_))->size() -= IP_HEADER_SIZE; link->recv(p,h); }

misc.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1994 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * miscellaneous "ns" commands */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include <stdlib.h> #include <math.h> #ifndef WIN32 #include <sys/time.h> #endif #include <ctype.h> #include "config.h" #include "scheduler.h" #include "random.h" #if defined(HAVE_INT64) class Add64Command : public TclCommand { public: Add64Command() : TclCommand("ns-add64") {} virtual int command(int argc, const char*const* argv); }; int
Add64Command::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { char res[22]; /* A 64 bit int at most 20 digits */ int64_t d1 = STRTOI64(argv[1], NULL, 0); int64_t d2 = STRTOI64(argv[2], NULL, 0); sprintf(res, STRTOI64_FMTSTR, d1+d2); tcl.resultf("%s", res); return (TCL_OK); } tcl.add_error("ns-add64 requires two arguments."); return (TCL_ERROR); } #endif class RandomCommand : public TclCommand { public: RandomCommand() : TclCommand("ns-random") { } virtual int command(int argc, const char*const* argv); }; /* * ns-random * ns-random $seed */ int RandomCommand::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 1) { sprintf(tcl.buffer(), "%u", Random::random()); tcl.result(tcl.buffer()); } else if (argc == 2) { int seed = atoi(argv[1]); if (seed == 0) seed = Random::seed_heuristically(); else Random::seed(seed); tcl.resultf("%d", seed); } return (TCL_OK); } extern "C" char version_string[]; class VersionCommand : public TclCommand { public: VersionCommand() : TclCommand("ns-version") { } virtual int command(int, const char*const*) { Tcl::instance().result(version_string); return (TCL_OK); } }; class TimeAtofCommand : public TclCommand { public: TimeAtofCommand() : TclCommand("time_atof") { } virtual int command(int argc, const char*const* argv) { if (argc != 2) return (TCL_ERROR); char* s = (char*) argv[1]; char wrk[32]; char* cp = wrk; while (isdigit(*s) || *s == 'e' || *s == '+' || *s == '-' || *s == '.') *cp++ = *s++; *cp = 0; double v = atof(wrk); switch (*s) { case 'm': v *= 1e-3; break; case 'u': v *= 1e-6; break; case 'n': v *= 1e-9; break; case 'p': v *= 1e-12; break; } Tcl::instance().resultf("%g", v); return (TCL_OK); } }; void init_misc(void) { (void)new VersionCommand; (void)new RandomCommand; (void)new TimeAtofCommand; #if defined(HAVE_INT64) (void)new Add64Command; #endif }

mobilenode.cc


/*-*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Ported from CMU/Monarch's code, nov'98 -Padma. * CMU-Monarch project's Mobility extensions ported by Padma Haldar, * 11/98. */ #include <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
PositionHandler::handle(Event*) { Scheduler& s = Scheduler::instance(); #if 0 fprintf(stderr, "*** POSITION HANDLER for node %d (time: %f) ***\n", node->address(), s.clock()); #endif /* * Update current location */ node->update_position(); /* * Choose a new random speed and direction */ #ifdef DEBUG fprintf(stderr, "%d - %s: calling random_destination()\n", node->address_, __PRETTY_FUNCTION__); #endif node->random_destination(); s.schedule(&node->pos_handle, &node->pos_intr, node->position_update_interval); } /* ====================================================================== Mobile Node ====================================================================== */ MobileNode::MobileNode(void) : Node(), pos_handle(this) #ifdef NAM_TRACE , namChan_(0) #endif { X = 0.0; Y = 0.0; Z = 0.0; speed = 0.0; dX=0.0; dY=0.0; dZ=0.0; destX=0.0; destY=0.0; // address_ = MobileNodeIndex++; random_motion_ = 0; base_stn_ = -1; T = 0; position_update_interval = POSITION_UPDATE_INTERVAL; position_update_time = 0.0; LIST_INSERT_HEAD(&nodehead, this, link); // node list LIST_INIT(&ifhead_); // interface list bind("X_", &X); bind("Y_", &Y); bind("Z_", &Z); bind("speed_", &speed); // bind("position_update_interval_", &position_update_interval); } int MobileNode::command(int argc, const char*const* argv) { if(argc == 2) { //Tcl& tcl = Tcl::instance(); // if(strcmp(argv[1], "id") == 0) { // tcl.resultf("%d", address_); // return TCL_OK; // } if(strcmp(argv[1], "start") == 0) { start(); return TCL_OK; } if(strcmp(argv[1], "log-movement") == 0) { #ifdef DEBUG fprintf(stderr, "%d - %s: calling update_position()\n", address_, __PRETTY_FUNCTION__); #endif update_position(); log_movement(); return TCL_OK; } if(strcmp(argv[1], "log-energy") == 0) { log_energy(1); return TCL_OK; } } else if(argc == 3) { if(strcmp(argv[1], "radius") == 0) { radius_ = strtod(argv[2],NULL); return TCL_OK; } if(strcmp(argv[1], "namattach") == 0) { Tcl& tcl = Tcl::instance(); int mode; const char* id = argv[2]; namChan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); if (namChan_ == 0) { tcl.resultf("trace: can't attach %s for writing", id); return (TCL_ERROR); } return (TCL_OK); } if(strcmp(argv[1], "random-motion") == 0) { random_motion_ = atoi(argv[2]); return TCL_OK; } else if(strcmp(argv[1], "addif") == 0) { WirelessPhy *n = (WirelessPhy*) TclObject::lookup(argv[2]); if(n == 0) return TCL_ERROR; n->insertnode(&ifhead_); n->setnode(this); return TCL_OK; } else if(strcmp(argv[1], "topography") == 0) { T = (Topography*) TclObject::lookup(argv[2]); if(T == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "log-target") == 0) { log_target = (Trace*) TclObject::lookup(argv[2]); if(log_target == 0) return TCL_ERROR; return TCL_OK; } else if (strcmp(argv[1],"base-station") == 0) { //base_stn_ = (MobileNode*) TclObject::lookup(argv[2]); base_stn_ = atoi(argv[2]); if(base_stn_ == -1) return TCL_ERROR; return TCL_OK; } } else if (argc == 5) { if (strcmp(argv[1], "setdest") == 0) { /* <mobilenode> setdest <X> <Y> <speed> */ #ifdef DEBUG fprintf(stderr, "%d - %s: calling set_destination()\n", address_, __FUNCTION__); #endif if(set_destination(atof(argv[2]), atof(argv[3]), atof(argv[4])) < 0) return TCL_ERROR; return TCL_OK; } } return Node::command(argc, argv); } /* ====================================================================== Other class functions ====================================================================== */ void MobileNode::dump(void) { Phy *n; fprintf(stdout, "Index: %d\n", address_); fprintf(stdout, "Network Interface List\n"); for(n = ifhead_.lh_first; n; n = n->nextnode() ) n->dump(); fprintf(stdout, "--------------------------------------------------\n"); } /* ====================================================================== Position Functions ====================================================================== */ void MobileNode::start() { Scheduler& s = Scheduler::instance(); if(random_motion_ == 0) { log_movement(); return; } assert(initialized()); random_position(); #ifdef DEBUG fprintf(stderr, "%d - %s: calling random_destination()\n", address_, __PRETTY_FUNCTION__); #endif random_destination(); s.schedule(&pos_handle, &pos_intr, position_update_interval); } void MobileNode::log_movement() { if (!log_target) return; Scheduler& s = Scheduler::instance(); sprintf(log_target->buffer(), "M %.5f %d (%.2f, %.2f, %.2f), (%.2f, %.2f), %.2f", s.clock(), address_, X, Y, Z, destX, destY, speed); log_target->dump(); } void MobileNode::log_energy(int flag) { if(!log_target) return; Scheduler &s = Scheduler::instance(); if (flag) { sprintf(log_target->buffer(),"N -t %f -n %d -e %f", s.clock(), address_,energy()); } else { sprintf(log_target->buffer(),"N -t %f -n %d -e 0 ", s.clock(), address_); } log_target->dump(); } void MobileNode::idle_energy_patch(float total, float P_idle) { float real_idle = total-(total_sndtime_+total_rcvtime_+total_sleeptime_); //printf("total=%f send=%f rcv=%f, slp=%f\n",total, total_sndtime_,total_rcvtime_,total_sleeptime_); //printf("real_idle=%f\n",real_idle); energy_model_-> DecrIdleEnergy(real_idle, P_idle); //set node energy into zero if ((this->energy_model())->energy() < 0) { // saying node died this->energy_model()->setenergy(0); this->log_energy(0); } } void MobileNode::bound_position() { double minX; double maxX; double minY; double maxY; int recheck = 1; assert(T != 0); minX = T->lowerX(); maxX = T->upperX(); minY = T->lowerY(); maxY = T->upperY(); while(recheck) { recheck = 0; if(X < minX) { X = minX + (minX - X); recheck = 1; } if(X > maxX) { X = maxX - (X - maxX); recheck = 1; } if(Y < minY) { Y = minY + (minY - Y); recheck = 1; } if(Y > maxY) { Y = maxY- (Y - maxY); recheck = 1; } if(recheck) { fprintf(stderr, "Adjust position of node %d\n",address_); } } } int MobileNode::set_destination(double x, double y, double s) { assert(initialized()); if(x >= T->upperX() || x <= T->lowerX()) return -1; if(y >= T->upperY() || y <= T->lowerY()) return -1; update_position(); // figure out where we are now destX = x; destY = y; speed = s; dX = destX - X; dY = destY - Y; dZ = 0.0; // this isn't used, since flying isn't allowed if(destX != X || destY != Y) { // normalize dx, dy to unit len double len = sqrt( (dX * dX) + (dY * dY) ); dX /= len; dY /= len; } position_update_time = Scheduler::instance().clock(); #ifdef DEBUG fprintf(stderr, "%d - %s: calling log_movement()\n", address_, __FUNCTION__); #endif log_movement(); /* update gridkeeper */ if (GridKeeper::instance()){ GridKeeper* gp = GridKeeper::instance(); gp-> new_moves(this); } #ifdef NAM_TRACE if (namChan_ != 0) { sprintf(nwrk_, "n -t %f -s %d -x %f -y %f -u %f -v %f -T %f", Scheduler::instance().clock(), nodeid_, X,Y, speed*dX, speed*dY, ((speed*dX) != 0 ) ? (destX-X)/(speed*dX) : speed*dX ); namdump(); } #endif return 0; } #ifdef NAM_TRACE void MobileNode::namdump() { int n = 0; /* Otherwise nwrk_ isn't initialized */ if (namChan_ != 0) n = strlen(nwrk_); if ((n > 0) && (namChan_ != 0)) { /* * tack on a newline (temporarily) instead * of doing two writes */ nwrk_[n] = '\n'; nwrk_[n + 1] = 0; (void)Tcl_Write(namChan_, nwrk_, n + 1); nwrk_[n] = 0; } } #endif void MobileNode::update_position() { double now = Scheduler::instance().clock(); double interval = now - position_update_time; if(interval == 0.0) return; X += dX * (speed * interval); Y += dY * (speed * interval); if ((dX > 0 && X > destX) || (dX < 0 && X < destX)) X = destX; // correct overshoot (slow? XXX) if ((dY > 0 && Y > destY) || (dY < 0 && Y < destY)) Y = destY; // correct overshoot (slow? XXX) bound_position(); Z = T->height(X, Y); #if 0 fprintf(stderr, "Node: %d, X: %6.2f, Y: %6.2f, Z: %6.2f, time: %f\n", address_, X, Y, Z, now); #endif position_update_time = now; } void MobileNode::random_position() { if(T == 0) { fprintf(stderr, "No TOPOLOGY assigned\n"); exit(1); } X = Random::uniform() * T->upperX(); Y = Random::uniform() * T->upperY(); Z = T->height(X, Y); position_update_time = 0.0; } void MobileNode::random_destination() { if(T == 0) { fprintf(stderr, "No TOPOLOGY assigned\n"); exit(1); } random_speed(); #ifdef DEBUG fprintf(stderr, "%d - %s: calling set_destination()\n", address_, __FUNCTION__); #endif (void) set_destination(Random::uniform() * T->upperX(), Random::uniform() * T->upperY(), speed); } void MobileNode::random_direction() { /* this code isn't used anymore -dam 1/22/98 */ double len; dX = (double) Random::random(); dY = (double) Random::random(); len = sqrt( (dX * dX) + (dY * dY) ); dX /= len; dY /= len; dZ = 0.0; // we're not flying... /* * Determine the sign of each component of the * direction vector. */ if(X > (T->upperX() - 2*T->resol())) { if(dX > 0) dX = -dX; } else if(X < (T->lowerX() + 2*T->resol())) { if(dX < 0) dX = -dX; } else if(Random::uniform() <= 0.5) { dX = -dX; } if(Y > (T->upperY() - 2*T->resol())) { if(dY > 0) dY = -dY; } else if(Y < (T->lowerY() + 2*T->resol())) { if(dY < 0) dY = -dY; } else if(Random::uniform() <= 0.5) { dY = -dY; } #if 0 fprintf(stderr, "Location: (%f, %f), Direction: (%f, %f)\n", X, Y, dX, dY); #endif } void MobileNode::random_speed() { speed = Random::uniform() * MAX_SPEED; } double MobileNode::distance(MobileNode *m) { update_position(); // update my position m->update_position(); // update m's position double Xpos = (X - m->X) * (X - m->X); double Ypos = (Y - m->Y) * (Y - m->Y); double Zpos = (Z - m->Z) * (Z - m->Z); return sqrt(Xpos + Ypos + Zpos); } double MobileNode::propdelay(MobileNode *m) { return distance(m) / SPEED_OF_LIGHT; }

modulation.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Ported from CMU/Monarch's code, nov'98 -Padma.*/ #include <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; }

ms-adc.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif //Measured Sum Admission control #include "adc.h" #include <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_; };
MS_ADC::MS_ADC() { bind("utilization_",&utilization_); type_ = new char[5]; strcpy(type_, "MSAC"); } void MS_ADC::rej_action(int cl,double r,int b) { double rate = get_rate(cl,r,b); est_[cl]->change_avload(-rate); } int MS_ADC::admit_flow(int cl,double r,int b) { double rate = get_rate(cl,r,b); if (rate+est_[cl]->avload() < utilization_* bandwidth_) { est_[cl]->change_avload(rate); return 1; } return 0; } static class MS_ADCClass : public TclClass { public: MS_ADCClass() : TclClass("ADC/MS") {} TclObject* create(int,const char*const*) { return (new MS_ADC()); } }class_ms_adc; /* a measured sum algorithm that uses peak rather than token rate */ class MSPK_ADC : public MS_ADC { public: MSPK_ADC() { }; protected: inline virtual double get_rate(int cl,double r,int b){ return(peak_rate(cl,r,b));}; }; static class MSPK_ADCClass : public TclClass { public: MSPK_ADCClass() : TclClass("ADC/MSPK") {} TclObject* create(int,const char*const*) { return (new MSPK_ADC()); } } class_mspk_adc;

net-interface.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * net-interface.cc * Copyright (C) 1997 by USC/ISI * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Ported by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (USC/ISI)"; #endif #include "net-interface.h" int
NetworkInterface::command(int argc, const char*const* argv) { if (argc > 1) { if (strcmp(argv[1], "label") == 0) { if (argc == 2) { Tcl::instance().resultf("%d", intf_label_); return TCL_OK; } if (argc == 3) { intf_label_ = atoi(argv[2]); return TCL_OK; } } } return (Connector::command(argc, argv)); } void NetworkInterface::recv(Packet* p, Handler* h) { hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); #ifdef LEO_DEBUG printf("Marking to %d\n", intf_label_); #endif ch->iface() = intf_label_; ch->direction()= hdr_cmn::NONE; //direction: none send(p, h); } static class NetworkInterfaceClass : public TclClass { public: NetworkInterfaceClass() : TclClass("NetworkInterface") {} TclObject* create(int, const char*const*) { return (new NetworkInterface); } } class_networkinterface;

nilist.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <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
slist_base::insert(slink *a) { count_++; if (last_) a->next_ = last_->next_; else last_ = a; last_->next_ = a; } #include <stdio.h> void slist_base::remove(slink *a, slink *prev) { remove_count_++; /* XXX */ count_--; if (prev && prev->next_ != a) printf("In remove(): Error: prev->next!=a prev=%p a=%p\n", prev, a); if (last_ == NULL) return; if (prev == NULL) if (last_->next_ == a) prev = last_; else return; prev->next_ = a->next_; if (last_ == a) // a was last in list last_ = prev; if (last_->next_ == a) // a was only one in list last_ = NULL; } void slist_base::append(slink *a) { append_count_++; /* XXX */ count_++; if (last_) { a->next_ = last_->next_; last_ = last_->next_ = a; } else last_ = a->next_ = a; } slink *slist_base::get() { count_--; if (last_ == 0) return NULL; slink * f = last_->next_; if (f == last_) last_ = 0; else last_->next_ = f->next_; return f; } slink *slist_base::find(int key) { slink *cur = last_; if (last_ == 0) return NULL; do { cur = cur->next_; if (cur->key_ == key) return cur; } while (cur != last_); return NULL; } slist_base_iter::slist_base_iter(slist_base &s) { cs = &s; ce = cs->last_; } slink * slist_base_iter::operator() () // return 0 to indicate end of iteration { slink *ret = ce ? (ce=ce->next_) : 0; if (ce == cs->last_) ce = 0; return ret; } template<class T> T* Slist_iter<T>::operator() () { Tlink<T> *lnk = (Tlink<T> *) slist_base_iter::operator() (); return lnk ? &lnk->info : 0; }

node.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Ported from CMU/Monarch's code, nov'98 -Padma. * CMU-Monarch project's Mobility extensions ported by Padma Haldar, * 10/98. * * $Header$ */ #include <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
LinkHead::label() { if (net_if_) return net_if_->intf_label(); printf("Configuration error: Network Interface missing\n"); exit(1); // Make msvc happy return 0; } int LinkHead::command(int argc, const char*const* argv) { //Tcl& tcl = Tcl::instance(); if (argc == 2) { } else if (argc == 3) { if(strcmp(argv[1], "setnetinf") == 0) { net_if_ = (NetworkInterface*) TclObject::lookup(argv[2]); if (net_if_ == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "setnode") == 0) { node_ = (Node*) TclObject::lookup(argv[2]); if (node_ == 0) return TCL_ERROR; return TCL_OK; } } return (Connector::command(argc, argv)); } static class NodeClass : public TclClass { public: NodeClass() : TclClass("Node") {} TclObject* create(int, const char*const*) { return (new Node); } } class_node; struct node_head Node::nodehead_ = { 0 }; // replaces LIST_INIT macro Node::Node(void) : address_(-1), energy_model_(NULL), sleep_mode_(0), total_sleeptime_(0), total_rcvtime_(0), total_sndtime_(0), adaptivefidelity_(0), powersavingflag_(0), namDefinedFlag_(0), last_time_gosleep(0),max_inroute_time_(300), maxttl_(5) { LIST_INIT(&ifhead_); LIST_INIT(&linklisthead_); insert(&(Node::nodehead_)); // insert self into static list of nodes neighbor_list.neighbor_cnt_ = 0; neighbor_list.head = NULL; } Node::~Node() { LIST_REMOVE(this, entry); } int Node::command(int argc, const char*const* argv) { if (argc == 2) { Tcl& tcl = Tcl::instance(); if(strcmp(argv[1], "address?") == 0) { tcl.resultf("%d", address_); return TCL_OK; } else if(strcmp(argv[1], "powersaving") == 0) { powersavingflag_ = 1; start_powersaving(); return TCL_OK; } else if(strcmp(argv[1], "adaptivefidelity") == 0) { adaptivefidelity_ = 1; powersavingflag_ = 1; start_powersaving(); return TCL_OK; } else if(strcmp(argv[1], "namDefined") == 0) { namDefinedFlag_ = 1; return TCL_OK; } else if (strcmp(argv[1], "energy") == 0) { Tcl& tcl = Tcl::instance(); tcl.resultf("%f",this->energy()); return TCL_OK; } else if (strcmp(argv[1], "adjustenergy") == 0) { // assume every 10 sec schedule and 1.15 W // idle energy consumption. needs to be // parameterized. idle_energy_patch(10, 1.15); total_sndtime_ = 0; total_rcvtime_ = 0; total_sleeptime_ = 0; return TCL_OK; } } if (argc == 3) { if(strcmp(argv[1], "addif") == 0) { WiredPhy* phyp = (WiredPhy*) TclObject::lookup(argv[2]); if(phyp == 0) return TCL_ERROR; phyp->insertnode(&ifhead_); phyp->setnode(this); return TCL_OK; } else if (strcmp(argv[1], "addr") == 0) { address_ = Address::instance().\ str2addr(argv[2]); return TCL_OK; } else if (strcmp(argv[1], "nodeid") == 0) { nodeid_ = atoi(argv[2]); return TCL_OK; } else if (strcmp(argv[1], "addenergymodel") == 0) { energy_model_ = (EnergyModel *) TclObject::lookup(argv[2]); if(!energy_model_) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "addlinkhead") == 0) { LinkHead* slhp = (LinkHead*) TclObject::lookup(argv[2]); if (slhp == 0) return TCL_ERROR; slhp->insertlink(&linklisthead_); return TCL_OK; } else if (strcmp(argv[1], "setsleeptime") == 0) { afe_->set_sleeptime(atof(argv[2])); afe_->set_sleepseed(atof(argv[2])); return TCL_OK; } else if (strcmp(argv[1], "setenergy") == 0) { energy_model_->setenergy(atof(argv[2])); return TCL_OK; } else if (strcmp(argv[1], "settalive") == 0) { max_inroute_time_ = atof(argv[2]); return TCL_OK; } else if (strcmp(argv[1], "maxttl") == 0) { maxttl_ = atoi(argv[2]); return TCL_OK; } } if (argc == 4) { if(strcmp(argv[1], "idleenergy") == 0) { this->idle_energy_patch(atof(argv[2]),atof(argv[3])); return TCL_OK; } } return TclObject::command(argc,argv); } // Given an interface label for a NetworkInterface on this node, we return // the head of that link NsObject* Node::intf_to_target(int32_t label) { LinkHead *lhp = linklisthead_.lh_first; for (; lhp; lhp = lhp->nextlinkhead()) if (label == lhp->label()) return ((NsObject*) lhp); return NULL; } void Node::start_powersaving() { snh_ = new SoftNeighborHandler(this); snh_->start(); afe_ = new AdaptiveFidelityEntity(this); afe_->start(); state_ = POWERSAVING_STATE; state_start_time_ = Scheduler::instance().clock(); } void Node::set_node_sleep(int status) { Tcl& tcl=Tcl::instance(); //static float last_time_gosleep; // status = 1 to set node into sleep mode // status = 0 to put node back to idel mode. // time in the sleep mode should be used as credit to idle time energy consumption if (status) { last_time_gosleep = Scheduler::instance().clock(); //printf("id=%d : put node into sleep at %f\n",address_,last_time_gosleep); sleep_mode_ = status; if (namDefinedFlag_) tcl.evalf("%s add-mark m1 blue hexagon",name()); } else { sleep_mode_ = status; if (namDefinedFlag_) tcl.evalf("%s delete-mark m1",name()); //printf("id= %d last_time_sleep = %f\n",address_,last_time_gosleep); if (last_time_gosleep) { total_sleeptime_ += Scheduler::instance().clock()-last_time_gosleep; last_time_gosleep = 0; } } } void Node::set_node_state(int state) { switch (state_) { case POWERSAVING_STATE: case WAITING: state_ = state; state_start_time_ = Scheduler::instance().clock(); break; case INROUTE: if (state == POWERSAVING_STATE) { state_ = state; } if (state == INROUTE) { // a data packet is forwarded, needs to reset state_start_time_ state_start_time_= Scheduler::instance().clock(); } break; default: printf("Wrong state, quit...\n"); exit(1); } } void Node::idle_energy_patch(float /*total*/, float /*P_idle*/) { /* float real_idle = total-(total_sndtime_+total_rcvtime_+total_sleeptime_); //printf("real_idle=%f\n",real_idle); energy_model_-> DecrIdleEnergy(real_idle, P_idle); //set node energy into zero if ((this->energy_model())->energy() <= 0) { // saying node died this->energy_model()->setenergy(0); this->log_energy(0); } */ } void Node::add_neighbor(u_int32_t nodeid) { neighbor_list_item *np; np = neighbor_list.head; for (; np; np = np->next) { if (np->id == nodeid) { np->ttl = maxttl_; break; } } if (!np) { // insert this new entry np = new neighbor_list_item; np->id = nodeid; np->ttl = maxttl_; np->next = neighbor_list.head; neighbor_list.head = np; neighbor_list.neighbor_cnt_++; } } void Node::scan_neighbor() { neighbor_list_item *np, *lp; if (neighbor_list.neighbor_cnt_ > 0) { lp = neighbor_list.head; np = lp->next; for (; np; np = np->next) { np->ttl--; if (np->ttl <= 0){ lp->next = np->next; delete np; np = lp; neighbor_list.neighbor_cnt_--; } lp = np; } // process the first element np = neighbor_list.head; np->ttl--; if (np->ttl <= 0) { neighbor_list.head = np->next; delete np; neighbor_list.neighbor_cnt_--; } } } void SoftNeighborHandler::start() { Scheduler &s = Scheduler::instance(); s.schedule(this, &intr, CHECKFREQ); } void SoftNeighborHandler::handle(Event *) { Scheduler &s = Scheduler::instance(); nid_->scan_neighbor(); s.schedule(this, &intr, CHECKFREQ); } void AdaptiveFidelityEntity::start() { float start_idletime; Scheduler &s = Scheduler::instance(); sleep_time_ = 2; sleep_seed_ = 2; idle_time_ = 10; start_idletime = Random::uniform(0, idle_time_); //printf("node id_ = %d starttime=%f\n", nid_, start_idletime); nid_->set_node_sleep(0); s.schedule(this, &intr, start_idletime); } void AdaptiveFidelityEntity::handle(Event *) { Scheduler &s = Scheduler::instance(); int node_state = nid_->state(); //printf("Node %d at State %d at time %f is in sleep %d \n", nid_->address(), node_state, s.clock(), nid_->sleep()); //printf("node id = %d: sleep_time=%f\n",nid_->address(),sleep_time_); switch (node_state) { case POWERSAVING_STATE: if (nid_->sleep()) { // node is in sleep mode, wake it up nid_->set_node_sleep(0); adapt_it(); s.schedule(this, &intr, idle_time_); } else { // node is in idle mode, put it into sleep nid_->set_node_sleep(1); adapt_it(); s.schedule(this, &intr, sleep_time_); } break; case INROUTE: // 100s is the maximum INROUTE time. if (s.clock()-(nid_->state_start_time()) < nid_->max_inroute_time()) { s.schedule(this, &intr, idle_time_); } else { nid_->set_node_state(POWERSAVING_STATE); adapt_it(); nid_->set_node_sleep(1); s.schedule(this, &intr, sleep_time_); } break; case WAITING: // 10s is the maximum WAITING time if (s.clock()-(nid_->state_start_time()) < MAX_WAITING_TIME) { s.schedule(this, &intr, idle_time_); } else { nid_->set_node_state(POWERSAVING_STATE); adapt_it(); nid_->set_node_sleep(1); s.schedule(this, &intr, sleep_time_); } break; default: fprintf(stderr, "Illegal Node State!"); abort(); } } void AdaptiveFidelityEntity::adapt_it() { float delay; // use adaptive fidelity if (nid_->adaptivefidelity()) { int neighbors = nid_->getneighbors(); if (!neighbors) neighbors=1; delay = sleep_seed_*Random::uniform(1,neighbors); this->set_sleeptime(delay); } } // return the node instance from the static node list Node * Node::get_node_by_address (nsaddr_t id) { Node * tnode = nodehead_.lh_first; for (; tnode; tnode = tnode->nextnode()) { if (tnode->address_ == id ) { return (tnode); } } return NULL; } #ifdef zero static class HierNodeClass : public TclClass { public: HierNodeClass() : TclClass("HierNode") {} TclObject* create(int, const char*const*) { return (new HierNode); } } class_hier_node; static class ManualRtNodeClass : public TclClass { public: ManualRtNodeClass() : TclClass("ManualRtNode") {} TclObject* create(int, const char*const*) { return (new ManualRtNode); } } class_ManualRt_node; static class VirtualClassifierNodeClass : public TclClass { public: VirtualClassifierNodeClass() : TclClass("VirtualClassifierNode") {} TclObject* create(int, const char*const*) { return (new VirtualClassifierNode); } } class_VirtualClassifier_node; #endif

ns-process.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ // // Copyright (c) 1997 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for non-commercial purposes // and without fee is hereby granted, provided that the above copyright // notice appear in all copies and that both the copyright notice and // this permission notice appear in supporting documentation. and that // any documentation, advertising materials, and other materials related // to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the University may not be used to // endorse or promote products derived from this software without // specific prior written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about // the suitability of this software for any purpose. THIS SOFTWARE IS // PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // Other copyrights might apply to parts of this software and are so // noted when applicable. // // ADU and ADU processor // // $Header$ #include "ns-process.h" static class ProcessClass : public TclClass { public: ProcessClass() : TclClass("Process") {} TclObject* create(int, const char*const*) { return (new Process); } } class_process; void
Process::process_data(int, AppData*) { abort(); } AppData* Process::get_data(int&, AppData*) { abort(); /* NOTREACHED */ return NULL; // Make msvc happy } int Process::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (strcmp(argv[1], "target") == 0) { if (argc == 2) { tcl.resultf("%s", target()->name()); return TCL_OK; } else if (argc == 3) { Process *p = (Process *)TclObject::lookup(argv[2]); if (p == NULL) { fprintf(stderr, "Non-existent media app %s\n", argv[2]); abort(); } target() = p; return TCL_OK; } } return TclObject::command(argc, argv); }

ns_tclsh.cc


/* * * Provides a default version of the Tcl_AppInit procedure for * use in wish and similar Tk-based applications. * * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include <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*
PacketHeaderClass::create(int, const char*const*) { return (0); } void PacketHeaderClass::bind() { TclClass::bind(); Tcl& tcl = Tcl::instance(); tcl.evalf("%s set hdrlen_ %d", classname_, hdrlen_); export_offsets(); add_method("offset"); } void PacketHeaderClass::export_offsets() { } void PacketHeaderClass::field_offset(const char* fieldname, int offset) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s set offset_(%s) %d", classname_, fieldname, offset); } int PacketHeaderClass::method(int ac, const char*const* av) { Tcl& tcl = Tcl::instance(); int argc = ac - 2; const char*const* argv = av + 2; if (argc == 3) { if (strcmp(argv[1], "offset") == 0) { if (offset_) { *offset_ = atoi(argv[2]); return TCL_OK; } tcl.resultf("Warning: cannot set offset_ for %s", classname_); return TCL_OK; } } else if (argc == 2) { if (strcmp(argv[1], "offset") == 0) { if (offset_) { tcl.resultf("%d", *offset_); return TCL_OK; } } } return TclClass::method(argc, argv); } class CommonHeaderClass : public PacketHeaderClass { public: CommonHeaderClass() : PacketHeaderClass("PacketHeader/Common", sizeof(hdr_cmn)) { bind_offset(&hdr_cmn::offset_); } void export_offsets() { field_offset("ptype_", OFFSET(hdr_cmn, ptype_)); field_offset("size_", OFFSET(hdr_cmn, size_)); field_offset("uid_", OFFSET(hdr_cmn, uid_)); field_offset("error_", OFFSET(hdr_cmn, error_)); }; } class_cmnhdr; class FlagsHeaderClass : public PacketHeaderClass { public: FlagsHeaderClass() : PacketHeaderClass("PacketHeader/Flags", sizeof(hdr_flags)) { bind_offset(&hdr_flags::offset_); } } class_flagshdr; /* manages active packet header types */ class PacketHeaderManager : public TclObject { public: PacketHeaderManager() { bind("hdrlen_", &Packet::hdrlen_); } }; static class PacketHeaderManagerClass : public TclClass { public: PacketHeaderManagerClass() : TclClass("PacketHeaderManager") {} TclObject* create(int, const char*const*) { return (new PacketHeaderManager); } } class_packethdr_mgr;

param-adc.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif /* Parameter-based admission control. Admission decisions are * based on the sum of reserved rates. */ #include "adc.h" #include <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); }

phy.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header: * * Ported from CMU/Monarch's code, nov'98 -Padma Haldar. * phy.cc */ #include <math.h> #include "config.h" #include <packet.h> #include <phy.h> #include <dsr/hdr_sr.h> class Mac; static int InterfaceIndex = 0; Phy::Phy() : BiConnector() { index_ = InterfaceIndex++; bandwidth_ = 0.0; channel_ = 0; node_ = 0; head_ = 0; } int
Phy::command(int argc, const char*const* argv) { if (argc == 2) { Tcl& tcl = Tcl::instance(); if(strcmp(argv[1], "id") == 0) { tcl.resultf("%d", index_); return TCL_OK; } } else if(argc == 3) { TclObject *obj; if( (obj = TclObject::lookup(argv[2])) == 0) { fprintf(stderr, "%s lookup failed\n", argv[1]); return TCL_ERROR; } if (strcmp(argv[1], "channel") == 0) { assert(channel_ == 0); channel_ = (Channel*) obj; downtarget_ = (NsObject*) obj; // LIST_INSERT_HEAD() is done by Channel return TCL_OK; } else if (strcmp(argv[1], "node") == 0) { assert(node_ == 0); node_ = (Node*) obj; // LIST_INSERT_HEAD() is done by Node return TCL_OK; } else if (strcmp(argv[1], "linkhead") == 0) { head_ = (LinkHead*) obj; return (TCL_OK); } } return BiConnector::command(argc, argv); } void Phy::recv(Packet* p, Handler*) { struct hdr_cmn *hdr = HDR_CMN(p); //struct hdr_sr *hsr = HDR_SR(p); /* * Handle outgoing packets */ switch(hdr->direction()) { case hdr_cmn::DOWN : /* * The MAC schedules its own EOT event so we just * ignore the handler here. It's only purpose * it distinguishing between incoming and outgoing * packets. */ sendDown(p); return; case hdr_cmn::UP : if (sendUp(p) == 0) { /* * XXX - This packet, even though not detected, * contributes to the Noise floor and hence * may affect the reception of other packets. */ Packet::free(p); return; } else { uptarget_->recv(p, (Handler*) 0); } break; default: printf("Direction for pkt-flow not specified; Sending pkt up the stack on default.\n\n"); if (sendUp(p) == 0) { /* * XXX - This packet, even though not detected, * contributes to the Noise floor and hence * may affect the reception of other packets. */ Packet::free(p); return; } else { uptarget_->recv(p, (Handler*) 0); } } } /* NOTE: this might not be the best way to structure the relation between the actual interfaces subclassed from net-if(phy) and net-if(phy). It's fine for now, but if we were to decide to have the interfaces themselves properly handle multiple incoming packets (they currently require assistance from the mac layer to do this), then it's not as generic as I'd like. The way it is now, each interface will have to have it's own logic to keep track of the packets that are arriving. Seems like this is general service that net-if could provide. Ok. A fair amount of restructuring is going to have to happen here when/if net-if keep track of the noise floor at their location. I'm gonna punt on it for now. Actually, this may be all wrong. Perhaps we should keep a separate noise floor per antenna, which would mean the particular interface types would have to track noise floor themselves, since only they know what kind of antenna diversity they have. -dam 8/7/98 */ // double // Phy::txtime(Packet *p) const // { // hdr_cmn *hdr = HDR_CMN(p); // return hdr->size() * 8.0 / Rb_; // } void Phy::dump(void) const { fprintf(stdout, "\tINDEX: %d\n", index_); fprintf(stdout, "\tuptarget: %x, channel: %x", (u_int32_t) uptarget_, (u_int32_t) channel_); }

ping.cc


/* * File: Code for a new 'Ping' Agent Class for the ns * network simulator * Author: Marc Greis (greis@cs.uni-bonn.de), May 1998 * * IMPORTANT: Incase of any changes made to this file , * tutorial/examples/ping.cc file (used in Greis' tutorial) should * be updated as well. */ #include "ping.h" static class PingHeaderClass : public PacketHeaderClass { public: PingHeaderClass() : PacketHeaderClass("PacketHeader/Ping", sizeof(hdr_ping)) {} } class_pinghdr; static class PingClass : public TclClass { public: PingClass() : TclClass("Agent/Ping") {} TclObject* create(int, const char*const*) { return (new PingAgent()); } } class_ping; PingAgent::PingAgent() : Agent(PT_PING) { bind("packetSize_", &size_); bind("off_ping_", &off_ping_); } int
PingAgent::command(int argc, const char*const* argv) { if (argc == 2) { if (strcmp(argv[1], "send") == 0) { // Create a new packet Packet* pkt = allocpkt(); // Access the Ping header for the new packet: hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_); // Set the 'ret' field to 0, so the receiving node knows // that it has to generate an echo packet hdr->ret = 0; // Store the current time in the 'send_time' field hdr->send_time = Scheduler::instance().clock(); // Send the packet send(pkt, 0); // return TCL_OK, so the calling function knows that the // command has been processed return (TCL_OK); } } // If the command hasn't been processed by PingAgent()::command, // call the command() function for the base class return (Agent::command(argc, argv)); } void PingAgent::recv(Packet* pkt, Handler*) { // Access the IP header for the received packet: hdr_ip* hdrip = (hdr_ip*)pkt->access(off_ip_); // Access the Ping header for the received packet: hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_); // Is the 'ret' field = 0 (i.e. the receiving node is being pinged)? if (hdr->ret == 0) { // Send an 'echo'. First save the old packet's send_time double stime = hdr->send_time; // Discard the packet Packet::free(pkt); // Create a new packet Packet* pktret = allocpkt(); // Access the Ping header for the new packet: hdr_ping* hdrret = (hdr_ping*)pktret->access(off_ping_); // Set the 'ret' field to 1, so the receiver won't send another echo hdrret->ret = 1; // Set the send_time field to the correct value hdrret->send_time = stime; // Send the packet send(pktret, 0); } else { // A packet was received. Use tcl.eval to call the Tcl // interpreter with the ping results. // Note: In the Tcl code, a procedure 'Agent/Ping recv {from rtt}' // has to be defined which allows the user to react to the ping // result. char out[100]; // Prepare the output to the Tcl interpreter. Calculate the round // trip time sprintf(out, "%s recv %d %3.1f", name(), hdrip->src_.addr_ >> Address::instance().NodeShift_[1], (Scheduler::instance().clock()-hdr->send_time) * 1000); Tcl& tcl = Tcl::instance(); tcl.eval(out); // Discard the packet Packet::free(pkt); } }

pkt-counter.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * pkt-counter.cc * Copyright (C) 1997 by USC/ISI * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Ported by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang * */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (USC/ISI)"; #endif #include "connector.h" class PktCounter : public Connector { public: PktCounter() : count_(0) { } int command(int argc, const char*const* argv); void recv(Packet* pkt, Handler* h) { count_++; send(pkt, h); } protected: int count_; }; static class PktCounterClass : public TclClass { public: PktCounterClass() : TclClass("PktCounter") {} TclObject* create(int, const char*const*) { return (new PktCounter); } } class_pktcounter; int
PktCounter::command(int argc, const char*const* argv) { if (argc == 2) { if (strcmp(argv[1], "reset") == 0) { count_ = 0; return (TCL_OK); } if (strcmp(argv[1], "value") == 0) { Tcl& tcl = Tcl::instance(); tcl.resultf("%d", count_); return (TCL_OK); } } return (Connector::command(argc, argv)); }

pointsample-est.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "estimator.h" #include <stdlib.h> #include <math.h> class PointSample_Est : public Estimator { public: PointSample_Est() {}; protected: void estimate(); }; void
PointSample_Est::estimate() { avload_=meas_mod_->bitcnt()/period_; //printf("%f %f\n",Scheduler::instance().clock(),avload_); fflush(stdout); meas_mod_->resetbitcnt(); } static class PointSample_EstClass : public TclClass { public: PointSample_EstClass() : TclClass ("Est/PointSample") {} TclObject* create(int,const char*const*) { return (new PointSample_Est()); } }class_pointsample_est;

priqueue.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Ported from CMU/Monarch's code, nov'98 -Padma.*/ /* -*- c++ -*- priqueue.cc A simple priority queue with a remove packet function $Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $ */ #include <object.h> #include <queue.h> #include <drop-tail.h> #include <packet.h> //#include <cmu/cmu-trace.h> #include "priqueue.h" typedef int (*PacketFilter)(Packet *, void *); PriQueue_List PriQueue::prhead = { 0 }; static class PriQueueClass : public TclClass { public: PriQueueClass() : TclClass("Queue/DropTail/PriQueue") {} TclObject* create(int, const char*const*) { return (new PriQueue); } } class_PriQueue; PriQueue::PriQueue() : DropTail() { bind("Prefer_Routing_Protocols", &Prefer_Routing_Protocols); LIST_INSERT_HEAD(&prhead, this, link); } int
PriQueue::command(int argc, const char*const* argv) { if (argc == 2 && strcasecmp(argv[1], "reset") == 0) { Terminate(); //FALL-THROUGH to give parents a chance to reset } return DropTail::command(argc, argv); } void PriQueue::recv(Packet *p, Handler *h) { struct hdr_cmn *ch = HDR_CMN(p); if(Prefer_Routing_Protocols) { switch(ch->ptype()) { case PT_DSR: case PT_MESSAGE: case PT_TORA: case PT_AODV: recvHighPriority(p, h); break; default: Queue::recv(p, h); } } else { Queue::recv(p, h); } } void PriQueue::recvHighPriority(Packet *p, Handler *) // insert packet at front of queue { q_->enqueHead(p); if (q_->length() >= qlim_) { Packet *to_drop = q_->lookup(q_->length()-1); q_->remove(to_drop); drop(to_drop); } if (!blocked_) { /* * We're not blocked. Get a packet and send it on. * We perform an extra check because the queue * might drop the packet even if it was * previously empty! (e.g., RED can do this.) */ p = deque(); if (p != 0) { blocked_ = 1; target_->recv(p, &qh_); } } } void PriQueue::filter(PacketFilter filter, void * data) // apply filter to each packet in queue, // - if filter returns 0 leave packet in queue // - if filter returns 1 remove packet from queue { int i = 0; while (i < q_->length()) { Packet *p = q_->lookup(i); if (filter(p,data)) { q_->remove(p); // decrements q len } else i++; } } Packet* PriQueue::filter(nsaddr_t id) { Packet *p = 0; Packet *pp = 0; struct hdr_cmn *ch; for(p = q_->head(); p; p = p->next_) { ch = HDR_CMN(p); if(ch->next_hop() == id) break; pp = p; } /* * Deque Packet */ if(p) { if(pp == 0) q_->remove(p); else q_->remove(p, pp); } return p; } /* * Called at the end of the simulation to purge the IFQ. */ void PriQueue::Terminate() { Packet *p; while((p = deque())) { //drop(p, DROP_END_OF_SIMULATION); drop(p); } }

propagation.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * propagation.cc $Id: AllCode__.html 980 2002-12-12 09:36:58Z ffilali $ */ #include <stdio.h> #include <topography.h> #include <propagation.h> #include <wireless-phy.h> class PacketStamp; int
Propagation::command(int argc, const char*const* argv) { TclObject *obj; if(argc == 3) { if( (obj = TclObject::lookup(argv[2])) == 0) { fprintf(stderr, "Propagation: %s lookup of %s failed\n", argv[1], argv[2]); return TCL_ERROR; } if (strcasecmp(argv[1], "topography") == 0) { topo = (Topography*) obj; return TCL_OK; } } return TclObject::command(argc,argv); } /* As new network-intefaces are added, add a default method here */ double Propagation::Pr(PacketStamp *, PacketStamp *, Phy *) { fprintf(stderr,"Propagation model %s not implemented for generic NetIF\n", name); abort(); return 0; // Make msvc happy } double Propagation::Pr(PacketStamp *, PacketStamp *, WirelessPhy *) { fprintf(stderr, "Propagation model %s not implemented for SharedMedia interface\n", name); abort(); return 0; // Make msvc happy }

ptypes2tcl.cc


#include <stdio.h> #include <ctype.h> #include "packet.h" // The following copied from ~tclcl/tcl2c++.c /* * Define TCL2C_INT if your compiler has problems with long strings. */ #if defined(WIN32) || defined(_WIN32) || defined(__alpha__) || defined(__hpux) #define TCL2C_INT #endif char* p_info::name_[PT_NTYPE+1]; void printLine(char *s) { #ifdef TCL2C_INT for (unsigned int i = 0; i < strlen(s); i++) if ((i > 0) && ((i % 20) == 0)) printf("%u,\n", s[i]); else printf("%u,", s[i]); printf("%u,%u,\n", '\\', '\n'); #else printf("%s\\n\\\n", s); #endif } char * lcase(const char *s) { static char charbuf[512]; char* to = charbuf; while ((*to++ = tolower(*s++))) /* NOTHING */; *to = '\0'; return charbuf; } int main() { p_info pinfo; #ifdef TCL2C_INT printf("static const char code[] = {\n"); #else printLine("static const char code[] = \""); #endif printLine("global ptype pvals"); printLine("set ptype(error) -1"); printLine("set pvals(-1) error"); char strbuf[512]; for (int i = 0; i < PT_NTYPE; i++) { sprintf(strbuf, "set ptype(%s) %d", lcase(pinfo.name(packet_t(i))), i); printLine(strbuf); sprintf(strbuf, "set pvals(%d) %s", i, pinfo.name(packet_t(i))); printLine(strbuf); } printLine("proc ptype2val {str} {"); printLine("global ptype"); printLine("set str [string tolower $str]"); printLine("if ![info exists ptype($str)] {"); printLine("set str error"); printLine("}"); printLine("set ptype($str)"); printLine("}"); printLine("proc pval2type {val} {"); printLine("global pvals"); printLine("if ![info exists pvals($val)] {"); printLine("set val -1"); printLine("}"); printLine("set pvals($val)"); printLine("}"); #ifdef TCL2C_INT printf("0 };\n"); #else printf("\";\n"); #endif printf("#include \"config.h\"\n"); printf("EmbeddedTcl et_ns_ptypes(code);\n"); return 0; }

queue-monitor.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "queue-monitor.h" int
QueueMonitor::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "get-bytes-integrator") == 0) { if (bytesInt_) tcl.resultf("%s", bytesInt_->name()); else tcl.resultf(""); return (TCL_OK); } if (strcmp(argv[1], "get-pkts-integrator") == 0) { if (pktsInt_) tcl.resultf("%s", pktsInt_->name()); else tcl.resultf(""); return (TCL_OK); } if (strcmp(argv[1], "get-delay-samples") == 0) { if (delaySamp_) tcl.resultf("%s", delaySamp_->name()); else tcl.resultf(""); return (TCL_OK); } } if (argc == 3) { if (strcmp(argv[1], "set-bytes-integrator") == 0) { bytesInt_ = (Integrator *) TclObject::lookup(argv[2]); if (bytesInt_ == NULL) return (TCL_ERROR); return (TCL_OK); } if (strcmp(argv[1], "set-pkts-integrator") == 0) { pktsInt_ = (Integrator *) TclObject::lookup(argv[2]); if (pktsInt_ == NULL) return (TCL_ERROR); return (TCL_OK); } if (strcmp(argv[1], "set-delay-samples") == 0) { delaySamp_ = (Samples*) TclObject::lookup(argv[2]); if (delaySamp_ == NULL) return (TCL_ERROR); return (TCL_OK); } if (strcmp(argv[1], "trace") == 0) { int mode; const char* id = argv[2]; channel_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); if (channel_ == 0) { tcl.resultf("trace: can't attach %s for writing", id); return (TCL_ERROR); } return (TCL_OK); } } if (argc == 4) { if (strcmp(argv[1], "set-src-dst") == 0) { srcId_ = atoi(argv[2]); dstId_ = atoi(argv[3]); return (TCL_OK); } } return TclObject::command(argc, argv); // else control reaches end of // non-void function, see? :-) } static class QueueMonitorClass : public TclClass { public: QueueMonitorClass() : TclClass("QueueMonitor") {} TclObject* create(int, const char*const*) { return (new QueueMonitor()); } } queue_monitor_class; void QueueMonitor::printStats() { char wrk[500]; int n; double now = Scheduler::instance().clock(); sprintf(wrk, "%-6.3f %d %d %d %d", now, srcId_, dstId_, size_, pkts_); n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(channel_, wrk, n+1); wrk[n] = 0; } // packet arrival to a queue void QueueMonitor::in(Packet* p) { hdr_cmn* hdr = (hdr_cmn*)p->access(off_cmn_); double now = Scheduler::instance().clock(); int pktsz = hdr->size(); barrivals_ += pktsz; parrivals_++; size_ += pktsz; pkts_++; if (bytesInt_) bytesInt_->newPoint(now, double(size_)); if (pktsInt_) pktsInt_->newPoint(now, double(pkts_)); if (delaySamp_) hdr->timestamp() = now; if (channel_) printStats(); } void QueueMonitor::out(Packet* p) { hdr_cmn* hdr = (hdr_cmn*)p->access(off_cmn_); double now = Scheduler::instance().clock(); int pktsz = hdr->size(); size_ -= pktsz; pkts_--; bdepartures_ += pktsz; pdepartures_++; if (bytesInt_) bytesInt_->newPoint(now, double(size_)); if (pktsInt_) pktsInt_->newPoint(now, double(pkts_)); if (delaySamp_) delaySamp_->newPoint(now - hdr->timestamp()); if (channel_) printStats(); } void QueueMonitor::drop(Packet* p) { hdr_cmn* hdr = (hdr_cmn*)p->access(off_cmn_); double now = Scheduler::instance().clock(); int pktsz = hdr->size(); size_ -= pktsz; pkts_--; bdrops_ += pktsz; pdrops_++; if (bytesInt_) bytesInt_->newPoint(now, double(size_)); if (pktsInt_) pktsInt_->newPoint(now, double(pkts_)); if (channel_) printStats(); } static class SnoopQueueInClass : public TclClass { public: SnoopQueueInClass() : TclClass("SnoopQueue/In") {} TclObject* create(int, const char*const*) { return (new SnoopQueueIn()); } } snoopq_in_class; static class SnoopQueueOutClass : public TclClass { public: SnoopQueueOutClass() : TclClass("SnoopQueue/Out") {} TclObject* create(int, const char*const*) { return (new SnoopQueueOut()); } } snoopq_out_class; static class SnoopQueueDropClass : public TclClass { public: SnoopQueueDropClass() : TclClass("SnoopQueue/Drop") {} TclObject* create(int, const char*const*) { return (new SnoopQueueDrop()); } } snoopq_drop_class; static class SnoopQueueEDropClass : public TclClass { public: SnoopQueueEDropClass() : TclClass("SnoopQueue/EDrop") {} TclObject* create(int, const char*const*) { return (new SnoopQueueEDrop); } } snoopq_edrop_class; static class QueueMonitorEDClass : public TclClass { public: QueueMonitorEDClass() : TclClass("QueueMonitor/ED") {} TclObject* create(int, const char*const*) { return (new EDQueueMonitor); } } queue_monitor_ed_class; /* * a 'QueueMonitorCompat', which is used by the compat * code to produce the link statistics used available in ns-1 * * in ns-1, the counters are the number of departures */ #include "ip.h" QueueMonitorCompat::QueueMonitorCompat() { bind("off_ip_", &off_ip_); memset(pkts_, 0, sizeof(pkts_)); memset(bytes_, 0, sizeof(bytes_)); memset(drops_, 0, sizeof(drops_)); memset(flowstats_, 0, sizeof(flowstats_)); } /* * create an entry in the flowstats_ array. */ void QueueMonitorCompat::flowstats(int flowid) { Tcl& tcl = Tcl::instance(); /* * here is the deal. we are in C code. we'd like to do * flowstats_[flowid] = new Samples; * but, we want to create an object that can be * referenced via tcl. (in particular, we want ->name_ * to be valid.) * * so, how do we do this? * * well, the answer is, call tcl to create it. then, * do a lookup on the result from tcl! */ tcl.evalf("new Samples"); flowstats_[flowid] = (Samples*)TclObject::lookup(tcl.result()); if (flowstats_[flowid] == 0) { abort(); /*NOTREACHED*/ } } void QueueMonitorCompat::out(Packet* pkt) { hdr_cmn* hdr = (hdr_cmn*)pkt->access(off_cmn_); hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_); double now = Scheduler::instance().clock(); int fid = iph->flowid(); if (fid >= MAXFLOW) { abort(); /*NOTREACHED*/ } // printf("QueueMonitorCompat::out(), fid=%d\n", fid); bytes_[fid] += ((hdr_cmn*)pkt->access(off_cmn_))->size(); pkts_[fid]++; if (flowstats_[fid] == 0) { flowstats(fid); } flowstats_[fid]->newPoint(now - hdr->timestamp()); QueueMonitor::out(pkt); } void QueueMonitorCompat::in(Packet* pkt) { hdr_cmn* hdr = (hdr_cmn*)pkt->access(off_cmn_); double now = Scheduler::instance().clock(); // QueueMonitor::in() *may* do this, but we always need it... hdr->timestamp() = now; QueueMonitor::in(pkt); } void QueueMonitorCompat::drop(Packet* pkt) { hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_); int fid = iph->flowid(); if (fid >= MAXFLOW) { abort(); /*NOTREACHED*/ } ++drops_[fid]; QueueMonitor::drop(pkt); } int QueueMonitorCompat::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); int fid; if (argc == 3) { fid = atoi(argv[2]); if (strcmp(argv[1], "bytes") == 0) { if (fid >= MAXFLOW) { abort(); /*NOTREACHED*/ } tcl.resultf("%d", bytes_[fid]); return TCL_OK; } else if (strcmp(argv[1], "pkts") == 0) { if (fid >= MAXFLOW) { abort(); /*NOTREACHED*/ } tcl.resultf("%d", pkts_[fid]); return TCL_OK; } else if (strcmp(argv[1], "drops") == 0) { if (fid >= MAXFLOW) { abort(); /*NOTREACHED*/ } tcl.resultf("%d", drops_[fid]); return TCL_OK; } else if (strcmp(argv[1], "get-class-delay-samples") == 0) { if (fid >= MAXFLOW) { abort(); /*NOTREACHED*/ } if (flowstats_[fid] == 0) { /* * instantiate one if user actually * cares enough to ask for it! * * (otherwise, need to return "", * and then special-case caller to * handle this null return.) */ flowstats(fid); } tcl.resultf("%s", flowstats_[fid]->name()); return TCL_OK; } } return (QueueMonitor::command(argc, argv)); } static class QueueMonitorCompatClass : public TclClass { public: QueueMonitorCompatClass() : TclClass("QueueMonitor/Compat") {} TclObject* create(int, const char*const*) { return (new QueueMonitorCompat); } } queue_monitor_compat_class;

queue.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1996-1997 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Network Research * Group at Lawrence Berkeley National Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include "queue.h" #include <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
REDQueue::reset() { /* * If queue is measured in bytes, scale min/max thresh * by the size of an average packet (which is specified by user). */ if (qib_) { edp_.th_min *= edp_.mean_pktsize; edp_.th_max *= edp_.mean_pktsize; } /* * Compute the "packet time constant" if we know the * link bandwidth. The ptc is the max number of (avg sized) * pkts per second which can be placed on the link. * The link bw is given in bits/sec, so scale mean psize * accordingly. */ if (link_) edp_.ptc = link_->bandwidth() / (8. * edp_.mean_pktsize); edv_.v_ave = 0.0; edv_.v_slope = 0.0; edv_.count = 0; edv_.count_bytes = 0; edv_.old = 0; edv_.v_a = 1 / (edp_.th_max - edp_.th_min); edv_.v_b = - edp_.th_min / (edp_.th_max - edp_.th_min); if (edp_.gentle) { edv_.v_c = ( 1.0 - 1 / edp_.max_p_inv ) / edp_.th_max; edv_.v_d = 2 / edp_.max_p_inv - 1.0; } idle_ = 1; if (&Scheduler::instance() != NULL) idletime_ = Scheduler::instance().clock(); else idletime_ = 0.0; /* sched not instantiated yet */ Queue::reset(); bcount_ = 0; } /* * Compute the average queue size. * The code contains two alternate methods for this, the plain EWMA * and the Holt-Winters method. * nqueued can be bytes or packets */ void REDQueue::run_estimator(int nqueued, int m) { float f, f_sl, f_old; f = (float)edv_.v_ave; f_sl = (float)edv_.v_slope; #define RED_EWMA #ifdef RED_EWMA while (--m >= 1) { f_old = f; f *= 1.0 - (float)edp_.q_w; } f_old = f; f *= 1.0 - (float)edp_.q_w; f += (float)edp_.q_w * nqueued; #endif #ifdef RED_HOLT_WINTERS while (--m >= 1) { f_old = f; f += f_sl; f *= 1.0 - edp_.q_w; f_sl *= 1.0 - 0.5 * edp_.q_w; f_sl += 0.5 * edp_.q_w * (f - f_old); } f_old = f; f += f_sl; f *= 1.0 - edp_.q_w; f += edp_.q_w * nqueued; f_sl *= 1.0 - 0.5 * edp_.q_w; f_sl += 0.5 * edp_.q_w * (f - f_old); #endif edv_.v_ave = f; edv_.v_slope = f_sl; } /* * Return the next packet in the queue for transmission. */ Packet* REDQueue::deque() { Packet *p; p = q_->deque(); if (p != 0) { idle_ = 0; bcount_ -= ((hdr_cmn*)p->access(off_cmn_))->size(); } else { idle_ = 1; // deque() may invoked by Queue::reset at init // time (before the scheduler is instantiated). // deal with this case if (&Scheduler::instance() != NULL) idletime_ = Scheduler::instance().clock(); else idletime_ = 0.0; } return (p); } /* * should the packet be dropped/marked due to a probabilistic drop? */ int REDQueue::drop_early(Packet* pkt) { double p; int no_ecn = 0; hdr_cmn* ch = (hdr_cmn*)pkt->access(off_cmn_); if (edp_.gentle && edv_.v_ave >= edp_.th_max) { // p ranges from max_p to 1 as the average queue // size ranges from th_max to twice th_max p = edv_.v_c * edv_.v_ave + edv_.v_d; no_ecn = 1; } else { // p ranges from 0 to max_p as the average queue // size ranges from th_min to th_max p = edv_.v_a * edv_.v_ave + edv_.v_b; p /= edp_.max_p_inv; } edv_.v_prob1 = p; if (edv_.v_prob1 > 1.0) edv_.v_prob1 = 1.0; double count1 = edv_.count; if (edp_.bytes) count1 = (double) (edv_.count_bytes/edp_.mean_pktsize); if (edp_.wait) { if (count1 * p < 1.0) p = 0.0; else if (count1 * p < 2.0) p /= (2 - count1 * p); else p = 1.0; } else { if (count1 * p < 1.0) p /= (1.0 - count1 * p); else p = 1.0; } if (edp_.bytes && p < 1.0) { p = p * ch->size() / edp_.mean_pktsize; } if (p > 1.0) p = 1.0; edv_.v_prob = p; // drop probability is computed, pick random number and act double u = Random::uniform(); if (u <= edv_.v_prob) { // DROP or MARK edv_.count = 0; edv_.count_bytes = 0; hdr_flags* hf = (hdr_flags*)pickPacketForECN(pkt)->access(off_flags_); if (edp_.setbit && hf->ect() && no_ecn==0) { hf->ce() = 1; // mark Congestion Experienced bit return (0); // no drop } else { return (1); // drop } } return (0); // no DROP/mark } /* * Pick packet for early congestion notification (ECN). This packet is then * marked or dropped. Having a separate function do this is convenient for * supporting derived classes that use the standard RED algorithm to compute * average queue size but use a different algorithm for choosing the packet for * ECN notification. */ Packet* REDQueue::pickPacketForECN(Packet* pkt) { return pkt; /* pick the packet that just arrived */ } /* * Pick packet to drop. Having a separate function do this is convenient for * supporting derived classes that use the standard RED algorithm to compute * average queue size but use a different algorithm for choosing the victim. */ Packet* REDQueue::pickPacketToDrop() { int victim; if (drop_front_) victim = min(1, q_->length()-1); else if (drop_rand_) victim = Random::integer(q_->length()); else /* default is drop_tail_ */ victim = q_->length() - 1; return(q_->lookup(victim)); } /* * Receive a new packet arriving at the queue. * The average queue size is computed. If the average size * exceeds the threshold, then the dropping probability is computed, * and the newly-arriving packet is dropped with that probability. * The packet is also dropped if the maximum queue size is exceeded. * * "Forced" drops mean a packet arrived when the underlying queue was * full or when the average q size exceeded maxthresh. * "Unforced" means a RED random drop. * * For forced drops, either the arriving packet is dropped or one in the * queue is dropped, depending on the setting of drop_tail_. * For unforced drops, the arriving packet is always the victim. */ #define DTYPE_NONE 0 /* ok, no drop */ #define DTYPE_FORCED 1 /* a "forced" drop */ #define DTYPE_UNFORCED 2 /* an "unforced" (random) drop */ void REDQueue::enque(Packet* pkt) { /* * if we were idle, we pretend that m packets arrived during * the idle period. m is set to be the ptc times the amount * of time we've been idle for */ int m = 0; if (idle_) { // A packet that arrives to an idle queue will never // be dropped. double now = Scheduler::instance().clock(); /* To account for the period when the queue was empty. */ idle_ = 0; m = int(edp_.ptc * (now - idletime_)); } /* * Run the estimator with either 1 new packet arrival, or with * the scaled version above [scaled by m due to idle time] * (bcount_ maintains the byte count in the underlying queue). * If the underlying queue is able to delete packets without * us knowing, then bcount_ will not be maintained properly! */ run_estimator(qib_ ? bcount_ : q_->length(), m + 1); /* * count and count_bytes keeps a tally of arriving traffic * that has not been dropped (i.e. how long, in terms of traffic, * it has been since the last early drop) */ hdr_cmn* ch = (hdr_cmn*)pkt->access(off_cmn_); ++edv_.count; edv_.count_bytes += ch->size(); /* * DROP LOGIC: * q = current q size, ~q = averaged q size * 1> if ~q > maxthresh, this is a FORCED drop * 2> if minthresh < ~q < maxthresh, this may be an UNFORCED drop * 3> if (q+1) > hard q limit, this is a FORCED drop */ register double qavg = edv_.v_ave; int droptype = DTYPE_NONE; int qlen = qib_ ? bcount_ : q_->length(); int qlim = qib_ ? (qlim_ * edp_.mean_pktsize) : qlim_; curq_ = qlen; // helps to trace queue during arrival, if enabled if (qavg >= edp_.th_min && qlen > 1) { if ((!edp_.gentle && qavg >= edp_.th_max) || (edp_.gentle && qavg >= 2 * edp_.th_max)) { droptype = DTYPE_FORCED; } else if (edv_.old == 0) { /* * The average queue size has just crossed the * threshold from below to above "minthresh", or * from above "minthresh" with an empty queue to * above "minthresh" with a nonempty queue. */ edv_.count = 1; edv_.count_bytes = ch->size(); edv_.old = 1; } else if (drop_early(pkt)) { droptype = DTYPE_UNFORCED; } } else { /* No packets are being dropped. */ edv_.v_prob = 0.0; edv_.old = 0; } if (qlen >= qlim) { // see if we've exceeded the queue size droptype = DTYPE_FORCED; } if (droptype == DTYPE_UNFORCED) { /* pick packet for ECN, which is dropping in this case */ Packet *pkt_to_drop = pickPacketForECN(pkt); /* * If the packet picked is different that the one that just arrived, * add it to the queue and remove the chosen packet. */ if (pkt_to_drop != pkt) { q_->enque(pkt); bcount_ += ch->size(); q_->remove(pkt_to_drop); bcount_ -= ((hdr_cmn*)pkt_to_drop->access(off_cmn_))->size(); pkt = pkt_to_drop; /* XXX okay because pkt is not needed anymore */ } // deliver to special "edrop" target, if defined if (de_drop_ != NULL) de_drop_->recv(pkt); else drop(pkt); } else { /* forced drop, or not a drop: first enqueue pkt */ q_->enque(pkt); bcount_ += ch->size(); /* drop a packet if we were told to */ if (droptype == DTYPE_FORCED) { /* drop random victim or last one */ pkt = pickPacketToDrop(); q_->remove(pkt); bcount_ -= ((hdr_cmn*)pkt->access(off_cmn_))->size(); drop(pkt); if (!ns1_compat_) { // bug-fix from Philip Liu, <phill@ece.ubc.ca> edv_.count = 0; edv_.count_bytes = 0; } } } return; } int REDQueue::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "reset") == 0) { reset(); return (TCL_OK); } if (strcmp(argv[1], "early-drop-target") == 0) { if (de_drop_ != NULL) tcl.resultf("%s", de_drop_->name()); return (TCL_OK); } } else if (argc == 3) { // attach a file for variable tracing if (strcmp(argv[1], "attach") == 0) { int mode; const char* id = argv[2]; tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); if (tchan_ == 0) { tcl.resultf("RED: trace: can't attach %s for writing", id); return (TCL_ERROR); } return (TCL_OK); } // tell RED about link stats if (strcmp(argv[1], "link") == 0) { LinkDelay* del = (LinkDelay*)TclObject::lookup(argv[2]); if (del == 0) { tcl.resultf("RED: no LinkDelay object %s", argv[2]); return(TCL_ERROR); } // set ptc now link_ = del; edp_.ptc = link_->bandwidth() / (8. * edp_.mean_pktsize); return (TCL_OK); } if (strcmp(argv[1], "early-drop-target") == 0) { NsObject* p = (NsObject*)TclObject::lookup(argv[2]); if (p == 0) { tcl.resultf("no object %s", argv[2]); return (TCL_ERROR); } de_drop_ = p; return (TCL_OK); } if (!strcmp(argv[1], "packetqueue-attach")) { delete q_; if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2]))) return (TCL_ERROR); else { pq_ = q_; return (TCL_OK); } } } return (Queue::command(argc, argv)); } /* * Routine called by TracedVar facility when variables change values. * Currently used to trace values of avg queue size, drop probability, * and the instantaneous queue size seen by arriving packets. * Note that the tracing of each var must be enabled in tcl to work. */ void REDQueue::trace(TracedVar* v) { char wrk[500], *p; if (((p = strstr(v->name(), "ave")) == NULL) && ((p = strstr(v->name(), "prob")) == NULL) && ((p = strstr(v->name(), "curq")) == NULL)) { fprintf(stderr, "RED:unknown trace var %s\n", v->name()); return; } if (tchan_) { int n; double t = Scheduler::instance().clock(); // XXX: be compatible with nsv1 RED trace entries if (*p == 'c') { sprintf(wrk, "Q %g %d", t, int(*((TracedInt*) v))); } else { sprintf(wrk, "%c %g %g", *p, t, double(*((TracedDouble*) v))); } n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(tchan_, wrk, n+1); } return; } /* for debugging help */ void REDQueue::print_edp() { printf("mean_pktsz: %d\n", edp_.mean_pktsize); printf("bytes: %d, wait: %d, setbit: %d\n", edp_.bytes, edp_.wait, edp_.setbit); printf("minth: %f, maxth: %f\n", edp_.th_min, edp_.th_max); printf("max_p_inv: %f, qw: %f, ptc: %f\n", edp_.max_p_inv, edp_.q_w, edp_.ptc); printf("qlim: %d, idletime: %f\n", qlim_, idletime_); printf("=========\n"); } void REDQueue::print_edv() { printf("v_a: %f, v_b: %f\n", edv_.v_a, edv_.v_b); }

replicator.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1996 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "classifier.h" #include "packet.h" #include "ip.h" /* * A replicator is not really a packet classifier but * we simply find convenience in leveraging its slot table. * (this object used to implement fan-out on a multicast * router as well as broadcast LANs) */ class Replicator : public Classifier { public: Replicator(); void recv(Packet*, Handler* h = 0); virtual int classify(Packet*) {/*NOTREACHED*/ return -1;}; protected: virtual int command(int argc, const char*const* argv); int ignore_; }; static class ReplicatorClass : public TclClass { public: ReplicatorClass() : TclClass("Classifier/Replicator") {} TclObject* create(int, const char*const*) { return (new Replicator()); } } class_replicator; Replicator::Replicator() : ignore_(0) { bind("ignore_", &ignore_); } void
Replicator::recv(Packet* p, Handler*) { hdr_ip* iph = hdr_ip::access(p); hdr_cmn* ch = hdr_cmn::access(p); if (maxslot_ < 0) { if (!ignore_) Tcl::instance().evalf("%s drop %ld %ld %d", name(), iph->saddr(), iph->daddr(), ch->iface()); Packet::free(p); return; } for (int i = 0; i < maxslot_; ++i) { NsObject* o = slot_[i]; if (o != 0) o->recv(p->copy()); } /* we know that maxslot is non-null */ slot_[maxslot_]->recv(p); } int Replicator::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { /* * $replicator slot */ if (strcmp(argv[1], "slots") == 0) { if (maxslot_ < 0) { tcl.result(""); return (TCL_OK); } for (int i = 0; i <= maxslot_; i++) { if (slot_[i] == 0) continue; tcl.resultf("%s %s", tcl.result(), slot_[i]->name()); } return (TCL_OK); } } return Classifier::command(argc, argv); }

resv.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #include "packet.h" #include "resv.h" int hdr_resv::offset_; static class ResvHeaderClass : public PacketHeaderClass { public: ResvHeaderClass() : PacketHeaderClass("PacketHeader/Resv", sizeof(hdr_resv)) { bind_offset(&hdr_resv::offset_); } void export_offsets() { field_offset("rate_", OFFSET(hdr_resv, rate_)); field_offset("bucket_", OFFSET(hdr_resv, bucket_)); field_offset("decision_", OFFSET(hdr_resv, decision_)); } } class_resvhdr;

rlm.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1994-1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include "agent.h" #include "node.h" struct srcpkt { double off; int level; int size; srcpkt* next; }; class RLM_Sender : public Agent { public: RLM_Sender(); ~RLM_Sender(); int command(int argc, const char*const* argv); protected: virtual void timeout(int); void start(); void stop(); void sched_next(); void sendpkt(int size, int level); void addpkt(double off, int size, int level); int running_; double interval_; srcpkt* pkt_; srcpkt* allpkt_; /*XXX make size dynamic*/ #define MAXLEVEL 32 int seqno_[MAXLEVEL]; int blkno_; }; static class RLMMatcher : public Matcher { public: RLMMatcher() : Matcher("agent") {} TclObject* match(const char* id) { if (strcmp(id, "rlm-sender") == 0) return (new RLM_Sender()); return (0); } } matcher_rlm; RLM_Sender::RLM_Sender() : Agent(PT_CBR), pkt_(0), allpkt_(0) { Tcl& tcl = Tcl::instance(); link_time("ns_rlm", "interval", &interval_, 0); link_int("ns_rlm", "packet-size", &size_, 0); running_ = 0; memset(seqno_, 0, sizeof(seqno_)); blkno_ = 0; } RLM_Sender::~RLM_Sender() { /*XXX free allpkt_ */ } void
RLM_Sender::start() { if (allpkt_ != 0) { running_ = 1; pkt_ = allpkt_; sched(pkt_->off, 0); } } void RLM_Sender::stop() { running_ = 0; } void RLM_Sender::sched_next() { srcpkt* p = pkt_; srcpkt* n = p->next; double t; if (n == 0) { t = interval_; n = allpkt_; ++blkno_; blkitem_ = 0; } else t = 0.; t += n->off - p->off; pkt_ = n; sched(t, 0); } void RLM_Sender::timeout(int) { if (running_) { sendpkt(pkt_->size, pkt_->level); sched_next(); } } void RLM_Sender::sendpkt(int size, int level) { Packet* p = allocpkt(seqno_[level]++); IPHeader *iph = IPHeader::access(p->bits()); RLMHeader *rh = RLMHeader::access(p->bits()); rh->blkno() = blkno_; rh->blkitem() = blkitem_++; iph->size() = size; iph->daddr() += level; #ifdef notdef iph->class() += level;/*XXX*/ #endif node_->transmit(p); } extern double time_atof(const char*); void RLM_Sender::addpkt(double off, int size, int level) { srcpkt* sp = new srcpkt; sp->next = 0; sp->off = off; sp->size = size; sp->level = level; srcpkt** p; for (p = &allpkt_; *p != 0; p = &(*p)->next) if (sp->off < (*p)->off) break; *p = sp; } /* * $obj start * $obj stop * $obj packet $off $size $level */ int RLM_Sender::command(int argc, const char*const* argv) { if (argc == 2) { if (strcmp(argv[1], "start") == 0) { start(); return (TCL_OK); } if (strcmp(argv[1], "stop") == 0) { stop(); return (TCL_OK); } } if (argc == 5) { if (strcmp(argv[1], "packet") == 0) { double off = time_atof(argv[2]); int size = atoi(argv[3]); int level = atoi(argv[4]); addpkt(off, size, level); return (TCL_OK); } } return (Agent::command(argc, argv)); } class RLM_Receiver : public Agent { public: RLM_Receiver(); int command(int argc, const char*const* argv); void recv(Packet* pkt); protected: char* proc_; int loss_; int expected_; int bytes_; int pblk_; int pseq_[MAXLEVEL]; }; static class RLM_ReceiverMatcher : public Matcher { public: RLM_ReceiverMatcher() : Matcher("agent") {} TclObject* match(const char* id) { if (strcmp(id, "rlm-receiver") == 0) return (new RLM_Receiver()); return (0); } } matcher_cbr; RLM_Receiver::RLM_Receiver() : Agent(-1), proc_(0), expected_(-1) { bytes_ = 0; loss_ = 0; link_int(0, "loss", &loss_, 1); link_int(0, "bytes", &bytes_, 1); } void RLM_Receiver::recv(Packet* pkt) { IPHeader *iph = IPHeader::access(pkt->bits()); SequenceHeader *sh = SequenceHeader::access(pkt->bits()); bytes_ += iph->size(); int seqno = sh->seqno(); int blkno = seqno >> 16; seqno &= 0xffff; /* * Check for lost packets */ if (expected_ >= 0) { int loss = sh->seqno() - expected_; if (loss > 0) { loss_ += loss; if (proc_ != 0) Tcl::instance().eval(proc_); } } expected_ = sh->seqno() + 1; Packet::free(pkt); } /* * $proc interval $interval * $proc size $size */ int RLM_Receiver::command(int argc, const char*const* argv) { if (argc == 2) { if (strcmp(argv[1], "clear") == 0) { expected_ = -1; return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "proc") == 0) { const char* proc = argv[2]; int n = strlen(proc) + 1; delete proc_; proc_ = new char[n]; strcpy(proc_, proc); return (TCL_OK); } } return (Agent::command(argc, argv)); }

rng.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif /* new random number generator */ #ifndef WIN32 #include <sys/time.h> // for gettimeofday #include <unistd.h> #endif #include <stdio.h> #include "rng.h" #include "config.h" // for gettimeofday #ifndef MAXINT #define MAXINT 2147483647 // XX [for now] #endif /* * RNGImplementation */ /* * Generate a periodic sequence of pseudo-random numbers with * a period of 2^31 - 2. The generator is the "minimal standard" * multiplicative linear congruential generator of Park, S.K. and * Miller, K.W., "Random Number Generators: Good Ones are Hard to Find," * CACM 31:10, Oct. 88, pp. 1192-1201. * * The algorithm implemented is: Sn = (a*s) mod m. * The modulus m can be approximately factored as: m = a*q + r, * where q = m div a and r = m mod a. * * Then Sn = g(s) + m*d(s) * where g(s) = a(s mod q) - r(s div q) * and d(s) = (s div q) - ((a*s) div m) * * Observations: * - d(s) is either 0 or 1. * - both terms of g(s) are in 0, 1, 2, . . ., m - 1. * - |g(s)| <= m - 1. * - if g(s) > 0, d(s) = 0, else d(s) = 1. * - s mod q = s - k*q, where k = s div q. * * Thus Sn = a(s - k*q) - r*k, * if (Sn <= 0), then Sn += m. * * To test an implementation for A = 16807, M = 2^31-1, you should * get the following sequences for the given starting seeds: * * s0, s1, s2, s3, . . . , s10000, . . . , s551246 * 1, 16807, 282475249, 1622650073, . . . , 1043618065, . . . , 1003 * 1973272912, 1207871363, 531082850, 967423018 * * It is important to check for s10000 and s551246 with s0=1, to guard * against overflow. */ /* * The sparc assembly code [no longer here] is based on Carta, D.G., "Two Fast * Implementations of the 'Minimal Standard' Random Number * Generator," CACM 33:1, Jan. 90, pp. 87-88. * * ASSUME that "the product of two [signed 32-bit] integers (a, sn) * will occupy two [32-bit] registers (p, q)." * Thus: a*s = (2^31)p + q * * From the observation that: x = y mod z is but * x = z * the fraction part of (y/z), * Let: sn = m * Frac(as/m) * * For m = 2^31 - 1, * sn = (2^31 - 1) * Frac[as/(2^31 -1)] * = (2^31 - 1) * Frac[as(2^-31 + 2^-2(31) + 2^-3(31) + . . .)] * = (2^31 - 1) * Frac{[(2^31)p + q] [2^-31 + 2^-2(31) + 2^-3(31) + . . .]} * = (2^31 - 1) * Frac[p+(p+q)2^-31+(p+q)2^-2(31)+(p+q)3^(-31)+ . . .] * * if p+q < 2^31: * sn = (2^31 - 1) * Frac[p + a fraction + a fraction + a fraction + . . .] * = (2^31 - 1) * [(p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .] * = p + q * * otherwise: * sn = (2^31 - 1) * Frac[p + 1.frac . . .] * = (2^31 - 1) * (-1 + 1.frac . . .) * = (2^31 - 1) * [-1 + (p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .] * = p + q - 2^31 + 1 */ #define A 16807L /* multiplier, 7**5 */ #define M 2147483647L /* modulus, 2**31 - 1; both used in random */ #define INVERSE_M ((double)4.656612875e-10) /* (1.0/(double)M) */ long
RNGImplementation::next() { long L, H; L = A * (seed_ & 0xffff); H = A * (seed_ >> 16); seed_ = ((H & 0x7fff) << 16) + L; seed_ -= 0x7fffffff; seed_ += H >> 15; if (seed_ <= 0) { seed_ += 0x7fffffff; } return(seed_); } double RNGImplementation::next_double() { long i = next(); return i * INVERSE_M; } /* * RNG implements a nice front-end around RNGImplementation */ #ifndef stand_alone static class RNGClass : public TclClass { public: RNGClass() : TclClass("RNG") {} TclObject* create(int, const char*const*) { return(new RNG()); } } class_rng; #endif /* stand_alone */ /* default RNG */ RNG* RNG::default_ = NULL; double RNG::normal(double avg, double std) { static int parity = 0; static double nextresult; double sam1, sam2, rad; if (std == 0) return avg; if (parity == 0) { sam1 = 2*uniform() - 1; sam2 = 2*uniform() - 1; while ((rad = sam1*sam1 + sam2*sam2) >= 1) { sam1 = 2*uniform() - 1; sam2 = 2*uniform() - 1; } rad = sqrt((-2*log(rad))/rad); nextresult = sam2 * rad; parity = 1; return (sam1 * rad * std + avg); } else { parity = 0; return (nextresult * std + avg); } } #ifndef stand_alone int RNG::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "testint") == 0) { int n = atoi(argv[2]); tcl.resultf("%d", uniform(n)); return (TCL_OK); } if (strcmp(argv[1], "testdouble") == 0) { double d = atof(argv[2]); tcl.resultf("%6e", uniform(d)); return (TCL_OK); } if (strcmp(argv[1], "seed") == 0) { int s = atoi(argv[2]); // NEEDSWORK: should be a way to set seed to PRDEF_SEED_SORUCE if (s) { if (s <= 0 || (unsigned int)s >= MAXINT) { tcl.resultf("Setting random number seed to known bad value."); return TCL_ERROR; }; set_seed(RAW_SEED_SOURCE, s); } else set_seed(HEURISTIC_SEED_SOURCE, 0); return(TCL_OK); } } else if (argc == 2) { if (strcmp(argv[1], "next-random") == 0) { tcl.resultf("%u", uniform_positive_int()); return(TCL_OK); } if (strcmp(argv[1], "seed") == 0) { tcl.resultf("%u", stream_.seed()); return(TCL_OK); } if (strcmp(argv[1], "default") == 0) { default_ = this; return(TCL_OK); } #if 0 if (strcmp(argv[1], "test") == 0) { if (test()) tcl.resultf("RNG test failed"); else tcl.resultf("RNG test passed"); return(TCL_OK); } #endif } else if (argc == 4) { if (strcmp(argv[1], "normal") == 0) { double avg = strtod(argv[2], NULL); double std = strtod(argv[3], NULL); tcl.resultf("%g", normal(avg, std)); return (TCL_OK); } else if (strcmp(argv[1], "lognormal") == 0) { double avg = strtod(argv[2], NULL); double std = strtod(argv[3], NULL); tcl.resultf("%g", lognormal(avg, std)); return (TCL_OK); } } return(TclObject::command(argc, argv)); } #endif /* stand_alone */ void RNG::set_seed(RNGSources source, int seed) { /* The following predefined seeds are evenly spaced around * the 2^31 cycle. Each is approximately 33,000,000 elements * apart. */ #define N_SEEDS_ 64 static long predef_seeds[N_SEEDS_] = { 1973272912L, 188312339L, 1072664641L, 694388766L, 2009044369L, 934100682L, 1972392646L, 1936856304L, 1598189534L, 1822174485L, 1871883252L, 558746720L, 605846893L, 1384311643L, 2081634991L, 1644999263L, 773370613L, 358485174L, 1996632795L, 1000004583L, 1769370802L, 1895218768L, 186872697L, 1859168769L, 349544396L, 1996610406L, 222735214L, 1334983095L, 144443207L, 720236707L, 762772169L, 437720306L, 939612284L, 425414105L, 1998078925L, 981631283L, 1024155645L, 822780843L, 701857417L, 960703545L, 2101442385L, 2125204119L, 2041095833L, 89865291L, 898723423L, 1859531344L, 764283187L, 1349341884L, 678622600L, 778794064L, 1319566104L, 1277478588L, 538474442L, 683102175L, 999157082L, 985046914L, 722594620L, 1695858027L, 1700738670L, 1995749838L, 1147024708L, 346983590L, 565528207L, 513791680L }; static long heuristic_sequence = 0; switch (source) { case RAW_SEED_SOURCE: // use it as it is break; case PREDEF_SEED_SOURCE: if (seed < 0 || seed >= N_SEEDS_) abort(); seed = predef_seeds[seed]; break; case HEURISTIC_SEED_SOURCE: timeval tv; gettimeofday(&tv, 0); heuristic_sequence++; // Always make sure we're different than last time. seed = (tv.tv_sec ^ tv.tv_usec ^ (heuristic_sequence << 8)) & 0x7fffffff; break; }; // set it // NEEDSWORK: should we throw out known bad seeds? // (are there any?) if (seed < 0) seed = -seed; stream_.set_seed(seed); // Toss away the first few values of heuristic seed. // In practice this makes sequential heuristic seeds // generate different first values. // // How many values to throw away should be the subject // of careful analysis. Until then, I just throw away // ``a bunch''. --johnh if (source == HEURISTIC_SEED_SOURCE) { int i; for (i = 0; i < 128; i++) { stream_.next(); }; }; } /* * RNGTest: * Make sure the RNG makes known values. * Optionally, print out some stuff. * * Simple test program: * #include "rng.h" * void main() { RNGTest test; test.verbose(); } */ #ifdef rng_test RNGTest::RNGTest() { RNG rng(RNG::RAW_SEED_SOURCE, 1L); int i; long r; for (i = 0; i < 10000; i++) r = rng.uniform_positive_int(); if (r != 1043618065L) abort(); for (i = 10000; i < 551246; i++) r = rng.uniform_positive_int(); if (r != 1003L) abort(); } void RNGTest::first_n(RNG::RNGSources source, long seed, int n) { RNG rng(source, seed); for (int i = 0; i < n; i++) { int r = rng.uniform_positive_int(); printf("%10d ", r); }; printf("\n"); } void RNGTest::verbose() { printf ("default: "); first_n(RNG::RAW_SEED_SOURCE, 1L, 5); int i; for (i = 0; i < 64; i++) { printf ("predef source %2d: ", i); first_n(RNG::PREDEF_SEED_SOURCE, i, 5); }; printf("heuristic seeds should be different from each other and on each run.\n"); for (i = 0; i < 64; i++) { printf ("heuristic source %2d: ", i); first_n(RNG::HEURISTIC_SEED_SOURCE, i, 5); }; } #endif /* rng_test */

route.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1991-1994 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and the Network Research Group at * Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Routing code for general topologies based on min-cost routing algorithm in * Bertsekas' book. Written originally by S. Keshav, 7/18/88 * (his work covered by identical UC Copyright) */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include <stdlib.h> #include <assert.h> #include "config.h" #include "route.h" #include "address.h" class RouteLogicClass : public TclClass { public: RouteLogicClass() : TclClass("RouteLogic") {} TclObject* create(int, const char*const*) { return (new RouteLogic()); } } routelogic_class; void
RouteLogic::reset_all() { delete[] adj_; delete[] route_; adj_ = 0; route_ = 0; size_ = 0; } int RouteLogic::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "compute") == 0) { if (adj_ == 0) { //fprintf(stderr, "No adjacency info; Probably a disconnected topology! Route not computed..\n"); return (TCL_OK); } compute_routes(); return (TCL_OK); } if (strcmp(argv[1], "hier-compute") == 0) { if (hadj_ == 0) { return (TCL_OK); } hier_compute(); return (TCL_OK); } if (strcmp(argv[1], "hier-print") == 0) { hier_print_hadj(); return (TCL_OK); } if (strcmp(argv[1], "hier-print-route") == 0) { hier_print_route(); return (TCL_OK); } if (strcmp(argv[1], "reset") == 0) { reset_all(); return (TCL_OK); } } else if (argc > 2) { if (strcmp(argv[1], "insert") == 0) { int src = atoi(argv[2]) + 1; int dst = atoi(argv[3]) + 1; if (src <= 0 || dst <= 0) { tcl.result("negative node number"); return (TCL_ERROR); } double cost = (argc == 5 ? atof(argv[4]) : 1); insert(src, dst, cost); return (TCL_OK); } if (strcmp(argv[1], "hlevel-is") == 0) { level_ = atoi(argv[2]); if (level_ < 1) { tcl.result("send-hlevel: # hierarchy levels should be non-zero"); return (TCL_ERROR); } return (TCL_OK); } if (strcmp(argv[1], "send-num-of-domains") == 0) { D_ = atoi(argv[2]) + 1; if (D_ <= 1) { tcl.result("send-num-of-domains: # domains should be non-zero"); return (TCL_ERROR); } return (TCL_OK); } if (strcmp(argv[1], "send-num-of-clusters") == 0) { if (argc != D_ + 1) { tcl.result("send-num-of-clusters: # args do not match as expected\n"); return (TCL_ERROR); } C_ = new int[D_]; int i, j = 2; for (i = 1; i < D_; i++) { C_[i] = atoi(argv[j]) + 1; j++; } hier_init(); return (TCL_OK); } if(strcmp(argv[1], "send-num-of-nodes") == 0) { int i, j, k=2, Ctotal=0 ; for (i=1; i < D_; i++) Ctotal = Ctotal + (C_[i]-1); if (argc != (Ctotal + 2)) { tcl.result("send-hlastdata: # args do not match"); return (TCL_ERROR); } for (i=1; i < D_; i++) for (j=1; (j < C_[i]); j++) { cluster_size_[INDEX(i, j, Cmax_)] = atoi(argv[k]); k++; } return (TCL_OK); } if (strcmp(argv[1], "hier-insert") == 0) { if(Cmax_== 0 || D_== 0) { tcl.result("Required Hier_data not sent"); return (TCL_ERROR); } int i; int src_addr[SMALL_LEN], dst_addr[SMALL_LEN]; /* initializing src and dst addr */ // for (i=0; i < SMALL_LEN; i++){ // src_addr[i] = 0; // dst_addr[i] = 0; // } str2address(argv, src_addr, dst_addr); // for (i=0; i < HIER_LEVEL; i++) for (i=0; i < level_; i++) if (src_addr[i]<=0 || dst_addr[i]<=0){ tcl.result ("negative node number"); return (TCL_ERROR); } int cost = (argc == 5 ? atoi(argv[4]) : 1); hier_insert(src_addr, dst_addr, cost); return (TCL_OK); } if (strcmp(argv[1], "hier-reset") == 0) { int i; int src_addr[SMALL_LEN], dst_addr[SMALL_LEN]; str2address(argv, src_addr, dst_addr); // assuming node-node addresses (instead of node-cluster or node-domain pair) // are sent for hier_reset // for (i=0; i < HIER_LEVEL; i++) for (i=0; i < level_; i++) if (src_addr[i]<=0 || dst_addr[i]<=0){ tcl.result ("negative node number"); return (TCL_ERROR); } hier_reset(src_addr, dst_addr); } if (strcmp(argv[1], "hier-lookup") == 0) { int nh; int res = lookup_hier((char*)argv[2], (char*)argv[3], nh); return res; } if (strcmp(argv[1], "reset") == 0) { int src = atoi(argv[2]) + 1; int dst = atoi(argv[3]) + 1; if (src <= 0 || dst <= 0) { tcl.result("negative node number"); return (TCL_ERROR); } reset(src, dst); return (TCL_OK); } if (strcmp(argv[1], "lookup") == 0) { int nh; int res = lookup_flat((char*)argv[2], (char*)argv[3], nh); if (res == TCL_OK) tcl.resultf("%d", nh); return res; } } return (TclObject::command(argc, argv)); } // xxx: using references as in this result is bogus---use pointers! int RouteLogic::lookup_flat(char* asrc, char* adst, int& result) { Tcl& tcl = Tcl::instance(); int src = atoi(asrc) + 1; int dst = atoi(adst) + 1; if (route_ == 0) { // routes are computed only after the simulator is running // ($ns run). tcl.result("routes not yet computed"); return (TCL_ERROR); } if (src >= size_ || dst >= size_) { tcl.result("node out of range"); return (TCL_ERROR); } result = route_[INDEX(src, dst, size_)].next_hop - 1; return TCL_OK; } // xxx: using references as in this result is bogus---use pointers! int RouteLogic::lookup_hier(char* asrc, char* adst, int& result) { int i; int src[SMALL_LEN], dst[SMALL_LEN]; Tcl& tcl = Tcl::instance(); if ( hroute_ == 0) { tcl.result("Required Hier_data not sent"); return TCL_ERROR; } ns_strtok(asrc, src); ns_strtok(adst, dst); for (i=0; i < level_; i++) if (src[i] <= 0) { tcl.result("negative src node number"); return TCL_ERROR; } if (dst[0] <= 0) { tcl.result("negative dst domain number"); return TCL_ERROR; } int d = src[0]; int index = INDEX(src[0], src[1], Cmax_); int size = cluster_size_[index]; if (hsize_[index] == 0) { tcl.result("Routes not computed"); return TCL_ERROR; } if ((src[0] < D_) || (dst[0] < D_)) { if((src[1] < C_[d]) || (dst[1] < C_[dst[0]])) if((src[2] <= size) || (dst[2] <= cluster_size_[INDEX(dst[0], dst[1], Cmax_)])) ; } else { tcl.result("node out of range"); return TCL_ERROR; } int next_hop = 0; /* if node-domain lookup */ if (((dst[1] <= 0) && (dst[2] <= 0)) || (src[0] != dst[0])){ next_hop = hroute_[index][N_D_INDEX(src[2], dst[0], size, C_[d], D_)]; } /* if node-cluster lookup */ else if ((dst[2] <= 0) || (src[1] != dst[1])) { next_hop = hroute_[index][N_C_INDEX(src[2], dst[1], size, C_[d], D_)]; } /* if node-node lookup */ else { next_hop = hroute_[index][N_N_INDEX(src[2], dst[2], size, C_[d], D_)]; } char target[SMALL_LEN]; if (next_hop > 0) { get_address(target, next_hop, index, d, size, src); tcl.result(target); result= Address::instance().str2addr(target); } else { tcl.result("-1"); result = -1; } return TCL_OK; } RouteLogic::RouteLogic() { size_ = 0; adj_ = 0; route_ = 0; /* additions for hierarchical routing extension */ C_ = 0; D_ = 0; Cmax_ = 0; level_ = 0; hsize_ = 0; hadj_ = 0; hroute_ = 0; hconnect_ = 0; cluster_size_ = 0; } RouteLogic::~RouteLogic() { delete[] adj_; delete[] route_; for (int i = 0; i < (Cmax_ * D_); i++) { for (int j = 0; j < (Cmax_ + D_) * (cluster_size_[i]+1); j++) { if (hconnect_[i][j] != NULL) delete [] hconnect_[i][j]; } delete [] hconnect_[i]; } for (int n =0; n < (Cmax_ * D_); n++) { if (hadj_[n] != NULL) delete [] hadj_[n]; if (hroute_[n] != NULL) delete [] hroute_[n]; } delete [] C_; delete [] hsize_; delete [] cluster_size_; delete hadj_; delete hroute_; delete hconnect_; } void RouteLogic::alloc(int n) { size_ = n; n *= n; adj_ = new adj_entry[n]; for (int i = 0; i < n; ++i) { adj_[i].cost = INFINITY; adj_[i].entry = 0; } } /* * Check that we have enough storage in the adjacency array * to hold a node numbered "n" */ void RouteLogic::check(int n) { if (n < size_) return; adj_entry* old = adj_; int osize = size_; int m = osize; if (m == 0) m = 16; while (m <= n) m <<= 1; alloc(m); for (int i = 0; i < osize; ++i) { for (int j = 0; j < osize; ++j) adj_[INDEX(i, j, m)].cost =old[INDEX(i, j, osize)].cost; } size_ = m; delete[] old; } void RouteLogic::insert(int src, int dst, double cost) { check(src); check(dst); adj_[INDEX(src, dst, size_)].cost = cost; } void RouteLogic::insert(int src, int dst, double cost, void* entry_) { check(src); check(dst); adj_[INDEX(src, dst, size_)].cost = cost; adj_[INDEX(src, dst, size_)].entry = entry_; } void RouteLogic::reset(int src, int dst) { assert(src < size_); assert(dst < size_); adj_[INDEX(src, dst, size_)].cost = INFINITY; } void RouteLogic::compute_routes() { int n = size_; int* parent = new int[n]; double* hopcnt = new double[n]; #define ADJ(i, j) adj_[INDEX(i, j, size_)].cost #define ADJ_ENTRY(i, j) adj_[INDEX(i, j, size_)].entry #define ROUTE(i, j) route_[INDEX(i, j, size_)].next_hop #define ROUTE_ENTRY(i, j) route_[INDEX(i, j, size_)].entry delete[] route_; route_ = new route_entry[n * n]; memset((char *)route_, 0, n * n * sizeof(route_[0])); /* do for all the sources */ int k; for (k = 1; k < n; ++k) { int v; for (v = 0; v < n; v++) parent[v] = v; /* set the route for all neighbours first */ for (v = 1; v < n; ++v) { if (parent[v] != k) { hopcnt[v] = ADJ(k, v); if (hopcnt[v] != INFINITY) { ROUTE(k, v) = v; ROUTE_ENTRY(k, v) = ADJ_ENTRY(k, v); } } } for (v = 1; v < n; ++v) { /* * w is the node that is the nearest to the subtree * that has been routed */ int o = 0; /* XXX */ hopcnt[0] = INFINITY; int w; for (w = 1; w < n; w++) if (parent[w] != k && hopcnt[w] < hopcnt[o]) o = w; parent[o] = k; /* * update distance counts for the nodes that are * adjacent to o */ if (o == 0) continue; for (w = 1; w < n; w++) { if (parent[w] != k && hopcnt[o] + ADJ(o, w) < hopcnt[w]) { ROUTE(k, w) = ROUTE(k, o); ROUTE_ENTRY(k, w) = ROUTE_ENTRY(k, o); hopcnt[w] = hopcnt[o] + ADJ(o, w); } } } } /* * The route to yourself is yourself. */ for (k = 1; k < n; ++k) { ROUTE(k, k) = k; ROUTE_ENTRY(k, k) = 0; // This should not matter } delete[] hopcnt; delete[] parent; } /* hierarchical routing support */ /* This function creates adjacency matrix for each cluster at the lowest level of the hierarchy for every node in the cluster, for every other cluster in the domain, and every other domain. can be extended from 3-level hierarchy to n-level along similar lines*/ void RouteLogic::hier_alloc(int i) { hsize_[i] = cluster_size_[i]+ Cmax_+ D_ ; hsize_[i] *= hsize_[i]; hadj_[i] = new int[hsize_[i]]; hroute_[i] = new int[hsize_[i]]; hconnect_[i] = new char*[(Cmax_ + D_) * (cluster_size_[i]+1)]; for (int n = 0; n < hsize_[i]; n++){ hadj_[i][n] = INFINITY; hroute_[i][n] = INFINITY; } } void RouteLogic::hier_check(int i) { if(hsize_[i] > 0) return; else hier_alloc(i); } void RouteLogic::hier_init(void) { int i; for (i = 1; i < D_; i++) { Cmax_ = C_[i] > Cmax_ ? C_[i]: Cmax_; } int arr_size = Cmax_ * D_ ; cluster_size_ = new int[arr_size]; hsize_ = new int[arr_size]; for (i = 0; i < arr_size; i++) hsize_[i] = 0; hadj_ = new int*[arr_size]; hroute_ = new int*[arr_size]; hconnect_ = new char**[arr_size]; } void RouteLogic::str2address(const char*const* argv, int *src_addr, int *dst_addr) { char src[SMALL_LEN]; char dst[SMALL_LEN]; strcpy(src, argv[2]); strcpy(dst, argv[3]); ns_strtok(src, src_addr); ns_strtok(dst, dst_addr); } void RouteLogic::ns_strtok(char *addr, int *addrstr) { int i; char tmpstr[SMALL_LEN]; char *next, *index; i = 0; strcpy(tmpstr, addr); next = tmpstr; while(*next){ index = strstr(next, "."); if (index != NULL){ next[index - next] = '\0'; addrstr[i] = atoi(next) + 1; next = index + 1; i++; } else { if (*next != '\0') //damn that ending point addrstr[i] = atoi(next) + 1; break; } } } void RouteLogic::get_address(char *address, int next_hop, int index, int d, int size, int *src) { if (next_hop <= size) { sprintf(address,"%d.%d.%d", src[0]-1, src[1]-1, next_hop-1); } else if ((next_hop > size) && (next_hop < (size + C_[d]))) { int temp = next_hop - size; int I = src[2] * (C_[d] + D_) + temp; strcpy(address, hconnect_[index][I]); } else { int temp = next_hop - size - (C_[d] - 1); int I = src[2] * (C_[d] + D_) + (C_[d] - 1 + temp); strcpy(address,hconnect_[index][I]); } } void RouteLogic::hier_reset(int *src, int *dst) { int i, d, n; d = src[0]; if (src[0] == dst[0]) if (src[1] == dst[1]) { i = INDEX(src[0], src[1], Cmax_); n = cluster_size_[i]; hadj_[i][N_N_INDEX(src[2], dst[2], n, C_[d], D_)] = INFINITY; } else { for (int y=1; y < C_[d]; y++) { i = INDEX(src[0], y, Cmax_); n = cluster_size_[i]; hadj_[i][C_C_INDEX(src[1], dst[1], n, C_[d], D_)] = INFINITY; if (y == src[1]) hadj_[i][N_C_INDEX(src[2], dst[1], n, C_[d], D_)] = INFINITY; } } else { for (int x=1; x < D_; x++) for (int y=1; y < C_[x]; y++) { i = INDEX(x, y, Cmax_); n = cluster_size_[i]; hadj_[i][D_D_INDEX(src[0], dst[0], n, C_[x], D_)] = INFINITY; if ( x == src[0] ){ hadj_[i][C_D_INDEX(src[1], dst[0], n, C_[x], D_)] = INFINITY; if (y == src[1]) hadj_[i][N_D_INDEX(src[2], dst[0], n, C_[x], D_)] = INFINITY; } } } } void RouteLogic::hier_insert(int *src_addr, int *dst_addr, int cost) { int X1 = src_addr[0]; int Y1 = src_addr[1]; int Z1 = src_addr[2]; int X2 = dst_addr[0]; int Y2 = dst_addr[1]; int Z2 = dst_addr[2]; int n, i; if ( X1 == X2) if (Y1 == Y2){ /* * For the same domain & cluster */ i = INDEX(X1, Y1, Cmax_); n = cluster_size_[i]; hier_check(i); hadj_[i][N_N_INDEX(Z1, Z2, n, C_[X1], D_)] = cost; } else { /* * For the same domain but diff clusters */ for (int y=1; y < C_[X1]; y++) { /* insert cluster connectivity */ i = INDEX(X1, y, Cmax_); n = cluster_size_[i]; hier_check(i); hadj_[i][C_C_INDEX(Y1, Y2, n, C_[X1], D_)] = cost; if (y == Y1) { /* insert node conn. */ hadj_[i][N_C_INDEX(Z1, Y2, n, C_[X1], D_)] = cost; int I = Z1 * (C_[X1]+ D_) + Y2; hconnect_[i][I] = new char[SMALL_LEN]; sprintf(hconnect_[i][I],"%d.%d.%d",X2-1,Y2-1,Z2-1); } } } else { /* * For different domains */ for (int x=1; x < D_; x++) { /* inset domain connectivity */ for (int y=1; y < C_[x]; y++) { i = INDEX(x, y, Cmax_); n = cluster_size_[i]; hier_check(i); hadj_[i][D_D_INDEX(X1, X2, n, C_[x], D_)] = cost; } } for (int y=1; y < C_[X1]; y++) { /* insert cluster connectivity */ i = INDEX(X1, y, Cmax_); n = cluster_size_[i]; hier_check(i); hadj_[i][C_D_INDEX(Y1, X2, n, C_[X1], D_)] = cost; } /* insert node connectivity */ i = INDEX(X1, Y1, Cmax_); n = cluster_size_[i]; hadj_[i][N_D_INDEX(Z1, X2, n, C_[X1], D_)] = cost; int I = Z1 * (C_[X1] + D_) + (C_[X1] - 1 + X2); hconnect_[i][I] = new char[SMALL_LEN]; sprintf(hconnect_[i][I],"%d.%d.%d",X2-1,Y2-1,Z2-1); } } void RouteLogic::hier_compute_routes(int i, int j) { int size = (cluster_size_[i] + C_[j] + D_); int n = size ; double* hopcnt = new double[n]; #define HADJ(i, j) adj_[INDEX(i, j, size)].cost #define HROUTE(i, j) route_[INDEX(i, j, size)].next_hop delete[] route_; route_ = new route_entry[n * n]; int* parent = new int[n]; memset((char *)route_, 0, n * n * sizeof(route_[0])); /* do for all the sources */ int k; for (k = 1; k < n; ++k) { int v; for (v = 0; v < n; v++) parent[v] = v; /* set the route for all neighbours first */ for (v = 1; v < n; ++v) { if (parent[v] != k) { hopcnt[v] = HADJ(k, v); if (hopcnt[v] != INFINITY) HROUTE(k, v) = v; } } for (v = 1; v < n; ++v) { /* * w is the node that is the nearest to the subtree * that has been routed */ int o = 0; /* XXX */ hopcnt[0] = INFINITY; int w; for (w = 1; w < n; w++) if (parent[w] != k && hopcnt[w] < hopcnt[o]) o = w; parent[o] = k; /* * update distance counts for the nodes that are * adjacent to o */ if (o == 0) continue; for (w = 1; w < n; w++) { if (parent[w] != k && hopcnt[o] + HADJ(o, w) < hopcnt[w]) { HROUTE(k, w) = HROUTE(k, o); hopcnt[w] = hopcnt[o] + HADJ(o, w); } } } } /* * The route to yourself is yourself. */ for (k = 1; k < n; ++k) HROUTE(k, k) = k; delete[] hopcnt; delete[] parent; } /* function to check the adjacency matrices created */ void RouteLogic::hier_print_hadj() { int i, j, k; for (j=1; j < D_; j++) for (k=1; k < C_[j]; k++) { i = INDEX(j, k, Cmax_); int s = (cluster_size_[i] + C_[j] + D_); printf("ADJ MATRIX[%d] for cluster %d.%d :\n",i,j,k); int temp = 1; printf(" "); while(temp < s){ printf(" %d",temp); temp++; } printf("\n"); for(int n=1; n < s;n++){ printf("%d ",n); for(int m=1;m < s;m++){ if(hadj_[i][INDEX(n,m,s)] == INFINITY) printf("~ "); else printf("%d ",hadj_[i][INDEX(n,m,s)]); } printf("\n"); } printf("\n\n"); } } void RouteLogic::hier_compute() { int i, j, k, m, n; for (j=1; j < D_; j++) for (k=1; k < C_[j]; k++) { i = INDEX(j, k, Cmax_); int s = (cluster_size_[i] + C_[j] + D_); adj_ = new adj_entry[(s * s)]; memset((char *)adj_, 0, s * s * sizeof(adj_[0])); for (n=0; n < s; n++) for(m=0; m < s; m++) adj_[INDEX(n, m, s)].cost = hadj_[i][INDEX(n, m, s)]; hier_compute_routes(i, j); for (n=0; n < s; n++) for(m=0; m < s; m++) hroute_[i][INDEX(n, m, s)] = route_[INDEX(n, m, s)].next_hop; delete [] adj_; } } /* * Prints routing table - debugging function */ void RouteLogic::hier_print_route() { for (int j=1; j < D_; j++) for (int k=1; k < C_[j]; k++) { int i = INDEX(j, k, Cmax_); int s = (cluster_size_[i]+C_[j]+D_); printf("ROUTE_TABLE[%d] for cluster %d.%d :\n",i,j,k); int temp = 1; printf(" "); while(temp < s){ printf(" %d",temp); temp++; } printf("\n"); for(int n=1; n < s; n++){ printf("%d ",n); for(int m=1; m < s; m++) printf("%d ",hroute_[i][INDEX(n, m, s)]); printf("\n"); } printf("\n\n"); } } static class RouteLogicAlgoClass : public TclClass { public: RouteLogicAlgoClass() : TclClass("RouteLogic/Algorithmic") {} TclObject* create(int, const char*const*) { return (new RouteLogicAlgo); } } class_routelogic_algo;

rtProtoDV.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * rtProtoDV.cc * * Copyright (C) 1997 by USC/ISI * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (USC/ISI)"; #endif #include "agent.h" #include "rtProtoDV.h" int hdr_DV::offset_; static class rtDVHeaderClass : public PacketHeaderClass { public: rtDVHeaderClass() : PacketHeaderClass("PacketHeader/rtProtoDV", sizeof(hdr_DV)) { bind_offset(&hdr_DV::offset_); } } class_rtProtoDV_hdr; static class rtProtoDVclass : public TclClass { public: rtProtoDVclass() : TclClass("Agent/rtProto/DV") {} TclObject* create(int, const char*const*) { return (new rtProtoDV); } } class_rtProtoDV; int
rtProtoDV::command(int argc, const char*const* argv) { if (strcmp(argv[1], "send-update") == 0) { ns_addr_t dst; dst.addr_ = atoi(argv[2]); dst.port_ = atoi(argv[3]); u_int32_t mtvar = atoi(argv[4]); u_int32_t size = atoi(argv[5]); sendpkt(dst, mtvar, size); return TCL_OK; } return Agent::command(argc, argv); } void rtProtoDV::sendpkt(ns_addr_t dst, u_int32_t mtvar, u_int32_t size) { daddr() = dst.addr_; dport() = dst.port_; size_ = size; Packet* p = Agent::allocpkt(); hdr_DV *rh = (hdr_DV*)p->access(off_DV_); rh->metricsVar() = mtvar; target_->recv(p); } void rtProtoDV::recv(Packet* p, Handler*) { hdr_DV* rh = (hdr_DV*)p->access(off_DV_); hdr_ip* ih = (hdr_ip*)p->access(off_ip_); Tcl::instance().evalf("%s recv-update %d %d", name(), ih->saddr(), rh->metricsVar()); Packet::free(p); }

rtcp.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include <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. ===================================================================== */
rtqueue::rtqueue() { head_ = tail_ = 0; len_ = 0; limit_ = RTQ_MAX_LEN; timeout_ = RTQ_TIMEOUT; } void rtqueue::enque(Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); p->next_ = 0; ch->ts_ = CURRENT_TIME + timeout_; if (len_ == limit_) { Packet *p0 = remove_head(); // decrements len_ assert(p0); if(HDR_CMN(p0)->ts_ > CURRENT_TIME) { drop(p0, DROP_RTR_QFULL); } else { drop(p0, DROP_RTR_QTIMEOUT); } } if(head_ == 0) { head_ = tail_ = p; } else { tail_->next_ = p; tail_ = p; } len_++; #ifdef DEBUG verifyQueue(); #endif } Packet* rtqueue::deque() { Packet *p; /* * Purge any packets that have timed out. */ purge(); p = remove_head(); #ifdef DEBUG verifyQueue(); #endif return p; } Packet* rtqueue::deque(nsaddr_t dst) { Packet *p, *prev; /* * Purge any packets that have timed out. */ purge(); findPacketWithDst(dst, p, prev); assert(p == 0 || (p == head_ && prev == 0) || (prev->next_ == p)); if(p == 0) return 0; if (p == head_) { p = remove_head(); } else if (p == tail_) { prev->next_ = 0; tail_ = prev; len_--; } else { prev->next_ = p->next_; len_--; } #ifdef DEBUG verifyQueue(); #endif return p; } char rtqueue::find(nsaddr_t dst) { Packet *p, *prev; findPacketWithDst(dst, p, prev); if (0 == p) return 0; else return 1; } /* ====================================================================== Private Routines ====================================================================== */ Packet* rtqueue::remove_head() { Packet *p = head_; if(head_ == tail_) { head_ = tail_ = 0; } else { head_ = head_->next_; } if(p) len_--; return p; } void rtqueue::purge() { Packet *p; while((p = head_) && HDR_CMN(p)->ts_ < CURRENT_TIME) { assert(p == remove_head()); drop(p, DROP_RTR_QTIMEOUT); } } void rtqueue::findPacketWithDst(nsaddr_t dst, Packet*& p, Packet*& prev) { p = prev = 0; for(p = head_; p; p = p->next_) { // if(HDR_IP(p)->dst() == dst) { if(HDR_IP(p)->daddr() == dst) { return; } prev = p; } if(p == 0) prev = 0; // not found } void rtqueue::verifyQueue() { Packet *p, *prev = 0; int cnt = 0; for(p = head_; p; p = p->next_) { cnt++; prev = p; } assert(cnt == len_); assert(prev == tail_); }

rttable.cc


/* The AODV code developed by the CMU/MONARCH group was optimized * and tuned by Samir Das (UTSA) and Mahesh Marina (UTSA). The * work was partially done in Sun Microsystems. * * The original CMU copyright is below. */ /* Copyright (c) 1997, 1998 Carnegie Mellon University. All Rights Reserved. Permission to use, copy, modify, and distribute this software and its documentation is hereby granted (including for commercial or for-profit use), provided that both the copyright notice and this permission notice appear in all copies of the software, derivative works, or modified versions, and any portions thereof, and that both notices appear in supporting documentation, and that credit is given to Carnegie Mellon University in all publications reporting on direct or indirect use of this code or its derivatives. ALL CODE, SOFTWARE, PROTOCOLS, AND ARCHITECTURES DEVELOPED BY THE CMU MONARCH PROJECT ARE EXPERIMENTAL AND ARE KNOWN TO HAVE BUGS, SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS SOFTWARE OR OTHER INTELLECTUAL PROPERTY IN ITS ``AS IS'' CONDITION, AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE OR INTELLECTUAL PROPERTY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Carnegie Mellon encourages (but does not require) users of this software or intellectual property to return any improvements or extensions that they make, and to grant Carnegie Mellon the rights to redistribute these changes without encumbrance. */ /* ported into VINT ns by Ya Xu, Sept. 1999 */ #include <rttable.h> /* ===================================================================== The Routing Table ===================================================================== */
rt_entry::rt_entry() { int i; rt_dst = 0; rt_seqno = 0; rt_nexthop = 0; rt_expire = 0.0; rt_hops = INFINITY2; rt_flags = RTF_DOWN; rt_errors = 0; rt_error_time = 0.0; rt_req_timeout = 0.0; rt_req_cnt = 0; rt_req_last_ttl = 0; hist_indx = 0; for (i=0; i < MAX_HISTORY; i++) { // rt_length[i] = 0; rt_disc_latency[i] = 0.0; } error_propagate_counter = 0; LIST_INIT(&rt_nblist); }; rt_entry::~rt_entry() { Neighbor *nb; while((nb = rt_nblist.lh_first)) { LIST_REMOVE(nb, nb_link); delete nb; } } void rt_entry::nb_insert(nsaddr_t id) { Neighbor *nb = new Neighbor(id); assert(nb); nb->nb_expire = 0; LIST_INSERT_HEAD(&rt_nblist, nb, nb_link); } Neighbor* rt_entry::nb_lookup(nsaddr_t id) { Neighbor *nb = rt_nblist.lh_first; for(; nb; nb = nb->nb_link.le_next) { if(nb->nb_addr == id) break; } return nb; } /* ===================================================================== The Routing Table ===================================================================== */ rt_entry* rttable::rt_lookup(nsaddr_t id) { rt_entry *rt = rthead.lh_first; for(; rt; rt = rt->rt_link.le_next) { if(rt->rt_dst == id) break; } return rt; } void rttable::rt_delete(nsaddr_t id) { rt_entry *rt = rt_lookup(id); if(rt) { LIST_REMOVE(rt, rt_link); delete rt; } } rt_entry* rttable::rt_add(nsaddr_t id) { rt_entry *rt; assert(rt_lookup(id) == 0); rt = new rt_entry; assert(rt); rt->rt_dst = id; LIST_INSERT_HEAD(&rthead, rt, rt_link); return rt; }

sa.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ //packets after it succeeds in a3-way handshake from the receiver // should be connected with Agent/SignalAck class #include "udp.h" #include "sa.h" #include "ip.h" #include "random.h" #define SAMPLERATE 8000 SA_Agent::SA_Agent() : Agent(PT_UDP), trafgen_(0), rtd_(0), callback_(0), sa_timer_(this), nextPkttime_(-1), running_(0), seqno_(-1) { bind ("off_resv_",&off_resv_); bind("off_rtp_", &off_rtp_); bind_bw("rate_",&rate_); bind("bucket_",&bucket_); bind("packetSize_", &size_); } SA_Agent::~SA_Agent() { if (callback_) delete[] callback_; } static class SA_AgentClass : public TclClass { public: SA_AgentClass() : TclClass("Agent/SA") {} TclObject* create(int, const char*const*) { return (new SA_Agent()); } } class_signalsource_agent; int
SA_Agent::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc==3) { if (strcmp(argv[1], "target") == 0) { target_ = (NsObject*)TclObject::lookup(argv[2]); if (target_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } ctrl_target_=target_; return (TCL_OK); } else if (strcmp(argv[1],"ctrl-target")== 0) { ctrl_target_=(NsObject*)TclObject::lookup(argv[2]); if (ctrl_target_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } return (TCL_OK); } if (strcmp(argv[1], "stoponidle") == 0) { stoponidle(argv[2]); return(TCL_OK); } if (strcmp(argv[1], "attach-traffic") == 0) { trafgen_ =(TrafficGenerator*)TclObject::lookup(argv[2]); if (trafgen_ == 0) { tcl.resultf("no such node %s", argv[2]); return(TCL_ERROR); } return(TCL_OK); } } if (argc == 2) { if (strcmp(argv[1], "start") == 0) { start(); return(TCL_OK); } else if (strcmp(argv[1], "stop") == 0) { stop(); return(TCL_OK); } } return (Agent::command(argc,argv)); } void SA_Agent::start() { //send the request packet if (trafgen_) { trafgen_->init(); //running_=1; sendreq(); } } void SA_Agent::stop() { sendteardown(); if (running_ != 0) { sa_timer_.cancel(); running_ =0; } } void SA_Agent::sendreq() { Packet *p = allocpkt(); hdr_cmn* ch= (hdr_cmn*)p->access(off_cmn_); ch->ptype()=PT_REQUEST; ch->size()=20; //also put in the r,b parameters for the flow in the packet hdr_resv* rv=(hdr_resv*)p->access(off_resv_); rv->decision() =1; rv->rate()=rate_; rv->bucket()=bucket_; ctrl_target_->recv(p); } void SA_Agent::sendteardown() { Packet *p = allocpkt(); hdr_cmn* ch= (hdr_cmn*)p->access(off_cmn_); ch->ptype()=PT_TEARDOWN; ch->size()=20; //also put in the r,b parameters for the flow in the packet hdr_resv* rv=(hdr_resv*)p->access(off_resv_); rv->decision() =1; rv->rate()=rate_; rv->bucket()=bucket_; ctrl_target_->recv(p); } void SA_Agent::recv(Packet *p, Handler *) { hdr_cmn *ch= (hdr_cmn *)p->access(off_cmn_); hdr_resv *rv=(hdr_resv *)p->access(off_resv_); hdr_ip * iph = (hdr_ip*)p->access(off_ip_); if ( ch->ptype() == PT_ACCEPT || ch->ptype() == PT_REJECT ) { ch->ptype() = PT_CONFIRM; // turn the packet around by swapping src and dst // (address and port) ns_addr_t tmp; tmp = iph->src(); iph->src() = iph->dst(); iph->dst() = tmp; ctrl_target_->recv(p); } // put an additional check here to see if admission was granted if (rv->decision()) { //printf("Flow %d accepted @ %f\n",iph->flowid(),Scheduler::instance().clock()); fflush(stdout); double t = trafgen_->next_interval(size_); running_=1; sa_timer_.resched(t); } else { //printf("Flow %d rejected @ %f\n",iph->flowid(),Scheduler::instance().clock()); fflush(stdout); //Currently the flow is stopped if rejected running_=0; } //make an upcall to sched a stoptime for this flow from now Tcl::instance().evalf("%s sched-stop %d",name(),rv->decision()); } void SA_Agent::stoponidle(const char *s) { callback_ = new char[strlen(s)+1]; strcpy(callback_, s); if (trafgen_->on()) { // Tcl::instance().evalf("puts \"%s waiting for burst at %f\"", name(), Scheduler::instance().clock()); rtd_ = 1; } else { stop(); Tcl::instance().evalf("%s %s", name(), callback_); } } void SA_Timer::expire(Event* /*e*/) { a_->timeout(0); } void SA_Agent::timeout(int) { if (running_) { /* send a packet */ sendpkt(); /* figure out when to send the next one */ nextPkttime_ = trafgen_->next_interval(size_); /* schedule it */ sa_timer_.resched(nextPkttime_); /* hack: if we are waiting for a current burst to end * before stopping . . . */ if (rtd_) { if (trafgen_->on() == 0) { stop(); //Tcl::instance().evalf("puts \"%s burst over at %f\"", // name(), Scheduler::instance().clock()); Tcl::instance().evalf("%s sched-stop %d", name(), 0); } } } } void SA_Agent::sendpkt() { Packet* p = allocpkt(); hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_); rh->seqno() = ++seqno_; rh->flags()=0; double local_time=Scheduler::instance().clock(); /*put in "rtp timestamps" and begining of talkspurt labels */ hdr_cmn* ch = (hdr_cmn*)p->access(off_cmn_); ch->timestamp()=(u_int32_t)(SAMPLERATE*local_time); ch->size()=size_; if ((nextPkttime_ != trafgen_->interval()) || (nextPkttime_ == -1)) rh->flags() |= RTP_M; target_->recv(p); } void SA_Agent::sendmsg(int nbytes, const char* /*flags*/) { Packet *p; int n; if (size_) n = nbytes / size_; else printf("Error: SA_Agent size = 0\n"); if (nbytes == -1) { start(); return; } while (n-- > 0) { p = allocpkt(); hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_); rh->seqno() = seqno_; target_->recv(p); } n = nbytes % size_; if (n > 0) { p = allocpkt(); hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_); rh->seqno() = seqno_; target_->recv(p); } idle(); }

saack.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ //SignalAckClass //Null receiver agent which merely acknowledges a request #include "agent.h" #include "ip.h" #include "resv.h" class SAack_Agent : public Agent { public: SAack_Agent(); protected: void recv(Packet *, Handler *); int command(int,const char* const*); int off_resv_; }; SAack_Agent::SAack_Agent(): Agent(PT_TCP) { bind("off_resv_",&off_resv_); } static class SAackClass : public TclClass { public: SAackClass() : TclClass("Agent/SAack") {} TclObject* create(int, const char*const*) { return (new SAack_Agent()); } } class_saack; void
SAack_Agent::recv(Packet *p, Handler *h) { hdr_cmn *ch = (hdr_cmn*)p->access(off_cmn_); if (ch->ptype() == PT_REQUEST) { Packet *newp =allocpkt(); hdr_cmn *newch=(hdr_cmn*)newp->access(off_cmn_); newch->size()=ch->size(); // turn the packet around by swapping src and dst hdr_ip * iph = (hdr_ip*)p->access(off_ip_); hdr_ip * newiph = (hdr_ip*)newp->access(off_ip_); newiph->dst()=iph->src(); newiph->flowid()=iph->flowid(); newiph->prio()=iph->prio(); hdr_resv* rv=(hdr_resv*)p->access(off_resv_); hdr_resv* newrv=(hdr_resv*)newp->access(off_resv_); newrv->decision()=rv->decision(); newrv->rate()=rv->rate(); newrv->bucket()=rv->bucket(); if (rv->decision()) newch->ptype() = PT_ACCEPT; else newch->ptype() = PT_REJECT; target_->recv(newp); Packet::free(p); return; } Agent::recv(p,h); } int SAack_Agent::command(int argc, const char*const* argv) { return (Agent::command(argc,argv)); }

salink.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ #include "packet.h" #include "ip.h" #include "resv.h" #include "connector.h" #include "adc.h" #include "salink.h" static class SALinkClass : public TclClass { public: SALinkClass() : TclClass("SALink") {} TclObject* create(int, const char*const*) { return (new SALink()); } }class_salink; SALink::SALink() : adc_(0), numfl_(-1), tchan_(0), onumfl_(0), last_(-1) { int i; for (i=0;i<NFLOWS;i++) { pending_[i].flowid=-1; pending_[i].status=0; } bind("off_resv_",&off_resv_); bind("off_ip_",&off_ip_); bind("src_", &src_); bind("dst_", &dst_); numfl_.tracer(this); numfl_.name("\"Admitted Flows\""); } void
SALink::recv(Packet *p, Handler *h) { int decide; int j; hdr_cmn *ch=(hdr_cmn*)p->access(off_cmn_); hdr_ip *iph=(hdr_ip*)p->access(off_ip_); hdr_resv *rv=(hdr_resv*)p->access(off_resv_); //CLEAN THIS UP int cl=(iph->flowid())?1:0; switch(ch->ptype()) { case PT_REQUEST: decide=adc_->admit_flow(cl,rv->rate(),rv->bucket()); if (tchan_) if (last_ != decide) { int n; char wrk[50]; double t = Scheduler::instance().clock(); sprintf(wrk, "l -t %g -s %d -d %d -S COLOR -c %s", t, src_, dst_, decide ? "MediumBlue" : "red" ); n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(tchan_, wrk, n+1); last_ = decide; } //put decide in the packet rv->decision() &= decide; if (decide) { j=get_nxt(); pending_[j].flowid=iph->flowid(); //pending_[j].status=decide; numfl_++; } break; case PT_ACCEPT: case PT_REJECT: break; case PT_CONFIRM: { j=lookup(iph->flowid()); if (j!=-1) { if (!rv->decision()) { //decrease the avload for this class adc_->rej_action(cl,rv->rate(),rv->bucket()); numfl_--; } pending_[j].flowid=-1; } break; } case PT_TEARDOWN: { adc_->teardown_action(cl,rv->rate(),rv->bucket()); numfl_--; break; } default: #ifdef notdef error("unknown signalling message type : %d",ch->ptype()); abort(); #endif break; } send(p,h); } int SALink::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); char wrk[500]; if (argc ==3) { if (strcmp(argv[1],"attach-adc") == 0 ) { adc_=(ADC *)TclObject::lookup(argv[2]); if (adc_ ==0 ) { tcl.resultf("no such node %s", argv[2]); return(TCL_ERROR); } return(TCL_OK); } if (strcmp(argv[1], "attach") == 0) { int mode; const char* id = argv[2]; tchan_ = Tcl_GetChannel(tcl.interp(), (char*)id, &mode); if (tchan_ == 0) { tcl.resultf("SALink: trace: can't attach %s for writing", id); return (TCL_ERROR); } return (TCL_OK); } } if (argc == 2) { if (strcmp(argv[1], "add-trace") == 0) { if (tchan_) { sprintf(wrk, "a -t * -n %s:%d-%d -s %d", adc_->type(), src_, dst_, src_); int n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(tchan_, wrk, n+1); numfl_ = 0; } return (TCL_OK); } } return Connector::command(argc,argv); } int SALink::lookup(int flowid) { int i; for (i=0;i<NFLOWS;i++) if (pending_[i].flowid==flowid) return i; return(-1); } int SALink::get_nxt() { int i; for (i=0;i<NFLOWS;i++) { if (pending_[i].flowid==-1) return i; } printf("Ran out of pending space \n"); exit(1); return i; } void SALink::trace(TracedVar* v) { char wrk[500]; int *p, newval; if (strcmp(v->name(), "\"Admitted Flows\"") == 0) { p = &onumfl_; } else { fprintf(stderr, "SALink: unknown trace var %s\n", v->name()); return; } newval = int(*((TracedInt*)v)); if (tchan_) { int n; double t = Scheduler::instance().clock(); /* f -t 0.0 -s 1 -a SA -T v -n Num -v 0 -o 0 */ sprintf(wrk, "f -t %g -s %d -a %s:%d-%d -T v -n %s -v %d -o %d", t, src_, adc_->type(), src_, dst_, v->name(), newval, *p); n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(tchan_, wrk, n+1); } *p = newval; return; }

satgeometry.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1999 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by Tom Henderson, UCB Daedalus Research Group, June 1999 */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "satgeometry.h" #include "satposition.h" static class SatGeometryClass : public TclClass { public: SatGeometryClass() : TclClass("SatGeometry") {} TclObject* create(int, const char*const*) { return (new SatGeometry()); } } class_sat_geometry; // Returns the distance in km between points a and b double
SatGeometry::distance(coordinate a, coordinate b) { double a_x, a_y, a_z, b_x, b_y, b_z; // cartesian spherical_to_cartesian(a.r, a.theta, a.phi, a_x, a_y, a_z); spherical_to_cartesian(b.r, b.theta, b.phi, b_x, b_y, b_z); return (Trace::round(DISTANCE(a_x, a_y, a_z, b_x, b_y, b_z), 1.0E+8)); } void SatGeometry::spherical_to_cartesian(double R, double Theta, double Phi, double &X, double &Y, double &Z) { X = R * sin(Theta) * cos (Phi); Y = R * sin(Theta) * sin (Phi); Z = R * cos(Theta); } // Propagation delay is the distance divided by the speed of light double SatGeometry::propdelay(coordinate a, coordinate b) { double delay = distance(a, b)/LIGHT; return (Trace::round(delay, 1.0E+8)); } double SatGeometry::get_altitude(coordinate a) { return (a.r - EARTH_RADIUS); } // Returns latitude in radians, in the range from -PI/2 to PI/2 double SatGeometry::get_latitude(coordinate a) { return (PI/2 - a.theta); } // Returns (earth-centric) longitude corresponding to the position of the node // (the input coordinate corresponds to fixed coordinate system, through // which the Earth rotates, so we have to scale back the effects of rotation). // The return value ranges from -PI to PI. double SatGeometry::get_longitude(coordinate coord_) { double period = EARTH_PERIOD; // period of earth in seconds // adjust longitude so that it is earth-centric (i.e., account // for earth rotating beneath). double earth_longitude = fmod((coord_.phi - (fmod(NOW + SatPosition::time_advance_,period)/period) * 2*PI), 2*PI); // Bring earth_longitude to be within (-PI, PI) if (earth_longitude < (-1*PI)) earth_longitude = 2*PI + earth_longitude; if (earth_longitude > PI) earth_longitude = (-(2*PI - earth_longitude)); if (fabs(earth_longitude) < 0.0001) return 0; // To avoid trace output of "-0.00" else return (earth_longitude); } // If the satellite is above the elevation mask of the terminal, returns // the elevation mask in radians; otherwise, returns 0. double SatGeometry::check_elevation(coordinate satellite, coordinate terminal, double elev_mask_) { double S = satellite.r; // satellite radius double S_2 = satellite.r * satellite.r; // satellite radius^2 double E = EARTH_RADIUS; double E_2 = E * E; double d, theta, alpha; d = distance(satellite, terminal); if (d < sqrt(S_2 - E_2)) { // elevation angle > 0 theta = acos((E_2+S_2-(d*d))/(2*E*S)); alpha = acos(sin(theta) * S/d); return ( (alpha > elev_mask_) ? alpha : 0); } else return 0; } // This function determines whether two satellites are too far apart // to establish an ISL between them, due to Earth atmospheric grazing // (or shadowing by the Earth itself). Assumes that both satellites nodes // are at the same altitude. The line between the two satellites can be // bisected, and a perpendicular from that point to the Earth's center will // form a right triangle. If the length of this perpendicular is less than // EARTH_RADIUS + ATMOS_MARGIN, the link cannot be established. // int SatGeometry::are_satellites_mutually_visible(coordinate first, coordinate second) { // if we drop a perpendicular from the ISL to the Earth's surface, // we have a right triangle. The atmospheric margin is the minimum // ISL grazing altitude. double c, d, min_radius, grazing_radius; double radius = get_radius(first); // could just use first.r here. double distance_ = distance(first, second); c = radius * radius; d = (distance_/2) * (distance_/2); grazing_radius = (EARTH_RADIUS + ATMOS_MARGIN); min_radius = sqrt(c - d); if (min_radius >= grazing_radius) { return TRUE; } else { return FALSE; } }

sathandoff.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1999 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by Tom Henderson, UCB Daedalus Research Group, June 1999 */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "random.h" #include "sathandoff.h" #include "satlink.h" #include "satroute.h" #include "satposition.h" #include "satnode.h" #include "satgeometry.h" #include <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_; }

satlink.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1999 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by Tom Henderson, UCB Daedalus Research Group, June 1999 */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif /* * Contains source code for: * SatLinkHead * SatLL * SatMac * SatPhy * SatChannel */ #include "satlink.h" #include "sattrace.h" #include "satposition.h" #include "satgeometry.h" #include "satnode.h" #include "errmodel.h" /*==========================================================================*/ /* * _SatLinkHead */ static class SatLinkHeadClass : public TclClass { public: SatLinkHeadClass() : TclClass("Connector/LinkHead/Sat") {} TclObject* create(int, const char*const*) { return (new SatLinkHead); } } class_sat_link_head; SatLinkHead::SatLinkHead() : linkup_(1), phy_tx_(0), phy_rx_(0), mac_(0), satll_(0), queue_(0), errmodel_(0) { } int
SatLinkHead::command(int argc, const char*const* argv) { if (argc == 2) { } else if (argc == 3) { if (strcmp(argv[1], "set_type") == 0) { if (strcmp(argv[2], "geo") == 0) { type_ = LINK_GSL_GEO; return TCL_OK; } else if (strcmp(argv[2], "polar") == 0) { type_ = LINK_GSL_POLAR; return TCL_OK; } else if (strcmp(argv[2], "gsl") == 0) { type_ = LINK_GSL; return TCL_OK; } else if (strcmp(argv[2], "gsl-repeater") == 0) { type_ = LINK_GSL_REPEATER; return TCL_OK; } else if (strcmp(argv[2], "interplane") == 0) { type_ = LINK_ISL_INTERPLANE; return TCL_OK; } else if (strcmp(argv[2], "intraplane") == 0) { type_ = LINK_ISL_INTRAPLANE; return TCL_OK; } else if (strcmp(argv[2], "crossseam") == 0) { type_ = LINK_ISL_CROSSSEAM; return TCL_OK; } else { printf("Unknown link type: %s\n", argv[2]); exit(1); } } if (strcmp(argv[1], "setll") == 0) { satll_ = (SatLL*) TclObject::lookup(argv[2]); if (satll_ == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "setphytx") == 0) { phy_tx_ = (SatPhy*) TclObject::lookup(argv[2]); if (phy_tx_ == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "setphyrx") == 0) { phy_rx_ = (SatPhy*) TclObject::lookup(argv[2]); if (phy_rx_ == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "setmac") == 0) { mac_ = (SatMac*) TclObject::lookup(argv[2]); if (mac_ == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "setqueue") == 0) { queue_ = (Queue*) TclObject::lookup(argv[2]); if (queue_ == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "seterrmodel") == 0) { errmodel_ = (ErrorModel*) TclObject::lookup(argv[2]); if (errmodel_ == 0) return TCL_ERROR; return TCL_OK; } } return (LinkHead::command(argc, argv)); } /*==========================================================================*/ /* * _SatLL */ static class SatLLClass : public TclClass { public: SatLLClass() : TclClass("LL/Sat") {} TclObject* create(int, const char*const*) { return (new SatLL); } } sat_class_ll; void SatLL::recv(Packet* p, Handler* /*h*/) { hdr_cmn *ch = HDR_CMN(p); /* * Sanity Check */ assert(initialized()); // If direction = UP, then pass it up the stack // Otherwise, set direction to DOWN and pass it down the stack if(ch->direction() == hdr_cmn::UP) { uptarget_ ? sendUp(p) : drop(p); return; } ch->direction() = hdr_cmn::DOWN; sendDown(p); } // Encode link layer sequence number, type, and mac address fields void SatLL::sendDown(Packet* p) { hdr_cmn *ch = HDR_CMN(p); hdr_ll *llh = HDR_LL(p); char *mh = (char*)p->access(hdr_mac::offset_); int peer_mac_; SatChannel* satchannel_; llh->seqno_ = ++seqno_; llh->lltype() = LL_DATA; // Set mac src, type, and dst mac_->hdr_src(mh, mac_->addr()); mac_->hdr_type(mh, ETHERTYPE_IP); // We'll just use ETHERTYPE_IP nsaddr_t dst = ch->next_hop(); // a value of -1 is IP_BROADCAST if (dst < -1) { printf("Error: next_hop_ field not set by routing agent\n"); exit(1); } switch(ch->addr_type()) { case NS_AF_INET: case NS_AF_NONE: if (IP_BROADCAST == (u_int32_t) dst) { mac_->hdr_dst((char*) HDR_MAC(p), MAC_BROADCAST); break; } /* * Here is where arp would normally occur. In the satellite * case, we don't arp (for now). Instead, use destination * address to find the mac address corresponding to the * peer connected to this channel. If someone wants to * add arp, look at how the wireless code does it. */ // Cache latest value used if (dst == arpcachedst_) { mac_->hdr_dst((char*) HDR_MAC(p), arpcache_); break; } // Search for peer's mac address (this is the pseudo-ARP) satchannel_ = (SatChannel*) channel(); peer_mac_ = satchannel_->find_peer_mac_addr(dst); if (peer_mac_ < 0 ) { printf("Error: couldn't find dest mac on channel "); printf("NOW %f\n", NOW); exit(1); } else { mac_->hdr_dst((char*) HDR_MAC(p), peer_mac_); arpcachedst_ = dst; arpcache_ = peer_mac_; break; } default: printf("Error: addr_type not set to NS_AF_INET or NS_AF_NONE\n"); exit(1); } // let mac decide when to take a new packet from the queue. Scheduler& s = Scheduler::instance(); s.schedule(downtarget_, p, delay_); } void SatLL::sendUp(Packet* p) { Scheduler& s = Scheduler::instance(); if (hdr_cmn::access(p)->error() > 0) drop(p); else s.schedule(uptarget_, p, delay_); } // Helper function Channel* SatLL::channel() { Phy* phy_ = (Phy*) mac_->downtarget(); return phy_->channel(); } /*==========================================================================*/ /* * _SatMac */ static class SatMacClass : public TclClass { public: SatMacClass() : TclClass("Mac/Sat") {} TclObject* create(int, const char*const*) { return (new SatMac); } } sat_class_mac; void MacSendTimer::expire(Event*) { a_->send_timer(); } void MacRecvTimer::expire(Event*) { a_->recv_timer(); } int SatMac::command(int argc, const char*const* argv) { if(argc == 2) { } else if (argc == 3) { TclObject *obj; if( (obj = TclObject::lookup(argv[2])) == 0) { fprintf(stderr, "%s lookup failed\n", argv[1]); return TCL_ERROR; } if (strcmp(argv[1], "channel") == 0) { //channel_ = (Channel*) obj; return (TCL_OK); } } return Mac::command(argc, argv); } void SatMac::sendUp(Packet* p) { hdr_mac* mh = HDR_MAC(p); int dst = this->hdr_dst((char*)mh); // mac destination address if (((u_int32_t)dst != MAC_BROADCAST) && (dst != index_)) { drop(p); return; } // First bit of packet has arrived-- wait for // (txtime + delay_) before sending up Scheduler::instance().schedule(uptarget_, p, delay_ + mh->txtime()); } void SatMac::sendDown(Packet* p) { Scheduler& s = Scheduler::instance(); double txt; // LINK_HDRSIZE is defined in satlink.h. This is the size of header // information for all layers below IP. Alternatively, one could // derive this information dynamically from packet headers. int packetsize_ = HDR_CMN(p)->size() + LINK_HDRSIZE; if (bandwidth_ != 0) txt = txtime(packetsize_); // For convenience, we encode the transmit time in the Mac header // The packet will be held (for collision detection) for txtime // at the receiving mac. HDR_MAC(p)->txtime() = txt; downtarget_->recv(p, this); // Callback for when this packet's transmission will be done s.schedule(&hRes_, &intr_, txt); } static class UnslottedAlohaMacClass : public TclClass { public: UnslottedAlohaMacClass() : TclClass("Mac/Sat/UnslottedAloha") {} TclObject* create(int, const char*const*) { return (new UnslottedAlohaMac()); } } sat_class_unslottedalohamac; /*==========================================================================*/ /* * _UnslottedAlohaMac */ UnslottedAlohaMac::UnslottedAlohaMac() : SatMac(), tx_state_(MAC_IDLE), rx_state_(MAC_IDLE), rtx_(0), end_of_contention_(0) { bind_time("mean_backoff_", &mean_backoff_); bind("rtx_limit_", &rtx_limit_); bind_time("send_timeout_", &send_timeout_); } void UnslottedAlohaMac::send_timer() { switch (tx_state_) { case MAC_SEND: // We've timed out on send-- back off backoff(); break; case MAC_COLL: // Our backoff timer has expired-- resend sendDown(snd_pkt_); break; default: printf("Error: wrong tx_state in unslotted aloha: %d\n", tx_state_); break; } } void UnslottedAlohaMac::recv_timer() { switch (rx_state_) { case MAC_RECV: // We've successfully waited out the reception end_of_contention(rcv_pkt_); break; default: printf("Error: wrong rx_state in unslotted aloha: %d\n", rx_state_); break; } } void UnslottedAlohaMac::sendUp(Packet* p) { hdr_mac* mh = HDR_MAC(p); if (rx_state_ == MAC_IDLE) { // First bit of packet has arrived-- wait for // txtime to make sure no collisions occur rcv_pkt_ = p; end_of_contention_ = NOW + mh->txtime(); rx_state_ = MAC_RECV; recv_timer_.resched(mh->txtime()); } else { // Collision: figure out if contention phase must be lengthened double temp = NOW + mh->txtime(); if (temp > end_of_contention_) { recv_timer_.resched(temp - NOW); } drop(p); if (rcv_pkt_) drop(rcv_pkt_); rcv_pkt_ = 0; } } void UnslottedAlohaMac::sendDown(Packet* p) { double txt; // compute transmission delay: int packetsize_ = HDR_CMN(p)->size() + LINK_HDRSIZE; if (bandwidth_ != 0) txt = txtime(packetsize_); HDR_MAC(p)->txtime() = txt; // Send the packet down tx_state_ = MAC_SEND; snd_pkt_ = p->copy(); // save a copy in case it gets retransmitted downtarget_->recv(p, this); // Set a timer-- if we do not hear our own transmission within this // interval (and cancel the timer), the send_timer will expire and // we will backoff and retransmit. send_timer_.resched(send_timeout_ + txt); } // Called when contention period ends void UnslottedAlohaMac::end_of_contention(Packet* p) { rx_state_ = MAC_IDLE; if (!p) return; // No packet to free or send up. hdr_mac* mh = HDR_MAC(p); int dst = this->hdr_dst((char*)mh); // mac destination address int src = this->hdr_src((char*)mh); // mac source address if (((u_int32_t)dst != MAC_BROADCAST) && (dst != index_) && (src != index_)) { drop(p); return; } if (src == index_) { // received our own packet: free up transmit side, drop this // packet, and perform callback to queue which is blocked if (!callback_) { printf("Error, queue callback_ is not valid\n"); exit(1); } send_timer_.force_cancel(); tx_state_ = MAC_IDLE; rtx_ = 0; drop(snd_pkt_); // Free the packet cached for retransmission resume(p); } else { // wait for processing delay (delay_) to send packet upwards Scheduler::instance().schedule(uptarget_, p, delay_); } } void UnslottedAlohaMac::backoff(double delay) { double backoff_ = Random::exponential(mean_backoff_); // if number of retransmissions is within limit, do exponential backoff // else drop the packet and resume if (++rtx_ <= rtx_limit_) { tx_state_ = MAC_COLL; delay += backoff_; send_timer_.resched(delay); } else { tx_state_ = MAC_IDLE; rtx_ = 0; resume(snd_pkt_); } } /*==========================================================================*/ /* * _SatPhy */ static class SatPhyClass: public TclClass { public: SatPhyClass() : TclClass("Phy/Sat") {} TclObject* create(int, const char*const*) { return (new SatPhy); } } class_SatPhy; void SatPhy::sendDown(Packet *p) { if (channel_) channel_->recv(p, this); else { // it is possible for routing to change (and a channel to // be disconnected) while a packet // is moving down the stack. Therefore, just log a drop // if there is no channel if ( ((SatNode*) head()->node())->trace() ) ((SatNode*) head()->node())->trace()->traceonly(p); Packet::free(p); } } // Note that this doesn't do that much right now. If you want to incorporate // an error model, you could insert a "propagation" object like in the // wireless case. int SatPhy::sendUp(Packet * /* pkt */) { return TRUE; } int SatPhy::command(int argc, const char*const* argv) { if (argc == 2) { } else if (argc == 3) { TclObject *obj; if( (obj = TclObject::lookup(argv[2])) == 0) { fprintf(stderr, "%s lookup failed\n", argv[1]); return TCL_ERROR; } } return Phy::command(argc, argv); } static class RepeaterPhyClass: public TclClass { public: RepeaterPhyClass() : TclClass("Phy/Repeater") {} TclObject* create(int, const char*const*) { return (new RepeaterPhy); } } class_RepeaterPhy; void RepeaterPhy::recv(Packet* p, Handler*) { struct hdr_cmn *hdr = HDR_CMN(p); if (hdr->direction() == hdr_cmn::UP) { // change direction and send to uptarget (which is // really a Phy_tx that is also a RepeaterPhy) hdr->direction() = hdr_cmn::DOWN; uptarget_->recv(p, (Handler*) 0); } else { sendDown(p); } } void RepeaterPhy::sendDown(Packet *p) { struct hdr_cmn *hdr = HDR_CMN(p); hdr->direction() = hdr_cmn::DOWN; if (channel_) channel_->recv(p, this); else { printf("Error, no channel on repeater\n"); exit(1); } } /*==========================================================================*/ /* * _SatChannel */ static class SatChannelClass : public TclClass { public: SatChannelClass() : TclClass("Channel/Sat") {} TclObject* create(int, const char*const*) { return (new SatChannel); } } class_Sat_channel; SatChannel::SatChannel(void) : Channel() { } double SatChannel::get_pdelay(Node* tnode, Node* rnode) { coordinate a = ((SatNode*)tnode)->position()->coord(); coordinate b = ((SatNode*)rnode)->position()->coord(); return (SatGeometry::propdelay(a, b)); } // This is a helper function that attaches a SatChannel to a Phy void SatChannel::add_interface(Phy* phy_) { phy_->setchnl(this); // Attach phy to this channel phy_->insertchnl(&ifhead_); // Add phy_ to list of phys on the channel } // Remove a phy from a channel void SatChannel::remove_interface(Phy* phy_) { phy_->setchnl(NULL); // Set phy_'s channel pointer to NULL phy_->removechnl(); // Remove phy_ to list of phys on the channel } // Search for destination mac address on this channel. Look through list // of phys on the channel. If the channel connects to a geo repeater, look // for the destination on the corresponding downlink channel. int SatChannel::find_peer_mac_addr(int dst) { Phy *n; Channel* chan_; chan_ = this; n = ifhead_.lh_first; if (n->head()->type() == LINK_GSL_REPEATER) { SatLinkHead* slh = (SatLinkHead*) n->head(); chan_ = slh->phy_tx()->channel(); } for(n = chan_->ifhead_.lh_first; n; n = n->nextchnl() ) { if (n->node()->address() == dst) { return (((SatMac*) n->uptarget())->addr()); } } return -1; }

satnode.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1999 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by Tom Henderson, UCB Daedalus Research Group, June 1999 */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "satnode.h" #include "satlink.h" #include "sattrace.h" #include "sathandoff.h" #include "satposition.h" static class SatNodeClass : public TclClass { public: SatNodeClass() : TclClass("Node/SatNode") {} TclObject* create(int , const char*const* ) { return (new SatNode); } } class_satnode; int SatNode::dist_routing_ = 0; SatNode::SatNode() : ragent_(0), trace_(0), hm_(0) { bind_bool("dist_routing_", &dist_routing_); } int
SatNode::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "set_downlink") == 0) { if (downlink_ != NULL) { tcl.result(downlink_->name()); return (TCL_OK); } } else if (strcmp(argv[1], "set_uplink") == 0) { if (downlink_ != NULL) { tcl.result(uplink_->name()); return (TCL_OK); } } else if (strcmp(argv[1], "start_handoff") == 0) { if (hm_) hm_->start(); else { printf("Error: starting non-existent "); printf("handoff mgr\n"); exit(1); } return (TCL_OK); } else if (strcmp(argv[1], "dump_sats") == 0) { dumpSats(); return (TCL_OK); } } if (argc == 3) { if (strcmp(argv[1], "set_uplink") == 0) { uplink_ = (SatChannel *) TclObject::lookup(argv[2]); if (uplink_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } return (TCL_OK); } else if (strcmp(argv[1], "set_downlink") == 0) { downlink_ = (SatChannel *) TclObject::lookup(argv[2]); if (downlink_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } return (TCL_OK); } else if (strcmp(argv[1], "set_trace") == 0) { trace_ = (SatTrace *) TclObject::lookup(argv[2]); if (trace_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } return (TCL_OK); } else if (strcmp(argv[1], "set_ragent") == 0) { ragent_ = (SatRouteAgent *) TclObject::lookup(argv[2]); if (ragent_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } return (TCL_OK); } else if(strcmp(argv[1], "addif") == 0) { SatPhy* n = (SatPhy*) TclObject::lookup(argv[2]); if(n == 0) return TCL_ERROR; n->insertnode(&ifhead_); n->setnode(this); return TCL_OK; } else if (strcmp(argv[1], "set_position") == 0) { pos_ = (SatPosition*) TclObject::lookup(argv[2]); if (pos_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } return (TCL_OK); } else if (strcmp(argv[1], "set_handoff_mgr") == 0) { hm_ = (LinkHandoffMgr*) TclObject::lookup(argv[2]); if (hm_ == 0) { tcl.resultf("no such object %s", argv[2]); return (TCL_ERROR); } return (TCL_OK); } } return (Node::command(argc, argv)); } // debugging method for dumping out all of the satellite and ISL locations // on demand from OTcl. void SatNode::dumpSats() { SatNode *snodep, *peer_snodep; SatPosition *sposp, *peer_sposp; SatLinkHead *slhp; printf("Dumping satellites at time %.2f\n", NOW); for (snodep= (SatNode*) Node::nodehead_.lh_first; snodep; snodep = (SatNode*) snodep->nextnode()) { // XXX Need check to see if node is a SatNode sposp = snodep->position(); printf("%d\t%.2f\t%.2f\n", snodep->address(), RAD_TO_DEG(SatGeometry::get_latitude(sposp->coord())), RAD_TO_DEG(SatGeometry::get_longitude(sposp->coord()))); } printf("\n"); // Dump satellite links // There is a static list of address classifiers //QQQ printf("Links:\n"); for (snodep= (SatNode*) Node::nodehead_.lh_first; snodep; snodep = (SatNode*) snodep->nextnode()) { // XXX Not all links necessarily satlinks for (slhp = (SatLinkHead*) snodep->linklisthead_.lh_first; slhp; slhp = (SatLinkHead*) slhp->nextlinkhead() ) { if (slhp->type() != LINK_ISL_CROSSSEAM && slhp->type() != LINK_ISL_INTERPLANE && slhp->type() != LINK_ISL_INTRAPLANE) continue; if (!slhp->linkup_) continue; // Link is up. Print out source lat point and dest // lat point. sposp = snodep->position(); peer_snodep = hm_->get_peer(slhp); if (peer_snodep == 0) continue; // this link interface is not attached peer_sposp = peer_snodep->position(); printf("%.2f\t%.2f\t%.2f\t%.2f\n", RAD_TO_DEG(SatGeometry::get_latitude(sposp->coord())), RAD_TO_DEG(SatGeometry::get_longitude(sposp->coord())), RAD_TO_DEG(SatGeometry::get_latitude(peer_sposp->coord())), RAD_TO_DEG(SatGeometry::get_longitude(peer_sposp->coord()))); } } }

satposition.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1999 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by Tom Henderson, UCB Daedalus Research Group, June 1999 */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include "satposition.h" #include "satgeometry.h" #include <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
SatTrace::format(int tt, int s, int d, Packet* p) { #ifdef OFF_HDR hdr_cmn *th = (hdr_cmn*)p->access(off_cmn_); hdr_ip *iph = (hdr_ip*)p->access(off_ip_); hdr_tcp *tcph = (hdr_tcp*)p->access(off_tcp_); hdr_rtp *rh = (hdr_rtp*)p->access(off_rtp_); hdr_srm *sh = (hdr_srm*)p->access(off_srm_); #else hdr_cmn *th = hdr_cmn::access(p); hdr_ip *iph = hdr_ip::access(p); hdr_tcp *tcph = hdr_tcp::access(p); hdr_rtp *rh = hdr_rtp::access(p); hdr_srm *sh = hdr_srm::access(p); #endif const char* sname = "null"; int lasth, nexth, snadd; Node* n; packet_t t = th->ptype(); const char* name = packet_info.name(t); /* SRM-specific */ if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) { if ( sh->type() < 5 && sh->type() > 0 ) { sname = srm_names_[sh->type()]; } } if (name == 0) abort(); int seqno; /* UDP's now have seqno's too */ if (t == PT_RTP || t == PT_CBR || t == PT_UDP || t == PT_EXP || t == PT_PARETO) seqno = rh->seqno(); else if (t == PT_TCP || t == PT_ACK || t == PT_HTTP || t == PT_FTP || t == PT_TELNET) seqno = tcph->seqno(); else seqno = -1; /* * When new flags are added, make sure to change NUMFLAGS * in trace.h */ char flags[NUMFLAGS+1]; for (int i = 0; i < NUMFLAGS; i++) flags[i] = '-'; flags[NUMFLAGS] = 0; #ifdef OFF_HDR hdr_flags* hf = (hdr_flags*)p->access(off_flags_); #else hdr_flags* hf = hdr_flags::access(p); #endif flags[0] = hf->ecn_ ? 'C' : '-'; // Ecn Echo flags[1] = hf->pri_ ? 'P' : '-'; flags[2] = '-'; flags[3] = hf->cong_action_ ? 'A' : '-'; // Congestion Action flags[4] = hf->ecn_to_echo_ ? 'E' : '-'; // Congestion Experienced flags[5] = hf->fs_ ? 'F' : '-'; flags[6] = hf->ecn_capable_ ? 'N' : '-'; #ifdef notdef flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-'; flags[2] = (iph->flags() & PF_USR1) ? '1' : '-'; flags[3] = (iph->flags() & PF_USR2) ? '2' : '-'; flags[5] = 0; #endif char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr()); char *src_portaddr = Address::instance().print_portaddr(iph->sport()); char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr()); char *dst_portaddr = Address::instance().print_portaddr(iph->dport()); // Find position of previous hop and next hop double s_lat = -999, s_lon = -999, d_lat = -999, d_lon = -999; n = Node::nodehead_.lh_first; // XXX what if n is not a SatNode?? Need a dynamic cast here, or make sure that // only sat tracing elements go between sat nodes. // SatNode *sn = dynamic_cast<SatNode*>(n); if (n) { lasth = th->last_hop_; nexth = th->next_hop_; for (; n; n = n->nextnode() ) { SatNode *sn = (SatNode*) n; snadd = sn->address(); if (lasth == snadd) { s_lat = RAD_TO_DEG(SatGeometry::get_latitude(sn->position()->coord())); s_lon = RAD_TO_DEG(SatGeometry::get_longitude(sn->position()->coord())); if (d_lat != -999) break; // Have now found both s and d } if (nexth == snadd) { d_lat = RAD_TO_DEG(SatGeometry::get_latitude(sn->position()->coord())); d_lon = RAD_TO_DEG(SatGeometry::get_longitude(sn->position()->coord())); if (s_lat != -999) break; // Have now found both s and d } } } if (!show_tcphdr_) { sprintf(wrk_, "%c %.4f %d %d %s %d %s %d %s.%s %s.%s %d %d %.2f %.2f %.2f %.2f", tt, round(Scheduler::instance().clock()), lasth, nexth, name, th->size(), flags, iph->flowid() /* was p->class_ */, // iph->src() >> (Address::instance().NodeShift_[1]), // iph->src() & (Address::instance().PortMask_), // iph->dst() >> (Address::instance().NodeShift_[1]), // iph->dst() & (Address::instance().PortMask_), src_nodeaddr, src_portaddr, dst_nodeaddr, dst_portaddr, seqno, th->uid(), /* was p->uid_ */ s_lat, s_lon, d_lat, d_lon); } else { sprintf(wrk_, "%c %.4f %d %d %s %d %s %d %s.%s %s.%s %d %d %d 0x%x %d %d %.2f %.2f %.2f %.2f", tt, round(Scheduler::instance().clock()), lasth, nexth, name, th->size(), flags, iph->flowid(), /* was p->class_ */ // iph->src() >> (Address::instance().NodeShift_[1]), // iph->src() & (Address::instance().PortMask_), // iph->dst() >> (Address::instance().NodeShift_[1]), // iph->dst() & (Address::instance().PortMask_), src_nodeaddr, src_portaddr, dst_nodeaddr, dst_portaddr, seqno, th->uid(), /* was p->uid_ */ tcph->ackno(), tcph->flags(), tcph->hlen(), tcph->sa_length(), s_lat, s_lon, d_lat, d_lon); } #ifdef NAM_TRACE if (namChan_ != 0) sprintf(nwrk_, "%c -t %g -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}", tt, Scheduler::instance().clock(), s, d, name, th->size(), iph->flowid(), th->uid(), iph->flowid(), src_nodeaddr, src_portaddr, dst_nodeaddr, dst_portaddr, seqno,flags,sname); #endif delete [] src_nodeaddr; delete [] src_portaddr; delete [] dst_nodeaddr; delete [] dst_portaddr; } void SatTrace::traceonly(Packet* p) { format(type_, src_, dst_, p); dump(); } // // we need a DequeTraceClass here because a 'h' event need to go together // with the '-' event. It's possible to use a postprocessing script, but // seems that's inconvient. // static class SatDequeTraceClass : public TclClass { public: SatDequeTraceClass() : TclClass("Trace/Sat/Deque") { } TclObject* create(int args, const char*const* argv) { if (args >= 5) return (new SatDequeTrace(*argv[4])); return NULL; } } sat_dequetrace_class; void SatDequeTrace::recv(Packet* p, Handler* h) { // write the '-' event first format(type_, src_, dst_, p); dump(); namdump(); #ifdef NAM_TRACE if (namChan_ != 0) { #ifdef OFF_HDR hdr_cmn *th = (hdr_cmn*)p->access(off_cmn_); hdr_ip *iph = (hdr_ip*)p->access(off_ip_); hdr_srm *sh = (hdr_srm*)p->access(off_srm_); #else hdr_cmn *th = hdr_cmn::access(p); hdr_ip *iph = hdr_ip::access(p); hdr_srm *sh = hdr_srm::access(p); #endif const char* sname = "null"; packet_t t = th->ptype(); const char* name = packet_info.name(t); if (strcmp(name,"SRM") == 0 || strcmp(name,"cbr") == 0 || strcmp(name,"udp") == 0) { if ( sh->type() < 5 && sh->type() > 0 ) { sname = srm_names_[sh->type()]; } } char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr()); char *src_portaddr = Address::instance().print_portaddr(iph->sport()); char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr()); char *dst_portaddr = Address::instance().print_portaddr(iph->dport()); char flags[NUMFLAGS+1]; for (int i = 0; i < NUMFLAGS; i++) flags[i] = '-'; flags[NUMFLAGS] = 0; #ifdef OFF_HDR hdr_flags* hf = (hdr_flags*)p->access(off_flags_); #else hdr_flags* hf = hdr_flags::access(p); #endif flags[0] = hf->ecn_ ? 'C' : '-'; // Ecn Echo flags[1] = hf->pri_ ? 'P' : '-'; flags[2] = '-'; flags[3] = hf->cong_action_ ? 'A' : '-'; // Congestion Action flags[4] = hf->ecn_to_echo_ ? 'E' : '-'; // Congestion Experienced flags[5] = hf->fs_ ? 'F' : '-'; flags[6] = hf->ecn_capable_ ? 'N' : '-'; #ifdef notdef flags[1] = (iph->flags() & PF_PRI) ? 'P' : '-'; flags[2] = (iph->flags() & PF_USR1) ? '1' : '-'; flags[3] = (iph->flags() & PF_USR2) ? '2' : '-'; flags[5] = 0; #endif sprintf(nwrk_, "%c -t %g -s %d -d %d -p %s -e %d -c %d -i %d -a %d -x {%s.%s %s.%s %d %s %s}", 'h', Scheduler::instance().clock(), src_, dst_, name, th->size(), iph->flowid(), th->uid(), iph->flowid(), src_nodeaddr, src_portaddr, dst_nodeaddr, dst_portaddr, -1, flags, sname); namdump(); delete [] src_nodeaddr; delete [] src_portaddr; delete [] dst_nodeaddr; delete [] dst_portaddr; } #endif /* hack: if trace object not attached to anything free packet */ if (target_ == 0) Packet::free(p); else send(p, h); }

scheduler.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1994 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header$ */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif #include <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
Scheduler::schedule(Handler* h, Event* e, double delay) { if (e->uid_ > 0) { printf("Scheduler: Event UID not valid!\n\n"); abort(); } if (delay < 0) { // You probably don't want to do this // (it probably represents a bug in your simulation). fprintf(stderr, "warning: ns Scheduler::schedule: scheduling event\n\twith negative delay (%f) at time %f.\n", delay, clock_); } if (uid_ < 0 || uid_ >= INT_MAX) { fprintf(stderr, "Scheduler: UID space exhausted!\n"); abort(); } e->uid_ = uid_++; e->handler_ = h; double t = clock_ + delay; e->time_ = t; insert(e); } void Scheduler::run() { instance_ = this; Event *p; while ((p = deque()) && !halted_) { dispatch(p); } } /* * dispatch a single simulator event by setting the system * virtul clock to the event's timestamp and calling its handler. * Note that the event may have side effects of placing other items * in the scheduling queue */ void Scheduler::dispatch(Event* p, double t) { if (t < clock_) { fprintf(stderr, "ns: scheduler going backwards in time from %f to %f.\n", clock_, t); } clock_ = t; p->uid_ = -p->uid_; // being dispatched p->handler_->handle(p); // dispatch } void Scheduler::dispatch(Event* p) { dispatch(p, p->time_); } class AtEvent : public Event { public: AtEvent() : proc_(0) { } ~AtEvent() { if (proc_) delete [] proc_; } char* proc_; }; class AtHandler : public Handler { public: void handle(Event* event); } at_handler; void AtHandler::handle(Event* e) { AtEvent* at = (AtEvent*)e; Tcl::instance().eval(at->proc_); delete at; } void Scheduler::reset() { clock_ = SCHED_START; } int Scheduler::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (instance_ == 0) instance_ = this; if (argc == 2) { if (strcmp(argv[1], "run") == 0) { /* set global to 0 before calling object reset methods */ reset(); // sets clock to zero run(); return (TCL_OK); } else if (strcmp(argv[1], "now") == 0) { sprintf(tcl.buffer(), "%.17g", clock()); tcl.result(tcl.buffer()); return (TCL_OK); } else if (strcmp(argv[1], "resume") == 0) { halted_ = 0; run(); return (TCL_OK); } else if (strcmp(argv[1], "halt") == 0) { halted_ = 1; return (TCL_OK); } else if (strcmp(argv[1], "clearMemTrace") == 0) { #ifdef MEMDEBUG_SIMULATIONS extern MemTrace *globalMemTrace; if (globalMemTrace) globalMemTrace->diff("Sim."); #endif return (TCL_OK); } else if (strcmp(argv[1], "is-running") == 0) { sprintf(tcl.buffer(), "%d", !halted_); return (TCL_OK); } else if (strcmp(argv[1], "dumpq") == 0) { if (!halted_) { fprintf(stderr, "Scheduler: dumpq only allowed while halted\n"); tcl.result("0"); return (TCL_ERROR); } dumpq(); return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "at") == 0 || strcmp(argv[1], "cancel") == 0) { Event* p = lookup(atoi(argv[2])); if (p != 0) { /*XXX make sure it really is an atevent*/ cancel(p); AtEvent* ae = (AtEvent*)p; delete ae; } } else if (strcmp(argv[1], "at-now") == 0) { const char* proc = argv[2]; // "at [$ns now]" may not work because of tcl's // string number resolution AtEvent* e = new AtEvent; int n = strlen(proc); e->proc_ = new char[n + 1]; strcpy(e->proc_, proc); schedule(&at_handler, e, 0); sprintf(tcl.buffer(), "%u", e->uid_); tcl.result(tcl.buffer()); } return (TCL_OK); } else if (argc == 4) { if (strcmp(argv[1], "at") == 0) { /* t < 0 means relative time: delay = -t */ double delay, t = atof(argv[2]); const char* proc = argv[3]; AtEvent* e = new AtEvent; int n = strlen(proc); e->proc_ = new char[n + 1]; strcpy(e->proc_, proc); delay = (t < 0) ? -t : t - clock(); if (delay < 0) { tcl.result("can't schedule command in past"); return (TCL_ERROR); } schedule(&at_handler, e, delay); sprintf(tcl.buffer(), "%u", e->uid_); tcl.result(tcl.buffer()); return (TCL_OK); } } return (TclObject::command(argc, argv)); } void Scheduler::dumpq() { Event *p; printf("Contents of scheduler queue (events) [cur time: %f]---\n", clock()); while ((p = deque()) != NULL) { printf("t:%f uid: %d handler: %p\n", p->time_, p->uid_, p->handler_); } } static class ListSchedulerClass : public TclClass { public: ListSchedulerClass() : TclClass("Scheduler/List") {} TclObject* create(int /* argc */, const char*const* /* argv */) { return (new ListScheduler); } } class_list_sched; void ListScheduler::insert(Event* e) { double t = e->time_; Event** p; for (p = &queue_; *p != 0; p = &(*p)->next_) if (t < (*p)->time_) break; e->next_ = *p; *p = e; } /* * Cancel an event. It is an error to call this routine * when the event is not actually in the queue. The caller * must free the event if necessary; this routine only removes * it from the scheduler queue. */ void ListScheduler::cancel(Event* e) { Event** p; if (e->uid_ <= 0) // event not in queue return; for (p = &queue_; *p != e; p = &(*p)->next_) if (*p == 0) abort(); *p = (*p)->next_; e->uid_ = - e->uid_; } Event* ListScheduler::lookup(int uid) { Event* e; for (e = queue_; e != 0; e = e->next_) if (e->uid_ == uid) break; return (e); } Event* ListScheduler::deque() { Event* e = queue_; if (e) queue_ = e->next_; return (e); } #include "heap.h" Heap::Heap(int size) : h_s_key(0), h_size(0), h_maxsize(size), h_iter(0) { h_elems = new Heap_elem[h_maxsize]; memset(h_elems, 0, h_maxsize*sizeof(Heap_elem)); //for (unsigned int i = 0; i < h_maxsize; i++) // h_elems[i].he_elem = 0; } Heap::~Heap() { delete [] h_elems; } /* * int heap_member(Heap *h, void *elem): O(n) algorithm. * * Returns index(elem \in h->he_elems[]) + 1, * if elem \in h->he_elems[], * 0, otherwise. * External callers should just test for zero, or non-zero. * heap_delete() uses this routine to find an element in the heap. */ int Heap::heap_member(void* elem) { unsigned int i; Heap::Heap_elem* he; for (i = 0, he = h_elems; i < h_size; i++, he++) if (he->he_elem == elem) return ++i; return 0; } /* * int heap_delete(Heap *h, void *elem): O(n) algorithm * * Returns 1 for success, 0 otherwise. * * find elem in h->h_elems[] using heap_member() * * To actually remove the element from the tree, first swap it to the * root (similar to the procedure applied when inserting a new * element, but no key comparisons--just get it to the root). * * Then call heap_extract_min() to remove it & fix the tree. * This process is not the most efficient, but we do not * particularily care about how fast heap_delete() is. * Besides, heap_member() is already O(n), * and is the dominating cost. * * Actually remove the element by calling heap_extract_min(). * The key that is now at the root is not necessarily the * minimum, but heap_extract_min() does not care--it just * removes the root. */ int Heap::heap_delete(void* elem) { int i; if ((i = heap_member(elem)) == 0) return 0; for (--i; i; i = parent(i)) { swap(i, parent(i)); } (void) heap_extract_min(); return 1; } /* * void heap_insert(Heap *h, heap_key_t *key, void *elem) * * Insert <key, elem> into heap h. * Adjust heap_size if we hit the limit. * * i := heap_size(h) * heap_size := heap_size + 1 * while (i > 0 and key < h[Parent(i)]) * do h[i] := h[Parent(i)] * i := Parent(i) * h[i] := key */ void Heap::heap_insert(heap_key_t key, void* elem) { unsigned int i, par; if (h_maxsize == h_size) { /* Adjust heap_size */ unsigned int osize = h_maxsize; Heap::Heap_elem *he_old = h_elems; h_maxsize *= 2; h_elems = new Heap::Heap_elem[h_maxsize]; memcpy(h_elems, he_old, osize*sizeof(Heap::Heap_elem)); //for (i = 0; i < osize; i++) // h_elems[i] = he_old[i]; //delete he_old; } i = h_size++; par = parent(i); while ((i > 0) && (KEY_LESS_THAN(key, h_s_key, h_elems[par].he_key, h_elems[par].he_s_key))) { h_elems[i] = h_elems[par]; i = par; par = parent(i); } h_elems[i].he_key = key; h_elems[i].he_s_key= h_s_key++; h_elems[i].he_elem = elem; return; }; /* * void *heap_extract_min(Heap *h) * * Returns the smallest element in the heap, if it exists. * NULL otherwise. * * if heap_size[h] == 0 * return NULL * min := h[0] * heap_size[h] := heap_size[h] - 1 # C array indices start at 0 * h[0] := h[heap_size[h]] * Heapify: * i := 0 * while (i < heap_size[h]) * do l = HEAP_LEFT(i) * r = HEAP_RIGHT(i) * if (r < heap_size[h]) * # right child exists => * # left child exists * then if (h[l] < h[r]) * then try := l * else try := r * else * if (l < heap_size[h]) * then try := l * else try := i * if (h[try] < h[i]) * then HEAP_SWAP(h[i], h[try]) * i := try * else break * done */ void* Heap::heap_extract_min() { void* min; /* return value */ unsigned int i; unsigned int l, r, x; if (h_size == 0) return 0; min = h_elems[0].he_elem; h_elems[0] = h_elems[--h_size]; // Heapify: i = 0; while (i < h_size) { l = left(i); r = right(i); if (r < h_size) { if (KEY_LESS_THAN(h_elems[l].he_key, h_elems[l].he_s_key, h_elems[r].he_key, h_elems[r].he_s_key)) x= l; else x= r; } else x = (l < h_size ? l : i); if ((x != i) && (KEY_LESS_THAN(h_elems[x].he_key, h_elems[x].he_s_key, h_elems[i].he_key, h_elems[i].he_s_key))) { swap(i, x); i = x; } else { break; } } return min; } static class HeapSchedulerClass : public TclClass { public: HeapSchedulerClass() : TclClass("Scheduler/Heap") {} TclObject* create(int /* argc */, const char*const* /* argv */) { return (new HeapScheduler); } } class_heap_sched; Event* HeapScheduler::lookup(int uid) { Event* e; for (e = (Event*) hp_->heap_iter_init(); e; e = (Event*) hp_->heap_iter()) if (e->uid_ == uid) break; return e; } Event* HeapScheduler::deque() { return ((Event*) hp_->heap_extract_min()); } /* * Calendar queue scheduler contributed by * David Wetherall <djw@juniper.lcs.mit.edu> * March 18, 1997. * * A calendar queue basically hashes events into buckets based on * arrival time. * * See R.Brown. "Calendar queues: A fast O(1) priority queue implementation * for the simulation event set problem." * Comm. of ACM, 31(10):1220-1227, Oct 1988 */ static class CalendarSchedulerClass : public TclClass { public: CalendarSchedulerClass() : TclClass("Scheduler/Calendar") {} TclObject* create(int /* argc */, const char*const* /* argv */) { return (new CalendarScheduler); } } class_calendar_sched; CalendarScheduler::CalendarScheduler() { reinit(2, 1.0, 0.0); resizeenabled_ = 1; max_ = 0.0; } CalendarScheduler::~CalendarScheduler() { delete [] buckets_; qsize_ = 0; } void CalendarScheduler::insert(Event* e) { /* (e->time_ * oneonwidth) needs to be less than the * largest integer on the machine for the mapping * of time to bucket to work properly. if it is not * we need to re-calculate the width. */ if (e->time_ > max_) { max_ = e->time_; if (e->time_ * oneonwidth_ > ULONG_MAX) { resize(nbuckets_); } } // bucket number and address int i = (int)(((long)(e->time_ * oneonwidth_)) & buckbits_); Event** p = buckets_ + i; // insert event in stable time sorted order while ((*p != NULL) && (e->time_ >= (*p)->time_)) p = &(*p)->next_; e->next_ = *p; *p = e; if (++qsize_ > top_threshold_) resize(nbuckets_<<1); } Event* CalendarScheduler::deque() { if (qsize_ == 0) return NULL; for (;;) { int i = lastbucket_; // check for an event this `year' do { Event* e = buckets_[i]; if ((e != NULL) && (e->time_ < buckettop_)) { buckets_[i] = e->next_; lastbucket_ = i; last_clock_ = e->time_; if (--qsize_ < bot_threshold_) resize(nbuckets_>>1); return e; } else { if (++i == nbuckets_) { i = 0; /* Brad Karp, karp@eecs.harvard.edu: at the end of each year, eliminate roundoff error in buckettop_ */ buckettop_ = prevtop_ + nbuckets_ * width_; prevtop_ = buckettop_; } else { buckettop_+= width_; } } } while (i != lastbucket_); // or direct search for the minimum event int pos = 0; Event* min; do { min = buckets_[pos++]; } while (min == NULL); pos--; int k; for (k = pos+1; k < nbuckets_; k++) { Event* e = buckets_[k]; if ((e != NULL) && (e->time_ < min->time_)) { min = e; pos = k; } } // adjust year and resume lastbucket_ = pos; last_clock_ = min->time_; unsigned long n = (unsigned long)(min->time_ * oneonwidth_); buckettop_ = width_*(n+1.5); prevtop_ = buckettop_ - lastbucket_ * width_; } //return deque(); } void CalendarScheduler::reinit(int nbuck, double bwidth, double start) { buckets_ = new Event*[nbuck]; memset(buckets_, 0, sizeof(Event*)*nbuck); width_ = bwidth; oneonwidth_ = 1.0 / width_; nbuckets_ = nbuck; buckbits_ = nbuck-1; qsize_ = 0; last_clock_ = start; long n = (long)(start * oneonwidth_); lastbucket_ = n & buckbits_; buckettop_ = width_*(n+1.5); prevtop_ = buckettop_ - lastbucket_ * width_; bot_threshold_ = (nbuck >> 1) - 2; top_threshold_ = (nbuck << 1); } void CalendarScheduler::resize(int newsize) { if (!resizeenabled_) return; double bwidth = newwidth(); Event** oldb = buckets_; int oldn = nbuckets_; // copy events to new buckets reinit(newsize, bwidth, clock_); int i; for (i = oldn-1; i >= 0; i--) { Event* e = oldb[i]; while (e != NULL) { Event* en = e->next_; insert(e); e = en; } } delete [] oldb; } #define MIN_WIDTH (1.0e-6) #define MAX_HOLD 25 double CalendarScheduler::newwidth() { static Event* hold[MAX_HOLD]; int nsamples; if (qsize_ < 2) return 1.0; if (qsize_ < 5) nsamples = qsize_; else nsamples = 5 + qsize_ / 10; if (nsamples > MAX_HOLD) nsamples = MAX_HOLD; // dequue and requeue sample events to gauge width double olp = clock_; double olt = buckettop_; int olb = lastbucket_; double olbt = prevtop_; resizeenabled_ = 0; for (int i = 0; i < nsamples; i++) hold[i] = deque(); // insert in the inverse order and using insert2 to take care of same-time events. for (int j = nsamples-1; j >= 0; j--) insert2(hold[j]); resizeenabled_ = 1; clock_ = olp; buckettop_ = olt; prevtop_ = olbt; lastbucket_ = olb; // try to work out average cluster separation double asep = (hold[nsamples-1]->time_ - hold[0]->time_) / (nsamples-1); double asep2 = 0.0; double min = (clock_ + 1.0) * MIN_WIDTH; int count = 0; for (int k = 1; k < nsamples; k++) { double diff = hold[k]->time_ - hold[k-1]->time_; if (diff < 2.0*asep) { asep2 += diff; count++; } } // but don't let things get too small for numerical stability double nw = count ? 3.0*(asep2/count) : asep; if (nw < min) nw = min; /* need to make sure that time_/width_ can be represented as * an int. see the comment at the start of insert(). */ if (max_/nw > ULONG_MAX) { nw = max_/ULONG_MAX; } return nw; } /* * Cancel an event. It is an error to call this routine * when the event is not actually in the queue. The caller * must free the event if necessary; this routine only removes * it from the scheduler queue. * * xxx: we may cancel the last event and invalidate the value of max_ * xxx: thus using wider buckets than really necessary */ void CalendarScheduler::cancel(Event* e) { int i = (int)(((long)(e->time_ * oneonwidth_)) & buckbits_); if (e->uid_ <= 0) // event not in queue return; for (Event** p = buckets_ + i; (*p) != NULL; p = &(*p)->next_) if ((*p) == e) { (*p) = (*p)->next_; e->uid_ = - e->uid_; qsize_--; return; } abort(); } Event* CalendarScheduler::lookup(int uid) { for (int i = 0; i < nbuckets_; i++) for (Event* p = buckets_[i]; p != NULL; p = p->next_) if (p->uid_== uid) return p; return NULL; } void CalendarScheduler::insert2(Event* e) { // Same as insert, but for inserts e *before* any same-time-events, if // there should be any. Since it is used only by CalendarScheduler::newwidth(), // some important checks present in insert() need not be performed. // bucket number and address int i = (int)(((long)(e->time_ * oneonwidth_)) & buckbits_); Event** p = buckets_ + i; // insert event in stable time sorted order while ((*p != NULL) && (e->time_ > (*p)->time_)) // > instead of >=! p = &(*p)->next_; e->next_ = *p; *p = e; ++qsize_; } #ifndef WIN32 #include <sys/time.h> #endif /* * Really should instance the list/calendar/heap discipline * inside a RealTimeScheduler or VirtualTimeScheduler */ #ifdef notyet class RealTimeScheduler : public CalendarScheduler { #endif class RealTimeScheduler : public ListScheduler { public: RealTimeScheduler(); virtual void run(); double start() const { return start_; } virtual void reset(); protected: void sync() { clock_ = tod(); } int rwait(double); // sleep double tod(); double slop_; // allowed drift between real-time and virt time double start_; // starting time }; static class RealTimeSchedulerClass : public TclClass { public: RealTimeSchedulerClass() : TclClass("Scheduler/RealTime") {} TclObject* create(int /* argc */, const char*const* /* argv */) { return (new RealTimeScheduler); } } class_realtime_sched; RealTimeScheduler::RealTimeScheduler() : start_(0.0) { bind("maxslop_", &slop_); } double RealTimeScheduler::tod() { timeval tv; gettimeofday(&tv, 0); double s = tv.tv_sec; s += (1e-6 * tv.tv_usec); return (s - start_); } // XXX not used? // static void nullTimer(ClientData) // { // } void RealTimeScheduler::reset() { clock_ = SCHED_START; start_ = tod(); } void RealTimeScheduler::run() { Event *p; double now; /*XXX*/ instance_ = this; while (!halted_) { now = tod(); //if ((clock_ - now) > slop_) { if ((now - clock_) > slop_) { fprintf(stderr, "RealTimeScheduler: warning: slop %f exceeded limit %f [now:%f, clock_:%f\n", now - clock_, slop_, now, clock_); } // // first handle any "old events" // while ((p = deque()) != NULL && (p->time_ <= now)) { dispatch(p); } // // now handle a "future event", if there is one // if (p != NULL) { int rval = rwait(p->time_); if (rval < 0) { fprintf(stderr, "RTScheduler: wait problem\n"); abort(); } else if (rval == 0) { // // proper time to dispatch sim event... do so // dispatch(p, clock_); } else { // // there was a simulator event which fired, and // may have added something to the queue, which // could cause our event p to not be the next, // so put p back into the event queue and cont // insert(p); } continue; } // // no sim events to handle at all, check with tcl // sync(); Tcl_DoOneEvent(TCL_DONT_WAIT); } return; // we reach here only if halted } /* * wait until the specified amount has elapsed, or a tcl event has happened, * whichever comes first. Return 1 if a tcl event happened, 0 if the * deadline has been reached, or -1 on error (shouldn't happen). */ int RealTimeScheduler::rwait(double deadline) { while (1) { sync(); if (Tcl_DoOneEvent(TCL_DONT_WAIT) == 1) return (1); if (deadline <= tod()) return 0; } return -1; }

scoreboard.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1996 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Network Research * Group at Lawrence Berkeley National Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* 9/96 Pittsburgh Supercomputing Center * UpdateScoreBoard, CheckSndNxt, MarkRetran modified for fack */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif /* A quick hack version of the scoreboard */ #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <math.h> #include "packet.h" #include "scoreboard.h" #include "tcp.h" #define ASSERT(x) if (!(x)) {printf ("Assert SB failed\n"); exit(1);} #define ASSERT1(x) if (!(x)) {printf ("Assert1 SB (length)\n"); exit(1);} #define SBNI SBN[i%SBSIZE] // last_ack = TCP last ack int
ScoreBoard::UpdateScoreBoard (int last_ack, hdr_tcp* tcph) { int i, sack_index, sack_left, sack_right; int retran_decr = 0; // If there is no scoreboard, create one. if (length_ == 0) { i = last_ack+1; SBNI.seq_no_ = i; SBNI.ack_flag_ = 0; SBNI.sack_flag_ = 0; SBNI.retran_ = 0; SBNI.snd_nxt_ = 0; first_ = i%SBSIZE; length_++; if (length_ >= SBSIZE) { printf ("Error, scoreboard too large (increase SBSIZE for more space)\n"); exit(1); } } for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) { sack_left = tcph->sa_left(sack_index); sack_right = tcph->sa_right(sack_index); // Create new entries off the right side. if (sack_right > SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_) { // Create new entries for (i = SBN[(first_+length_+SBSIZE-1)%SBSIZE].seq_no_+1; i<sack_right; i++) { SBNI.seq_no_ = i; SBNI.ack_flag_ = 0; SBNI.sack_flag_ = 0; SBNI.retran_ = 0; SBNI.snd_nxt_ = 0; length_++; if (length_ >= SBSIZE) { printf ("Error, scoreboard too large (increase SBSIZE for more space)\n"); exit(1); } } } // Advance the left edge of the block. if (SBN[first_].seq_no_ <= last_ack) { for (i=SBN[(first_)%SBSIZE].seq_no_; i<=last_ack; i++) { // Advance the ACK if (SBNI.seq_no_ <= last_ack) { ASSERT(first_ == i%SBSIZE); first_ = (first_+1)%SBSIZE; length_--; ASSERT1(length_ >= 0); SBNI.ack_flag_ = 1; SBNI.sack_flag_ = 1; if (SBNI.retran_) { SBNI.retran_ = 0; SBNI.snd_nxt_ = 0; retran_decr++; } if (length_==0) break; } } } for (i=SBN[(first_)%SBSIZE].seq_no_; i<sack_right; i++) { // Check to see if this segment is now covered by the sack block if (SBNI.seq_no_ >= sack_left && SBNI.seq_no_ < sack_right) { if (! SBNI.sack_flag_) { SBNI.sack_flag_ = 1; } if (SBNI.retran_) { SBNI.retran_ = 0; retran_decr++; } } } } return (retran_decr); } int ScoreBoard::CheckSndNxt (hdr_tcp* tcph) { int i, sack_index, sack_left, sack_right; int force_timeout = 0; for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) { sack_left = tcph->sa_left(sack_index); sack_right = tcph->sa_right(sack_index); for (i=SBN[(first_)%SBSIZE].seq_no_; i<sack_right; i++) { // Check to see if this segment's snd_nxt_ is now covered by the sack block if (SBNI.retran_ && SBNI.snd_nxt_ < sack_right) { // the packet was lost again SBNI.retran_ = 0; SBNI.snd_nxt_ = 0; force_timeout = 1; } } } return (force_timeout); } void ScoreBoard::ClearScoreBoard() { length_ = 0; } /* * GetNextRetran() returns "-1" if there is no packet that is * not acked and not sacked and not retransmitted. */ int ScoreBoard::GetNextRetran() // Returns sequence number of next pkt... { int i; if (length_) { for (i=SBN[(first_)%SBSIZE].seq_no_; i<SBN[(first_)%SBSIZE].seq_no_+length_; i++) { if (!SBNI.ack_flag_ && !SBNI.sack_flag_ && !SBNI.retran_) { return (i); } } } return (-1); } void ScoreBoard::MarkRetran (int retran_seqno, int snd_nxt) { SBN[retran_seqno%SBSIZE].retran_ = 1; SBN[retran_seqno%SBSIZE].snd_nxt_ = snd_nxt; } void ScoreBoard::MarkRetran (int retran_seqno) { SBN[retran_seqno%SBSIZE].retran_ = 1; }

semantic-packetqueue.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California at Berkeley. * 4. Neither the name of the University nor of the Research Group may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * semantic-packetqueue.cc: contributed by the Daedalus Research Group, * UC Berkeley (http://daedalus.cs.berkeley.edu). */ #include "ip.h" #include "tcp.h" #include "template.h" #include "semantic-packetqueue.h" #include "ack-recons.h" static class SemanticPacketQueueClass : public TclClass { public: SemanticPacketQueueClass() : TclClass("PacketQueue/Semantic") {} TclObject* create(int , const char*const*) { return (new SemanticPacketQueue()); } } class_semanticpacketqueue; SemanticPacketQueue::SemanticPacketQueue() : ack_count(0), data_count(0), acks_to_send(0), marked_count_(0), unmarked_count_(0) { bind("off_cmn_", &off_cmn_); bind("off_flags_", &off_flags_); bind("off_ip_", &off_ip_); bind("off_tcp_", &off_tcp_); bind("off_flags_", &off_flags_); bind_bool("acksfirst_", &acksfirst_); bind_bool("filteracks_", &filteracks_); bind_bool("reconsAcks_", &reconsAcks_); bind_bool("replace_head_", &replace_head_); bind_bool("priority_drop_", &priority_drop_); bind_bool("random_drop_", &random_drop_); bind_bool("random_ecn_", &random_ecn_); } int
SemanticPacketQueue::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "ackrecons") == 0) { if ((reconsCtrl_ = (AckReconsController *) TclObject::lookup(argv[2]))) { reconsCtrl_->spq_ = this; reconsAcks_ = 1; } } return (TCL_OK); } return (TclObject::command(argc, argv)); } /* * Deque TCP acks before any other type of packet. */ Packet* SemanticPacketQueue::deque_acksfirst() { Packet* p = head_; Packet* pp = NULL; packet_t type; if (ack_count > 0) { while (p) { type = ((hdr_cmn*)p->access(off_cmn_))->ptype_; if (type == PT_ACK) break; pp = p; p = p->next_; } if (!p) fprintf(stderr, "In deque_acksfirst(): ack_count: %d but no acks in queue, length = %d\n", ack_count, length()); PacketQueue::remove(p, pp); } else { p = PacketQueue::deque(); } return p; } /* * Purge the queue of acks that are older (i.e., have a smaller sequence * number) than the most recent ack. If replace_head is set, the most recent * ack (pointed to by pkt) takes the place of the oldest ack that is purged. * Otherwise, it remains at the tail of the queue. pkt must be an ACK -- this * is checked by the caller. */ void SemanticPacketQueue::filterAcks(Packet *pkt, int replace_head) { int done_replacement = 0; Packet *p, *pp, *new_p; hdr_tcp *tcph = (hdr_tcp*) pkt->access(off_tcp_); int &ack = tcph->seqno(); hdr_ip *iph = (hdr_ip*) pkt->access(off_ip_); for (p = head(), pp = p; p != 0; ) { /* * Check if packet in the queue belongs to the * same connection as the most recent ack */ if (compareFlows((hdr_ip*) p->access(off_ip_), iph)) { /* check if queued packet is an ack */ if (((hdr_cmn*)p->access(off_cmn_))->ptype_==PT_ACK) { hdr_tcp *th = (hdr_tcp*) p->access(off_tcp_); /* is this ack older than the current one? */ if ((th->seqno() < ack) || (replace_head && th->seqno() == ack)) { /* * If we haven't yet replaced the ack * closest to the head with the most * recent ack, do so now. */ if (replace_head && pkt != p && !done_replacement) { PacketQueue::remove(pkt); ack_count--; /* XXX */ pkt->next_ = p; if (pp) pp->next_ = pkt; pp = pkt; done_replacement = 1; continue; } else if (done_replacement||pkt != p){ new_p = p->next_; /* * If p is in scheduler queue, * cancel the event. Also, * print out a warning because * this should never happen. */ Scheduler &s = Scheduler::instance(); if (s.lookup(p->uid_)) { s.cancel(p); fprintf(stderr, "Warning: In filterAcks(): packet being dropped from queue is in scheduler queue\n"); } PacketQueue::remove(p, pp); /* XXX should drop, but we don't have access to q */ Packet::free(p); ack_count--; p = new_p; continue; } if (ack_count <= 0) fprintf(stderr, "oops! ackcount %d\n", ack_count); } } } pp = p; p = p->next_; } } /* check if packet is marked */ int SemanticPacketQueue::isMarked(Packet *p) { return(((hdr_flags*)p->access(off_flags_))->fs_); } /* pick out the index'th of the appropriate kind (marked/unmarked) depending on markedFlag */ Packet* SemanticPacketQueue::lookup(int index, int markedFlag) { if (index < 0) { fprintf(stderr, "In SemanticPacketQueue::lookup(): index = %d\n", index); return (NULL); } for (Packet* p = head_; p != 0; p = p->next_) { if (isMarked(p) == markedFlag) if (--index < 0) return (p); } return (NULL); } /* * If random_ecn_ is set, pick out the packet for ECN at random from among the * packets in the queue and the packet that just arrived ('pkt'). Otherwise, just * pick the packet that just arrived. */ Packet* SemanticPacketQueue::pickPacketForECN(Packet* pkt) { Packet *victim; int victimIndex; if (random_ecn_) { victimIndex = Random::integer(length()+1); if (victimIndex == length()) victim = pkt; else victim = PacketQueue::lookup(victimIndex); } else victim = pkt; return (victim); } /* * If priority_drop_ is set, drop marked packets before unmarked ones. * If in addition or separately random_drop_ is set, use randomization in * picking out the victim. XXX not used at present */ Packet* SemanticPacketQueue::pickPacketToDrop() { Packet *victim; int victimIndex, victimMarked; if (!priority_drop_) { if (random_drop_) victim=PacketQueue::lookup(Random::integer(length())); else victim = PacketQueue::lookup(length() - 1); } else { /* if there are marked (low priority) packets */ if (marked_count_) { victimMarked = 1; if (!random_drop_) victimIndex = marked_count_ - 1; else victimIndex = Random::integer(marked_count_); } else { victimMarked = 0; if (!random_drop_) victimIndex = unmarked_count_ - 1; else victimIndex = Random::integer(unmarked_count_); } victim = lookup(victimIndex, victimMarked); } return (victim); } void SemanticPacketQueue::enque(Packet *pkt) { if (reconsAcks_&&(((hdr_cmn*)pkt->access(off_cmn_))->ptype_==PT_ACK)) { reconsCtrl_->recv(pkt); return; } if (((hdr_cmn*)pkt->access(off_cmn_))->ptype_ == PT_ACK) ack_count++; else data_count++; if (isMarked(pkt)) marked_count_++; else unmarked_count_++; PacketQueue::enque(pkt); /* actually enqueue the packet */ if (filteracks_ && (((hdr_cmn*)pkt->access(off_cmn_))->ptype_==PT_ACK)) filterAcks(pkt, replace_head_); } Packet * SemanticPacketQueue::deque() { Packet *pkt; if (acksfirst_) pkt = deque_acksfirst(); else pkt = PacketQueue::deque(); if (pkt) { if (((hdr_cmn*)pkt->access(off_cmn_))->ptype_ == PT_ACK) ack_count--; else data_count--; if (isMarked(pkt)) marked_count_--; else unmarked_count_--; } return pkt; } void SemanticPacketQueue::remove(Packet *pkt) { PacketQueue::remove(pkt); if (pkt) { if (((hdr_cmn*)pkt->access(off_cmn_))->ptype_ == PT_ACK) ack_count--; else data_count--; if (isMarked(pkt)) marked_count_--; else unmarked_count_--; } }

semantic-red.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * A RED queue that allows certain operations to be done in a way * that depends on higher-layer semantics. The only such operation * at present is pickPacketToDrop(), which invokes the corresponding * member function in SemanticPacketQueue. */ #include "red.h" #include "semantic-packetqueue.h" class SemanticREDQueue : public REDQueue { public: SemanticREDQueue() : REDQueue() {} Packet* pickPacketToDrop() { return(((SemanticPacketQueue*) pq_)->pickPacketToDrop()); } Packet* pickPacketForECN(Packet *pkt) { return(((SemanticPacketQueue*) pq_)->pickPacketForECN(pkt)); } }; static class SemanticREDClass : public TclClass { public: SemanticREDClass() : TclClass("Queue/RED/Semantic") {} TclObject* create(int, const char*const*) { return (new SemanticREDQueue); } } class_semantic_red;

session-rtp.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$"; #endif #include <stdlib.h> #include "packet.h" #include "ip.h" #include "rtp.h" static class RTPSourceClass : public TclClass { public: RTPSourceClass() : TclClass("RTPSource") {} TclObject* create(int argc, const char*const* argv) { if (argc >= 5) return (new RTPSource(atoi(argv[4]))); return 0; } } class_rtp_source; static class RTPSessionClass : public TclClass { public: RTPSessionClass() : TclClass("Session/RTP") {} TclObject* create(int, const char*const*) { return (new RTPSession()); } } class_rtp_session; RTPSession::RTPSession() : allsrcs_(0), localsrc_(0), last_np_(0) { bind("off_rtp_", &off_rtp_); } RTPSession::~RTPSession() { while (allsrcs_ != 0) { RTPSource* p = allsrcs_; allsrcs_ = allsrcs_->next; delete p; } delete localsrc_; } void
RTPSession::localsrc_update(int) { localsrc_->np(1); } #define RTCP_HDRSIZE 8 #define RTCP_SR_SIZE 20 #define RTCP_RR_SIZE 48 int RTPSession::build_report(int bye) { int nsrc = 0; int nrr = 0; int len = RTCP_HDRSIZE; int we_sent = 0; if (localsrc_->np() != last_np_) { last_np_ = localsrc_->np(); we_sent = 1; len += RTCP_SR_SIZE; } for (RTPSource* sp = allsrcs_; sp != 0; sp = sp->next) { ++nsrc; int received = sp->np() - sp->snp(); if (received == 0) { continue; } sp->snp(sp->np()); len += RTCP_RR_SIZE; if (++nrr >= 31) break; } if (bye) len += build_bye(); else len += build_sdes(); Tcl::instance().evalf("%s adapt-timer %d %d %d", name(), nsrc, nrr, we_sent); Tcl::instance().evalf("%s sample-size %d", name(), len); return (len); } int RTPSession::build_bye() { return (8); } int RTPSession::build_sdes() { /* XXX We'll get to this later... */ return (20); } void RTPSession::recv(Packet* p, Handler*) { hdr_rtp *rh = (hdr_rtp*)p->access(off_rtp_); u_int32_t srcid = rh->srcid(); RTPSource* s = lookup(srcid); if (s == 0) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s new-source %d", name(), srcid); s = (RTPSource*)TclObject::lookup(tcl.result()); } s->np(1); s->ehsr(rh->seqno()); Packet::free(p); } void RTPSession::recv_ctrl(Packet* p) { hdr_cmn* ch = (hdr_cmn*)p->access(off_cmn_); Tcl::instance().evalf("%s sample-size %d", name(), ch->size()); Packet::free(p); } /* XXX Should hash this... */ RTPSource* RTPSession::lookup(u_int32_t srcid) { RTPSource *p; for (p = allsrcs_; p != 0; p = p->next) if (p->srcid() == srcid) return (p); return (0); } void RTPSession::enter(RTPSource* s) { s->next = allsrcs_; allsrcs_ = s; } int RTPSession::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "enter") == 0) { RTPSource* s = (RTPSource*)TclObject::lookup(argv[2]); enter(s); return (TCL_OK); } if (strcmp(argv[1], "localsrc") == 0) { localsrc_ = (RTPSource*)TclObject::lookup(argv[2]); enter(localsrc_); return (TCL_OK); } } return (TclObject::command(argc, argv)); } RTPSource::RTPSource(u_int32_t srcid) : next(0), np_(0), snp_(0), ehsr_(-1) { bind("srcid_", (int*)&srcid_); srcid_ = srcid; }

sessionhelper.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * sessionhelper.cc * Copyright (C) 1997 by USC/ISI * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang * */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (USC/ISI)"; #endif #include "config.h" #include "tclcl.h" #include "ip.h" #include "packet.h" #include "connector.h" #include "errmodel.h" //Definitions for special reference count events class RcEvent : public Event { public: Packet* packet_; Handler* real_handler_; }; class RcHandler : public Handler { public: void handle(Event* event); } rc_handler; void
RcHandler::handle(Event* e) { RcEvent* rc = (RcEvent*)e; rc->real_handler_->handle(rc->packet_); delete rc; } struct dstobj { double bw; double delay; double prev_arrival; int ttl; int dropped; nsaddr_t addr; NsObject *obj; dstobj *next; }; struct rcv_depobj { dstobj *obj; rcv_depobj *next; }; struct loss_depobj { ErrorModel *obj; loss_depobj *loss_dep; rcv_depobj *rcv_dep; loss_depobj *next; }; class SessionHelper : public Connector { public: SessionHelper(); int command(int, const char*const*); void recv(Packet*, Handler*); protected: void get_dropped(loss_depobj*, Packet*); void mark_dropped(loss_depobj*); void clear_dropped(); dstobj* find_dstobj(NsObject*); void delete_dstobj(NsObject*); loss_depobj* find_loss_depobj(ErrorModel*); void show_dstobj(); void show_loss_depobj(loss_depobj*); nsaddr_t src_; dstobj *dstobj_; loss_depobj *loss_dependency_; int off_ip_; int ndst_; int rc_; //enable reference count }; static class SessionHelperClass : public TclClass { public: SessionHelperClass() : TclClass("SessionHelper") {} TclObject* create(int, const char*const*) { return (new SessionHelper()); } } class_sessionhelper; SessionHelper::SessionHelper() : dstobj_(0), ndst_(0), rc_(0) { bind("off_ip_", &off_ip_); bind("rc_", &rc_); loss_dependency_ = new loss_depobj; loss_dependency_->obj = 0; loss_dependency_->loss_dep = 0; loss_dependency_->rcv_dep = 0; loss_dependency_->next = 0; } void SessionHelper::recv(Packet* pkt, Handler*) { dstobj *tmpdst = dstobj_; Scheduler& s = Scheduler::instance(); hdr_cmn* th = (hdr_cmn*)pkt->access(off_cmn_); hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_); double tmp_arrival; //printf ("src %d, size %d, iface %d\n", src_, th->size(), th->iface()); clear_dropped(); get_dropped(loss_dependency_->loss_dep, pkt); if (rc_) { th->ref_count() = ndst_; } while (tmpdst != 0) { if (!(tmpdst->dropped)) { int ttl = iph->ttl() - tmpdst->ttl; if (ttl > 0) { if (tmpdst->bw == 0) { tmp_arrival = tmpdst->delay; } else { tmp_arrival = th->size()*8/tmpdst->bw + tmpdst->delay; } if (tmpdst->prev_arrival >= tmp_arrival) { tmp_arrival = tmpdst->prev_arrival + 0.000001; /* Assume 1 ns process delay; just to maintain the causality */ } tmpdst->prev_arrival = tmp_arrival; if (rc_) { // reference count //s.rc_schedule(tmpdst->obj, pkt, tmp_arrival); RcEvent* rc = new RcEvent; rc->packet_ = pkt; rc->real_handler_ = tmpdst->obj; s.schedule(&rc_handler, rc, tmp_arrival); } else { Packet* tmppkt = pkt->copy(); hdr_ip* tmpiph = (hdr_ip*)tmppkt->access(off_ip_); tmpiph->ttl() = ttl; s.schedule(tmpdst->obj, tmppkt, tmp_arrival); } } else { if (rc_) th->ref_count() -= 1; } } else { if (rc_) th->ref_count() -= 1; } tmpdst = tmpdst->next; } Packet::free(pkt); } void SessionHelper::get_dropped(loss_depobj* loss_dep, Packet* pkt) { if (loss_dep != 0) if (loss_dep->obj != 0) { if (loss_dep->obj->corrupt(pkt)) { mark_dropped(loss_dep); } else { get_dropped(loss_dep->loss_dep, pkt); } get_dropped(loss_dep->next, pkt); } } void SessionHelper::mark_dropped(loss_depobj* loss_dep) { if (loss_dep != 0) { rcv_depobj *tmprcv_dep = loss_dep->rcv_dep; loss_depobj *tmploss_dep = loss_dep->loss_dep; while (tmprcv_dep != 0) { tmprcv_dep->obj->dropped = 1; tmprcv_dep = tmprcv_dep->next; } while (tmploss_dep != 0) { mark_dropped(tmploss_dep); tmploss_dep = tmploss_dep->next; } } } void SessionHelper::clear_dropped() { dstobj *tmpdst = dstobj_; while (tmpdst != 0) { tmpdst->dropped = 0; tmpdst = tmpdst->next; } } dstobj* SessionHelper::find_dstobj(NsObject* obj) { dstobj *tmpdst = dstobj_; while (tmpdst != 0) { if (tmpdst->obj == obj) return (tmpdst); tmpdst = tmpdst->next; } return 0; } loss_depobj* SessionHelper::find_loss_depobj(ErrorModel* err) { struct stackobj { loss_depobj *loss_obj; stackobj *next; }; if (!loss_dependency_) return 0; stackobj *top = new stackobj; top->loss_obj = loss_dependency_; top->next = 0; while (top != 0) { if (top->loss_obj->obj == err) { loss_depobj *tmp_loss_obj = top->loss_obj; while (top != 0) { stackobj *befreed = top; top = top->next; free(befreed); } return (tmp_loss_obj); } loss_depobj *tmploss = top->loss_obj->loss_dep; stackobj *befreed = top; top = top->next; free(befreed); while (tmploss != 0) { stackobj *new_element = new stackobj; new_element->loss_obj = tmploss; new_element->next = top; top = new_element; tmploss = tmploss->next; } } return 0; } void SessionHelper::show_dstobj() { dstobj *tmpdst = dstobj_; while (tmpdst != 0) { printf("bw:%.2f, delay:%.2f, ttl:%d, dropped:%d, addr:%d, obj:%s\n", tmpdst->bw, tmpdst->delay, tmpdst->ttl, tmpdst->dropped, tmpdst->addr, tmpdst->obj->name()); tmpdst = tmpdst->next; } } void SessionHelper::delete_dstobj(NsObject *obj) { dstobj *tmpdst = dstobj_; dstobj *tmpprev = 0; while (tmpdst != 0) { if (tmpdst->obj == obj) { if (tmpprev == 0) dstobj_ = tmpdst->next; else tmpprev->next = tmpdst->next; free(tmpdst); return; } tmpprev = tmpdst; tmpdst = tmpdst->next; } } void SessionHelper::show_loss_depobj(loss_depobj *loss_obj) { loss_depobj *tmploss = loss_obj->loss_dep; rcv_depobj *tmprcv = loss_obj->rcv_dep; while (tmprcv != 0) { printf("%d ", tmprcv->obj->addr); tmprcv = tmprcv->next; } while (tmploss != 0) { printf("(%s: ", tmploss->obj->name()); show_loss_depobj(tmploss); tmploss = tmploss->next; } if (loss_obj == loss_dependency_) { printf("\n"); } else { printf(")"); } } int SessionHelper::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "list-mbr") == 0) { dstobj *tmp = dstobj_; while (tmp != 0) { tcl.resultf("%s %s", tcl.result(), tmp->obj->name()); tmp = tmp->next; } return (TCL_OK); } if (strcmp(argv[1], "show-loss-depobj") == 0) { show_loss_depobj(loss_dependency_); return (TCL_OK); } if (strcmp(argv[1], "show-dstobj") == 0) { show_dstobj(); return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "set-node") == 0) { int src = atoi(argv[2]); src_ = src; //printf("set node %d\n", src_); return (TCL_OK); } if (strcmp(argv[1], "update-loss-top") == 0) { loss_depobj *tmploss = (loss_depobj*)(atoi(argv[2])); tmploss->next = loss_dependency_->loss_dep; loss_dependency_->loss_dep = tmploss; return (TCL_OK); } } else if (argc == 4) { if (strcmp(argv[1], "update-loss-rcv") == 0) { ErrorModel *tmperr = (ErrorModel*)TclObject::lookup(argv[2]); NsObject *tmpobj = (NsObject*)TclObject::lookup(argv[3]); //printf("errmodel %s, agent %s\n", tmperr->name(), tmpobj->name()); loss_depobj *tmploss = find_loss_depobj(tmperr); //printf ("%d, loss_dependency_ %d\n", tmploss, loss_dependency_); if (!tmploss) { tmploss = new loss_depobj; tmploss->obj = tmperr; tmploss->next = 0; tmploss->rcv_dep = 0; tmploss->loss_dep = 0; tcl.resultf("%d", tmploss); } else { tcl.result("0"); } rcv_depobj *tmprcv = new rcv_depobj; tmprcv->obj = find_dstobj(tmpobj); tmprcv->next = tmploss->rcv_dep; tmploss->rcv_dep = tmprcv; return (TCL_OK); } if (strcmp(argv[1], "update-loss-loss") == 0) { ErrorModel *tmperrparent = (ErrorModel*)TclObject::lookup(argv[2]); loss_depobj *tmplossparent = find_loss_depobj(tmperrparent); loss_depobj *tmplosschild = (loss_depobj*)(atoi(argv[3])); if (!tmplossparent) { tmplossparent = new loss_depobj; tmplossparent->obj = tmperrparent; tmplossparent->next = 0; tmplossparent->loss_dep = 0; tmplossparent->rcv_dep = 0; tcl.resultf("%d", tmplossparent); } else { tcl.result("0"); } tmplosschild->next = tmplossparent->loss_dep; tmplossparent->loss_dep = tmplosschild; return (TCL_OK); } if (strcmp(argv[1], "delete-dst") == 0) { int tmpaddr = atoi(argv[2]); //NsObject *tmpobj = (NsObject*)TclObject::lookup(argv[3]); printf ("addr = %d\n", tmpaddr); return (TCL_OK); } } else if (argc == 7) { if (strcmp(argv[1], "add-dst") == 0) { dstobj *tmp = new dstobj; tmp->bw = atof(argv[2]); tmp->delay = atof(argv[3]); tmp->prev_arrival = 0; tmp->ttl = atoi(argv[4]); tmp->addr = atoi(argv[5]); tmp->obj = (NsObject*)TclObject::lookup(argv[6]); //printf ("addr = %d, argv3 = %s, obj = %d, ttl=%d\n", tmp->addr, argv[3], tmp->obj, tmp->ttl); tmp->next = dstobj_; dstobj_ = tmp; ndst_ += 1; return (TCL_OK); } } return (Connector::command(argc, argv)); }

sfq.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the MASH Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file contributed by Curtis Villamizar < curtis@ans.net >, Feb 1997. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (ANS)"; #endif #include <stdlib.h> #include "config.h" #include "queue.h" class PacketSFQ; // one queue class SFQ; // a set of SFQ queues class PacketSFQ : public PacketQueue { PacketSFQ() : pkts(0), prev(0), next(0) {} friend SFQ; protected: void sfqdebug(); int pkts; PacketSFQ *prev; PacketSFQ *next; inline PacketSFQ * activate(PacketSFQ *head) { if (head) { this->prev = head->prev; this->next = head; head->prev->next = this; head->prev = this; return head; } this->prev = this; this->next = this; return this; } inline PacketSFQ * idle(PacketSFQ *head) { if (head == this) { if (this->next == this) return 0; this->next->prev = this->prev; this->prev->next = this->next; return this->next; } return head; } }; class SFQ : public Queue { public: SFQ(); virtual int command(int argc, const char*const* argv); Packet *deque(void); void enque(Packet *pkt); protected: int maxqueue_; // max queue size in packets int buckets_; // number of queues PacketSFQ *bucket; void initsfq(); void clear(); int hash(Packet *); PacketSFQ *active; int occupied; int fairshare; int off_ip_; }; static class SFQClass : public TclClass { public: SFQClass() : TclClass("Queue/SFQ") {} TclObject* create(int, const char*const*) { return (new SFQ); } } class_sfq;
SFQ::SFQ() { maxqueue_ = 40; buckets_ = 16; bucket = 0; active = 0; bind("maxqueue_", &maxqueue_); bind("buckets_", &buckets_); bind("off_ip_", &off_ip_); } void SFQ::clear() { PacketSFQ *q = bucket; int i = buckets_; if (!q) return; while (i) { if (q->pkts) { fprintf(stderr, "SFQ changed while queue occupied\n"); exit(1); } ++q; } delete[](bucket); bucket = 0; } void SFQ::initsfq() { bucket = new PacketSFQ[buckets_]; active = 0; occupied = 0; fairshare = maxqueue_ / buckets_; // fprintf(stderr, "SFQ initsfq: %d %d\n", maxqueue_, buckets_); } /* * This implements the following tcl commands: * $sfq limit $size * $sfq buckets $num */ int SFQ::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "limit") == 0) { maxqueue_ = atoi(argv[2]); fairshare = maxqueue_ / buckets_; return (TCL_OK); } if (strcmp(argv[1], "buckets") == 0) { clear(); buckets_ = atoi(argv[2]); return (TCL_OK); } } return (Queue::command(argc, argv)); } void PacketSFQ::sfqdebug() { PacketSFQ *q = this; fprintf(stderr, "sfq: "); while (q) { fprintf(stderr, " 0x%p(%d)", q, q->pkts); q = q->next; if (q == this) break; } fprintf(stderr, "\n"); } Packet* SFQ::deque(void) { Packet* pkt; if (!bucket) initsfq(); if (!active) { // fprintf(stderr, " dequeue: empty\n"); return (0); } --active->pkts; --occupied; pkt = active->deque(); // fprintf(stderr, "dequeue 0x%x(%d): 0x%x\n", // (int)active, active->pkts, (int)pkt); // active->sfqdebug(); if (active->pkts == 0) active = active->idle(active); else active = active->next; return pkt; } void SFQ::enque(Packet* pkt) { int which; PacketSFQ *q; int used, left; if (!bucket) initsfq(); which = hash(pkt) % buckets_; q = &bucket[which]; // log_packet_arrival(pkt); used = q->pkts; left = maxqueue_ - occupied; // note: if maxqueue_ is changed while running left can be < 0 if ((used >= (left >> 1)) || (left < buckets_ && used > fairshare) || (left <= 0)) { // log_packet_drop(pkt); drop(pkt); // fprintf(stderr, " drop: 0x%x\n", (int)pkt); return; } q->enque(pkt); ++occupied; ++q->pkts; if (q->pkts == 1) active = q->activate(active); // fprintf(stderr, " enqueue(%d=%d): 0x%x\n", which, q->pkts, (int)pkt); // active->sfqdebug(); } int SFQ::hash(Packet* pkt) { hdr_ip* iph = (hdr_ip*)pkt->access(off_ip_); int i = (int)iph->saddr(); int j = (int)iph->daddr(); int k = i + j; return (k + (k >> 8) + ~(k >> 4)) % ((2<<19)-1); // modulo a large prime }

simple-intserv-sched.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ /* * Copyright (c) 1994 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (LBL)"; #endif //Simple scheduler with 2 service priority levels and protects signalling //ctrl packets #include "config.h" #include "queue.h" #define CLASSES 2 class SimpleIntServ : public Queue { public: SimpleIntServ() { int i; char buf[10]; for (i=0;i<CLASSES;i++) { q_[i] = new PacketQueue; qlimit_[i] = 0; sprintf(buf,"qlimit%d_",i); bind(buf,&qlimit_[i]); } bind("off_ip_",&off_ip_); } protected : void enque(Packet *); Packet *deque(); PacketQueue *q_[CLASSES]; int qlimit_[CLASSES]; int off_ip_; }; static class SimpleIntServClass : public TclClass { public: SimpleIntServClass() : TclClass("Queue/SimpleIntServ") {} TclObject* create(int, const char*const*) { return (new SimpleIntServ); } } class_simple_intserv; void
SimpleIntServ::enque(Packet* p) { hdr_ip* iph=(hdr_ip*)p->access(off_ip_); int cl=(iph->flowid()) ? 1:0; if (q_[cl]->length() >= (qlimit_[cl]-1)) { hdr_cmn* ch=(hdr_cmn*)p->access(off_cmn_); packet_t ptype = ch->ptype(); if ( (ptype != PT_REQUEST) && (ptype != PT_REJECT) && (ptype != PT_ACCEPT) && (ptype != PT_CONFIRM) && (ptype != PT_TEARDOWN) ) { drop(p); } else { q_[cl]->enque(p); } } else { q_[cl]->enque(p); } } Packet *SimpleIntServ::deque() { int i; for (i=CLASSES-1;i>=0;i--) if (q_[i]->length()) return q_[i]->deque(); return 0; }

snoop.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Research Group may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (UCB)"; #endif #include "snoop.h" int hdr_snoop::offset_; class SnoopHeaderClass : public PacketHeaderClass { public: SnoopHeaderClass() : PacketHeaderClass("PacketHeader/Snoop", sizeof(hdr_snoop)) { bind_offset(&hdr_snoop::offset_); } } class_snoophdr; static class LLSnoopClass : public TclClass { public: LLSnoopClass() : TclClass("LL/LLSnoop") {} TclObject* create(int, const char*const*) { return (new LLSnoop()); } } llsnoop_class; static class SnoopClass : public TclClass { public: SnoopClass() : TclClass("Snoop") {} TclObject* create(int, const char*const*) { return (new Snoop()); } } snoop_class; Snoop::Snoop() : NsObject(), fstate_(0), lastSeen_(-1), lastAck_(-1), expNextAck_(0), expDupacks_(0), bufhead_(0), toutPending_(0), buftail_(0), wl_state_(SNOOP_WLEMPTY), wl_lastSeen_(-1), wl_lastAck_(-1), wl_bufhead_(0), wl_buftail_(0) { bind("snoopDisable_", &snoopDisable_); bind_time("srtt_", &srtt_); bind_time("rttvar_", &rttvar_); bind("maxbufs_", &maxbufs_); bind("snoopTick_", &snoopTick_); bind("g_", &g_); bind("tailTime_", &tailTime_); bind("rxmitStatus_", &rxmitStatus_); bind("lru_", &lru_); rxmitHandler_ = new SnoopRxmitHandler(this); int i; for (i = 0; i < SNOOP_MAXWIND; i++) /* data from wired->wireless */ pkts_[i] = 0; for (i = 0; i < SNOOP_WLSEQS; i++) {/* data from wireless->wired */ wlseqs_[i] = (hdr_seq *) malloc(sizeof(hdr_seq)); wlseqs_[i]->seq = wlseqs_[i]->num = 0; } if (maxbufs_ == 0) maxbufs_ = SNOOP_MAXWIND; } void
Snoop::reset() { // printf("%x resetting\n", this); fstate_ = 0; lastSeen_ = -1; lastAck_ = -1; expNextAck_ = 0; expDupacks_ = 0; bufhead_ = buftail_ = 0; if (toutPending_) Scheduler::instance().cancel(toutPending_); toutPending_ = 0; for (int i = 0; i < SNOOP_MAXWIND; i++) { if (pkts_[i]) { Packet::free(pkts_[i]); pkts_[i] = 0; } } } void Snoop::wlreset() { wl_state_ = SNOOP_WLEMPTY; wl_bufhead_ = wl_buftail_ = 0; for (int i = 0; i < SNOOP_WLSEQS; i++) { wlseqs_[i]->seq = wlseqs_[i]->num = 0; } } int Snoop::command(int argc, const char*const* argv) { //Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "llsnoop") == 0) { parent_ = (LLSnoop *) TclObject::lookup(argv[2]); if (parent_) recvtarget_ = parent_->uptarget(); return (TCL_OK); } if (strcmp(argv[1], "check-rxmit") == 0) { if (empty_()) { rxmitStatus_ = SNOOP_PROPAGATE; return (TCL_OK); } Packet *p = pkts_[buftail_]; hdr_snoop *sh = hdr_snoop::access(p); if (sh->sndTime()!=-1 && sh->sndTime()<atoi(argv[2]) && sh->numRxmit() == 0) /* candidate for retransmission */ rxmitStatus_ = snoop_rxmit(p); else rxmitStatus_ = SNOOP_PROPAGATE; return (TCL_OK); } } return NsObject::command(argc, argv); } void LLSnoop::recv(Packet *p, Handler *h) { Tcl &tcl = Tcl::instance(); hdr_ip *iph = hdr_ip::access(p); /* get-snoop creates a snoop object if none currently exists */ if (h == 0) /* In ns, addresses have ports embedded in them. */ tcl.evalf("%s get-snoop %d %d", name(), iph->daddr(), iph->saddr()); else tcl.evalf("%s get-snoop %d %d", name(), iph->saddr(), iph->daddr()); Snoop *snoop = (Snoop *) TclObject::lookup(tcl.result()); snoop->recv(p, h); if (integrate_) tcl.evalf("%s integrate %d %d", name(), iph->saddr(), iph->daddr()); if (h) /* resume higher layer (queue) */ Scheduler::instance().schedule(h, &intr_, 0.000001); return; } /* * Receive a packet from higher layer or from the network. * Call snoop_data() if TCP packet and forward it on if it's an ack. */ void Snoop::recv(Packet* p, Handler* h) { if (h == 0) { // from MAC classifier handle((Event *) p); return; } packet_t type = hdr_cmn::access(p)->ptype(); /* Put packet (if not ack) in cache after checking, and send it on */ if (type == PT_TCP) snoop_data(p); else if (type == PT_ACK) snoop_wired_ack(p); parent_->sendDown(p); /* vector to LLSnoop's sendto() */ } /* * Handle a packet received from peer across wireless link. Check first * for packet errors, then call snoop_ack() or pass it up as necessary. */ void Snoop::handle(Event *e) { Packet *p = (Packet *) e; packet_t type = hdr_cmn::access(p)->ptype(); //int seq = hdr_tcp::access(p)->seqno(); int prop = SNOOP_PROPAGATE; // by default; propagate ack or packet Scheduler& s = Scheduler::instance(); //hdr_ll *llh = hdr_ll::access(p); if (hdr_cmn::access(p)->error()) { parent_->drop(p); // drop packet if it's been corrupted return; } if (type == PT_ACK) prop = snoop_ack(p); else if (type == PT_TCP) /* XXX what about TELNET? */ snoop_wless_data(p); if (prop == SNOOP_PROPAGATE) s.schedule(recvtarget_, e, parent_->delay()); else { // suppress ack /* printf("---- %f suppressing ack %d\n", s.clock(), seq);*/ Packet::free(p); } } /* * Data packet processing. p is guaranteed to be of type PT_TCP when * this function is called. */ void Snoop::snoop_data(Packet *p) { Scheduler &s = Scheduler::instance(); int seq = hdr_tcp::access(p)->seqno(); int resetPending = 0; // printf("%x snoop_data: %f sending packet %d\n", this, s.clock(), seq); if (fstate_ & SNOOP_ALIVE && seq == 0) reset(); fstate_ |= SNOOP_ALIVE; if ((fstate_ & SNOOP_FULL) && !lru_) { // printf("snoop full, fwd'ing\n t %d h %d", buftail_, bufhead_); if (seq > lastSeen_) lastSeen_ = seq; return; } /* * Only if the ifq is NOT full do we insert, since otherwise we want * congestion control to kick in. */ if (parent_->ifq()->length() < parent_->ifq()->limit()-1) resetPending = snoop_insert(p); if (toutPending_ && resetPending == SNOOP_TAIL) { s.cancel(toutPending_); toutPending_ = 0; } if (!toutPending_ && !empty_()) { toutPending_ = (Event *) (pkts_[buftail_]); s.schedule(rxmitHandler_, toutPending_, timeout()); } return; } /* * snoop_insert() does all the hard work for snoop_data(). It traverses the * snoop cache and looks for the right place to insert this packet (or * determines if its already been cached). It then decides whether * this is a packet in the normal increasing sequence, whether it * is a sender-rexmitted-but-lost-due-to-congestion (or network * out-of-order) packet, or if it is a sender-rexmitted packet that * was buffered by us before. */ int Snoop::snoop_insert(Packet *p) { int i, seq = hdr_tcp::access(p)->seqno(), retval=0; if (seq <= lastAck_) return retval; if (fstate_ & SNOOP_FULL) { /* free tail and go on */ printf("snoop full, making room\n"); Packet::free(pkts_[buftail_]); pkts_[buftail_] = 0; buftail_ = next(buftail_); fstate_ |= ~SNOOP_FULL; } if (seq > lastSeen_ || pkts_[buftail_] == 0) { // in-seq or empty cache i = bufhead_; bufhead_ = next(bufhead_); } else if (seq < hdr_snoop::access(pkts_[buftail_])->seqno()) { buftail_ = prev(buftail_); i = buftail_; } else { for (i = buftail_; i != bufhead_; i = next(i)) { hdr_snoop *sh = hdr_snoop::access(pkts_[i]); if (sh->seqno() == seq) { sh->numRxmit() = 0; sh->senderRxmit() = 1; sh->sndTime() = Scheduler::instance().clock(); return SNOOP_TAIL; } else if (sh->seqno() > seq) { Packet *temp = pkts_[prev(buftail_)]; for (int j = buftail_; j != i; j = next(j)) pkts_[prev(j)] = pkts_[j]; i = prev(i); pkts_[i] = temp; buftail_ = prev(buftail_); break; } } if (i == bufhead_) bufhead_ = next(bufhead_); } savepkt_(p, seq, i); if (bufhead_ == buftail_) fstate_ |= SNOOP_FULL; /* * If we have one of the following packets: * 1. a network-out-of-order packet, or * 2. a fast rxmit packet, or 3. a sender retransmission * AND it hasn't already been buffered, * then seq will be < lastSeen_. * We mark this packet as having been due to a sender rexmit * and use this information in snoop_ack(). We let the dupacks * for this packet go through according to expDupacks_. */ if (seq < lastSeen_) { /* not in-order -- XXX should it be <= ? */ if (buftail_ == i) { hdr_snoop *sh = hdr_snoop::access(pkts_[i]); sh->senderRxmit() = 1; sh->numRxmit() = 0; } expNextAck_ = buftail_; retval = SNOOP_TAIL; } else lastSeen_ = seq; return retval; } void Snoop::savepkt_(Packet *p, int seq, int i) { pkts_[i] = p->copy(); Packet *pkt = pkts_[i]; hdr_snoop *sh = hdr_snoop::access(pkt); sh->seqno() = seq; sh->numRxmit() = 0; sh->senderRxmit() = 0; sh->sndTime() = Scheduler::instance().clock(); } /* * Ack processing in snoop protocol. We know for sure that this is an ack. * Return SNOOP_SUPPRESS if ack is to be suppressed and SNOOP_PROPAGATE o.w. */ int Snoop::snoop_ack(Packet *p) { Packet *pkt; int ack = hdr_tcp::access(p)->seqno(); /* * There are 3 cases: * 1. lastAck_ > ack. In this case what has happened is * that the acks have come out of order, so we don't * do any local processing but forward it on. * 2. lastAck_ == ack. This is a duplicate ack. If we have * the packet we resend it, and drop the dupack. * Otherwise we never got it from the fixed host, so we * need to let the dupack get through. * Set expDupacks_ to number of packets already sent * This is the number of dup acks to ignore. * 3. lastAck_ < ack. Set lastAck_ = ack, and update * the head of the buffer queue. Also clean up ack'd packets. */ if (fstate_ & SNOOP_CLOSED || lastAck_ > ack) return SNOOP_PROPAGATE; // send ack onward if (lastAck_ == ack) { /* A duplicate ack; pure window updates don't occur in ns. */ pkt = pkts_[buftail_]; if (pkt == 0) return SNOOP_PROPAGATE; hdr_snoop *sh = hdr_snoop::access(pkt); if (pkt == 0 || sh->seqno() > ack + 1) /* don't have packet, letting thru' */ return SNOOP_PROPAGATE; /* * We have the packet: one of 3 possibilities: * 1. We are not expecting any dupacks (expDupacks_ == 0) * 2. We are expecting dupacks (expDupacks_ > 0) * 3. We are in an inconsistent state (expDupacks_ == -1) */ if (expDupacks_ == 0) { // not expecting it #define RTX_THRESH 1 static int thresh = 0; if (thresh++ < RTX_THRESH) { /* no action if under RTX_THRESH */ return SNOOP_PROPAGATE; } thresh = 0; if (sh->senderRxmit()) return SNOOP_PROPAGATE; /* * Otherwise, not triggered by sender. If this is * the first dupack recd., we must determine how many * dupacks will arrive that must be ignored, and also * rexmit the desired packet. Note that expDupacks_ * will be -1 if we miscount for some reason. */ expDupacks_ = bufhead_ - expNextAck_; if (expDupacks_ < 0) expDupacks_ += SNOOP_MAXWIND; expDupacks_ -= RTX_THRESH + 1; expNextAck_ = next(buftail_); if (sh->numRxmit() == 0) return snoop_rxmit(pkt); } else if (expDupacks_ > 0) { expDupacks_--; return SNOOP_SUPPRESS; } else if (expDupacks_ == -1) { if (sh->numRxmit() < 2) { return snoop_rxmit(pkt); } } else // let sender deal with it return SNOOP_PROPAGATE; } else { // a new ack fstate_ &= ~SNOOP_NOACK; // have seen at least 1 new ack /* free buffers */ double sndTime = snoop_cleanbufs_(ack); if (sndTime != -1) snoop_rtt(sndTime); expDupacks_ = 0; expNextAck_ = buftail_; lastAck_ = ack; } return SNOOP_PROPAGATE; } /* * Handle data packets that arrive from a wireless link, and we're not * the end recipient. See if there are any holes in the transmission, and * if there are, mark them as candidates for wireless loss. Then, when * (dup)acks troop back for this loss, set the ELN bit in their header, to * help the sender (or a snoop agent downstream) retransmit. */ void Snoop::snoop_wless_data(Packet *p) { hdr_tcp *th = hdr_tcp::access(p); int i, seq = th->seqno(); if (wl_state_ & SNOOP_WLALIVE && seq == 0) wlreset(); wl_state_ |= SNOOP_WLALIVE; if (wl_state_ & SNOOP_WLEMPTY && seq >= wl_lastAck_) { wlseqs_[wl_bufhead_]->seq = seq; wlseqs_[wl_bufhead_]->num = 1; wl_buftail_ = wl_bufhead_; wl_bufhead_ = wl_next(wl_bufhead_); wl_lastSeen_ = seq; wl_state_ &= ~SNOOP_WLEMPTY; return; } /* WL data list definitely not empty at this point. */ if (seq >= wl_lastSeen_) { wl_lastSeen_ = seq; i = wl_prev(wl_bufhead_); if (wlseqs_[i]->seq + wlseqs_[i]->num == seq) { wlseqs_[i]->num++; return; } i = wl_bufhead_; wl_bufhead_ = wl_next(wl_bufhead_); } else if (seq == wlseqs_[i = wl_buftail_]->seq - 1) { } else return; wlseqs_[i]->seq = seq; wlseqs_[i]->num++; /* Ignore network out-of-ordering and retransmissions for now */ return; } /* * Ack from wired side (for sender on "other" side of wireless link. */ void Snoop::snoop_wired_ack(Packet *p) { hdr_tcp *th = hdr_tcp::access(p); int ack = th->seqno(); int i; if (ack == wl_lastAck_ && snoop_wlessloss(ack)) { hdr_flags::access(p)->eln_ = 1; } else if (ack > wl_lastAck_) { /* update info about unack'd data */ for (i = wl_buftail_; i != wl_bufhead_; i = wl_next(i)) { hdr_seq *t = wlseqs_[i]; if (t->seq + t->num - 1 <= ack) { t->seq = t->num = 0; } else if (ack < t->seq) { break; } else if (ack < t->seq + t->num - 1) { /* ack for part of a block */ t->num -= ack - t->seq +1; t->seq = ack + 1; break; } } wl_buftail_ = i; if (wl_buftail_ == wl_bufhead_) wl_state_ |= SNOOP_WLEMPTY; wl_lastAck_ = ack; /* Even a new ack could cause an ELN to be set. */ if (wl_bufhead_ != wl_buftail_ && snoop_wlessloss(ack)) hdr_flags::access(p)->eln_ = 1; } } /* * Return 1 if we think this packet loss was not congestion-related, and * 0 otherwise. This function simply implements the lookup into the table * that maintains this info; most of the hard work is done in * snoop_wless_data() and snoop_wired_ack(). */ int Snoop::snoop_wlessloss(int ack) { if ((wl_bufhead_ == wl_buftail_) || wlseqs_[wl_buftail_]->seq > ack+1) return 1; return 0; } /* * clean snoop cache of packets that have been acked. */ double Snoop::snoop_cleanbufs_(int ack) { Scheduler &s = Scheduler::instance(); double sndTime = -1; if (toutPending_) s.cancel(toutPending_); toutPending_ = 0; if (empty_()) return sndTime; int i = buftail_; do { hdr_snoop *sh = hdr_snoop::access(pkts_[i]); int seq = hdr_tcp::access(pkts_[i])->seqno(); if (seq <= ack) { sndTime = sh->sndTime(); Packet::free(pkts_[i]); pkts_[i] = 0; fstate_ &= ~SNOOP_FULL; /* XXX redundant? */ } else if (seq > ack) break; i = next(i); } while (i != bufhead_); if ((i != buftail_) || (bufhead_ != buftail_)) { fstate_ &= ~SNOOP_FULL; buftail_ = i; } if (!empty_()) { toutPending_ = (Event *) (pkts_[buftail_]); s.schedule(rxmitHandler_, toutPending_, timeout()); hdr_snoop *sh = hdr_snoop::access(pkts_[buftail_]); tailTime_ = sh->sndTime(); } return sndTime; } /* * Calculate smoothed rtt estimate and linear deviation. */ void Snoop::snoop_rtt(double sndTime) { double rtt = Scheduler::instance().clock() - sndTime; if (parent_->integrate()) { parent_->snoop_rtt(sndTime); return; } if (rtt > 0) { srtt_ = g_*srtt_ + (1-g_)*rtt; double delta = rtt - srtt_; if (delta < 0) delta = -delta; if (rttvar_ != 0) rttvar_ = g_*delta + (1-g_)*rttvar_; else rttvar_ = delta; } } /* * Calculate smoothed rtt estimate and linear deviation. */ void LLSnoop::snoop_rtt(double sndTime) { double rtt = Scheduler::instance().clock() - sndTime; if (rtt > 0) { srtt_ = g_*srtt_ + (1-g_)*rtt; double delta = rtt - srtt_; if (delta < 0) delta = -delta; if (rttvar_ != 0) rttvar_ = g_*delta + (1-g_)*rttvar_; else rttvar_ = delta; } } /* * Returns 1 if recent queue length is <= half the maximum and 0 otherwise. */ int Snoop::snoop_qlong() { /* For now only instantaneous lengths */ if (parent_->ifq()->length() <= 3*parent_->ifq()->limit()/4) return 1; return 0; } /* * Ideally, would like to schedule snoop retransmissions at higher priority. */ int Snoop::snoop_rxmit(Packet *pkt) { Scheduler& s = Scheduler::instance(); if (pkt != 0) { hdr_snoop *sh = hdr_snoop::access(pkt); if (sh->numRxmit() < SNOOP_MAX_RXMIT && snoop_qlong()) { /* && sh->seqno() == lastAck_+1) */ #if 0 printf("%f Rxmitting packet %d\n", s.clock(), hdr_tcp::access(pkt)->seqno()); #endif sh->sndTime() = s.clock(); sh->numRxmit() = sh->numRxmit() + 1; Packet *p = pkt->copy(); parent_->sendDown(p); } else return SNOOP_PROPAGATE; } /* Reset timeout for later time. */ if (toutPending_) s.cancel(toutPending_); toutPending_ = (Event *)pkt; s.schedule(rxmitHandler_, toutPending_, timeout()); return SNOOP_SUPPRESS; } void Snoop::snoop_cleanup() { } void SnoopRxmitHandler::handle(Event *) { Packet *p = snoop_->pkts_[snoop_->buftail_]; snoop_->toutPending_ = 0; if (p == 0) return; hdr_snoop *sh = hdr_snoop::access(p); if (sh->seqno() != snoop_->lastAck_ + 1) return; if ((snoop_->bufhead_ != snoop_->buftail_) || (snoop_->fstate_ & SNOOP_FULL)) { /* printf("%f timeout\n", Scheduler::instance().clock());*/ if (snoop_->snoop_rxmit(p) == SNOOP_SUPPRESS) snoop_->expNextAck_ = snoop_->next(snoop_->buftail_); } }

srm-ssm.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ // // Copyright (c) 1997 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for non-commercial purposes // and without fee is hereby granted, provided that the above copyright // notice appear in all copies and that both the copyright notice and // this permission notice appear in supporting documentation. and that // any documentation, advertising materials, and other materials related // to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the University may not be used to // endorse or promote products derived from this software without // specific prior written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about // the suitability of this software for any purpose. THIS SOFTWARE IS // PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // Other copyrights might apply to parts of this software and are so // noted when applicable. // // Maintainer: // Version Date: Tue Jul 22 15:41:16 PDT 1997 // The code implements scalable session message. See // http://catarina.usc.edu/estrin/papers/infocom98/ssession.ps // #ifndef lint static const char rcsid[] = "@(#) $Header$ (USC/ISI)"; #endif #include <stdlib.h> #include <assert.h> #include <stdio.h> #include "config.h" #include "tclcl.h" #include "agent.h" #include "packet.h" #include "ip.h" #include "srm.h" #include "srm-ssm.h" #include "trace.h" int hdr_srm_ext::offset_; static class SRMEXTHeaderClass : public PacketHeaderClass { public: SRMEXTHeaderClass() : PacketHeaderClass("PacketHeader/SRMEXT", sizeof(hdr_srm_ext)) { bind_offset(&hdr_srm_ext::offset_); } } class_srmexthdr; static class SSMSRMAgentClass : public TclClass { public: SSMSRMAgentClass() : TclClass("Agent/SRM/SSM") {} TclObject* create(int, const char*const*) { return (new SSMSRMAgent()); } } class_srm_ssm_agent; SSMSRMAgent::SSMSRMAgent() : SRMAgent(), glb_sessCtr_(-1), loc_sessCtr_(-1), rep_sessCtr_(-1) { bind("group_scope_",&groupScope_); bind("local_scope_",&localScope_); bind("scope_flag_",&scopeFlag_); bind("rep_id_", &repid_); bind("off_srm_ext_", &off_srm_ext_); } int
SSMSRMAgent::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (strcmp(argv[1], "send") == 0) { if (strcmp(argv[2], "session") == 0) { send_sess(); return TCL_OK; } if (strcmp(argv[2], "request") == 0) { int round = atoi(argv[3]); int sender = atoi(argv[4]); int msgid = atoi(argv[5]); send_ctrl(SRM_RQST, round, sender, msgid, 0); return TCL_OK; } if (strcmp(argv[2], "repair") == 0) { int round = atoi(argv[3]); int sender = atoi(argv[4]); int msgid = atoi(argv[5]); send_ctrl(SRM_REPR, round, sender, msgid, packetSize_); return TCL_OK; } tcl.resultf("%s: invalid send request %s", name_, argv[2]); return TCL_ERROR; /* #if 0 fprintf(stdout,"%s: send request %s passed to srm_agent", name_, argv[2]); #endif return SRMAgent::command(argc, argv); */ } if (argc == 2) { if (strcmp(argv[1], "start") == 0) { sip_->sender_ = addr(); sip_->distance_ = 0.0; /* sip_->repid_ = addr_; sip_->scopeFlag_ = SRM_GLOBAL; repid_ = addr_; scopeFlag_ = SRM_GLOBAL; */ groupScope_ = 32; senderFlag_ = 0; printf("%s is %d and rep-status %d\n", name_, addr(), scopeFlag_); return TCL_OK; } if (strcmp(argv[1], "ch-rep") == 0) { if(scopeFlag_ == SRM_GLOBAL) { sip_->repid_ = repid_ = addr(); sip_->scopeFlag_ = SRM_GLOBAL; } else { sip_->repid_ = repid_; sip_->scopeFlag_ = SRM_LOCAL; } return TCL_OK; } if (strcmp(argv[1], "distances?") == 0) { if (sip_->sender_ < 0) { // i.e. this agent is not tcl.result(""); // yet active. return TCL_OK; } for (SRMinfo* sp = sip_; sp; sp = sp->next_) { if((sp->distanceFlag_ == REP_DISTANCE) || (sp->distanceFlag_ == SELF_DISTANCE)) { tcl.resultf("%s %d %f", tcl.result(), sp->sender_, sp->distance_); } else { /* Return reps distance */ SRMinfo* rsp = get_state(sp->repid_); tcl.resultf("%s %d %f", tcl.result(), sp->sender_, rsp->distance_); } } return TCL_OK; } } if (argc == 3) { if (strcmp(argv[1], "distance?") == 0) { int sender = atoi(argv[2]); SRMinfo* sp = get_state(sender); if((sp->distanceFlag_ == REP_DISTANCE) || (sp->distanceFlag_ == SELF_DISTANCE)) { tcl.resultf("%f", sp->distance_); } else { /* Return reps distance */ SRMinfo* rsp = get_state(sp->repid_); tcl.resultf("%f", rsp->distance_); } return TCL_OK; } } return SRMAgent::command(argc, argv); } void SSMSRMAgent::recv(Packet* p, Handler* h) { hdr_ip* ih = (hdr_ip*) p->access(off_ip_); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_); if (ih->daddr() == 0) { // Packet from local agent. Add srm headers, set dst, and fwd sh->type() = SRM_DATA; sh->sender() = addr(); sh->seqnum() = ++dataCtr_; seh->repid() = repid_; ih->dst() = dst_; ih->src() = here_; target_->recv(p, h); } else { #if 0 static char *foo[] = {"NONE", "DATA", "SESS", "RQST", "REPR"}; fprintf(stdout, "%7.4f %s %d recvd SRM_%s <%d, %d> from %d\n", Scheduler::instance().clock(), name_, addr_, foo[sh->type()], sh->sender(), sh->seqnum(), ih->src()); fflush(stdout); #endif switch (sh->type()) { case SRM_DATA: recv_data(sh->sender(), sh->seqnum(), seh->repid(), p->accessdata()); Packet::free(p); break; case SRM_RQST: recv_rqst(ih->saddr(), sh->round(), sh->sender(), sh->seqnum(), seh->repid()); Packet::free(p); break; case SRM_REPR: recv_repr(sh->round(), sh->sender(), sh->seqnum(), p->accessdata()); Packet::free(p); break; case SRM_SESS: // This seqnum() is the session sequence number, // not the data packet sequence numbers seen before. // Send the whole pkt for ttl etc.. recv_sess(sh->seqnum(), (int*) p->accessdata(), p); break; } } } void SSMSRMAgent::recv_data(int sender, int id, int repid, u_char* data) { SRMinfo* sp = get_state(sender); /* Just store the repid and call srmagent recv_data */ sp->repid_ = repid; SRMAgent::recv_data(sender,id,data); } void SSMSRMAgent::send_ctrl(int type, int round, int sender, int msgid, int size) { Packet* p = Agent::allocpkt(); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_); sh->type() = type; sh->sender() = sender; sh->seqnum() = msgid; sh->round() = round; seh->repid() = repid_; /* For ctrl messages this is your own repid */ hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() = sizeof(hdr_srm) + size; target_->recv(p, (Handler*)NULL); } void SSMSRMAgent::recv_rqst(int requestor, int round, int sender, int msgid, int repid) { //Tcl& tcl = Tcl::instance(); SRMinfo* rsp = get_state(requestor); rsp->repid_ = repid; SRMAgent::recv_rqst(requestor,round, sender,msgid); } void SSMSRMAgent::send_sess() { if (scopeFlag_ == SRM_GLOBAL) { send_glb_sess(); send_rep_sess(); } else { send_loc_sess(); } // timeout_info(); } #define SESSINFO_SIZE 5 #define SESS_CONST 2 void SSMSRMAgent::send_glb_sess() { int size = (SESS_CONST + groupSize_ * SESSINFO_SIZE) * sizeof(int); /* Currently do extra allocation, later change */ int num_entries; Packet* p = Agent::allocpkt(size); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_); #if 0 printf("sending global session message\n"); #endif sh->type() = SRM_SESS; sh->sender() = addr(); sh->seqnum() = ++glb_sessCtr_; seh->repid() = repid_; int* data = (int*) p->accessdata(); *data++ = groupSize_; *data++ = SRM_GLOBAL; num_entries = 0; for (SRMinfo* sp = sip_; sp; sp = sp->next_) { /* Global Session Message has information about Senders/reps */ if ((sp->senderFlag_ || (sp->scopeFlag_ == SRM_GLOBAL) || (sp->sender_ == addr())) && (is_active(sp))) { *data++ = sp->sender_; *data++ = sp->ldata_; *data++ = sp->recvTime_; *data++ = sp->sendTime_; *data++ = sp->repid_; num_entries++; } } data = (int*) p->accessdata(); data[0] = num_entries; data[1] = SRM_GLOBAL; size = (SESS_CONST + num_entries * SESSINFO_SIZE) * sizeof(int); data[5] = (int) (Scheduler::instance().clock()*1000); hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() += size+ sizeof(hdr_srm); /* Add size of srm_hdr_ext */ hdr_ip* ih = (hdr_ip*) p->access(off_ip_); ih->ttl() = groupScope_; // Currently put this to distinguish various session messages ih->flowid() = SRM_GLOBAL; seh->ottl() = groupScope_; target_->recv(p, (Handler*)NULL); } void SSMSRMAgent::send_loc_sess() { int size = (SESS_CONST + groupSize_ * SESSINFO_SIZE) * sizeof(int); /* Currently do extra allocation, later change */ int num_entries; Packet* p = Agent::allocpkt(size); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_); sh->type() = SRM_SESS; sh->sender() = addr(); sh->seqnum() = ++loc_sessCtr_; seh->repid() = repid_; #if 0 printf("sending local session message\n"); #endif int* data = (int*) p->accessdata(); //int* tmp_data = (int*) p->accessdata(); *data++ = groupSize_; *data++ = SRM_LOCAL; num_entries = 0; for (SRMinfo* sp = sip_; sp; sp = sp->next_) { /* Local Session Message has information about Senders/other locals */ if ((sp->senderFlag_ || (sp->scopeFlag_ == SRM_LOCAL) || (sp->distanceFlag_ = SELF_DISTANCE) || /* For the reps that I am hearing from */ (sp->sender_ == addr()) || // just in case, I have not set the flags properly, // one entry has to be there (repid_ == sp->sender_)) && (is_active(sp))) { *data++ = sp->sender_; *data++ = sp->ldata_; *data++ = sp->recvTime_; *data++ = sp->sendTime_; *data++ = sp->repid_; num_entries++; } } data = (int*) p->accessdata(); data[0] = num_entries; data[1] = SRM_LOCAL; size = (SESS_CONST + num_entries * SESSINFO_SIZE) * sizeof(int); data[5] = (int) (Scheduler::instance().clock()*1000); hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() += size+ sizeof(hdr_srm); hdr_ip* ih = (hdr_ip*) p->access(off_ip_); ih->ttl() = localScope_; // Currently put this to distinguish various session messages ih->flowid() = SRM_LOCAL; seh->ottl() = localScope_; target_->recv(p, (Handler*)NULL); } void SSMSRMAgent::send_rep_sess() { int size = (SESS_CONST + groupSize_ * SESSINFO_SIZE) * sizeof(int); /* Currently do extra allocation, later change */ int num_entries, num_local_members; Packet* p = Agent::allocpkt(size); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_); sh->type() = SRM_SESS; sh->sender() = addr(); sh->seqnum() = ++rep_sessCtr_; seh->repid() = repid_; #if 0 printf("sending rep_info session message\n"); #endif int* data = (int*) p->accessdata(); *data++ = groupSize_; *data++ = SRM_RINFO; num_entries = 0; num_local_members = 0; for (SRMinfo* sp = sip_; sp; sp = sp->next_) { if (sp->activeFlag_ == ACTIVE) { /* Rep info has distance to others reps and timestamps for everyone */ *data++ = sp->sender_; *data++ = sp->ldata_; if (sp->scopeFlag_ == SRM_GLOBAL) { *data++ = (int) (sp->distance_*1000); data++; } else { // Put a check here for only people I have heard from.?? *data++ = sp->recvTime_; *data++ = sp->sendTime_; num_local_members++; } *data++ = sp->repid_; num_entries++; } } if (num_local_members <= 0) { Packet::free(p); return; } data = (int*) p->accessdata(); data[0] = num_entries; data[1] = SRM_RINFO; size = (SESS_CONST + num_entries * SESSINFO_SIZE) * sizeof(int); data[5] = (int) (Scheduler::instance().clock()*1000); hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() += size+ sizeof(hdr_srm); hdr_ip* ih = (hdr_ip*) p->access(off_ip_); ih->ttl() = localScope_; // Currently put this to distinguish various session messages ih->flowid() = SRM_RINFO; seh->ottl() = localScope_; target_->recv(p, (Handler*)NULL); } #define GET_SESSION_INFO \ sender = *data++; \ dataCnt = *data++; \ rtime = *data++; \ stime = *data++; \ repid = *data++; \ // printf("s:%d, d:%d, rt:%d, st:%d, rep:%d\n",sender, // dataCnt,rtime,stime,repid) void SSMSRMAgent::recv_sess(int sessCtr, int* data, Packet* p) { int type = data[1]; switch (type) { case SRM_GLOBAL : recv_glb_sess(sessCtr,data,p); break; case SRM_LOCAL : recv_loc_sess(sessCtr,data,p); break; case SRM_RINFO : if (scopeFlag_ == SRM_GLOBAL) return; recv_rep_sess(sessCtr,data,p); break; } Packet::free(p); } void SSMSRMAgent::recv_glb_sess(int sessCtr, int* data, Packet* p) { Tcl& tcl = Tcl::instance(); SRMinfo* sp; int ttl; hdr_ip* ih = (hdr_ip*) p->access(off_ip_); //hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_); ttl = seh->ottl() - ih->ttl(); int sender, dataCnt, rtime, stime,repid; int now, sentAt, sentBy; int cnt = *data++; //int type = *data++; int i; // data = data + SESS_CONST; /* As as included type of session message also */ /* The first block contains the sender's own state */ GET_SESSION_INFO; if (sender == addr()) // sender's own session message return; if (seh->repid() != repid) { fprintf(stdout,"%f Recvd a glb-sess with diff header(%d) != inside(%d)\n", Scheduler::instance().clock(),seh->repid(),repid); /* abort(); */ return; } if (sender != repid) { fprintf(stdout,"%f Recvd a glb-sess with repid(%d) != address(%d)\n", Scheduler::instance().clock(),repid,sender); /* abort(); */ return; } sp = get_state(sender); if (sp->lglbsess_ > sessCtr) // older session message recd. return; #if 0 fprintf(stdout,"%s recv-gsess from %d\n",name_,sender); #endif tcl.evalf("%s recv-gsess %d %d", name_, sender, ttl); if (sp->scopeFlag_ != SRM_GLOBAL) { sp->scopeFlag_ = SRM_GLOBAL; } sp->repid_ = repid; now = (int) (Scheduler::instance().clock() * 1000); sentBy = sender; // to later compute rtt sentAt = stime; sp->lglbsess_ = sessCtr; sp->recvTime_ = now; sp->sendTime_ = stime; for (i = sp->ldata_ + 1; i <= dataCnt; i++) if (! sp->ifReceived(i)) tcl.evalf("%s request %d %d", name_, sender, i, sp->repid_); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; for (i = 1; i < cnt; i++) { GET_SESSION_INFO; if (sender == addr() && now) { int rtt = (now - sentAt) + (rtime - stime); sp = get_state(sentBy); sp->distance_ = (double) rtt / 2 / 1000; sp->distanceFlag_ = SELF_DISTANCE; #if 0 fprintf(stderr, "%7.4f %s compute distance to %d: %f\n", Scheduler::instance().clock(), name_, sentBy, sp->distance_); #endif continue; } sp = get_state(sender); for (int j = sp->ldata_ + 1; j <= dataCnt; j++) if (! sp->ifReceived(j)) tcl.evalf("%s request %d %d", name_, sender, j, sp->repid_); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; } } void SSMSRMAgent::recv_loc_sess(int sessCtr, int* data, Packet* p) { Tcl& tcl = Tcl::instance(); SRMinfo* sp; int ttl; hdr_ip* ih = (hdr_ip*) p->access(off_ip_); //hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_srm_ext* seh = (hdr_srm_ext*) p->access(off_srm_ext_); ttl = seh->ottl() - ih->ttl(); int sender, dataCnt, rtime, stime,repid; int now, sentAt, sentBy; int cnt = *data++; /*int type = * */data++; int i; // data = data + SESS_CONST; /* As as included type of session message also */ /* The first block contains the sender's own state */ GET_SESSION_INFO; if (sender == addr()) // sender's own session message return; sp = get_state(sender); if (sp->llocsess_ > sessCtr) // older session message recd. return; if (sp->scopeFlag_ != SRM_LOCAL) { sp->scopeFlag_ = SRM_LOCAL; // Also put a check if this is my child } sp->repid_ = repid; #if 0 fprintf(stdout,"%s recv-lsess from %d\n",name_,sender); #endif tcl.evalf("%s recv-lsess %d %d %d", name_, sender, repid, ttl); now = (int) (Scheduler::instance().clock() * 1000); sentBy = sender; // to later compute rtt sentAt = stime; sp->llocsess_ = sessCtr; sp->recvTime_ = now; sp->sendTime_ = stime; for (i = sp->ldata_ + 1; i <= dataCnt; i++) if (! sp->ifReceived(i)) tcl.evalf("%s request %d %d", name_, sender, i, sp->repid_); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; for (i = 1; i < cnt; i++) { GET_SESSION_INFO; if (sender == addr() && now) { int rtt = (now - sentAt) + (rtime - stime); sp = get_state(sentBy); sp->distance_ = (double) rtt / 2 / 1000; sp->distanceFlag_ = SELF_DISTANCE; #if 0 fprintf(stderr, "%7.4f %s compute distance to %d: %f\n", Scheduler::instance().clock(), name_, sentBy, sp->distance_); #endif continue; } sp = get_state(sender); for (int j = sp->ldata_ + 1; j <= dataCnt; j++) if (! sp->ifReceived(j)) tcl.evalf("%s request %d %d", name_, sender, j, sp->repid_); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; } } // For the global members the repid == addr void SSMSRMAgent::recv_rep_sess(int sessCtr, int* data, Packet*) { Tcl& tcl = Tcl::instance(); SRMinfo* sp; int sender, dataCnt, rtime, stime,repid; int now, sentAt, sentBy; int cnt = *data++; /*int type = **/data++; int i; //data = data + SESS_CONST; /* As as included type of session message also */ /* The first block contains the sender's own state */ GET_SESSION_INFO; if (sender == addr()) // sender's own session message return; if (sender != repid_) // not from my rep return; if (sender != repid) { fprintf(stdout,"Recvd a rep-sess with repid(%d) != address(%d)\n", repid,sender); abort(); } sp = get_state(sender); if (sp->lrepsess_ > sessCtr) // older session message recd. return; if (sp->scopeFlag_ != SRM_GLOBAL) // Should I change the repid also?? sp->scopeFlag_ = SRM_GLOBAL; now = (int) (Scheduler::instance().clock() * 1000); sentBy = sender; // to later compute rtt sentAt = stime; sp->lrepsess_ = sessCtr; sp->recvTime_ = now; sp->sendTime_ = stime; for (i = sp->ldata_ + 1; i <= dataCnt; i++) if (! sp->ifReceived(i)) tcl.evalf("%s request %d %d", name_, sender, i, sp->repid_); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; for (i = 1; i < cnt; i++) { GET_SESSION_INFO; if (sender == addr() && now) { int rtt = (now - sentAt) + (rtime - stime); sp = get_state(sentBy); sp->distance_ = (double) rtt / 2 / 1000; sp->distanceFlag_ = SELF_DISTANCE; #if 0 fprintf(stderr, "%7.4f %s compute distance to %d: %f\n", Scheduler::instance().clock(), name_, sentBy, sp->distance_); #endif continue; } if ((sender == repid) && (sender != sentBy)) { sp = get_state(sender); if (!(is_active(sp) && (sp->distanceFlag_ == SELF_DISTANCE))) { sp->distance_ = (double) rtime/1000; /* As for global members this is distance */ sp->distanceFlag_ = REP_DISTANCE; /* ?? What if I am hearing from this guy already */ } } sp = get_state(sender); for (int j = sp->ldata_ + 1; j <= dataCnt; j++) if (! sp->ifReceived(j)) tcl.evalf("%s request %d %d", name_, sender, j, sp->repid_); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; } } #define sessionDelay 1000 void SSMSRMAgent::timeout_info() { int now; now = (int) (Scheduler::instance().clock() * 1000); for (SRMinfo* sp = sip_->next_; sp; sp = sp->next_) { if ((now - sp->recvTime_) >= 3*sessionDelay) { sp->activeFlag_ = INACTIVE; groupSize_--; } } } int SSMSRMAgent::is_active(SRMinfo *sp) { int now; now = (int) (Scheduler::instance().clock() * 1000); if ((sp->sender_ != addr()) && ((now - sp->recvTime_) >= 3*sessionDelay)) { return 0; } else { return 1; } }

srm-topo.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or derivative * work. Xerox grants no other licenses expressed or implied. The Xerox trade * name should not be used in any advertising without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this software. * * This file contributed by Suchitra Raman <sraman@parc.xerox.com>, June 1997. */ #include <stdlib.h> #include <math.h> #include "config.h" #include "tclcl.h" #include "srm-topo.h" #include "scheduler.h" #define SRM_DEBUG Topology::Topology(int nn, int src) : idx_(nn), src_(src) { node_ = new SrmNode[nn]; for (int i = 0; i < nn; i ++) node_[i].id(i); bind("src_", &src_); bind("delay_", &delay_); bind("D_", &D_); bind("frac_", &frac_); /* D_ (ms) is the delay of node 1 from node 0 */ bind("det_", &det_); bind("rtt_est_", &rtt_est_); bind("rand_", &rand_); } Topology::~Topology() { delete [] node_; } int
Topology::command(int argc, const char*const* argv) { //Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "flood") == 0) { flood(0, atoi(argv[2])); return (TCL_OK); } } return (TclObject::command(argc, argv)); } SrmNode* Topology::node(int nn) { if (nn < 0 || nn >= idx_) return 0; return &(node_[nn]); } static class LineClass : public TclClass { public: LineClass() : TclClass("Topology/Line") {} TclObject* create(int, const char*const* argv) { int nn = atoi(argv[4]); return (new Line(nn, 0)); } } class_line_topo; double Line::backoff(int dst) { double rtt; if (topology->rtt_estimated() == 1) rtt = delay(dst, 0); else rtt = D_ * frac_; double b; double sqroot = sqrt(rtt); double r = Random::uniform(0.0, 1.0); switch(c2func_) { case LOG : b = rtt * (det_ + rand_ * r * log(rtt)/log(D_)); break; case SQRT : b = rtt * (det_ + rand_ * r * sqroot/sqrt(D_)); break; case LINEAR : b = rtt * (det_ + rand_ * r * rtt/D_); break; case CONSTANT : b = rtt * (det_ + rand_ * r * 1.); break; } return b; } #ifdef SRM_BIMODAL double Line::backoff(int dst) { double rtt; if (topology->rtt_estimated() == 1) rtt = delay(dst, 0); else rtt = D_ * frac_; double rbackoff; double p = Random::uniform(0.0, 1.0); int bin = 0; int copies = c_; int size = topology->idx(); if (p <= copies * 1./size) { rbackoff = Random::uniform(0.0, alpha_); bin = 0; } else { rbackoff = Random::uniform(beta_, 1.0 + beta_); bin = 1; } return (rtt * (det_ + rand_ * rbackoff)); } #endif Interface_List* Line::oif(int node, int iif=SRM_NOIF) { //int oif; Interface_List *ilist = new Interface_List; /* If there are no more nodes downstream, return -1 */ if ((iif <= node && node >= idx_ - 1) || (iif > node && node == 0)) return 0; if (iif == SRM_NOIF) { ilist->append(node + 1); ilist->append(node - 1); } else if (iif <= node) ilist->append(node + 1); else ilist->append(node - 1); return (ilist); } double Line::delay(int src, int dst) { if (src == 0 || dst == 0) return D_ + delay_ * abs(dst - src - 1); else return delay_ * abs(dst - src); } double Star::delay(int src, int dst) { if (src == 0 || dst == 0) return D_; else return delay_; } /* * Very simple now, can only send to direct ancestor/descendant */ double BTree::delay(int src, int dst) { double src_ht = 0; double dst_ht = 0; if (src > 0) src_ht = 1 + floor(log(src)/log(2)); if (dst > 0) dst_ht = 1 + floor(log(dst)/log(2)); if (src == 0 || dst == 0) return D_ + delay_ * abs(int (dst_ht - src_ht - 1)); else return delay_ * abs(int (dst_ht - src_ht)); } /* * There is always an outbound interface. We should not * start a flood() from a leaf node. * Change it for other topologies. */ void Line::flood(int start, int seqno) { SRM_Event *se = new SRM_Event(seqno, SRM_DATA, start); node_[start].send(se); } /* * BTree - */ static class BTreeClass : public TclClass { public: BTreeClass() : TclClass("Topology/BTree") {} TclObject* create(int, const char*const* argv) { int nn = atoi(argv[4]); return (new BTree(nn, 0)); } } class_btree_topo; /* * The ranges of the different distributions * must be normalized to 1. */ double BTree::backoff(int id) { double rtt; if (topology->rtt_estimated()) rtt = delay(id, 0); else rtt = D_ * frac_; double r = Random::uniform(0.0, 1.0); double b; double sqroot = sqrt(rtt); double D = topology->D(); switch(c2func_) { case LOG : b = rtt * (det_ + rand_ * r * log(rtt)/log(D)); break; case SQRT : b = rtt * (det_ + rand_ * r * sqroot/sqrt(D)); break; case LINEAR : b = rtt * (det_ + rand_ * r * rtt/D); break; case CONSTANT : b = rtt * (det_ + rand_ * r * 1.); break; } return b; } Interface_List* BTree::oif(int node, int iif=SRM_NOIF) { //int oif; Interface_List *ilist = new Interface_List; /* * If the packet comes from the source, * there is only 1 outgoing link. * We make the assumption that source = 0 always (YUCK!) */ if (iif == SRM_NOIF) { if (node == 0) { ilist->append(1); } else { ilist->append(2 * node + 1); ilist->append(2 * node); int k = (int)floor(.5 * node); ilist->append(k); } } else if (iif <= node) { ilist->append(2 * node + 1); ilist->append(2 * node); } // Packet came along 2n + 1 or 2n + 2 else if (iif == 2 * node + 1) { if (node == 0) return ilist; ilist->append(2 * node); ilist->append((int) floor(.5 * node)); } else if (iif == 2 * node) { ilist->append(2 * node + 1); ilist->append((int)floor(.5 * node)); } return (ilist); } /* * Star - */ static class StarClass : public TclClass { public: StarClass() : TclClass("Topology/Star") {} TclObject* create(int, const char*const* argv) { int nn = atoi(argv[4]); return (new Star(nn, 0)); } } class_star_topo; /* * SrmNode - */ void SrmNode::dump_packet(SRM_Event *e) { #ifdef SRM_DEBUG tprintf(("(type %d) (in %d) -- @ %d --> \n", e->type(), e->iif(), id_)); #endif } /* This forwards an event by making multiple copies of the * event 'e'. Does NOT free event 'e'. */ void SrmNode::send(SRM_Event *e) { /* * Copy the packet and send it over to * all the outbound interfaces */ int nn; Scheduler& s = Scheduler::instance(); SRM_Event *copy; Interface *p; Interface_List *ilist = topology->oif(id_, e->iif()); if (e->iif() < 0) e->iif(id_); if (ilist) { for (p=ilist->head_; p; p=p->next_) { nn = p->in_; int t = e->type(); //int i = id_; int snum = e->seqno(); SrmNode *next = topology->node(nn); if (next) { copy = new SRM_Event(snum, t, id_); s.schedule(next, copy, topology->delay(id_, nn)); } } } delete ilist; delete e; } /* * Demux the two types of events depending on * the type field. */ void SrmNode::handle(Event* event) { SRM_Event *srm_event = (SRM_Event *) event; int type = srm_event->type(); int seqno = srm_event->seqno(); //int iif = srm_event->iif(); //Scheduler& s = Scheduler::instance(); switch (type) { case SRM_DATA : if (seqno != expected_) sched_nack(seqno); expected_ = seqno; break; case SRM_PENDING_RREQ : tprintf(("Fired RREQ (node %d)\n", id_)); remove(seqno, SRM_NO_SUPPRESS); srm_event->type(SRM_RREQ); break; case SRM_RREQ : remove(seqno, SRM_SUPPRESS); break; default : tprintf(("panic: node(%d) Unexpected type %d\n", id_, type)); return; } #ifdef SRM_STAR if (type == SRM_RREQ || type == SRM_DATA) { delete srm_event; return; } #endif send(srm_event); return; } /* * XXX Should take two sequence numbers. The iif field is a dummy. We should be * careful not to use it for NACKs */ void SrmNode::sched_nack(int seqno) { double backoff, time; Scheduler& s = Scheduler::instance(); SRM_Event *event = new SRM_Event(seqno, SRM_PENDING_RREQ, SRM_NOIF); append(event); backoff = topology->backoff(id_); time = backoff + s.clock(); // tprintf(("node(%d) schd rrq after %f s\n", id_, backoff)); s.schedule(this, event, backoff); } void SrmNode::append(SRM_Event *e) { SRM_Request *req = new SRM_Request(e); req->next_ = pending_; pending_ = req; } /* If an event identical to e exists, cancel it */ void SrmNode::remove(int seqno, int flag) { SRM_Request *curr, *prev; SRM_Event *ev; if (!pending_) return; for (curr=pending_, prev=0; curr; curr=curr->next_) { ev = curr->event_; if (ev->seqno() == seqno) { if (!prev) pending_ = curr->next_; else { prev->next_ = curr->next_; prev = curr; } if (flag == SRM_SUPPRESS) { curr->cancel_timer(); } delete curr; } } } SRM_Event::SRM_Event(SRM_Event *e) { seqno_ = e->seqno(); type_ = e->type(); iif_ = e->iif(); } SRM_Request::~SRM_Request() {} void SRM_Request::cancel_timer() { if (event_) { Scheduler& s = Scheduler::instance(); s.cancel(event_); } } void Interface_List::append(int in) { Interface *i = new Interface(in); i->next_ = head_; head_ = i; } Interface_List::~Interface_List() { Interface *p, *next; for (p=head_; p; p=next) { next = p->next_; delete p; } } void BTree::flood(int start, int seqno) { SRM_Event *se = new SRM_Event(seqno, SRM_DATA, SRM_NOIF); node_[start].send(se); } void Star::flood(int start, int seqno) { SRM_Event *se = new SRM_Event(seqno, SRM_DATA, start); node_[start].send(se); } Interface_List* Star::oif(int node, int iif=SRM_NOIF) { int i; Interface_List *ilist = new Interface_List; /* Make a list with every node except myself */ for (i = 0; i < topology->idx(); i ++) { if (i != node && i != iif) { ilist->append(i); } } return (ilist); } /* * Distance of source to cluster = D_ */ double Star::backoff(int id) { double rtt = topology->delay(id, 0); double rbackoff; double p = Random::uniform(0.0, 1.0); static int bin = 0; int copies = c_; int size = topology->idx(); if (p <= copies * 1./size) { rbackoff = Random::uniform(0.0, alpha_); bin ++; } else { rbackoff = Random::uniform(beta_, 1.0 + beta_); } return (rtt * (det_ + rand_ * rbackoff)); } #ifdef SRM_BIMODAL double BTree::backoff(int dst) { double height = floor(log(dst)/log(2)); double D = topology->D(); double rtt = delay_ * height + D; double p = Random::uniform(0.0, 1.0); double rbackoff; static int bin = 0; int copies = c_; int size = topology->idx(); if (p <= copies * 1./size) { rbackoff = Random::uniform(0.0, alpha_); bin ++; } else { rbackoff = Random::uniform(1.0 + alpha_, 2.0); } return (rtt * (det_ + rand_ * rbackoff)); } #endif

srm.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ // // Copyright (c) 1997 by the University of Southern California // All rights reserved. // // Permission to use, copy, modify, and distribute this software and its // documentation in source and binary forms for non-commercial purposes // and without fee is hereby granted, provided that the above copyright // notice appear in all copies and that both the copyright notice and // this permission notice appear in supporting documentation. and that // any documentation, advertising materials, and other materials related // to such distribution and use acknowledge that the software was // developed by the University of Southern California, Information // Sciences Institute. The name of the University may not be used to // endorse or promote products derived from this software without // specific prior written permission. // // THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about // the suitability of this software for any purpose. THIS SOFTWARE IS // PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, // INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // Other copyrights might apply to parts of this software and are so // noted when applicable. // // Maintainer: Kannan Varadhan <kannan@isi.edu> // Version Date: Tue Jul 22 15:41:16 PDT 1997 // #ifndef lint static const char rcsid[] = "@(#) $Header$ (USC/ISI)"; #endif #include <stdlib.h> #include <assert.h> #include "config.h" #include "agent.h" #include "ip.h" #include "srm.h" #include "trace.h" #include "rtp.h" int hdr_srm::offset_; int hdr_asrm::offset_; static class SRMHeaderClass : public PacketHeaderClass { public: SRMHeaderClass() : PacketHeaderClass("PacketHeader/SRM", sizeof(hdr_srm)) { bind_offset(&hdr_srm::offset_); } } class_srmhdr; static class ASRMHeaderClass : public PacketHeaderClass { public: ASRMHeaderClass() : PacketHeaderClass("PacketHeader/aSRM", sizeof(hdr_asrm)) { bind_offset(&hdr_asrm::offset_); } } class_adaptive_srmhdr; static class SRMAgentClass : public TclClass { public: SRMAgentClass() : TclClass("Agent/SRM") {} TclObject* create(int, const char*const*) { return (new SRMAgent()); } } class_srm_agent; static class ASRMAgentClass : public TclClass { public: ASRMAgentClass() : TclClass("Agent/SRM/Adaptive") {} TclObject* create(int, const char*const*) { return (new ASRMAgent()); } } class_adaptive_srm_agent; SRMAgent::SRMAgent() : Agent(PT_SRM), dataCtr_(-1), sessCtr_(-1), siphash_(0), seqno_(-1), app_type_(PT_NTYPE) { sip_ = new SRMinfo(-1); bind("off_srm_", &off_srm_); bind("off_cmn_", &off_cmn_); bind("off_rtp_", &off_rtp_); bind("packetSize_", &packetSize_); bind("groupSize_", &groupSize_); bind("app_fid_", &app_fid_); } SRMAgent::~SRMAgent() { cleanup(); } int
SRMAgent::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (strcmp(argv[1], "send") == 0) { if (strcmp(argv[2], "session") == 0) { send_sess(); return TCL_OK; } if (strcmp(argv[2], "request") == 0) { int round = atoi(argv[3]); int sender = atoi(argv[4]); int msgid = atoi(argv[5]); send_ctrl(SRM_RQST, round, sender, msgid, 0); return TCL_OK; } if (strcmp(argv[2], "repair") == 0) { int round = atoi(argv[3]); int sender = atoi(argv[4]); int msgid = atoi(argv[5]); send_ctrl(SRM_REPR, round, sender, msgid, packetSize_); return TCL_OK; } tcl.resultf("%s: invalid send request %s", name_, argv[2]); return TCL_ERROR; } if (argc == 2) { if (strcmp(argv[1], "distances?") == 0) { tcl.result(""); if (sip_->sender_ >= 0) { // i.e. this agent is active for (SRMinfo* sp = sip_; sp; sp = sp->next_) { tcl.resultf("%s %d %f", tcl.result(), sp->sender_, sp->distance_); } } return TCL_OK; } if (strcmp(argv[1], "start") == 0) { start(); return TCL_OK; } } if (argc == 3) { if (strcmp(argv[1], "distance?") == 0) { int sender = atoi(argv[2]); SRMinfo* sp = get_state(sender); tcl.resultf("%lf", sp->distance_); return TCL_OK; } } return Agent::command(argc, argv); } void SRMAgent::recv(Packet* p, Handler* h) { hdr_ip* ih = (hdr_ip*) p->access(off_ip_); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); if (ih->daddr() == -1) { // Packet from local agent. Add srm headers, set dst, and fwd sh->type() = SRM_DATA; sh->sender() = addr(); sh->seqnum() = ++dataCtr_; addExtendedHeaders(p); ih->dst() = dst_; target_->recv(p, h); } else { #if 0 static char *foo[] = {"NONE", "DATA", "SESS", "RQST", "REPR"}; fprintf(stderr, "%7.4f %s %d recvd SRM_%s <%d, %d> from %d\n", Scheduler::instance().clock(), name_, addr_, foo[sh->type()], sh->sender(), sh->seqnum(), ih->src()); #endif parseExtendedHeaders(p); switch (sh->type()) { case SRM_DATA: recv_data(sh->sender(), sh->seqnum(), p->accessdata()); break; case SRM_RQST: recv_rqst(ih->saddr(), sh->round(), sh->sender(), sh->seqnum()); break; case SRM_REPR: recv_repr(sh->round(), sh->sender(), sh->seqnum(), p->accessdata()); break; case SRM_SESS: // This seqnum() is the session sequence number, // not the data packet sequence numbers seen before. recv_sess(p, sh->seqnum(), (int*) p->accessdata()); break; } Packet::free(p); } } void SRMAgent::sendmsg(int nbytes, const char* /*flags*/) { if (nbytes == -1) { printf("Error: sendmsg() for SRM should not be -1\n"); return; } // The traffic generator may have reset our payload type when it // initialized. If so, save the current payload type as app_type_, // and set type_ to PT_SRM. Use app_type_ for all app. packets // if (type_ != PT_SRM) { app_type_ = type_; type_ = PT_SRM; } size_ = nbytes; Packet *p; p = allocpkt(); hdr_ip* ih = (hdr_ip*) p->access(off_ip_); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); hdr_rtp* rh = (hdr_rtp*)p->access(off_rtp_); hdr_cmn* ch = (hdr_cmn*)p->access(off_cmn_); //hdr_cmn* ch = hdr_cmn::access(p); ch->ptype() = app_type_; ch->size() = size_; ih->flowid() = app_fid_; rh->seqno() = ++seqno_; // Add srm headers, set dst, and fwd sh->type() = SRM_DATA; sh->sender() = addr(); sh->seqnum() = ++dataCtr_; addExtendedHeaders(p); ih->dst() = dst_; target_->recv(p); } void SRMAgent::send_ctrl(int type, int round, int sender, int msgid, int size) { Packet* p = Agent::allocpkt(); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); sh->type() = type; sh->sender() = sender; sh->seqnum() = msgid; sh->round() = round; addExtendedHeaders(p); hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() = sizeof(hdr_srm) + size; target_->recv(p); } void SRMAgent::recv_data(int sender, int msgid, u_char*) { Tcl& tcl = Tcl::instance(); SRMinfo* sp = get_state(sender); if (msgid > sp->ldata_) { (void) request(sp, msgid - 1); sp->setReceived(msgid); sp->ldata_ = msgid; } else { tcl.evalf("%s recv data %d %d", name_, sender, msgid); } } void SRMAgent::recv_rqst(int requestor, int round, int sender, int msgid) { Tcl& tcl = Tcl::instance(); SRMinfo* sp = get_state(sender); if (msgid > sp->ldata_) { (void) request(sp, msgid); // request upto msgid sp->ldata_ = msgid; } else { tcl.evalf("%s recv request %d %d %d %d", name_, requestor, round, sender, msgid); } } void SRMAgent::recv_repr(int round, int sender, int msgid, u_char*) { Tcl& tcl = Tcl::instance(); SRMinfo* sp = get_state(sender); if (msgid > sp->ldata_) { (void) request(sp, msgid - 1); // request upto msgid - 1 sp->setReceived(msgid); sp->ldata_ = msgid; } else { tcl.evalf("%s recv repair %d %d %d", name_, round, sender, msgid); } // Notice that we currently make no provisions for a listener // agent to receive the data. } void SRMAgent::send_sess() { int size = (1 + groupSize_ * 4) * sizeof(int); Packet* p = Agent::allocpkt(size); hdr_srm* sh = (hdr_srm*) p->access(off_srm_); sh->type() = SRM_SESS; sh->sender() = addr(); sh->seqnum() = ++sessCtr_; addExtendedHeaders(p); int* data = (int*) p->accessdata(); *data++ = groupSize_; for (SRMinfo* sp = sip_; sp; sp = sp->next_) { *data++ = sp->sender_; *data++ = sp->ldata_; *data++ = sp->recvTime_; *data++ = sp->sendTime_; } data = (int*) p->accessdata(); data[4] = (int) (Scheduler::instance().clock()*1000); hdr_cmn* ch = (hdr_cmn*) p->access(off_cmn_); ch->size() = size+ sizeof(hdr_srm); target_->recv(p, (Handler*)NULL); } #define GET_SESSION_INFO \ sender = *data++; \ dataCnt = *data++; \ rtime = *data++; \ stime = *data++ void SRMAgent::recv_sess(Packet*, int sessCtr, int* data) { SRMinfo* sp; int sender, dataCnt, rtime, stime; int now, sentAt, sentBy; int cnt = *data++; int i; /* The first block contains the sender's own state */ GET_SESSION_INFO; if (sender == addr()) // sender's own session message return; sp = get_state(sender); if (sp->lsess_ > sessCtr) // older session message recd. return; now = (int) (Scheduler::instance().clock() * 1000); sentBy = sender; // to later compute rtt sentAt = stime; sp->lsess_ = sessCtr; sp->recvTime_ = now; sp->sendTime_ = stime; (void) request(sp, dataCnt); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; for (i = 1; i < cnt; i++) { GET_SESSION_INFO; if (sender == addr() && now) { // // This session message from sender sentBy: // vvvvv // now <=======+ sentAt // | | // stime +=======> rtime // ^^^^^ // Earlier session message sent by ``this'' agent // int rtt = (now - sentAt) + (rtime - stime); sp = get_state(sentBy); sp->distance_ = (double) rtt / 2 / 1000; #if 0 fprintf(stderr, "%7.4f %s compute distance to %d: %f\n", Scheduler::instance().clock(), name_, sentBy, sp->distance_); #endif continue; } sp = get_state(sender); (void) request(sp, dataCnt); if (sp->ldata_ < dataCnt) sp->ldata_ = dataCnt; } }

tbf.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) Xerox Corporation 1997. All rights reserved. * * License is granted to copy, to use, and to make and to use derivative * works for research and evaluation purposes, provided that Xerox is * acknowledged in all documentation pertaining to any such copy or * derivative work. Xerox grants no other licenses expressed or * implied. The Xerox trade name should not be used in any advertising * without its written permission. * * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without * express or implied warranty of any kind. * * These notices must be retained in any copies of any part of this * software. */ /* Token Bucket filter which has 3 parameters : a. Token Generation rate b. Token bucket depth c. Max. Queue Length (a finite length would allow this to be used as policer as packets are dropped after queue gets full) */ #include "connector.h" #include "packet.h" #include "queue.h" #include "tbf.h" TBF::TBF() :tokens_(0),tbf_timer_(this), init_(1) { q_=new PacketQueue(); bind_bw("rate_",&rate_); bind("bucket_",&bucket_); bind("qlen_",&qlen_); } TBF::~TBF() { if (q_->length() != 0) { //Clear all pending timers tbf_timer_.cancel(); //Free up the packetqueue for (Packet *p=q_->head();p!=0;p=p->next_) Packet::free(p); } delete q_; } void
TBF::recv(Packet *p, Handler *) { //start with a full bucket if (init_) { tokens_=bucket_; lastupdatetime_ = Scheduler::instance().clock(); init_=0; } hdr_cmn *ch=(hdr_cmn *)p->access(off_cmn_); //enque packets appropriately if a non-zero q already exists if (q_->length() !=0) { if (q_->length() < qlen_) { q_->enque(p); return; } drop(p); return; } double tok; tok = getupdatedtokens(); int pktsize = ch->size()<<3; if (tokens_ >=pktsize) { target_->recv(p); tokens_-=pktsize; } else { if (qlen_!=0) { q_->enque(p); tbf_timer_.resched((pktsize-tokens_)/rate_); } else { drop(p); } } } double TBF::getupdatedtokens(void) { double now=Scheduler::instance().clock(); tokens_ += (now-lastupdatetime_)*rate_; if (tokens_ > bucket_) tokens_=bucket_; lastupdatetime_ = Scheduler::instance().clock(); return tokens_; } void TBF::timeout(int) { if (q_->length() == 0) { fprintf (stderr,"ERROR in tbf\n"); abort(); } Packet *p=q_->deque(); double tok; tok = getupdatedtokens(); hdr_cmn *ch=(hdr_cmn *)p->access(off_cmn_); int pktsize = ch->size()<<3; //We simply send the packet here without checking if we have enough tokens //because the timer is supposed to fire at the right time target_->recv(p); tokens_-=pktsize; if (q_->length() !=0 ) { p=q_->head(); hdr_cmn *ch=(hdr_cmn *)p->access(off_cmn_); pktsize = ch->size()<<3; tbf_timer_.resched((pktsize-tokens_)/rate_); } } void TBF_Timer::expire(Event* /*e*/) { tbf_->timeout(0); } static class TBFClass : public TclClass { public: TBFClass() : TclClass ("TBF") {} TclObject* create(int,const char*const*) { return (new TBF()); } }class_tbf;

tclAppInit.cc


/* * tclAppInit.c -- * * Provides a default version of the main program and Tcl_AppInit * procedure for Tcl applications (without Tk). * * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclAppInit.c 1.17 96/03/26 12:45:29 */ #include "config.h" extern void init_misc(void); extern EmbeddedTcl et_ns_lib; extern EmbeddedTcl et_ns_ptypes; /* MSVC requires this global var declaration to be outside of 'extern "C"' */ #ifdef MEMDEBUG_SIMULATIONS #include "mem-trace.h" MemTrace *globalMemTrace; #endif extern "C" { /* * The following variable is a special hack that is needed in order for * Sun shared libraries to be used for Tcl. */ #ifdef TCL_TEST EXTERN int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); #endif /* TCL_TEST */ /* *---------------------------------------------------------------------- * * main -- * * This is the main program for the application. * * Results: * None: Tcl_Main never returns here, so this procedure never * returns either. * * Side effects: * Whatever the application does. * *---------------------------------------------------------------------- */ int main(int argc, char **argv) { Tcl_Main(argc, argv, Tcl_AppInit); return 0; /* Needed only to prevent compiler warning. */ } /* *---------------------------------------------------------------------- * * Tcl_AppInit -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in interp->result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ int Tcl_AppInit(Tcl_Interp *interp) { #ifdef MEMDEBUG_SIMULATIONS extern MemTrace *globalMemTrace; globalMemTrace = new MemTrace; #endif if (Tcl_Init(interp) == TCL_ERROR || Otcl_Init(interp) == TCL_ERROR) return TCL_ERROR; #ifdef HAVE_LIBTCLDBG extern int Tcldbg_Init(Tcl_Interp *); // hackorama if (Tcldbg_Init(interp) == TCL_ERROR) { return TCL_ERROR; } #endif Tcl_SetVar(interp, "tcl_rcFileName", "~/.ns.tcl", TCL_GLOBAL_ONLY); Tcl::init(interp, "ns"); et_ns_ptypes.load(); et_ns_lib.load(); init_misc(); #ifdef TCL_TEST if (Tcltest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, (Tcl_PackageInitProc *) NULL); #endif /* TCL_TEST */ return TCL_OK; } #ifndef WIN32 void abort() { Tcl& tcl = Tcl::instance(); tcl.evalc("[Simulator instance] flush-trace"); #ifdef abort #undef abort abort(); #else exit(1); #endif /*abort*/ /*NOTREACHED*/ } #endif }

tcp-abs.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* tcp-abs.cc * Copyright (C) 1999 by USC/ISI * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, advertising * materials, and other materials related to such distribution and use * acknowledge that the software was developed by the University of * Southern California, Information Sciences Institute. The name of the * University may not be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Contributed by Polly Huang (USC/ISI), http://www-scf.usc.edu/~bhuang * @(#) $Header$ (LBL)"; */ #include "ip.h" #include "tcp.h" #include "tcp-abs.h" //AbsTcp AbsTcpAgent::AbsTcpAgent() : Agent(PT_TCP), rtt_(0), current_(NULL),offset_(0), seqno_lb_(-1), connection_size_(0), timer_(this), rescheduled_(0) { size_ = 1000; } void
AbsTcpAgent::timeout() { if (rescheduled_ == 0 && current_->transition_[offset_]!= current_->transition_[0]) { set_timer(2*rtt_); rescheduled_ = 1; } else { rescheduled_ = 0; seqno_lb_ += current_->batch_size_; if (current_->drop_[offset_] == NULL) { printf("Error: This fsm can't handle multi losses per connection\n"); exit(0); } current_ = current_->drop_[offset_]; send_batch(); } } void AbsTcpAgent::sendmsg(int pktcnt) { connection_size_ = pktcnt; start(); } void AbsTcpAgent::advanceby(int pktcnt) { connection_size_ = pktcnt; start(); } void AbsTcpAgent::start() { //printf("starting fsm tcp, %d\n", connection_size_); send_batch(); } void AbsTcpAgent::send_batch() { int seqno = seqno_lb_; offset_ = 0; //printf("sending batch, %d\n", current_->batch_size_); for (int i=0; i<current_->batch_size_ && seqno < connection_size_-1; i++) { seqno++; output(seqno); } if (seqno == connection_size_-1) { finish(); } else if (seqno < connection_size_-1) { if (current_->drop_[offset_] == NULL) { printf("Error: current fsm can't handle this tcp connection flow id %d (possibly too long)\n", fid_); exit(0); } //printf("start timer %d\n", current_->transition_[offset_]); if (current_->transition_[offset_] == 0) { current_ = current_->drop_[offset_]; send_batch(); } else if (current_->transition_[offset_] == RTT) { set_timer(rtt_); } else if (current_->transition_[offset_] == TIMEOUT) { set_timer(rtt_ * 3); } else { printf("Error: weird transition timer\n"); exit(0); } } else { printf("Error: sending more than %d packets\n", connection_size_); exit(0); } } void AbsTcpAgent::drop(int seqno) { //printf("dropped: %d\n", seqno); if (offset_ != 0) { printf("Error: Sorry, can't handle multiple drops per batch\n"); exit(0); } offset_ = seqno - seqno_lb_; connection_size_++; } void AbsTcpAgent::finish() { //printf("finish: sent %d\n", seqno_lb_+1); cancel_timer(); } void AbsTcpAgent::output(int seqno) { Packet* p = allocpkt(); hdr_tcp *tcph = hdr_tcp::access(p); tcph->seqno() = seqno; send(p, 0); } void AbsTcpAgent::recv(Packet* pkt, Handler*) { Packet::free(pkt); } int AbsTcpAgent::command(int argc, const char*const* argv) { if (argc == 3 ) { if (strcmp(argv[1], "rtt") == 0) { rtt_ = atof(argv[2]); //printf("rtt %f\n", rtt_); return (TCL_OK); } if (strcmp(argv[1], "advance") == 0) { advanceby(atoi(argv[2])); return (TCL_OK); } if (strcmp(argv[1], "advanceby") == 0) { advanceby(atoi(argv[2])); return (TCL_OK); } if(strcmp(argv[1], "print-stats") == 0) { // xxx: works best if invoked on a new fsm // (otherwise you don't get the whole thing). int n = atoi(argv[2]); if (n < 0 || n >= 17) return TCL_ERROR; FSM::print_FSM_stats(current_, n); return (TCL_OK); }; } else if (argc == 2) { if (strcmp(argv[1], "print") == 0) { // xxx: works best if invoked on a new fsm // (otherwise you don't get the whole thing). FSM::print_FSM(current_); return (TCL_OK); }; }; return (Agent::command(argc, argv)); } void AbsTcpTimer::expire(Event*) { a_->timeout(); } //AbsTCP/TahoeAck static class AbsTcpTahoeAckClass : public TclClass { public: AbsTcpTahoeAckClass() : TclClass("Agent/AbsTCP/TahoeAck") {} TclObject* create(int, const char*const*) { return (new AbsTcpTahoeAckAgent()); } } class_abstcptahoeack; AbsTcpTahoeAckAgent::AbsTcpTahoeAckAgent() : AbsTcpAgent() { size_ = 1000; current_ = TahoeAckFSM::instance().start_state(); DropTargetAgent::instance().insert_tcp(this); } //AbsTCP/RenoAck static class AbsTcpRenoAckClass : public TclClass { public: AbsTcpRenoAckClass() : TclClass("Agent/AbsTCP/RenoAck") {} TclObject* create(int, const char*const*) { return (new AbsTcpRenoAckAgent()); } } class_abstcprenoack; AbsTcpRenoAckAgent::AbsTcpRenoAckAgent() : AbsTcpAgent() { size_ = 1000; current_ = RenoAckFSM::instance().start_state(); DropTargetAgent::instance().insert_tcp(this); } //AbsTCP/TahoeDelAck static class AbsTcpTahoeDelAckClass : public TclClass { public: AbsTcpTahoeDelAckClass() : TclClass("Agent/AbsTCP/TahoeDelAck") {} TclObject* create(int, const char*const*) { return (new AbsTcpTahoeDelAckAgent()); } } class_abstcptahoedelack; AbsTcpTahoeDelAckAgent::AbsTcpTahoeDelAckAgent() : AbsTcpAgent() { size_ = 1000; current_ = TahoeDelAckFSM::instance().start_state(); DropTargetAgent::instance().insert_tcp(this); } //AbsTCP/RenoDelAck static class AbsTcpRenoDelAckClass : public TclClass { public: AbsTcpRenoDelAckClass() : TclClass("Agent/AbsTCP/RenoDelAck") {} TclObject* create(int, const char*const*) { return (new AbsTcpRenoDelAckAgent()); } } class_abstcprenodelack; AbsTcpRenoDelAckAgent::AbsTcpRenoDelAckAgent() : AbsTcpAgent() { size_ = 1000; current_ = RenoDelAckFSM::instance().start_state(); DropTargetAgent::instance().insert_tcp(this); } //AbsTcpSink static class AbsTcpSinkClass : public TclClass { public: AbsTcpSinkClass() : TclClass("Agent/AbsTCPSink") {} TclObject* create(int, const char*const*) { return (new AbsTcpSink()); } } class_abstcpsink; AbsTcpSink::AbsTcpSink() : Agent(PT_ACK) { size_ = 40; } void AbsTcpSink::recv(Packet* pkt, Handler*) { Packet* p = allocpkt(); send(p, 0); Packet::free(pkt); } static class AbsDelAckSinkClass : public TclClass { public: AbsDelAckSinkClass() : TclClass("Agent/AbsTCPSink/DelAck") {} TclObject* create(int, const char*const*) { return (new AbsDelAckSink()); } } class_absdelacksink; AbsDelAckSink::AbsDelAckSink() : AbsTcpSink(), delay_timer_(this) { size_ = 40; interval_ = 0.1; } void AbsDelAckSink::recv(Packet* pkt, Handler*) { if (delay_timer_.status() != TIMER_PENDING) { delay_timer_.resched(interval_); } else { delay_timer_.cancel(); Packet* p = allocpkt(); send(p, 0); } Packet::free(pkt); } void AbsDelAckSink::timeout() { /* * The timer expired so we ACK the last packet seen. * (shouldn't this check for a particular time out#? -kf) */ Packet* p = allocpkt(); send(p, 0); } void AbsDelayTimer::expire(Event */*e*/) { a_->timeout(); } //Special drop target agent DropTargetAgent* DropTargetAgent::instance_; static class DropTargetClass : public TclClass { public: DropTargetClass() : TclClass("DropTargetAgent") {} TclObject* create(int, const char*const*) { return (new DropTargetAgent()); } } class_droptarget; DropTargetAgent::DropTargetAgent(): Connector(), dropper_list_(NULL) { instance_ = this; } void DropTargetAgent::recv(Packet* pkt, Handler*) { Dropper* tmp = dropper_list_; hdr_tcp *tcph = hdr_tcp::access(pkt); hdr_ip *iph = hdr_ip::access(pkt); //printf("flow %d dropping seqno %d\n", iph->flowid(),tcph->seqno()); while(tmp != NULL) { if(tmp->agent_->flowid() == iph->flowid()) tmp->agent_->drop(tcph->seqno()); tmp = tmp->next_; } Packet::free(pkt); } void DropTargetAgent::insert_tcp(AbsTcpAgent* tcp) { Dropper* dppr = new Dropper; dppr->agent_=tcp; dppr->next_ = dropper_list_; dropper_list_ = dppr; }

tcp-asym-fs.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by the Daedalus Research Group, U.C.Berkeley * http://daedalus.cs.berkeley.edu */ /* * tcp-asym-fs: TCP mods for asymmetric networks (tcp-asym) with fast start * (tcp-fs). * * Contributed by Venkat Padmanabhan (padmanab@cs.berkeley.edu), * Daedalus Research Group, U.C.Berkeley */ #include "tcp-asym.h" #include "tcp-fs.h" /* TCP-FS with NewReno */ class NewRenoTcpAsymFsAgent : public NewRenoTcpAsymAgent, public NewRenoTcpFsAgent { public: NewRenoTcpAsymFsAgent() : NewRenoTcpAsymAgent(), NewRenoTcpFsAgent() {count_bytes_acked_= 1;} /* helper functions */ virtual void output_helper(Packet* pkt) {NewRenoTcpAsymAgent::output_helper(pkt); NewRenoTcpFsAgent::output_helper(pkt);} virtual void recv_helper(Packet* pkt) {NewRenoTcpAsymAgent::recv_helper(pkt); NewRenoTcpFsAgent::recv_helper(pkt);} virtual void send_helper(int maxburst) {NewRenoTcpFsAgent::send_helper(maxburst);} virtual void send_idle_helper() {NewRenoTcpFsAgent::send_idle_helper();} virtual void recv_newack_helper(Packet* pkt) {printf("count_bytes_acked_=%d\n", count_bytes_acked_); NewRenoTcpFsAgent::recv_newack_helper(pkt); NewRenoTcpAsymAgent::t_exact_srtt_ = NewRenoTcpFsAgent::t_exact_srtt_;} virtual void partialnewack_helper(Packet* pkt) {NewRenoTcpFsAgent::partialnewack_helper(pkt);} virtual void set_rtx_timer() {NewRenoTcpFsAgent::set_rtx_timer();} virtual void timeout_nonrtx(int tno) {NewRenoTcpFsAgent::timeout_nonrtx(tno);} virtual void timeout_nonrtx_helper(int tno) {NewRenoTcpFsAgent::timeout_nonrtx_helper(tno);} }; static class NewRenoTcpAsymFsClass : public TclClass { public: NewRenoTcpAsymFsClass() : TclClass("Agent/TCP/Newreno/Asym/FS") {} TclObject* create(int, const char*const*) { return (new NewRenoTcpAsymFsAgent()); } } class_newrenotcpasymfs;

tcp-asym-sink.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by the Daedalus Research Group, U.C.Berkeley * http://daedalus.cs.berkeley.edu * * @(#) $Header: */ /* * tcp-asym includes modifications to several flavors of TCP to enhance * performance over asymmetric networks, where the ack channel is * constrained. Types of asymmetry we have studied and used these mods * include bandwidth asymmetry and latency asymmetry (where variable * latencies cause problems to TCP, e.g., in packet radio networks. * The receiver-side code in this file is derived from the regular * TCP sink code. The main additional functionality is that the sink responds * to ECN by performing ack congestion control, i.e. it multiplicatively backs * off the frequency with which it sends acks (up to a limit). For each * subsequent round-trip period during which it does not receive an ECN, * it gradually increases the frequency of acks (up to a maximum of 1 * per data packet). * * For questions/comments, please contact: * Venkata N. Padmanabhan (padmanab@cs.berkeley.edu) * http://www.cs.berkeley.edu/~padmanab */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (UCB)"; #endif #include "template.h" #include "flags.h" #include "tcp-sink.h" #include "tcp-asym.h" class TcpAsymSink : public DelAckSink { public: TcpAsymSink(Acker*); virtual void recv(Packet* pkt, Handler* h); virtual void timeout(int tno); protected: virtual void add_to_ack(Packet* pkt); int delackcount_; /* the number of consecutive packets that have not been acked yet */ int maxdelack_; /* the maximum extent to which acks can be delayed */ int delackfactor_; /* the dynamically varying limit on the extent to which acks can be delayed */ int delacklim_; /* limit on the extent of del ack based on the sender's window */ double ts_ecn_; /* the time when an ECN was received last */ double ts_decrease_; /* the time when delackfactor_ was decreased last */ double highest_ts_echo_;/* the highest timestamp echoed by the peer */ }; static class TcpAsymSinkClass : public TclClass { public: TcpAsymSinkClass() : TclClass("Agent/TCPSink/Asym") {} TclObject* create(int, const char*const*) { return (new TcpAsymSink(new Acker)); } } class_tcpasymsink; TcpAsymSink::TcpAsymSink(Acker* acker) : DelAckSink(acker), delackcount_(0), delackfactor_(1), delacklim_(0), ts_ecn_(0), ts_decrease_(0) { bind("maxdelack_", &maxdelack_); } /* Add fields to the ack. Not needed? */ void
TcpAsymSink::add_to_ack(Packet* pkt) { hdr_tcpasym *tha = hdr_tcpasym::access(pkt); tha->ackcount() = delackcount_; } void TcpAsymSink::recv(Packet* pkt, Handler*) { int olddelackfactor = delackfactor_; int olddelacklim = delacklim_; int max_sender_can_send = 0; hdr_flags *fh = hdr_flags::access(pkt); hdr_tcp *th = hdr_tcp::access(pkt); hdr_tcpasym *tha = hdr_tcpasym::access(pkt); double now = Scheduler::instance().clock(); int numBytes = hdr_cmn::access(pkt)->size(); acker_->update_ts(th->seqno(),th->ts()); acker_->update(th->seqno(), numBytes); #if 0 // johnh int numToDeliver; /* XXX if the #if 0 is removed, delete the call to acker_->update() above */ numToDeliver = acker_->update(th->seqno(), numBytes); if (numToDeliver) recvBytes(numToDeliver); #endif /* 0 */ /* determine the highest timestamp the sender has echoed */ highest_ts_echo_ = max(highest_ts_echo_, th->ts_echo()); /* * if we receive an ECN and haven't received one in the past * round-trip, double delackfactor_ (and consequently halve * the frequency of acks) subject to a maximum */ if (fh->ecnecho() && highest_ts_echo_ >= ts_ecn_) { delackfactor_ = min(2*delackfactor_, maxdelack_); ts_ecn_ = now; } /* * else if we haven't received an ECN in the past round trip and * haven't (linearly) decreased delackfactor_ in the past round * trip, we decrease delackfactor_ by 1 (and consequently increase * the frequency of acks) subject to a minimum */ else if (highest_ts_echo_ >= ts_ecn_ && highest_ts_echo_ >= ts_decrease_) { delackfactor_ = max(delackfactor_ - 1, 1); ts_decrease_ = now; } /* * if this is the next packet in sequence, we can consider delaying the ack. * Set delacklim_ based on how much data the sender can send if we don't * send back any more acks. The idea is to avoid stalling the sender because * of a lack of acks. */ if (th->seqno() == acker_->Seqno()) { max_sender_can_send = (int) min(tha->win()+acker_->Seqno()-tha->highest_ack(), tha->max_left_to_send()); /* XXXX we use a safety factor 2 */ delacklim_ = min(maxdelack_, max_sender_can_send/2); } else delacklim_ = 0; if (delackfactor_ < delacklim_) delacklim_ = delackfactor_; /* * Log values of variables of interest. Since this is the only place * where this is done, we decided against using a more general method * as used for logging TCP sender state variables. */ if (channel_ && (olddelackfactor != delackfactor_ || olddelacklim != delacklim_)) { char wrk[500]; int n; /* we print src and dst in reverse order to conform to sender side */ sprintf(wrk, "time: %-6.3f saddr: %-2d sport: %-2d daddr:" " %-2d dport: %-2d dafactor: %2d dalim: %2d max_scs:" " %4d win: %4d\n", now, addr(), port(), daddr(), dport(), delackfactor_, delacklim_,max_sender_can_send, tha->win()); n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; (void)Tcl_Write(channel_, wrk, n+1); wrk[n] = 0; } delackcount_++; /* check if we have waited long enough that we should send an ack */ if (delackcount_ < delacklim_) { /* it is not yet time to send an ack */ /* if the delayed ack timer is not set, set it now */ if (!(delay_timer_.status() == TIMER_PENDING)) { save_ = pkt; delay_timer_.resched(interval_); } else { hdr_tcp *sth = hdr_tcp::access(save_); /* save the pkt with the more recent timestamp */ if (th->ts() > sth->ts()) { Packet::free(save_); save_ = pkt; } } return; } else { /* send back an ack now */ if (delay_timer_.status() == TIMER_PENDING) { delay_timer_.cancel(); Packet::free(save_); save_ = 0; } hdr_flags* hf = hdr_flags::access(pkt); hf->ect() = 1; ack(pkt); delackcount_ = 0; Packet::free(pkt); } } void TcpAsymSink::timeout(int /*tno*/) { /* * The timer expired so we ACK the last packet seen. */ Packet* pkt = save_; delackcount_ = 0; ack(pkt); save_ = 0; Packet::free(pkt); }

tcp-asym.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Daedalus Research * Group at the University of California Berkeley. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Contributed by the Daedalus Research Group, U.C.Berkeley * http://daedalus.cs.berkeley.edu * * @(#) $Header: */ /* * tcp-asym includes modifications to several flavors of TCP to enhance * performance over asymmetric networks, where the ack channel is * constrained. Types of asymmetry we have studied and used these mods * include bandwidth asymmetry and latency asymmetry (where variable * latencies cause problems to TCP, e.g., in packet radio networks. * The sender-side modifications in this file are structured as helper * functions that are invoked from various points in the TCP code. The main * additional functionality is (a) the sender increases its congestion window * in proportion to the amount of data acked rather than the number of acks * received, (b) it breaks up potentially large bursts into smaller ones * when acks are few and far between by rate-based pacing, and * (c) it copies the ecn_to_echo_ bit from acks into subsequent data packets, * using which the sink can perform ack congestion control (tcp-asym-sink.cc). * The tcp-asym source is usually used in conjunction with a tcp-asym sink, or * with a router/end-host implementing ack filtering (semantic-packetqueue.cc). * * For questions/comments, please contact: * Venkata N. Padmanabhan (padmanab@cs.berkeley.edu) * http://www.cs.berkeley.edu/~padmanab */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (UCB)"; #endif #include "tcp-asym.h" int hdr_tcpasym::offset_; static class TCPAHeaderClass : public PacketHeaderClass { public: TCPAHeaderClass() : PacketHeaderClass("PacketHeader/TCPA", sizeof(hdr_tcpasym)) { bind_offset(&hdr_tcpasym::offset_); } } class_tcpahdr; static class TcpAsymClass : public TclClass { public: TcpAsymClass() : TclClass("Agent/TCP/Asym") {} TclObject* create(int, const char*const*) { return (new TcpAsymAgent()); } } class_tcpasym; TcpAsymAgent::TcpAsymAgent() : TcpAgent(), ecn_to_echo_(0), t_exact_srtt_(0) { /* bind("exact_srtt_", &t_exact_srtt_);*/ bind("g_", &g_); /* bind("avg_win_", &avg_win_);*/ /* bind("damp_", &damp_);*/ } static class TcpRenoAsymClass : public TclClass { public: TcpRenoAsymClass() : TclClass("Agent/TCP/Reno/Asym") {} TclObject* create(int, const char*const*) { return (new TcpRenoAsymAgent()); } } class_tcprenoasym; static class NewRenoTcpAsymClass : public TclClass { public: NewRenoTcpAsymClass() : TclClass("Agent/TCP/Newreno/Asym") {} TclObject* create(int, const char*const*) { return (new NewRenoTcpAsymAgent()); } } class_newrenotcpasym; /* The helper functions */ /* fill in the TCP asym header before packet is sent out */ void
TcpAsymAgent::output_helper(Packet* p) { hdr_tcpasym *tcpha = hdr_tcpasym::access(p); hdr_flags *flagsh = hdr_flags::access(p); tcpha->win() = min(highest_ack_+window(), curseq_) - t_seqno_; tcpha->highest_ack() = highest_ack_; tcpha->max_left_to_send() = curseq_ - highest_ack_; /* XXXX not needed? */ flagsh->ecnecho() = ecn_to_echo_; ecn_to_echo_ = 0; } /* schedule the next burst of data (of size at most maxburst) */ void TcpAsymAgent::send_helper(int maxburst) { /* * If there is still data to be sent and there is space in the * window, set a timer to schedule the next burst. Note that * we wouldn't get here if TCP_TIMER_BURSTSEND were pending, * so we do not need an explicit check here. */ if (t_seqno_ <= highest_ack_ + window() && t_seqno_ < curseq_) { burstsnd_timer_.resched(t_exact_srtt_*maxburst/window()); } } /* check if the received ack has an ECN that needs to be echoed back to the sink */ void TcpAsymAgent::recv_helper(Packet *pkt) { if (hdr_flags::access(pkt)->ce()) ecn_to_echo_ = 1; } /* open cwnd in proportion to the amount of data acked */ void TcpAsymAgent::recv_newack_helper(Packet *pkt) { int i; hdr_tcp *tcph = hdr_tcp::access(pkt); int ackcount = tcph->seqno() - last_ack_; double tao = Scheduler::instance().clock() - tcph->ts_echo(); newack(pkt); /* update our fine-grained estimate of the smoothed RTT */ if (t_exact_srtt_ != 0) t_exact_srtt_ = g_*tao + (1-g_)*t_exact_srtt_; else t_exact_srtt_ = tao; /* avg_win_ = g_*window() + (1-g_)*avg_win_;*/ /* grow cwnd */ for (i=0; i<ackcount; i++) opencwnd(); /* if the connection is done, call finish() */ if ((highest_ack_ >= curseq_-1) && !closed_) { closed_ = 1; finish(); } } /* Print out if tcp-asym-specific variables have been modified */ void TcpAsymAgent::traceVar(TracedVar* v) { Scheduler& s = Scheduler::instance(); char wrk[500]; double curtime = &s ? s.clock() : 0; if (!strcmp(v->name(), "exact_srtt_")) sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f", curtime, addr(), port(), daddr(), dport(), v->name(), double(*((TracedDouble*) v))); else if (!strcmp(v->name(), "avg_win_")) sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f", curtime, addr(), port(), daddr(), dport(), v->name(), double(*((TracedDouble*) v))); else { TcpAgent::traceVar(v); return; } int n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; if (channel_) (void)Tcl_Write(channel_, wrk, n+1); wrk[n] = 0; return; } /* Print out all the traced variables whenever any one is changed */ void TcpAsymAgent::traceAll() { double curtime; Scheduler& s = Scheduler::instance(); char wrk[500]; int n; TcpAgent::traceAll(); curtime = &s ? s.clock() : 0; sprintf(wrk, "time: %-8.5f saddr: %-2d sport: %-2d daddr: %-2d dport:" " %-2d exact_srtt %d", curtime, addr(), port(), daddr(), dport(), (int(t_exact_srtt_))); n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; if (channel_) (void)Tcl_Write(channel_, wrk, n+1); wrk[n] = 0; return; }

tcp-fack.cc


/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * Copyright (c) 1990, 1997 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Lawrence Berkeley Laboratory, * Berkeley, CA. The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint static const char rcsid[] = "@(#) $Header$ (PSC)"; #endif #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include "ip.h" #include "tcp.h" #include "flags.h" #include "scoreboard.h" #include "random.h" #include "tcp-fack.h" #include "template.h" static class FackTcpClass : public TclClass { public: FackTcpClass() : TclClass("Agent/TCP/Fack") {} TclObject* create(int, const char*const*) { return (new FackTcpAgent()); } } class_fack; FackTcpAgent::FackTcpAgent() : timeout_(FALSE), wintrim_(0), wintrimmult_(.5), rampdown_(0), fack_(-1), retran_data_(0), ss_div4_(0) // What about fastrecov_ and scb_ { bind_bool("ss-div4_", &ss_div4_); bind_bool("rampdown_", &rampdown_); } int
FackTcpAgent::window() { int win; win = int((cwnd_ < wnd_ ? (double) cwnd_ : (double) wnd_) + wintrim_); return (win); } void FackTcpAgent::reset () { scb_.ClearScoreBoard(); TcpAgent::reset (); } /* * Process a dupack. */ void FackTcpAgent::oldack(Packet* pkt) { hdr_tcp *tcph = (hdr_tcp*)pkt->access(off_tcp_); last_ack_ = tcph->seqno(); highest_ack_ = last_ack_; fack_ = max(fack_,highest_ack_); /* * There are conditions under which certain versions of TCP (e.g., tcp-fs) * retract maxseq_. The following line of code helps in those cases. For * versions of TCP, it is a NOP. */ maxseq_ = max(maxseq_, highest_ack_); if (t_seqno_ < last_ack_ + 1) t_seqno_ = last_ack_ + 1; newtimer(pkt); if (rtt_active_ && tcph->seqno() >= rtt_seq_) { rtt_active_ = 0; t_backoff_ = 1; } /* with timestamp option */ double tao = Scheduler::instance().clock() - tcph->ts_echo(); rtt_update(tao); /* update average window */ awnd_ *= 1.0 - wnd_th_; awnd_ += wnd_th_ * cwnd_; /* if the connection is done, call finish() */ if ((highest_ack_ >= curseq_-1) && !closed_) { closed_ = 1; finish(); } } int FackTcpAgent::maxsack(Packet *pkt) { hdr_tcp *tcph = (hdr_tcp*)pkt->access(off_tcp_); int maxsack=-1, sack_index; for (sack_index=0; sack_index < tcph->sa_length(); sack_index++) { if (tcph->sa_right(sack_index) > maxsack) maxsack = tcph->sa_right(sack_index); } return (maxsack-1); } void FackTcpAgent::recv_newack_helper(Packet *pkt) { newack(pkt); opencwnd(); /* if the connection is done, call finish() */ if ((highest_ack_ >= curseq_-1) && !closed_) { closed_ = 1; finish(); } } void FackTcpAgent::recv(Packet *pkt, Handler*) { hdr_tcp *tcph = (hdr_tcp*)pkt->access(off_tcp_); int ms; #ifdef notdef if (pkt->type_ != PT_ACK) { Tcl::instance().evalf("%s error \"received non-ack\"", name()); Packet::free(pkt); return; } #endif ts_peer_ = tcph->ts(); if (((hdr_flags*)pkt->access(off_flags_))->ecnecho() && ecn_) ecn(tcph->seqno()); recv_helper(pkt); if (!fastrecov_) { // Not in fast recovery if ((int)tcph->seqno() > last_ack_ && tcph->sa_length() == 0) { /* * regular ACK not in fast recovery... normal */ recv_newack_helper(pkt); fack_ = last_ack_; timeout_ = FALSE; scb_.ClearScoreBoard(); retran_data_ = 0; wintrim_ = 0; } else if ((int)tcph->seqno() < last_ack_) { // Do nothing; ack may have been misordered } else { retran_data_ -= scb_.UpdateScoreBoard (highest_ack_, tcph); oldack(pkt); ms = maxsack(pkt); if (ms > fack_) fack_ = ms; if (fack_ >= t_seqno_) t_seqno_ = fack_ + 1; dupacks_ = (fack_ - last_ack_) - 1; /* * a duplicate ACK */ if (dupacks_ >= NUMDUPACKS) { /* * Assume we dropped just one packet. * Retransmit last ack + 1 * and try to resume the sequence. */ recover_ = t_seqno_; last_cwnd_action_ = CWND_ACTION_DUPACK; if ((ss_div4_ == 1) && (cwnd_ <= ssthresh_ + .5)) { cwnd_ /= 2; wintrimmult_ = .75; } else { wintrimmult_ = .5; } slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART); if (rampdown_) { wintrim_ = (t_seqno_ - fack_ - 1) * wintrimmult_; } reset_rtx_timer(1,0); fastrecov_ = TRUE; scb_.MarkRetran (last_ack_+1, t_seqno_); retran_data_++; output(last_ack_ + 1, TCP_REASON_DUPACK); } } if (dupacks_ == 0) send_much(FALSE, 0, maxburst_); } else { // we are in fast recovery oldack(pkt); ms = maxsack(pkt); if (ms > fack_) { if (rampdown_) { wintrim_ -= ((float)ms - (float)fack_)* wintrimmult_; if (wintrim_< 0) wintrim_ = 0; } fack_ = ms; } if (fack_ >= t_seqno_) t_seqno_ = fack_ + 1; retran_data_ -= scb_.UpdateScoreBoard (highest_ack_, tcph); // If the retransmission was lost again, timeout_ forced to TRUE // if timeout_ TRUE, this shuts off send() timeout_ |= scb_.CheckSndNxt (tcph); opencwnd(); if (retran_data_ < 0) { printf("Error, retran_data_ < 0"); } if ((int)tcph->sa_length() == 0 && (last_ack_ >= recover_)) { // No SACK blocks indicates fast recovery is over fastrecov_ = FALSE; timeout_ = FALSE; scb_.ClearScoreBoard(); retran_data_ = 0; wintrim_ = 0; dupacks_ = 0; } send_much(FALSE, 0, maxburst_); } Packet::free(pkt); #ifdef notyet if (trace_) plot(); #endif } void FackTcpAgent::timeout(int tno) { if (tno == TCP_TIMER_RTX) { if (highest_ack_ == maxseq_ && !slow_start_restart_) { /* * TCP option: * If no outstanding data, then don't do anything. */ return; }; // Do not clear fastrecov_ or alter recover_ variable timeout_ = FALSE; if (highest_ack_ > last_ack_) last_ack_ = highest_ack_; #ifdef DEBUGSACK1A printf ("timeout. highest_ack: %d seqno: %d\n", highest_ack_, t_seqno_); #endif retran_data_ = 0; last_cwnd_action_ = CWND_ACTION_TIMEOUT; /* if there is no outstanding data, don't cut down ssthresh_ */ if (highest_ack_ == maxseq_ && restart_bugfix_) slowdown(CLOSE_CWND_INIT); else { // close down to 1 segment slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART); } scb_.ClearScoreBoard(); /* if there is no outstanding data, don't back off rtx timer */ if (highest_ack_ == maxseq_) reset_rtx_timer(TCP_REASON_TIMEOUT,0); else reset_rtx_timer(TCP_REASON_TIMEOUT,1); fack_ = last_ack_; t_seqno_ = last_ack_ + 1; send_much(0, TCP_REASON_TIMEOUT); } else { TcpAgent::timeout(tno); } } void FackTcpAgent::send_much(int force, int reason, int maxburst) { register int found, npacket = 0; send_idle_helper(); int win = window(); int xmit_seqno; if (!force && delsnd_timer_.status() == TIMER_PENDING) return; /* * If TCP_TIMER_BURSTSND is pending, cancel it. The timer is * set again, if necessary, after the maxburst pakts have been * sent out. */ if (burstsnd_timer_.status() == TIMER_PENDING) burstsnd_timer_.cancel(); found = 1; /* * as long as the pipe is open and there is app data to send... */ while (( t_seqno_ <= fack_ + win - retran_data_) && (!timeout_)) { if (overhead_ == 0 || force) { found = 0; xmit_seqno = scb_.GetNextRetran (); #ifdef DEBUGSACK1A printf("highest_ack: %d xmit_seqno: %d timeout: %d seqno: %d fack: % d win: %d retran_data: %d\n", highest_ack_, xmit_seqno, timeout_, t_seqno_, fack_, win, retran_data_); #endif if (xmit_seqno == -1) { // no retransmissions to send /* * if there is no more application data to send, * do nothing */ if (t_seqno_ >= curseq_) return; found = 1; xmit_seqno = t_seqno_++; #ifdef DEBUGSACK1A printf("sending %d fastrecovery: %d win %d\n", xmit_seqno, fastrecov_, win); #endif } else { found = 1; scb_.MarkRetran (xmit_seqno, t_seqno_); retran_data_++; win = window(); } if (found) { output(xmit_seqno, reason); if (t_seqno_ <= xmit_seqno) { printf("Hit a strange case 2.\n"); t_seqno_ = xmit_seqno + 1; } npacket++; } } else if (!(delsnd_timer_.status() == TIMER_PENDING)) { /* * Set a delayed send timeout. */ delsnd_timer_.resched(Random::uniform(overhead_)); return; } if (maxburst && npacket == maxburst) break; } /* while */ /* cal