/* * ls.cc * Copyright (C) 2000 by the University of Southern California * $Id: ls.cc,v 1.5 2005/08/25 18:58:06 johnh Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * * The copyright of this module includes the following * linking-with-specific-other-licenses addition: * * In addition, as a special exception, the copyright holders of * this module give you permission to combine (via static or * dynamic linking) this module with free software programs or * libraries that are released under the GNU LGPL and with code * included in the standard release of ns-2 under the Apache 2.0 * license or under otherwise-compatible licenses with advertising * requirements (or modified versions of such code, with unchanged * license). You may copy and distribute such a system following the * terms of the GNU GPL for this module and the licenses of the * other code concerned, provided that you include the source code of * that other code when and as the GNU GPL requires distribution of * source code. * * Note that people who make modified versions of this module * are not obligated to grant this special exception for their * modified versions; it is their choice whether to do so. The GNU * General Public License gives permission to release a modified * version without this exception; this exception also makes it * possible to release a modified version which carries forward this * exception. * */ // // Other copyrights might apply to parts of this software and are so // noted when applicable. // // Copyright (C) 1998 by Mingzhou Sun. All rights reserved. // This software is developed at Rensselaer Polytechnic Institute under // DARPA grant No. F30602-97-C-0274 // Redistribution and use in source and binary forms are permitted // provided that the above copyright notice and this paragraph are // duplicated in all such forms and that any documentation, advertising // materials, and other materials related to such distribution and use // acknowledge that the software was developed by Mingzhou Sun at the // Rensselaer Polytechnic Institute. The name of the University may not // be used to endorse or promote products derived from this software // without specific prior written permission. // // $Header: /nfs/jade/vint/CVSROOT/ns-2/linkstate/ls.cc,v 1.5 2005/08/25 18:58:06 johnh Exp $ #include "config.h" #ifdef HAVE_STL #include "ls.h" // a global variable LsMessageCenter LsMessageCenter::msgctr_; int LsRouting::msgSizes[LS_MESSAGE_TYPES]; static class initRouting { public: initRouting() { LsRouting::msgSizes[LS_MSG_LSA] = LS_LSA_MESSAGE_SIZE; LsRouting::msgSizes[LS_MSG_TPM] = LS_TOPO_MESSAGE_SIZE; LsRouting::msgSizes[LS_MSG_LSAACK] = LS_ACK_MESSAGE_SIZE; LsRouting::msgSizes[LS_MSG_TPMACK] = LS_ACK_MESSAGE_SIZE; } } lsRoutingInitializer; static void ls_error(char* msg) { fprintf(stderr, "%s\n", msg); abort(); } /* LsNodeIdList methods */ int LsNodeIdList::appendUnique (const LsNodeIdList & x) { int newHopCount = 0; for (LsNodeIdList::const_iterator itr1 = x.begin(); itr1 != x.end(); itr1++) { LsNodeIdList::iterator itr2; for (itr2 = begin(); itr2 != end(); itr2++) // check for duplicate if ((*itr1) == (*itr2)) break; if (itr2 == end()) { // no duplicate, insert it push_back(*itr1); newHopCount++; // forgot what newHopCount is used for } } return newHopCount; } /* LsTopoMap methods */ LsLinkStateList * LsTopoMap::insertLinkState (int nodeId, const LsLinkState& linkState) { LsLinkStateList* lsp = LsLinkStateListMap::findPtr(nodeId); if (lsp != NULL) { // there's a node with other linkState, not checking if there's // duplicate lsp->push_back(linkState); return lsp; } // else new node LsLinkStateList lsl; // an empty one iterator itr = insert(nodeId, lsl); if (itr !=end()){ // successful (*itr).second.push_back(linkState); return &((*itr).second); } // else something is wrong ls_error("LsTopoMap::insertLinkState failed\n"); // debug return (LsLinkStateList *) NULL; } // -- update --, return true if anything's changed bool LsTopoMap::update(int nodeId, const LsLinkStateList& linkStateList) { LsLinkStateList * LSLptr = findPtr (nodeId); if (LSLptr == NULL) { insert(nodeId, linkStateList); return true; } bool retCode = false; LsLinkStateList::iterator itrOld; for (LsLinkStateList::const_iterator itrNew = linkStateList.begin(); itrNew != linkStateList.end(); itrNew++ ) { for (itrOld = LSLptr->begin(); itrOld != LSLptr->end(); itrOld++) { if ((*itrNew).neighborId_ == (*itrOld).neighborId_) { // old link state found if (nodeId != myNodeId_) // update the sequence number, if // it's not my own link state (*itrOld).sequenceNumber_ = (*itrNew).sequenceNumber_; if ((*itrNew).status_ != (*itrOld).status_) { (*itrOld).status_ = (*itrNew).status_; retCode = true; } if ((*itrNew).cost_ != (*itrOld).cost_) { (*itrOld).cost_ = (*itrNew).cost_; retCode = true; } break; // no need to search for more old link state; } // end if old link state found } // end for old link states if (itrOld == LSLptr->end()) { // no old link found LSLptr->push_back(*itrNew); retCode = true; } }// end for new link states return retCode; } /* LsPaths methods */ // insertPath(), returns end() if error, else return iterator LsPaths::iterator LsPaths::insertPath(int destId, int cost, int nextHop) { iterator itr = LsEqualPathsMap::find(destId); // if new path, insert it and return iterator if (itr == end()) return insertPathNoChecking(destId, cost, nextHop); LsEqualPaths * ptrEP = &(*itr).second; // if the old path is better, ignore it, return end() // to flag the error if (ptrEP->cost < cost) return end(); // else if the new path is better, erase the old ones and save the new one LsNodeIdList & nhList = ptrEP->nextHopList; if (ptrEP->cost > cost) { ptrEP->cost = cost; nhList.erase(nhList.begin(), nhList.end()); nhList.push_back(nextHop); return itr; } // else the old path is the same cost, check for duplicate for (LsNodeIdList::iterator itrList = nhList.begin(); itrList != nhList.end(); itrList++) // if duplicate found, return 0 to flag the error if ((*itrList) == nextHop) return end(); // else, the new path is installed indeed, the total number of nextHops // is returned. nhList.push_back(nextHop); return itr; } LsPaths::iterator LsPaths::insertNextHopList(int destId, int cost, const LsNodeIdList& nextHopList) { iterator itr = LsEqualPathsMap::find(destId); // if new path, insert it and return iterator if (itr == end()) { LsEqualPaths ep(cost, nextHopList); itr = insert(destId, ep); return itr; } // else get the old ep LsEqualPaths* ptrOldEp = &(*itr).second; // if the old path is better, ignore it, return end() to flag error if (ptrOldEp->cost < cost) return end(); // else if the new path is better, replace the old one with the new one if (ptrOldEp->cost > cost) { ptrOldEp->cost = cost; ptrOldEp->nextHopList = nextHopList ; // copy return itr; } // equal cost: append the new next hops with checking for duplicates ptrOldEp->appendNextHopList(nextHopList); return itr; } /* LsPathsTentative methods */ LsPath LsPathsTentative::popShortestPath() { findMinEqualPaths(); LsPath path; if (empty() || (minCostIterator == end())) return path; // an invalid one LsNodeIdList& nhList = (*minCostIterator).second.nextHopList; if (nhList.empty() && (findMinEqualPaths() == end())) return path; path.destination = (*minCostIterator).first; path.cost=(*minCostIterator).second.cost; // the first 'nextHop' path.nextHop = nhList.front(); nhList.pop_front(); // if this pops out the last nextHop in the EqualPaths, find a new one. if (nhList.empty()) { erase(minCostIterator); findMinEqualPaths(); } return path; } LsPathsTentative::iterator LsPathsTentative::findMinEqualPaths() { minCost = LS_MAX_COST + 1; minCostIterator = end(); for (iterator itr = begin(); itr != end(); itr++){ if ((minCost > (*itr).second.cost) && !(*itr).second.nextHopList.empty()) { minCost = (*itr).second.cost; minCostIterator = itr; } } return minCostIterator; } /* LsMessageCenter methods */ LsMessage* LsMessageCenter::newMessage(int nodeId, ls_message_type_t type) { // check if max_message_number is invalid, call init () if (max_size == 0) init(); // if max_size reached, recycle message_storage* storagePtr; u_int32_t currentId; // current_lsa_id and current_other_id are odd and even, respectively if ((type == LS_MSG_LSA) || (type == LS_MSG_TPM)) { storagePtr = & lsa_messages; currentId = current_lsa_id; if ((current_lsa_id += 2) == LS_INVALID_MESSAGE_ID) current_lsa_id += 2; } else { storagePtr = &other_messages; currentId = current_other_id; if ((current_other_id += 2) == LS_INVALID_MESSAGE_ID) current_other_id +=2; } if (storagePtr->size() >= max_size) storagePtr->erase(storagePtr->begin()); LsMessage* msgPtr = (LsMessage *)NULL; message_storage::iterator itr = storagePtr->insert(currentId, LsMessage(currentId, nodeId, type)); if (itr == storagePtr->end()) ls_error("Can't insert new message in " "LsMessageCenter::newMessage.\n"); else msgPtr = &((*itr).second); return msgPtr; } bool LsMessageCenter::deleteMessage(u_int32_t msgId) { message_storage::iterator itr = other_messages.find (msgId); if (itr == other_messages.end()) return false; other_messages.erase(itr); return true; } // init() void LsMessageCenter::init() { // only when nothing is provided by tcl code max_size = 300; } /* LsMessageHistory methods */ // TODO, rewrite this method for topo message bool LsMessageHistory::isNewMessage ( const LsMessage& msg ) { iterator itr = find(msg.originNodeId_); if (itr != end()) { if (((*itr).second < msg.sequenceNumber_) || ((*itr).second - msg.sequenceNumber_ > LS_WRAPAROUND_THRESHOLD)) { // The new message is more up-to-date than the old one (*itr).second = msg.sequenceNumber_; return true; } else { // We had a more up-to-date or same message from // this node before return false; } } else { // We never received message from this node before insert(msg.originNodeId_, msg.sequenceNumber_); return true; } } /* LsRetransmissionManager Methods */ void LsRetransmissionManager::initTimeout(LsDelayMap * delayMapPtr) { if (delayMapPtr == NULL) return; for (LsDelayMap::iterator itr = delayMapPtr->begin(); itr != delayMapPtr->end(); itr++) // timeout is LS_TIMEOUT_FACTOR*one-way-delay estimate insert((*itr).first, LsUnackPeer(this, (*itr).first, LS_TIMEOUT_FACTOR*(*itr).second)); } void LsRetransmissionManager::cancelTimer (int nbrId) { LsUnackPeer* peerPtr = findPtr(nbrId); if (peerPtr == NULL) return; peerPtr->tpmSeq_ = LS_INVALID_MESSAGE_ID; peerPtr->lsaMap_.eraseAll(); peerPtr->timer_.force_cancel(); } // Called by LsRouting when a message is sent out int LsRetransmissionManager::messageOut(int peerId, const LsMessage& msg) { LsUnackPeer* peerPtr = findPtr(peerId); if (peerPtr == NULL) { iterator itr = insert(peerId, LsUnackPeer(this, peerId)); if (itr == end()) { ls_error ("Can't insert."); } peerPtr = &((*itr).second); } LsIdSeq* idSeqPtr; switch (msg.type_) { case LS_MSG_TPM: peerPtr->tpmSeq_ = msg.sequenceNumber_; break; case LS_MSG_LSA: idSeqPtr = peerPtr->lsaMap_.findPtr(msg.originNodeId_); if (idSeqPtr == NULL) peerPtr->lsaMap_.insert(msg.originNodeId_, LsIdSeq(msg.messageId_, msg.sequenceNumber_)); else { idSeqPtr->msgId_ = msg.messageId_; idSeqPtr->seq_ = msg.sequenceNumber_; } break; case LS_MSG_TPMACK: case LS_MSG_LSAACK: case LS_MSG_LSM: default: // nothing, just to avoid compiler warning break; } // reschedule timer to allow account for this latest message peerPtr->timer_.resched(peerPtr->rtxTimeout_); return 0; } // Called by LsRouting, when an ack is received // Or by messageIn, some the message can serve as ack int LsRetransmissionManager::ackIn(int peerId, const LsMessage& msg) { LsUnackPeer* peerPtr = findPtr(peerId); if ((peerPtr == NULL) || (peerPtr->tpmSeq_ == LS_INVALID_MESSAGE_ID) && peerPtr->lsaMap_.empty()) // no pending ack for this neighbor return 0; LsMap::iterator itr; switch (msg.type_) { case LS_MSG_TPMACK: if (peerPtr->tpmSeq_ == msg.sequenceNumber_) // We've got the right ack, so erase the unack record peerPtr->tpmSeq_ = LS_INVALID_MESSAGE_ID; break; case LS_MSG_LSAACK: itr = peerPtr->lsaMap_.find(msg.originNodeId_); if ((itr != peerPtr->lsaMap_.end()) && ((*itr).second.seq_ == msg.sequenceNumber_)) // We've got the right ack, so erase the unack record peerPtr->lsaMap_.erase(itr); break; case LS_MSG_TPM: case LS_MSG_LSA: case LS_MSG_LSM: default: break; } if ((peerPtr->tpmSeq_ == LS_INVALID_MESSAGE_ID) && (peerPtr->lsaMap_.empty())) // No more pending ack, cancel timer peerPtr->timer_.cancel(); // ack deleted in calling function LsRouting::receiveMessage return 0; } // resendMessage int LsRetransmissionManager::resendMessages (int peerId) { LsUnackPeer* peerPtr = findPtr (peerId); if (peerPtr == NULL) // That's funny, We should never get in here ls_error ("Wait a minute, nothing to send for this neighbor"); // resend topo map if (peerPtr->tpmSeq_ != LS_INVALID_MESSAGE_ID) lsRouting_.resendMessage(peerId, peerPtr->tpmSeq_, LS_MSG_TPM); // resend all other unack'ed LSA for (LsMap::iterator itr = peerPtr->lsaMap_.begin(); itr != peerPtr->lsaMap_.end(); ++itr) lsRouting_.resendMessage(peerId, (*itr).second.msgId_, LS_MSG_LSA); // reschedule retransmit timer peerPtr->timer_.resched(peerPtr->rtxTimeout_); return 0; } /* LsRouting methods */ bool LsRouting::init(LsNode * nodePtr) { if (nodePtr == NULL) return false; myNodePtr_ = nodePtr; myNodeId_ = myNodePtr_->getNodeId(); linkStateDatabase_.setNodeId(myNodeId_); peerIdListPtr_ = myNodePtr_->getPeerIdListPtr(); linkStateListPtr_ = myNodePtr_->getLinkStateListPtr(); if (linkStateListPtr_ != NULL) linkStateDatabase_.insert(myNodeId_, *linkStateListPtr_); LsDelayMap* delayMapPtr = myNodePtr_->getDelayMapPtr(); if (delayMapPtr != NULL) ackManager_.initTimeout(delayMapPtr) ; return true; } void LsRouting::linkStateChanged () { if (linkStateListPtr_ == NULL) ls_error("LsRouting::linkStateChanged: linkStateListPtr null\n"); LsLinkStateList* oldLsPtr = linkStateDatabase_.findPtr(myNodeId_); if (oldLsPtr == NULL) // Should never happen,something's wrong, we didn't // initialize properly ls_error("LsRouting::linkStateChanged: oldLsPtr null!!\n"); // save the old link state for processing LsLinkStateList oldlsl(*oldLsPtr); // if there's any changes, compute new routes and send link states // Note: we do want to send link states before topo bool changed=linkStateDatabase_.update(myNodeId_, *linkStateListPtr_); if (changed) { computeRoutes(); sendLinkStates(/* buffer before sending */ true); // tcl code will call sendBufferedMessage } // Check if there's need to send topo or cancel timer LsLinkStateList::iterator oldLsItr = oldlsl.begin(); for (LsLinkStateList::iterator newLsItr = linkStateListPtr_->begin(); newLsItr != linkStateListPtr_->end(); newLsItr++, oldLsItr++) { // here we are assuming the two link state list are the same // except the status and costs, buggy if ((*newLsItr).neighborId_ != (*oldLsItr).neighborId_) // something's wrong ls_error("New and old link State list are not aligned.\n"); // if link goes down, clear neighbor's not ack'ed entry if ((*newLsItr).status_ == LS_STATUS_DOWN) ackManager_.cancelTimer((*newLsItr).neighborId_); if (((*newLsItr).status_ == LS_STATUS_DOWN) || ((*oldLsItr).status_ == LS_STATUS_UP)) // Don't have to send out tpm if the link goes from // up to down, or it was originally up continue; // else we have to set out the whole topology map that we have // to our neighbor that just resumes peering with us // the messages are buffered, will flush the buffer after the // routes are installed in the node // But don't worry, only a const ptr to our topo map is sent sendTopo( (*newLsItr).neighborId_); } } /* -- isUp -- */ // a linear search, but not too bad if most nodes will have // less than a couple of interfaces bool LsRouting::isUp(int neighborId) { if (linkStateListPtr_ == NULL) return false; for (LsLinkStateList::iterator itr = linkStateListPtr_->begin(); itr!= linkStateListPtr_->end(); itr++) if ((*itr).neighborId_ == neighborId) return ((*itr).status_ == LS_STATUS_UP) ? true : false; return false; } /* -- receiveMessage -- */ /* return true if there's a need to re-compute routes */ bool LsRouting::receiveMessage (int senderId, u_int32_t msgId) { if (senderId == LS_INVALID_NODE_ID) return false; LsMessage* msgPtr = msgctr().retrieveMessagePtr(msgId); if (msgPtr == NULL) return false; // A switch statement to see the type. // and handle differently bool retCode = false; switch (msgPtr->type_){ case LS_MSG_LSM: // not supported yet break; case LS_MSG_TPM: retCode = receiveTopo (senderId, msgPtr); break; case LS_MSG_LSA: // Link State Update retCode = receiveLSA (senderId, msgPtr); break; case LS_MSG_LSAACK: case LS_MSG_TPMACK: receiveAck(senderId, msgPtr); msgctr().deleteMessage(msgId); break; default: break; } return retCode; } // LsRouting::receiveAck is in-line in header file bool LsRouting::receiveLSA(int senderId, LsMessage* msgPtr) { if (msgPtr == NULL) return false; u_int32_t msgId = msgPtr->messageId_; int originNodeId = msgPtr->originNodeId_; sendAck(senderId, LS_MSG_LSAACK, originNodeId, msgId); if ((originNodeId == myNodeId_) || !lsaHistory_.isNewMessage(*msgPtr)) return false; // looks like we've got a new message LSA int peerId; if ((peerIdListPtr_ != NULL) && (myNodePtr_ != NULL)) { // forwards to peers whose links are up, except the sender // and the originator for (LsNodeIdList::iterator itr = peerIdListPtr_->begin(); itr != peerIdListPtr_->end(); itr++) { peerId = *itr; if ((peerId == originNodeId) || (peerId == senderId)) continue; if (isUp(peerId) && ((peerId) != senderId)) { ackManager_.messageOut(peerId, *msgPtr); myNodePtr_->sendMessage(peerId, msgId); } } } // Get the content of the message if (msgPtr->contentPtr_ == NULL) return false; bool changed = linkStateDatabase_.update(msgPtr->originNodeId_, *(msgPtr->lslPtr_)); if (changed) // linkstate database has changed, re-compute routes computeRoutes(); return changed; } // -- sendLinkStates -- bool LsRouting::sendLinkStates(bool buffer /* = false */) { if (myNodePtr_ == NULL) return false; if ((peerIdListPtr_ == NULL) || peerIdListPtr_->empty()) return false; LsLinkStateList* myLSLptr = linkStateDatabase_.findPtr(myNodeId_); if ((myLSLptr == NULL) || myLSLptr->empty()) return false; LsMessage* msgPtr = msgctr().newMessage(myNodeId_, LS_MSG_LSA); if (msgPtr == NULL) return false; // can't get new message u_int32_t msgId = msgPtr->messageId_; u_int32_t seq = msgPtr->sequenceNumber_; // update the sequence number in my own data base for (LsLinkStateList::iterator itr = myLSLptr->begin(); itr != myLSLptr->end(); itr++) (*itr).sequenceNumber_ = seq; LsLinkStateList* newLSLptr = new LsLinkStateList( *myLSLptr); if (newLSLptr == NULL) { ls_error ("Can't get new link state list, in LsRouting::sendLinkStates\n"); // can't get new link state list msgctr().deleteMessage(msgId); return false; } msgPtr->lslPtr_ = newLSLptr; for (LsNodeIdList::iterator itr = peerIdListPtr_->begin(); itr != peerIdListPtr_->end(); itr++) { if (!isUp(*itr)) continue; // link is down if (!buffer) { myNodePtr_->sendMessage((*itr), msgId); ackManager_.messageOut((*itr), *msgPtr); } else { // put in buffer for later sending bufferedSend((*itr), msgPtr); } } return true; } // send acknowledgment, called self bool LsRouting::sendAck (int nbrId, ls_message_type_t type, int originNodeIdAcked, u_int32_t seqAcked) { // Get a new message fom messageCenter LsMessage * msgPtr = msgctr().newMessage(myNodeId_, type); if (msgPtr == NULL) return false; // can't get new message u_int32_t msgId = msgPtr->messageId_; // fill in the blank // msgPtr->type = type; msgPtr->originNodeId_ = originNodeIdAcked; msgPtr->sequenceNumber_ = seqAcked; // Call node to send out message myNodePtr_->sendMessage (nbrId, msgId, LS_ACK_MESSAGE_SIZE); return true; } // After a link comes up, receive Topology update from the // corresponding neighbor bool LsRouting::receiveTopo(int neighborId, LsMessage * msgPtr) { // TODO bool changed = false; // send Ack sendAck(neighborId, LS_MSG_TPMACK, neighborId, msgPtr->sequenceNumber_); // check if it's a new message if (!tpmHistory_.isNewMessage(*msgPtr)) return false; if (msgPtr->topoPtr_ == NULL) return false; // Compare with my own database for (LsTopoMap::const_iterator recItr = msgPtr->topoPtr_->begin(); recItr != msgPtr->topoPtr_->end(); recItr++) { if ((*recItr).first == myNodeId_) // Don't need peer to tell me my own link state continue; // find my own record of the LSA of the node being examined LsLinkStateList* myRecord = linkStateDatabase_.findPtr((*recItr).first); if ((myRecord == NULL) || // we don't have it myRecord->empty() || // or we have an older record ((*(myRecord->begin())).sequenceNumber_ < (*((*recItr).second.begin())).sequenceNumber_) || ((*(myRecord->begin())).sequenceNumber_ - (*((*recItr).second.begin())).sequenceNumber_ > LS_WRAPAROUND_THRESHOLD)) { // Update our database changed = true; if (myRecord == NULL) linkStateDatabase_.insert((*recItr).first, (*recItr).second); else *myRecord = (*recItr).second ; // Regenerate the LSA message and send to my peers, // except the sender of the topo and the // originator of the LSA regenAndSend (/* to except */neighborId, /* originator */(*recItr).first, /* the linkstateList */(*recItr).second); } } if (changed) computeRoutes(); // if anything relevant has changed, recompute routes return changed; } // replicate a LSA and send it out void LsRouting::regenAndSend(int exception, int origin, const LsLinkStateList& lsl) { if (lsl.empty()) ls_error("lsl is empty, in LsRouting::regenAndSend.\n"); LsLinkStateList* newLSLptr = new LsLinkStateList(lsl); if (newLSLptr == NULL) { ls_error("Can't get new link state list, in " "LsRouting::sendLinkStates\n"); return; } // replicate the LSA LsMessage* msgPtr = msgctr().newMessage(origin, LS_MSG_LSA); msgPtr->sequenceNumber_ = (*lsl.begin()).sequenceNumber_; msgPtr->originNodeId_ = origin; for (LsNodeIdList::iterator itr = peerIdListPtr_->begin(); itr != peerIdListPtr_->end(); itr++) { if ((*itr == origin) || (*itr == exception) || !isUp(*itr)) continue; bufferedSend(*itr, msgPtr); // debug // cout << "Node " << myNodeId << " regenAndSend " // << (*(lsl.begin())).sequenceNumber << " from origin " << origin // << " to peer " << *itr << endl; } } // After a link comes up, receive Topo with the corresponding neighbor void LsRouting::sendTopo(int neighborId) { // if we've gone so far, messageCenterPtr should not be null, // don't check LsMessage* msgPtr= msgctr().newMessage(myNodeId_, LS_MSG_TPM); // XXX, here we are going to send the pointer that points // to my own topo, because sending the who topomap is too costly in // simulation msgPtr->contentPtr_ = &linkStateDatabase_; bufferedSend(neighborId, msgPtr); } void LsRouting::sendBufferedMessages() { for (MessageBuffer::iterator itr = messageBuffer_.begin(); itr != messageBuffer_.end(); itr++) { ackManager_.messageOut((*itr).peerId_, *((*itr).msgPtr_)); myNodePtr_->sendMessage((*itr).peerId_, (*itr).msgPtr_->messageId_, msgSizes[(*itr).msgPtr_->type_]); } messageBuffer_.eraseAll(); } // private _computeRoutes, called by public computeRoutes LsPaths* LsRouting::_computeRoutes () { LsPathsTentative* pTentativePaths = new LsPathsTentative(); LsPaths* pPaths = new LsPaths() ; // to be returned; // step 1. put myself in path LsPath toSelf(myNodeId_, 0, myNodeId_); // zero cost, nextHop is myself pPaths->insertPathNoChecking(toSelf); int newNodeId = myNodeId_; LsLinkStateList * ptrLSL = linkStateDatabase_.findPtr(newNodeId); if (ptrLSL == NULL ) // don't have my own linkState return pPaths; bool done = false; // start the loop while (! done) { // Step 2. for the new node just put in path // find the next hop to the new node LsNodeIdList nhl; LsNodeIdList *nhlp = &nhl; // nextHopeList pointer if (newNodeId != myNodeId_) { // if not looking at my own links, find the next hop // to new node nhlp = pPaths->lookupNextHopListPtr(newNodeId); if (nhlp == NULL) ls_error("computeRoutes: nhlp == NULL \n"); } // for each of it's links for (LsLinkStateList::iterator itrLink = ptrLSL->begin(); itrLink != ptrLSL->end(); itrLink++) { if ((*itrLink).status_ != LS_STATUS_UP) // link is not up, skip this link continue; int dest = (*itrLink).neighborId_; int path_cost = (*itrLink).cost_ + pPaths->lookupCost(newNodeId); if (pPaths->lookupCost(dest) < path_cost) // better path already in paths, // move on to next link continue; else { // else we have a new or equally good path, // LsPathsTentative::insertPath(...) will // take care of checking if the new path is // a better or equally good one, etc. LsNodeIdList nextHopList; if (newNodeId == myNodeId_) { // destination is directly connected, // nextHop is itself nextHopList.push_back(dest); nhlp = &nextHopList; } pTentativePaths->insertNextHopList(dest, path_cost, *nhlp); } } done = true; // if tentatives empty, terminate; while (!pTentativePaths->empty()) { // else pop shortest path triple from tentatives LsPath sp = pTentativePaths->popShortestPath(); if (!sp.isValid()) ls_error (" popShortestPath() failed\n"); // install the newly found shortest path among // tentatives pPaths->insertPath(sp); newNodeId = sp.destination; ptrLSL = linkStateDatabase_.findPtr(newNodeId); if (ptrLSL != NULL) { // if we have the link state for the new node // break out of inner do loop to continue // computing routes done = false; break; } // else we don't have linkstate for this new node, // we need to keep popping shortest paths } } // endof while ( ! done ); delete pTentativePaths; return pPaths; } #endif //HAVE_STL