Multicast Routing Modelling In OMNeT++
PimSplitter.cc
Go to the documentation of this file.
00001 
00011 #include "PimSplitter.h"
00012 
00013 using namespace std;
00014 
00015 Define_Module(PimSplitter);
00016 
00017 
00027 PIMHello* PimSplitter::createHelloPkt(int iftID)
00028 {
00029         PIMHello *msg = new PIMHello();
00030         msg->setName("PIMHello");
00031 
00032         IPControlInfo *ctrl = new IPControlInfo();
00033         IPAddress ga1("224.0.0.13");
00034         ctrl->setDestAddr(ga1);
00035         //ctrl->setProtocol(IP_PROT_PIM);
00036         ctrl->setProtocol(103);
00037         ctrl->setTimeToLive(1);
00038         ctrl->setInterfaceId(iftID);
00039         msg->setControlInfo(ctrl);
00040 
00041         return msg;
00042 }
00043 
00053 void PimSplitter::sendHelloPkt()
00054 {
00055         EV << "PIM::sendHelloPkt" << endl;
00056         int intID;
00057         PIMHello* msg;
00058 
00059         // send to all PIM interfaces
00060         for (int i = 0; i < pimIft->getNumInterface(); i++)
00061         {
00062                 intID = pimIft->getInterface(i)->getInterfaceID();
00063                 msg = createHelloPkt(intID);
00064                 send(msg, "transportOut");
00065         }
00066 
00067         // start Hello timer
00068         PIMTimer *timer = new PIMTimer("Hello");
00069         timer->setTimerKind(HelloTimer);
00070         scheduleAt(simTime() + HT, timer);
00071 }
00072 
00087 void PimSplitter::processHelloPkt(PIMPacket *msg)
00088 {
00089         EV << "PIM::processHelloPkt" << endl;
00090 
00091         IPControlInfo *ctrl = dynamic_cast<IPControlInfo *>(msg->getControlInfo());
00092         PimNeighbor newEntry;
00093         PIMnlt *nlt;
00094 
00095         // get information about neighbor from Hello packet
00096         newEntry.setAddr(ctrl->getSrcAddr());
00097         newEntry.setInterfaceID(ctrl->getInterfaceId());
00098         newEntry.setInterfacePtr(ift->getInterfaceById(ctrl->getInterfaceId()));
00099         newEntry.setVersion(msg->getVersion());
00100 
00101 
00102         // new neighbor (it is not in PIM neighbor table)
00103         // insert new neighbor to table
00104         // set Neighbor Livness Timer
00105         if (!pimNbt->isInTable(newEntry))
00106         {
00107                 nlt = new PIMnlt("NeighborLivenessTimer");
00108                 nlt->setTimerKind(NeighborLivenessTimer);
00109                 nlt->setNtId(pimNbt->getIdCounter());
00110                 scheduleAt(simTime() + 3.5*HT, nlt);
00111 
00112                 newEntry.setNlt(nlt);
00113                 pimNbt->addNeighbor(newEntry);
00114                 EV << "PimSplitter::New Entry was added: addr = " << newEntry.getAddr() << ", iftID = " << newEntry.getInterfaceID() << ", ver = " << newEntry.getVersion() << endl;
00115         }
00116         // neighbor is already in PIM neighbor table
00117         // refresh Neighbor Livness Timer
00118         else
00119         {
00120                 nlt = pimNbt->findNeighbor(ctrl->getInterfaceId(), ctrl->getSrcAddr())->getNlt();
00121                 cancelEvent(nlt);
00122                 scheduleAt(simTime() + 3.5*HT, nlt);
00123         }
00124 
00125         delete msg;
00126 }
00127 
00138 void PimSplitter::processNLTimer(PIMTimer *timer)
00139 {
00140         EV << "PIM::processNLTimer"<< endl;
00141         PIMnlt *nlt = check_and_cast <PIMnlt *> (timer);
00142         int id = nlt->getNtId();
00143         IPAddress neighbor;
00144 
00145         // if neighbor exists store its IP address
00146         if (pimNbt->getNeighborsByID(id) != NULL)
00147                 neighbor = pimNbt->getNeighborsByID(id)->getAddr();
00148 
00149         // Record in PIM Neighbor Table was found, can be deleted.
00150         if (pimNbt->deleteNeighbor(id))
00151                 EV << "PIM::processNLTimer: Neighbor " << neighbor << "was removed from PIM neighbor table." << endl;
00152 
00153         delete nlt;
00154 }
00155 
00168 void PimSplitter::processPIMPkt(PIMPacket *pkt)
00169 {
00170         EV << "PIM::processPIMPkt" << endl;
00171 
00172         IPControlInfo *ctrl = dynamic_cast<IPControlInfo *>(pkt->getControlInfo());
00173         int intID = ctrl->getInterfaceId();
00174         int mode = 0;
00175 
00176         // find information about interface where packet came from
00177         PimInterface *pimInt = pimIft->getInterfaceByIntID(intID);
00178         if (pimInt != NULL)
00179                 mode = pimInt->getMode();
00180 
00181         // according to interface PIM mode send packet to appropriate PIM module
00182         switch(mode)
00183         {
00184                 case Dense:
00185                         send(pkt, "pimDMOut");
00186                         break;
00187                 case Sparse:
00188                         send(pkt, "pimSMOut");
00189                         break;
00190                 default:
00191                         EV << "PIM::processPIMPkt: PIM is not enabled on interface number: "<< intID << endl;
00192                         delete pkt;
00193         }
00194 }
00195 
00210 void PimSplitter::handleMessage(cMessage *msg)
00211 {
00212         EV << "PimSplitter::handleMessage" << endl;
00213 
00214         // self message (timer)
00215    if (msg->isSelfMessage())
00216    {
00217            PIMTimer *timer = check_and_cast <PIMTimer *> (msg);
00218            if (timer->getTimerKind() == HelloTimer)
00219            {
00220                    EV << "PIM::HelloTimer" << endl;
00221                    sendHelloPkt();
00222                    delete timer;
00223            }
00224            else if (timer->getTimerKind() == NeighborLivenessTimer)
00225            {
00226                    EV << "PIM::NeighborLivnessTimer" << endl;
00227                    processNLTimer(timer);
00228            }
00229    }
00230 
00231    // PIM packet from network layer
00232    else if (dynamic_cast<PIMPacket *>(msg) && (strcmp(msg->getArrivalGate()->getName(), "transportIn") == 0))
00233    {
00234            PIMPacket *pkt = check_and_cast<PIMPacket *>(msg);
00235 
00236            if (pkt->getType() == Hello)
00237                    processHelloPkt(pkt);
00238            else
00239                    processPIMPkt(pkt);
00240    }
00241 
00242    // PIM packet from PIM mode, send to network layer
00243    else if (dynamic_cast<PIMPacket *>(msg))
00244            send(msg, "transportOut");
00245 
00246    else
00247            EV << "PIM:ERROR - bad type of message" << endl;
00248 }
00249 
00261 void PimSplitter::initialize(int stage)
00262 {
00263         // in stage 2 interfaces are registered
00264         // in stage 3 table pimInterfaces is built
00265         if (stage == 4)
00266         {
00267                 EV << "PimSplitter::initialize" << endl;
00268                 hostname = par("hostname");
00269 
00270                 // Pointer to routing tables, interface tables, notification board
00271                 rt = RoutingTableAccess().get();
00272                 mrt = MulticastRoutingTableAccess().get();
00273                 ift = AnsaInterfaceTableAccess().get();
00274                 nb = NotificationBoardAccess().get();
00275                 pimIft = PimInterfaceTableAccess().get();
00276                 pimNbt = PimNeighborTableAccess().get();
00277 
00278                 // subscribtion of notifications (future use)
00279                 nb->subscribe(this, NF_IPv4_NEW_MULTICAST);
00280                 nb->subscribe(this, NF_INTERFACE_IPv4CONFIG_CHANGED);
00281 
00282                 // is PIM enabled?
00283                 if (pimIft->getNumInterface() == 0)
00284                         return;
00285                 else
00286                         EV << "PIM is enabled on device " << hostname << endl;
00287 
00288                 // send Hello packets to PIM neighbors (224.0.0.13)
00289                 PIMTimer *timer = new PIMTimer("Hello");
00290                 timer->setTimerKind(HelloTimer);
00291                 scheduleAt(simTime() + uniform(0,5), timer);
00292         }
00293 }
00294 
00295 
00306 void PimSplitter::receiveChangeNotification(int category, const cPolymorphic *details)
00307 {
00308         // ignore notifications during initialize
00309         if (simulation.getContextType()==CTX_INITIALIZE)
00310                 return;
00311 
00312         // PIM needs details
00313         if (details == NULL)
00314                 return;
00315 
00316         Enter_Method_Silent();
00317         printNotificationBanner(category, details);
00318 
00319         // according to category of event...
00320         switch (category)
00321         {
00322                 // new multicast data appears in router
00323                 case NF_IPv4_NEW_MULTICAST:
00324                         EV <<  "PimSplitter::receiveChangeNotification - NEW MULTICAST" << endl;
00325                         IPControlInfo *ctrl;
00326                         ctrl = (IPControlInfo *)(details);
00327                         newMulticast(ctrl->getDestAddr(), ctrl->getSrcAddr());
00328                         break;
00329 
00330                 // configuration of interface changed, it means some change from IGMP
00331                 case NF_INTERFACE_IPv4CONFIG_CHANGED:
00332                         EV << "PimSplitter::receiveChangeNotification - IGMP change" << endl;
00333                         InterfaceEntry * interface = (InterfaceEntry *)(details);
00334                         igmpChange(interface);
00335                         break;
00336         }
00337 }
00338 
00348 void PimSplitter::igmpChange(InterfaceEntry *interface)
00349 {
00350         EV << "PimSplitter::igmpChange" << endl;
00351         int intId = interface->getInterfaceId();
00352         PimInterface * pimInt = pimIft->getInterfaceByIntID(intId);
00353 
00354         // save old and new set of multicast IP address assigned to interface
00355         vector<IPAddress> multicastAddrsOld = pimInt->getIntMulticastAddresses();
00356         vector<IPAddress> multicastAddrsNew = pimInt->deleteLocalIPs(interface->ipv4Data()->getMulticastGroups());
00357 
00358         // vectors of new and removed multicast addresses
00359         vector<IPAddress> add;
00360         vector<IPAddress> remove;
00361 
00362         // which address was removed from interface
00363         for (unsigned int i = 0; i < multicastAddrsOld.size(); i++)
00364         {
00365                 unsigned int j;
00366                 for (j = 0; j < multicastAddrsNew.size(); j++)
00367                 {
00368                         if (multicastAddrsOld[i] == multicastAddrsNew[j])
00369                                 break;
00370                 }
00371                 if (j == multicastAddrsNew.size())
00372                 {
00373                         EV << "Multicast address " << multicastAddrsOld[i] << " was removed from the interface " << intId << endl;
00374                         remove.push_back(multicastAddrsOld[i]);
00375                 }
00376         }
00377 
00378         // which address was added to interface
00379         for (unsigned int i = 0; i < multicastAddrsNew.size(); i++)
00380         {
00381                 unsigned int j;
00382                 for (j = 0; j < multicastAddrsOld.size(); j++)
00383                 {
00384                         if (multicastAddrsNew[i] == multicastAddrsOld[j])
00385                                 break;
00386                 }
00387                 if (j == multicastAddrsOld.size())
00388                 {
00389                         EV << "Multicast address " << multicastAddrsNew[i] << " was added to the interface " << intId <<endl;
00390                         add.push_back(multicastAddrsNew[i]);
00391                 }
00392         }
00393 
00394         // notification about removed multicast address to PIM modules
00395         addRemoveAddr *addr = new addRemoveAddr();
00396         if (remove.size() > 0)
00397         {
00398                 // remove new address
00399                 for(unsigned int i = 0; i < remove.size(); i++)
00400                         pimInt->removeIntMulticastAddress(remove[i]);
00401 
00402                 // send notification
00403                 addr->setAddr(remove);
00404                 addr->setInt(pimInt);
00405                 nb->fireChangeNotification(NF_IPv4_NEW_IGMP_REMOVED, addr);
00406         }
00407 
00408         // notification about new multicast address to PIM modules
00409         if (add.size() > 0)
00410         {
00411                 // add new address
00412                 for(unsigned int i = 0; i < add.size(); i++)
00413                         pimInt->addIntMulticastAddress(add[i]);
00414 
00415                 // send notification
00416                 addr->setAddr(add);
00417                 addr->setInt(pimInt);
00418                 nb->fireChangeNotification(NF_IPv4_NEW_IGMP_ADDED, addr);
00419         }
00420 }
00421 
00433 void PimSplitter::newMulticast(IPAddress destAddr, IPAddress srcAddr)
00434 {
00435         EV << "PimSplitter::newMulticast - group: " << destAddr << ", source: " << srcAddr << endl;
00436 
00437         // find RPF interface for new multicast stream
00438         InterfaceEntry *inInt = rt->getInterfaceForDestAddr(srcAddr);
00439         if (inInt == NULL)
00440         {
00441                 EV << "ERROR: PimSplitter::newMulticast(): cannot find RPF interface, routing information is missing.";
00442                 return;
00443         }
00444         int rpfId = inInt->getInterfaceId();
00445         PimInterface *pimInt = pimIft->getInterfaceByIntID(rpfId);
00446 
00447         // if it is interface configured with PIM, create new route
00448         if (pimInt != NULL)
00449         {
00450                 // create new multicast route
00451                 MulticastIPRoute *newRoute = new MulticastIPRoute();
00452                 newRoute->setGroup(destAddr);
00453                 newRoute->setSource(srcAddr);
00454 
00455                 // Directly connected routes to source does not have next hop
00456                 // RPF neighbor is source of packet
00457                 IPAddress rpf;
00458                 const IPRoute *routeToSrc = rt->findBestMatchingRoute(srcAddr);
00459                 if (routeToSrc->getSource() == IPRoute::IFACENETMASK)
00460                 {
00461                         newRoute->addFlag(A);
00462                         rpf = srcAddr;
00463                 }
00464                 // Not directly connected, next hop address is saved in routing table
00465                 else
00466                         rpf = rt->getGatewayForDestAddr(srcAddr);
00467 
00468                 newRoute->setInInt(inInt, inInt->getInterfaceId(), rpf);
00469 
00470                 // notification for PIM module about new multicast route
00471                 if (pimInt->getMode() == Dense)
00472                         nb->fireChangeNotification(NF_IPv4_NEW_MULTICAST_DENSE, newRoute);
00473         }
00474 }
00475 
00500 bool PimSplitter::LoadConfigFromXML(const char *filename)
00501 {
00502         // file loading
00503         cXMLElement* asConfig = ev.getXMLDocument(filename);
00504         if (asConfig == NULL)
00505            return false;
00506 
00507         // first element <Router id="192.168.10.7">
00508         std::string routerXPath("Router[@id='");
00509         IPAddress routerId = rt->getRouterId();
00510         routerXPath += routerId.str();
00511         routerXPath += "']";
00512 
00513         cXMLElement* routerNode = asConfig->getElementByPath(routerXPath.c_str());
00514         if (routerNode == NULL)
00515         {
00516                 error("No configuration for Router ID: %s", routerId.str().c_str());
00517            return false;
00518         }
00519 
00520         // Routing element
00521         cXMLElement* routingNode = routerNode->getElementByPath("Routing");
00522         if (routingNode == NULL)
00523                  return false;
00524 
00525         // Multicast element
00526         cXMLElement* multicastNode = routingNode->getElementByPath("Multicast");
00527         if (multicastNode == NULL)
00528            return false;
00529 
00530 
00531         // Multicast has to be enabled
00532         const char* enableAtt = multicastNode->getAttribute("enable");
00533         if (strcmp(enableAtt, "1"))
00534                 return false;
00535 
00536 
00537         // Where is PIM protocol enabled?
00538         // Interfaces element
00539         cXMLElement* iftNode = routerNode->getElementByPath("Interfaces");
00540         if (iftNode == NULL)
00541                  return false;
00542 
00543    // list of interfaces, where PIM is enabled
00544    cXMLElementList childrenNodes = iftNode->getChildrenByTagName("Interface");
00545    //EV << "PimSplitter::Interface" << endl;
00546    if (childrenNodes.size() > 0)
00547    {
00548            //EV << "PimSplitter::Interface size: " << childrenNodes.size() << endl;
00549           for (cXMLElementList::iterator node = childrenNodes.begin(); node != childrenNodes.end(); node++)
00550           {
00551                   cXMLElement* pimNode = (*node)->getElementByPath("Pim");
00552                   if (pimNode == NULL)
00553                           continue;
00554                   //EV << "PimSplitter::PIM interface" << endl;
00555                   // get ID of PIM interface
00556                   InterfaceEntry *interface = ift->getInterfaceByName((*node)->getAttribute("name"));
00557 
00558                   // create new PIM interface
00559                   PimInterface newentry;
00560                   newentry.setInterfaceID(interface->getInterfaceId());
00561                   newentry.setInterfacePtr(interface);
00562 
00563                   // register pim multicast address 224.0.0.13 on pim interface
00564                   vector<IPAddress> intMulticastAddresses = interface->ipv4Data()->getMulticastGroups();
00565                   intMulticastAddresses.push_back("224.0.0.13");
00566                   interface->ipv4Data()->setMulticastGroups(intMulticastAddresses);
00567 
00568                   // get PIM mode for interface
00569                   cXMLElement* pimMode = pimNode->getElementByPath("Mode");
00570                   if (pimMode == NULL)
00571                           return false;
00572 
00573                   const char *mode = pimMode->getNodeValue();
00574                   //EV << "PimSplitter::PIM interface mode = "<< mode << endl;
00575                   if (!strcmp(mode, "dense-mode"))
00576                           newentry.setMode(Dense);
00577                   else if (!strcmp(mode, "sparse-mode"))
00578                           newentry.setMode(Sparse);
00579                   else
00580                           return false;
00581                   pimIft->addInterface(newentry);
00582           }
00583    }
00584    else
00585           return false;
00586    return true;
00587 }