RoutingTable6.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005 Andras Varga
00003 // Copyright (C) 2005 Wei Yang, Ng
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
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 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
00016 // License along with this program; if not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 
00020 #include <algorithm>
00021 #include "opp_utils.h"
00022 #include "RoutingTable6.h"
00023 #include "IPv6InterfaceData.h"
00024 #include "InterfaceTableAccess.h"
00025 
00026 
00027 
00028 Define_Module(RoutingTable6);
00029 
00030 
00031 std::string IPv6Route::info() const
00032 {
00033     std::stringstream out;
00034     out << getDestPrefix() << "/" << getPrefixLength() << " --> ";
00035     out << "if=" << getInterfaceId() << " next hop:" << getNextHop(); // FIXME try printing interface name
00036     out << " " << routeSrcName(getSrc());
00037     if (getExpiryTime()>0)
00038         out << " exp:" << getExpiryTime();
00039     return out.str();
00040 }
00041 
00042 std::string IPv6Route::detailedInfo() const
00043 {
00044     return std::string();
00045 }
00046 
00047 const char *IPv6Route::routeSrcName(RouteSrc src)
00048 {
00049     switch (src)
00050     {
00051         case FROM_RA:         return "FROM_RA";
00052         case OWN_ADV_PREFIX:  return "OWN_ADV_PREFIX";
00053         case STATIC:          return "STATIC";
00054         case ROUTING_PROT:    return "ROUTING_PROT";
00055         default:              return "???";
00056     }
00057 }
00058 
00059 //----
00060 
00061 std::ostream& operator<<(std::ostream& os, const IPv6Route& e)
00062 {
00063     os << e.info();
00064     return os;
00065 };
00066 
00067 std::ostream& operator<<(std::ostream& os, const RoutingTable6::DestCacheEntry& e)
00068 {
00069     os << "if=" << e.interfaceId << " " << e.nextHopAddr;  //FIXME try printing interface name
00070     return os;
00071 };
00072 
00073 RoutingTable6::RoutingTable6()
00074 {
00075 }
00076 
00077 RoutingTable6::~RoutingTable6()
00078 {
00079     for (unsigned int i=0; i<routeList.size(); i++)
00080         delete routeList[i];
00081 }
00082 
00083 void RoutingTable6::initialize(int stage)
00084 {
00085     if (stage==1)
00086     {
00087         ift = InterfaceTableAccess().get();
00088         nb = NotificationBoardAccess().get();
00089 
00090         nb->subscribe(this, NF_INTERFACE_CREATED);
00091         nb->subscribe(this, NF_INTERFACE_DELETED);
00092         nb->subscribe(this, NF_INTERFACE_STATE_CHANGED);
00093         nb->subscribe(this, NF_INTERFACE_CONFIG_CHANGED);
00094         nb->subscribe(this, NF_INTERFACE_IPv6CONFIG_CHANGED);
00095 
00096         WATCH_PTRVECTOR(routeList);
00097         WATCH_MAP(destCache); // FIXME commented out for now
00098         isrouter = par("isRouter");
00099         WATCH(isrouter);
00100 
00101         // add IPv6InterfaceData to interfaces
00102         for (int i=0; i<ift->getNumInterfaces(); i++)
00103         {
00104             InterfaceEntry *ie = ift->getInterface(i);
00105             configureInterfaceForIPv6(ie);
00106         }
00107 
00108         parseXMLConfigFile();
00109 
00110         // skip hosts
00111         if (isrouter)
00112         {
00113             // add globally routable prefixes to routing table
00114             for (int x = 0; x < ift->getNumInterfaces(); x++)
00115             {
00116                 InterfaceEntry *ie = ift->getInterface(x);
00117 
00118                 if (ie->isLoopback())
00119                     continue;
00120 
00121                 for (int y = 0; y < ie->ipv6Data()->getNumAdvPrefixes(); y++)
00122                     if (ie->ipv6Data()->getAdvPrefix(y).prefix.isGlobal())
00123                         addOrUpdateOwnAdvPrefix(ie->ipv6Data()->getAdvPrefix(y).prefix,
00124                                                 ie->ipv6Data()->getAdvPrefix(y).prefixLength,
00125                                                 ie->getInterfaceId(), 0);
00126             }
00127         }
00128     }
00129     else if (stage==4)
00130     {
00131         // configurator adds routes only in stage==3
00132         updateDisplayString();
00133     }
00134 }
00135 
00136 void RoutingTable6::parseXMLConfigFile()
00137 {
00138     // TODO to be revised by Andras
00139     // configure interfaces from XML config file
00140     cXMLElement *config = par("routingTableFile");
00141     for (cXMLElement *child=config->getFirstChild(); child; child = child->getNextSibling())
00142     {
00143         //std::cout << "configuring interfaces from XML file." << endl;
00144         //std::cout << "selected element is: " << child->getTagName() << endl;
00145         // we ensure that the selected element is local.
00146         if (opp_strcmp(child->getTagName(),"local")!=0) continue;
00147         //ensure that this is the right parent module we are configuring.
00148         if (opp_strcmp(child->getAttribute("node"),getParentModule()->getFullName())!=0)
00149             continue;
00150         //Go one level deeper.
00151         //child = child->getFirstChild();
00152         for (cXMLElement *ifTag=child->getFirstChild(); ifTag; ifTag = ifTag->getNextSibling())
00153         {
00154             //The next tag should be "interface".
00155             if (opp_strcmp(ifTag->getTagName(),"interface")!=0)
00156                 continue;
00157             //std::cout << "Getting attribute: name" << endl;
00158             const char *ifname = ifTag->getAttribute("name");
00159             if (!ifname)
00160                 error("<interface> without name attribute at %s", child->getSourceLocation());
00161             InterfaceEntry *ie = ift->getInterfaceByName(ifname);
00162             if (!ie)
00163                 error("no interface named %s was registered, %s", ifname, child->getSourceLocation());
00164             configureInterfaceFromXML(ie, ifTag);
00165         }
00166     }
00167 }
00168 
00169 void RoutingTable6::updateDisplayString()
00170 {
00171     if (!ev.isGUI())
00172         return;
00173 
00174     std::stringstream os;
00175 
00176     os << getNumRoutes() << " routes\n" << destCache.size() << " destcache entries";
00177     getDisplayString().setTagArg("t", 0, os.str().c_str());
00178 }
00179 
00180 void RoutingTable6::handleMessage(cMessage *msg)
00181 {
00182     opp_error("This module doesn't process messages");
00183 }
00184 
00185 void RoutingTable6::receiveChangeNotification(int category, const cPolymorphic *details)
00186 {
00187     if (simulation.getContextType()==CTX_INITIALIZE)
00188         return;  // ignore notifications during initialize
00189 
00190     Enter_Method_Silent();
00191     printNotificationBanner(category, details);
00192 
00193     if (category==NF_INTERFACE_CREATED)
00194     {
00195         //TODO something like this:
00196         //InterfaceEntry *ie = check_and_cast<InterfaceEntry*>(details);
00197         //configureInterfaceForIPv6(ie);
00198     }
00199     else if (category==NF_INTERFACE_DELETED)
00200     {
00201         //TODO remove all routes that point to that interface (?)
00202     }
00203     else if (category==NF_INTERFACE_STATE_CHANGED)
00204     {
00205         //TODO invalidate routing cache (?)
00206     }
00207     else if (category==NF_INTERFACE_CONFIG_CHANGED)
00208     {
00209         //TODO invalidate routing cache (?)
00210     }
00211     else if (category==NF_INTERFACE_IPv6CONFIG_CHANGED)
00212     {
00213         //TODO
00214     }
00215 }
00216 
00217 void RoutingTable6::configureInterfaceForIPv6(InterfaceEntry *ie)
00218 {
00219     IPv6InterfaceData *ipv6IfData = new IPv6InterfaceData();
00220     ie->setIPv6Data(ipv6IfData);
00221 
00222     // for routers, turn on advertisements by default
00223     //FIXME: we will use this isRouter flag for now. what if future implementations
00224     //have 2 interfaces where one interface is configured as a router and the other
00225     //as a host?
00226     ipv6IfData->setAdvSendAdvertisements(isrouter);//Added by WEI
00227 
00228     // metric: some hints: OSPF cost (2e9/bps value), MS KB article Q299540, ...
00229     //d->setMetric((int)ceil(2e9/ie->getDatarate())); // use OSPF cost as default
00230     //FIXME TBD fill in the rest
00231 
00232     assignRequiredNodeAddresses(ie);
00233 }
00234 
00235 void RoutingTable6::assignRequiredNodeAddresses(InterfaceEntry *ie)
00236 {
00237     //RFC 3513 Section 2.8:A Node's Required Addresses
00238     /*A host is required to recognize the following addresses as
00239     identifying itself:*/
00240 
00241     //o  The loopback address.
00242     if (ie->isLoopback())
00243     {
00244         ie->ipv6Data()->assignAddress(IPv6Address("::1"), false, 0, 0);
00245         return;
00246     }
00247     //o  Its required Link-Local Address for each interface.
00248     //IPv6Address linkLocalAddr = IPv6Address().formLinkLocalAddress(ie->getInterfaceToken());
00249     //ie->ipv6Data()->assignAddress(linkLocalAddr, true, 0, 0);
00250 
00251     /*o  Any additional Unicast and Anycast Addresses that have been configured
00252     for the node's interfaces (manually or automatically).*/
00253 
00254     // FIXME FIXME Andras: commented out the following lines, because these addresses
00255     // are implicitly checked for in isLocalAddress()  (we don't want redundancy,
00256     // and manually adding solicited-node mcast address for each and every address
00257     // is very error-prone!)
00258     //
00259     //o  The All-Nodes Multicast Addresses defined in section 2.7.1.
00260 
00261     /*o  The Solicited-Node Multicast Address for each of its unicast and anycast
00262     addresses.*/
00263 
00264     //o  Multicast Addresses of all other groups to which the node belongs.
00265 
00266     /*A router is required to recognize all addresses that a host is
00267     required to recognize, plus the following addresses as identifying
00268     itself:*/
00269     /*o  The Subnet-Router Anycast Addresses for all interfaces for
00270     which it is configured to act as a router.*/
00271 
00272     //o  All other Anycast Addresses with which the router has been configured.
00273     //o  The All-Routers Multicast Addresses defined in section 2.7.1.
00274 }
00275 
00276 static const char *getRequiredAttr(cXMLElement *elem, const char *attrName)
00277 {
00278     const char *s = elem->getAttribute(attrName);
00279     if (!s)
00280         opp_error("element <%s> misses required attribute %s at %s",
00281                   elem->getTagName(), attrName, elem->getSourceLocation());
00282     return s;
00283 }
00284 static bool toBool(const char *s, bool defaultValue=false)
00285 {
00286     if (!s)
00287         return defaultValue;
00288     return !strcmp(s,"on") || !strcmp(s,"true") || !strcmp(s,"yes");
00289 }
00290 
00291 void RoutingTable6::configureInterfaceFromXML(InterfaceEntry *ie, cXMLElement *cfg)
00292 {
00293     /*XML parsing capabilities tweaked by WEI. For now, we can configure a specific
00294     node's interface. We can set advertising prefixes and other variables to be used
00295     in RAs. The IPv6 interface data gets overwritten if lines 249 to 262 is uncommented.
00296     The fix is to create an XML file with all the default values. Customised XML files
00297     can be used for future protocols that requires different values. (MIPv6)*/
00298     IPv6InterfaceData *d = ie->ipv6Data();
00299 
00300     // parse basic config (attributes)
00301     d->setAdvSendAdvertisements(toBool(getRequiredAttr(cfg, "AdvSendAdvertisements")));
00302     //TODO: leave this off first!! They overwrite stuff!
00303 /* TODO: Wei commented out the stuff below. To be checked why (Andras).
00304     d->setMaxRtrAdvInterval(OPP_Global::atod(getRequiredAttr(cfg, "MaxRtrAdvInterval")));
00305     d->setMinRtrAdvInterval(OPP_Global::atod(getRequiredAttr(cfg, "MinRtrAdvInterval")));
00306     d->setAdvManagedFlag(toBool(getRequiredAttr(cfg, "AdvManagedFlag")));
00307     d->setAdvOtherConfigFlag(toBool(getRequiredAttr(cfg, "AdvOtherConfigFlag")));
00308     d->setAdvLinkMTU(OPP_Global::atoul(getRequiredAttr(cfg, "AdvLinkMTU")));
00309     d->setAdvReachableTime(OPP_Global::atoul(getRequiredAttr(cfg, "AdvReachableTime")));
00310     d->setAdvRetransTimer(OPP_Global::atoul(getRequiredAttr(cfg, "AdvRetransTimer")));
00311     d->setAdvCurHopLimit(OPP_Global::atoul(getRequiredAttr(cfg, "AdvCurHopLimit")));
00312     d->setAdvDefaultLifetime(OPP_Global::atoul(getRequiredAttr(cfg, "AdvDefaultLifetime")));
00313     ie->setMtu(OPP_Global::atoul(getRequiredAttr(cfg, "HostLinkMTU")));
00314     d->setCurHopLimit(OPP_Global::atoul(getRequiredAttr(cfg, "HostCurHopLimit")));
00315     d->setBaseReachableTime(OPP_Global::atoul(getRequiredAttr(cfg, "HostBaseReachableTime")));
00316     d->setRetransTimer(OPP_Global::atoul(getRequiredAttr(cfg, "HostRetransTimer")));
00317     d->setDupAddrDetectTransmits(OPP_Global::atoul(getRequiredAttr(cfg, "HostDupAddrDetectTransmits")));
00318 */
00319 
00320     // parse prefixes (AdvPrefix elements; they should be inside an AdvPrefixList
00321     // element, but we don't check that)
00322     cXMLElementList prefixList = cfg->getElementsByTagName("AdvPrefix");
00323     for (unsigned int i=0; i<prefixList.size(); i++)
00324     {
00325         cXMLElement *node = prefixList[i];
00326         IPv6InterfaceData::AdvPrefix prefix;
00327 
00328         // FIXME todo implement: advValidLifetime, advPreferredLifetime can
00329         // store (absolute) expiry time (if >0) or lifetime (delta) (if <0);
00330         // 0 should be treated as infinity
00331         int pfxLen;
00332         if (!prefix.prefix.tryParseAddrWithPrefix(node->getNodeValue(),pfxLen))
00333             opp_error("element <%s> at %s: wrong IPv6Address/prefix syntax %s",
00334                       node->getTagName(), node->getSourceLocation(), node->getNodeValue());
00335         prefix.prefixLength = pfxLen;
00336         prefix.advValidLifetime = OPP_Global::atoul(getRequiredAttr(node, "AdvValidLifetime"));
00337         prefix.advOnLinkFlag = toBool(getRequiredAttr(node, "AdvOnLinkFlag"));
00338         prefix.advPreferredLifetime = OPP_Global::atoul(getRequiredAttr(node, "AdvPreferredLifetime"));
00339         prefix.advAutonomousFlag = toBool(getRequiredAttr(node, "AdvAutonomousFlag"));
00340         d->addAdvPrefix(prefix);
00341     }
00342 
00343     // parse addresses
00344     cXMLElementList addrList = cfg->getChildrenByTagName("inetAddr");
00345     for (unsigned int k=0; k<addrList.size(); k++)
00346     {
00347         cXMLElement *node = addrList[k];
00348         IPv6Address address = node->getNodeValue();
00349         //We can now decide if the address is tentative or not.
00350         d->assignAddress(address, toBool(getRequiredAttr(node, "tentative")), 0, 0);  // set up with infinite lifetimes
00351     }
00352 }
00353 
00354 InterfaceEntry *RoutingTable6::getInterfaceByAddress(const IPv6Address& addr)
00355 {
00356     Enter_Method("getInterfaceByAddress(%s)=?", addr.str().c_str());
00357 
00358     if (addr.isUnspecified())
00359         return NULL;
00360     for (int i=0; i<ift->getNumInterfaces(); ++i)
00361     {
00362         InterfaceEntry *ie = ift->getInterface(i);
00363         if (ie->ipv6Data()->hasAddress(addr))
00364             return ie;
00365     }
00366     return NULL;
00367 }
00368 
00369 bool RoutingTable6::isLocalAddress(const IPv6Address& dest) const
00370 {
00371     Enter_Method("isLocalAddress(%s) y/n", dest.str().c_str());
00372 
00373     // first, check if we have an interface with this address
00374     for (int i=0; i<ift->getNumInterfaces(); i++)
00375     {
00376         InterfaceEntry *ie = ift->getInterface(i);
00377         if (ie->ipv6Data()->hasAddress(dest))
00378             return true;
00379     }
00380 
00381     // then check for special, preassigned multicast addresses
00382     // (these addresses occur more rarely than specific interface addresses,
00383     // that's why we check for them last)
00384 
00385     if (dest==IPv6Address::ALL_NODES_1 || dest==IPv6Address::ALL_NODES_2)
00386         return true;
00387     if (isRouter() && (dest==IPv6Address::ALL_ROUTERS_1 || dest==IPv6Address::ALL_ROUTERS_2 || dest==IPv6Address::ALL_ROUTERS_5))
00388         return true;
00389 
00390     // check for solicited-node multicast address
00391     if (dest.matches(IPv6Address::SOLICITED_NODE_PREFIX, 104))
00392     {
00393         for (int i=0; i<ift->getNumInterfaces(); i++)
00394         {
00395             InterfaceEntry *ie = ift->getInterface(i);
00396             if (ie->ipv6Data()->matchesSolicitedNodeMulticastAddress(dest))
00397                 return true;
00398         }
00399     }
00400     return false;
00401 }
00402 
00403 const IPv6Address& RoutingTable6::lookupDestCache(const IPv6Address& dest, int& outInterfaceId) const
00404 {
00405     Enter_Method("lookupDestCache(%s)", dest.str().c_str());
00406 
00407     DestCache::const_iterator it = destCache.find(dest);
00408     if (it == destCache.end())
00409     {
00410         outInterfaceId = -1;
00411         return IPv6Address::UNSPECIFIED_ADDRESS;
00412     }
00413     outInterfaceId = it->second.interfaceId;
00414     return it->second.nextHopAddr;
00415 }
00416 
00417 const IPv6Route *RoutingTable6::doLongestPrefixMatch(const IPv6Address& dest)
00418 {
00419     Enter_Method("doLongestPrefixMatch(%s)", dest.str().c_str());
00420 
00421     // we'll just stop at the first match, because the table is sorted
00422     // by prefix lengths and metric (see addRoute())
00423     for (RouteList::const_iterator it=routeList.begin(); it!=routeList.end(); it++)
00424     {
00425         if (dest.matches((*it)->getDestPrefix(),(*it)->getPrefixLength()))
00426         {
00427             // FIXME proofread this code, iterator invalidation-wise, etc
00428             bool entryExpired = false;
00429             if (simTime() > (*it)->getExpiryTime() && (*it)->getExpiryTime() != 0)//since 0 represents infinity.
00430             {
00431                 EV << "Expired prefix detected!!" << endl;
00432                 removeOnLinkPrefix((*it)->getDestPrefix(), (*it)->getPrefixLength());
00433                 entryExpired = true;
00434             }
00435             if (entryExpired == false) return *it;
00436         }
00437     }
00438     // FIXME todo: if we selected an expired route, throw it out and select again!
00439     return NULL;
00440 }
00441 
00442 bool RoutingTable6::isPrefixPresent(const IPv6Address& prefix) const
00443 {
00444     for (RouteList::const_iterator it=routeList.begin(); it!=routeList.end(); it++)
00445         if (prefix.matches((*it)->getDestPrefix(),128))
00446             return true;
00447     return false;
00448 }
00449 
00450 void RoutingTable6::updateDestCache(const IPv6Address& dest, const IPv6Address& nextHopAddr, int interfaceId)
00451 {
00452     // FIXME this performs 2 lookups -- optimize to do only one
00453     destCache[dest].nextHopAddr = nextHopAddr;
00454     destCache[dest].interfaceId = interfaceId;
00455 
00456     updateDisplayString();
00457 }
00458 
00459 void RoutingTable6::purgeDestCache()
00460 {
00461     destCache.clear();
00462     updateDisplayString();
00463 }
00464 
00465 void RoutingTable6::purgeDestCacheEntriesToNeighbour(const IPv6Address& nextHopAddr, int interfaceId)
00466 {
00467     for (DestCache::iterator it=destCache.begin(); it!=destCache.end(); )
00468     {
00469         if (it->second.interfaceId==interfaceId && it->second.nextHopAddr==nextHopAddr)
00470         {
00471             // move the iterator past this element before removing it
00472             DestCache::iterator oldIt = it++;
00473             destCache.erase(oldIt);
00474         }
00475         else
00476         {
00477             it++;
00478         }
00479     }
00480 
00481     updateDisplayString();
00482 }
00483 
00484 void RoutingTable6::addOrUpdateOnLinkPrefix(const IPv6Address& destPrefix, int prefixLength,
00485                                             int interfaceId, simtime_t expiryTime)
00486 {
00487     // see if prefix exists in table
00488     IPv6Route *route = NULL;
00489     for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00490     {
00491         if ((*it)->getSrc()==IPv6Route::FROM_RA && (*it)->getDestPrefix()==destPrefix && (*it)->getPrefixLength()==prefixLength)
00492         {
00493             route = *it;
00494             break;
00495         }
00496     }
00497 
00498     if (route==NULL)
00499     {
00500         // create new route object
00501         IPv6Route *route = new IPv6Route(destPrefix, prefixLength, IPv6Route::FROM_RA);
00502         route->setInterfaceId(interfaceId);
00503         route->setExpiryTime(expiryTime);
00504         route->setMetric(0);
00505 
00506         // then add it
00507         addRoute(route);
00508     }
00509     else
00510     {
00511         // update existing one; notification-wise, we pretend the route got removed then re-added
00512         nb->fireChangeNotification(NF_IPv6_ROUTE_DELETED, route);
00513         route->setInterfaceId(interfaceId);
00514         route->setExpiryTime(expiryTime);
00515         nb->fireChangeNotification(NF_IPv6_ROUTE_ADDED, route);
00516     }
00517 
00518     updateDisplayString();
00519 }
00520 
00521 void RoutingTable6::addOrUpdateOwnAdvPrefix(const IPv6Address& destPrefix, int prefixLength,
00522                                             int interfaceId, simtime_t expiryTime)
00523 {
00524     // FIXME this is very similar to the one above -- refactor!!
00525 
00526     // see if prefix exists in table
00527     IPv6Route *route = NULL;
00528     for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00529     {
00530         if ((*it)->getSrc()==IPv6Route::OWN_ADV_PREFIX && (*it)->getDestPrefix()==destPrefix && (*it)->getPrefixLength()==prefixLength)
00531         {
00532             route = *it;
00533             break;
00534         }
00535     }
00536 
00537     if (route==NULL)
00538     {
00539         // create new route object
00540         IPv6Route *route = new IPv6Route(destPrefix, prefixLength, IPv6Route::OWN_ADV_PREFIX);
00541         route->setInterfaceId(interfaceId);
00542         route->setExpiryTime(expiryTime);
00543         route->setMetric(0);
00544 
00545         // then add it
00546         addRoute(route);
00547     }
00548     else
00549     {
00550         // update existing one; notification-wise, we pretend the route got removed then re-added
00551         nb->fireChangeNotification(NF_IPv6_ROUTE_DELETED, route);
00552         route->setInterfaceId(interfaceId);
00553         route->setExpiryTime(expiryTime);
00554         nb->fireChangeNotification(NF_IPv6_ROUTE_ADDED, route);
00555     }
00556 
00557     updateDisplayString();
00558 }
00559 
00560 void RoutingTable6::removeOnLinkPrefix(const IPv6Address& destPrefix, int prefixLength)
00561 {
00562     // scan the routing table for this prefix and remove it
00563     for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00564     {
00565         if ((*it)->getSrc()==IPv6Route::FROM_RA && (*it)->getDestPrefix()==destPrefix && (*it)->getPrefixLength()==prefixLength)
00566         {
00567             routeList.erase(it);
00568             return; // there can be only one such route, addOrUpdateOnLinkPrefix() guarantees that
00569         }
00570     }
00571 
00572     updateDisplayString();
00573 }
00574 
00575 void RoutingTable6::addStaticRoute(const IPv6Address& destPrefix, int prefixLength,
00576                     unsigned int interfaceId, const IPv6Address& nextHop,
00577                     int metric)
00578 {
00579     // create route object
00580     IPv6Route *route = new IPv6Route(destPrefix, prefixLength, IPv6Route::STATIC);
00581     route->setInterfaceId(interfaceId);
00582     route->setNextHop(nextHop);
00583     if (metric==0)
00584         metric = 10; // TBD should be filled from interface metric
00585     route->setMetric(metric);
00586 
00587     // then add it
00588     addRoute(route);
00589 }
00590 
00591 void RoutingTable6::addDefaultRoute(const IPv6Address& nextHop, unsigned int ifID,
00592     simtime_t routerLifetime)
00593 {
00594     // create route object
00595     IPv6Route *route = new IPv6Route(IPv6Address(), 0, IPv6Route::FROM_RA);
00596     route->setInterfaceId(ifID);
00597     route->setNextHop(nextHop);
00598     route->setMetric(10);//FIXME:should be filled from interface metric
00599 
00600     // then add it
00601     addRoute(route);
00602 }
00603 
00604 void RoutingTable6::addRoutingProtocolRoute(IPv6Route *route)
00605 {
00606     ASSERT(route->getSrc()==IPv6Route::ROUTING_PROT);
00607     addRoute(route);
00608 }
00609 
00610 bool RoutingTable6::routeLessThan(const IPv6Route *a, const IPv6Route *b)
00611 {
00612     // helper for sort() in addRoute(). We want routes with longer
00613     // prefixes to be at front, so we compare them as "less".
00614     // For metric, a smaller value is better (we report that as "less").
00615     if (a->getPrefixLength()!=b->getPrefixLength())
00616         return a->getPrefixLength() > b->getPrefixLength();
00617     return a->getMetric() < b->getMetric();
00618 }
00619 
00620 void RoutingTable6::addRoute(IPv6Route *route)
00621 {
00622     routeList.push_back(route);
00623 
00624     // we keep entries sorted by prefix length in routeList, so that we can
00625     // stop at the first match when doing the longest prefix matching
00626     std::sort(routeList.begin(), routeList.end(), routeLessThan);
00627 
00628     updateDisplayString();
00629 
00630     nb->fireChangeNotification(NF_IPv6_ROUTE_ADDED, route);
00631 }
00632 
00633 void RoutingTable6::removeRoute(IPv6Route *route)
00634 {
00635     RouteList::iterator it = std::find(routeList.begin(), routeList.end(), route);
00636     ASSERT(it!=routeList.end());
00637 
00638     nb->fireChangeNotification(NF_IPv6_ROUTE_DELETED, route); // rather: going to be deleted
00639 
00640     routeList.erase(it);
00641     delete route;
00642 
00643     updateDisplayString();
00644 }
00645 
00646 int RoutingTable6::getNumRoutes() const
00647 {
00648     return routeList.size();
00649 }
00650 
00651 IPv6Route *RoutingTable6::getRoute(int i)
00652 {
00653     ASSERT(i>=0 && i<(int)routeList.size());
00654     return routeList[i];
00655 }
00656