INET Framework for OMNeT++/OMNEST
ansaRoutingTable6.cc
Go to the documentation of this file.
00001 //
00002 // Marek Cerny, 2MSK
00003 // FIT VUT 2011
00004 //
00005 // This program is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU Lesser General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (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 #include <algorithm>
00020 
00021 #include "IPv6InterfaceData.h"
00022 #include "InterfaceTableAccess.h"
00023 
00024 #include "ansaRoutingTable6.h"
00025 
00026 Define_Module(AnsaRoutingTable6);
00027 
00028 /*****************************************************************************/
00029 /* AnsaIPv6Route class                                                       */
00030 
00031 /*
00032  * Prints routing table in Cisco IOS "show ipv6 route" format
00033  */
00034 std::string AnsaIPv6Route::printRoute() const {
00035 
00036    std::stringstream out;
00037 
00038    if (!isActive()){
00039       out << "(down) ";
00040    }
00041 
00042    // first letter describes type of the route
00043    // C - directly connected
00044    // A - own advertise prefix
00045    // S - static
00046    // N - from NDP router advertisements
00047    // P - routing protocol (RoutingTable6 does not have entries for specific protocols)
00048    switch (getSrc()){
00049 
00050       case STATIC:
00051          if (getMetric() == 0){
00052             out << "C";
00053          }else{
00054             out << "S";
00055          }
00056          break;
00057 
00058       case OWN_ADV_PREFIX:
00059          out << "A";
00060          break;
00061 
00062       case FROM_RA:
00063          out << "N";
00064          break;
00065 
00066       case ROUTING_PROT:
00067          out << "P";
00068          break;
00069    }
00070 
00071    out << "  ";
00072    if (getDestPrefix() == IPv6Address::UNSPECIFIED_ADDRESS){
00073       out << "::";
00074    }else{
00075       out << getDestPrefix();
00076    }
00077 
00078    out << "/" << getPrefixLength() << " ";
00079    out << "[" << getMetric() << "] ";
00080    out << "via ";
00081 
00082    if (getNextHop() == IPv6Address::UNSPECIFIED_ADDRESS){
00083       out << "::";
00084    }else{
00085       out << getNextHop();
00086    }
00087 
00088    if (getInterfaceId() != -1){
00089       out << ", " << getInterfaceName();
00090    }
00091 
00092    return out.str();
00093 }
00094 
00095 std::ostream& operator<<(std::ostream& os, const AnsaIPv6Route& e){
00096    os << e.printRoute();
00097    return os;
00098 }
00099 
00100 std::ostream& operator<<(std::ostream& os, const IPv6Route& e);
00101 
00102 
00103 /*****************************************************************************/
00104 /* AnsaRoutingTable6 class                                                   */
00105 
00106 AnsaRoutingTable6::AnsaRoutingTable6(){
00107    routes = (std::vector<AnsaIPv6Route*> *) &routeList;
00108 }
00109 
00110 void AnsaRoutingTable6::initialize(int stage){
00111 
00112    if (stage == 1){
00113       ift = InterfaceTableAccess().get();
00114       nb = NotificationBoardAccess().get();
00115 
00116       if (ift == NULL){
00117          throw cRuntimeError("AnsaInterfaceTable not found");
00118       }
00119 
00120       if (nb == NULL){
00121          throw cRuntimeError("NotificationBoard not found");
00122       }
00123 
00124       nb->subscribe(this, NF_INTERFACE_STATE_CHANGED);
00125 
00126       WATCH_PTRVECTOR(*routes);
00127       WATCH_PTRVECTOR(routeList);
00128       WATCH_MAP(destCache);
00129       isrouter = par("isRouter");
00130       WATCH(isrouter);
00131 
00132       // add IPv6InterfaceData to interfaces
00133       for (int i = 0; i < ift->getNumInterfaces(); i++){
00134          InterfaceEntry *ie = ift->getInterface(i);
00135          configureInterfaceForIPv6(ie);
00136       }
00137 
00138       if (isrouter){
00139          // add globally routable prefixes to routing table
00140          for (int x = 0; x < ift->getNumInterfaces(); x++){
00141             InterfaceEntry *ie = ift->getInterface(x);
00142 
00143             if (ie->isLoopback())
00144                continue;
00145 
00146             for (int y = 0; y < ie->ipv6Data()->getNumAdvPrefixes(); y++){
00147                if (ie->ipv6Data()->getAdvPrefix(y).prefix.isGlobal()){
00148                   addOrUpdateOwnAdvPrefix(ie->ipv6Data()->getAdvPrefix(y).prefix, ie->ipv6Data()->getAdvPrefix(y).prefixLength, ie->getInterfaceId(), 0);
00149                }
00150             }
00151          }
00152       }
00153    }else if (stage == 4){
00154       // configurator adds routes only in stage==3
00155       updateDisplayString();
00156    }
00157 }
00158 
00159 void AnsaRoutingTable6::receiveChangeNotification(int category, const cPolymorphic *details){
00160 
00161    if (simulation.getContextType() == CTX_INITIALIZE)
00162       return;
00163 
00164    Enter_Method_Silent();
00165 
00166    if (category == NF_INTERFACE_STATE_CHANGED){
00167 
00168       InterfaceEntry *ie;
00169       AnsaIPv6Route *r;
00170 
00171       // Walk thru the whole routing table and try to get interface for each route.
00172       // If interface does not exist in InterfaceTable, it's down and we should
00173       // disable the route.
00174       // If interface of a disabled route does exist in InterfaceTable, it's up
00175       // and we should enable the route again.
00176       for (RouteList::const_iterator it = routeList.begin(); it != routeList.end(); it++){
00177          r = (AnsaIPv6Route *)(*it);
00178          ie = ift->getInterfaceById(r->getInterfaceId());
00179 
00180          if (ie == NULL && r->isActive()){
00181             r->setActive(false);
00182          }else if (ie != NULL && ie->isDown() && r->isActive()){
00183             r->setActive(false);
00184          }else if (ie != NULL && !ie->isDown() && !r->isActive()){
00185             r->setActive(true);
00186          }
00187       }
00188 
00189       std::sort(routeList.begin(), routeList.end(), routeLessThan);
00190       purgeDestCache();
00191    }
00192 }
00193 
00194 
00195 const IPv6Route *AnsaRoutingTable6::doLongestPrefixMatch(const IPv6Address& dest){
00196 
00197    Enter_Method("doLongestPrefixMatch(%s)", dest.str().c_str());
00198 
00199    AnsaIPv6Route *route;
00200 
00201    // we'll just stop at the first match, because the table is sorted
00202    // by prefix lengths and metric (see addRoute())
00203    for (RouteList::const_iterator it = routeList.begin(); it != routeList.end(); it++){
00204       if (dest.matches((*it)->getDestPrefix(), (*it)->getPrefixLength())){
00205 
00206          route = (AnsaIPv6Route *)(*it);
00207          if (!route->isActive()){
00208             return NULL;
00209          }
00210 
00211          bool entryExpired = false;
00212          if (simTime() > (*it)->getExpiryTime() && (*it)->getExpiryTime() != 0){
00213             EV<< "Expired prefix detected!!" << endl;
00214             removeOnLinkPrefix((*it)->getDestPrefix(), (*it)->getPrefixLength());
00215             entryExpired = true;
00216             continue;
00217          }else{
00218             return *it;
00219          }
00220       }
00221    }
00222    return NULL;
00223 }
00224 
00225 
00226 void AnsaRoutingTable6::addDirectRoute(const IPv6Address& destPrefix, int prefixLength, unsigned int interfaceId){
00227 
00228    // create route object
00229    IPv6Route *route = new IPv6Route(destPrefix, prefixLength, IPv6Route::STATIC);
00230    route->setInterfaceId(interfaceId);
00231    route->setNextHop(IPv6Address::UNSPECIFIED_ADDRESS);
00232    route->setMetric(0);
00233 
00234    // then add it
00235    addRoute(route);
00236 }
00237 
00238 bool AnsaRoutingTable6::routeLessThan(const IPv6Route *a, const IPv6Route *b){
00239 
00240    // Helper for sort() in addRoute().
00241 
00242    // We want routes with longer prefixes to be at front,
00243    // so we compare them as "less". For metric, a smaller
00244    // value is better (we report that as "less"). Disabled
00245    // routes are "more" than enabled routes.
00246 
00247    AnsaIPv6Route *ax = (AnsaIPv6Route *) a;
00248    AnsaIPv6Route *bx = (AnsaIPv6Route *) b;
00249 
00250    if (ax->isActive() && !bx->isActive())
00251       return true;
00252    if (!ax->isActive() && bx->isActive())
00253       return false;
00254 
00255    if (a->getPrefixLength() != b->getPrefixLength())
00256       return a->getPrefixLength() > b->getPrefixLength();
00257 
00258    return a->getMetric() < b->getMetric();
00259 }
00260 
00261 void AnsaRoutingTable6::addRoute(IPv6Route *route){
00262 
00263 
00264    AnsaIPv6Route *route6 = new AnsaIPv6Route(route->getDestPrefix(),
00265                                              route->getPrefixLength(),
00266                                              route->getSrc());
00267 
00268    route6->setNextHop(route->getNextHop());
00269    route6->setMetric(route->getMetric());
00270    route6->setInterfaceId(route->getInterfaceId());
00271    route6->setExpiryTime(route->getExpiryTime());
00272    route6->setActive(true);
00273 
00274    if (route->getInterfaceId() != -1){
00275       InterfaceEntry *ie = ift->getInterfaceById(route->getInterfaceId());
00276       if (ie != NULL){
00277          route6->setInterfaceName(ie->getName());
00278       }
00279    }
00280 
00281    delete route;
00282    routeList.push_back(route6);
00283 
00284    // we keep entries sorted by prefix length and metric in routeList,
00285    // so that we can stop at the first match when doing the longest prefix matching
00286    std::sort(routeList.begin(), routeList.end(), routeLessThan);
00287 
00288    updateDisplayString();
00289 
00290    nb->fireChangeNotification(NF_IPv6_ROUTE_ADDED, route6);
00291 }