Multicast Routing Modelling In OMNeT++
Protected Member Functions | Private Member Functions | Private Attributes
PimSplitter Class Reference

Class implements PIM Splitter, which splits PIM messages to correct PIM module. More...

#include <PimSplitter.h>

List of all members.

Protected Member Functions

virtual int numInitStages () const
virtual void handleMessage (cMessage *msg)
virtual void initialize (int stage)

Private Member Functions

void processPIMPkt (PIMPacket *pkt)
void processNLTimer (PIMTimer *timer)
PIMHello * createHelloPkt (int iftID)
void sendHelloPkt ()
void processHelloPkt (PIMPacket *pkt)
void receiveChangeNotification (int category, const cPolymorphic *details)
virtual void newMulticast (IPAddress destAddr, IPAddress srcAddr)
void igmpChange (InterfaceEntry *interface)
bool LoadConfigFromXML (const char *filename)

Private Attributes

IRoutingTable * rt
MulticastRoutingTablemrt
IInterfaceTable * ift
NotificationBoard * nb
PimInterfaceTablepimIft
PimNeighborTablepimNbt
const char * hostname

Detailed Description

Class implements PIM Splitter, which splits PIM messages to correct PIM module.

This module is needed because we cannot distinguish PIM mode on layer 3, all of them have same protocol number (103). PIM Splitter can resend PIM message to correct PIM module according to configuration saved in PimInterfaceTable. Splitter also manages PimNeighborTable.

Definition at line 41 of file PimSplitter.h.


Member Function Documentation

void PimSplitter::processPIMPkt ( PIMPacket *  pkt) [private]

PROCESS PIM PACKET

The method processes new coming PIM packet. It has to find out where packet has to be sent to. It looks to interface from which packet is coming. According to interface ID, method findes record in PIM Interface Table and gets info about PIM mode. According to mode it send to appropriate PIM model.

Parameters:
pktNew coming PIM packet.
See also:
PimInterface

Definition at line 168 of file PimSplitter.cc.

{
        EV << "PIM::processPIMPkt" << endl;

        IPControlInfo *ctrl = dynamic_cast<IPControlInfo *>(pkt->getControlInfo());
        int intID = ctrl->getInterfaceId();
        int mode = 0;

        // find information about interface where packet came from
        PimInterface *pimInt = pimIft->getInterfaceByIntID(intID);
        if (pimInt != NULL)
                mode = pimInt->getMode();

        // according to interface PIM mode send packet to appropriate PIM module
        switch(mode)
        {
                case Dense:
                        send(pkt, "pimDMOut");
                        break;
                case Sparse:
                        send(pkt, "pimSMOut");
                        break;
                default:
                        EV << "PIM::processPIMPkt: PIM is not enabled on interface number: "<< intID << endl;
                        delete pkt;
        }
}
void PimSplitter::processNLTimer ( PIMTimer *  timer) [private]

PROCESS NEIGHBOR LIVENESS TIMER

The method process Neighbor Liveness Timer. After its expiration neighbor is removed from PimNeighborTable.

Parameters:
timerPIM Neighbor Liveness Timer.
See also:
PimNeighbor
PIMnlt()

Definition at line 138 of file PimSplitter.cc.

{
        EV << "PIM::processNLTimer"<< endl;
        PIMnlt *nlt = check_and_cast <PIMnlt *> (timer);
        int id = nlt->getNtId();
        IPAddress neighbor;

        // if neighbor exists store its IP address
        if (pimNbt->getNeighborsByID(id) != NULL)
                neighbor = pimNbt->getNeighborsByID(id)->getAddr();

        // Record in PIM Neighbor Table was found, can be deleted.
        if (pimNbt->deleteNeighbor(id))
                EV << "PIM::processNLTimer: Neighbor " << neighbor << "was removed from PIM neighbor table." << endl;

        delete nlt;
}
PIMHello * PimSplitter::createHelloPkt ( int  iftID) [private]

CREATE HELLO PACKET

The method creates new PIM Hello Packet and sets all necessary info.

Parameters:
iftIDID of interface to which the packet has to be sent
Returns:
Return PIMHello message, which is ready to be sent.
See also:
PIMHello

Definition at line 27 of file PimSplitter.cc.

