ls.cc

Go to the documentation of this file.
00001 
00002 /*
00003  * ls.cc
00004  * Copyright (C) 2000 by the University of Southern California
00005  * $Id: ls.cc,v 1.5 2005/08/25 18:58:06 johnh Exp $
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License,
00009  * version 2, as published by the Free Software Foundation.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with this program; if not, write to the Free Software Foundation, Inc.,
00018  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00019  *
00020  *
00021  * The copyright of this module includes the following
00022  * linking-with-specific-other-licenses addition:
00023  *
00024  * In addition, as a special exception, the copyright holders of
00025  * this module give you permission to combine (via static or
00026  * dynamic linking) this module with free software programs or
00027  * libraries that are released under the GNU LGPL and with code
00028  * included in the standard release of ns-2 under the Apache 2.0
00029  * license or under otherwise-compatible licenses with advertising
00030  * requirements (or modified versions of such code, with unchanged
00031  * license).  You may copy and distribute such a system following the
00032  * terms of the GNU GPL for this module and the licenses of the
00033  * other code concerned, provided that you include the source code of
00034  * that other code when and as the GNU GPL requires distribution of
00035  * source code.
00036  *
00037  * Note that people who make modified versions of this module
00038  * are not obligated to grant this special exception for their
00039  * modified versions; it is their choice whether to do so.  The GNU
00040  * General Public License gives permission to release a modified
00041  * version without this exception; this exception also makes it
00042  * possible to release a modified version which carries forward this
00043  * exception.
00044  *
00045  */
00046 //
00047 // Other copyrights might apply to parts of this software and are so
00048 // noted when applicable.
00049 //
00050 //  Copyright (C) 1998 by Mingzhou Sun. All rights reserved.
00051 //  This software is developed at Rensselaer Polytechnic Institute under 
00052 //  DARPA grant No. F30602-97-C-0274
00053 //  Redistribution and use in source and binary forms are permitted
00054 //  provided that the above copyright notice and this paragraph are
00055 //  duplicated in all such forms and that any documentation, advertising
00056 //  materials, and other materials related to such distribution and use
00057 //  acknowledge that the software was developed by Mingzhou Sun at the
00058 //  Rensselaer  Polytechnic Institute.  The name of the University may not 
00059 //  be used to endorse or promote products derived from this software 
00060 //  without specific prior written permission.
00061 //
00062 // $Header: /nfs/jade/vint/CVSROOT/ns-2/linkstate/ls.cc,v 1.5 2005/08/25 18:58:06 johnh Exp $
00063 
00064 #include "config.h"
00065 #ifdef HAVE_STL
00066 
00067 #include "ls.h"
00068 
00069 // a global variable
00070 LsMessageCenter LsMessageCenter::msgctr_;
00071 
00072 int LsRouting::msgSizes[LS_MESSAGE_TYPES];
00073 
00074 static class initRouting {
00075 public:
00076     initRouting() {
00077         LsRouting::msgSizes[LS_MSG_LSA] = LS_LSA_MESSAGE_SIZE;
00078         LsRouting::msgSizes[LS_MSG_TPM] =  LS_TOPO_MESSAGE_SIZE;
00079         LsRouting::msgSizes[LS_MSG_LSAACK] = LS_ACK_MESSAGE_SIZE;
00080         LsRouting::msgSizes[LS_MSG_TPMACK] = LS_ACK_MESSAGE_SIZE;
00081     }
00082 } lsRoutingInitializer;
00083 
00084 static void ls_error(char* msg) 
00085 { 
00086     fprintf(stderr, "%s\n", msg);
00087     abort();
00088 }
00089 
00090 /*
00091   LsNodeIdList methods
00092 */
00093 int LsNodeIdList::appendUnique (const LsNodeIdList & x) 
00094 {
00095     int newHopCount = 0;
00096     for (LsNodeIdList::const_iterator itr1 = x.begin(); 
00097          itr1 != x.end(); itr1++) {
00098         LsNodeIdList::iterator itr2;
00099         for (itr2 = begin(); itr2 != end(); itr2++)
00100             // check for duplicate
00101             if ((*itr1) == (*itr2))
00102                 break;
00103         if (itr2 == end()) {
00104             // no duplicate, insert it 
00105             push_back(*itr1);
00106             newHopCount++; // forgot what newHopCount is used for
00107         }
00108     }
00109     return newHopCount;
00110 }
00111 
00112 /*
00113   LsTopoMap methods
00114 */
00115 LsLinkStateList * 
00116 LsTopoMap::insertLinkState (int nodeId, const LsLinkState& linkState)
00117 {
00118     LsLinkStateList* lsp = LsLinkStateListMap::findPtr(nodeId);
00119     if (lsp != NULL) {
00120         // there's a node with other linkState, not checking if there's
00121         // duplicate
00122         lsp->push_back(linkState);
00123         return lsp;
00124     }
00125     // else new node
00126     LsLinkStateList lsl; // an empty one
00127     iterator itr = insert(nodeId, lsl);
00128     if (itr !=end()){
00129         // successful
00130         (*itr).second.push_back(linkState);
00131         return &((*itr).second);
00132     }
00133     // else something is wrong
00134     ls_error("LsTopoMap::insertLinkState failed\n"); // debug
00135     return (LsLinkStateList *) NULL;
00136 }
00137 
00138 // -- update --, return true if anything's changed 
00139 bool LsTopoMap::update(int nodeId, 
00140                const LsLinkStateList& linkStateList)
00141 {
00142     LsLinkStateList * LSLptr = findPtr (nodeId);
00143     if (LSLptr == NULL) {
00144         insert(nodeId, linkStateList);
00145         return true;
00146     }
00147 
00148     bool retCode = false;
00149     LsLinkStateList::iterator itrOld;
00150     for (LsLinkStateList::const_iterator itrNew = linkStateList.begin();
00151          itrNew != linkStateList.end(); itrNew++ ) {
00152   
00153         for (itrOld = LSLptr->begin();
00154              itrOld != LSLptr->end(); itrOld++) {
00155 
00156             if ((*itrNew).neighborId_ == (*itrOld).neighborId_) {
00157                 // old link state found
00158                 if (nodeId != myNodeId_)
00159                     // update the sequence number, if 
00160                     // it's not  my own link state
00161                     (*itrOld).sequenceNumber_ = 
00162                         (*itrNew).sequenceNumber_;
00163                 if ((*itrNew).status_ != (*itrOld).status_) {
00164                     (*itrOld).status_ = (*itrNew).status_;
00165                     retCode = true;
00166                 }
00167                 if ((*itrNew).cost_ != (*itrOld).cost_) {
00168                     (*itrOld).cost_ = (*itrNew).cost_;
00169                     retCode = true;
00170                 }
00171                 break; // no need to search for more old link state;
00172             } // end if old link state found
00173         } // end for old link states
00174         if (itrOld == LSLptr->end()) {
00175             // no old link found
00176             LSLptr->push_back(*itrNew);
00177             retCode = true;
00178         }
00179     }// end for new link states 
00180     return retCode;
00181 }
00182 
00183 /*
00184   LsPaths methods
00185 */
00186 
00187 // insertPath(), returns end() if error, else return iterator 
00188 LsPaths::iterator LsPaths::insertPath(int destId, int cost, int nextHop) 
00189 {
00190     iterator itr = LsEqualPathsMap::find(destId);
00191     // if new path, insert it and return iterator
00192     if (itr == end())
00193         return insertPathNoChecking(destId, cost, nextHop);
00194 
00195     LsEqualPaths * ptrEP = &(*itr).second;
00196     // if the old path is better, ignore it, return end() 
00197     // to flag the error
00198     if (ptrEP->cost < cost)
00199         return end(); 
00200     // else if the new path is better, erase the old ones and save the new one
00201     LsNodeIdList & nhList = ptrEP->nextHopList;
00202     if (ptrEP->cost > cost) {
00203         ptrEP->cost = cost;
00204         nhList.erase(nhList.begin(), nhList.end());
00205         nhList.push_back(nextHop);
00206         return itr;
00207     }
00208     // else the old path is the same cost, check for duplicate
00209     for (LsNodeIdList::iterator itrList = nhList.begin();
00210          itrList != nhList.end(); itrList++)
00211         // if duplicate found, return 0 to flag the error 
00212         if ((*itrList) == nextHop)
00213             return end(); 
00214     // else, the new path is installed indeed, the total number of nextHops
00215     // is returned. 
00216     nhList.push_back(nextHop);
00217     return itr;
00218 }
00219 
00220 LsPaths::iterator 
00221 LsPaths::insertNextHopList(int destId, int cost, 
00222                const LsNodeIdList& nextHopList) 
00223 {
00224     iterator itr = LsEqualPathsMap::find(destId);
00225     // if new path, insert it and return iterator 
00226     if (itr == end()) {
00227         LsEqualPaths ep(cost, nextHopList);
00228         itr = insert(destId, ep);
00229         return itr;
00230     }
00231     // else get the old ep
00232     LsEqualPaths* ptrOldEp = &(*itr).second;
00233     // if the old path is better, ignore it, return end() to flag error
00234     if (ptrOldEp->cost < cost)
00235         return end();
00236     // else if the new path is better, replace the old one with the new one
00237     if (ptrOldEp->cost > cost) {
00238         ptrOldEp->cost = cost;
00239         ptrOldEp->nextHopList = nextHopList ; // copy
00240         return itr;
00241     }
00242     // equal cost: append the new next hops with checking for duplicates
00243     ptrOldEp->appendNextHopList(nextHopList);
00244     return itr;
00245 }
00246 
00247 /*
00248   LsPathsTentative methods
00249 */
00250 LsPath LsPathsTentative::popShortestPath() 
00251 {
00252     findMinEqualPaths();
00253     LsPath path;
00254     if (empty() || (minCostIterator == end()))
00255         return path; // an invalid one
00256 
00257     LsNodeIdList& nhList = (*minCostIterator).second.nextHopList;
00258     if (nhList.empty() && (findMinEqualPaths() == end()))
00259         return path;
00260     path.destination = (*minCostIterator).first;
00261     path.cost=(*minCostIterator).second.cost;
00262 
00263     // the first 'nextHop'
00264     path.nextHop = nhList.front();
00265     nhList.pop_front();
00266 
00267     // if this pops out the last nextHop in the EqualPaths, find a new one.
00268     if (nhList.empty()) {
00269         erase(minCostIterator);
00270         findMinEqualPaths();
00271     }
00272 
00273     return path;
00274 }
00275 
00276 LsPathsTentative::iterator LsPathsTentative::findMinEqualPaths()
00277 {
00278     minCost = LS_MAX_COST + 1; 
00279     minCostIterator = end();
00280     for (iterator itr = begin(); itr != end(); itr++){
00281         if ((minCost > (*itr).second.cost) && 
00282             !(*itr).second.nextHopList.empty()) {
00283             minCost = (*itr).second.cost;
00284             minCostIterator = itr;
00285         }
00286     }
00287     return minCostIterator;
00288 }
00289 
00290 /*
00291   LsMessageCenter methods
00292 */
00293 
00294 LsMessage* LsMessageCenter::newMessage(int nodeId, ls_message_type_t type) 
00295 {
00296     // check if max_message_number is invalid, call init ()
00297     if (max_size == 0)
00298         init(); 
00299 
00300     // if max_size reached, recycle
00301     message_storage* storagePtr;
00302     u_int32_t currentId;
00303 
00304     // current_lsa_id and current_other_id are odd and even, respectively
00305     if ((type == LS_MSG_LSA) || (type == LS_MSG_TPM)) { 
00306         storagePtr = & lsa_messages;
00307         currentId = current_lsa_id;
00308         if ((current_lsa_id += 2) == LS_INVALID_MESSAGE_ID)  
00309             current_lsa_id += 2;
00310     } else {
00311         storagePtr = &other_messages;
00312         currentId = current_other_id;
00313         if ((current_other_id += 2) == LS_INVALID_MESSAGE_ID)  
00314             current_other_id +=2;
00315     }
00316 
00317     if (storagePtr->size() >= max_size)
00318         storagePtr->erase(storagePtr->begin());
00319 
00320     LsMessage* msgPtr = (LsMessage *)NULL;
00321     message_storage::iterator itr = 
00322         storagePtr->insert(currentId, 
00323                    LsMessage(currentId, nodeId, type));
00324     if (itr == storagePtr->end())
00325         ls_error("Can't insert new message in "
00326              "LsMessageCenter::newMessage.\n");
00327     else
00328         msgPtr = &((*itr).second);
00329     return msgPtr;
00330 }
00331 
00332 bool LsMessageCenter::deleteMessage(u_int32_t msgId)
00333 {
00334     message_storage::iterator itr = other_messages.find (msgId); 
00335     if (itr == other_messages.end())
00336         return false;
00337     other_messages.erase(itr);
00338     return true;
00339 }
00340 
00341 // init()
00342 void LsMessageCenter::init() 
00343 {
00344     // only when nothing is provided by tcl code
00345     max_size = 300;
00346 }
00347 
00348 /*
00349   LsMessageHistory methods 
00350 */
00351 
00352 // TODO, rewrite this method for topo message
00353 bool LsMessageHistory::isNewMessage ( const LsMessage& msg ) 
00354 {
00355     iterator itr = find(msg.originNodeId_);
00356     if (itr != end()) {
00357         if (((*itr).second < msg.sequenceNumber_) || 
00358             ((*itr).second - msg.sequenceNumber_ > 
00359              LS_WRAPAROUND_THRESHOLD)) {
00360             // The new message is more up-to-date than the old one
00361             (*itr).second = msg.sequenceNumber_;
00362             return true;
00363         } else {
00364             // We had a more up-to-date or same message from 
00365             // this node before
00366             return false;
00367         }
00368     } else {
00369         // We never received message from this node before 
00370         insert(msg.originNodeId_, msg.sequenceNumber_);
00371         return true;
00372     }
00373  
00374 }
00375 
00376 /* LsRetransmissionManager Methods */
00377 
00378 void LsRetransmissionManager::initTimeout(LsDelayMap * delayMapPtr) 
00379 {
00380     if (delayMapPtr == NULL)
00381         return;
00382     for (LsDelayMap::iterator itr = delayMapPtr->begin();
00383          itr != delayMapPtr->end(); itr++)
00384         // timeout is LS_TIMEOUT_FACTOR*one-way-delay estimate
00385         insert((*itr).first, 
00386                LsUnackPeer(this, (*itr).first, 
00387                    LS_TIMEOUT_FACTOR*(*itr).second));
00388 }
00389 
00390 void LsRetransmissionManager::cancelTimer (int nbrId) 
00391 {
00392     LsUnackPeer* peerPtr = findPtr(nbrId);
00393     if (peerPtr == NULL) 
00394         return;
00395     peerPtr->tpmSeq_ = LS_INVALID_MESSAGE_ID;
00396     peerPtr->lsaMap_.eraseAll();
00397     peerPtr->timer_.force_cancel();
00398 }
00399 
00400 // Called by LsRouting when a message is sent out
00401 int LsRetransmissionManager::messageOut(int peerId, 
00402                     const LsMessage& msg)
00403 {
00404     LsUnackPeer* peerPtr = findPtr(peerId);
00405     if (peerPtr == NULL) {
00406         iterator itr = insert(peerId, LsUnackPeer(this, peerId));
00407         if (itr == end()) { 
00408             ls_error ("Can't insert."); 
00409         }
00410         peerPtr = &((*itr).second);
00411     }
00412     LsIdSeq* idSeqPtr;
00413     switch (msg.type_) {
00414     case LS_MSG_TPM:
00415         peerPtr->tpmSeq_ = msg.sequenceNumber_;
00416         break;
00417     case LS_MSG_LSA:
00418         idSeqPtr =  peerPtr->lsaMap_.findPtr(msg.originNodeId_);
00419         if (idSeqPtr == NULL)
00420             peerPtr->lsaMap_.insert(msg.originNodeId_, 
00421                  LsIdSeq(msg.messageId_, msg.sequenceNumber_));
00422         else {
00423             idSeqPtr->msgId_ = msg.messageId_;
00424             idSeqPtr->seq_ = msg.sequenceNumber_;
00425         }
00426         break;
00427     case LS_MSG_TPMACK:
00428     case LS_MSG_LSAACK:
00429     case LS_MSG_LSM:
00430     default:
00431         // nothing, just to avoid compiler warning
00432         break;
00433     }
00434  
00435     // reschedule timer to allow account for this latest message
00436     peerPtr->timer_.resched(peerPtr->rtxTimeout_);
00437   
00438     return 0;
00439 }
00440   
00441 // Called by LsRouting,  when an ack is received
00442 // Or by messageIn, some the message can serve as ack
00443 int LsRetransmissionManager::ackIn(int peerId, const LsMessage& msg)
00444 {
00445     LsUnackPeer* peerPtr = findPtr(peerId);
00446     if ((peerPtr == NULL) ||
00447         (peerPtr->tpmSeq_ == LS_INVALID_MESSAGE_ID) &&
00448         peerPtr->lsaMap_.empty())
00449         // no pending ack for this neighbor 
00450         return 0;
00451 
00452     LsMap<int, LsIdSeq>::iterator itr;
00453     switch (msg.type_) {
00454     case LS_MSG_TPMACK:
00455         if (peerPtr->tpmSeq_ == msg.sequenceNumber_)
00456             // We've got the right ack, so erase the unack record
00457             peerPtr->tpmSeq_ = LS_INVALID_MESSAGE_ID;
00458         break;
00459     case LS_MSG_LSAACK:
00460         itr = peerPtr->lsaMap_.find(msg.originNodeId_);
00461         if ((itr != peerPtr->lsaMap_.end()) && 
00462             ((*itr).second.seq_ == msg.sequenceNumber_)) 
00463             // We've got the right ack, so erase the unack record
00464             peerPtr->lsaMap_.erase(itr);
00465         break;
00466     case LS_MSG_TPM:
00467     case LS_MSG_LSA: 
00468     case LS_MSG_LSM:
00469     default:
00470         break;
00471     }
00472 
00473     if ((peerPtr->tpmSeq_ == LS_INVALID_MESSAGE_ID) &&
00474         (peerPtr->lsaMap_.empty()))
00475         // No more pending ack, cancel timer
00476         peerPtr->timer_.cancel();
00477 
00478     // ack deleted in calling function LsRouting::receiveMessage
00479     return 0;
00480 }
00481 
00482 // resendMessage
00483 int LsRetransmissionManager::resendMessages (int peerId) 
00484 {
00485     LsUnackPeer* peerPtr = findPtr (peerId);
00486     if (peerPtr == NULL) 
00487         // That's funny, We should never get in here
00488         ls_error ("Wait a minute, nothing to send for this neighbor");
00489 
00490     // resend topo map
00491     if (peerPtr->tpmSeq_ != LS_INVALID_MESSAGE_ID) 
00492         lsRouting_.resendMessage(peerId, peerPtr->tpmSeq_, LS_MSG_TPM);
00493   
00494     // resend all other unack'ed LSA
00495     for (LsMap<int, LsIdSeq>::iterator itr = peerPtr->lsaMap_.begin();
00496          itr != peerPtr->lsaMap_.end(); ++itr)
00497         lsRouting_.resendMessage(peerId, (*itr).second.msgId_, 
00498                      LS_MSG_LSA);
00499 
00500     // reschedule retransmit timer
00501     peerPtr->timer_.resched(peerPtr->rtxTimeout_);
00502     return 0;
00503 } 
00504 
00505 /*
00506   LsRouting methods
00507 */
00508 
00509 bool LsRouting::init(LsNode * nodePtr) 
00510 {
00511     if (nodePtr == NULL) 
00512         return false;
00513 
00514     myNodePtr_ = nodePtr;
00515     myNodeId_ = myNodePtr_->getNodeId();
00516     linkStateDatabase_.setNodeId(myNodeId_);
00517     peerIdListPtr_ = myNodePtr_->getPeerIdListPtr();
00518     linkStateListPtr_ = myNodePtr_->getLinkStateListPtr();
00519     if (linkStateListPtr_ != NULL) 
00520         linkStateDatabase_.insert(myNodeId_, *linkStateListPtr_);
00521 
00522     LsDelayMap* delayMapPtr = myNodePtr_->getDelayMapPtr();
00523     if (delayMapPtr != NULL)
00524         ackManager_.initTimeout(delayMapPtr) ;
00525     return true;
00526 }  
00527 
00528 void LsRouting::linkStateChanged () 
00529 {
00530     if (linkStateListPtr_ == NULL)
00531         ls_error("LsRouting::linkStateChanged: linkStateListPtr null\n");
00532    
00533     LsLinkStateList* oldLsPtr = linkStateDatabase_.findPtr(myNodeId_);
00534     if (oldLsPtr == NULL) 
00535         // Should never happen,something's wrong, we didn't 
00536         // initialize properly
00537         ls_error("LsRouting::linkStateChanged: oldLsPtr null!!\n");
00538 
00539     // save the old link state for processing
00540     LsLinkStateList oldlsl(*oldLsPtr);
00541 
00542     // if there's any changes, compute new routes and send link states
00543     // Note: we do want to send link states before topo
00544     bool changed=linkStateDatabase_.update(myNodeId_, *linkStateListPtr_);
00545     if (changed) {
00546         computeRoutes();
00547         sendLinkStates(/* buffer before sending */ true); 
00548         // tcl code will call sendBufferedMessage
00549     }
00550 
00551     // Check if there's need to send topo or cancel timer
00552     LsLinkStateList::iterator oldLsItr = oldlsl.begin();
00553     for (LsLinkStateList::iterator newLsItr = linkStateListPtr_->begin();
00554           newLsItr != linkStateListPtr_->end();
00555           newLsItr++, oldLsItr++) {
00556         // here we are assuming the two link state list are the same 
00557         // except the status and costs, buggy    
00558         if ((*newLsItr).neighborId_ != (*oldLsItr).neighborId_)
00559             // something's wrong
00560             ls_error("New and old link State list are not aligned.\n");
00561         // if link goes down, clear neighbor's not ack'ed entry
00562         if ((*newLsItr).status_ == LS_STATUS_DOWN)
00563             ackManager_.cancelTimer((*newLsItr).neighborId_);
00564 
00565         if (((*newLsItr).status_ == LS_STATUS_DOWN) || 
00566             ((*oldLsItr).status_ == LS_STATUS_UP))
00567             // Don't have to send out tpm if the link goes from 
00568             // up to down, or it was originally up
00569             continue;
00570         // else we have to set out the whole topology map that we have 
00571         // to our neighbor that just resumes peering with us
00572         // the messages are buffered, will flush the buffer after the 
00573         // routes are installed in the node
00574         // But don't worry, only a const ptr to our topo map is sent
00575         sendTopo( (*newLsItr).neighborId_);
00576     }
00577 }
00578 
00579 /* -- isUp -- */
00580 // a linear search, but not too bad if most nodes will have 
00581 // less than a couple of interfaces
00582 bool LsRouting::isUp(int neighborId) 
00583 {
00584     if (linkStateListPtr_ == NULL) 
00585         return false;
00586 
00587     for (LsLinkStateList::iterator itr = linkStateListPtr_->begin();
00588          itr!= linkStateListPtr_->end(); itr++)
00589         if ((*itr).neighborId_ == neighborId)
00590             return ((*itr).status_ == LS_STATUS_UP) ? true : false;
00591     return false;
00592 }
00593 
00594 /* -- receiveMessage -- */
00595 /* return true if there's a need to re-compute routes */
00596 bool LsRouting::receiveMessage (int senderId, u_int32_t msgId)
00597 {
00598     if (senderId == LS_INVALID_NODE_ID)
00599         return false;
00600     LsMessage* msgPtr = msgctr().retrieveMessagePtr(msgId);
00601     if (msgPtr == NULL)
00602         return false;
00603 
00604     // A switch statement to see the type.
00605     // and handle differently
00606     bool retCode = false;
00607     switch (msgPtr->type_){
00608     case LS_MSG_LSM:
00609         // not supported yet
00610         break;
00611     case LS_MSG_TPM:
00612         retCode = receiveTopo (senderId, msgPtr);
00613         break;
00614     case LS_MSG_LSA:  // Link State Update 
00615         retCode = receiveLSA (senderId, msgPtr);
00616         break;
00617     case LS_MSG_LSAACK: 
00618     case LS_MSG_TPMACK: 
00619         receiveAck(senderId, msgPtr);
00620         msgctr().deleteMessage(msgId);
00621         break;
00622     default:
00623         break;
00624     }
00625     return retCode;
00626 }
00627 
00628 // LsRouting::receiveAck is in-line in header file
00629 bool LsRouting::receiveLSA(int senderId, LsMessage* msgPtr)
00630 {
00631     if (msgPtr == NULL) 
00632         return false;
00633     u_int32_t msgId = msgPtr->messageId_;
00634     int originNodeId = msgPtr->originNodeId_;
00635 
00636     sendAck(senderId, LS_MSG_LSAACK, originNodeId, msgId);
00637        
00638     if ((originNodeId == myNodeId_) ||
00639          !lsaHistory_.isNewMessage(*msgPtr)) 
00640         return false; 
00641 
00642     // looks like we've got a new message LSA
00643     int peerId;
00644     if ((peerIdListPtr_ != NULL) && (myNodePtr_ != NULL)) {
00645         // forwards to peers whose links are up, except the sender 
00646         // and the originator 
00647         for (LsNodeIdList::iterator itr = peerIdListPtr_->begin();
00648              itr != peerIdListPtr_->end(); itr++) {
00649             peerId = *itr;
00650             if ((peerId == originNodeId) || (peerId == senderId))
00651                 continue; 
00652             if (isUp(peerId) && ((peerId) != senderId)) {
00653                 ackManager_.messageOut(peerId, *msgPtr);
00654                 myNodePtr_->sendMessage(peerId, msgId);
00655             }
00656         }
00657     }
00658 
00659     // Get the content of the message 
00660     if (msgPtr->contentPtr_ == NULL) 
00661         return false;
00662     bool changed = linkStateDatabase_.update(msgPtr->originNodeId_,
00663                          *(msgPtr->lslPtr_));
00664     if (changed)
00665         // linkstate database has changed, re-compute routes
00666         computeRoutes();
00667     return changed;
00668 }
00669 
00670 
00671 // -- sendLinkStates --
00672 bool LsRouting::sendLinkStates(bool buffer /* = false */) 
00673 {
00674     if (myNodePtr_ == NULL)
00675         return false;
00676     if ((peerIdListPtr_ == NULL) || peerIdListPtr_->empty())
00677         return false;
00678 
00679     LsLinkStateList* myLSLptr = linkStateDatabase_.findPtr(myNodeId_);
00680     if ((myLSLptr == NULL) || myLSLptr->empty())
00681         return false;
00682 
00683     LsMessage* msgPtr = msgctr().newMessage(myNodeId_, LS_MSG_LSA);
00684     if (msgPtr == NULL) 
00685         return false; // can't get new message
00686 
00687     u_int32_t msgId = msgPtr->messageId_;
00688     u_int32_t seq = msgPtr->sequenceNumber_;
00689     // update the sequence number in my own data base
00690     for (LsLinkStateList::iterator itr = myLSLptr->begin();
00691          itr != myLSLptr->end(); itr++)
00692         (*itr).sequenceNumber_ = seq;
00693   
00694     LsLinkStateList* newLSLptr = new LsLinkStateList( *myLSLptr);
00695     if (newLSLptr == NULL) {
00696         ls_error ("Can't get new link state list, in LsRouting::sendLinkStates\n");
00697         // can't get new link state list
00698         msgctr().deleteMessage(msgId);
00699         return false;
00700     }
00701 
00702     msgPtr->lslPtr_ = newLSLptr;
00703     for (LsNodeIdList::iterator itr = peerIdListPtr_->begin();
00704          itr != peerIdListPtr_->end(); itr++) {
00705         if (!isUp(*itr))
00706             continue; // link is down 
00707         if (!buffer) {
00708             myNodePtr_->sendMessage((*itr), msgId);
00709             ackManager_.messageOut((*itr), *msgPtr);
00710         } else {
00711             // put in buffer for later sending
00712             bufferedSend((*itr), msgPtr);
00713         }
00714     }
00715     return true;
00716 }
00717 
00718 // send acknowledgment, called self
00719 bool LsRouting::sendAck (int nbrId, ls_message_type_t type, 
00720              int originNodeIdAcked, u_int32_t seqAcked) 
00721 {
00722     // Get a new message fom messageCenter
00723     LsMessage * msgPtr = msgctr().newMessage(myNodeId_, type);
00724     if (msgPtr == NULL)
00725         return false; // can't get new message
00726 
00727     u_int32_t msgId = msgPtr->messageId_;
00728     // fill in the blank
00729     // msgPtr->type = type;
00730     msgPtr->originNodeId_ = originNodeIdAcked;
00731     msgPtr->sequenceNumber_ = seqAcked;
00732 
00733     // Call node to send out message
00734     myNodePtr_->sendMessage (nbrId, msgId, LS_ACK_MESSAGE_SIZE);
00735     return true;
00736 }
00737 
00738 // After a link comes up, receive Topology update from the 
00739 // corresponding neighbor
00740 bool LsRouting::receiveTopo(int neighborId, LsMessage * msgPtr)
00741 {
00742     // TODO
00743     bool changed = false;
00744     // send Ack 
00745     sendAck(neighborId, LS_MSG_TPMACK, neighborId, 
00746         msgPtr->sequenceNumber_);
00747     // check if it's a new message
00748     if (!tpmHistory_.isNewMessage(*msgPtr))
00749         return false;
00750 
00751     if (msgPtr->topoPtr_ == NULL)
00752         return false;
00753     // Compare with my own database
00754     for (LsTopoMap::const_iterator recItr = msgPtr->topoPtr_->begin();
00755          recItr != msgPtr->topoPtr_->end(); recItr++) {
00756 
00757         if ((*recItr).first == myNodeId_)
00758             // Don't need peer to tell me my own link state 
00759             continue; 
00760         // find my own record of the LSA of the node being examined
00761         LsLinkStateList* myRecord = 
00762             linkStateDatabase_.findPtr((*recItr).first);
00763 
00764         if ((myRecord == NULL) || // we don't have it
00765             myRecord->empty() ||
00766             // or we have an older record
00767             ((*(myRecord->begin())).sequenceNumber_ <
00768              (*((*recItr).second.begin())).sequenceNumber_) ||
00769             ((*(myRecord->begin())).sequenceNumber_ - 
00770              (*((*recItr).second.begin())).sequenceNumber_ > 
00771              LS_WRAPAROUND_THRESHOLD)) {
00772 
00773             // Update our database
00774             changed = true;
00775             if (myRecord == NULL)
00776                 linkStateDatabase_.insert((*recItr).first, 
00777                              (*recItr).second);
00778             else 
00779                 *myRecord = (*recItr).second ;
00780             // Regenerate the LSA message and send to my peers, 
00781             // except the sender of the topo and the 
00782             // originator of the LSA
00783             regenAndSend (/* to except */neighborId, 
00784                       /* originator */(*recItr).first, 
00785                       /* the linkstateList */(*recItr).second);
00786         }
00787     }
00788     if (changed)
00789         computeRoutes();
00790     // if anything relevant has changed, recompute routes
00791     return changed;
00792 }
00793 
00794 // replicate a LSA and send it out
00795 void LsRouting::regenAndSend(int exception, int origin, 
00796                  const LsLinkStateList& lsl)
00797 {
00798     if (lsl.empty())
00799         ls_error("lsl is empty, in LsRouting::regenAndSend.\n");
00800     LsLinkStateList* newLSLptr = new LsLinkStateList(lsl);
00801     if (newLSLptr == NULL) { 
00802         ls_error("Can't get new link state list, in "
00803              "LsRouting::sendLinkStates\n");
00804         return;
00805     }
00806 
00807     // replicate the LSA 
00808     LsMessage* msgPtr =  msgctr().newMessage(origin, LS_MSG_LSA);
00809     msgPtr->sequenceNumber_ = (*lsl.begin()).sequenceNumber_;
00810     msgPtr->originNodeId_ = origin;
00811 
00812     for (LsNodeIdList::iterator itr = peerIdListPtr_->begin();
00813          itr != peerIdListPtr_->end(); itr++) {
00814         if ((*itr == origin) || (*itr == exception) || !isUp(*itr))
00815             continue; 
00816         bufferedSend(*itr, msgPtr);
00817         // debug 
00818 //          cout << "Node " << myNodeId << " regenAndSend " 
00819 //               << (*(lsl.begin())).sequenceNumber << " from origin  " << origin 
00820 //               << " to peer " << *itr << endl;
00821     }
00822 }
00823                
00824 // After a link comes up, receive Topo with the corresponding neighbor
00825 void LsRouting::sendTopo(int neighborId) 
00826 {
00827     // if we've gone so far, messageCenterPtr should not be null, 
00828     // don't check
00829     LsMessage* msgPtr= msgctr().newMessage(myNodeId_, LS_MSG_TPM);
00830     // XXX, here we are going to send the pointer that points
00831     // to my own topo, because sending the who topomap is too costly in
00832     // simulation
00833     msgPtr->contentPtr_ = &linkStateDatabase_;
00834     bufferedSend(neighborId, msgPtr);
00835 }
00836 
00837 void LsRouting::sendBufferedMessages()
00838 {
00839     for (MessageBuffer::iterator itr = messageBuffer_.begin();
00840          itr != messageBuffer_.end(); itr++) {
00841         ackManager_.messageOut((*itr).peerId_, *((*itr).msgPtr_));
00842         myNodePtr_->sendMessage((*itr).peerId_, 
00843                     (*itr).msgPtr_->messageId_,
00844                     msgSizes[(*itr).msgPtr_->type_]);
00845     }
00846     messageBuffer_.eraseAll();
00847 }
00848 
00849 // private _computeRoutes, called by public computeRoutes
00850 LsPaths* LsRouting::_computeRoutes () 
00851 {
00852     LsPathsTentative* pTentativePaths = new LsPathsTentative();
00853     LsPaths* pPaths = new LsPaths() ; // to be returned; 
00854  
00855     // step 1. put myself in path
00856     LsPath toSelf(myNodeId_, 0, myNodeId_); // zero cost, nextHop is myself
00857     pPaths->insertPathNoChecking(toSelf);
00858     int newNodeId = myNodeId_;
00859     LsLinkStateList * ptrLSL = linkStateDatabase_.findPtr(newNodeId);
00860     if (ptrLSL == NULL )
00861         // don't have my own linkState
00862         return pPaths;
00863 
00864     bool done = false;
00865     // start the loop
00866     while (! done) {
00867         // Step 2. for the new node just put in path
00868         // find the next hop to the new node
00869         LsNodeIdList nhl;
00870         LsNodeIdList *nhlp = &nhl; // nextHopeList pointer
00871     
00872         if (newNodeId != myNodeId_) {
00873             // if not looking at my own links, find the next hop 
00874             // to new node
00875             nhlp = pPaths->lookupNextHopListPtr(newNodeId);
00876             if (nhlp == NULL)
00877                 ls_error("computeRoutes: nhlp == NULL \n");
00878         }
00879         // for each of it's links
00880         for (LsLinkStateList::iterator itrLink = ptrLSL->begin();
00881              itrLink != ptrLSL->end(); itrLink++) {
00882             if ((*itrLink).status_ != LS_STATUS_UP)
00883                 // link is not up, skip this link
00884                 continue;
00885             int dest = (*itrLink).neighborId_;
00886             int path_cost = (*itrLink).cost_ + 
00887                 pPaths->lookupCost(newNodeId);
00888             if (pPaths->lookupCost(dest) < path_cost)
00889                 // better path already in paths, 
00890                 // move on to next link
00891                 continue;
00892             else {
00893                 // else we have a new or equally good path, 
00894                 // LsPathsTentative::insertPath(...) will 
00895                 // take care of checking if the new path is
00896                 // a better or equally good one, etc.
00897                 LsNodeIdList nextHopList;
00898                 if (newNodeId == myNodeId_) {
00899                     // destination is directly connected, 
00900                     // nextHop is itself
00901                     nextHopList.push_back(dest);
00902                     nhlp = &nextHopList;
00903                 }
00904                 pTentativePaths->insertNextHopList(dest, 
00905                            path_cost, *nhlp);
00906             }
00907         }
00908         done = true;
00909         // if tentatives empty, terminate;
00910         while (!pTentativePaths->empty()) {
00911             // else pop shortest path triple from tentatives
00912             LsPath sp = pTentativePaths->popShortestPath();
00913             if (!sp.isValid())
00914                 ls_error (" popShortestPath() failed\n");
00915             // install the newly found shortest path among 
00916             // tentatives
00917             pPaths->insertPath(sp);
00918             newNodeId = sp.destination;
00919             ptrLSL = linkStateDatabase_.findPtr(newNodeId);
00920             if (ptrLSL != NULL) {
00921                 // if we have the link state for the new node
00922                 // break out of inner do loop to continue 
00923                 // computing routes
00924                 done = false;
00925                 break;
00926             } 
00927             // else  we don't have linkstate for this new node, 
00928             // we need to keep popping shortest paths
00929         }
00930 
00931     } // endof while ( ! done );
00932     delete pTentativePaths;
00933     return pPaths;
00934 }
00935 
00936 #endif //HAVE_STL

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