OverSim
InetUnderlayConfigurator.cc
Go to the documentation of this file.
1 //
2 // This program is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU General Public License
4 // as published by the Free Software Foundation; either version 2
5 // of the License, or (at your option) any later version.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11 //
12 // You should have received a copy of the GNU General Public License
13 // along with this program; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 //
16 
23 
24 #include <GlobalNodeList.h>
25 #include <TransportAddress.h>
26 
27 #include <StringConvert.h>
28 
29 #include <AccessNet.h>
30 #include <IRoutingTable.h>
31 #include <RoutingTable6.h>
32 #include <IInterfaceTable.h>
33 #include <IPAddressResolver.h>
34 #include <IPv4InterfaceData.h>
35 #include <IPv6InterfaceData.h>
36 #include <NotificationBoard.h>
37 
38 
39 #include <InetInfo.h>
40 
42 
44 {
45  //backbone configuration
46  if (stage == MIN_STAGE_UNDERLAY) {
47  // Find all router modules.
48  cTopology topo("topo");
49  topo.extractByProperty("node");
50 
51  if (par("useIPv6Addresses").boolValue()) {
52  setUpIPv6(topo);
53  //opp_error("IPv6 is not supported in this release but is coming soon.");
54  } else {
55  setUpIPv4(topo);
56  }
57  }
58  //access net configuration
59  else if(stage == MAX_STAGE_UNDERLAY) {
60  // fetch some parameters
61  accessRouterNum = getParentModule()->par("accessRouterNum");
62  overlayAccessRouterNum = getParentModule()->par("overlayAccessRouterNum");
63 
64  // count the overlay clients
66 
67  numCreated = 0;
68  numKilled = 0;
69 
70  // add access node modules to access node vector
71  cModule* node;
72  for (int i = 0; i < accessRouterNum; i++) {
73  node = getParentModule()->getSubmodule("accessRouter", i);
74  accessNode.push_back( node );
75  }
76 
77  for (int i = 0; i < overlayAccessRouterNum; i++) {
78  node = getParentModule()->getSubmodule("overlayAccessRouter", i);
79  accessNode.push_back( node );
80  }
81 
82  // debug stuff
83  WATCH_PTRVECTOR(accessNode);
84  }
85 }
86 
88 {
89  Enter_Method_Silent();
90  // derive overlay node from ned
91  std::string nameStr = "overlayTerminal";
92  if( churnGenerator.size() > 1 ){
93  nameStr += "-" + convertToString<uint32_t>(type.typeID);
94  }
95  cModuleType* moduleType = cModuleType::get(type.terminalType.c_str());
96  cModule* node = moduleType->create(nameStr.c_str(), getParentModule(),
97  numCreated + 1, numCreated);
98 
99  if (type.channelTypesTx.size() > 0) {
100  throw cRuntimeError("InetUnderlayConfigurator::createNode(): Setting "
101  "channel types via the churn generator is not allowed "
102  "with the InetUnderlay. Use **.accessNet.channelTypes instead!");
103  }
104 
105  node->setGateSize("pppg", 1);
106 
107  std::string displayString;
108 
109  if ((type.typeID > 0) && (type.typeID <= NUM_COLORS)) {
110  ((displayString += "i=device/wifilaptop_l,")
111  += colorNames[type.typeID - 1])
112  += ",40;i2=block/circle_s";
113  } else {
114  displayString = "i=device/wifilaptop_l;i2=block/circle_s";
115  }
116 
117  node->finalizeParameters();
118  node->setDisplayString(displayString.c_str());
119 
120  node->buildInside();
121  node->scheduleStart(simTime());
122 
123  // create meta information
124  InetInfo* info = new InetInfo(type.typeID, node->getId(), type.context);
125  AccessNet* accessNet= check_and_cast<AccessNet*>
126  (accessNode[intuniform(0, accessNode.size() - 1)]
127  ->getSubmodule("accessNet"));
128 
129  info->setAccessNetModule(accessNet);
130  info->setNodeID(node->getId());
131 
132  // add node to a randomly chosen access net and bootstrap oracle
133  globalNodeList->addPeer(accessNet->addOverlayNode(node), info);
134 
135  // if the node was not created during startup we have to
136  // finish the initialization process manually
137  if (!initialize) {
138  for (int i = MAX_STAGE_UNDERLAY + 1; i < NUM_STAGES_ALL; i++) {
139  node->callInitialize(i);
140  }
141  }
142 
144  numCreated++;
145 
146  churnGenerator[type.typeID]->terminalCount++;
147 
148  TransportAddress *address = new TransportAddress(
149  IPAddressResolver().addressOf(node));
150 
151  // update display
153 
154  return address;
155 }
156 
157 //TODO: getRandomNode()
159 {
160  Enter_Method_Silent();
161 
162  AccessNet* accessNetModule = NULL;
163  int nodeID;
164  InetInfo* info;
165 
166  // If no address given, get random node
167  if (addr == NULL) {
169 
170  if (addr == NULL) {
171  // all nodes are already prekilled
172  std::cout << "all nodes are already prekilled" << std::endl;
173  return;
174  }
175  }
176 
177  // get node information
178  info = dynamic_cast<InetInfo*>(globalNodeList->getPeerInfo(*addr));
179 
180  if (info != NULL) {
181  accessNetModule = info->getAccessNetModule();
182  nodeID = info->getNodeID();
183  } else {
184  opp_error("IPv4UnderlayConfigurator: Trying to pre kill node "
185  "with nonexistant TransportAddress!");
186  }
187 
188  uint32_t effectiveType = info->getTypeID();
189 
190  // do not kill node that is already scheduled
191  if(scheduledID.count(nodeID))
192  return;
193 
194  cModule* node = accessNetModule->getOverlayNode(nodeID);
195  globalNodeList->removePeer(IPAddressResolver().addressOf(node));
196 
197  //put node into the kill list and schedule a message for final removal of the node
198  killList.push_front(IPAddressResolver().addressOf(node));
199  scheduledID.insert(nodeID);
200 
202  numKilled++;
203 
204  churnGenerator[effectiveType]->terminalCount--;
205 
206  // update display
208 
209  // inform the notification board about the removal
210  NotificationBoard* nb = check_and_cast<NotificationBoard*>(
211  node->getSubmodule("notificationBoard"));
212  nb->fireChangeNotification(NF_OVERLAY_NODE_LEAVE);
213 
214  double random = uniform(0, 1);
215 
216  if (random < gracefulLeaveProbability) {
217  nb->fireChangeNotification(NF_OVERLAY_NODE_GRACEFUL_LEAVE);
218  }
219 
220  cMessage* msg = new cMessage();
221  scheduleAt(simTime() + gracefulLeaveDelay, msg);
222 
223 }
224 
226 {
227  Enter_Method_Silent();
228 
229  AccessNet* accessNetModule = NULL;
230  int nodeID = -1;
231  InetInfo* info;
232 
233  // If no address given, get random node
234  if(addr == NULL) {
235  info = dynamic_cast<InetInfo*>(globalNodeList->getRandomPeerInfo(type.typeID));
236  } else {
237  // get node information
238  info = dynamic_cast<InetInfo*>(globalNodeList->getPeerInfo(*addr));
239  }
240 
241  if(info != NULL) {
242  accessNetModule = info->getAccessNetModule();
243  nodeID = info->getNodeID();
244  } else {
245  opp_error("IPv4UnderlayConfigurator: Trying to pre kill node with nonexistant TransportAddress!");
246  }
247 
248  // do not migrate node that is already scheduled
249  if(scheduledID.count(nodeID))
250  return;
251 
252  cModule* node = accessNetModule->removeOverlayNode(nodeID);//intuniform(0, accessNetModule->size() - 1));
253 
254  if(node == NULL)
255  opp_error("IPv4UnderlayConfigurator: Trying to remove node which is nonexistant in AccessNet!");
256 
257  //remove node from bootstrap oracle
258  globalNodeList->killPeer(IPAddressResolver().addressOf(node));
259 
260  node->bubble("I am migrating!");
261 
262  // connect the node to another access net
263  AccessNet* newAccessNetModule;
264 
265  do {
266  newAccessNetModule = check_and_cast<AccessNet*>(accessNode[intuniform(0, accessNode.size() - 1)]->getSubmodule("accessNet"));
267  } while((newAccessNetModule == accessNetModule) && (accessNode.size() != 1));
268 
269  // create meta information
270  InetInfo* newinfo = new InetInfo(type.typeID, node->getId(), type.context);
271 
272  newinfo->setAccessNetModule(newAccessNetModule);
273  newinfo->setNodeID(node->getId());
274 
275  //add node to a randomly chosen access net bootstrap oracle
276  globalNodeList->addPeer(newAccessNetModule->addOverlayNode(node, true), newinfo);
277 
278  // inform the notification board about the migration
279  NotificationBoard* nb = check_and_cast<NotificationBoard*>(node->getSubmodule("notificationBoard"));
280  nb->fireChangeNotification(NF_OVERLAY_TRANSPORTADDRESS_CHANGED);
281 }
282 
284 {
285  Enter_Method_Silent();
286 
287  // get next scheduled node from the kill list
288  IPvXAddress addr = killList.back();
289  killList.pop_back();
290 
291  AccessNet* accessNetModule = NULL;
292  int nodeID = -1;
293 
294  InetInfo* info = dynamic_cast<InetInfo*>(globalNodeList->getPeerInfo(addr));
295  if(info != NULL) {
296  accessNetModule = info->getAccessNetModule();
297  nodeID = info->getNodeID();
298  } else {
299  opp_error("IPv4UnderlayConfigurator: Trying to kill node with nonexistant TransportAddress!");
300  }
301 
302  scheduledID.erase(nodeID);
303  globalNodeList->killPeer(addr);
304 
305  cModule* node = accessNetModule->removeOverlayNode(nodeID);
306 
307  if(node == NULL)
308  opp_error("IPv4UnderlayConfigurator: Trying to remove node which is nonexistant in AccessNet!");
309 
310  node->callFinish();
311  node->deleteModule();
312 
313  delete msg;
314 }
315 
317 {
318  char buf[80];
319  sprintf(buf, "%i overlay terminals\n%i access router\n%i overlay access router",
321  getDisplayString().setTagArg("t", 0, buf);
322 }
323 
325 {
326  // statistics
327  recordScalar("Terminals added", numCreated);
328  recordScalar("Terminals removed", numKilled);
329 
330  if (!isInInitPhase()) {
331  struct timeval now, diff;
332  gettimeofday(&now, NULL);
333  timersub(&now, &initFinishedTime, &diff);
334  printf("Simulation time: %li.%06li\n", diff.tv_sec, diff.tv_usec);
335  }
336 }
337 
339 {
340  // Assign IP addresses to all router modules.
341  std::vector<uint32> nodeAddresses;
342  nodeAddresses.resize(topo.getNumNodes());
343 
344  // IP addresses for backbone
345  // Take start IP from config file
346  // FIXME: Make Netmask for Routers configurable!
347  uint32 lowIPBoundary = IPAddress(par("startIPv4").stringValue()).getInt();
348 
349  // uint32 lowIPBoundary = uint32((1 << 24) + 1);
350  int numIPNodes = 0;
351 
352  for (int i = 0; i < topo.getNumNodes(); i++) {
353  ++numIPNodes;
354 
355  uint32 addr = lowIPBoundary + uint32(numIPNodes << 16);
356  nodeAddresses[i] = addr;
357 
358  // update ip display string
359  if (ev.isGUI()) {
360  topo.getNode(i)->getModule()->getDisplayString().insertTag("t", 0);
361  topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 0,
362  const_cast<char*>(IPAddress(addr).str().c_str()));
363  topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 1, "l");
364  topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 2, "red");
365  }
366 
367  // find interface table and assign address to all (non-loopback) interfaces
368  IInterfaceTable* ift = IPAddressResolver().interfaceTableOf(topo.getNode(i)->getModule());
369 
370  for ( int k = 0; k < ift->getNumInterfaces(); k++ ) {
371  InterfaceEntry* ie = ift->getInterface(k);
372  if (!ie->isLoopback()) {
373  ie->ipv4Data()->setIPAddress(IPAddress(addr));
374  // full address must match for local delivery
375  ie->ipv4Data()->setNetmask(IPAddress::ALLONES_ADDRESS);
376  }
377  }
378  }
379 
380  // Fill in routing tables.
381  for (int i = 0; i < topo.getNumNodes(); i++) {
382  cTopology::Node* destNode = topo.getNode(i);
383  uint32 destAddr = nodeAddresses[i];
384 
385  // calculate shortest paths from everywhere towards destNode
386  topo.calculateUnweightedSingleShortestPathsTo(destNode);
387 
388  // add overlayAccessRouters and overlayBackboneRouters
389  // to the GlobalNodeList
390  if ((strcmp(destNode->getModule()->getName(), "overlayBackboneRouter") == 0) ||
391  (strcmp(destNode->getModule()->getName(), "overlayAccessRouter") == 0)) {
392  //add node to bootstrap oracle
393  PeerInfo* info = new PeerInfo(0, destNode->getModule()->getId(), NULL);
394  globalNodeList->addPeer(IPvXAddress(nodeAddresses[i]), info);
395  }
396 
397 
398  // If destNode is the outRouter, add a default route
399  // to outside network via the TunOutDevice and a route to the
400  // Gateway
401  if ( strcmp(destNode->getModule()->getName(), "outRouter" ) == 0 ) {
402  IPRoute* defRoute = new IPRoute();
403  defRoute->setHost(IPAddress::UNSPECIFIED_ADDRESS);
404  defRoute->setNetmask(IPAddress::UNSPECIFIED_ADDRESS);
405  defRoute->setGateway(IPAddress(par("gatewayIP").stringValue()));
406  defRoute->setInterface(IPAddressResolver().interfaceTableOf(destNode->getModule())->getInterfaceByName("tunDev"));
407  defRoute->setType(IPRoute::REMOTE);
408  defRoute->setSource(IPRoute::MANUAL);
409  IPAddressResolver().routingTableOf(destNode->getModule())->addRoute(defRoute);
410 
411  IPRoute* gwRoute = new IPRoute();
412  gwRoute->setHost(IPAddress(par("gatewayIP").stringValue()));
413  gwRoute->setNetmask(IPAddress(255, 255, 255, 255));
414  gwRoute->setInterface(IPAddressResolver().interfaceTableOf(destNode->getModule())->getInterfaceByName("tunDev"));
415  gwRoute->setType(IPRoute::DIRECT);
416  gwRoute->setSource(IPRoute::MANUAL);
417  IPAddressResolver().routingTableOf(destNode->getModule())->addRoute(gwRoute);
418  }
419 
420  // add route (with host=destNode) to every routing table in the network
421  for (int j = 0; j < topo.getNumNodes(); j++) {
422  // continue if same node
423  if (i == j)
424  continue;
425 
426  // cancel simulation if node is not connected with destination
427  cTopology::Node* atNode = topo.getNode(j);
428 
429  if (atNode->getNumPaths() == 0) {
430  error((std::string(atNode->getModule()->getName()) + ": Network is not entirely connected."
431  "Please increase your value for the "
432  "connectivity parameter").c_str());
433  }
434 
435  //
436  // Add routes at the atNode.
437  //
438 
439  // find atNode's interface and routing table
440  IInterfaceTable* ift = IPAddressResolver().interfaceTableOf(atNode->getModule());
441  IRoutingTable* rt = IPAddressResolver().routingTableOf(atNode->getModule());
442 
443  // find atNode's interface entry for the next hop node
444  int outputGateId = atNode->getPath(0)->getLocalGate()->getId();
445  InterfaceEntry *ie = ift->getInterfaceByNodeOutputGateId(outputGateId);
446 
447  // find the next hop node on the path towards destNode
448  cModule* next_hop = atNode->getPath(0)->getRemoteNode()->getModule();
449  IPAddress next_hop_ip = IPAddressResolver().addressOf(next_hop).get4();
450 
451 
452  // Requirement 1: Each router has exactly one routing entry
453  // (netmask 255.255.0.0) to each other router
454  IPRoute* re = new IPRoute();
455 
456  re->setHost(IPAddress(destAddr));
457  re->setInterface(ie);
458  re->setSource(IPRoute::MANUAL);
459  re->setNetmask(IPAddress(255, 255, 0, 0));
460  re->setGateway(IPAddress(next_hop_ip));
461  re->setType(IPRoute::REMOTE);
462 
463  rt->addRoute(re);
464 
465  // Requirement 2: Each router has a point-to-point routing
466  // entry (netmask 255.255.255.255) for each immediate neighbour
467  if (atNode->getDistanceToTarget() == 1) {
468  IPRoute* re2 = new IPRoute();
469 
470  re2->setHost(IPAddress(destAddr));
471  re2->setInterface(ie);
472  re2->setSource(IPRoute::MANUAL);
473  re2->setNetmask(IPAddress(255, 255, 255, 255));
474  re2->setType(IPRoute::DIRECT);
475 
476  rt->addRoute(re2);
477  }
478 
479  // If destNode is the outRouter, add a default route
480  // to the next hop in the direction of the outRouter
481  if (strcmp(destNode->getModule()->getName(), "outRouter" ) == 0) {
482  IPRoute* defRoute = new IPRoute();
483  defRoute->setHost(IPAddress::UNSPECIFIED_ADDRESS);
484  defRoute->setNetmask(IPAddress::UNSPECIFIED_ADDRESS);
485  defRoute->setGateway(IPAddress(next_hop_ip));
486  defRoute->setInterface(ie);
487  defRoute->setType(IPRoute::REMOTE);
488  defRoute->setSource(IPRoute::MANUAL);
489 
490  rt->addRoute(defRoute);
491  }
492  }
493  }
494 }
495 
497 {
498  // Assign IP addresses to all router modules.
499  std::vector<IPv6Words> nodeAddresses;
500  nodeAddresses.resize(topo.getNumNodes());
501 
502  // IP addresses for backbone
503  // Take start IP from config file
504  // FIXME: Make Netmask for Routers configurable!
505  IPv6Words lowIPBoundary(IPv6Address(par("startIPv6").stringValue()));
506 
507  // uint32 lowIPBoundary = uint32((1 << 24) + 1);
508  int numIPNodes = 0;
509 
510  for (int i = 0; i < topo.getNumNodes(); i++) {
511  ++numIPNodes;
512 
513  IPv6Words addr = lowIPBoundary;
514  addr.d0 += numIPNodes;
515  nodeAddresses[i] = addr;
516 
517  // update ip display string
518  if (ev.isGUI()) {
519  topo.getNode(i)->getModule()->getDisplayString().insertTag("t", 0);
520  topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 0,
521  const_cast<char*>(IPv6Address(addr.d0, addr.d1, addr.d2, addr.d3).str().c_str()));
522  topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 1, "l");
523  topo.getNode(i)->getModule()->getDisplayString().setTagArg("t", 2, "red");
524  }
525 
526  // find interface table and assign address to all (non-loopback) interfaces
527  IInterfaceTable* ift = IPAddressResolver().interfaceTableOf(topo.getNode(i)->getModule());
528 
529  for ( int k = 0; k < ift->getNumInterfaces(); k++ ) {
530  InterfaceEntry* ie = ift->getInterface(k);
531  if (!ie->isLoopback() && ie->ipv6Data()) {
532  //ie->ipv6Data()->assignAddress(IPv6Address(addr.d0, addr.d1, addr.d2, addr.d3), false, 0, 0);
533  // full address must match for local delivery
534  IPv6Address prefix(addr.d0, addr.d1, addr.d2, addr.d3);
535  IPv6InterfaceData::AdvPrefix p;
536  p.prefix = prefix;
537  p.prefixLength = 32;
538  p.advAutonomousFlag = true;
539  p.advPreferredLifetime = 0;
540  p.advValidLifetime = 0;
541  p.advOnLinkFlag = true;
542  ie->ipv6Data()->addAdvPrefix(p);
543  ie->setMACAddress(MACAddress::generateAutoAddress());
544 
545  ie->ipv6Data()->assignAddress(prefix,false, 0, 0);
546 
547  if (ie->ipv6Data()->getLinkLocalAddress().isUnspecified()) {
548  ie->ipv6Data()->assignAddress(IPv6Address::formLinkLocalAddress(ie->getInterfaceToken()),false, 0, 0);
549  }
550  }
551  }
552  }
553 
554  // Fill in routing tables.
555  for (int i = 0; i < topo.getNumNodes(); i++) {
556  cTopology::Node* destNode = topo.getNode(i);
557 
558  // calculate shortest paths from everywhere towards destNode
559  topo.calculateUnweightedSingleShortestPathsTo(destNode);
560 
561  // add overlayAccessRouters and overlayBackboneRouters
562  // to the GlobalNodeList
563  if ((strcmp(destNode->getModule()->getName(), "overlayBackboneRouter") == 0) ||
564  (strcmp(destNode->getModule()->getName(), "overlayAccessRouter") == 0)) {
565  //add node to bootstrap oracle
566  PeerInfo* info = new PeerInfo(0, destNode->getModule()->getId(), NULL);
567  globalNodeList->addPeer(IPvXAddress(IPv6Address(nodeAddresses[i].d0, nodeAddresses[i].d1, nodeAddresses[i].d2, nodeAddresses[i].d3)), info);
568  }
569 
570  // add route (with host=destNode) to every routing table in the network
571  for (int j = 0; j < topo.getNumNodes(); j++) {
572  // continue if same node
573  if (i == j)
574  continue;
575 
576  // cancel simulation if node is not connected with destination
577  cTopology::Node* atNode = topo.getNode(j);
578 
579  if (atNode->getNumPaths() == 0) {
580  error((std::string(atNode->getModule()->getName()) + ": Network is not entirely connected."
581  "Please increase your value for the "
582  "connectivity parameter").c_str());
583  }
584 
585  //
586  // Add routes at the atNode.
587  //
588 
589  // find atNode's interface and routing table
590  IInterfaceTable* ift = IPAddressResolver().interfaceTableOf(atNode->getModule());
591  RoutingTable6* rt = IPAddressResolver().routingTable6Of(atNode->getModule());
592 
593  // find atNode's interface entry for the next hop node
594  int outputGateId = atNode->getPath(0)->getLocalGate()->getId();
595  InterfaceEntry *ie = ift->getInterfaceByNodeOutputGateId(outputGateId);
596 
597  // find the next hop node on the path towards destNode
598  cModule* next_hop = atNode->getPath(0)->getRemoteNode()->getModule();
599  int destGateId = destNode->getLinkIn(0)->getLocalGateId();
600  IInterfaceTable* destIft = IPAddressResolver().interfaceTableOf(destNode->getModule());
601  int remoteGateId = atNode->getPath(0)->getRemoteGateId();
602  IInterfaceTable* remoteIft = IPAddressResolver().interfaceTableOf(next_hop);
603  IPv6Address next_hop_ip = remoteIft->getInterfaceByNodeInputGateId(remoteGateId)->ipv6Data()->getLinkLocalAddress();
604  IPv6InterfaceData::AdvPrefix destPrefix = destIft->getInterfaceByNodeInputGateId(destGateId)->ipv6Data()->getAdvPrefix(0);
605 
606  // create routing entry for next hop
607  rt->addStaticRoute(destPrefix.prefix, destPrefix.prefixLength, ie->getInterfaceId(), next_hop_ip);
608 
609  }
610  }
611 }
612 
613 
623 double uniform2(double start, double end, double index, double new_calc)
624 {
625  static std::vector<double> value;
626  if ( (unsigned int)index >= value.size() )
627  value.resize((int)index + 1);
628  if ( new_calc == 1 )
629  value[(int)index] = uniform(start, end);
630  return value[(int)index];
631 };
632 
642 double intuniform2(double start, double end, double index, double new_calc)
643 {
644  static std::vector<double> value;
645  if ( (unsigned int)index >= value.size() )
646  value.resize((int)index + 1);
647  if ( new_calc == 1 )
648  value[(int)index] = (double)intuniform((int)start, (int)end);
649  return value[(int)index];
650 };
651