{
        PIMHello *msg = new PIMHello();
        msg->setName("PIMHello");

        IPControlInfo *ctrl = new IPControlInfo();
        IPAddress ga1("224.0.0.13");
        ctrl->setDestAddr(ga1);
        //ctrl->setProtocol(IP_PROT_PIM);
        ctrl->setProtocol(103);
        ctrl->setTimeToLive(1);
        ctrl->setInterfaceId(iftID);
        msg->setControlInfo(ctrl);

        return msg;
}
void PimSplitter::sendHelloPkt ( ) [private]

SEND HELLO PACKET

The method goes through all PIM interfaces and sends Hello packet to each of them. It also schedule next sending of Hello packets (sets Hello Timer).

See also:
createHelloPkt()

Definition at line 53 of file PimSplitter.cc.

{
        EV << "PIM::sendHelloPkt" << endl;
        int intID;
        PIMHello* msg;

        // send to all PIM interfaces
        for (int i = 0; i < pimIft->getNumInterface(); i++)
        {
                intID = pimIft->getInterface(i)->getInterfaceID();
                msg = createHelloPkt(intID);
                send(msg, "transportOut");
        }

        // start Hello timer
        PIMTimer *timer = new PIMTimer("Hello");
        timer->setTimerKind(HelloTimer);
        scheduleAt(simTime() + HT, timer);
}
void PimSplitter::processHelloPkt ( PIMPacket *  msg) [private]

PROCESS HELLO PACKET

The method processes new coming Hello packet from any of its neighbor. It reads info about neighbor from the packet and tries to find neighbor in PimNeighborTable. If neighbor is not in the table, method adds him and sets Neighbor Liveness Timer for the record. If neighbor is already in PimNeighborTable it refreshes Neighbor Liveness Timer

Parameters:
msgPointer to incoming Hello packet
See also:
PimNeighbor
PIMnlt

Definition at line 87 of file PimSplitter.cc.

{
        EV << "PIM::processHelloPkt" << endl;

        IPControlInfo *ctrl = dynamic_cast<IPControlInfo *>(msg->getControlInfo());
        PimNeighbor newEntry;
        PIMnlt *nlt;

        // get information about neighbor from Hello packet
        newEntry.setAddr(ctrl->getSrcAddr());
        newEntry.setInterfaceID(ctrl->getInterfaceId());
        newEntry.setInterfacePtr(ift->getInterfaceById(ctrl->getInterfaceId()));
        newEntry.setVersion(msg->getVersion());


        // new neighbor (it is not in PIM neighbor table)
        // insert new neighbor to table
        // set Neighbor Livness Timer
        if (!pimNbt->isInTable(newEntry))
        {
                nlt = new PIMnlt("NeighborLivenessTimer");
                nlt->setTimerKind(NeighborLivenessTimer);
                nlt->setNtId(pimNbt->getIdCounter());
                scheduleAt(simTime() + 3.5*HT, nlt);

                newEntry.setNlt(nlt);
                pimNbt->addNeighbor(newEntry);
                EV << "PimSplitter::New Entry was added: addr = " << newEntry.getAddr() << ", iftID = " << newEntry.getInterfaceID() << ", ver = " << newEntry.getVersion() << endl;
        }
        // neighbor is already in PIM neighbor table
        // refresh Neighbor Livness Timer
        else
        {
                nlt = pimNbt->findNeighbor(ctrl->getInterfaceId(), ctrl->getSrcAddr())->getNlt();
                cancelEvent(nlt);
                scheduleAt(simTime() + 3.5*HT, nlt);
        }

        delete msg;
}
void PimSplitter::receiveChangeNotification ( int  category,
const cPolymorphic *  details 
) [private]

RECEIVE CHANGE NOTIFICATION

The method from class Notification Board is used to catch its events.

Parameters:
categoryCategory of notification.
detailsAdditional information for notification.
See also:
newMulticast()
igmpChange()

Definition at line 306 of file PimSplitter.cc.

{
        // ignore notifications during initialize
        if (simulation.getContextType()==CTX_INITIALIZE)
                return;

        // PIM needs details
        if (details == NULL)
                return;

        Enter_Method_Silent();
        printNotificationBanner(category, details);

        // according to category of event...
        switch (category)
        {
                // new multicast data appears in router
                case NF_IPv4_NEW_MULTICAST:
                        EV <<  "PimSplitter::receiveChangeNotification - NEW MULTICAST" << endl;
                        IPControlInfo *ctrl;
                        ctrl = (IPControlInfo *)(details);
                        newMulticast(ctrl->getDestAddr(), ctrl->getSrcAddr());
                        break;

                // configuration of interface changed, it means some change from IGMP
                case NF_INTERFACE_IPv4CONFIG_CHANGED:
                        EV << "PimSplitter::receiveChangeNotification - IGMP change" << endl;
                        InterfaceEntry * interface = (InterfaceEntry *)(details);
                        igmpChange(interface);
                        break;
        }
}
void PimSplitter::newMulticast ( IPAddress  destAddr,
IPAddress  srcAddr 
) [private, virtual]

