RoutingTable.cc

Go to the documentation of this file.
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