sathandoff.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/sathandoff.cc,v 1.11 2005/08/22 05:08:34 tomh Exp $";
00040 #endif
00041 
00042 #include "random.h"
00043 #include "sathandoff.h"
00044 #include "satlink.h"
00045 #include "satroute.h"
00046 #include "satposition.h"
00047 #include "satnode.h"
00048 #include "satgeometry.h"
00049 #include <math.h>
00050 
00051 
00052 static class LinkHandoffMgrClass : public TclClass {
00053 public:
00054         LinkHandoffMgrClass() : TclClass("HandoffManager") {}
00055         TclObject* create(int, const char*const*) {
00056                 return (new LinkHandoffMgr());
00057         }
00058 } class_link_handoff_manager;
00059 
00060 static class SatLinkHandoffMgrClass : public TclClass {
00061 public:
00062         SatLinkHandoffMgrClass() : TclClass("HandoffManager/Sat") {}
00063         TclObject* create(int, const char*const*) {
00064                 return (new SatLinkHandoffMgr());
00065         }
00066 } class_sat_link_handoff_manager;
00067 
00068 static class TermLinkHandoffMgrClass : public TclClass {
00069 public:
00070         TermLinkHandoffMgrClass() : TclClass("HandoffManager/Term") {}
00071         TclObject* create(int, const char*const*) {
00072                 return (new TermLinkHandoffMgr());
00073         }
00074 } class_term_link_handoff_manager;
00075 
00076 void SatHandoffTimer::expire(Event*)
00077 {                           
00078         a_->handoff();  
00079 }                               
00080 
00081 void TermHandoffTimer::expire(Event*)
00082 {                           
00083         a_->handoff();  
00084 }                               
00085 
00087 // class LinkHandoffMgr
00089 
00090 RNG LinkHandoffMgr::handoff_rng_;
00091 int LinkHandoffMgr::handoff_randomization_ = 0;
00092 
00093 LinkHandoffMgr::LinkHandoffMgr()
00094 {
00095     bind_bool("handoff_randomization_", &handoff_randomization_);
00096 }
00097 
00098 int LinkHandoffMgr::command(int argc, const char*const* argv)
00099 {
00100     if (argc == 2) {
00101     } else if (argc == 3) {
00102         if(strcmp(argv[1], "setnode") == 0) {
00103             node_ = (Node*) TclObject::lookup(argv[2]);
00104             if (node_ == 0)
00105                 return TCL_ERROR;
00106             return TCL_OK;
00107         }
00108     }
00109     return (TclObject::command(argc, argv));
00110 }
00111 
00112 // Each crossseam satellite will have two net stacks-- at most one will
00113 // be occupied.  This procedure finds an unoccupied stack on the node.
00114 SatLinkHead* LinkHandoffMgr::get_peer_next_linkhead(SatNode* np)
00115 {
00116     LinkHead* lhp;
00117     SatLinkHead* slhp;
00118     for (lhp = np->linklisthead().lh_first; lhp; 
00119         lhp = lhp->nextlinkhead() ) {
00120         slhp = (SatLinkHead*) lhp;
00121         if (slhp->type() == LINK_ISL_CROSSSEAM) {
00122             if (!slhp->phy_tx()->channel() && 
00123                 !slhp->phy_rx()->channel() ) 
00124                 return slhp;
00125         }
00126     }
00127     printf("Error, couldn't find an empty crossseam stack for handoff\n");
00128     return 0;
00129 }
00130 
00131 // This helper function assumes that the channel to which the link interface
00132 // is attached has one peer node (i.e., no other receive infs on channel)
00133 SatLinkHead* LinkHandoffMgr::get_peer_linkhead(SatLinkHead* slhp)
00134 {
00135     SatChannel *schan_;
00136     Phy *remote_phy_;
00137     Node *remote_node_;
00138 
00139     schan_ = (SatChannel*) slhp->phy_tx()->channel();
00140     if (schan_ == 0) {
00141         printf("Error:  get_peer_linkhead called for a non-");
00142         printf("connected link on node %d\n", slhp->node()->address());
00143         return 0; // Link is not currently connected
00144     }
00145     remote_phy_ = schan_->ifhead_.lh_first; 
00146     if (remote_phy_ == 0) {
00147         printf("Error:  node %d's tx phy ", slhp->node()->address());
00148         printf("connected to channel with no receivers\n");
00149         return 0;
00150     }
00151     remote_node_ = remote_phy_->head()->node();
00152     if (remote_phy_->nextchnl()) {
00153         printf("Error:  This ISL channel has more than one target\n");
00154         return 0;
00155     }
00156     return ( (SatLinkHead*) remote_phy_->head());
00157 }
00158 
00159 // This helper function assumes that the channel to which the link interface
00160 // is attached has one peer node (i.e., no other receive infs on channel)
00161 SatNode* LinkHandoffMgr::get_peer(SatLinkHead* slhp)
00162 {
00163     SatChannel *schan_;
00164     Phy *remote_phy_;
00165 
00166     schan_ = (SatChannel*) slhp->phy_tx()->channel();
00167     if (schan_ == 0)
00168         return 0; // Link is not currently connected
00169     remote_phy_ = schan_->ifhead_.lh_first; 
00170     if (remote_phy_ == 0) {
00171         // this is not an error as far as satellite GSL endpoints
00172         // appear to be concerned.
00173         // Commented out for drawing GSL links in dumpSats()
00174         // in satnode.cc
00175         // printf("Error:  node %d's tx phy ", slhp->node()->address());
00176         // printf("connected to channel with no receivers\n");
00177         return 0;
00178     }
00179     if (remote_phy_->nextchnl()) {
00180         printf("Error:  This ISL channel has more than one target\n");
00181         return 0;
00182     }
00183     
00184     return ( (SatNode*) remote_phy_->head()->node());
00185 }
00186 
00188 // class TermLinkHandoffMgr
00190 
00191 double TermLinkHandoffMgr::elevation_mask_ = 0;
00192 int TermLinkHandoffMgr::term_handoff_int_ = 10;
00193 
00194 TermLinkHandoffMgr::TermLinkHandoffMgr() : timer_(this)
00195 {
00196     bind("elevation_mask_", &elevation_mask_);
00197     bind("term_handoff_int_", &term_handoff_int_);
00198 }
00199 
00200 // 
00201 // This is called each time the node checks to see if its link to a
00202 // polar satellite needs to be handed off.  
00203 // There are two cases:
00204 //     i) current link is up; check to see if it stays up or is handed off
00205 //     ii) current link is down; check to see if it can go up
00206 // If there are any changes, call for rerouting.  Finally, restart the timer. 
00207 //
00208 int TermLinkHandoffMgr::handoff()
00209 {
00210     coordinate sat_coord, earth_coord;
00211     SatLinkHead* slhp;
00212     SatNode *peer_; // Polar satellite at opposite end of the GSL
00213     SatNode *best_peer_ = 0; // Best found peer for handoff
00214     Node *nodep;  // Pointer used in searching the list of nodes
00215     PolarSatPosition *nextpos_;
00216     int link_changes_flag_ = FALSE; // Flag indicating change took place 
00217     int restart_timer_flag_ = FALSE; // Restart timer only if polar links
00218     double found_elev_ = 0;  //``Flag'' indicates whether handoff can occur 
00219     double best_found_elev_ = 0; 
00220     double mask_ = DEG_TO_RAD(TermLinkHandoffMgr::elevation_mask_);
00221 
00222     earth_coord = ((SatNode *)node_)->position()->coord();
00223     // Traverse the linked list of link interfaces
00224     for (slhp = (SatLinkHead*) node_->linklisthead().lh_first; slhp; 
00225         slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
00226         if (slhp->type() == LINK_GSL_GEO || 
00227             slhp->type() == LINK_GENERIC)
00228             continue;
00229         if (slhp->type() != LINK_GSL_POLAR) {
00230             printf("Error: Terminal link type ");
00231             printf("not valid %d NOW %f\n", slhp->type(), NOW);
00232             exit(1);
00233         }
00234         // The link is a GSL_POLAR link-- should be one receive 
00235         // interface on it
00236         restart_timer_flag_ = TRUE;
00237         peer_ = get_peer(slhp);
00238         if (peer_) {
00239             sat_coord = peer_->position()->coord();
00240             if (!SatGeometry::check_elevation(sat_coord, 
00241                 earth_coord, mask_) && slhp->linkup_) {
00242                 slhp->linkup_ = FALSE;
00243                 link_changes_flag_ = TRUE;
00244                 // Detach receive link interface from channel
00245                 // Next line removes phy from linked list
00246                 //   of interfaces attached to channel
00247                 slhp->phy_rx()->removechnl();
00248                 // Set our channel pointers to NULL
00249                 slhp->phy_tx()->setchnl(0);
00250                 slhp->phy_rx()->setchnl(0);
00251                 // wired-satellite integration
00252                 if (SatRouteObject::instance().wiredRouting()) {
00253                     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
00254                     // Must do this bidirectionally
00255                     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
00256                 }
00257             }
00258         }
00259         if (!slhp->linkup_) {
00260             // If link is down, see if we can use another satellite
00261             // 
00262             // As an optimization, first check the next satellite 
00263             // coming over the horizon.  Next, consider all 
00264             // remaining satellites.
00265             // 
00266             if (peer_) {
00267                 // Next satellite
00268                 nextpos_ = ((PolarSatPosition*) 
00269                     peer_->position())->next();
00270                 if (nextpos_) {
00271                     sat_coord = nextpos_->coord();
00272                     found_elev_ = SatGeometry::check_elevation(sat_coord, earth_coord, mask_);
00273                     if (found_elev_)
00274                         peer_ = (SatNode*) nextpos_->node();
00275                 }
00276             }
00277             // Next, check all remaining satellites if not found
00278             if (!found_elev_) {
00279                 for (nodep=Node::nodehead_.lh_first; nodep;
00280                     nodep = nodep->nextnode()) {
00281                     if (!SatNode::IsASatNode(nodep->address()))
00282                         continue;
00283                     peer_ = (SatNode*) nodep;
00284                     if (peer_->position() && 
00285                         (peer_->position()->type() != 
00286                         POSITION_SAT_POLAR))
00287                             continue;
00288                     sat_coord = 
00289                         peer_->position()->coord();
00290                     found_elev_ = SatGeometry::check_elevation(sat_coord, earth_coord, mask_);
00291                     if (found_elev_ > best_found_elev_) {
00292                         best_peer_ = peer_;
00293                         best_found_elev_ = found_elev_;
00294                     }
00295                 }
00296                 if (best_found_elev_ > 0.0) {
00297                     assert (best_peer_ != 0);
00298                     peer_ = best_peer_;
00299                     found_elev_ = best_found_elev_;
00300                 }
00301             }
00302             if (found_elev_) {
00303                 slhp->linkup_ = TRUE;
00304                 link_changes_flag_ = TRUE;
00305                 // Point slhp->phy_tx to peer_'s inlink
00306                 slhp->phy_tx()->setchnl(peer_->uplink());
00307                 // Point slhp->phy_rx to peer_'s outlink and
00308                 // add phy_rx to the channels list of phy's
00309                 slhp->phy_rx()->setchnl(peer_->downlink());
00310                 // Add phy to channel's linked list of i/fces
00311                 slhp->phy_rx()->insertchnl(&(peer_->downlink()->ifhead_));
00312             }
00313         }
00314     }
00315     if (link_changes_flag_) { 
00316         SatRouteObject::instance().recompute();
00317     }
00318     if (restart_timer_flag_) {
00319         // If we don't have polar GSLs, don't reset the timer
00320         if (handoff_randomization_) {
00321             timer_.resched(term_handoff_int_ + 
00322                 handoff_rng_.uniform(-1 * term_handoff_int_/2, 
00323                 term_handoff_int_/2));
00324         } else
00325             timer_.resched(term_handoff_int_);
00326     }
00327         return link_changes_flag_;
00328 }
00329 
00331 // class SatLinkHandoffMgr
00333 
00334 double SatLinkHandoffMgr::latitude_threshold_ = 0;
00335 double SatLinkHandoffMgr::longitude_threshold_ = 0;
00336 int SatLinkHandoffMgr::sat_handoff_int_ = 10;
00337 
00338 SatLinkHandoffMgr::SatLinkHandoffMgr() : timer_(this)
00339 {
00340     bind("sat_handoff_int_", &sat_handoff_int_);
00341     bind("latitude_threshold_", &latitude_threshold_);
00342     bind("longitude_threshold_", &longitude_threshold_);
00343 }
00344 
00345 //
00346 // This function is responsible for activating, deactivating, and handing off
00347 // satellite ISLs.  If the ISL is an intraplane link, 
00348 // do nothing.  If the ISL is an interplane link, it will be taken down
00349 // when _either_ of the connected satellites are above lat_threshold_ 
00350 // degrees, and brought back up when _both_ satellites move below 
00351 // lat_threshold_ again.  If an ISL is a cross-seam link, it must also be 
00352 // handed off periodically while the satellite is below lat_threshold_.  
00353 // 
00354 // Finally, optimizations that avoid going through the linked lists unless 
00355 // the satellite is ``close'' to lat_threshold_ are employed.
00356 //
00357 int SatLinkHandoffMgr::handoff()
00358 {
00359     SatLinkHead *slhp, *peer_slhp, *peer_next_slhp;
00360     SatNode *local_, *peer_, *peer_next_; 
00361     PolarSatPosition *pos_, *peer_pos_, *peer_next_pos_;
00362     double dist_to_peer, dist_to_next;
00363     Channel *tx_channel_, *rx_channel_;
00364     double sat_latitude_, sat_longitude_, peer_latitude_, peer_longitude_;  
00365     int link_down_flag_;
00366     double lat_threshold_ = DEG_TO_RAD(latitude_threshold_);
00367     double cross_long_threshold_ = DEG_TO_RAD(longitude_threshold_);    
00368     int link_changes_flag_ = FALSE; // Flag indicating change took place 
00369     coordinate local_coord_, peer_coord_;
00370 
00371     local_ = (SatNode*) node_;
00372     local_coord_ = local_->position()->coord();
00373     sat_latitude_ = SatGeometry::get_latitude(local_->position()->coord());
00374     sat_longitude_= SatGeometry::get_longitude(local_->position()->coord());
00375 
00376     // First go through crossseam ISLs to search for handoffs
00377     for (slhp = (SatLinkHead*) local_->linklisthead().lh_first; slhp; 
00378         slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
00379         if (slhp->type() != LINK_ISL_CROSSSEAM)  
00380             continue;
00381         peer_ = get_peer(slhp);
00382         if (peer_ == 0)
00383             continue; // this link interface is not attached
00384         // If this is a crossseam link, first see if the link must 
00385         // be physically handed off to the next satellite.
00386         // Handoff is needed if the satellite at the other end of
00387         // the link is further away than the ``next'' satellite
00388         // in the peer's orbital plane.
00389         pos_ = (PolarSatPosition*)slhp->node()->position(); 
00390         peer_slhp = get_peer_linkhead(slhp);
00391         peer_pos_ = (PolarSatPosition*) peer_->position();
00392         peer_coord_ = peer_pos_->coord();
00393         if (fabs(sat_latitude_) > lat_threshold_)
00394             link_down_flag_ = TRUE;
00395         else
00396             link_down_flag_ = FALSE;
00397         if (peer_pos_->plane() < pos_->plane()) {
00398             // Crossseam handoff is controlled by satellites
00399             // in the plane with a lower index
00400             break;  
00401         }
00402         peer_next_pos_ = peer_pos_->next();
00403         if (!peer_next_pos_) {
00404             printf("Error:  crossseam handoffs require ");
00405             printf("setting the ``next'' field\n");
00406             exit(1);
00407         }
00408         peer_next_ = (SatNode*) peer_next_pos_->node();
00409         dist_to_peer = SatGeometry::distance(peer_coord_, local_coord_);
00410         dist_to_next = SatGeometry::distance(peer_next_pos_->coord(), 
00411             local_coord_); 
00412         if (dist_to_next < dist_to_peer) {
00413             // Handoff -- the "next" satellite should have a 
00414             // currently unused network stack.  Find this 
00415             // unused stack and handoff the channels to it.
00416             // 
00417             // Remove peer's tx/rx interface from channel
00418             peer_slhp->phy_rx()->removechnl();
00419             peer_slhp->phy_tx()->setchnl(0);
00420             peer_slhp->phy_rx()->setchnl(0);
00421             // Add peer_next's tx/rx interfaces to our channels
00422             peer_next_slhp = get_peer_next_linkhead(peer_next_);
00423             tx_channel_ = slhp->phy_tx()->channel();
00424             rx_channel_ = slhp->phy_rx()->channel();
00425                         peer_next_slhp->phy_tx()->setchnl(rx_channel_);
00426             peer_next_slhp->phy_rx()->setchnl(tx_channel_);
00427             peer_next_slhp->phy_rx()->insertchnl(&(tx_channel_->ifhead_));
00428             link_changes_flag_ = TRUE; 
00429             // wired-satellite integration
00430             if (SatRouteObject::instance().wiredRouting()) {
00431                 // Check if link is up first before deleting
00432                 if (slhp->linkup_) { 
00433                     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
00434                 }
00435                 if (peer_slhp->linkup_) { 
00436                     Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
00437                 }
00438             }
00439             // Now reset the peer_ variables to point to next
00440             peer_ = peer_next_;
00441             peer_slhp = peer_next_slhp;
00442             peer_coord_ = peer_->position()->coord();
00443         }
00444         // Next, see if the link needs to be taken down.
00445         peer_latitude_ = 
00446             SatGeometry::get_latitude(peer_coord_);
00447         peer_longitude_ = SatGeometry::get_longitude(peer_coord_);
00448         if (fabs(peer_latitude_) > lat_threshold_)
00449             link_down_flag_ = TRUE;
00450         // If the two satellites are too close to each other in
00451         // longitude, the link should be down
00452         if ((fabs(peer_longitude_ - sat_longitude_) <
00453             cross_long_threshold_) ||
00454             fabs(peer_longitude_ - sat_longitude_) >
00455             (2 * PI - cross_long_threshold_))
00456             link_down_flag_ = TRUE;
00457         // Check to see if link grazes atmosphere at an altitude
00458         // below the atmospheric margin
00459         link_down_flag_ |= !(SatGeometry::are_satellites_mutually_visible(peer_coord_, local_coord_));
00460         // Evaluate whether a change in link status is needed
00461         if ((slhp->linkup_ || peer_slhp->linkup_) && link_down_flag_) {
00462             slhp->linkup_ = FALSE;
00463             peer_slhp->linkup_ = FALSE;
00464             link_changes_flag_ = TRUE;
00465             // wired-satellite integration
00466             if (SatRouteObject::instance().wiredRouting()) {
00467                 Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
00468                 Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
00469             }
00470         } else if ((!slhp->linkup_  || !peer_slhp->linkup_) && 
00471             !link_down_flag_) {
00472             slhp->linkup_ = TRUE;
00473             peer_slhp->linkup_ = TRUE;
00474             link_changes_flag_ = TRUE;
00475         }
00476     }
00477 
00478     // Now, work on interplane ISLs (intraplane ISLs are not handed off)
00479     
00480     // Now search for interplane ISLs
00481     for (slhp = (SatLinkHead*) local_->linklisthead().lh_first; slhp; 
00482         slhp = (SatLinkHead*) slhp->nextlinkhead() ) {
00483         if (slhp->type() != LINK_ISL_INTERPLANE)  
00484             continue;
00485         if (fabs(sat_latitude_) > lat_threshold_)
00486             link_down_flag_ = TRUE;
00487         else
00488             link_down_flag_ = FALSE;
00489         peer_ = get_peer(slhp);
00490         peer_slhp = get_peer_linkhead(slhp);
00491         peer_coord_ = peer_->position()->coord();
00492         peer_latitude_ = SatGeometry::get_latitude(peer_coord_);
00493         if (fabs(peer_latitude_) > lat_threshold_)
00494             link_down_flag_ = TRUE;
00495         link_down_flag_ |= !(SatGeometry::are_satellites_mutually_visible(peer_coord_, local_coord_));
00496         if (slhp->linkup_ && link_down_flag_) {
00497             // Take links down if either satellite at high latitude
00498             slhp->linkup_ = FALSE;
00499             peer_slhp->linkup_ = FALSE;
00500             link_changes_flag_ = TRUE;
00501             // wired-satellite integration
00502             if (SatRouteObject::instance().wiredRouting()) {
00503                 Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
00504                 Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
00505             }                                                       
00506         } else if (!slhp->linkup_ && !link_down_flag_) {
00507             slhp->linkup_ = TRUE;
00508             peer_slhp->linkup_ = TRUE;
00509             link_changes_flag_ = TRUE;
00510         }
00511     }
00512     if (link_changes_flag_)  {
00513         SatRouteObject::instance().recompute();
00514     }
00515     if (handoff_randomization_) {
00516         timer_.resched(sat_handoff_int_ + 
00517             handoff_rng_.uniform(-1 * sat_handoff_int_/2, 
00518             sat_handoff_int_/2));
00519     } else
00520         timer_.resched(sat_handoff_int_);
00521     return link_changes_flag_;
00522 }

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