ConnectReaSE.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2010 Institut fuer Telematik, Karlsruher Institut fuer Technologie (KIT)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00025 #include <vector>
00026 #include <iostream>
00027 
00028 #include <omnetpp.h>
00029 
00030 #include <IRoutingTable.h>
00031 #include <IInterfaceTable.h>
00032 #include <IPAddressResolver.h>
00033 #include <IPv4InterfaceData.h>
00034 
00035 #include "ConnectReaSE.h"
00036 
00037 using namespace ::std;
00038 
00039 Define_Module(ConnectReaSE);
00040 
00041 std::ostream& operator<<(std::ostream& os, terminalInfo& n)
00042 {
00043     os << n.module;
00044     return os;
00045 }
00046 
00047 void ConnectReaSE::initialize(int stage)
00048 {
00049     //EV << "Connector Stage" << stage;
00050     if (stage != MAX_STAGE_UNDERLAY)
00051         return;
00052 
00053     //get parameters
00054     channelTypesTx = cStringTokenizer(par("channelTypes"), " ").asVector();
00055     channelTypesRx = cStringTokenizer(par("channelTypesRx"), " ").asVector();
00056     channelDiversity = par("channelDiversity");
00057 
00058     if (channelTypesTx.size() < channelTypesRx.size()) {
00059         channelTypesTx = channelTypesRx;
00060     }
00061     else if (channelTypesTx.size() > channelTypesRx.size()) {
00062         channelTypesRx = channelTypesTx;
00063     }
00064 
00065     // make sure that delay cannot be zero and diversity cannot be below zero
00066     if (channelDiversity>=100)
00067         channelDiversity = 99.99f;
00068     else if (channelDiversity<0)
00069         channelDiversity = 0;
00070 
00071     // statistics
00072     lifetimeVector.setName("Terminal Lifetime");
00073 
00074     // set up network
00075 
00076     cModule* tempModule;
00077     cTopology tempTopology("tempTopo");
00078     edgePool tempEdgePool;
00079 
00080 
00081     tempTopology.extractByProperty("AS");
00082     totalCountOfAS = tempTopology.getNumNodes();
00083 
00084     nextPow = 0;
00085     while (((uint32_t) 1 << nextPow) < totalCountOfAS + 1) {
00086         nextPow++;
00087     }
00088     ASShift = 32 - nextPow;
00089 
00090     if (tempTopology.getNumNodes() == 0) {
00091 
00092         //no AS topology
00093 
00094         tempTopology.extractByProperty("RL");
00095 
00096         if (tempTopology.getNumNodes() == 0)
00097 
00098             //no router topology
00099             opp_error("ConnectReaSE: Neither an AS topology nor a router topology was detected.");
00100 
00101         setUpAS(getParentModule());
00102     }
00103     else {
00104 
00105         // set up all autonomous systems (AS)
00106         int index = 0;
00107         std::vector<cModule*> Modules;
00108         for (int i=0; i<tempTopology.getNumNodes(); i++) {
00109 
00110             tempModule = tempTopology.getNode(i)->getModule();
00111             Modules.push_back(tempModule);
00112             index++;
00113         }
00114         for (uint32 i=0; i< Modules.size(); i++) {
00115             setUpAS(Modules[i]);
00116         }
00117     }
00118 
00119     // put all edge router in one data structure to get a equal probability of selection
00120     for (uint32 i=0; i<AS_Pool.size(); i++) {
00121         for (uint32 j=0; j< AS_Pool[i].edgeRouter.size(); j++) {
00122             tempEdgePool.edge = &AS_Pool[i].edgeRouter[j];
00123             tempEdgePool.indexAS = i;
00124             globalEdgePool.push_back(tempEdgePool);
00125         }
00126     }
00127     //cout << "Number of Edges in Network: " << globalEdgePool.size() << endl;
00128 
00129     for (uint32 i=0; i<globalEdgePool.size(); i++) {
00130 
00131         //select channel
00132         globalEdgePool[i].edge->channelTypeTxStr = channelTypesTx[intuniform(0,channelTypesTx.size()-1)];
00133         globalEdgePool[i].edge->channelTypeRxStr = channelTypesRx[intuniform(0,channelTypesRx.size()-1)];
00134     }
00135 }
00136 
00137 AccessInfo ConnectReaSE::getAccessNode()
00138 {
00139     Enter_Method("getAccessNode()");
00140 
00141     bool candidateOK = false;
00142     int numTries = 10;
00143     uint32 test_IP = 0;
00144     AccessInfo node;
00145     edgeRoutes* connectionCandidate;
00146     uint32 tempIndex, tempASindex;
00147 
00148     while ((numTries > 0)&&(!candidateOK)) {
00149         numTries--;
00150         tempIndex = intuniform(0, globalEdgePool.size()-1);
00151         connectionCandidate = globalEdgePool[tempIndex].edge;
00152         tempASindex = globalEdgePool[tempIndex].indexAS;
00153 
00154         //limit terminals per edge router
00155         if (connectionCandidate->IPAddresses.size() >= ((uint32_t) 1 << AS_Pool[tempASindex].edgeShift)) // maximum reached?
00156             continue;
00157 
00158 //        test_IP = connectionCandidate->IPAddress + 1; // begin with first IP after the edge router
00159 //        for (int i = 0; i < (1 << AS_Pool[tempASindex].edgeShift); i++ ) {
00160 //            test_IP += i;
00161 //            candidateOK = true;
00162 //            for (uint32 j = 0; j < connectionCandidate->IPAddresses.size(); j++) {
00163 //                if (connectionCandidate->IPAddresses[j] == test_IP) {
00164 //                    candidateOK =false;
00165 //                    break;
00166 //                }
00167 //            }
00168 //            if (candidateOK) {
00169 //                connectionCandidate->IPAddresses.push_back(test_IP);
00170 //                break;
00171 //            }
00172 //        }
00173 
00174         // FIXME: check overlays for side effects of reused IP addresses
00175 
00176         test_IP = ++connectionCandidate->lastIP;
00177         connectionCandidate->IPAddresses.push_back(test_IP);
00178         break;
00179 
00180     }
00181 
00182     // no free IP address after 10 tries
00183     if (numTries == 0) {
00184         opp_error("Error creating node: No available IP found after four tries!");
00185     }
00186     EV << "Found available IP: " << test_IP;
00187 
00188     node.ASindex = tempASindex;
00189     node.IPAddress = test_IP;
00190     node.edge = connectionCandidate;
00191     return node;
00192 }
00193 
00194 int ConnectReaSE::addOverlayNode(AccessInfo* overlayNode, bool migrate)
00195 {
00196         Enter_Method("addOverlayNode()");
00197 
00198         cModule* node = overlayNode->terminal;
00199         terminalInfo terminal;
00200 
00201         terminal.module = node;
00202         terminal.interfaceTable = IPAddressResolver().interfaceTableOf(node);
00203         terminal.remoteInterfaceTable = overlayNode->edge->interfaceTable;
00204         terminal.routingTable = IPAddressResolver().routingTableOf(node);
00205         terminal.PPPInterface = node->getSubmodule("ppp", 0);
00206         terminal.createdAt = simTime();
00207         terminal.IPAddress = overlayNode->IPAddress;
00208         terminal.edgeRouter = overlayNode->edge;
00209         terminal.ASindex = overlayNode->ASindex;
00210 
00211         // update display
00212         if (ev.isGUI()) {
00213                 const char* ip_disp = const_cast<char*>
00214                 (IPAddress(terminal.IPAddress).str().c_str());
00215                 terminal.module->getDisplayString().insertTag("t", 0);
00216                 terminal.module->getDisplayString().setTagArg("t", 0, ip_disp);
00217                 terminal.module->getDisplayString().setTagArg("t", 1, "l");
00218         }
00219 
00220         //find first unused interface
00221         int k = 1;
00222         while ( overlayNode->edge->Router->findSubmodule("ppp", k) != -1 )
00223             k++;
00224 
00225 
00226         cModuleType* pppInterfaceModuleType = cModuleType::get("inet.linklayer.ppp.PPPInterface");
00227         terminal.remotePPPInterface = pppInterfaceModuleType->
00228         create("ppp", overlayNode->edge->Router, 0, k);
00229 
00230         overlayNode->edge->countPPPInterfaces++;
00231 
00232 
00233         // connect terminal to access router and vice versa
00234         cGate* routerInGate = firstUnusedGate(overlayNode->edge->Router, "pppg", cGate::INPUT);
00235         cGate* routerOutGate = firstUnusedGate(overlayNode->edge->Router, "pppg", cGate::OUTPUT);
00236 
00237         cChannelType* channelTypeRx = cChannelType::find( overlayNode->edge->channelTypeRxStr.c_str() );
00238         cChannelType* channelTypeTx = cChannelType::find( overlayNode->edge->channelTypeTxStr.c_str() );
00239         if (!channelTypeRx || !channelTypeTx)
00240             opp_error("Could not find Channel or ChannelRx Type. Most likely "
00241                 "parameter channelTypes does not match the channels defined "
00242                 "in channels.ned");
00243 
00244         //create channels
00245         cDatarateChannel* channelRx = check_and_cast<cDatarateChannel*>(channelTypeRx->create(overlayNode->edge->channelTypeRxStr.c_str()));
00246         cDatarateChannel* channelTx = check_and_cast<cDatarateChannel*>(channelTypeTx->create(overlayNode->edge->channelTypeTxStr.c_str()));
00247 
00248         //connect terminal
00249         terminal.module->gate("pppg$o", 0)->connectTo(routerInGate,channelRx);
00250         routerOutGate->connectTo(terminal.module->gate("pppg$i", 0),channelTx);
00251 
00252         // connect ppp interface module to router module and vice versa
00253         routerInGate->connectTo(terminal.remotePPPInterface->gate("phys$i"));
00254         terminal.remotePPPInterface->gate("phys$o")->connectTo(routerOutGate);
00255 
00256         // connect ppp interface module to network layer module and vice versa
00257         cModule* netwModule = overlayNode->edge->Router->getSubmodule("networkLayer");
00258 
00259         cGate* netwInGate = firstUnusedGate(netwModule, "ifIn");
00260         cGate* netwOutGate = firstUnusedGate(netwModule, "ifOut");
00261 
00262         netwOutGate->connectTo(terminal.remotePPPInterface->gate("netwIn"));
00263         terminal.remotePPPInterface->gate("netwOut")->connectTo(netwInGate);
00264 
00265         // connect network layer module to ip and arp modules
00266         cModule* ipModule = overlayNode->edge->Router->getSubmodule("networkLayer")->
00267         getSubmodule("ip");
00268 
00269         cGate* ipIn = firstUnusedGate(ipModule, "queueIn");
00270         netwInGate->connectTo(ipIn);
00271 
00272         //
00273         // Start ppp interface modules
00274         //
00275         terminal.remotePPPInterface->finalizeParameters();
00276         terminal.remotePPPInterface->setDisplayString("i=block/ifcard");
00277         terminal.remotePPPInterface->buildInside();
00278         terminal.remotePPPInterface->scheduleStart(simTime());
00279         terminal.remotePPPInterface->callInitialize();
00280 
00281         if ( !migrate) {
00282             // we are already in stage 4 and need to call initialize
00283         // for all previous stages manually
00284             for (int i=0; i < MAX_STAGE_UNDERLAY + 1; i++) {
00285                 terminal.module->callInitialize(i);
00286             }
00287         }
00288 
00289         //calculate diversity factor for both channels (+/- diversity)
00290         double diversityFactor = (uniform(0 , 2*channelDiversity) + (100-channelDiversity))/100;
00291 
00292         //customize channel delays
00293         channelRx->setDelay(SIMTIME_DBL(channelRx->getDelay()*diversityFactor));
00294         channelTx->setDelay(SIMTIME_DBL(channelTx->getDelay()*diversityFactor));
00295 
00296         terminal.remoteInterfaceEntry = overlayNode->edge->interfaceTable->getInterface(
00297         overlayNode->edge->interfaceTable->getNumInterfaces() - 1);
00298         terminal.interfaceEntry = terminal.interfaceTable->getInterfaceByName("ppp0");
00299 
00300 
00301         //
00302         // Fill in interface table.
00303         //
00304 
00305         // router
00306         IPv4InterfaceData* interfaceData = new IPv4InterfaceData;
00307         interfaceData->setIPAddress(overlayNode->edge->IPAddress);
00308         interfaceData->setNetmask(IPAddress::ALLONES_ADDRESS);
00309         terminal.remoteInterfaceEntry->setIPv4Data(interfaceData);
00310 
00311         // terminal
00312         terminal.interfaceEntry->ipv4Data()->setIPAddress(IPAddress(terminal.IPAddress));
00313         terminal.interfaceEntry->ipv4Data()->setNetmask(IPAddress::ALLONES_ADDRESS);
00314 
00315         //
00316         // Fill in routing table.
00317         //
00318 
00319 
00320         // add edge routing entry
00321 
00322         IPRoute* re = new IPRoute();
00323         re->setHost(IPAddress(terminal.IPAddress));
00324         re->setNetmask(IPAddress::ALLONES_ADDRESS);
00325         re->setInterface(terminal.remoteInterfaceEntry);
00326         re->setType(IPRoute::DIRECT);
00327         re->setSource(IPRoute::MANUAL);
00328         overlayNode->edge->routingTable->addRoute(re);
00329         terminal.remoteRoutingEntry = re;
00330 
00331 
00332         //  add terminal routing entry
00333         IPRoute* te = new IPRoute();
00334         te->setHost(IPAddress::UNSPECIFIED_ADDRESS);
00335         te->setNetmask(IPAddress::UNSPECIFIED_ADDRESS);
00336         te->setGateway(overlayNode->edge->IPAddress);
00337         te->setInterface(terminal.interfaceEntry);
00338         te->setType(IPRoute::REMOTE);
00339         te->setSource(IPRoute::MANUAL);
00340         terminal.routingTable->addRoute(te);
00341         terminal.routingEntry = te;
00342 
00343         // append module to overlay terminal vector
00344         overlayTerminal.push_back(terminal);
00345         updateDisplayString();
00346         int ID = node->getId();
00347         return ID;
00348 }
00349 
00350 cModule* ConnectReaSE::removeOverlayNode(int ID)
00351 {
00352     Enter_Method("removeOverlayNode()");
00353 
00354     cModule* node = NULL;
00355     terminalInfo terminal;
00356     int index = 0;
00357     uint32 releasedIP;
00358 
00359     // find module
00360     for (unsigned int i=0; i<overlayTerminal.size(); i++) {
00361         if (overlayTerminal[i].module->getId() == ID) {
00362             terminal = overlayTerminal[i];
00363             node = terminal.module;
00364             index = i;
00365             break;
00366         }
00367     }
00368 
00369     if (node == NULL) return NULL;
00370 
00371 
00372     releasedIP = IPAddressResolver().addressOf(terminal.module).get4().getInt();;
00373 
00374     // free IP address
00375     for (unsigned int i=0; i < terminal.edgeRouter->IPAddresses.size(); i++) {
00376             if (terminal.edgeRouter->IPAddresses[i] == releasedIP) {
00377                 terminal.edgeRouter->IPAddresses.erase(terminal.edgeRouter->IPAddresses.begin() + i);
00378                 break;
00379             }
00380         }
00381 
00382 
00383     cModule* ppp = terminal.remotePPPInterface;
00384 
00385 
00386     // disconnect terminal
00387     node->gate("pppg$o", 0)->disconnect();
00388     node->gate("pppg$i", 0)->getPreviousGate()->disconnect();
00389 
00390     // disconnect ip and arp modules
00391     ppp->gate("netwIn")->getPathStartGate()->disconnect();
00392     ppp->gate("netwOut")->getNextGate()->disconnect();
00393 
00394     // remove associated ppp interface module
00395     ppp->callFinish();
00396     ppp->deleteModule();
00397 
00398     terminal.edgeRouter->countPPPInterfaces--;
00399 
00400     // remove associated interface table entry
00401     terminal.edgeRouter->interfaceTable->deleteInterface(terminal.remoteInterfaceEntry);
00402 
00403     // remove routing entries
00404 
00405     terminal.routingTable->deleteRoute(terminal.routingEntry);
00406     terminal.edgeRouter->routingTable ->deleteRoute(terminal.remoteRoutingEntry);
00407 
00408     //TODO: implement life vector statistics
00409     lifetimeVector.record(simTime() - overlayTerminal[index].createdAt);
00410 
00411     // remove terminal from overlay terminal vector
00412     overlayTerminal.erase(overlayTerminal.begin() + index);
00413 
00414      updateDisplayString();
00415 
00416     return node;
00417 }
00418 
00419 cModule* ConnectReaSE::getOverlayNode(int ID)
00420 {
00421     Enter_Method("getOverlayNode()");
00422 
00423     cModule* node = NULL;
00424 
00425     for (unsigned int i=0; i<overlayTerminal.size(); i++) {
00426         if (overlayTerminal[i].module->getId() == ID) {
00427             node = overlayTerminal[i].module;
00428             return node;
00429         }
00430     }
00431     opp_error("Node was not found in global list of overlay terminals");
00432     return node;
00433 }
00434 
00435 AccessInfo ConnectReaSE::migrateNode(int ID)
00436 {
00437 
00438     Enter_Method("migrateNode()");
00439 
00440     AccessInfo newEdgeRouter;
00441     terminalInfo terminal;
00442 
00443     for (unsigned int i=0; i<overlayTerminal.size(); i++) {
00444         if (overlayTerminal[i].module->getId() == ID) {
00445             terminal = overlayTerminal[i];
00446             break;
00447         }
00448     }
00449 
00450     if (terminal.module == NULL) opp_error("ConnectReaSE: Cannot find migrating node");
00451 
00452     do {
00453         newEdgeRouter = getAccessNode();
00454     }
00455     while ((newEdgeRouter.edge->Router->getId() == terminal.edgeRouter->Router->getId()) && (AS_Pool[terminal.ASindex].edgeRouter.size()!= 1));
00456 
00457     return newEdgeRouter;
00458 }
00459 
00460 void ConnectReaSE::handleMessage(cMessage* msg)
00461 {
00462     error("this module doesn't handle messages, it runs only in initialize()");
00463 }
00464 
00465 void ConnectReaSE::updateDisplayString()
00466 {
00467     if (ev.isGUI()) {
00468         char buf[80];
00469         if ( overlayTerminal.size() == 1 ) {
00470             sprintf(buf, "1 terminal connected");
00471         } else {
00472             sprintf(buf, "%zi terminals connected", overlayTerminal.size());
00473         }
00474         getDisplayString().setTagArg("t", 0, buf);
00475         getDisplayString().setTagArg("t", 2, "blue");
00476 
00477         if ((overlayTerminal.size() % 100) == 0) {
00478             cerr << "ConnectReaSE: " << overlayTerminal.size() << " Terminals connected in network." <<endl;
00479         }
00480     }
00481 }
00482 
00483 cGate* ConnectReaSE::firstUnusedGate(cModule* owner, const char* name, cGate::Type type)
00484 {
00485     int index;
00486     for (index = 0; index < owner->gateSize(name); index++) {
00487         cGate *gate = type == cGate::NONE ? owner->gate(name, index) : owner->gateHalf(name, type, index);
00488         if (!gate->isConnectedOutside()) {
00489             return gate;
00490         }
00491     }
00492 
00493     owner->setGateSize(name, index + 2);
00494     return type == cGate::NONE ? owner->gate(name, index + 1) : owner->gateHalf(name, type, index + 1);
00495 }
00496 
00497 bool ConnectReaSE::extractFromParentModule(cModule* currModule, void* properties)
00498 {
00499     topologyProperty* currProp = (topologyProperty*)properties;
00500 
00501     if (currModule->getParentModule() == currProp->pModule) {
00502         if (currModule->getProperties()->get(currProp->property)) {
00503             return true;
00504         }
00505     }
00506     return false;
00507 }
00508 
00509 void ConnectReaSE::setUpAS(cModule* currAS)
00510 {
00511 
00512     cTopology edgeTopo("Edges");
00513     cTopology Topo("All nodes");
00514     topologyProperty* tempProp = new topologyProperty;
00515     cModule* tempNode;
00516     uint32 tempIP;
00517     edgeRoutes tempEdge;
00518     autoSystem tempAS;
00519     int k;
00520 
00521     tempProp->pModule = currAS;
00522 
00523 
00524     tempProp->property = "EdgeRouter";
00525     edgeTopo.extractFromNetwork(extractFromParentModule, (void*) tempProp);
00526 
00527     tempProp->property = "RL";
00528     Topo.extractFromNetwork(extractFromParentModule, (void*) tempProp);
00529 
00530     //get net shift for IP address
00531 
00532     nextPow = 1;
00533     while ((1 << nextPow) < edgeTopo.getNumNodes() + 2) {
00534         nextPow++;
00535     }
00536     tempAS.edgeShift = ASShift - nextPow;
00537 
00538     // add information about edge router
00539 
00540     for (int i=0; i< edgeTopo.getNumNodes(); i++) {
00541 
00542         tempEdge.Router = edgeTopo.getNode(i)->getModule();
00543         tempEdge.IPAddress = IPAddressResolver().addressOf(tempEdge.Router).get4().getInt();
00544         tempEdge.IPAddresses.push_back(IPAddressResolver().addressOf(tempEdge.Router).get4().getInt());
00545         tempEdge.interfaceTable = IPAddressResolver().interfaceTableOf(tempEdge.Router);
00546         tempEdge.routingTable = IPAddressResolver().routingTableOf(tempEdge.Router);
00547 
00548         k = 0;
00549         while ( tempEdge.Router->findSubmodule("ppp", k) != -1 )
00550             k++;
00551         tempEdge.countPPPInterfaces = k;
00552 
00553         // the last allocated IP is the router address plus the (k - 1) connected ReaSE hosts
00554         tempEdge.lastIP = tempEdge.IPAddress + k - 1; // FIXME: check overlays for side effects of reused IP addresses
00555 
00556         // find hosts
00557 
00558         Topo.calculateUnweightedSingleShortestPathsTo(Topo.getNodeFor(edgeTopo.getNode(i)->getModule()));
00559 
00560         for (int j=0; j< Topo.getNumNodes(); j++) {
00561             tempNode = Topo.getNode(j)->getModule();
00562             if (tempNode->getProperties()->get("CoreRouter"))
00563                 continue;
00564             if (tempNode->getProperties()->get("GatewayRouter"))
00565                 continue;
00566             if (tempNode->getProperties()->get("EdgeRouter"))
00567                 continue;
00568             if (Topo.getNode(j)->getPath(0)->getRemoteNode()->getModule() != edgeTopo.getNode(i)->getModule())
00569                 continue;
00570 
00571             //fill IP table
00572             tempIP = IPAddressResolver().addressOf(Topo.getNode(j)->getModule()).get4().getInt();
00573             tempEdge.IPAddresses.push_back(tempIP);
00574         }
00575 
00576         tempAS.edgeRouter.push_back(tempEdge);
00577     }
00578 
00579     delete tempProp;
00580     AS_Pool.push_back(tempAS);
00581 }