|
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 "deviceConfigurator.h" 00020 00021 #include "IPv6Address.h" 00022 #include "IPv6InterfaceData.h" 00023 #include "xmlParser.h" 00024 00025 Define_Module(DeviceConfigurator); 00026 00027 using namespace std; 00028 00029 void DeviceConfigurator::initialize(int stage){ 00030 00031 // interfaces and routing table are not ready before stage 2 00032 if (stage == 2){ 00033 00034 // get table of interfaces of this device 00035 ift = InterfaceTableAccess().get(); 00036 if (ift == NULL){ 00037 throw cRuntimeError("AnsaInterfaceTable not found"); 00038 } 00039 00040 // get routing table of this device 00041 rt6 = AnsaRoutingTable6Access().get(); 00042 if (rt6 == NULL){ 00043 throw cRuntimeError("RoutingTable6 not found"); 00044 } 00045 00046 // RFC 4861 specifies that sending RAs should be disabled by default 00047 for (int i = 0; i < ift->getNumInterfaces(); i++){ 00048 ift->getInterface(i)->ipv6Data()->setAdvSendAdvertisements(false); 00049 } 00050 00051 00052 // get access to device node from XML 00053 const char *deviceType = par("deviceType"); 00054 const char *deviceId = par("deviceId"); 00055 const char *configFile = par("configFile"); 00056 00057 cXMLElement *device = xmlParser::GetDevice(deviceType, deviceId, configFile); 00058 if (device == NULL){ 00059 ev << "No configuration found for this device (" << deviceType << " id=" << deviceId << ")" << endl; 00060 return; 00061 } 00062 00063 00064 // configure interfaces - addressing 00065 cXMLElement *iface = xmlParser::GetInterface(NULL, device); 00066 if (iface == NULL){ 00067 ev << "No interface configuration found for this device (" << deviceType << " id=" << deviceId << ")" << endl; 00068 }else{ 00069 loadInterfaceConfig(iface); 00070 } 00071 00072 00073 // configure static routing 00074 cXMLElement *route = xmlParser::GetStaticRoute6(NULL, device); 00075 if (route == NULL && strcmp(deviceType, "Router") == 0){ 00076 ev << "No static routing configuration found for this device (" << deviceType << " id=" << deviceId << ")" << endl; 00077 }else{ 00078 loadStaticRouting(route); 00079 } 00080 00081 00082 // Adding default route requires routing table lookup to pick the right output 00083 // interface. This needs to be performed when all IPv6 addresses are already assigned 00084 // and there are matching records in the routing table. 00085 cXMLElement *gateway = device->getFirstChildWithTag("DefaultRouter"); 00086 if (gateway == NULL && strcmp(deviceType, "Host") == 0){ 00087 ev << "No default-router configuration found for this device (" << deviceType << " id=" << deviceId << ")" << endl; 00088 }else{ 00089 loadDefaultRouter(gateway); 00090 } 00091 } 00092 } 00093 00094 00095 void DeviceConfigurator::loadInterfaceConfig(cXMLElement *iface){ 00096 00097 // for each interface node 00098 while (iface != NULL){ 00099 00100 // get interface name and find matching interface in interface table 00101 const char *ifaceName = iface->getAttribute("name"); 00102 InterfaceEntry *ie = ift->getInterfaceByName(ifaceName); 00103 if (ie == NULL){ 00104 throw cRuntimeError("No interface called %s on this device", ifaceName); 00105 } 00106 00107 // for each IPv6 address 00108 cXMLElement *addr = xmlParser::GetIPv6Address(NULL, iface); 00109 while (addr != NULL){ 00110 00111 // get address string 00112 string addrFull = addr->getNodeValue(); 00113 IPv6Address ipv6; 00114 int prefixLen; 00115 00116 // check if it's a valid IPv6 address string with prefix and get prefix 00117 if (!ipv6.tryParseAddrWithPrefix(addrFull.c_str(), prefixLen)){ 00118 throw cRuntimeError("Unable to set IPv6 address %s on interface %s", addrFull.c_str(), ifaceName); 00119 } 00120 00121 ipv6 = addrFull.substr(0, addrFull.find_last_of('/')).c_str(); 00122 00123 // IPv6NeighbourDiscovery doesn't implement DAD for non-link-local addresses 00124 // -> we have to set the address as non-tentative 00125 ie->ipv6Data()->assignAddress(ipv6, false, 0, 0); 00126 00127 // adding directly connected route to the routing table 00128 rt6->addDirectRoute(ipv6.getPrefix(prefixLen), prefixLen, ie->getInterfaceId()); 00129 00130 00131 // get next IPv6 address 00132 addr = xmlParser::GetIPv6Address(addr, NULL); 00133 } 00134 00135 00136 // for each parameter 00137 for (cXMLElement *param = iface->getFirstChild(); param; param = param->getNextSibling()){ 00138 00139 if(strcmp(param->getTagName(), "NdpAdvSendAdvertisements") == 0){ 00140 bool value = false; 00141 if (!xmlParser::Str2Bool(&value, param->getNodeValue())){ 00142 throw cRuntimeError("Invalid NdpAdvSendAdvertisements value on interface %s", ie->getName()); 00143 } 00144 ie->ipv6Data()->setAdvSendAdvertisements(value); 00145 } 00146 00147 if(strcmp(param->getTagName(), "NdpMaxRtrAdvInterval") == 0){ 00148 int value = 0; 00149 if (!xmlParser::Str2Int(&value, param->getNodeValue())){ 00150 throw cRuntimeError("Unable to parse valid NdpMaxRtrAdvInterval %s on interface %s", value, ifaceName); 00151 } 00152 if (value < 4 || value > 1800){ 00153 value = 600; 00154 } 00155 ie->ipv6Data()->setMaxRtrAdvInterval(value); 00156 } 00157 00158 if(strcmp(param->getTagName(), "NdpMinRtrAdvInterval") == 0){ 00159 int value = 0; 00160 if (!xmlParser::Str2Int(&value, param->getNodeValue())){ 00161 throw cRuntimeError("Unable to parse valid NdpMinRtrAdvInterval %s on interface %s", value, ifaceName); 00162 } 00163 if (value < 3 || value > 1350){ 00164 value = 200; 00165 } 00166 ie->ipv6Data()->setMinRtrAdvInterval(value); 00167 } 00168 } 00169 00170 00171 00172 // for each IPv6 prefix 00173 cXMLElement *prefix = xmlParser::GetAdvPrefix(NULL, iface); 00174 while (prefix != NULL){ 00175 00176 // get address string 00177 string addrFull = prefix->getNodeValue(); 00178 IPv6InterfaceData::AdvPrefix advPrefix; 00179 int prefixLen; 00180 00181 // check if it's a valid IPv6 address string with prefix and get prefix 00182 if (!advPrefix.prefix.tryParseAddrWithPrefix(addrFull.c_str(), prefixLen)){ 00183 throw cRuntimeError("Unable to parse IPv6 prefix %s on interface %s", addrFull.c_str(), ifaceName); 00184 } 00185 advPrefix.prefix = addrFull.substr(0, addrFull.find_last_of('/')).c_str(); 00186 advPrefix.prefixLength = prefixLen; 00187 00188 const char *validLifeTime = prefix->getAttribute("valid"); 00189 const char *preferredLifeTime = prefix->getAttribute("preferred"); 00190 int value; 00191 00192 value = 2592000; 00193 if (validLifeTime != NULL){ 00194 if (!xmlParser::Str2Int(&value, validLifeTime)){ 00195 throw cRuntimeError("Unable to parse valid lifetime %s on IPv6 prefix %s on interface %s", validLifeTime, addrFull.c_str(), ifaceName); 00196 } 00197 advPrefix.advValidLifetime = value; 00198 } 00199 00200 value = 604800; 00201 if (preferredLifeTime != NULL){ 00202 if (!xmlParser::Str2Int(&value, preferredLifeTime)){ 00203 throw cRuntimeError("Unable to parse preferred lifetime %s on IPv6 prefix %s on interface %s", preferredLifeTime, addrFull.c_str(), ifaceName); 00204 } 00205 advPrefix.advPreferredLifetime = value; 00206 } 00207 00208 advPrefix.advOnLinkFlag = true; 00209 advPrefix.advAutonomousFlag = true; 00210 00211 // adding prefix 00212 ie->ipv6Data()->addAdvPrefix(advPrefix); 00213 00214 // get next IPv6 address 00215 prefix = xmlParser::GetAdvPrefix(prefix, NULL); 00216 } 00217 00218 00219 00220 // get next interface 00221 iface = xmlParser::GetInterface(iface, NULL); 00222 } 00223 } 00224 00225 00226 void DeviceConfigurator::loadStaticRouting(cXMLElement *route){ 00227 00228 // for each static route 00229 while (route != NULL){ 00230 00231 // get network address string with prefix 00232 cXMLElement *network = route->getFirstChildWithTag("NetworkAddress"); 00233 if (network == NULL){ 00234 throw cRuntimeError("IPv6 network address for static route not set"); 00235 } 00236 00237 string addrFull = network->getNodeValue(); 00238 IPv6Address addrNetwork; 00239 int prefixLen; 00240 00241 // check if it's a valid IPv6 address string with prefix and get prefix 00242 if (!addrNetwork.tryParseAddrWithPrefix(addrFull.c_str(), prefixLen)){ 00243 throw cRuntimeError("Unable to set IPv6 network address %s for static route", addrFull.c_str()); 00244 } 00245 00246 addrNetwork = addrFull.substr(0, addrFull.find_last_of('/')).c_str(); 00247 00248 00249 // get IPv6 next hop address string without prefix 00250 cXMLElement *nextHop = route->getFirstChildWithTag("NextHopAddress"); 00251 if (nextHop == NULL){ 00252 throw cRuntimeError("IPv6 next hop address for static route not set"); 00253 } 00254 00255 IPv6Address addrNextHop = nextHop->getNodeValue(); 00256 00257 00258 // optinal argument - administrative distance is set to 1 if not set 00259 cXMLElement *distance = route->getFirstChildWithTag("AdministrativeDistance"); 00260 int adminDistance = 1; 00261 if (distance != NULL){ 00262 if (!xmlParser::Str2Int(&adminDistance, distance->getNodeValue())){ 00263 adminDistance = 0; 00264 } 00265 } 00266 00267 if (adminDistance < 1 || adminDistance > 255){ 00268 throw cRuntimeError("Invalid administrative distance for static route (%d)", adminDistance); 00269 } 00270 00271 00272 // current INET routing lookup implementation is not recursive 00273 // -> nextHop needs to be known network and we have to set output interface manually 00274 00275 // browse connected routes and find one that matches next hop address 00276 const IPv6Route *record = rt6->doLongestPrefixMatch(addrNextHop); 00277 if (record == NULL){ 00278 ev << "No directly connected route for IPv6 next hop address " << addrNextHop << " found" << endl; 00279 }else{ 00280 // add static route 00281 rt6->addStaticRoute(addrNetwork, prefixLen, record->getInterfaceId(), addrNextHop, adminDistance); 00282 } 00283 00284 00285 // get next static route 00286 route = xmlParser::GetStaticRoute6(route, NULL); 00287 } 00288 } 00289 00290 00291 void DeviceConfigurator::loadDefaultRouter(cXMLElement *gateway){ 00292 00293 if (gateway == NULL) 00294 return; 00295 00296 // get default-router address string (without prefix) 00297 IPv6Address nextHop = gateway->getNodeValue(); 00298 00299 // browse routing table to find the best route to default-router 00300 const IPv6Route *route = rt6->doLongestPrefixMatch(nextHop); 00301 if (route == NULL){ 00302 return; 00303 } 00304 00305 // add default static route 00306 rt6->addStaticRoute(IPv6Address::UNSPECIFIED_ADDRESS, 0, route->getInterfaceId(), nextHop, 1); 00307 } 00308 00309 00310 void DeviceConfigurator::handleMessage(cMessage *msg){ 00311 throw cRuntimeError("This module does not receive messages"); 00312 delete msg; 00313 }