![]() |
Multicast Routing Modelling In OMNeT++
|
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 }