OSPFRouting.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Andras Babos and Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #include "OSPFRouting.h"
00019 #include "IPAddress.h"
00020 #include "IPAddressResolver.h"
00021 #include "IPControlInfo.h"
00022 #include "OSPFcommon.h"
00023 #include "OSPFArea.h"
00024 #include "OSPFInterface.h"
00025 #include "MessageHandler.h"
00026 #include "RoutingTableAccess.h"
00027 #include "InterfaceTableAccess.h"
00028 #include <string>
00029 #include <map>
00030 #include <stdlib.h>
00031 #include <memory.h>
00032 
00033 
00034 Define_Module(OSPFRouting);
00035 
00036 
00037 OSPFRouting::OSPFRouting()
00038 {
00039     ospfRouter = NULL;
00040 }
00041 
00046 OSPFRouting::~OSPFRouting(void)
00047 {
00048     delete ospfRouter;
00049 }
00050 
00051 
00059 void OSPFRouting::initialize(int stage)
00060 {
00061     // we have to wait for stage 2 until interfaces get registered(stage 0)
00062     // and routerId gets assigned(stage 3)
00063     if (stage == 4)
00064     {
00065         rt = RoutingTableAccess().get();
00066         ift = InterfaceTableAccess().get();
00067 
00068         // Get routerId
00069         ospfRouter = new OSPF::Router(rt->getRouterId().getInt(), this);
00070 
00071         // read the OSPF AS configuration
00072         const char *fileName = par("ospfConfigFile");
00073         if (fileName == NULL || (!strcmp(fileName, "")) || !LoadConfigFromXML(fileName))
00074             error("Error reading AS configuration from file %s", fileName);
00075 
00076         ospfRouter->AddWatches();
00077     }
00078 }
00079 
00080 
00085 void OSPFRouting::handleMessage(cMessage *msg)
00086 {
00087 //    if (simulation.getEventNumber() == 90591) {
00088 //        __asm int 3;
00089 //    }
00090     ospfRouter->GetMessageHandler()->MessageReceived(msg);
00091 }
00092 
00096 int OSPFRouting::ResolveInterfaceName(const std::string& name) const
00097 {
00098     InterfaceEntry* ie = ift->getInterfaceByName(name.c_str());
00099     if (!ie)
00100         opp_error("error reading XML config: IInterfaceTable contains no interface named '%s'", name.c_str());
00101     return ie->getInterfaceId();
00102 }
00103 
00109 void OSPFRouting::GetAreaListFromXML(const cXMLElement& routerNode, std::map<std::string, int>& areaList) const
00110 {
00111     cXMLElementList routerConfig = routerNode.getChildren();
00112     for (cXMLElementList::iterator routerConfigIt = routerConfig.begin(); routerConfigIt != routerConfig.end(); routerConfigIt++) {
00113         std::string nodeName = (*routerConfigIt)->getTagName();
00114         if ((nodeName == "PointToPointInterface") ||
00115             (nodeName == "BroadcastInterface") ||
00116             (nodeName == "NBMAInterface") ||
00117             (nodeName == "PointToMultiPointInterface"))
00118         {
00119             std::string areaId = (*routerConfigIt)->getChildrenByTagName("AreaID")[0]->getNodeValue();
00120             if (areaList.find(areaId) == areaList.end()) {
00121                 areaList[areaId] = 1;
00122             }
00123         }
00124     }
00125 }
00126 
00127 
00134 void OSPFRouting::LoadAreaFromXML(const cXMLElement& asConfig, const std::string& areaID)
00135 {
00136     std::string areaXPath("Area[@id='");
00137     areaXPath += areaID;
00138     areaXPath += "']";
00139 
00140     cXMLElement* areaConfig = asConfig.getElementByPath(areaXPath.c_str());
00141     if (areaConfig == NULL) {
00142         error("No configuration for Area ID: %s", areaID.c_str());
00143     }
00144     else {
00145         EV << "    loading info for Area id = " << areaID << "\n";
00146     }
00147 
00148     OSPF::Area* area = new OSPF::Area(ULongFromAddressString(areaID.c_str()));
00149     cXMLElementList areaDetails = areaConfig->getChildren();
00150     for (cXMLElementList::iterator arIt = areaDetails.begin(); arIt != areaDetails.end(); arIt++) {
00151         std::string nodeName = (*arIt)->getTagName();
00152         if (nodeName == "AddressRange") {
00153             OSPF::IPv4AddressRange addressRange;
00154             addressRange.address = IPv4AddressFromAddressString((*arIt)->getChildrenByTagName("Address")[0]->getNodeValue());
00155             addressRange.mask = IPv4AddressFromAddressString((*arIt)->getChildrenByTagName("Mask")[0]->getNodeValue());
00156             std::string status = (*arIt)->getChildrenByTagName("Status")[0]->getNodeValue();
00157             if (status == "Advertise") {
00158                 area->AddAddressRange(addressRange, true);
00159             } else {
00160                 area->AddAddressRange(addressRange, false);
00161             }
00162         }
00163         if ((nodeName == "Stub") && (areaID != "0.0.0.0")) {    // the backbone cannot be configured as a stub
00164             area->SetExternalRoutingCapability(false);
00165             area->SetStubDefaultCost(atoi((*arIt)->getChildrenByTagName("DefaultCost")[0]->getNodeValue()));
00166         }
00167     }
00168     // Add the Area to the router
00169     ospfRouter->AddArea(area);
00170 }
00171 
00172 
00178 void OSPFRouting::LoadInterfaceParameters(const cXMLElement& ifConfig)
00179 {
00180     OSPF::Interface* intf          = new OSPF::Interface;
00181     std::string      ifName        = ifConfig.getAttribute("ifName");
00182     int              ifIndex       = ResolveInterfaceName(ifName);
00183     std::string      interfaceType = ifConfig.getTagName();
00184 
00185     EV << "        loading " << interfaceType << " " << ifName << " ifIndex[" << ifIndex << "]\n";
00186 
00187     intf->SetIfIndex(ifIndex);
00188     if (interfaceType == "PointToPointInterface") {
00189         intf->SetType(OSPF::Interface::PointToPoint);
00190     } else if (interfaceType == "BroadcastInterface") {
00191         intf->SetType(OSPF::Interface::Broadcast);
00192     } else if (interfaceType == "NBMAInterface") {
00193         intf->SetType(OSPF::Interface::NBMA);
00194     } else if (interfaceType == "PointToMultiPointInterface") {
00195         intf->SetType(OSPF::Interface::PointToMultiPoint);
00196     } else {
00197         delete intf;
00198         error("Loading %s ifIndex[%d] aborted", interfaceType.c_str(), ifIndex);
00199     }
00200 
00201     OSPF::AreaID    areaID    = 0;
00202     cXMLElementList ifDetails = ifConfig.getChildren();
00203 
00204     for (cXMLElementList::iterator ifElemIt = ifDetails.begin(); ifElemIt != ifDetails.end(); ifElemIt++) {
00205         std::string nodeName = (*ifElemIt)->getTagName();
00206         if (nodeName == "AreaID") {
00207             areaID = ULongFromAddressString((*ifElemIt)->getNodeValue());
00208             intf->SetAreaID(areaID);
00209         }
00210         if (nodeName == "InterfaceOutputCost") {
00211             intf->SetOutputCost(atoi((*ifElemIt)->getNodeValue()));
00212         }
00213         if (nodeName == "RetransmissionInterval") {
00214             intf->SetRetransmissionInterval(atoi((*ifElemIt)->getNodeValue()));
00215         }
00216         if (nodeName == "InterfaceTransmissionDelay") {
00217             intf->SetTransmissionDelay(atoi((*ifElemIt)->getNodeValue()));
00218         }
00219         if (nodeName == "RouterPriority") {
00220             intf->SetRouterPriority(atoi((*ifElemIt)->getNodeValue()));
00221         }
00222         if (nodeName == "HelloInterval") {
00223             intf->SetHelloInterval(atoi((*ifElemIt)->getNodeValue()));
00224         }
00225         if (nodeName == "RouterDeadInterval") {
00226             intf->SetRouterDeadInterval(atoi((*ifElemIt)->getNodeValue()));
00227         }
00228         if (nodeName == "AuthenticationType") {
00229             std::string authenticationType = (*ifElemIt)->getNodeValue();
00230             if (authenticationType == "SimplePasswordType") {
00231                 intf->SetAuthenticationType(OSPF::SimplePasswordType);
00232             } else if (authenticationType == "CrytographicType") {
00233                 intf->SetAuthenticationType(OSPF::CrytographicType);
00234             } else {
00235                 intf->SetAuthenticationType(OSPF::NullType);
00236             }
00237         }
00238         if (nodeName == "AuthenticationKey") {
00239             std::string key = (*ifElemIt)->getNodeValue();
00240             OSPF::AuthenticationKeyType keyValue;
00241             memset(keyValue.bytes, 0, 8 * sizeof(char));
00242             int keyLength = key.length();
00243             if ((keyLength > 4) && (keyLength <= 18) && (keyLength % 2 == 0) && (key[0] == '0') && (key[1] == 'x')) {
00244                 for (int i = keyLength; (i > 2); i -= 2) {
00245                     keyValue.bytes[(i - 2) / 2] = HexPairToByte(key[i - 1], key[i]);
00246                 }
00247             }
00248             intf->SetAuthenticationKey(keyValue);
00249         }
00250         if (nodeName == "PollInterval") {
00251             intf->SetPollInterval(atoi((*ifElemIt)->getNodeValue()));
00252         }
00253         if ((interfaceType == "NBMAInterface") && (nodeName == "NBMANeighborList")) {
00254             cXMLElementList neighborList = (*ifElemIt)->getChildren();
00255             for (cXMLElementList::iterator neighborIt = neighborList.begin(); neighborIt != neighborList.end(); neighborIt++) {
00256                 std::string neighborNodeName = (*neighborIt)->getTagName();
00257                 if (neighborNodeName == "NBMANeighbor") {
00258                     OSPF::Neighbor* neighbor = new OSPF::Neighbor;
00259                     neighbor->SetAddress(IPv4AddressFromAddressString((*neighborIt)->getChildrenByTagName("NetworkInterfaceAddress")[0]->getNodeValue()));
00260                     neighbor->SetPriority(atoi((*neighborIt)->getChildrenByTagName("NeighborPriority")[0]->getNodeValue()));
00261                     intf->AddNeighbor(neighbor);
00262                 }
00263             }
00264         }
00265         if ((interfaceType == "PointToMultiPointInterface") && (nodeName == "PointToMultiPointNeighborList")) {
00266             cXMLElementList neighborList = (*ifElemIt)->getChildren();
00267             for (cXMLElementList::iterator neighborIt = neighborList.begin(); neighborIt != neighborList.end(); neighborIt++) {
00268                 std::string neighborNodeName = (*neighborIt)->getTagName();
00269                 if (neighborNodeName == "PointToMultiPointNeighbor") {
00270                     OSPF::Neighbor* neighbor = new OSPF::Neighbor;
00271                     neighbor->SetAddress(IPv4AddressFromAddressString((*neighborIt)->getNodeValue()));
00272                     intf->AddNeighbor(neighbor);
00273                 }
00274             }
00275         }
00276 
00277     }
00278     // add the interface to it's Area
00279     OSPF::Area* area = ospfRouter->GetArea(areaID);
00280     if (area != NULL) {
00281         area->AddInterface(intf);
00282         intf->ProcessEvent(OSPF::Interface::InterfaceUp); // notification should come from the blackboard...
00283     } else {
00284         delete intf;
00285         error("Loading %s ifIndex[%d] in Area %d aborted", interfaceType.c_str(), ifIndex, areaID);
00286     }
00287 }
00288 
00289 
00294 void OSPFRouting::LoadExternalRoute(const cXMLElement& externalRouteConfig)
00295 {
00296     std::string               ifName  = externalRouteConfig.getAttribute("ifName");
00297     int                       ifIndex = ResolveInterfaceName(ifName);
00298     OSPFASExternalLSAContents asExternalRoute;
00299     OSPF::RoutingTableEntry   externalRoutingEntry; // only used here to keep the path cost calculation in one place
00300     OSPF::IPv4AddressRange    networkAddress;
00301 
00302     EV << "        loading ExternalInterface " << ifName << " ifIndex[" << ifIndex << "]\n";
00303 
00304     cXMLElementList ifDetails = externalRouteConfig.getChildren();
00305     for (cXMLElementList::iterator exElemIt = ifDetails.begin(); exElemIt != ifDetails.end(); exElemIt++) {
00306         std::string nodeName = (*exElemIt)->getTagName();
00307         if (nodeName == "AdvertisedExternalNetwork") {
00308             networkAddress.address = IPv4AddressFromAddressString((*exElemIt)->getChildrenByTagName("Address")[0]->getNodeValue());
00309             networkAddress.mask    = IPv4AddressFromAddressString((*exElemIt)->getChildrenByTagName("Mask")[0]->getNodeValue());
00310             asExternalRoute.setNetworkMask(ULongFromIPv4Address(networkAddress.mask));
00311         }
00312         if (nodeName == "ExternalInterfaceOutputParameters") {
00313             std::string metricType = (*exElemIt)->getChildrenByTagName("ExternalInterfaceOutputType")[0]->getNodeValue();
00314             int         routeCost  = atoi((*exElemIt)->getChildrenByTagName("ExternalInterfaceOutputCost")[0]->getNodeValue());
00315 
00316             asExternalRoute.setRouteCost(routeCost);
00317             if (metricType == "Type2") {
00318                 asExternalRoute.setE_ExternalMetricType(true);
00319                 externalRoutingEntry.SetType2Cost(routeCost);
00320                 externalRoutingEntry.SetPathType(OSPF::RoutingTableEntry::Type2External);
00321             } else {
00322                 asExternalRoute.setE_ExternalMetricType(false);
00323                 externalRoutingEntry.SetCost(routeCost);
00324                 externalRoutingEntry.SetPathType(OSPF::RoutingTableEntry::Type1External);
00325             }
00326         }
00327         if (nodeName == "ForwardingAddress") {
00328             asExternalRoute.setForwardingAddress(ULongFromAddressString((*exElemIt)->getNodeValue()));
00329         }
00330         if (nodeName == "ExternalRouteTag") {
00331             std::string externalRouteTag = (*exElemIt)->getNodeValue();
00332             char        externalRouteTagValue[4];
00333 
00334             memset(externalRouteTagValue, 0, 4 * sizeof(char));
00335             int externalRouteTagLength = externalRouteTag.length();
00336             if ((externalRouteTagLength > 4) && (externalRouteTagLength <= 10) && (externalRouteTagLength % 2 == 0) && (externalRouteTag[0] == '0') && (externalRouteTag[1] == 'x')) {
00337                 for (int i = externalRouteTagLength; (i > 2); i -= 2) {
00338                     externalRouteTagValue[(i - 2) / 2] = HexPairToByte(externalRouteTag[i - 1], externalRouteTag[i]);
00339                 }
00340             }
00341             asExternalRoute.setExternalRouteTag((externalRouteTagValue[0] << 24) + (externalRouteTagValue[1] << 16) + (externalRouteTagValue[2] << 8) + externalRouteTagValue[3]);
00342         }
00343     }
00344     // add the external route to the OSPF datastructure
00345     ospfRouter->UpdateExternalRoute(networkAddress.address, asExternalRoute, ifIndex);
00346 }
00347 
00348 
00353 void OSPFRouting::LoadHostRoute(const cXMLElement& hostRouteConfig)
00354 {
00355     OSPF::HostRouteParameters hostParameters;
00356     OSPF::AreaID              hostArea;
00357 
00358     std::string ifName = hostRouteConfig.getAttribute("ifName");
00359     hostParameters.ifIndex = ResolveInterfaceName(ifName);
00360 
00361     EV << "        loading HostInterface " << ifName << " ifIndex[" << static_cast<short> (hostParameters.ifIndex) << "]\n";
00362 
00363     cXMLElementList ifDetails = hostRouteConfig.getChildren();
00364     for (cXMLElementList::iterator hostElemIt = ifDetails.begin(); hostElemIt != ifDetails.end(); hostElemIt++) {
00365         std::string nodeName = (*hostElemIt)->getTagName();
00366         if (nodeName == "AreaID") {
00367             hostArea = ULongFromAddressString((*hostElemIt)->getNodeValue());
00368         }
00369         if (nodeName == "AttachedHost") {
00370             hostParameters.address = IPv4AddressFromAddressString((*hostElemIt)->getNodeValue());
00371         }
00372         if (nodeName == "LinkCost") {
00373             hostParameters.linkCost = atoi((*hostElemIt)->getNodeValue());
00374         }
00375     }
00376     // add the host route to the OSPF datastructure.
00377     OSPF::Area* area = ospfRouter->GetArea(hostArea);
00378     if (area != NULL) {
00379         area->AddHostRoute(hostParameters);
00380 
00381     } else {
00382         error("Loading HostInterface ifIndex[%d] in Area %d aborted", hostParameters.ifIndex, hostArea);
00383     }
00384 }
00385 
00386 
00391 void OSPFRouting::LoadVirtualLink(const cXMLElement& virtualLinkConfig)
00392 {
00393     OSPF::Interface* intf     = new OSPF::Interface;
00394     std::string      endPoint = virtualLinkConfig.getAttribute("endPointRouterID");
00395     OSPF::Neighbor*  neighbor = new OSPF::Neighbor;
00396 
00397     EV << "        loading VirtualLink to " << endPoint << "\n";
00398 
00399     intf->SetType(OSPF::Interface::Virtual);
00400     neighbor->SetNeighborID(ULongFromAddressString(endPoint.c_str()));
00401     intf->AddNeighbor(neighbor);
00402 
00403     cXMLElementList ifDetails = virtualLinkConfig.getChildren();
00404     for (cXMLElementList::iterator ifElemIt = ifDetails.begin(); ifElemIt != ifDetails.end(); ifElemIt++) {
00405         std::string nodeName = (*ifElemIt)->getTagName();
00406         if (nodeName == "TransitAreaID") {
00407             intf->SetTransitAreaID(ULongFromAddressString((*ifElemIt)->getNodeValue()));
00408         }
00409         if (nodeName == "RetransmissionInterval") {
00410             intf->SetRetransmissionInterval(atoi((*ifElemIt)->getNodeValue()));
00411         }
00412         if (nodeName == "InterfaceTransmissionDelay") {
00413             intf->SetTransmissionDelay(atoi((*ifElemIt)->getNodeValue()));
00414         }
00415         if (nodeName == "HelloInterval") {
00416             intf->SetHelloInterval(atoi((*ifElemIt)->getNodeValue()));
00417         }
00418         if (nodeName == "RouterDeadInterval") {
00419             intf->SetRouterDeadInterval(atoi((*ifElemIt)->getNodeValue()));
00420         }
00421         if (nodeName == "AuthenticationType") {
00422             std::string authenticationType = (*ifElemIt)->getNodeValue();
00423             if (authenticationType == "SimplePasswordType") {
00424                 intf->SetAuthenticationType(OSPF::SimplePasswordType);
00425             } else if (authenticationType == "CrytographicType") {
00426                 intf->SetAuthenticationType(OSPF::CrytographicType);
00427             } else {
00428                 intf->SetAuthenticationType(OSPF::NullType);
00429             }
00430         }
00431         if (nodeName == "AuthenticationKey") {
00432             std::string key = (*ifElemIt)->getNodeValue();
00433             OSPF::AuthenticationKeyType keyValue;
00434             memset(keyValue.bytes, 0, 8 * sizeof(char));
00435             int keyLength = key.length();
00436             if ((keyLength > 4) && (keyLength <= 18) && (keyLength % 2 == 0) && (key[0] == '0') && (key[1] == 'x')) {
00437                 for (int i = keyLength; (i > 2); i -= 2) {
00438                     keyValue.bytes[(i - 2) / 2] = HexPairToByte(key[i - 1], key[i]);
00439                 }
00440             }
00441             intf->SetAuthenticationKey(keyValue);
00442         }
00443     }
00444 
00445     // add the virtual link to the OSPF datastructure.
00446     OSPF::Area* transitArea = ospfRouter->GetArea(intf->GetAreaID());
00447     OSPF::Area* backbone    = ospfRouter->GetArea(OSPF::BackboneAreaID);
00448 
00449     if ((backbone != NULL) && (transitArea != NULL) && (transitArea->GetExternalRoutingCapability())) {
00450         backbone->AddInterface(intf);
00451     } else {
00452         delete intf;
00453         error("Loading VirtualLink to %s through Area %d aborted", endPoint.c_str(), intf->GetAreaID());
00454     }
00455 }
00456 
00457 
00464 bool OSPFRouting::LoadConfigFromXML(const char * filename)
00465 {
00466     cXMLElement* asConfig = ev.getXMLDocument(filename);
00467     if (asConfig == NULL) {
00468         error("Cannot read AS configuration from file: %s", filename);
00469     }
00470 
00471     // load information on this router
00472     std::string routerXPath("Router[@id='");
00473     IPAddress routerId(ospfRouter->GetRouterID());
00474     routerXPath += routerId.str();
00475     routerXPath += "']";
00476 
00477     cXMLElement* routerNode = asConfig->getElementByPath(routerXPath.c_str());
00478     if (routerNode == NULL) {
00479         error("No configuration for Router ID: %s", routerId.str().c_str());
00480     }
00481     else {
00482         EV << "OSPFRouting: Loading info for Router id = " << routerId.str() << "\n";
00483     }
00484 
00485     if (routerNode->getChildrenByTagName("RFC1583Compatible").size() > 0) {
00486         ospfRouter->SetRFC1583Compatibility(true);
00487     }
00488 
00489     std::map<std::string, int> areaList;
00490     GetAreaListFromXML(*routerNode, areaList);
00491 
00492     // load area information
00493     for (std::map<std::string, int>::iterator areaIt = areaList.begin(); areaIt != areaList.end(); areaIt++) {
00494         LoadAreaFromXML(*asConfig, areaIt->first);
00495     }
00496     // if the router is an area border router then it MUST be part of the backbone(area 0)
00497     if ((areaList.size() > 1) && (areaList.find("0.0.0.0") == areaList.end())) {
00498         LoadAreaFromXML(*asConfig, "0.0.0.0");
00499     }
00500 
00501     // load interface information
00502     cXMLElementList routerConfig = routerNode->getChildren();
00503     for (cXMLElementList::iterator routerConfigIt = routerConfig.begin(); routerConfigIt != routerConfig.end(); routerConfigIt++) {
00504         std::string nodeName = (*routerConfigIt)->getTagName();
00505         if ((nodeName == "PointToPointInterface") ||
00506             (nodeName == "BroadcastInterface") ||
00507             (nodeName == "NBMAInterface") ||
00508             (nodeName == "PointToMultiPointInterface"))
00509         {
00510             LoadInterfaceParameters(*(*routerConfigIt));
00511         }
00512         if (nodeName == "ExternalInterface") {
00513             LoadExternalRoute(*(*routerConfigIt));
00514         }
00515         if (nodeName == "HostInterface") {
00516             LoadHostRoute(*(*routerConfigIt));
00517         }
00518         if (nodeName == "VirtualLink") {
00519             LoadVirtualLink(*(*routerConfigIt));
00520         }
00521     }
00522     return true;
00523 }