![]() |
Multicast Routing Modelling In OMNeT++
|
Class implements PIM Splitter, which splits PIM messages to correct PIM module. More...
#include <PimSplitter.h>
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 |
MulticastRoutingTable * | mrt |
IInterfaceTable * | ift |
NotificationBoard * | nb |
PimInterfaceTable * | pimIft |
PimNeighborTable * | pimNbt |
const char * | hostname |
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.
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.
pkt | New coming PIM packet. |
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.
timer | PIM Neighbor Liveness Timer. |
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.
iftID | ID of interface to which the packet has to be sent |
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).
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
msg | Pointer to incoming Hello packet |
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.
category | Category of notification. |
details | Additional information for notification. |
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.
destAddr | Destination IP address = multicast group IP address. |
srcAddr | Source IP address. |
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.
interface | Pointer to interface where IP address changed. |
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>
filename | Name of configuration file. |
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.
msg | Pointer to message which has came to the module. |
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.
stage | Stage of initialization. |
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); } }
IRoutingTable* PimSplitter::rt [private] |
Pointer to routing table.
Definition at line 44 of file PimSplitter.h.
MulticastRoutingTable* PimSplitter::mrt [private] |
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.
PimInterfaceTable* PimSplitter::pimIft [private] |
Pointer to table of PIM interfaces.
Definition at line 48 of file PimSplitter.h.
PimNeighborTable* PimSplitter::pimNbt [private] |
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.