satroute.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) 1999 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the MASH Research
00017  *      Group at the University of California Berkeley.
00018  * 4. Neither the name of the University nor of the Research Group may be
00019  *    used to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * Contributed by Tom Henderson, UCB Daedalus Research Group, June 1999
00035  */
00036 
00037 #ifndef lint
00038 static const char rcsid[] =
00039     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/satellite/satroute.cc,v 1.13 2005/05/19 03:19:02 tomh Exp $";
00040 #endif
00041 
00042 #include "satroute.h"
00043 #include "sattrace.h"
00044 #include "satnode.h"
00045 #include "satlink.h"
00046 #include "route.h"
00047 #include <address.h>
00048 
00049 static class SatRouteClass:public TclClass
00050 {
00051   public:
00052     SatRouteClass ():TclClass ("Agent/SatRoute") { }
00053     TclObject *create (int, const char *const *) {
00054             return (new SatRouteAgent ());
00055     }
00056 } class_satroute;
00057 
00058 SatRouteAgent::SatRouteAgent (): Agent (PT_MESSAGE), maxslot_(0), nslot_(0), slot_(0)
00059 {
00060     bind ("myaddr_", &myaddr_);
00061 }
00062 
00063 SatRouteAgent::~SatRouteAgent()
00064 {
00065     if (slot_)
00066         delete [] slot_;
00067 }
00068 
00069 void SatRouteAgent::alloc(int slot)
00070 {
00071     slot_entry *old = slot_;
00072     int n = nslot_;
00073     if (old == 0)
00074         nslot_ = 32;
00075     while (nslot_ <= slot)
00076         nslot_ <<= 1;
00077     slot_ = new slot_entry[nslot_];
00078     memset(slot_, 0, nslot_ * sizeof(slot_entry));
00079     for (int i = 0; i < n; ++i) {
00080         slot_[i].next_hop = old[i].next_hop;
00081         slot_[i].entry = old[i].entry;
00082     }
00083     delete [] old;
00084 }
00085 
00086 void SatRouteAgent::install(int slot, int nh, NsObject* p)
00087 {
00088     if (slot >= nslot_)
00089         alloc(slot);
00090     slot_[slot].next_hop = nh;
00091     slot_[slot].entry = p;
00092     if (slot >= maxslot_)
00093         maxslot_ = slot;
00094 }
00095 
00096 void SatRouteAgent::clear_slots()
00097 {
00098     if (slot_)
00099         delete [] slot_;
00100     slot_ = 0;
00101     nslot_ = 0;
00102     maxslot_ = -1;
00103 }
00104 
00105 int SatRouteAgent::command (int argc, const char *const *argv)
00106 {
00107         Tcl& tcl = Tcl::instance();
00108         if (argc == 2) {
00109         }
00110         if (argc == 3) {
00111                if (strcmp(argv[1], "set_node") == 0) {
00112                         node_ = (SatNode *) TclObject::lookup(argv[2]);
00113                         if (node_ == 0) {
00114                                 tcl.resultf("no such object %s", argv[2]);
00115                                 return (TCL_ERROR);
00116                         }
00117                         return (TCL_OK);
00118         }
00119     }
00120     return (Agent::command (argc, argv));
00121 }
00122 
00123 /*
00124  *  Find a target for the received packet
00125  */
00126 void SatRouteAgent::forwardPacket(Packet * p)
00127 {
00128     hdr_ip *iph = hdr_ip::access(p);
00129     hdr_cmn *hdrc = HDR_CMN (p);
00130     NsObject *link_entry_;
00131 
00132     hdrc->direction() = hdr_cmn::DOWN; // send it down the stack
00133     int dst = Address::instance().get_nodeaddr(iph->daddr());
00134     // Here we need to have an accurate encoding of the next hop routing
00135     // information
00136     if (myaddr_ == iph->daddr()) {
00137         printf("Error:  trying to forward a packet destined to self: %d\n", myaddr_); 
00138         Packet::free(p);
00139     }
00140     hdrc->addr_type_ = NS_AF_INET;
00141     hdrc->last_hop_ = myaddr_; // for tracing purposes 
00142     if (SatRouteObject::instance().data_driven_computation())
00143         SatRouteObject::instance().recompute_node(myaddr_);
00144     if (SatNode::dist_routing_ == 0) {
00145         if (slot_ == 0) { // No routes to anywhere
00146             if (node_->trace())
00147                 node_->trace()->traceonly(p);
00148             Packet::free(p);
00149             return;
00150         }
00151         link_entry_ = slot_[dst].entry;
00152         if (link_entry_ == 0) {
00153             if (node_->trace())
00154                 node_->trace()->traceonly(p);
00155             Packet::free(p);
00156             return;
00157         }
00158         hdrc->next_hop_ = slot_[dst].next_hop;
00159         link_entry_->recv(p, (Handler *)0);
00160         return;
00161     } else {
00162         // DISTRIBUTED ROUTING LOOKUP COULD GO HERE
00163         printf("Error:  distributed routing not available\n");
00164         exit(1);
00165     }
00166 }
00167 
00168 void SatRouteAgent::recv (Packet * p, Handler *)
00169 {
00170     hdr_ip *iph = hdr_ip::access(p);
00171     hdr_cmn *cmh = hdr_cmn::access(p);
00172 
00173     if (iph->saddr() == myaddr_ && cmh->num_forwards() == 0) {
00174         // Must be a packet I'm originating... add the IP header
00175         iph->ttl_ = IP_DEF_TTL;
00176     } else if (iph->saddr() == myaddr_) {
00177         // I received a packet that I sent.  Probably a routing loop.
00178         Packet::free(p);
00179         return;
00180     } else {
00181         // Packet I'm forwarding...
00182         // Check the TTL.  If it is zero, then discard.
00183         if(--iph->ttl_ == 0) {
00184             Packet::free(p);
00185             return;
00186         }
00187     }
00188     if ((iph->saddr() != myaddr_) && (iph->dport() == ROUTER_PORT)) {
00189         // DISTRIBUTED ROUTING PROTOCOL COULD GO HERE
00190         printf("Error:  distributed routing not available\n");
00191         exit(1);
00192     } else {
00193         forwardPacket(p);
00194     }
00195 }
00196 
00197 //###########################################################################
00198 
00199 static class SatRouteObjectClass:public TclClass
00200 {
00201   public:
00202         SatRouteObjectClass ():TclClass ("SatRouteObject") { }
00203         TclObject *create (int, const char *const *) {
00204                 return (new SatRouteObject ());
00205         }
00206 } class_satrouteobject;
00207 
00208 SatRouteObject* SatRouteObject::instance_;
00209 
00210 SatRouteObject::SatRouteObject() : suppress_initial_computation_(0) 
00211 {
00212     bind_bool("wiredRouting_", &wiredRouting_);
00213     bind_bool("metric_delay_", &metric_delay_);
00214     bind_bool("data_driven_computation_", &data_driven_computation_);
00215 }
00216 
00217 int SatRouteObject::command (int argc, const char *const *argv)
00218 {
00219         if (instance_ == 0)
00220                 instance_ = this;
00221     if (argc == 2) {
00222         // While suppress_initial_computation_ may seem more 
00223         // appropriate as a bound variable, it is useful to 
00224         // implement the setting of this variable this way so that 
00225         // the ``instance_ = this'' assignment is made at the
00226         // start of simulation.
00227         if (strcmp(argv[1], "suppress_initial_computation") == 0) {
00228             suppress_initial_computation_ = 1;
00229             return (TCL_OK);
00230         }
00231         if (strcmp(argv[1], "compute_routes") == 0) {
00232             recompute();
00233             return (TCL_OK);
00234         }
00235         if (strcmp(argv[1], "dump") == 0) {
00236             printf("Dumping\n");
00237             dump();
00238             return (TCL_OK);
00239         }
00240     }
00241     return (RouteLogic::command(argc, argv));
00242 }                       
00243 
00244 // Wrapper to catch whether OTcl-based (wired-satellite) routing is enabled
00245 void SatRouteObject::insert_link(int src, int dst, double cost)
00246 {
00247     if (wiredRouting_) {
00248         Tcl::instance().evalf("[Simulator instance] sat_link_up %d %d %f", (src - 1), (dst - 1), cost);
00249     } else
00250         insert(src, dst, cost);
00251 }
00252 
00253 // Wrapper to catch whether OTcl-based (wired) routing is enabled
00254 void SatRouteObject::insert_link(int src, int dst, double cost, void* entry)
00255 {
00256     SatLinkHead* slhp = (SatLinkHead*) entry;
00257     if (wiredRouting_) {
00258         // Here we do an upcall to an instproc in ns-sat.tcl
00259         // that populates the link_(:) array
00260         Tcl::instance().evalf("[Simulator instance] sat_link_up %d %d %f %s %s", (src - 1), (dst - 1), cost, slhp->name(), slhp->queue()->name());
00261     } else
00262         insert(src, dst, cost, entry); // base class insert()
00263 }
00264 
00265 void SatRouteObject::recompute_node(int node)
00266 {
00267     compute_topology();
00268     node_compute_routes(node);
00269     populate_routing_tables(node);
00270 }
00271 void SatRouteObject::recompute()
00272 {
00273     // For very large topologies (e.g., Teledesic), we don't want to
00274     // waste a lot of time computing routes at the beginning of the
00275     // simulation.  This first if() clause suppresses route computations.
00276     if (data_driven_computation_ ||
00277         (NOW < 0.001 && suppress_initial_computation_) ) 
00278         return;
00279     else {
00280         compute_topology();
00281         if (wiredRouting_) {
00282             Tcl::instance().evalf("[Simulator instance] compute-flat-routes");
00283         } else {
00284             compute_routes(); // base class function
00285         }
00286         populate_routing_tables();
00287     }
00288 }
00289 
00290 // Derives link adjacency information from the nodes and gives the current
00291 // topology information to the RouteLogic.
00292 void SatRouteObject::compute_topology()
00293 {
00294     Node *nodep;
00295     Phy *phytxp, *phyrxp, *phytxp2, *phyrxp2;
00296     SatLinkHead *slhp;
00297     Channel *channelp, *channelp2;
00298     int src, dst; 
00299     double delay;
00300 
00301     // wired-satellite integration
00302     if (wiredRouting_) {
00303         // There are two route objects being used
00304         // a SatRouteObject and a RouteLogic (for wired)
00305         // We need to also reset the RouteLogic one
00306         Tcl::instance().evalf("[[Simulator instance] get-routelogic] reset");
00307     }
00308     reset_all();
00309     // Compute adjacencies.  Traverse linked list of nodes 
00310         for (nodep=Node::nodehead_.lh_first; nodep; nodep = nodep->nextnode()) {
00311         // Cycle through the linked list of linkheads
00312         if (!SatNode::IsASatNode(nodep->address()))
00313             continue;
00314         for (slhp = (SatLinkHead*) nodep->linklisthead().lh_first; slhp; 
00315           slhp = (SatLinkHead*) slhp->nextlinkhead()) {
00316         if (slhp->type() == LINK_GSL_REPEATER)
00317             continue;
00318         if (!slhp->linkup_)
00319             continue;
00320         phytxp = (Phy *) slhp->phy_tx();
00321         assert(phytxp);
00322         channelp = phytxp->channel();
00323         if (!channelp) 
00324             continue; // Not currently connected to channel
00325         // Next, look for receive interfaces on this channel
00326         phyrxp = channelp->ifhead_.lh_first;
00327         for (; phyrxp; phyrxp = phyrxp->nextchnl()) {
00328             if (phyrxp == phytxp) {
00329             printf("Configuration error:  a transmit interface \
00330               is a channel target\n");
00331             exit(1);
00332             } 
00333             if (phyrxp->head()->type() == LINK_GSL_REPEATER) {
00334             double delay_firsthop = ((SatChannel*)
00335                     channelp)->get_pdelay(phytxp->node(), 
00336                     phyrxp->node());
00337             if (!((SatLinkHead*)phyrxp->head())->linkup_)
00338                     continue;
00339             phytxp2 = ((SatLinkHead*)phyrxp->head())->phy_tx();
00340             channelp2 = phytxp2->channel();
00341             if (!channelp2) 
00342                     continue; // Not currently connected to channel
00343             phyrxp2 = channelp2->ifhead_.lh_first;
00344             for (; phyrxp2; phyrxp2 = phyrxp2->nextchnl()) {
00345                     if (phyrxp2 == phytxp2) {
00346                     printf("Config error: a transmit interface \
00347                       is a channel target\n");
00348                     exit(1);
00349                 }
00350                     // Found an adjacency relationship.
00351                     // Add this link to the RouteLogic
00352                     src = phytxp->node()->address() + 1;
00353                     dst = phyrxp2->node()->address() + 1;
00354                 if (src == dst)
00355                 continue;
00356                 if (metric_delay_)
00357                         delay = ((SatChannel*) 
00358                       channelp2)->get_pdelay(phytxp2->node(), 
00359                       phyrxp2->node());
00360                 else {
00361                 delay = 1;
00362                 delay_firsthop = 0;
00363                 }
00364                 insert_link(src, dst, delay+delay_firsthop, (void*)slhp);
00365             }
00366             } else {
00367                 // Found an adjacency relationship.
00368                 // Add this link to the RouteLogic
00369                 src = phytxp->node()->address() + 1;
00370                 dst = phyrxp->node()->address() + 1;
00371             if (metric_delay_)
00372                     delay = ((SatChannel*) 
00373                       channelp)->get_pdelay(phytxp->node(), 
00374                   phyrxp->node());
00375             else
00376                 delay = 1;
00377             insert_link(src, dst, delay, (void*)slhp);
00378             }
00379         }
00380         }
00381     }
00382     //dump();
00383 }
00384 
00385 void SatRouteObject::populate_routing_tables(int node)
00386 {
00387     SatNode *snodep = (SatNode*) Node::nodehead_.lh_first;
00388     SatNode *snodep2;
00389     int next_hop, src, dst;
00390     NsObject *target;
00391 
00392     if (wiredRouting_) {
00393         Tcl::instance().evalf("[Simulator instance] populate-flat-classifiers [Node set nn_]");
00394         return;
00395     }
00396         for (; snodep; snodep = (SatNode*) snodep->nextnode()) {
00397         if (!SatNode::IsASatNode(snodep->address()))
00398             continue;   
00399         // First, clear slots of the current routing table
00400         if (snodep->ragent())
00401             snodep->ragent()->clear_slots();
00402         src = snodep->address();
00403         if (node != -1 && node != src)
00404             continue;
00405         snodep2 = (SatNode*) Node::nodehead_.lh_first;
00406         for (; snodep2; snodep2 = (SatNode*) snodep2->nextnode()) {
00407                         if (!SatNode::IsASatNode(snodep->address()))
00408                                 continue;
00409             dst = snodep2->address();
00410             next_hop = lookup(src, dst);
00411             if (next_hop != -1 && src != dst) {
00412                 // Here need to insert target into slot table
00413                 target = (NsObject*) lookup_entry(src, dst);
00414                 if (target == 0) {
00415                     printf("Error, routelogic target ");
00416                     printf("not populated %f\n", NOW); 
00417                     exit(1);
00418                 }
00419                 ((SatNode*)snodep)->ragent()->install(dst, 
00420                     next_hop, target); 
00421             }
00422         }
00423     }
00424         
00425 }
00426 
00427 int SatRouteObject::lookup(int s, int d)
00428 {                                       
00429     int src = s + 1;        
00430     int dst = d + 1;
00431     if (src >= size_ || dst >= size_) {
00432         return (-1); // Next hop = -1
00433     }
00434     return (route_[INDEX(src, dst, size_)].next_hop - 1);
00435 }
00436 
00437 void* SatRouteObject::lookup_entry(int s, int d)
00438 {                       
00439     int src = s + 1;
00440     int dst = d + 1;
00441     if (src >= size_ || dst >= size_) {
00442         return (0); // Null pointer
00443     }
00444     return (route_[INDEX(src, dst, size_)].entry);
00445 }
00446 
00447 // This method is used for debugging only
00448 void SatRouteObject::dump()
00449 {
00450     int i, src, dst;
00451     for (i = 0; i < (size_ * size_); i++) {
00452         if (adj_[i].cost != SAT_ROUTE_INFINITY) {
00453             src = i / size_ - 1;
00454             dst = i % size_ - 1;
00455             printf("Found a link from %d to %d with cost %f\n", src, dst, adj_[i].cost);
00456         }
00457         }
00458 }
00459 
00460 void SatRouteObject::node_compute_routes(int node)
00461 {
00462         int n = size_;
00463         int* parent = new int[n];
00464         double* hopcnt = new double[n];
00465 #define ADJ(i, j) adj_[INDEX(i, j, size_)].cost
00466 #define ADJ_ENTRY(i, j) adj_[INDEX(i, j, size_)].entry
00467 #define ROUTE(i, j) route_[INDEX(i, j, size_)].next_hop
00468 #define ROUTE_ENTRY(i, j) route_[INDEX(i, j, size_)].entry
00469         delete[] route_;
00470         route_ = new route_entry[n * n];
00471         memset((char *)route_, 0, n * n * sizeof(route_[0]));
00472         /* compute routes only for node "node" */
00473         int k = node + 1; // must add one to get the right offset in tables  
00474         int v;
00475         for (v = 0; v < n; v++) 
00476                 parent[v] = v;
00477 
00478         /* set the route for all neighbours first */
00479         for (v = 1; v < n; ++v) {
00480                 if (parent[v] != k) {
00481                         hopcnt[v] = ADJ(k, v);
00482                         if (hopcnt[v] != SAT_ROUTE_INFINITY) {
00483                                 ROUTE(k, v) = v;
00484                                 ROUTE_ENTRY(k, v) = ADJ_ENTRY(k, v);
00485                         }
00486                 }
00487         }
00488         for (v = 1; v < n; ++v) {
00489                 /*
00490                  * w is the node that is the nearest to the subtree
00491                  * that has been routed
00492                  */
00493                 int o = 0;
00494                 /* XXX */
00495                 hopcnt[0] = SAT_ROUTE_INFINITY;
00496                 int w;
00497                 for (w = 1; w < n; w++)
00498                         if (parent[w] != k && hopcnt[w] < hopcnt[o])
00499                                 o = w;
00500                 parent[o] = k;
00501                 /*
00502                  * update distance counts for the nodes that are
00503                  * adjacent to o
00504                  */
00505                 if (o == 0)
00506                         continue;
00507                 for (w = 1; w < n; w++) {
00508                         if (parent[w] != k &&
00509                             hopcnt[o] + ADJ(o, w) < hopcnt[w]) {
00510                                 ROUTE(k, w) = ROUTE(k, o);
00511                                 ROUTE_ENTRY(k, w) =
00512                                     ROUTE_ENTRY(k, o);
00513                                 hopcnt[w] = hopcnt[o] + ADJ(o, w);
00514                         }
00515                 }
00516         }
00517         /*
00518          * The route to yourself is yourself.
00519          */
00520         ROUTE(k, k) = k;
00521         ROUTE_ENTRY(k, k) = 0; // This should not matter
00522 
00523         delete[] hopcnt;
00524         delete[] parent;
00525 }

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