Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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.12 2001/11/06 06:21:47 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 != 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] != 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] = 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 Apr 20 12:14:31 2004 for NS2.26SourcesOriginal by doxygen 1.3.3