NEW MULTICAST

The method process notification about new coming multicast data. According to IP addresses it find all necessary info to create new entry for multicast table.

Parameters:
destAddrDestination IP address = multicast group IP address.
srcAddrSource IP address.
See also:
MulticastIPRoute

Definition at line 433 of file PimSplitter.cc.

{
        EV << "PimSplitter::newMulticast - group: " << destAddr << ", source: " << srcAddr << endl;

        // find RPF interface for new multicast stream
        InterfaceEntry *inInt = rt->getInterfaceForDestAddr(srcAddr);
        if (inInt == NULL)
        {
                EV << "ERROR: PimSplitter::newMulticast(): cannot find RPF interface, routing information is missing.";
                return;
        }
        int rpfId = inInt->getInterfaceId();
        PimInterface *pimInt = pimIft->getInterfaceByIntID(rpfId);

        // if it is interface configured with PIM, create new route
        if (pimInt != NULL)
        {
                // create new multicast route
                MulticastIPRoute *newRoute = new MulticastIPRoute();
                newRoute->setGroup(destAddr);
                newRoute->setSource(srcAddr);

                // Directly connected routes to source does not have next hop
                // RPF neighbor is source of packet
                IPAddress rpf;
                const IPRoute *routeToSrc = rt->findBestMatchingRoute(srcAddr);
                if (routeToSrc->getSource() == IPRoute::IFACENETMASK)
                {
                        newRoute->addFlag(A);
                        rpf = srcAddr;
                }
                // Not directly connected, next hop address is saved in routing table
                else
                        rpf = rt->getGatewayForDestAddr(srcAddr);

                newRoute->setInInt(inInt, inInt->getInterfaceId(), rpf);

                // notification for PIM module about new multicast route
                if (pimInt->getMode() == Dense)
                        nb->fireChangeNotification(NF_IPv4_NEW_MULTICAST_DENSE, newRoute);
        }
}
void PimSplitter::igmpChange ( InterfaceEntry *  interface) [private]

IGMP CHANGE

The method is used to process notification about IGMP change. Splitter will find out which IP address were added or removed from interface and will send them to appropriate PIM mode.

Parameters:
interfacePointer to interface where IP address changed.
See also:
addRemoveAddr

Definition at line 348 of file PimSplitter.cc.

{
        EV << "PimSplitter::igmpChange" << endl;
        int intId = interface->getInterfaceId();
        PimInterface * pimInt = pimIft->getInterfaceByIntID(intId);

        // save old and new set of multicast IP address assigned to interface
        vector<IPAddress> multicastAddrsOld = pimInt->getIntMulticastAddresses();
        vector<IPAddress> multicastAddrsNew = pimInt->deleteLocalIPs(interface->ipv4Data()->getMulticastGroups());

        // vectors of new and removed multicast addresses
        vector<IPAddress> add;
        vector<IPAddress> remove;

        // which address was removed from interface
        for (unsigned int i = 0; i < multicastAddrsOld.size(); i++)
        {
                unsigned int j;
                for (j = 0; j < multicastAddrsNew.size(); j++)
                {
                        if (multicastAddrsOld[i] == multicastAddrsNew[j])
                                break;
                }
                if (j == multicastAddrsNew.size())
                {
                        EV << "Multicast address " << multicastAddrsOld[i] << " was removed from the interface " << intId << endl;
                        remove.push_back(multicastAddrsOld[i]);
                }
        }

        // which address was added to interface
        for (unsigned int i = 0; i < multicastAddrsNew.size(); i++)
        {
                unsigned int j;
                for (j = 0; j < multicastAddrsOld.size(); j++)
                {
                        if (multicastAddrsNew[i] == multicastAddrsOld[j])
                                break;
                }
                if (j == multicastAddrsOld.size())
                {
                        EV << "Multicast address " << multicastAddrsNew[i] << " was added to the interface " << intId <<endl;
                        add.push_back(multicastAddrsNew[i]);
                }
        }

        // notification about removed multicast address to PIM modules
        addRemoveAddr *addr = new addRemoveAddr();
        if (remove.size() > 0)
        {
                // remove new address
                for(unsigned int i = 0; i < remove.size(); i++)
                        pimInt->removeIntMulticastAddress(remove[i]);

                // send notification
                addr->setAddr(remove);
                addr->setInt(pimInt);
                nb->fireChangeNotification(NF_IPv4_NEW_IGMP_REMOVED, addr);
        }

        // notification about new multicast address to PIM modules
        if (add.size() > 0)
        {
                // add new address
                for(unsigned int i = 0; i < add.size(); i++)
                        pimInt->addIntMulticastAddress(add[i]);

                // send notification
                addr->setAddr(add);
                addr->setInt(pimInt);
                nb->fireChangeNotification(NF_IPv4_NEW_IGMP_ADDED, addr);
        }
}
bool PimSplitter::LoadConfigFromXML ( const char *  filename) [private]

