00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <ctype.h>
00026 #include <algorithm>
00027 #include <sstream>
00028
00029 #include "RoutingTable.h"
00030 #include "RoutingTableParser.h"
00031 #include "IPRoute.h"
00032 #include "IPv4InterfaceData.h"
00033 #include "IInterfaceTable.h"
00034 #include "InterfaceTableAccess.h"
00035 #include "NotifierConsts.h"
00036
00037
00038 Define_Module(RoutingTable);
00039
00040
00041 std::ostream& operator<<(std::ostream& os, const IPRoute& e)
00042 {
00043 os << e.info();
00044 return os;
00045 };
00046
00047 RoutingTable::RoutingTable()
00048 {
00049 }
00050
00051 RoutingTable::~RoutingTable()
00052 {
00053 for (unsigned int i=0; i<routes.size(); i++)
00054 delete routes[i];
00055 for (unsigned int i=0; i<multicastRoutes.size(); i++)
00056 delete multicastRoutes[i];
00057 }
00058
00059 void RoutingTable::initialize(int stage)
00060 {
00061 if (stage==0)
00062 {
00063
00064 nb = NotificationBoardAccess().get();
00065 ift = InterfaceTableAccess().get();
00066
00067 IPForward = par("IPForward").boolValue();
00068
00069 nb->subscribe(this, NF_INTERFACE_CREATED);
00070 nb->subscribe(this, NF_INTERFACE_DELETED);
00071 nb->subscribe(this, NF_INTERFACE_STATE_CHANGED);
00072 nb->subscribe(this, NF_INTERFACE_CONFIG_CHANGED);
00073 nb->subscribe(this, NF_INTERFACE_IPv4CONFIG_CHANGED);
00074
00075 WATCH_PTRVECTOR(routes);
00076 WATCH_PTRVECTOR(multicastRoutes);
00077 WATCH(IPForward);
00078 WATCH(routerId);
00079 }
00080 else if (stage==1)
00081 {
00082
00083
00084 const char *filename = par("routingFile");
00085
00086
00087
00088 IInterfaceTable *interfaceTable = InterfaceTableAccess().get();
00089 for (int i=0; i<interfaceTable->getNumInterfaces(); ++i)
00090 configureInterfaceForIPv4(interfaceTable->getInterface(i));
00091 configureLoopbackForIPv4();
00092
00093
00094 RoutingTableParser parser(ift, this);
00095 if (*filename && parser.readRoutingTableFromFile(filename)==-1)
00096 error("Error reading routing table file %s", filename);
00097
00098
00099
00100 const char *routerIdStr = par("routerId").stringValue();
00101 if (strcmp(routerIdStr, "") && strcmp(routerIdStr, "auto"))
00102 routerId = IPAddress(routerIdStr);
00103 }
00104 else if (stage==3)
00105 {
00106
00107
00108 configureRouterId();
00109
00110
00111
00112 updateNetmaskRoutes();
00113
00114
00115 }
00116 }
00117
00118 void RoutingTable::configureRouterId()
00119 {
00120 if (routerId.isUnspecified())
00121 {
00122 const char *routerIdStr = par("routerId").stringValue();
00123 if (!strcmp(routerIdStr, "auto"))
00124 {
00125
00126 for (int i=0; i<ift->getNumInterfaces(); ++i)
00127 {
00128 InterfaceEntry *ie = ift->getInterface(i);
00129 if (!ie->isLoopback() && ie->ipv4Data()->getIPAddress().getInt() > routerId.getInt())
00130 routerId = ie->ipv4Data()->getIPAddress();
00131 }
00132 }
00133 }
00134 else
00135 {
00136
00137
00138 if (getInterfaceByAddress(routerId)==NULL)
00139 {
00140 InterfaceEntry *lo0 = ift->getFirstLoopbackInterface();
00141 lo0->ipv4Data()->setIPAddress(routerId);
00142 lo0->ipv4Data()->setNetmask(IPAddress::ALLONES_ADDRESS);
00143 }
00144 }
00145 }
00146
00147 void RoutingTable::updateDisplayString()
00148 {
00149 if (!ev.isGUI())
00150 return;
00151
00152 std::stringstream os;
00153
00154 if (!routerId.isUnspecified())
00155 os << "routerId: " << routerId <<"\n";
00156
00157 os << "" << routes.size() << "+" << multicastRoutes.size() << " routes";
00158 getDisplayString().setTagArg("t", 0, os.str().c_str());
00159 }
00160
00161 void RoutingTable::handleMessage(cMessage *msg)
00162 {
00163 opp_error("This module doesn't process messages");
00164 }
00165
00166 void RoutingTable::receiveChangeNotification(int category, const cPolymorphic *details)
00167 {
00168 if (simulation.getContextType()==CTX_INITIALIZE)
00169 return;
00170
00171 Enter_Method_Silent();
00172 printNotificationBanner(category, details);
00173
00174 if (category==NF_INTERFACE_CREATED)
00175 {
00176
00177 updateNetmaskRoutes();
00178 }
00179 else if (category==NF_INTERFACE_DELETED)
00180 {
00181
00182 InterfaceEntry *entry = check_and_cast<InterfaceEntry*>(details);
00183 deleteInterfaceRoutes(entry);
00184 }
00185 else if (category==NF_INTERFACE_STATE_CHANGED)
00186 {
00187 invalidateCache();
00188 }
00189 else if (category==NF_INTERFACE_CONFIG_CHANGED)
00190 {
00191 invalidateCache();
00192 }
00193 else if (category==NF_INTERFACE_IPv4CONFIG_CHANGED)
00194 {
00195
00196
00197 updateNetmaskRoutes();
00198 }
00199 }
00200
00201 void RoutingTable::deleteInterfaceRoutes(InterfaceEntry *entry)
00202 {
00203 RouteVector::iterator it = routes.begin();
00204 while (it != routes.end())
00205 {
00206 IPRoute *route = *it;
00207 if (route->getInterface() == entry)
00208 {
00209 deleteRoute(route);
00210 it = routes.begin();
00211 }
00212 else
00213 {
00214 ++it;
00215 }
00216 }
00217 }
00218
00219 void RoutingTable::invalidateCache()
00220 {
00221 routingCache.clear();
00222 localAddresses.clear();
00223 }
00224
00225 void RoutingTable::printRoutingTable() const
00226 {
00227 EV << "-- Routing table --\n";
00228 ev.printf("%-16s %-16s %-16s %-3s %s\n",
00229 "Destination", "Gateway", "Netmask", "Iface");
00230
00231 for (int i=0; i<getNumRoutes(); i++)
00232 EV << getRoute(i)->detailedInfo() << "\n";
00233 EV << "\n";
00234 }
00235
00236 std::vector<IPAddress> RoutingTable::gatherAddresses() const
00237 {
00238 std::vector<IPAddress> addressvector;
00239
00240 for (int i=0; i<ift->getNumInterfaces(); ++i)
00241 addressvector.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress());
00242 return addressvector;
00243 }
00244
00245
00246
00247 void RoutingTable::configureInterfaceForIPv4(InterfaceEntry *ie)
00248 {
00249 IPv4InterfaceData *d = new IPv4InterfaceData();
00250 ie->setIPv4Data(d);
00251
00252
00253 d->setMetric((int)ceil(2e9/ie->getDatarate()));
00254 }
00255
00256 InterfaceEntry *RoutingTable::getInterfaceByAddress(const IPAddress& addr) const
00257 {
00258 Enter_Method("getInterfaceByAddress(%u.%u.%u.%u)", addr.getDByte(0), addr.getDByte(1), addr.getDByte(2), addr.getDByte(3));
00259
00260 if (addr.isUnspecified())
00261 return NULL;
00262 for (int i=0; i<ift->getNumInterfaces(); ++i)
00263 {
00264 InterfaceEntry *ie = ift->getInterface(i);
00265 if (ie->ipv4Data()->getIPAddress()==addr)
00266 return ie;
00267 }
00268 return NULL;
00269 }
00270
00271
00272 void RoutingTable::configureLoopbackForIPv4()
00273 {
00274 InterfaceEntry *ie = ift->getFirstLoopbackInterface();
00275
00276
00277
00278 IPv4InterfaceData *d = new IPv4InterfaceData();
00279 d->setIPAddress(IPAddress::LOOPBACK_ADDRESS);
00280 d->setNetmask(IPAddress::LOOPBACK_NETMASK);
00281 d->setMetric(1);
00282 ie->setIPv4Data(d);
00283 }
00284
00285
00286
00287 bool RoutingTable::isLocalAddress(const IPAddress& dest) const
00288 {
00289 Enter_Method("isLocalAddress(%u.%u.%u.%u)", dest.getDByte(0), dest.getDByte(1), dest.getDByte(2), dest.getDByte(3));
00290
00291 if (localAddresses.empty())
00292 {
00293
00294 for (int i=0; i<ift->getNumInterfaces(); i++)
00295 {
00296 IPAddress interfaceAddr = ift->getInterface(i)->ipv4Data()->getIPAddress();
00297 localAddresses.insert(interfaceAddr);
00298 }
00299 }
00300
00301 AddressSet::iterator it = localAddresses.find(dest);
00302 return it!=localAddresses.end();
00303 }
00304
00305 bool RoutingTable::isLocalMulticastAddress(const IPAddress& dest) const
00306 {
00307 Enter_Method("isLocalMulticastAddress(%u.%u.%u.%u)", dest.getDByte(0), dest.getDByte(1), dest.getDByte(2), dest.getDByte(3));
00308
00309 for (int i=0; i<ift->getNumInterfaces(); i++)
00310 {
00311 InterfaceEntry *ie = ift->getInterface(i);
00312 if (ie->ipv4Data()->isMemberOfMulticastGroup(dest))
00313 return true;
00314 }
00315 return false;
00316 }
00317
00318
00319 const IPRoute *RoutingTable::findBestMatchingRoute(const IPAddress& dest) const
00320 {
00321 Enter_Method("findBestMatchingRoute(%u.%u.%u.%u)", dest.getDByte(0), dest.getDByte(1), dest.getDByte(2), dest.getDByte(3));
00322
00323 RoutingCache::iterator it = routingCache.find(dest);
00324 if (it != routingCache.end())
00325 return it->second;
00326
00327
00328
00329 const IPRoute *bestRoute = NULL;
00330 uint32 longestNetmask = 0;
00331 for (RouteVector::const_iterator i=routes.begin(); i!=routes.end(); ++i)
00332 {
00333 const IPRoute *e = *i;
00334 if (IPAddress::maskedAddrAreEqual(dest, e->getHost(), e->getNetmask()) &&
00335 (!bestRoute || e->getNetmask().getInt() > longestNetmask))
00336 {
00337 bestRoute = e;
00338 longestNetmask = e->getNetmask().getInt();
00339 }
00340 }
00341 routingCache[dest] = bestRoute;
00342 return bestRoute;
00343 }
00344
00345 InterfaceEntry *RoutingTable::getInterfaceForDestAddr(const IPAddress& dest) const
00346 {
00347 Enter_Method("getInterfaceForDestAddr(%u.%u.%u.%u)", dest.getDByte(0), dest.getDByte(1), dest.getDByte(2), dest.getDByte(3));
00348
00349 const IPRoute *e = findBestMatchingRoute(dest);
00350 return e ? e->getInterface() : NULL;
00351 }
00352
00353 IPAddress RoutingTable::getGatewayForDestAddr(const IPAddress& dest) const
00354 {
00355 Enter_Method("getGatewayForDestAddr(%u.%u.%u.%u)", dest.getDByte(0), dest.getDByte(1), dest.getDByte(2), dest.getDByte(3));
00356
00357 const IPRoute *e = findBestMatchingRoute(dest);
00358 return e ? e->getGateway() : IPAddress();
00359 }
00360
00361
00362 MulticastRoutes RoutingTable::getMulticastRoutesFor(const IPAddress& dest) const
00363 {
00364 Enter_Method("getMulticastRoutesFor(%u.%u.%u.%u)", dest.getDByte(0), dest.getDByte(1), dest.getDByte(2), dest.getDByte(3));
00365
00366 MulticastRoutes res;
00367 res.reserve(16);
00368 for (RouteVector::const_iterator i=multicastRoutes.begin(); i!=multicastRoutes.end(); ++i)
00369 {
00370 const IPRoute *e = *i;
00371 if (IPAddress::maskedAddrAreEqual(dest, e->getHost(), e->getNetmask()))
00372 {
00373 MulticastRoute r;
00374 r.interf = e->getInterface();
00375 r.gateway = e->getGateway();
00376 res.push_back(r);
00377 }
00378 }
00379 return res;
00380 }
00381
00382
00383 int RoutingTable::getNumRoutes() const
00384 {
00385 return routes.size()+multicastRoutes.size();
00386 }
00387
00388 const IPRoute *RoutingTable::getRoute(int k) const
00389 {
00390 if (k < (int)routes.size())
00391 return routes[k];
00392 k -= routes.size();
00393 if (k < (int)multicastRoutes.size())
00394 return multicastRoutes[k];
00395 return NULL;
00396 }
00397
00398 const IPRoute *RoutingTable::getDefaultRoute() const
00399 {
00400 int n = (int)routes.size();
00401 for (int i=0; i<n; i++)
00402 if (routes[i]->getNetmask().isUnspecified())
00403 return routes[i];
00404 return NULL;
00405 }
00406
00407 const IPRoute *RoutingTable::findRoute(const IPAddress& target, const IPAddress& netmask,
00408 const IPAddress& gw, int metric, const char *dev) const
00409 {
00410 int n = getNumRoutes();
00411 for (int i=0; i<n; i++)
00412 if (routeMatches(getRoute(i), target, netmask, gw, metric, dev))
00413 return getRoute(i);
00414 return NULL;
00415 }
00416
00417 void RoutingTable::addRoute(const IPRoute *entry)
00418 {
00419 Enter_Method("addRoute(...)");
00420
00421
00422 if (entry->getHost().isUnspecified() != entry->getNetmask().isUnspecified())
00423 error("addRoute(): to add a default route, set both host and netmask to zero");
00424
00425 if (entry->getHost().doAnd(entry->getNetmask().isUnspecified()).getInt() != 0)
00426 error("addRoute(): suspicious route: host %s has 1-bits outside netmask %s",
00427 entry->getHost().str().c_str(), entry->getNetmask().str().c_str());
00428
00429
00430 if (!entry->getInterface())
00431 error("addRoute(): interface cannot be NULL");
00432
00433
00434 if (entry->getNetmask().isUnspecified() && getDefaultRoute()!=NULL)
00435 deleteRoute(getDefaultRoute());
00436
00437
00438 if (!entry->getHost().isMulticast())
00439 routes.push_back(const_cast<IPRoute*>(entry));
00440 else
00441 multicastRoutes.push_back(const_cast<IPRoute*>(entry));
00442
00443 invalidateCache();
00444 updateDisplayString();
00445
00446 nb->fireChangeNotification(NF_IPv4_ROUTE_ADDED, entry);
00447 }
00448
00449
00450 bool RoutingTable::deleteRoute(const IPRoute *entry)
00451 {
00452 Enter_Method("deleteRoute(...)");
00453
00454 RouteVector::iterator i = std::find(routes.begin(), routes.end(), entry);
00455 if (i!=routes.end())
00456 {
00457 nb->fireChangeNotification(NF_IPv4_ROUTE_DELETED, entry);
00458 routes.erase(i);
00459 delete entry;
00460 invalidateCache();
00461 updateDisplayString();
00462 return true;
00463 }
00464 i = std::find(multicastRoutes.begin(), multicastRoutes.end(), entry);
00465 if (i!=multicastRoutes.end())
00466 {
00467 nb->fireChangeNotification(NF_IPv4_ROUTE_DELETED, entry);
00468 multicastRoutes.erase(i);
00469 delete entry;
00470 invalidateCache();
00471 updateDisplayString();
00472 return true;
00473 }
00474 return false;
00475 }
00476
00477
00478 bool RoutingTable::routeMatches(const IPRoute *entry,
00479 const IPAddress& target, const IPAddress& nmask,
00480 const IPAddress& gw, int metric, const char *dev) const
00481 {
00482 if (!target.isUnspecified() && !target.equals(entry->getHost()))
00483 return false;
00484 if (!nmask.isUnspecified() && !nmask.equals(entry->getNetmask()))
00485 return false;
00486 if (!gw.isUnspecified() && !gw.equals(entry->getGateway()))
00487 return false;
00488 if (metric && metric!=entry->getMetric())
00489 return false;
00490 if (dev && strcmp(dev, entry->getInterfaceName()))
00491 return false;
00492
00493 return true;
00494 }
00495
00496 void RoutingTable::updateNetmaskRoutes()
00497 {
00498
00499 for (unsigned int k=0; k<routes.size(); k++)
00500 if (routes[k]->getSource()==IPRoute::IFACENETMASK)
00501 routes.erase(routes.begin()+(k--));
00502
00503
00504 for (int i=0; i<ift->getNumInterfaces(); i++)
00505 {
00506 InterfaceEntry *ie = ift->getInterface(i);
00507 if (ie->ipv4Data()->getNetmask()!=IPAddress::ALLONES_ADDRESS)
00508 {
00509 IPRoute *route = new IPRoute();
00510 route->setType(IPRoute::DIRECT);
00511 route->setSource(IPRoute::IFACENETMASK);
00512 route->setHost(ie->ipv4Data()->getIPAddress());
00513 route->setNetmask(ie->ipv4Data()->getNetmask());
00514 route->setGateway(IPAddress());
00515 route->setMetric(ie->ipv4Data()->getMetric());
00516 route->setInterface(ie);
00517 routes.push_back(route);
00518 }
00519 }
00520
00521 invalidateCache();
00522 updateDisplayString();
00523 }
00524
00525