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