LOAD CONFIG FROM XML

The method is not used now. Config is loaded by class DeviceConfigurator.

The method provides loading of configuration for protocol PIM from configuration file. The main information is if router has enabled multicast and on which interfaces which mode of PIM is set up.

<Routing> <Multicast enable="1"></Multicast> </Routing> <Interfaces> <Interface name="eth0"> <Pim> <Mode>dense-mode</Mode> </Pim> </Interface> </Interfaces>

Parameters:
filenameName of configuration file.
Returns:
Return true, if loading was successful, or false.
See also:
DeviceConfigurator

Definition at line 500 of file PimSplitter.cc.

{
        // file loading
        cXMLElement* asConfig = ev.getXMLDocument(filename);
        if (asConfig == NULL)
           return false;

        // first element <Router id="192.168.10.7">
        std::string routerXPath("Router[@id='");
        IPAddress routerId = rt->getRouterId();
        routerXPath += routerId.str();
        routerXPath += "']";

        cXMLElement* routerNode = asConfig->getElementByPath(routerXPath.c_str());
        if (routerNode == NULL)
        {
                error("No configuration for Router ID: %s", routerId.str().c_str());
           return false;
        }

        // Routing element
        cXMLElement* routingNode = routerNode->getElementByPath("Routing");
        if (routingNode == NULL)
                 return false;

        // Multicast element
        cXMLElement* multicastNode = routingNode->getElementByPath("Multicast");
        if (multicastNode == NULL)
           return false;


        // Multicast has to be enabled
        const char* enableAtt = multicastNode->getAttribute("enable");
        if (strcmp(enableAtt, "1"))
                return false;


        // Where is PIM protocol enabled?
        // Interfaces element
        cXMLElement* iftNode = routerNode->getElementByPath("Interfaces");
        if (iftNode == NULL)
                 return false;

   // list of interfaces, where PIM is enabled
   cXMLElementList childrenNodes = iftNode->getChildrenByTagName("Interface");
   //EV << "PimSplitter::Interface" << endl;
   if (childrenNodes.size() > 0)
   {
           //EV << "PimSplitter::Interface size: " << childrenNodes.size() << endl;
          for (cXMLElementList::iterator node = childrenNodes.begin(); node != childrenNodes.end(); node++)
          {
                  cXMLElement* pimNode = (*node)->getElementByPath("Pim");
                  if (pimNode == NULL)
                          continue;
                  //EV << "PimSplitter::PIM interface" << endl;
                  // get ID of PIM interface
                  InterfaceEntry *interface = ift->getInterfaceByName((*node)->getAttribute("name"));

                  // create new PIM interface
                  PimInterface newentry;
                  newentry.setInterfaceID(interface->getInterfaceId());
                  newentry.setInterfacePtr(interface);

                  // register pim multicast address 224.0.0.13 on pim interface
                  vector<IPAddress> intMulticastAddresses = interface->ipv4Data()->getMulticastGroups();
                  intMulticastAddresses.push_back("224.0.0.13");
                  interface->ipv4Data()->setMulticastGroups(intMulticastAddresses);

                  // get PIM mode for interface
                  cXMLElement* pimMode = pimNode->getElementByPath("Mode");
                  if (pimMode == NULL)
                          return false;

                  const char *mode = pimMode->getNodeValue();
                  //EV << "PimSplitter::PIM interface mode = "<< mode << endl;
                  if (!strcmp(mode, "dense-mode"))
                          newentry.setMode(Dense);
                  else if (!strcmp(mode, "sparse-mode"))
                          newentry.setMode(Sparse);
                  else
                          return false;
                  pimIft->addInterface(newentry);
          }
   }
   else
          return false;
   return true;
}
void PimSplitter::handleMessage ( cMessage *  msg) [protected, virtual]

