|
INET Framework for OMNeT++/OMNEST
|
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