sathandoff.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:19k
- /* -*- 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: /cvsroot/nsnam/ns-2/satellite/sathandoff.cc,v 1.11 2005/08/22 05:08:34 tomh Exp $";
- #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 handoffn");
- 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 %dn", 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 receiversn");
- return 0;
- }
- remote_node_ = remote_phy_->head()->node();
- if (remote_phy_->nextchnl()) {
- printf("Error: This ISL channel has more than one targetn");
- 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) {
- // this is not an error as far as satellite GSL endpoints
- // appear to be concerned.
- // Commented out for drawing GSL links in dumpSats()
- // in satnode.cc
- // printf("Error: node %d's tx phy ", slhp->node()->address());
- // printf("connected to channel with no receiversn");
- return 0;
- }
- if (remote_phy_->nextchnl()) {
- printf("Error: This ISL channel has more than one targetn");
- 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_ = 0; // 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 %fn", 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
- // Next line removes phy from linked list
- // of interfaces attached to channel
- slhp->phy_rx()->removechnl();
- // Set our channel pointers to NULL
- slhp->phy_tx()->setchnl(0);
- slhp->phy_rx()->setchnl(0);
- // wired-satellite integration
- if (SatRouteObject::instance().wiredRouting()) {
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
- // Must do this bidirectionally
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
- }
- }
- }
- 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()) {
- if (!SatNode::IsASatNode(nodep->address()))
- continue;
- 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_ > 0.0) {
- assert (best_peer_ != 0);
- 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());
- // Add phy to channel's linked list of i/fces
- 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'' fieldn");
- 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;
- // wired-satellite integration
- if (SatRouteObject::instance().wiredRouting()) {
- // Check if link is up first before deleting
- if (slhp->linkup_) {
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
- }
- if (peer_slhp->linkup_) {
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
- }
- }
- // 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;
- // wired-satellite integration
- if (SatRouteObject::instance().wiredRouting()) {
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
- }
- } 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;
- // wired-satellite integration
- if (SatRouteObject::instance().wiredRouting()) {
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", slhp->phy_tx()->node()->address(), peer_->address());
- Tcl::instance().evalf("[Simulator instance] sat_link_destroy %d %d", peer_->address(), slhp->phy_tx()->node()->address());
- }
- } 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_;
- }