srm-topo.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) Xerox Corporation 1997. All rights reserved.
00004  *  
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU General Public License as published by the
00007  * Free Software Foundation; either version 2 of the License, or (at your
00008  * option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along
00016  * with this program; if not, write to the Free Software Foundation, Inc.,
00017  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  *
00019  * Linking this file statically or dynamically with other modules is making
00020  * a combined work based on this file.  Thus, the terms and conditions of
00021  * the GNU General Public License cover the whole combination.
00022  *
00023  * In addition, as a special exception, the copyright holders of this file
00024  * give you permission to combine this file with free software programs or
00025  * libraries that are released under the GNU LGPL and with code included in
00026  * the standard release of ns-2 under the Apache 2.0 license or under
00027  * otherwise-compatible licenses with advertising requirements (or modified
00028  * versions of such code, with unchanged license).  You may copy and
00029  * distribute such a system following the terms of the GNU GPL for this
00030  * file and the licenses of the other code concerned, provided that you
00031  * include the source code of that other code when and as the GNU GPL
00032  * requires distribution of source code.
00033  *
00034  * Note that people who make modified versions of this file are not
00035  * obligated to grant this special exception for their modified versions;
00036  * it is their choice whether to do so.  The GNU General Public License
00037  * gives permission to release a modified version without this exception;
00038  * this exception also makes it possible to release a modified version
00039  * which carries forward this exception.
00040  *
00041  * This file contributed by Suchitra Raman <sraman@parc.xerox.com>, June 1997.
00042  */
00043 
00044 #include <stdlib.h>
00045 #include <math.h>
00046 #include <assert.h>
00047 
00048 #include "config.h"
00049 #include "tclcl.h"
00050 #include "srm-topo.h"
00051 #include "scheduler.h"
00052 
00053 #define SRM_DEBUG
00054 
00055 
00056 Topology::Topology(int nn, int src) : idx_(nn), src_(src)
00057 {
00058     node_ = new SrmNode[nn];
00059     for (int i = 0; i < nn; i ++) 
00060         node_[i].id(i);
00061 
00062     bind("src_", &src_);
00063     bind("delay_", &delay_);
00064     bind("D_", &D_);
00065     bind("frac_", &frac_);
00066     /* D_ (ms) is the delay of node 1 from node 0 */
00067 
00068     bind("det_", &det_);
00069     bind("rtt_est_", &rtt_est_);
00070     bind("rand_", &rand_);
00071 }
00072 
00073 Topology::~Topology() {
00074     delete [] node_;
00075 }
00076 
00077 int Topology::command(int argc, const char*const* argv) 
00078 {
00079     //Tcl& tcl = Tcl::instance();
00080     if (argc == 3) {
00081         if (strcmp(argv[1], "flood") == 0) {
00082             flood(0, atoi(argv[2]));
00083             return (TCL_OK);
00084         }
00085     }
00086     return (TclObject::command(argc, argv));
00087 }
00088 
00089 SrmNode* Topology::node(int nn) 
00090 { 
00091     if (nn < 0 || nn >= idx_) return 0;
00092     return &(node_[nn]); 
00093 }
00094 
00095 
00096 static class LineClass : public TclClass {
00097 public:
00098     LineClass() : TclClass("Topology/Line") {} 
00099     TclObject* create(int, const char*const* argv) {
00100         int nn = atoi(argv[4]);
00101         return (new Line(nn, 0));
00102     }
00103 } class_line_topo;
00104 
00105 
00106 double Line::backoff(int dst) 
00107 {
00108     double rtt;
00109 
00110     if (topology->rtt_estimated() == 1)
00111         rtt = delay(dst, 0);
00112     else rtt = D_ * frac_;
00113     double b;
00114     double sqroot = sqrt(rtt);
00115     double r = Random::uniform(0.0, 1.0);
00116 
00117     switch(c2func_) {
00118     case LOG :
00119         b = rtt * (det_ +  rand_ * r * log(rtt)/log(D_));
00120         break;
00121     case SQRT :
00122         b = rtt * (det_ +  rand_ * r * sqroot/sqrt(D_));
00123         break;
00124     case LINEAR :
00125         b = rtt * (det_ +  rand_ * r * rtt/D_);
00126         break;
00127     case CONSTANT :
00128         b = rtt * (det_ +  rand_ * r * 1.);
00129         break;
00130     default:
00131         // quiet compiler
00132         b = 0.0;
00133         assert (false);
00134         break;
00135     }
00136     return b;
00137 }
00138 
00139 #ifdef SRM_BIMODAL
00140 double Line::backoff(int dst) 
00141 {
00142     double rtt;
00143     if (topology->rtt_estimated() == 1) 
00144         rtt = delay(dst, 0);
00145     else rtt = D_ * frac_;
00146 
00147     double rbackoff;
00148     double p = Random::uniform(0.0, 1.0);
00149     int bin = 0;
00150     int copies = c_;
00151     int size = topology->idx();
00152     
00153     if (p <= copies * 1./size) {
00154         rbackoff = Random::uniform(0.0, alpha_);
00155         bin = 0;
00156     } else {
00157         rbackoff = Random::uniform(beta_, 1.0 + beta_);
00158         bin = 1;
00159     }
00160 
00161     return (rtt * (det_ + rand_ * rbackoff));
00162 }
00163 #endif
00164 
00165 Interface_List* Line::oif(int node, int iif=SRM_NOIF)
00166 {
00167     //int oif;
00168     Interface_List *ilist = new Interface_List;
00169 
00170     /* If there are no more nodes downstream, return -1 */
00171     if ((iif <= node && node >= idx_ - 1) ||  (iif > node && node == 0))
00172         return 0;
00173 
00174     if (iif == SRM_NOIF) 
00175     {
00176         ilist->append(node + 1);
00177         ilist->append(node - 1);
00178     } else if (iif <= node) 
00179         ilist->append(node + 1);
00180     else 
00181         ilist->append(node - 1);
00182     return (ilist);
00183 }
00184 
00185 double Line::delay(int src, int dst) 
00186 {
00187     if (src == 0 || dst == 0) 
00188         return D_ + delay_ * abs(dst - src - 1);
00189     else
00190         return delay_ * abs(dst - src);
00191 }
00192 
00193 
00194 double Star::delay(int src, int dst) 
00195 {
00196     if (src == 0 || dst == 0) 
00197         return D_;
00198     else
00199         return delay_;
00200 }
00201 
00202 /* 
00203  * Very simple now, can only send to direct ancestor/descendant 
00204  */
00205 double BTree::delay(int src, int dst)
00206 {
00207     double src_ht = 0;
00208     double dst_ht = 0;
00209     
00210     if (src > 0) 
00211         src_ht = 1 + floor(log(src)/log(2));
00212     if (dst > 0)
00213         dst_ht = 1 + floor(log(dst)/log(2));
00214     
00215     if (src == 0 || dst == 0) 
00216         return D_ + delay_ * abs(int (dst_ht - src_ht - 1));
00217     else 
00218         return delay_ * abs(int (dst_ht - src_ht));
00219 }   
00220 
00221 /* 
00222  * There is always an outbound interface. We should not 
00223  * start a flood() from a leaf node. 
00224  * Change it for other topologies. 
00225  */
00226 void Line::flood(int start, int seqno)
00227 {
00228     SRM_Event *se = new SRM_Event(seqno, SRM_DATA, start);
00229     node_[start].send(se);
00230 }
00231 
00232 /*
00233  * BTree -
00234  */
00235 
00236 static class BTreeClass : public TclClass {
00237 public:
00238     BTreeClass() : TclClass("Topology/BTree") {} 
00239     TclObject* create(int, const char*const* argv) {
00240         int nn = atoi(argv[4]);
00241         return (new BTree(nn, 0));
00242     }
00243 } class_btree_topo;
00244 
00245 
00246 /* 
00247  * The ranges of the different distributions 
00248  * must be normalized to 1. 
00249  */
00250 double BTree::backoff(int id) 
00251 {
00252     double rtt;
00253     if (topology->rtt_estimated())
00254         rtt = delay(id, 0);
00255     else rtt = D_ * frac_; 
00256 
00257     double r = Random::uniform(0.0, 1.0);
00258     double b;
00259     double sqroot = sqrt(rtt);
00260     double D = topology->D();
00261 
00262     switch(c2func_) {
00263     case LOG :
00264         b = rtt * (det_ +  rand_ * r * log(rtt)/log(D));
00265         break;
00266     case SQRT :
00267         b = rtt * (det_ +  rand_ * r * sqroot/sqrt(D));
00268         break;
00269     case LINEAR :
00270         b = rtt * (det_ +  rand_ * r * rtt/D);
00271         break;
00272     case CONSTANT :
00273         b = rtt * (det_ +  rand_ * r * 1.);
00274         break;
00275     default:
00276         // quiet compiler
00277         b = 0.0;
00278         assert (false);
00279         break;
00280     }
00281     return b;
00282 }
00283 
00284 Interface_List* BTree::oif(int node, int iif=SRM_NOIF)
00285 {
00286     //int oif;
00287     Interface_List *ilist = new Interface_List;
00288     /* 
00289      * If the packet comes from the source, 
00290      * there is only 1 outgoing link.
00291      * We make the assumption that source = 0 always (YUCK!)
00292      */
00293     if (iif == SRM_NOIF) {
00294         if (node == 0) {
00295             ilist->append(1);
00296         }
00297         else {
00298             ilist->append(2 * node + 1);
00299             ilist->append(2 * node);
00300             int k = (int)floor(.5 * node);
00301             ilist->append(k);
00302         }
00303     } else if (iif <= node) {
00304         ilist->append(2 * node + 1);
00305         ilist->append(2 * node);
00306     }
00307 
00308     // Packet came along 2n + 1 or 2n + 2
00309     else if (iif == 2 * node + 1) {
00310         if (node == 0)
00311             return ilist;
00312         
00313         ilist->append(2 * node);
00314         ilist->append((int) floor(.5 * node));
00315     } else if (iif == 2 * node) {
00316         ilist->append(2 * node + 1);
00317         ilist->append((int)floor(.5 * node));
00318     }
00319     return (ilist);
00320 }
00321 
00322 /*
00323  * Star -
00324  */
00325 
00326 static class StarClass : public TclClass {
00327 public:
00328     StarClass() : TclClass("Topology/Star") {} 
00329     TclObject* create(int, const char*const* argv) {
00330         int nn = atoi(argv[4]);
00331         return (new Star(nn, 0));
00332     }
00333 } class_star_topo;
00334 
00335 
00336 /* 
00337  * SrmNode -
00338  */
00339 
00340 void SrmNode::dump_packet(SRM_Event *e) 
00341 {
00342 #ifdef SRM_DEBUG
00343     tprintf(("(type %d) (in %d) -- @ %d --> \n", e->type(), e->iif(), id_));
00344 #endif
00345 }
00346 
00347 /* This forwards an event by making multiple copies of the
00348  * event 'e'. Does NOT free event 'e'. 
00349  */
00350 void SrmNode::send(SRM_Event *e) 
00351 {
00352     /* 
00353      * Copy the packet and send it over to 
00354      * all the outbound interfaces 
00355      */
00356     int nn;
00357     Scheduler& s = Scheduler::instance();
00358     SRM_Event *copy;
00359     Interface *p;
00360     Interface_List *ilist = topology->oif(id_, e->iif());
00361     if (e->iif() < 0)
00362         e->iif(id_);
00363 
00364     if (ilist) {
00365         for (p=ilist->head_; p; p=p->next_) {
00366             nn = p->in_;
00367             int t = e->type();
00368             //int i = id_; 
00369             int snum = e->seqno();
00370             SrmNode *next = topology->node(nn);
00371             if (next) {
00372                 copy = new SRM_Event(snum, t, id_);
00373                 s.schedule(next, copy,
00374                        topology->delay(id_, nn));    
00375             }
00376         }
00377     }
00378     delete ilist;
00379     delete e;
00380 }
00381 
00382 
00383 /* 
00384  * Demux the two types of events depending on 
00385  * the type field.
00386  */ 
00387 void SrmNode::handle(Event* event)
00388 {
00389     SRM_Event *srm_event = (SRM_Event *) event;
00390     int type  = srm_event->type();
00391     int seqno = srm_event->seqno();
00392     //int iif   = srm_event->iif();
00393     //Scheduler& s = Scheduler::instance();
00394 
00395     switch (type) {
00396     case SRM_DATA :
00397         if (seqno != expected_) 
00398             sched_nack(seqno);
00399         expected_ = seqno;
00400         break;
00401 
00402     case SRM_PENDING_RREQ :
00403         tprintf(("Fired RREQ (node %d)\n", id_));
00404         remove(seqno, SRM_NO_SUPPRESS);
00405         srm_event->type(SRM_RREQ);
00406         break;
00407 
00408     case SRM_RREQ :
00409 
00410         remove(seqno, SRM_SUPPRESS);
00411         break;
00412 
00413     default :
00414         tprintf(("panic: node(%d) Unexpected type %d\n", id_, type));
00415         return;
00416     }
00417 #ifdef SRM_STAR
00418     if (type == SRM_RREQ || type == SRM_DATA) {
00419         delete srm_event;
00420         return;
00421     }
00422 #endif
00423     send(srm_event);    
00424     return;
00425 }
00426 
00427 /* 
00428  * XXX Should take two sequence numbers. The iif field is a dummy. We should be
00429  * careful not to use it for NACKs 
00430  */
00431 void SrmNode::sched_nack(int seqno) 
00432 {
00433     double backoff, time;
00434     Scheduler& s = Scheduler::instance();
00435     SRM_Event *event = new SRM_Event(seqno, 
00436                      SRM_PENDING_RREQ, SRM_NOIF);
00437     append(event);
00438 
00439     backoff = topology->backoff(id_);
00440     time = backoff + s.clock();
00441 //  tprintf(("node(%d) schd rrq after %f s\n", id_, backoff));
00442     s.schedule(this, event, backoff);
00443 }
00444 
00445 void SrmNode::append(SRM_Event *e) 
00446 {
00447     SRM_Request *req = new SRM_Request(e);
00448     req->next_ = pending_;
00449     pending_ = req;
00450 }
00451 
00452 /* If an event identical to e exists, cancel it */
00453 void SrmNode::remove(int seqno, int flag)
00454 {
00455     SRM_Request *curr, *prev;
00456     SRM_Event *ev;
00457 
00458     if (!pending_)
00459         return;
00460     for (curr=pending_, prev=0; curr; curr=curr->next_) 
00461     {
00462         ev = curr->event_;
00463         if (ev->seqno() == seqno) {
00464             if (!prev) 
00465                 pending_ = curr->next_;
00466             else {
00467                 prev->next_ = curr->next_;
00468                 prev = curr;
00469             }
00470             if (flag == SRM_SUPPRESS) {
00471                 curr->cancel_timer();
00472             }
00473             delete curr;
00474         }
00475     }
00476 }
00477 
00478 
00479 SRM_Event::SRM_Event(SRM_Event *e) 
00480 {
00481     seqno_ = e->seqno();
00482     type_  = e->type();
00483     iif_   = e->iif();
00484 }
00485 
00486 SRM_Request::~SRM_Request() {}
00487 
00488 void SRM_Request::cancel_timer() 
00489 {
00490     if (event_) {
00491         Scheduler& s = Scheduler::instance();
00492         s.cancel(event_);
00493         // xxx: should event be free'd?  possible memory leak.
00494     }
00495 }
00496 
00497 void Interface_List::append(int in) 
00498 {
00499     Interface *i = new Interface(in);
00500     i->next_ = head_;
00501     head_ = i;
00502 }
00503 
00504 Interface_List::~Interface_List() 
00505 {
00506     Interface *p, *next;
00507     for (p=head_; p; p=next)
00508     {
00509         next = p->next_;
00510         delete p;
00511     }
00512 }
00513 
00514 void BTree::flood(int start, int seqno)
00515 {
00516     SRM_Event *se = new SRM_Event(seqno, SRM_DATA, SRM_NOIF);
00517     node_[start].send(se);
00518 }
00519 
00520 void Star::flood(int start, int seqno)
00521 {
00522     SRM_Event *se = new SRM_Event(seqno, SRM_DATA, start);
00523     node_[start].send(se);
00524 }
00525 
00526 Interface_List* Star::oif(int node, int iif=SRM_NOIF)
00527 {
00528     int i;
00529     Interface_List *ilist = new Interface_List;
00530 
00531     /* Make a list with every node except myself */
00532     for (i = 0; i < topology->idx(); i ++)
00533     {
00534         if (i != node && i != iif) {
00535             ilist->append(i);
00536         }
00537     }
00538 
00539     return (ilist);
00540 }
00541 
00542 /* 
00543  * Distance of source to cluster = D_
00544  */
00545 double Star::backoff(int id)
00546 {
00547     double rtt = topology->delay(id, 0);
00548     double rbackoff;
00549     double p = Random::uniform(0.0, 1.0);
00550     static int bin = 0;
00551     int copies = c_;
00552     int size = topology->idx();
00553     
00554     if (p <= copies * 1./size) {
00555         rbackoff = Random::uniform(0.0, alpha_);
00556         bin ++;
00557     } else {
00558         rbackoff = Random::uniform(beta_, 1.0 + beta_);
00559     }
00560     return (rtt * (det_ + rand_ * rbackoff));
00561 }
00562 
00563 
00564 #ifdef SRM_BIMODAL
00565 double BTree::backoff(int dst) 
00566 {
00567     double height = floor(log(dst)/log(2));
00568 
00569     double D = topology->D();
00570     double rtt = delay_ * height + D;
00571     double p = Random::uniform(0.0, 1.0);
00572     double rbackoff;
00573 
00574     static int bin = 0;
00575     int copies = c_;
00576     int size = topology->idx();
00577     
00578     if (p <= copies * 1./size) {
00579         rbackoff = Random::uniform(0.0, alpha_);
00580         bin ++;
00581     } else {
00582         rbackoff = Random::uniform(1.0 + alpha_, 2.0);
00583     }
00584     return (rtt * (det_ + rand_ * rbackoff));
00585 }
00586 #endif

Generated on Tue Mar 6 16:47:51 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6