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