#include <RoutingTable6.h>
See the NED documentation for general overview.
This is a simple module without gates, it requires function calls to it (message handling does nothing). Methods are provided for reading and updating the interface table and the route table, as well as for unicast and multicast routing.
The route table is read from a file. The route table can also be read and modified during simulation, typically by routing protocol implementations.
Public Member Functions | |
| RoutingTable6 () | |
| virtual | ~RoutingTable6 () |
| bool | isRouter () const |
Interfaces | |
| InterfaceEntry * | interfaceByAddress (const IPv6Address &address) |
Routing functions | |
| bool | localDeliver (const IPv6Address &dest) |
| const IPv6Address & | lookupDestCache (const IPv6Address &dest, int &outInterfaceId) |
| const IPv6Route * | doLongestPrefixMatch (const IPv6Address &dest) |
| bool | isPrefixPresent (const IPv6Address &prefix) |
Managing the destination cache | |
| void | updateDestCache (const IPv6Address &dest, const IPv6Address &nextHopAddr, int interfaceId) |
| void | purgeDestCache () |
| void | purgeDestCacheEntriesToNeighbour (const IPv6Address &nextHopAddr, int interfaceId) |
Managing prefixes and the route table | |
| void | addOrUpdateOnLinkPrefix (const IPv6Address &destPrefix, int prefixLength, int interfaceId, simtime_t expiryTime) |
| void | removeOnLinkPrefix (const IPv6Address &destPrefix, int prefixLength) |
| void | addOrUpdateOwnAdvPrefix (const IPv6Address &destPrefix, int prefixLength, int interfaceId, simtime_t expiryTime) |
| void | addStaticRoute (const IPv6Address &destPrefix, int prefixLength, unsigned int interfaceId, const IPv6Address &nextHop, int metric=0) |
| void | addDefaultRoute (const IPv6Address &raSrcAddr, unsigned int ifID, simtime_t routerLifetime) |
| void | addRoutingProtocolRoute (IPv6Route *route) |
| void | removeRoute (IPv6Route *route) |
| int | numRoutes () const |
| IPv6Route * | route (int i) |
Protected Member Functions | |
| void | updateDisplayString () |
| int | numInitStages () const |
| void | initialize (int stage) |
| void | parseXMLConfigFile () |
| void | handleMessage (cMessage *) |
Private Types | |
| typedef std::map< IPv6Address, DestCacheEntry > | DestCache |
| typedef std::vector< IPv6Route * > | RouteList |
Private Member Functions | |
| void | addRoute (IPv6Route *route) |
| void | configureInterfaceForIPv6 (InterfaceEntry *ie) |
| void | assignRequiredNodeAddresses (InterfaceEntry *ie) |
| void | configureInterfaceFromXML (InterfaceEntry *ie, cXMLElement *cfg) |
Static Private Member Functions | |
| static bool | routeLessThan (const IPv6Route *a, const IPv6Route *b) |
Private Attributes | |
| InterfaceTable * | ift |
| bool | isrouter |
| DestCache | destCache |
| RouteList | routeList |
Friends | |
| std::ostream & | operator<< (std::ostream &os, const DestCacheEntry &e) |
Classes | |
| struct | DestCacheEntry |
|
|
|
|
|
|
|
|
00075 {
00076 }
|
|
|
|
|
||||||||||||||||
|
Adds a default route for a host. This method requires the RA's source address and the router expiry time plus the simTime(). 00552 {
00553 // create route object
00554 IPv6Route *route = new IPv6Route(IPv6Address(), 0, IPv6Route::FROM_RA);
00555 route->setInterfaceID(ifID);
00556 route->setNextHop(nextHop);
00557 route->setMetric(10);//FIXME:should be filled from interface metric
00558
00559 // then add it
00560 addRoute(route);
00561 }
|
|
||||||||||||||||||||
|
Add on-link prefix (route of type FROM_RA), or update existing one. To be called from code processing on-link prefixes in Router Advertisements. Expiry time can be derived from the Valid Lifetime field in the Router Advertisements. NOTE: This method does NOT update the lifetime of matching addresses in the InterfaceTable (see IPv6InterfaceData); that has to be done separately. 00447 {
00448 // see if prefix exists in table
00449 IPv6Route *route = NULL;
00450 for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00451 {
00452 if ((*it)->src()==IPv6Route::FROM_RA && (*it)->destPrefix()==destPrefix && (*it)->prefixLength()==prefixLength)
00453 {
00454 route = *it;
00455 break;
00456 }
00457 }
00458
00459 if (route==NULL)
00460 {
00461 // create new route object
00462 IPv6Route *route = new IPv6Route(destPrefix, prefixLength, IPv6Route::FROM_RA);
00463 route->setInterfaceID(interfaceId);
00464 route->setExpiryTime(expiryTime);
00465 route->setMetric(0);
00466
00467 // then add it
00468 addRoute(route);
00469 }
00470 else
00471 {
00472 // update existing one
00473 route->setInterfaceID(interfaceId);
00474 route->setExpiryTime(expiryTime);
00475 }
00476
00477 updateDisplayString();
00478 }
|
|
||||||||||||||||||||
|
Add route of type OWN_ADV_PREFIX. This is a prefix that *this* router advertises on this interface. 00482 {
00483 // FIXME this is very similar to the one above -- refactor!!
00484
00485 // see if prefix exists in table
00486 IPv6Route *route = NULL;
00487 for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00488 {
00489 if ((*it)->src()==IPv6Route::OWN_ADV_PREFIX && (*it)->destPrefix()==destPrefix && (*it)->prefixLength()==prefixLength)
00490 {
00491 route = *it;
00492 break;
00493 }
00494 }
00495
00496 if (route==NULL)
00497 {
00498 // create new route object
00499 IPv6Route *route = new IPv6Route(destPrefix, prefixLength, IPv6Route::OWN_ADV_PREFIX);
00500 route->setInterfaceID(interfaceId);
00501 route->setExpiryTime(expiryTime);
00502 route->setMetric(0);
00503
00504 // then add it
00505 addRoute(route);
00506 }
00507 else
00508 {
00509 // update existing one
00510 route->setInterfaceID(interfaceId);
00511 route->setExpiryTime(expiryTime);
00512 }
00513
00514 updateDisplayString();
00515 }
|
|
|
00580 {
00581 routeList.push_back(route);
00582
00583 // we keep entries sorted by prefix length in routeList, so that we can
00584 // stop at the first match when doing the longest prefix matching
00585 std::sort(routeList.begin(), routeList.end(), routeLessThan);
00586
00587 updateDisplayString();
00588 }
|
|
|
Adds the given route (which can be OSPF, BGP, RIP or any other route) with src==ROUTING_PROT. To store additional information with the route, one can subclass from IPv6Route and add more fields. 00564 {
00565 ASSERT(route->src()==IPv6Route::ROUTING_PROT);
00566 addRoute(route);
00567 }
|
|
||||||||||||||||||||||||
|
Creates a static route. If metric is omitted, it gets initialized to the interface's metric value. 00535 {
00536 // create route object
00537 IPv6Route *route = new IPv6Route(destPrefix, prefixLength, IPv6Route::STATIC);
00538 route->setInterfaceID(interfaceId);
00539 route->setNextHop(nextHop);
00540 if (metric==0)
00541 {
00542 metric = 10; // TBD should be filled from interface metric
00543 }
00544 route->setMetric(metric);
00545
00546 // then add it
00547 addRoute(route);
00548 }
|
|
|
RFC 3513: Section 2.8 A Node's Required Address Assign the various addresses to the node's respective interface. This should be done when the IPv6 Protocol stack is created. 00197 {
00198 //RFC 3513 Section 2.8:A Node's Required Addresses
00199 /*A host is required to recognize the following addresses as
00200 identifying itself:*/
00201
00202 //o The loopback address.
00203 if (ie->isLoopback())
00204 {
00205 ie->ipv6()->assignAddress(IPv6Address("::1"), false, 0, 0);
00206 return;
00207 }
00208 //o Its required Link-Local Address for each interface.
00209 //IPv6Address linkLocalAddr = IPv6Address().formLinkLocalAddress(ie->interfaceToken());
00210 //ie->ipv6()->assignAddress(linkLocalAddr, true, 0, 0);
00211
00212 /*o Any additional Unicast and Anycast Addresses that have been configured
00213 for the node's interfaces (manually or automatically).*/
00214
00215 // FIXME FIXME Andras: commented out the following lines, because these addresses
00216 // are implicitly checked for in localDeliver() (we don't want redundancy,
00217 // and manually adding solicited-node mcast address for each and every address
00218 // is very error-prone!)
00219 //
00220 //o The All-Nodes Multicast Addresses defined in section 2.7.1.
00221
00222 /*o The Solicited-Node Multicast Address for each of its unicast and anycast
00223 addresses.*/
00224
00225 //o Multicast Addresses of all other groups to which the node belongs.
00226
00227 /*A router is required to recognize all addresses that a host is
00228 required to recognize, plus the following addresses as identifying
00229 itself:*/
00230 /*o The Subnet-Router Anycast Addresses for all interfaces for
00231 which it is configured to act as a router.*/
00232
00233 //o All other Anycast Addresses with which the router has been configured.
00234 //o The All-Routers Multicast Addresses defined in section 2.7.1.
00235 }
|
|
|
00179 {
00180 IPv6InterfaceData *ipv6IfData = new IPv6InterfaceData();
00181 ie->setIPv6Data(ipv6IfData);
00182
00183 // for routers, turn on advertisements by default
00184 //FIXME: we will use this isRouter flag for now. what if future implementations
00185 //have 2 interfaces where one interface is configured as a router and the other
00186 //as a host?
00187 ipv6IfData->setAdvSendAdvertisements(isrouter);//Added by WEI
00188
00189 // metric: some hints: OSPF cost (2e9/bps value), MS KB article Q299540, ...
00190 //d->setMetric((int)ceil(2e9/ie->datarate())); // use OSPF cost as default
00191 //FIXME TBD fill in the rest
00192
00193 assignRequiredNodeAddresses(ie);
00194 }
|
|
||||||||||||
|
00253 {
00254 /*XML parsing capabilities tweaked by WEI. For now, we can configure a specific
00255 node's interface. We can set advertising prefixes and other variables to be used
00256 in RAs. The IPv6 interface data gets overwritten if lines 249 to 262 is uncommented.
00257 The fix is to create an XML file with all the default values. Customised XML files
00258 can be used for future protocols that requires different values. (MIPv6)*/
00259 IPv6InterfaceData *d = ie->ipv6();
00260
00261 // parse basic config (attributes)
00262 d->setAdvSendAdvertisements(toBool(getRequiredAttr(cfg, "AdvSendAdvertisements")));
00263 //TODO: leave this off first!! They overwrite stuff!
00264 /* TODO: Wei commented out the stuff below. To be checked why (Andras).
00265 d->setMaxRtrAdvInterval(OPP_Global::atod(getRequiredAttr(cfg, "MaxRtrAdvInterval")));
00266 d->setMinRtrAdvInterval(OPP_Global::atod(getRequiredAttr(cfg, "MinRtrAdvInterval")));
00267 d->setAdvManagedFlag(toBool(getRequiredAttr(cfg, "AdvManagedFlag")));
00268 d->setAdvOtherConfigFlag(toBool(getRequiredAttr(cfg, "AdvOtherConfigFlag")));
00269 d->setAdvLinkMTU(OPP_Global::atoul(getRequiredAttr(cfg, "AdvLinkMTU")));
00270 d->setAdvReachableTime(OPP_Global::atoul(getRequiredAttr(cfg, "AdvReachableTime")));
00271 d->setAdvRetransTimer(OPP_Global::atoul(getRequiredAttr(cfg, "AdvRetransTimer")));
00272 d->setAdvCurHopLimit(OPP_Global::atoul(getRequiredAttr(cfg, "AdvCurHopLimit")));
00273 d->setAdvDefaultLifetime(OPP_Global::atoul(getRequiredAttr(cfg, "AdvDefaultLifetime")));
00274 ie->setMtu(OPP_Global::atoul(getRequiredAttr(cfg, "HostLinkMTU")));
00275 d->setCurHopLimit(OPP_Global::atoul(getRequiredAttr(cfg, "HostCurHopLimit")));
00276 d->setBaseReachableTime(OPP_Global::atoul(getRequiredAttr(cfg, "HostBaseReachableTime")));
00277 d->setRetransTimer(OPP_Global::atoul(getRequiredAttr(cfg, "HostRetransTimer")));
00278 d->setDupAddrDetectTransmits(OPP_Global::atoul(getRequiredAttr(cfg, "HostDupAddrDetectTransmits")));
00279 */
00280
00281 // parse prefixes (AdvPrefix elements; they should be inside an AdvPrefixList
00282 // element, but we don't check that)
00283 cXMLElementList prefixList = cfg->getElementsByTagName("AdvPrefix");
00284 for (unsigned int i=0; i<prefixList.size(); i++)
00285 {
00286 cXMLElement *node = prefixList[i];
00287 IPv6InterfaceData::AdvPrefix prefix;
00288
00289 // FIXME todo implement: advValidLifetime, advPreferredLifetime can
00290 // store (absolute) expiry time (if >0) or lifetime (delta) (if <0);
00291 // 0 should be treated as infinity
00292 int pfxLen;
00293 if (!prefix.prefix.tryParseAddrWithPrefix(node->getNodeValue(),pfxLen))
00294 opp_error("element <%s> at %s: wrong IPv6Address/prefix syntax %s",
00295 node->getTagName(), node->getSourceLocation(), node->getNodeValue());
00296 prefix.prefixLength = pfxLen;
00297 prefix.advValidLifetime = OPP_Global::atoul(getRequiredAttr(node, "AdvValidLifetime"));
00298 prefix.advOnLinkFlag = toBool(getRequiredAttr(node, "AdvOnLinkFlag"));
00299 prefix.advPreferredLifetime = OPP_Global::atoul(getRequiredAttr(node, "AdvPreferredLifetime"));
00300 prefix.advAutonomousFlag = toBool(getRequiredAttr(node, "AdvAutonomousFlag"));
00301 d->addAdvPrefix(prefix);
00302 }
00303
00304 // parse addresses
00305 cXMLElementList addrList = cfg->getChildrenByTagName("inetAddr");
00306 for (unsigned int k=0; k<addrList.size(); k++)
00307 {
00308 cXMLElement *node = addrList[k];
00309 IPv6Address address(node->getNodeValue());
00310 //We can now decide if the address is tentative or not.
00311 d->assignAddress(address, toBool(getRequiredAttr(node, "tentative")), 0, 0); // set up with infinite lifetimes
00312 }
00313 }
|
|
|
Performs longest prefix match in the routing table and returns the resulting route, or NULL if there was no match. 00379 {
00380 Enter_Method("doLongestPrefixMatch(%s)", dest.str().c_str());
00381
00382 // we'll just stop at the first match, because the table is sorted
00383 // by prefix lengths and metric (see addRoute())
00384 for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00385 {
00386 if (dest.matches((*it)->destPrefix(),(*it)->prefixLength()))
00387 {
00388 // FIXME proofread this code, iterator invalidation-wise, etc
00389 bool entryExpired = false;
00390 if (simTime() > (*it)->expiryTime() && (*it)->expiryTime() != 0)//since 0 represents infinity.
00391 {
00392 EV << "Expired prefix detected!!" << endl;
00393 removeOnLinkPrefix((*it)->destPrefix(), (*it)->prefixLength());
00394 entryExpired = true;
00395 }
00396 if (entryExpired == false) return *it;
00397 }
00398 }
00399 // FIXME todo: if we selected an expired route, throw it out and select again!
00400 return NULL;
00401 }
|
|
|
Raises an error. 00174 {
00175 opp_error("This module doesn't process messages");
00176 }
|
|
|
00085 {
00086 if (stage==1)
00087 {
00088 ift = InterfaceTableAccess().get();
00089
00090 WATCH_PTRVECTOR(routeList);
00091 WATCH_MAP(destCache); // FIXME commented out for now
00092 isrouter = par("isRouter");
00093 WATCH(isrouter);
00094
00095 // add IPv6InterfaceData to interfaces
00096 for (int i=0; i<ift->numInterfaces(); i++)
00097 {
00098 InterfaceEntry *ie = ift->interfaceAt(i);
00099 configureInterfaceForIPv6(ie);
00100 }
00101
00102 parseXMLConfigFile();
00103
00104 // skip hosts
00105 if (isrouter)
00106 {
00107 // add globally routable prefixes to routing table
00108 for (int x = 0; x < ift->numInterfaces(); x++)
00109 {
00110 InterfaceEntry *ie = ift->interfaceAt(x);
00111
00112 if (ie->isLoopback())
00113 continue;
00114
00115 for (int y = 0; y < ie->ipv6()->numAdvPrefixes(); y++)
00116 if (ie->ipv6()->advPrefix(y).prefix.isGlobal())
00117 addOrUpdateOwnAdvPrefix(ie->ipv6()->advPrefix(y).prefix,
00118 ie->ipv6()->advPrefix(y).prefixLength,
00119 x, 0);
00120 }
00121 }
00122 }
00123 else if (stage==4)
00124 {
00125 // configurator adds routes only in stage==3
00126 updateDisplayString();
00127 }
00128 }
|
|
|
Returns an interface given by its address. Returns NULL if not found. 00316 {
00317 Enter_Method("interfaceByAddress(%s)=?", addr.str().c_str());
00318
00319 if (addr.isUnspecified())
00320 return NULL;
00321 for (int i=0; i<ift->numInterfaces(); ++i)
00322 {
00323 InterfaceEntry *ie = ift->interfaceAt(i);
00324 if (ie->ipv6()->hasAddress(addr))
00325 return ie;
00326 }
00327 return NULL;
00328 }
|
|
|
Checks if the given prefix already exists in the routing table (prefix list) 00404 {
00405 for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00406 if (prefix.matches((*it)->destPrefix(),128))
00407 return true;
00408 return false;
00409 }
|
|
|
IP forwarding on/off 00171 {return isrouter;}
|
|
|
Checks if the address is one of the host's addresses, i.e. assigned to one of its interfaces (tentatively or not). 00331 {
00332 Enter_Method("localDeliver(%s) y/n", dest.str().c_str());
00333
00334 // first, check if we have an interface with this address
00335 for (int i=0; i<ift->numInterfaces(); i++)
00336 {
00337 InterfaceEntry *ie = ift->interfaceAt(i);
00338 if (ie->ipv6()->hasAddress(dest))
00339 return true;
00340 }
00341
00342 // then check for special, preassigned multicast addresses
00343 // (these addresses occur more rarely than specific interface addresses,
00344 // that's why we check for them last)
00345
00346 if (dest==IPv6Address::ALL_NODES_1 || dest==IPv6Address::ALL_NODES_2)
00347 return true;
00348 if (isRouter() && (dest==IPv6Address::ALL_ROUTERS_1 || dest==IPv6Address::ALL_ROUTERS_2 || dest==IPv6Address::ALL_ROUTERS_5))
00349 return true;
00350
00351 // check for solicited-node multicast address
00352 if (dest.matches(IPv6Address::SOLICITED_NODE_PREFIX, 104))
00353 {
00354 for (int i=0; i<ift->numInterfaces(); i++)
00355 {
00356 InterfaceEntry *ie = ift->interfaceAt(i);
00357 if (ie->ipv6()->matchesSolicitedNodeMulticastAddress(dest))
00358 return true;
00359 }
00360 }
00361 return false;
00362 }
|
|
||||||||||||
|
Looks up the given destination address in the Destination Cache, then returns the next-hop address and the interface in the outInterfaceId variable. If the destination is not in the cache, outInterfaceId is set to -1 and the unspecified address is returned. The caller should check for interfaceId==-1, because unspecified address is also returned if the link layer doesn't use addresses at all (e.g. PPP). NOTE: outInterfaceId is an OUTPUT parameter -- its initial value is ignored, and the lookupDestCache() sets it to the correct value instead. 00365 {
00366 Enter_Method("lookupDestCache(%s)", dest.str().c_str());
00367
00368 DestCache::iterator it = destCache.find(dest);
00369 if (it == destCache.end())
00370 {
00371 outInterfaceId = -1;
00372 return IPv6Address::UNSPECIFIED_ADDRESS;
00373 }
00374 outInterfaceId = it->second.interfaceId;
00375 return it->second.nextHopAddr;
00376 }
|
|
|
00150 {return 5;}
|
|
|
Return the number of routes. 00600 {
00601 return routeList.size();
00602 }
|
|
|
00131 {
00132 // TODO to be revised by Andras
00133 // configure interfaces from XML config file
00134 cXMLElement *config = par("routingTableFile");
00135 for (cXMLElement *child=config->getFirstChild(); child; child = child->getNextSibling())
00136 {
00137 //std::cout << "configuring interfaces from XML file." << endl;
00138 //std::cout << "selected element is: " << child->getTagName() << endl;
00139 // we ensure that the selected element is local.
00140 if (opp_strcmp(child->getTagName(),"local")!=0) continue;
00141 //ensure that this is the right parent module we are configuring.
00142 if (opp_strcmp(child->getAttribute("node"),parentModule()->fullName())!=0)
00143 continue;
00144 //Go one level deeper.
00145 //child = child->getFirstChild();
00146 for (cXMLElement *ifTag=child->getFirstChild(); ifTag; ifTag = ifTag->getNextSibling())
00147 {
00148 //The next tag should be "interface".
00149 if (opp_strcmp(ifTag->getTagName(),"interface")!=0)
00150 continue;
00151 //std::cout << "Getting attribute: name" << endl;
00152 const char *ifname = ifTag->getAttribute("name");
00153 if (!ifname)
00154 error("<interface> without name attribute at %s", child->getSourceLocation());
00155 InterfaceEntry *ie = ift->interfaceByName(ifname);
00156 if (!ie)
00157 error("no interface named %s was registered, %s", ifname, child->getSourceLocation());
00158 configureInterfaceFromXML(ie, ifTag);
00159 }
00160 }
00161 }
|
|
|
Discard all entries in destination cache 00421 {
00422 destCache.clear();
00423 updateDisplayString();
00424 }
|
|
||||||||||||
|
Discard all entries in destination cache where next hop is the given address on the given interface. This is typically called when a router becomes unreachable, and all destinations going via that router have to go though router selection again. 00427 {
00428 for (DestCache::iterator it=destCache.begin(); it!=destCache.end(); )
00429 {
00430 if (it->second.interfaceId==interfaceId && it->second.nextHopAddr==nextHopAddr)
00431 {
00432 // move the iterator past this element before removing it
00433 DestCache::iterator oldIt = it++;
00434 destCache.erase(oldIt);
00435 }
00436 else
00437 {
00438 it++;
00439 }
00440 }
00441
00442 updateDisplayString();
00443 }
|
|
||||||||||||
|
Remove an on-link prefix. To be called when the prefix gets advertised with zero lifetime, or to purge an expired prefix. NOTE: This method does NOT remove the matching addresses from the InterfaceTable (see IPv6InterfaceData); that has to be done separately. 00518 {
00519 // scan the routing table for this prefix and remove it
00520 for (RouteList::iterator it=routeList.begin(); it!=routeList.end(); it++)
00521 {
00522 if ((*it)->src()==IPv6Route::FROM_RA && (*it)->destPrefix()==destPrefix && (*it)->prefixLength()==prefixLength)
00523 {
00524 routeList.erase(it);
00525 return; // there can be only one such route, addOrUpdateOnLinkPrefix() guarantees that
00526 }
00527 }
00528
00529 updateDisplayString();
00530 }
|
|
|
Deletes the given route from the route table. 00591 {
00592 RouteList::iterator it = std::find(routeList.begin(), routeList.end(), route);
00593 ASSERT(it!=routeList.end());
00594 routeList.erase(it);
00595
00596 updateDisplayString();
00597 }
|
|
|
Return the ith route.
|
|
||||||||||||
|
00570 {
00571 // helper for sort() in addRoute(). We want routes with longer
00572 // prefixes to be at front, so we compare them as "less".
00573 // For metric, a smaller value is better (we report that as "less").
00574 if (a->prefixLength()!=b->prefixLength())
00575 return a->prefixLength() > b->prefixLength();
00576 return a->metric() < b->metric();
00577 }
|
|
||||||||||||||||
|
Add or update a destination cache entry. 00412 {
00413 // FIXME this performs 2 lookups -- optimize to do only one
00414 destCache[dest].nextHopAddr = nextHopAddr;
00415 destCache[dest].interfaceId = interfaceId;
00416
00417 updateDisplayString();
00418 }
|
|
|
00164 {
00165 if (!ev.isGUI())
00166 return;
00167
00168 char buf[80];
00169 sprintf(buf, "%d routes\n%d destcache entries", numRoutes(), destCache.size());
00170 displayString().setTagArg("t",0,buf);
00171 }
|
|
||||||||||||
|
00069 {
00070 os << "if=" << e.interfaceId << " " << e.nextHopAddr; //FIXME try printing interface name
00071 return os;
00072 };
|
|
|
|
|
|
|
|
|
|
|
|
|
1.4.1