OverSim
ConnectReaSE.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2010 Institut fuer Telematik, Karlsruher Institut fuer Technologie (KIT)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
25 #include <vector>
26 #include <iostream>
27 
28 #include <omnetpp.h>
29 
30 #include <IRoutingTable.h>
31 #include <IInterfaceTable.h>
32 #include <IPAddressResolver.h>
33 #include <IPv4InterfaceData.h>
34 
35 #include "ConnectReaSE.h"
36 
37 using namespace ::std;
38 
40 
41 std::ostream& operator<<(std::ostream& os, terminalInfo& n)
42 {
43  os << n.module;
44  return os;
45 }
46 
47 void ConnectReaSE::initialize(int stage)
48 {
49  //EV << "Connector Stage" << stage;
50  if (stage != MAX_STAGE_UNDERLAY)
51  return;
52 
53  //get parameters
54  channelTypesTx = cStringTokenizer(par("channelTypes"), " ").asVector();
55  channelTypesRx = cStringTokenizer(par("channelTypesRx"), " ").asVector();
56  channelDiversity = par("channelDiversity");
57 
58  if (channelTypesTx.size() < channelTypesRx.size()) {
60  }
61  else if (channelTypesTx.size() > channelTypesRx.size()) {
63  }
64 
65  // make sure that delay cannot be zero and diversity cannot be below zero
66  if (channelDiversity>=100)
67  channelDiversity = 99.99f;
68  else if (channelDiversity<0)
69  channelDiversity = 0;
70 
71  // statistics
72  lifetimeVector.setName("Terminal Lifetime");
73 
74  // set up network
75 
76  cModule* tempModule;
77  cTopology tempTopology("tempTopo");
78  edgePool tempEdgePool;
79 
80 
81  tempTopology.extractByProperty("AS");
82  totalCountOfAS = tempTopology.getNumNodes();
83 
84  nextPow = 0;
85  while (((uint32_t) 1 << nextPow) < totalCountOfAS + 1) {
86  nextPow++;
87  }
88  ASShift = 32 - nextPow;
89 
90  if (tempTopology.getNumNodes() == 0) {
91 
92  //no AS topology
93 
94  tempTopology.extractByProperty("RL");
95 
96  if (tempTopology.getNumNodes() == 0)
97 
98  //no router topology
99  opp_error("ConnectReaSE: Neither an AS topology nor a router topology was detected.");
100 
101  setUpAS(getParentModule());
102  }
103  else {
104 
105  // set up all autonomous systems (AS)
106  int index = 0;
107  std::vector<cModule*> Modules;
108  for (int i=0; i<tempTopology.getNumNodes(); i++) {
109 
110  tempModule = tempTopology.getNode(i)->getModule();
111  Modules.push_back(tempModule);
112  index++;
113  }
114  for (uint32 i=0; i< Modules.size(); i++) {
115  setUpAS(Modules[i]);
116  }
117  }
118 
119  // put all edge router in one data structure to get a equal probability of selection
120  for (uint32 i=0; i<AS_Pool.size(); i++) {
121  for (uint32 j=0; j< AS_Pool[i].edgeRouter.size(); j++) {
122  tempEdgePool.edge = &AS_Pool[i].edgeRouter[j];
123  tempEdgePool.indexAS = i;
124  globalEdgePool.push_back(tempEdgePool);
125  }
126  }
127  //cout << "Number of Edges in Network: " << globalEdgePool.size() << endl;
128 
129  for (uint32 i=0; i<globalEdgePool.size(); i++) {
130 
131  //select channel
132  globalEdgePool[i].edge->channelTypeTxStr = channelTypesTx[intuniform(0,channelTypesTx.size()-1)];
133  globalEdgePool[i].edge->channelTypeRxStr = channelTypesRx[intuniform(0,channelTypesRx.size()-1)];
134  }
135 }
136 
138 {
139  Enter_Method("getAccessNode()");
140 
141  bool candidateOK = false;
142  int numTries = 10;
143  uint32 test_IP = 0;
144  AccessInfo node;
145  edgeRoutes* connectionCandidate;
146  uint32 tempIndex, tempASindex;
147 
148  while ((numTries > 0)&&(!candidateOK)) {
149  numTries--;
150  tempIndex = intuniform(0, globalEdgePool.size()-1);
151  connectionCandidate = globalEdgePool[tempIndex].edge;
152  tempASindex = globalEdgePool[tempIndex].indexAS;
153 
154  //limit terminals per edge router
155  if (connectionCandidate->IPAddresses.size() >= ((uint32_t) 1 << AS_Pool[tempASindex].edgeShift)) // maximum reached?
156  continue;
157 
158 // test_IP = connectionCandidate->IPAddress + 1; // begin with first IP after the edge router
159 // for (int i = 0; i < (1 << AS_Pool[tempASindex].edgeShift); i++ ) {
160 // test_IP += i;
161 // candidateOK = true;
162 // for (uint32 j = 0; j < connectionCandidate->IPAddresses.size(); j++) {
163 // if (connectionCandidate->IPAddresses[j] == test_IP) {
164 // candidateOK =false;
165 // break;
166 // }
167 // }
168 // if (candidateOK) {
169 // connectionCandidate->IPAddresses.push_back(test_IP);
170 // break;
171 // }
172 // }
173 
174  // FIXME: check overlays for side effects of reused IP addresses
175 
176  test_IP = ++connectionCandidate->lastIP;
177  connectionCandidate->IPAddresses.push_back(test_IP);
178  break;
179 
180  }
181 
182  // no free IP address after 10 tries
183  if (numTries == 0) {
184  opp_error("Error creating node: No available IP found after four tries!");
185  }
186  EV << "Found available IP: " << test_IP;
187 
188  node.ASindex = tempASindex;
189  node.IPAddress = test_IP;
190  node.edge = connectionCandidate;
191  return node;
192 }
193 
194 int ConnectReaSE::addOverlayNode(AccessInfo* overlayNode, bool migrate)
195 {
196  Enter_Method("addOverlayNode()");
197 
198  cModule* node = overlayNode->terminal;
199  terminalInfo terminal;
200 
201  terminal.module = node;
202  terminal.interfaceTable = IPAddressResolver().interfaceTableOf(node);
203  terminal.remoteInterfaceTable = overlayNode->edge->interfaceTable;
204  terminal.routingTable = IPAddressResolver().routingTableOf(node);
205  terminal.PPPInterface = node->getSubmodule("ppp", 0);
206  terminal.createdAt = simTime();
207  terminal.IPAddress = overlayNode->IPAddress;
208  terminal.edgeRouter = overlayNode->edge;
209  terminal.ASindex = overlayNode->ASindex;
210 
211  // update display
212  if (ev.isGUI()) {
213  const char* ip_disp = const_cast<char*>
214  (IPAddress(terminal.IPAddress).str().c_str());
215  terminal.module->getDisplayString().insertTag("t", 0);
216  terminal.module->getDisplayString().setTagArg("t", 0, ip_disp);
217  terminal.module->getDisplayString().setTagArg("t", 1, "l");
218  }
219 
220  //find first unused interface
221  int k = 1;
222  while ( overlayNode->edge->Router->findSubmodule("ppp", k) != -1 )
223  k++;
224 
225 
226  cModuleType* pppInterfaceModuleType = cModuleType::get("inet.linklayer.ppp.PPPInterface");
227  terminal.remotePPPInterface = pppInterfaceModuleType->
228  create("ppp", overlayNode->edge->Router, 0, k);
229 
230  overlayNode->edge->countPPPInterfaces++;
231 
232 
233  // connect terminal to access router and vice versa
234  cGate* routerInGate = firstUnusedGate(overlayNode->edge->Router, "pppg", cGate::INPUT);
235  cGate* routerOutGate = firstUnusedGate(overlayNode->edge->Router, "pppg", cGate::OUTPUT);
236 
237  cChannelType* channelTypeRx = cChannelType::find( overlayNode->edge->channelTypeRxStr.c_str() );
238  cChannelType* channelTypeTx = cChannelType::find( overlayNode->edge->channelTypeTxStr.c_str() );
239  if (!channelTypeRx || !channelTypeTx)
240  opp_error("Could not find Channel or ChannelRx Type. Most likely "
241  "parameter channelTypes does not match the channels defined "
242  "in channels.ned");
243 
244  //create channels
245  cDatarateChannel* channelRx = check_and_cast<cDatarateChannel*>(channelTypeRx->create(overlayNode->edge->channelTypeRxStr.c_str()));
246  cDatarateChannel* channelTx = check_and_cast<cDatarateChannel*>(channelTypeTx->create(overlayNode->edge->channelTypeTxStr.c_str()));
247 
248  //connect terminal
249  terminal.module->gate("pppg$o", 0)->connectTo(routerInGate,channelRx);
250  routerOutGate->connectTo(terminal.module->gate("pppg$i", 0),channelTx);
251 
252  // connect ppp interface module to router module and vice versa
253  routerInGate->connectTo(terminal.remotePPPInterface->gate("phys$i"));
254  terminal.remotePPPInterface->gate("phys$o")->connectTo(routerOutGate);
255 
256  // connect ppp interface module to network layer module and vice versa
257  cModule* netwModule = overlayNode->edge->Router->getSubmodule("networkLayer");
258 
259  cGate* netwInGate = firstUnusedGate(netwModule, "ifIn");
260  cGate* netwOutGate = firstUnusedGate(netwModule, "ifOut");
261 
262  netwOutGate->connectTo(terminal.remotePPPInterface->gate("netwIn"));
263  terminal.remotePPPInterface->gate("netwOut")->connectTo(netwInGate);
264 
265  // connect network layer module to ip and arp modules
266  cModule* ipModule = overlayNode->edge->Router->getSubmodule("networkLayer")->
267  getSubmodule("ip");
268 
269  cGate* ipIn = firstUnusedGate(ipModule, "queueIn");
270  netwInGate->connectTo(ipIn);
271 
272  //
273  // Start ppp interface modules
274  //
275  terminal.remotePPPInterface->finalizeParameters();
276  terminal.remotePPPInterface->setDisplayString("i=block/ifcard");
277  terminal.remotePPPInterface->buildInside();
278  terminal.remotePPPInterface->scheduleStart(simTime());
279  terminal.remotePPPInterface->callInitialize();
280 
281  if ( !migrate) {
282  // we are already in stage 4 and need to call initialize
283  // for all previous stages manually
284  for (int i=0; i < MAX_STAGE_UNDERLAY + 1; i++) {
285  terminal.module->callInitialize(i);
286  }
287  }
288 
289  //calculate diversity factor for both channels (+/- diversity)
290  double diversityFactor = (uniform(0 , 2*channelDiversity) + (100-channelDiversity))/100;
291 
292  //customize channel delays
293  channelRx->setDelay(SIMTIME_DBL(channelRx->getDelay()*diversityFactor));
294  channelTx->setDelay(SIMTIME_DBL(channelTx->getDelay()*diversityFactor));
295 
296  terminal.remoteInterfaceEntry = overlayNode->edge->interfaceTable->getInterface(
297  overlayNode->edge->interfaceTable->getNumInterfaces() - 1);
298  terminal.interfaceEntry = terminal.interfaceTable->getInterfaceByName("ppp0");
299 
300 
301  //
302  // Fill in interface table.
303  //
304 
305  // router
306  IPv4InterfaceData* interfaceData = new IPv4InterfaceData;
307  interfaceData->setIPAddress(overlayNode->edge->IPAddress);
308  interfaceData->setNetmask(IPAddress::ALLONES_ADDRESS);
309  terminal.remoteInterfaceEntry->setIPv4Data(interfaceData);
310 
311  // terminal
312  terminal.interfaceEntry->ipv4Data()->setIPAddress(IPAddress(terminal.IPAddress));
313  terminal.interfaceEntry->ipv4Data()->setNetmask(IPAddress::ALLONES_ADDRESS);
314 
315  //
316  // Fill in routing table.
317  //
318 
319 
320  // add edge routing entry
321 
322  IPRoute* re = new IPRoute();
323  re->setHost(IPAddress(terminal.IPAddress));
324  re->setNetmask(IPAddress::ALLONES_ADDRESS);
325  re->setInterface(terminal.remoteInterfaceEntry);
326  re->setType(IPRoute::DIRECT);
327  re->setSource(IPRoute::MANUAL);
328  overlayNode->edge->routingTable->addRoute(re);
329  terminal.remoteRoutingEntry = re;
330 
331 
332  // add terminal routing entry
333  IPRoute* te = new IPRoute();
334  te->setHost(IPAddress::UNSPECIFIED_ADDRESS);
335  te->setNetmask(IPAddress::UNSPECIFIED_ADDRESS);
336  te->setGateway(overlayNode->edge->IPAddress);
337  te->setInterface(terminal.interfaceEntry);
338  te->setType(IPRoute::REMOTE);
339  te->setSource(IPRoute::MANUAL);
340  terminal.routingTable->addRoute(te);
341  terminal.routingEntry = te;
342 
343  // append module to overlay terminal vector
344  overlayTerminal.push_back(terminal);
346  int ID = node->getId();
347  return ID;
348 }
349 
351 {
352  Enter_Method("removeOverlayNode()");
353 
354  cModule* node = NULL;
355  terminalInfo terminal;
356  int index = 0;
357  uint32 releasedIP;
358 
359  // find module
360  for (unsigned int i=0; i<overlayTerminal.size(); i++) {
361  if (overlayTerminal[i].module->getId() == ID) {
362  terminal = overlayTerminal[i];
363  node = terminal.module;
364  index = i;
365  break;
366  }
367  }
368 
369  if (node == NULL) return NULL;
370 
371 
372  releasedIP = IPAddressResolver().addressOf(terminal.module).get4().getInt();;
373 
374  // free IP address
375  for (unsigned int i=0; i < terminal.edgeRouter->IPAddresses.size(); i++) {
376  if (terminal.edgeRouter->IPAddresses[i] == releasedIP) {
377  terminal.edgeRouter->IPAddresses.erase(terminal.edgeRouter->IPAddresses.begin() + i);
378  break;
379  }
380  }
381 
382 
383  cModule* ppp = terminal.remotePPPInterface;
384 
385 
386  // disconnect terminal
387  node->gate("pppg$o", 0)->disconnect();
388  node->gate("pppg$i", 0)->getPreviousGate()->disconnect();
389 
390  // disconnect ip and arp modules
391  ppp->gate("netwIn")->getPathStartGate()->disconnect();
392  ppp->gate("netwOut")->getNextGate()->disconnect();
393 
394  // remove associated ppp interface module
395  ppp->callFinish();
396  ppp->deleteModule();
397 
398  terminal.edgeRouter->countPPPInterfaces--;
399 
400  // remove associated interface table entry
401  terminal.edgeRouter->interfaceTable->deleteInterface(terminal.remoteInterfaceEntry);
402 
403  // remove routing entries
404 
405  terminal.routingTable->deleteRoute(terminal.routingEntry);
406  terminal.edgeRouter->routingTable ->deleteRoute(terminal.remoteRoutingEntry);
407 
408  //TODO: implement life vector statistics
409  lifetimeVector.record(simTime() - overlayTerminal[index].createdAt);
410 
411  // remove terminal from overlay terminal vector
412  overlayTerminal.erase(overlayTerminal.begin() + index);
413 
415 
416  return node;
417 }
418 
420 {
421  Enter_Method("getOverlayNode()");
422 
423  cModule* node = NULL;
424 
425  for (unsigned int i=0; i<overlayTerminal.size(); i++) {
426  if (overlayTerminal[i].module->getId() == ID) {
427  node = overlayTerminal[i].module;
428  return node;
429  }
430  }
431  opp_error("Node was not found in global list of overlay terminals");
432  return node;
433 }
434 
436 {
437 
438  Enter_Method("migrateNode()");
439 
440  AccessInfo newEdgeRouter;
441  terminalInfo terminal;
442 
443  for (unsigned int i=0; i<overlayTerminal.size(); i++) {
444  if (overlayTerminal[i].module->getId() == ID) {
445  terminal = overlayTerminal[i];
446  break;
447  }
448  }
449 
450  if (terminal.module == NULL) opp_error("ConnectReaSE: Cannot find migrating node");
451 
452  do {
453  newEdgeRouter = getAccessNode();
454  }
455  while ((newEdgeRouter.edge->Router->getId() == terminal.edgeRouter->Router->getId()) && (AS_Pool[terminal.ASindex].edgeRouter.size()!= 1));
456 
457  return newEdgeRouter;
458 }
459 
460 void ConnectReaSE::handleMessage(cMessage* msg)
461 {
462  error("this module doesn't handle messages, it runs only in initialize()");
463 }
464 
466 {
467  if (ev.isGUI()) {
468  char buf[80];
469  if ( overlayTerminal.size() == 1 ) {
470  sprintf(buf, "1 terminal connected");
471  } else {
472  sprintf(buf, "%zi terminals connected", overlayTerminal.size());
473  }
474  getDisplayString().setTagArg("t", 0, buf);
475  getDisplayString().setTagArg("t", 2, "blue");
476 
477  if ((overlayTerminal.size() % 100) == 0) {
478  cerr << "ConnectReaSE: " << overlayTerminal.size() << " Terminals connected in network." <<endl;
479  }
480  }
481 }
482 
483 cGate* ConnectReaSE::firstUnusedGate(cModule* owner, const char* name, cGate::Type type)
484 {
485  int index;
486  for (index = 0; index < owner->gateSize(name); index++) {
487  cGate *gate = type == cGate::NONE ? owner->gate(name, index) : owner->gateHalf(name, type, index);
488  if (!gate->isConnectedOutside()) {
489  return gate;
490  }
491  }
492 
493  owner->setGateSize(name, index + 2);
494  return type == cGate::NONE ? owner->gate(name, index + 1) : owner->gateHalf(name, type, index + 1);
495 }
496 
497 bool ConnectReaSE::extractFromParentModule(cModule* currModule, void* properties)
498 {
499  topologyProperty* currProp = (topologyProperty*)properties;
500 
501  if (currModule->getParentModule() == currProp->pModule) {
502  if (currModule->getProperties()->get(currProp->property)) {
503  return true;
504  }
505  }
506  return false;
507 }
508 
509 void ConnectReaSE::setUpAS(cModule* currAS)
510 {
511 
512  cTopology edgeTopo("Edges");
513  cTopology Topo("All nodes");
514  topologyProperty* tempProp = new topologyProperty;
515  cModule* tempNode;
516  uint32 tempIP;
517  edgeRoutes tempEdge;
518  autoSystem tempAS;
519  int k;
520 
521  tempProp->pModule = currAS;
522 
523 
524  tempProp->property = "EdgeRouter";
525  edgeTopo.extractFromNetwork(extractFromParentModule, (void*) tempProp);
526 
527  tempProp->property = "RL";
528  Topo.extractFromNetwork(extractFromParentModule, (void*) tempProp);
529 
530  //get net shift for IP address
531 
532  nextPow = 1;
533  while ((1 << nextPow) < edgeTopo.getNumNodes() + 2) {
534  nextPow++;
535  }
536  tempAS.edgeShift = ASShift - nextPow;
537 
538  // add information about edge router
539 
540  for (int i=0; i< edgeTopo.getNumNodes(); i++) {
541 
542  tempEdge.Router = edgeTopo.getNode(i)->getModule();
543  tempEdge.IPAddress = IPAddressResolver().addressOf(tempEdge.Router).get4().getInt();
544  tempEdge.IPAddresses.push_back(IPAddressResolver().addressOf(tempEdge.Router).get4().getInt());
545  tempEdge.interfaceTable = IPAddressResolver().interfaceTableOf(tempEdge.Router);
546  tempEdge.routingTable = IPAddressResolver().routingTableOf(tempEdge.Router);
547 
548  k = 0;
549  while ( tempEdge.Router->findSubmodule("ppp", k) != -1 )
550  k++;
551  tempEdge.countPPPInterfaces = k;
552 
553  // the last allocated IP is the router address plus the (k - 1) connected ReaSE hosts
554  tempEdge.lastIP = tempEdge.IPAddress + k - 1; // FIXME: check overlays for side effects of reused IP addresses
555 
556  // find hosts
557 
558  Topo.calculateUnweightedSingleShortestPathsTo(Topo.getNodeFor(edgeTopo.getNode(i)->getModule()));
559 
560  for (int j=0; j< Topo.getNumNodes(); j++) {
561  tempNode = Topo.getNode(j)->getModule();
562  if (tempNode->getProperties()->get("CoreRouter"))
563  continue;
564  if (tempNode->getProperties()->get("GatewayRouter"))
565  continue;
566  if (tempNode->getProperties()->get("EdgeRouter"))
567  continue;
568  if (Topo.getNode(j)->getPath(0)->getRemoteNode()->getModule() != edgeTopo.getNode(i)->getModule())
569  continue;
570 
571  //fill IP table
572  tempIP = IPAddressResolver().addressOf(Topo.getNode(j)->getModule()).get4().getInt();
573  tempEdge.IPAddresses.push_back(tempIP);
574  }
575 
576  tempAS.edgeRouter.push_back(tempEdge);
577  }
578 
579  delete tempProp;
580  AS_Pool.push_back(tempAS);
581 }