|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2004-2006 Andras Varga 00003 // Copyright (C) 2000 Institut fuer Telematik, Universitaet Karlsruhe 00004 // 00005 // This program is free software; you can redistribute it and/or 00006 // modify it under the terms of the GNU Lesser General Public License 00007 // as published by the Free Software Foundation; either version 2 00008 // of the License, or (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU Lesser General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU Lesser General Public License 00016 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00017 // 00018 00019 00020 // Cleanup and rewrite: Andras Varga, 2004 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 // get a pointer to the NotificationBoard module and IInterfaceTable 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 // L2 modules register themselves in stage 0, so we can only configure 00083 // the interfaces in stage 1. 00084 const char *filename = par("routingFile"); 00085 00086 // At this point, all L2 modules have registered themselves (added their 00087 // interface entries). Create the per-interface IPv4 data structures. 00088 IInterfaceTable *interfaceTable = InterfaceTableAccess().get(); 00089 for (int i=0; i<interfaceTable->getNumInterfaces(); ++i) 00090 configureInterfaceForIPv4(interfaceTable->getInterface(i)); 00091 configureLoopbackForIPv4(); 00092 00093 // read routing table file (and interface configuration) 00094 RoutingTableParser parser(ift, this); 00095 if (*filename && parser.readRoutingTableFromFile(filename)==-1) 00096 error("Error reading routing table file %s", filename); 00097 00098 // set routerId if param is not "" (==no routerId) or "auto" (in which case we'll 00099 // do it later in stage 3, after network configurators configured the interfaces) 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 // routerID selection must be after stage==2 when network autoconfiguration 00107 // assigns interface addresses 00108 configureRouterId(); 00109 00110 // we don't use notifications during initialize(), so we do it manually. 00111 // Should be in stage=3 because autoconfigurator runs in stage=2. 00112 updateNetmaskRoutes(); 00113 00114 //printRoutingTable(); 00115 } 00116 } 00117 00118 void RoutingTable::configureRouterId() 00119 { 00120 if (routerId.isUnspecified()) // not yet configured 00121 { 00122 const char *routerIdStr = par("routerId").stringValue(); 00123 if (!strcmp(routerIdStr, "auto")) // non-"auto" cases already handled in stage 1 00124 { 00125 // choose highest interface address as routerId 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 // already configured 00135 { 00136 // if there is no interface with routerId yet, assign it to the loopback address; 00137 // TODO find out if this is a good practice, in which situations it is useful etc. 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; // ignore notifications during initialize 00170 00171 Enter_Method_Silent(); 00172 printNotificationBanner(category, details); 00173 00174 if (category==NF_INTERFACE_CREATED) 00175 { 00176 // add netmask route for the new interface 00177 updateNetmaskRoutes(); 00178 } 00179 else if (category==NF_INTERFACE_DELETED) 00180 { 00181 // remove all routes that point to that interface 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 // if anything IPv4-related changes in the interfaces, interface netmask 00196 // based routes have to be re-built. 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(); // iterator became invalid -- start over 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 // metric: some hints: OSPF cost (2e9/bps value), MS KB article Q299540, ... 00253 d->setMetric((int)ceil(2e9/ie->getDatarate())); // use OSPF cost as default 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)); // note: str().c_str() too slow here 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 // add IPv4 info. Set 127.0.0.1/8 as address by default -- 00277 // we may reconfigure later it to be the routerId 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)); // note: str().c_str() too slow here 00290 00291 if (localAddresses.empty()) 00292 { 00293 // collect interface addresses if not yet done 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)); // note: str().c_str() too slow here 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)); // note: str().c_str() too slow here 00322 00323 RoutingCache::iterator it = routingCache.find(dest); 00324 if (it != routingCache.end()) 00325 return it->second; 00326 00327 // find best match (one with longest prefix) 00328 // default route has zero prefix length, so (if exists) it'll be selected as last resort 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()) && // match 00335 (!bestRoute || e->getNetmask().getInt() > longestNetmask)) // longest so far 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)); // note: str().c_str() too slow here 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)); // note: str().c_str() too slow here 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)); // note: str().c_str() too slow here here 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 // check for null address and default route 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 // check that the interface exists 00430 if (!entry->getInterface()) 00431 error("addRoute(): interface cannot be NULL"); 00432 00433 // if this is a default route, remove old default route (we're replacing it) 00434 if (entry->getNetmask().isUnspecified() && getDefaultRoute()!=NULL) 00435 deleteRoute(getDefaultRoute()); 00436 00437 // add to tables 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); // rather: going to be deleted 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); // rather: going to be deleted 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 // first, delete all routes with src=IFACENETMASK 00499 for (unsigned int k=0; k<routes.size(); k++) 00500 if (routes[k]->getSource()==IPRoute::IFACENETMASK) 00501 routes.erase(routes.begin()+(k--)); // '--' is necessary because indices shift down 00502 00503 // then re-add them, according to actual interface configuration 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