![]() |
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.
1.8.0