HANDLE MESSAGE

The method handles new coming message and process it according to its type. Self message is timer. Other messages should be PIM packets.

Parameters:
msgPointer to message which has came to the module.
See also:
PIMTimer
sendHelloPkt()
processNLTimer()
PIMPacket
processHelloPkt()
processPIMPkt()

Definition at line 210 of file PimSplitter.cc.

{
        EV << "PimSplitter::handleMessage" << endl;

        // self message (timer)
   if (msg->isSelfMessage())
   {
           PIMTimer *timer = check_and_cast <PIMTimer *> (msg);
           if (timer->getTimerKind() == HelloTimer)
           {
                   EV << "PIM::HelloTimer" << endl;
                   sendHelloPkt();
                   delete timer;
           }
           else if (timer->getTimerKind() == NeighborLivenessTimer)
           {
                   EV << "PIM::NeighborLivnessTimer" << endl;
                   processNLTimer(timer);
           }
   }

   // PIM packet from network layer
   else if (dynamic_cast<PIMPacket *>(msg) && (strcmp(msg->getArrivalGate()->getName(), "transportIn") == 0))
   {
           PIMPacket *pkt = check_and_cast<PIMPacket *>(msg);

           if (pkt->getType() == Hello)
                   processHelloPkt(pkt);
           else
                   processPIMPkt(pkt);
   }

   // PIM packet from PIM mode, send to network layer
   else if (dynamic_cast<PIMPacket *>(msg))
           send(msg, "transportOut");

   else
           EV << "PIM:ERROR - bad type of message" << endl;
}
void PimSplitter::initialize ( int  stage) [protected, virtual]

INITIALIZE

The method initialize ale structures (tables) which will use. It subscribes to appropriate events of Notification Board. If there is no PIM interface, PIM stops working. Otherwise it schedule Hello Timer.

Parameters:
stageStage of initialization.
See also:
MulticastRoutingTable
PIMTimer

Definition at line 261 of file PimSplitter.cc.

{
        // in stage 2 interfaces are registered
        // in stage 3 table pimInterfaces is built
        if (stage == 4)
        {
                EV << "PimSplitter::initialize" << endl;
                hostname = par("hostname");

                // Pointer to routing tables, interface tables, notification board
                rt = RoutingTableAccess().get();
                mrt = MulticastRoutingTableAccess().get();
                ift = AnsaInterfaceTableAccess().get();
                nb = NotificationBoardAccess().get();
                pimIft = PimInterfaceTableAccess().get();
                pimNbt = PimNeighborTableAccess().get();

                // subscribtion of notifications (future use)
                nb->subscribe(this, NF_IPv4_NEW_MULTICAST);
                nb->subscribe(this, NF_INTERFACE_IPv4CONFIG_CHANGED);

                // is PIM enabled?
                if (pimIft->getNumInterface() == 0)
                        return;
                else
                        EV << "PIM is enabled on device " << hostname << endl;

                // send Hello packets to PIM neighbors (224.0.0.13)
                PIMTimer *timer = new PIMTimer("Hello");
                timer->setTimerKind(HelloTimer);
                scheduleAt(simTime() + uniform(0,5), timer);
        }
}

Member Data Documentation

IRoutingTable* PimSplitter::rt [private]

Pointer to routing table.

Definition at line 44 of file PimSplitter.h.

Pointer to multicast routing table.

Definition at line 45 of file PimSplitter.h.

IInterfaceTable* PimSplitter::ift [private]

Pointer to interface table.

Definition at line 46 of file PimSplitter.h.

NotificationBoard* PimSplitter::nb [private]

Pointer to notification table.

Definition at line 47 of file PimSplitter.h.

Pointer to table of PIM interfaces.

Definition at line 48 of file PimSplitter.h.

Pointer to table of PIM neighbors.

Definition at line 49 of file PimSplitter.h.

const char* PimSplitter::hostname [private]

Router hostname.

Definition at line 50 of file PimSplitter.h.


The documentation for this class was generated from the following files: