InetUnderlayConfigurator.cc

Go to the documentation of this file.
00001 //
00002 // This program is free software; you can redistribute it and/or
00003 // modify it under the terms of the GNU General Public License
00004 // as published by the Free Software Foundation; either version 2
00005 // of the License, or (at your option) any later version.
00006 //
00007 // This program is distributed in the hope that it will be useful,
00008 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010 // GNU General Public License for more details.
00011 //
00012 // You should have received a copy of the GNU General Public License
00013 // along with this program; if not, write to the Free Software
00014 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00015 //
00016 
00022 #include "InetUnderlayConfigurator.h"
00023 
00024 #include <GlobalNodeList.h>
00025 #include <TransportAddress.h>
00026 
00027 #include <StringConvert.h>
00028 
00029 #include <AccessNet.h>
00030 #include <IRoutingTable.h>
00031 #include <IInterfaceTable.h>
00032 #include <IPAddressResolver.h>
00033 #include <IPv4InterfaceData.h>
00034 #include <NotificationBoard.h>
00035 
00036 
00037 #include <InetInfo.h>
00038 
00039 Define_Module(InetUnderlayConfigurator);
00040 
00041 void InetUnderlayConfigurator::initializeUnderlay(int stage)
00042 {
00043     //backbone configuration
00044     if (stage == MIN_STAGE_UNDERLAY) {
00045         // Find all router modules.
00046         cTopology topo("topo");
00047         topo.extractByProperty("node");
00048 
00049         // Assign IP addresses to all router modules.
00050         std::vector<uint32> nodeAddresses;
00051         nodeAddresses.resize(topo.getNumNodes());
00052 
00053         // IP addresses for backbone
00054         // Take start IP from config file
00055         // FIXME: Make Netmask for Routers configurable!
00056         uint32 lowIPBoundary = IPAddress(par("startIP").stringValue()).getInt();
00057 
00058         // uint32 lowIPBoundary = uint32((1 << 24) + 1);
00059         int numIPNodes = 0;
00060 
00061         for (int i = 0; i < topo.getNumNodes(); i++) {
00062             ++numIPNodes;
00063 
00064             uint32 addr = lowIPBoundary + uint32(numIPNodes << 16);
00065             nodeAddresses[i] = addr;
00066 
00067             // update ip display string
00068             if (ev.isGUI()) {
00069                 topo.getNode(i)->getModule()->getDisplayString().insertTag("t", 0);
00070                 topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 0,
00071                                         const_cast<char*>(IPAddress(addr).str().c_str()));
00072                 topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 1, "l");
00073                 topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 2, "red");
00074             }
00075 
00076             // find interface table and assign address to all (non-loopback) interfaces
00077             IInterfaceTable* ift = IPAddressResolver().interfaceTableOf(topo.getNode(i)->getModule());
00078 
00079             for ( int k = 0; k < ift->getNumInterfaces(); k++ ) {
00080                 InterfaceEntry* ie = ift->getInterface(k);
00081                 if (!ie->isLoopback()) {
00082                     ie->ipv4Data()->setIPAddress(IPAddress(addr));
00083                     // full address must match for local delivery
00084                     ie->ipv4Data()->setNetmask(IPAddress::ALLONES_ADDRESS);
00085                 }
00086             }
00087         }
00088 
00089         // Fill in routing tables.
00090         for (int i = 0; i < topo.getNumNodes(); i++) {
00091             cTopology::Node* destNode = topo.getNode(i);
00092             uint32 destAddr = nodeAddresses[i];
00093 
00094             // calculate shortest paths from everywhere towards destNode
00095             topo.calculateUnweightedSingleShortestPathsTo(destNode);
00096 
00097             // add overlayAccessRouters and overlayBackboneRouters
00098             // to the GlobalNodeList
00099             if ((strcmp(destNode->getModule()->getName(), "overlayBackboneRouter") == 0) ||
00100                     (strcmp(destNode->getModule()->getName(), "overlayAccessRouter") == 0)) {
00101                 //add node to bootstrap oracle
00102                 PeerInfo* info = new PeerInfo(0, destNode->getModule()->getId(), NULL);
00103                 globalNodeList->addPeer(IPvXAddress(nodeAddresses[i]), info);
00104             }
00105 
00106 
00107             // If destNode is the outRouter, add a default route
00108             // to outside network via the TunOutDevice and a route to the
00109             // Gateway
00110             if ( strcmp(destNode->getModule()->getName(), "outRouter" ) == 0 ) {
00111                 IPRoute* defRoute = new IPRoute();
00112                 defRoute->setHost(IPAddress::UNSPECIFIED_ADDRESS);
00113                 defRoute->setNetmask(IPAddress::UNSPECIFIED_ADDRESS);
00114                 defRoute->setGateway(IPAddress(par("gatewayIP").stringValue()));
00115                 defRoute->setInterface(IPAddressResolver().interfaceTableOf(destNode->getModule())->getInterfaceByName("tunDev"));
00116                 defRoute->setType(IPRoute::REMOTE);
00117                 defRoute->setSource(IPRoute::MANUAL);
00118                 IPAddressResolver().routingTableOf(destNode->getModule())->addRoute(defRoute);
00119 
00120                 IPRoute* gwRoute = new IPRoute();
00121                 gwRoute->setHost(IPAddress(par("gatewayIP").stringValue()));
00122                 gwRoute->setNetmask(IPAddress(255, 255, 255, 255));
00123                 gwRoute->setInterface(IPAddressResolver().interfaceTableOf(destNode->getModule())->getInterfaceByName("tunDev"));
00124                 gwRoute->setType(IPRoute::DIRECT);
00125                 gwRoute->setSource(IPRoute::MANUAL);
00126                 IPAddressResolver().routingTableOf(destNode->getModule())->addRoute(gwRoute);
00127             }
00128 
00129             // add route (with host=destNode) to every routing table in the network
00130             for (int j = 0; j < topo.getNumNodes(); j++) {
00131                 // continue if same node
00132                 if (i == j)
00133                     continue;
00134 
00135                 // cancel simulation if node is not connected with destination
00136                 cTopology::Node* atNode = topo.getNode(j);
00137 
00138                 if (atNode->getNumPaths() == 0) {
00139                     error((std::string(atNode->getModule()->getName()) + ": Network is not entirely connected."
00140                             "Please increase your value for the "
00141                             "connectivity parameter").c_str());
00142                 }
00143 
00144                 //
00145                 // Add routes at the atNode.
00146                 //
00147 
00148                 // find atNode's interface and routing table
00149                 IInterfaceTable* ift = IPAddressResolver().interfaceTableOf(atNode->getModule());
00150                 IRoutingTable* rt = IPAddressResolver().routingTableOf(atNode->getModule());
00151 
00152                 // find atNode's interface entry for the next hop node
00153                 int outputGateId = atNode->getPath(0)->getLocalGate()->getId();
00154                 InterfaceEntry *ie = ift->getInterfaceByNodeOutputGateId(outputGateId);
00155 
00156                 // find the next hop node on the path towards destNode
00157                 cModule* next_hop = atNode->getPath(0)->getRemoteNode()->getModule();
00158                 IPAddress next_hop_ip = IPAddressResolver().addressOf(next_hop).get4();
00159 
00160 
00161                 // Requirement 1: Each router has exactly one routing entry
00162                 // (netmask 255.255.0.0) to each other router
00163                 IPRoute* re = new IPRoute();
00164 
00165                 re->setHost(IPAddress(destAddr));
00166                 re->setInterface(ie);
00167                 re->setSource(IPRoute::MANUAL);
00168                 re->setNetmask(IPAddress(255, 255, 0, 0));
00169                 re->setGateway(IPAddress(next_hop_ip));
00170                 re->setType(IPRoute::REMOTE);
00171 
00172                 rt->addRoute(re);
00173 
00174                 // Requirement 2: Each router has a point-to-point routing
00175                 // entry (netmask 255.255.255.255) for each immediate neighbour
00176                 if (atNode->getDistanceToTarget() == 1) {
00177                     IPRoute* re2 = new IPRoute();
00178 
00179                     re2->setHost(IPAddress(destAddr));
00180                     re2->setInterface(ie);
00181                     re2->setSource(IPRoute::MANUAL);
00182                     re2->setNetmask(IPAddress(255, 255, 255, 255));
00183                     re2->setType(IPRoute::DIRECT);
00184 
00185                     rt->addRoute(re2);
00186                 }
00187 
00188                 // If destNode is the outRouter, add a default route
00189                 // to the next hop in the direction of the outRouter
00190                 if (strcmp(destNode->getModule()->getName(), "outRouter" ) == 0) {
00191                     IPRoute* defRoute = new IPRoute();
00192                     defRoute->setHost(IPAddress::UNSPECIFIED_ADDRESS);
00193                     defRoute->setNetmask(IPAddress::UNSPECIFIED_ADDRESS);
00194                     defRoute->setGateway(IPAddress(next_hop_ip));
00195                     defRoute->setInterface(ie);
00196                     defRoute->setType(IPRoute::REMOTE);
00197                     defRoute->setSource(IPRoute::MANUAL);
00198 
00199                     rt->addRoute(defRoute);
00200                 }
00201             }
00202         }
00203     }
00204     //access net configuration
00205     else if(stage == MAX_STAGE_UNDERLAY) {
00206         // fetch some parameters
00207         accessRouterNum = getParentModule()->par("accessRouterNum");
00208         overlayAccessRouterNum = getParentModule()->par("overlayAccessRouterNum");
00209 
00210         // count the overlay clients
00211         overlayTerminalCount = 0;
00212 
00213         numCreated = 0;
00214         numKilled = 0;
00215 
00216         // add access node modules to access node vector
00217         cModule* node;
00218         for (int i = 0; i < accessRouterNum; i++) {
00219             node = getParentModule()->getSubmodule("accessRouter", i);
00220             accessNode.push_back( node );
00221         }
00222 
00223         for (int i = 0; i < overlayAccessRouterNum; i++) {
00224             node = getParentModule()->getSubmodule("overlayAccessRouter", i);
00225             accessNode.push_back( node );
00226         }
00227 
00228         // debug stuff
00229         WATCH_PTRVECTOR(accessNode);
00230     }
00231 }
00232 
00233 TransportAddress* InetUnderlayConfigurator::createNode(NodeType type, bool initialize)
00234 {
00235     Enter_Method_Silent();
00236     // derive overlay node from ned
00237     std::string nameStr = "overlayTerminal";
00238     if( churnGenerator.size() > 1 ){
00239         nameStr += "-" + convertToString<uint32_t>(type.typeID);
00240     }
00241     cModuleType* moduleType = cModuleType::get(type.terminalType.c_str());
00242     cModule* node = moduleType->create(nameStr.c_str(), getParentModule(),
00243                                        numCreated + 1, numCreated);
00244 
00245     if (type.channelTypesTx.size() > 0) {
00246         throw cRuntimeError("InetUnderlayConfigurator::createNode(): Setting "
00247                     "channel types via the churn generator is not allowed "
00248                     "with the InetUnderlay. Use **.accessNet.channelTypes instead!");
00249     }
00250 
00251     node->par("overlayType").setStringValue(type.overlayType.c_str());
00252     node->par("tier1Type").setStringValue(type.tier1Type.c_str());
00253     node->par("tier2Type").setStringValue(type.tier2Type.c_str());
00254     node->par("tier3Type").setStringValue(type.tier3Type.c_str());
00255 
00256     node->setGateSize("pppg", 1);
00257 
00258     std::string displayString;
00259 
00260     if ((type.typeID > 1) && (type.typeID <= (NUM_COLORS + 1))) {
00261         ((displayString += "i=device/wifilaptop_l,")
00262                         += colorNames[type.typeID - 2])
00263                         += ",40;i2=block/circle_s";
00264     } else {
00265         displayString = "i=device/wifilaptop_l;i2=block/circle_s";
00266     }
00267 
00268     node->finalizeParameters();
00269     node->setDisplayString(displayString.c_str());
00270 
00271     node->buildInside();
00272     node->scheduleStart(simTime());
00273 
00274     // create meta information
00275     InetInfo* info = new InetInfo(type.typeID, node->getId(), type.context);
00276     AccessNet* accessNet= check_and_cast<AccessNet*>
00277         (accessNode[intuniform(0, accessNode.size() - 1)]
00278                 ->getSubmodule("accessNet"));
00279     info->setAccessNetModule(accessNet);
00280     // add node to a randomly chosen access net
00281     info->setNodeID(accessNet->addOverlayNode(node));
00282 
00283     // add node to bootstrap oracle
00284     globalNodeList->addPeer(IPAddressResolver().addressOf(node), info);
00285 
00286     // if the node was not created during startup we have to
00287     // finish the initialization process manually
00288     if (!initialize) {
00289         for (int i = MAX_STAGE_UNDERLAY + 1; i < NUM_STAGES_ALL; i++) {
00290             node->callInitialize(i);
00291         }
00292     }
00293 
00294     overlayTerminalCount++;
00295     numCreated++;
00296 
00297     churnGenerator[type.typeID - 1]->terminalCount++;
00298 
00299     TransportAddress *address = new TransportAddress(
00300                                        IPAddressResolver().addressOf(node));
00301 
00302     // update display
00303     setDisplayString();
00304 
00305     return address;
00306 }
00307 
00308 //TODO: getRandomNode()
00309 void InetUnderlayConfigurator::preKillNode(NodeType type, TransportAddress* addr)
00310 {
00311     Enter_Method_Silent();
00312 
00313     AccessNet* accessNetModule = NULL;
00314     int nodeID;
00315     InetInfo* info;
00316 
00317     // If no address given, get random node
00318     if (addr == NULL) {
00319         addr = globalNodeList->getRandomAliveNode(type.typeID);
00320 
00321         if (addr == NULL) {
00322             // all nodes are already prekilled
00323             std::cout << "all nodes are already prekilled" << std::endl;
00324             return;
00325         }
00326     }
00327 
00328     // get node information
00329     info = dynamic_cast<InetInfo*>(globalNodeList->getPeerInfo(*addr));
00330 
00331     if (info != NULL) {
00332         accessNetModule = info->getAccessNetModule();
00333         nodeID = info->getNodeID();
00334     } else {
00335         opp_error("IPv4UnderlayConfigurator: Trying to pre kill node "
00336                   "with nonexistant TransportAddress!");
00337     }
00338 
00339     uint32_t effectiveType = info->getTypeID();
00340 
00341     // do not kill node that is already scheduled
00342     if(scheduledID.count(nodeID))
00343         return;
00344 
00345     cModule* node = accessNetModule->getOverlayNode(nodeID);
00346     globalNodeList->removePeer(IPAddressResolver().addressOf(node));
00347 
00348     //put node into the kill list and schedule a message for final removal of the node
00349     killList.push_front(IPAddressResolver().addressOf(node));
00350     scheduledID.insert(nodeID);
00351 
00352     overlayTerminalCount--;
00353     numKilled++;
00354 
00355     churnGenerator[effectiveType - 1]->terminalCount--;
00356 
00357     // update display
00358     setDisplayString();
00359 
00360     // inform the notification board about the removal
00361     NotificationBoard* nb = check_and_cast<NotificationBoard*>(
00362             node->getSubmodule("notificationBoard"));
00363     nb->fireChangeNotification(NF_OVERLAY_NODE_LEAVE);
00364 
00365     double random = uniform(0, 1);
00366 
00367     if (random < gracefulLeaveProbability) {
00368         nb->fireChangeNotification(NF_OVERLAY_NODE_GRACEFUL_LEAVE);
00369     }
00370 
00371     cMessage* msg = new cMessage();
00372     scheduleAt(simTime() + gracefulLeaveDelay, msg);
00373 
00374 }
00375 
00376 void InetUnderlayConfigurator::migrateNode(NodeType type, TransportAddress* addr)
00377 {
00378     Enter_Method_Silent();
00379 
00380     AccessNet* accessNetModule = NULL;
00381     int nodeID = -1;
00382     InetInfo* info;
00383 
00384     // If no address given, get random node
00385     if(addr == NULL) {
00386         info = dynamic_cast<InetInfo*>(globalNodeList->getRandomPeerInfo(type.typeID));
00387     } else {
00388         // get node information
00389         info = dynamic_cast<InetInfo*>(globalNodeList->getPeerInfo(*addr));
00390     }
00391 
00392     if(info != NULL) {
00393         accessNetModule = info->getAccessNetModule();
00394         nodeID = info->getNodeID();
00395     } else {
00396         opp_error("IPv4UnderlayConfigurator: Trying to pre kill node with nonexistant TransportAddress!");
00397     }
00398 
00399     // do not migrate node that is already scheduled
00400     if(scheduledID.count(nodeID))
00401         return;
00402 
00403     cModule* node = accessNetModule->removeOverlayNode(nodeID);//intuniform(0, accessNetModule->size() - 1));
00404 
00405     if(node == NULL)
00406         opp_error("IPv4UnderlayConfigurator: Trying to remove node which is nonexistant in AccessNet!");
00407 
00408     //remove node from bootstrap oracle
00409     globalNodeList->killPeer(IPAddressResolver().addressOf(node));
00410 
00411     node->bubble("I am migrating!");
00412 
00413     // connect the node to another access net
00414     AccessNet* newAccessNetModule;
00415 
00416     do {
00417         newAccessNetModule = check_and_cast<AccessNet*>(accessNode[intuniform(0, accessNode.size() - 1)]->getSubmodule("accessNet"));
00418     } while((newAccessNetModule == accessNetModule) && (accessNode.size() != 1));
00419 
00420     // create meta information
00421     InetInfo* newinfo = new InetInfo(type.typeID, node->getId(), type.context);
00422     // add node to a randomly chosen access net
00423     newinfo->setAccessNetModule(newAccessNetModule);
00424     newinfo->setNodeID(newAccessNetModule->addOverlayNode(node, true));
00425 
00426     //add node to bootstrap oracle
00427     globalNodeList->addPeer(IPAddressResolver().addressOf(node), newinfo);
00428 
00429     // inform the notification board about the migration
00430     NotificationBoard* nb = check_and_cast<NotificationBoard*>(node->getSubmodule("notificationBoard"));
00431     nb->fireChangeNotification(NF_OVERLAY_TRANSPORTADDRESS_CHANGED);
00432 }
00433 
00434 void InetUnderlayConfigurator::handleTimerEvent(cMessage* msg)
00435 {
00436     Enter_Method_Silent();
00437 
00438     // get next scheduled node from the kill list
00439     IPvXAddress addr = killList.back();
00440     killList.pop_back();
00441 
00442     AccessNet* accessNetModule = NULL;
00443     int nodeID = -1;
00444 
00445     InetInfo* info = dynamic_cast<InetInfo*>(globalNodeList->getPeerInfo(addr));
00446     if(info != NULL) {
00447         accessNetModule = info->getAccessNetModule();
00448         nodeID = info->getNodeID();
00449     } else {
00450         opp_error("IPv4UnderlayConfigurator: Trying to kill node with nonexistant TransportAddress!");
00451     }
00452 
00453     scheduledID.erase(nodeID);
00454     globalNodeList->killPeer(addr);
00455 
00456     cModule* node = accessNetModule->removeOverlayNode(nodeID);
00457 
00458     if(node == NULL)
00459         opp_error("IPv4UnderlayConfigurator: Trying to remove node which is nonexistant in AccessNet!");
00460 
00461     node->callFinish();
00462     node->deleteModule();
00463 
00464     delete msg;
00465 }
00466 
00467 void InetUnderlayConfigurator::setDisplayString()
00468 {
00469     char buf[80];
00470     sprintf(buf, "%i overlay terminals\n%i access router\n%i overlay access router",
00471             overlayTerminalCount, accessRouterNum, overlayAccessRouterNum);
00472     getDisplayString().setTagArg("t", 0, buf);
00473 }
00474 
00475 void InetUnderlayConfigurator::finishUnderlay()
00476 {
00477     // statistics
00478     recordScalar("Terminals added", numCreated);
00479     recordScalar("Terminals removed", numKilled);
00480 
00481     if (!isInInitPhase()) {
00482         struct timeval now, diff;
00483         gettimeofday(&now, NULL);
00484         timersub(&now, &initFinishedTime, &diff);
00485         printf("Simulation time: %li.%06li\n", diff.tv_sec, diff.tv_usec);
00486     }
00487 }
00488 
00489 
00499 double uniform2(double start, double end, double index, double new_calc)
00500 {
00501     static std::vector<double> value;
00502     if ( (unsigned int)index >= value.size() )
00503         value.resize((int)index + 1);
00504     if ( new_calc == 1 )
00505         value[(int)index] = uniform(start, end);
00506     return value[(int)index];
00507 };
00508 
00518 double intuniform2(double start, double end, double index, double new_calc)
00519 {
00520     static std::vector<double> value;
00521     if ( (unsigned int)index >= value.size() )
00522         value.resize((int)index + 1);
00523     if ( new_calc == 1 )
00524         value[(int)index] = (double)intuniform((int)start, (int)end);
00525     return value[(int)index];
00526 };
00527 
00528 Define_Function(uniform2, 4);
00529 Define_Function(intuniform2, 4);
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3