![]() |
Multicast Routing Modelling In OMNeT++
|
00001 00009 #include "pimDM.h" 00010 00011 00012 Define_Module(pimDM); 00013 00014 using namespace std; 00015 00027 void pimDM::sendPimJoinPrune(IPAddress nextHop, IPAddress src, IPAddress grp, int intId) 00028 { 00029 EV << "pimDM::sendPimJoinPrune" << endl; 00030 EV << "UpstreamNeighborAddress: " << nextHop << ", Source: " << src << ", Group: " << grp << ", IntId: " << intId << endl; 00031 00032 PIMJoinPrune *msg = new PIMJoinPrune(); 00033 msg->setName("PIMJoinPrune"); 00034 msg->setUpstreamNeighborAddress(nextHop); 00035 msg->setHoldTime(PT); 00036 msg->setMulticastGroupsArraySize(1); 00037 00038 //FIXME change to add also join groups 00039 // we do not need it at this time 00040 00041 // set multicast groups 00042 MulticastGroup *group = new MulticastGroup(); 00043 group->setGroupAddress(grp); 00044 group->setJoinedSourceAddressArraySize(0); 00045 group->setPrunedSourceAddressArraySize(1); 00046 group->setPrunedSourceAddress(0, src); 00047 msg->setMulticastGroups(0, *group); 00048 00049 // set IP Control info 00050 IPControlInfo *ctrl = new IPControlInfo(); 00051 IPAddress ga1("224.0.0.13"); 00052 ctrl->setDestAddr(ga1); 00053 //ctrl->setProtocol(IP_PROT_PIM); 00054 ctrl->setProtocol(103); 00055 ctrl->setTimeToLive(1); 00056 ctrl->setInterfaceId(intId); 00057 msg->setControlInfo(ctrl); 00058 send(msg, "spiltterOut"); 00059 } 00060 00071 void pimDM::sendPimGraftAck(PIMGraftAck *msg) 00072 { 00073 msg->setName("PIMGraftAck"); 00074 msg->setType(GraftAck); 00075 00076 // set IP Control info 00077 IPControlInfo *oldCtrl = (IPControlInfo*) (msg->removeControlInfo()); 00078 IPControlInfo *ctrl = new IPControlInfo(); 00079 ctrl->setDestAddr(oldCtrl->getSrcAddr()); 00080 ctrl->setSrcAddr(oldCtrl->getDestAddr()); 00081 ctrl->setProtocol(103); 00082 ctrl->setTimeToLive(1); 00083 ctrl->setInterfaceId(oldCtrl->getInterfaceId()); 00084 delete oldCtrl; 00085 msg->setControlInfo(ctrl); 00086 send(msg, "spiltterOut"); 00087 } 00088 00102 void pimDM::sendPimGraft(IPAddress nextHop, IPAddress src, IPAddress grp, int intId) 00103 { 00104 EV << "pimDM::sendPimGraft" << endl; 00105 EV << "UpstreamNeighborAddress: " << nextHop << ", Source: " << src << ", Group: " << grp << ", IntId: " << intId << endl; 00106 00107 PIMGraft *msg = new PIMGraft(); 00108 msg->setName("PIMGraft"); 00109 msg->setHoldTime(0); 00110 msg->setUpstreamNeighborAddress(nextHop); 00111 msg->setMulticastGroupsArraySize(1); 00112 00113 // set multicast groups 00114 MulticastGroup *group = new MulticastGroup(); 00115 group->setGroupAddress(grp); 00116 group->setJoinedSourceAddressArraySize(1); 00117 group->setPrunedSourceAddressArraySize(0); 00118 group->setJoinedSourceAddress(0, src); 00119 msg->setMulticastGroups(0, *group); 00120 00121 // set IP Control info 00122 IPControlInfo *ctrl = new IPControlInfo(); 00123 ctrl->setDestAddr(nextHop); 00124 //ctrl->setProtocol(IP_PROT_PIM); 00125 ctrl->setProtocol(103); 00126 ctrl->setTimeToLive(1); 00127 ctrl->setInterfaceId(intId); 00128 msg->setControlInfo(ctrl); 00129 send(msg, "spiltterOut"); 00130 } 00131 00145 void pimDM::sendPimStateRefresh(IPAddress originator, IPAddress src, IPAddress grp, int intId, bool P) 00146 { 00147 EV << "pimDM::sendPimStateRefresh" << endl; 00148 00149 PIMStateRefresh *msg = new PIMStateRefresh(); 00150 msg->setName("PIMStateRefresh"); 00151 msg->setGroupAddress(grp); 00152 msg->setSourceAddress(src); 00153 msg->setOriginatorAddress(originator); 00154 msg->setInterval(SRT); 00155 msg->setP(P); 00156 00157 // set IP Control info 00158 IPControlInfo *ctrl = new IPControlInfo(); 00159 ctrl->setDestAddr(grp); 00160 //ctrl->setProtocol(IP_PROT_PIM); 00161 ctrl->setProtocol(103); 00162 ctrl->setTimeToLive(1); 00163 ctrl->setInterfaceId(intId); 00164 msg->setControlInfo(ctrl); 00165 send(msg, "spiltterOut"); 00166 } 00167 00182 PIMpt* pimDM::createPruneTimer(IPAddress source, IPAddress group, int intId, int holdTime) 00183 { 00184 EV << "pimDM::createPruneTimer" << endl; 00185 PIMpt *timer = new PIMpt(); 00186 timer->setName("PimPruneTimer"); 00187 timer->setSource(source); 00188 timer->setGroup(group); 00189 timer->setIntId(intId); 00190 scheduleAt(simTime() + holdTime, timer); 00191 return timer; 00192 } 00193 00207 PIMgrt* pimDM::createGraftRetryTimer(IPAddress source, IPAddress group) 00208 { 00209 EV << "pimDM::createPruneTimer" << endl; 00210 PIMgrt *timer = new PIMgrt(); 00211 timer->setName("PIMGraftRetryTimer"); 00212 timer->setSource(source); 00213 timer->setGroup(group); 00214 scheduleAt(simTime() + GRT, timer); 00215 return timer; 00216 } 00217 00230 PIMsat* pimDM::createSourceActiveTimer(IPAddress source, IPAddress group) 00231 { 00232 EV << "pimDM::createSourceActiveTimer" << endl; 00233 PIMsat *timer = new PIMsat(); 00234 timer->setName("PIMSourceActiveTimer"); 00235 timer->setSource(source); 00236 timer->setGroup(group); 00237 scheduleAt(simTime() + SAT, timer); 00238 return timer; 00239 } 00240 00253 PIMsrt* pimDM::createStateRefreshTimer(IPAddress source, IPAddress group) 00254 { 00255 EV << "pimDM::createStateRefreshTimer" << endl; 00256 PIMsrt *timer = new PIMsrt(); 00257 timer->setName("PIMStateRefreshTimer"); 00258 timer->setSource(source); 00259 timer->setGroup(group); 00260 scheduleAt(simTime() + SRT, timer); 00261 return timer; 00262 } 00263 00264 00283 void pimDM::processGraftPacket(IPAddress source, IPAddress group, IPAddress sender, int intId) 00284 { 00285 EV << "pimDM::processGraftPacket" << endl; 00286 00287 MulticastIPRoute *route = mrt->getRouteFor(group, source); 00288 bool forward = false; 00289 00290 // check if message come to non-RPF interface 00291 if (route->isRpf(intId)) 00292 { 00293 EV << "ERROR: Graft message came to RPF interface." << endl; 00294 return; 00295 } 00296 00297 // find outgoing interface to neighbor 00298 InterfaceVector outInt = route->getOutInt(); 00299 for (unsigned int l = 0; l < outInt.size(); l++) 00300 { 00301 if(outInt[l].intId == intId) 00302 { 00303 forward = true; 00304 if (outInt[l].forwarding == Pruned) 00305 { 00306 EV << "Interface " << outInt[l].intId << " transit to forwarding state (Graft)." << endl; 00307 outInt[l].forwarding = Forward; 00308 00309 //cancel Prune Timer 00310 PIMpt* timer = outInt[l].pruneTimer; 00311 cancelEvent(timer); 00312 delete timer; 00313 outInt[l].pruneTimer = NULL; 00314 } 00315 } 00316 } 00317 route->setOutInt(outInt); 00318 00319 // if all route was pruned, remove prune flag 00320 // if upstrem is not source, send Graft message 00321 if (route->isFlagSet(P) && forward && (route->getGrt() == NULL)) 00322 { 00323 if (!route->isFlagSet(A)) 00324 { 00325 EV << "Route is not pruned any more, send Graft to upstream" << endl; 00326 sendPimGraft(route->getInIntNextHop(), source, group, route->getInIntId()); 00327 PIMgrt* timer = createGraftRetryTimer(source, group); 00328 route->setGrt(timer); 00329 } 00330 else 00331 route->removeFlag(P); 00332 } 00333 } 00334 00345 void pimDM::processGraftAckPacket(MulticastIPRoute *route) 00346 { 00347 EV << "pimDM::processGraftAckPacket" << endl; 00348 PIMgrt *grt = route->getGrt(); 00349 if (grt != NULL) 00350 { 00351 cancelEvent(grt); 00352 delete grt; 00353 route->setGrt(NULL); 00354 route->removeFlag(P); 00355 } 00356 } 00357 00373 void pimDM::processPrunePacket(MulticastIPRoute *route, int intId, int holdTime) 00374 { 00375 EV << "pimDM::processPrunePacket" << endl; 00376 InterfaceVector outInt = route->getOutInt(); 00377 int i = route->getOutIdByIntId(intId); 00378 bool change = false; 00379 00380 // we find correct outgoing interface 00381 if (i < (int) outInt.size()) 00382 { 00383 // if interface was already pruned, restart Prune Timer 00384 if (outInt[i].forwarding == Pruned) 00385 { 00386 EV << "Outgoing interface is already pruned, restart Prune Timer." << endl; 00387 PIMpt* timer = outInt[i].pruneTimer; 00388 cancelEvent(timer); 00389 scheduleAt(simTime() + holdTime, timer); 00390 } 00391 // if interface is forwarding, transit its state to pruned and set Prune timer 00392 else 00393 { 00394 EV << "Outgoing interfaces is forwarding now -> change to Pruned, set the timer." << endl; 00395 outInt[i].forwarding = Pruned; 00396 PIMpt* timer = createPruneTimer(route->getSource(), route->getGroup(), intId, holdTime); 00397 outInt[i].pruneTimer = timer; 00398 change = true; 00399 } 00400 } 00401 route->setOutInt(outInt); 00402 00403 // if there is no forwarding outgoing int, transit route to pruned state 00404 if (route->isOilistNull() && change) 00405 { 00406 EV << "All interfaces are pruned, send Pruned to upstream." << endl; 00407 route->addFlag(P); 00408 00409 // if GRT is running now, do not send Prune msg 00410 if (route->isFlagSet(P) && (route->getGrt() != NULL)) 00411 { 00412 cancelEvent(route->getGrt()); 00413 delete route->getGrt(); 00414 route->setGrt(NULL); 00415 } 00416 else if (!route->isFlagSet(A)) 00417 sendPimJoinPrune(route->getInIntNextHop(), route->getSource(), route->getGroup(), route->getInIntId()); 00418 } 00419 } 00420 00421 00438 void pimDM::processJoinPruneGraftPacket(PIMJoinPrune *pkt, PIMPacketType type) 00439 { 00440 EV << "pimDM::processJoinePruneGraftPacket" << endl; 00441 00442 IPControlInfo *ctrl = (IPControlInfo *) pkt->getControlInfo(); 00443 IPAddress sender = ctrl->getSrcAddr(); 00444 InterfaceEntry * nt = rt->getInterfaceForDestAddr(sender); 00445 vector<PimNeighbor> neighbors = pimNbt->getNeighborsByIntID(nt->getInterfaceId()); 00446 IPAddress addr = nt->ipv4Data()->getIPAddress(); 00447 00448 // does packet belong to this router? 00449 if (pkt->getUpstreamNeighborAddress() != nt->ipv4Data()->getIPAddress() && type != GraftAck) 00450 { 00451 EV << "Paket neni urceny pro tento router" << endl; 00452 delete pkt; 00453 return; 00454 } 00455 00456 // go through list of multicast groups 00457 for (unsigned int i = 0; i < pkt->getMulticastGroupsArraySize(); i++) 00458 { 00459 MulticastGroup group = pkt->getMulticastGroups(i); 00460 IPAddress groupAddr = group.getGroupAddress(); 00461 00462 // go through list of joined sources 00463 //EV << "JoinedSourceAddressArraySize: " << group.getJoinedSourceAddressArraySize() << endl; 00464 for (unsigned int j = 0; j < group.getJoinedSourceAddressArraySize(); j++) 00465 { 00466 IPAddress source = group.getJoinedSourceAddress(j); 00467 MulticastIPRoute *route = mrt->getRouteFor(groupAddr, source); 00468 00469 if (type == JoinPrune) 00470 { 00471 //FIXME join action 00472 // only if there is more than one PIM neighbor on one interface 00473 // interface change to forwarding state 00474 // cancel Prune Timer 00475 // send Graft to upstream 00476 } 00477 else if (type == Graft) 00478 processGraftPacket(source, groupAddr, sender, nt->getInterfaceId()); 00479 else if (type == GraftAck) 00480 processGraftAckPacket(route); 00481 } 00482 00483 // go through list of pruned sources (only for PIM Join Prune msg) 00484 if (type == JoinPrune) 00485 { 00486 //EV << "JoinedPrunedAddressArraySize: " << group.getPrunedSourceAddressArraySize() << endl; 00487 for(unsigned int k = 0; k < group.getPrunedSourceAddressArraySize(); k++) 00488 { 00489 IPAddress source = group.getPrunedSourceAddress(k); 00490 MulticastIPRoute *route = mrt->getRouteFor(groupAddr, source); 00491 00492 if (source != route->getSource()) 00493 continue; 00494 00495 // if there could be more than one PIM neighbor on interface 00496 if (neighbors.size() > 1) 00497 { 00498 EV << "Vice sousedu na rozhrani" << endl; 00499 ; //FIXME set PPT timer 00500 } 00501 // if there is only one PIM neighbor on interface 00502 else 00503 processPrunePacket(route, nt->getInterfaceId(), pkt->getHoldTime()); 00504 } 00505 } 00506 } 00507 00508 // Send GraftAck for this Graft message 00509 if (type == Graft) 00510 sendPimGraftAck((PIMGraftAck *) (pkt)); 00511 mrt->generateShowIPMroute(); 00512 } 00513 00528 void pimDM::processStateRefreshPacket(PIMStateRefresh *pkt) 00529 { 00530 EV << "pimDM::processStateRefreshPacket" << endl; 00531 00532 // FIXME actions of upstream automat according to pruned/forwarding state and Prune Indicator from msg 00533 00534 // first check if there is route for given group address and source 00535 MulticastIPRoute *route = mrt->getRouteFor(pkt->getGroupAddress(), pkt->getSourceAddress()); 00536 if (route == NULL) 00537 { 00538 delete pkt; 00539 return; 00540 } 00541 InterfaceVector outInt = route->getOutInt(); 00542 bool pruneIndicator; 00543 00544 // chceck if State Refresh msg has came to RPF interface 00545 IPControlInfo *ctrl = (IPControlInfo*) pkt->getControlInfo(); 00546 if (ctrl->getInterfaceId() != route->getInIntId()) 00547 { 00548 delete pkt; 00549 return; 00550 } 00551 00552 // this router is pruned, but outgoing int of upstream router leading to this router is forwarding 00553 if (route->isFlagSet(P) && !pkt->getP()) 00554 { 00555 // send Prune msg to upstream 00556 if (route->getGrt() == NULL) 00557 sendPimJoinPrune(route->getInIntNextHop(), route->getSource(), route->getGroup(), route->getInIntId()); 00558 else 00559 { 00560 cancelEvent(route->getGrt()); 00561 delete route->getGrt(); 00562 route->setGrt(NULL); 00563 } 00564 } 00565 00566 // go through all outgoing interfaces, reser Prune Timer and send out State Refresh msg 00567 for (unsigned int i = 0; i < outInt.size(); i++) 00568 { 00569 if (outInt[i].forwarding == Pruned) 00570 { 00571 // P = true 00572 pruneIndicator = true; 00573 // reset PT 00574 cancelEvent(outInt[i].pruneTimer); 00575 scheduleAt(simTime() + PT, outInt[i].pruneTimer); 00576 } 00577 else if (outInt[i].forwarding == Forward) 00578 { 00579 // P = false 00580 pruneIndicator = false; 00581 } 00582 sendPimStateRefresh(pkt->getOriginatorAddress(), pkt->getSourceAddress(), pkt->getGroupAddress(), outInt[i].intId, pruneIndicator); 00583 } 00584 delete pkt; 00585 } 00586 00587 00600 void pimDM::processPruneTimer(PIMpt *timer) 00601 { 00602 EV << "pimDM::processPruneTimer" << endl; 00603 00604 IPAddress source = timer->getSource(); 00605 IPAddress group = timer->getGroup(); 00606 int intId = timer->getIntId(); 00607 00608 // find correct (S,G) route which timer belongs to 00609 MulticastIPRoute *route = mrt->getRouteFor(group, source); 00610 if (route == NULL) 00611 { 00612 delete timer; 00613 return; 00614 } 00615 00616 // state of interface is changed to forwarding 00617 int i = route->getOutIdByIntId(intId); 00618 InterfaceVector outInt = route->getOutInt(); 00619 if (i < (int) outInt.size()) 00620 { 00621 EV << "Nalezen out int" << endl; 00622 delete timer; 00623 outInt[i].pruneTimer = NULL; 00624 outInt[i].forwarding = Forward; 00625 route->setOutInt(outInt); 00626 00627 // if the router is pruned from multicast tree, join again 00628 if (route->isFlagSet(P) && (route->getGrt() == NULL)) 00629 { 00630 if (!route->isFlagSet(A)) 00631 { 00632 EV << "Pruned cesta prejde do forwardu, posli Graft" << endl; 00633 sendPimGraft(route->getInIntNextHop(), source, group, route->getInIntId()); 00634 PIMgrt* timer = createGraftRetryTimer(source, group); 00635 route->setGrt(timer); 00636 } 00637 else 00638 route->removeFlag(P); 00639 } 00640 mrt->generateShowIPMroute(); 00641 } 00642 } 00643 00656 void pimDM::processGraftRetryTimer(PIMgrt *timer) 00657 { 00658 EV << "pimDM::processGraftRetryTimer" << endl; 00659 MulticastIPRoute *route = mrt->getRouteFor(timer->getGroup(), timer->getSource()); 00660 sendPimGraft(route->getInIntNextHop(), timer->getSource(), timer->getGroup(), route->getInIntId()); 00661 timer = createGraftRetryTimer(timer->getSource(), timer->getGroup()); 00662 } 00663 00673 void pimDM::processSourceActiveTimer(PIMsat * timer) 00674 { 00675 EV << "pimDM::processSourceActiveTimer: route will be deleted" << endl; 00676 MulticastIPRoute *route = mrt->getRouteFor(timer->getGroup(), timer->getSource()); 00677 00678 delete timer; 00679 route->setSat(NULL); 00680 mrt->deleteRoute(route); 00681 } 00682 00696 void pimDM::processStateRefreshTimer(PIMsrt * timer) 00697 { 00698 EV << "pimDM::processStateRefreshTimer" << endl; 00699 MulticastIPRoute *route = mrt->getRouteFor(timer->getGroup(), timer->getSource()); 00700 InterfaceVector outInt = route->getOutInt(); 00701 bool pruneIndicator; 00702 00703 for (unsigned int i = 0; i < outInt.size(); i++) 00704 { 00705 if (outInt[i].forwarding == Pruned) 00706 { 00707 // P = true 00708 pruneIndicator = true; 00709 // reset PT 00710 cancelEvent(outInt[i].pruneTimer); 00711 scheduleAt(simTime() + PT, outInt[i].pruneTimer); 00712 } 00713 else if (outInt[i].forwarding == Forward) 00714 { 00715 pruneIndicator = false; 00716 } 00717 int intId = outInt[i].intId; 00718 sendPimStateRefresh(ift->getInterfaceById(intId)->ipv4Data()->getIPAddress(), timer->getSource(), timer->getGroup(), intId, pruneIndicator); 00719 } 00720 delete timer; 00721 route->setSrt(createStateRefreshTimer(route->getSource(), route->getGroup())); 00722 } 00723 00735 void pimDM::processPIMTimer(PIMTimer *timer) 00736 { 00737 EV << "pimDM::processPIMTimer: "; 00738 00739 switch(timer->getTimerKind()) 00740 { 00741 case AssertTimer: 00742 EV << "AssertTimer" << endl; 00743 break; 00744 case PruneTimer: 00745 EV << "PruneTimer" << endl; 00746 processPruneTimer(check_and_cast<PIMpt *> (timer)); 00747 break; 00748 case PrunePendingTimer: 00749 EV << "PrunePendingTimer" << endl; 00750 break; 00751 case GraftRetryTimer: 00752 EV << "GraftRetryTimer" << endl; 00753 processGraftRetryTimer(check_and_cast<PIMgrt *> (timer)); 00754 break; 00755 case UpstreamOverrideTimer: 00756 EV << "UpstreamOverrideTimer" << endl; 00757 break; 00758 case PruneLimitTimer: 00759 EV << "PruneLimitTimer" << endl; 00760 break; 00761 case SourceActiveTimer: 00762 EV << "SourceActiveTimer" << endl; 00763 processSourceActiveTimer(check_and_cast<PIMsat *> (timer)); 00764 break; 00765 case StateRefreshTimer: 00766 EV << "StateRefreshTimer" << endl; 00767 processStateRefreshTimer(check_and_cast<PIMsrt *> (timer)); 00768 break; 00769 default: 00770 EV << "BAD TYPE, DROPPED" << endl; 00771 delete timer; 00772 } 00773 } 00774 00785 void pimDM::processPIMPkt(PIMPacket *pkt) 00786 { 00787 EV << "pimDM::processPIMPkt: "; 00788 00789 switch(pkt->getType()) 00790 { 00791 case JoinPrune: 00792 EV << "JoinPrune" << endl; 00793 processJoinPruneGraftPacket(check_and_cast<PIMJoinPrune *> (pkt), (PIMPacketType) pkt->getType()); 00794 break; 00795 case Assert: 00796 EV << "Assert" << endl; 00797 // FIXME for future use 00798 break; 00799 case Graft: 00800 EV << "Graft" << endl; 00801 processJoinPruneGraftPacket(check_and_cast<PIMJoinPrune *> (pkt), (PIMPacketType) pkt->getType()); 00802 break; 00803 case GraftAck: 00804 EV << "GraftAck" << endl; 00805 processJoinPruneGraftPacket(check_and_cast<PIMJoinPrune *> (pkt), (PIMPacketType) pkt->getType()); 00806 break; 00807 case StateRefresh: 00808 EV << "StateRefresh" << endl; 00809 processStateRefreshPacket(check_and_cast<PIMStateRefresh *> (pkt)); 00810 break; 00811 default: 00812 EV << "BAD TYPE, DROPPED" << endl; 00813 delete pkt; 00814 } 00815 } 00816 00817 00831 void pimDM::handleMessage(cMessage *msg) 00832 { 00833 EV << "PIMDM::handleMessage" << endl; 00834 00835 // self message (timer) 00836 if (msg->isSelfMessage()) 00837 { 00838 EV << "PIMDM::handleMessage:Timer" << endl; 00839 PIMTimer *timer = check_and_cast <PIMTimer *> (msg); 00840 processPIMTimer(timer); 00841 } 00842 // PIM packet from PIM neighbor 00843 else if (dynamic_cast<PIMPacket *>(msg)) 00844 { 00845 EV << "PIMDM::handleMessage: PIM-DM packet" << endl; 00846 PIMPacket *pkt = check_and_cast<PIMPacket *>(msg); 00847 processPIMPkt(pkt); 00848 } 00849 // wrong message, mistake 00850 else 00851 EV << "PIMDM::handleMessage: Wrong message" << endl; 00852 } 00853 00863 void pimDM::initialize(int stage) 00864 { 00865 if (stage == 4) 00866 { 00867 EV << "pimDM::initialize" << endl; 00868 00869 // Pointer to routing tables, interface tables, notification board 00870 rt = RoutingTableAccess().get(); 00871 mrt = MulticastRoutingTableAccess().get(); 00872 ift = AnsaInterfaceTableAccess().get(); 00873 nb = NotificationBoardAccess().get(); 00874 pimIft = PimInterfaceTableAccess().get(); 00875 pimNbt = PimNeighborTableAccess().get(); 00876 00877 // is PIM enabled? 00878 if (pimIft->getNumInterface() == 0) 00879 { 00880 EV << "PIM is NOT enabled on device " << endl; 00881 return; 00882 } 00883 00884 // subscribe for notifications 00885 nb->subscribe(this, NF_IPv4_NEW_MULTICAST_DENSE); 00886 nb->subscribe(this, NF_IPv4_NEW_IGMP_ADDED); 00887 nb->subscribe(this, NF_IPv4_NEW_IGMP_REMOVED); 00888 nb->subscribe(this, NF_IPv4_DATA_ON_PRUNED_INT); 00889 nb->subscribe(this, NF_IPv4_DATA_ON_NONRPF); 00890 nb->subscribe(this, NF_IPv4_DATA_ON_RPF); 00891 //nb->subscribe(this, NF_IPv4_RPF_CHANGE); 00892 nb->subscribe(this, NF_IPv4_ROUTE_ADDED); 00893 } 00894 } 00895 00906 void pimDM::receiveChangeNotification(int category, const cPolymorphic *details) 00907 { 00908 // ignore notifications during initialize 00909 if (simulation.getContextType()==CTX_INITIALIZE) 00910 return; 00911 00912 // PIM needs addition info for each notification 00913 if (details == NULL) 00914 return; 00915 00916 Enter_Method_Silent(); 00917 printNotificationBanner(category, details); 00918 IPControlInfo *ctrl; 00919 MulticastIPRoute *route; 00920 addRemoveAddr *members; 00921 00922 // according to category of event... 00923 switch (category) 00924 { 00925 // new multicast data appears in router 00926 case NF_IPv4_NEW_MULTICAST_DENSE: 00927 EV << "pimDM::receiveChangeNotification - NEW MULTICAST DENSE-" << endl; 00928 route = (MulticastIPRoute *)(details); 00929 newMulticast(route); 00930 break; 00931 00932 // configuration of interface changed, it means some change from IGMP, address were added. 00933 case NF_IPv4_NEW_IGMP_ADDED: 00934 EV << "pimDM::receiveChangeNotification - IGMP change - address were added." << endl; 00935 members = (addRemoveAddr *) (details); 00936 newMulticastAddr(members); 00937 break; 00938 00939 // configuration of interface changed, it means some change from IGMP, address were removed. 00940 case NF_IPv4_NEW_IGMP_REMOVED: 00941 EV << "pimDM::receiveChangeNotification - IGMP change - address were removed." << endl; 00942 members = (addRemoveAddr *) (details); 00943 oldMulticastAddr(members); 00944 break; 00945 00946 case NF_IPv4_DATA_ON_PRUNED_INT: 00947 EV << "pimDM::receiveChangeNotification - Data appears on pruned interface." << endl; 00948 ctrl = (IPControlInfo *)(details); 00949 dataOnPruned(ctrl->getDestAddr(), ctrl->getSrcAddr()); 00950 break; 00951 00952 // data come to non-RPF interface 00953 case NF_IPv4_DATA_ON_NONRPF: 00954 EV << "pimDM::receiveChangeNotification - Data appears on non-RPF interface." << endl; 00955 ctrl = (IPControlInfo *)(details); 00956 dataOnNonRpf(ctrl->getDestAddr(), ctrl->getSrcAddr(), ctrl->getInterfaceId()); 00957 break; 00958 00959 // data come to RPF interface 00960 case NF_IPv4_DATA_ON_RPF: 00961 EV << "pimDM::receiveChangeNotification - Data appears on RPF interface." << endl; 00962 route = (MulticastIPRoute *)(details); 00963 dataOnRpf(route); 00964 break; 00965 00966 // RPF interface has changed 00967 case NF_IPv4_ROUTE_ADDED: 00968 EV << "pimDM::receiveChangeNotification - RPF interface has changed." << endl; 00969 IPRoute *entry = (IPRoute *) (details); 00970 vector<MulticastIPRoute*> routes = mrt->getRoutesForSource(entry->getHost()); 00971 for (unsigned int i = 0; i < routes.size(); i++) 00972 rpfIntChange(routes[i]); 00973 break; 00974 } 00975 } 00976 00977 00991 void pimDM::rpfIntChange(MulticastIPRoute *route) 00992 { 00993 IPAddress source = route->getSource(); 00994 IPAddress group = route->getGroup(); 00995 InterfaceEntry *newRpf = rt->getInterfaceForDestAddr(source); 00996 int rpfId = newRpf->getInterfaceId(); 00997 00998 // is there any change? 00999 if (rpfId == route->getInIntId()) 01000 return; 01001 EV << "New RPF int for group " << group << " source " << source << " is " << rpfId << endl; 01002 01003 // set new RPF 01004 inInterface oldRpf = route->getInInt(); 01005 route->setInInt(newRpf, rpfId, pimNbt->getNeighborsByIntID(rpfId)[0].getAddr()); 01006 01007 // route was not pruned, join to the multicast tree again 01008 if (!route->isFlagSet(P)) 01009 { 01010 sendPimGraft(route->getInIntNextHop(), source, group, rpfId); 01011 PIMgrt* timer = createGraftRetryTimer(source, group); 01012 route->setGrt(timer); 01013 } 01014 01015 // find rpf int in outgoing imterfaces and delete it 01016 InterfaceVector outInt = route->getOutInt(); 01017 for(unsigned int i = 0; i < outInt.size(); i++) 01018 { 01019 if (outInt[i].intId == rpfId) 01020 { 01021 if (outInt[i].pruneTimer != NULL) 01022 { 01023 cancelEvent(outInt[i].pruneTimer); 01024 delete outInt[i].pruneTimer; 01025 outInt[i].pruneTimer = NULL; 01026 } 01027 outInt.erase(outInt.begin() + i); 01028 break; 01029 } 01030 } 01031 01032 // old RPF should be now outgoing interface if it is not down 01033 if (!oldRpf.intPtr->isDown()) 01034 { 01035 outInterface newOutInt; 01036 newOutInt.intId = oldRpf.intId; 01037 newOutInt.intPtr = oldRpf.intPtr; 01038 newOutInt.pruneTimer = NULL; 01039 newOutInt.forwarding = Forward; 01040 newOutInt.mode = Densemode; 01041 outInt.push_back(newOutInt); 01042 } 01043 01044 route->setOutInt(outInt); 01045 mrt->generateShowIPMroute(); 01046 } 01047 01048 01058 void pimDM::dataOnRpf(MulticastIPRoute *route) 01059 { 01060 cancelEvent(route->getSat()); 01061 scheduleAt(simTime() + SAT, route->getSat()); 01062 } 01063 01077 void pimDM::dataOnNonRpf(IPAddress group, IPAddress source, int intId) 01078 { 01079 EV << "pimDM::dataOnNonRpf, intID: " << intId << endl; 01080 01081 // load route from mroute 01082 MulticastIPRoute *route = mrt->getRouteFor(group, source); 01083 if (route == NULL) 01084 return; 01085 01086 // in case of p2p link, send prune 01087 // FIXME There should be better indicator of P2P link 01088 if (pimNbt->getNumNeighborsOnInt(intId) == 1) 01089 { 01090 // send Prune msg to the neighbor who sent these multicast data 01091 IPAddress nextHop = (pimNbt->getNeighborsByIntID(intId))[0].getAddr(); 01092 sendPimJoinPrune(nextHop, source, group, intId); 01093 01094 // find incoming interface 01095 int i = route->getOutIdByIntId(intId); 01096 InterfaceVector outInt = route->getOutInt(); 01097 01098 // the incoming interface has to change its state to Pruned 01099 if (outInt[i].forwarding == Forward) 01100 { 01101 outInt[i].forwarding = Pruned; 01102 PIMpt* timer = createPruneTimer(route->getSource(), route->getGroup(), intId, PT); 01103 outInt[i].pruneTimer = timer; 01104 route->setOutInt(outInt); 01105 01106 // if there is no outgoing interface, Prune msg has to be sent on upstream 01107 if (route->isOilistNull()) 01108 { 01109 EV << "pimDM::dataOnNonRpf: oilist is NULL, send prune msg to upstream." << endl; 01110 route->addFlag(P); 01111 if (!route->isFlagSet(A)) 01112 sendPimJoinPrune(route->getInIntNextHop(), route->getSource(), route->getGroup(), route->getInIntId()); 01113 } 01114 mrt->generateShowIPMroute(); 01115 } 01116 } 01117 01118 //FIXME in case of LAN 01119 } 01120 01131 void pimDM::dataOnPruned(IPAddress group, IPAddress source) 01132 { 01133 EV << "pimDM::dataOnPruned" << endl; 01134 MulticastIPRoute *route = mrt->getRouteFor(group, source); 01135 // if GRT is running now, do not send Prune msg 01136 if (route->isFlagSet(P) && (route->getGrt() != NULL)) 01137 { 01138 cancelEvent(route->getGrt()); 01139 delete route->getGrt(); 01140 route->setGrt(NULL); 01141 } 01142 // otherwise send Prune msg to upstream router 01143 else if (!route->isFlagSet(A)) 01144 sendPimJoinPrune(route->getInIntNextHop(), source, group, route->getInIntId()); 01145 } 01146 01158 void pimDM::oldMulticastAddr(addRemoveAddr *members) 01159 { 01160 EV << "pimDM::oldMulticastAddr" << endl; 01161 vector<IPAddress> oldAddr = members->getAddr(); 01162 PimInterface * pimInt = members->getInt(); 01163 bool connected = false; 01164 01165 // go through all old multicast addresses assigned to interface 01166 for (unsigned int i = 0; i < oldAddr.size(); i++) 01167 { 01168 EV << "Removed multicast address: " << oldAddr[i] << endl; 01169 vector<MulticastIPRoute*> routes = mrt->getRouteFor(oldAddr[i]); 01170 01171 // there is no route for group in the table 01172 if (routes.size() == 0) 01173 continue; 01174 01175 // go through all multicast routes 01176 for (unsigned int j = 0; j < routes.size(); j++) 01177 { 01178 MulticastIPRoute *route = routes[j]; 01179 InterfaceVector outInt = route->getOutInt(); 01180 unsigned int k; 01181 01182 // is interface in list of outgoing interfaces? 01183 for (k = 0; k < outInt.size(); k++) 01184 { 01185 if (outInt[k].intId == pimInt->getInterfaceID()) 01186 { 01187 EV << "Interface is present, removing it from the list of outgoing interfaces." << endl; 01188 outInt.erase(outInt.begin() + k); 01189 } 01190 else if(outInt[k].forwarding == Forward) 01191 { 01192 if ((pimNbt->getNeighborsByIntID(outInt[k].intId)).size() == 0) 01193 connected = true; 01194 } 01195 } 01196 route->setOutInt(outInt); 01197 01198 // if there is no directly connected member of group 01199 if (!connected) 01200 route->removeFlag(C); 01201 01202 // there is no receiver of multicast, prune the router from the multicast tree 01203 if (route->isOilistNull()) 01204 { 01205 EV << "There is no receiver for the group -> prune from the tree" << endl; 01206 // if GRT is running now, do not send Prune msg 01207 if (route->isFlagSet(P) && (route->getGrt() != NULL)) 01208 { 01209 cancelEvent(route->getGrt()); 01210 delete route->getGrt(); 01211 route->setGrt(NULL); 01212 sendPimJoinPrune(route->getInIntNextHop(), route->getSource(), route->getGroup(), route->getInIntId()); 01213 } 01214 01215 // if the source is not directly connected, sent Prune msg 01216 if (!route->isFlagSet(A) && !route->isFlagSet(P)) 01217 sendPimJoinPrune(route->getInIntNextHop(), route->getSource(), route->getGroup(), route->getInIntId()); 01218 01219 route->addFlag(P); 01220 } 01221 } 01222 } 01223 mrt->generateShowIPMroute(); 01224 } 01225 01239 void pimDM::newMulticastAddr(addRemoveAddr *members) 01240 { 01241 EV << "pimDM::newMulticastAddr" << endl; 01242 vector<IPAddress> newAddr = members->getAddr(); 01243 PimInterface * pimInt = members->getInt(); 01244 bool forward = false; 01245 01246 // go through all new multicast addresses assigned to interface 01247 for (unsigned int i = 0; i < newAddr.size(); i++) 01248 { 01249 EV << "New multicast address: " << newAddr[i] << endl; 01250 vector<MulticastIPRoute*> routes = mrt->getRouteFor(newAddr[i]); 01251 01252 // there is no route for group in the table in this moment 01253 if (routes.size() == 0) 01254 continue; 01255 01256 // go through all multicast routes 01257 for (unsigned int j = 0; j < routes.size(); j++) 01258 { 01259 MulticastIPRoute *route = routes[j]; 01260 InterfaceVector outInt = route->getOutInt(); 01261 unsigned int k; 01262 01263 // check on RPF interface 01264 if (route->getInIntId() == pimInt->getInterfaceID()) 01265 continue; 01266 01267 // is interface in list of outgoing interfaces? 01268 for (k = 0; k < outInt.size(); k++) 01269 { 01270 if (outInt[k].intId == pimInt->getInterfaceID()) 01271 { 01272 EV << "Interface is already on list of outgoing interfaces" << endl; 01273 if (outInt[k].forwarding == Pruned) 01274 outInt[k].forwarding = Forward; 01275 forward = true; 01276 break; 01277 } 01278 } 01279 01280 // interface is not in list of outgoing interfaces 01281 if (k == outInt.size()) 01282 { 01283 EV << "Interface is not on list of outgoing interfaces yet, it will be added" << endl; 01284 outInterface newInt; 01285 newInt.intPtr = pimInt->getInterfacePtr(); 01286 newInt.intId = pimInt->getInterfaceID(); 01287 newInt.mode = Densemode; 01288 newInt.forwarding = Forward; 01289 newInt.pruneTimer = NULL; 01290 outInt.push_back(newInt); 01291 forward = true; 01292 } 01293 route->setOutInt(outInt); 01294 route->addFlag(C); 01295 01296 // route was pruned, has to be added to multicast tree 01297 if (route->isFlagSet(P) && forward) 01298 { 01299 EV << "Route was pruned -> router has to join to multicast tree" << endl; 01300 01301 // if source is not directly connected, send Graft to upstream 01302 if (!route->isFlagSet(A)) 01303 { 01304 sendPimGraft(route->getInIntNextHop(), route->getSource(), route->getGroup(), route->getInIntId()); 01305 PIMgrt *timer = createGraftRetryTimer(route->getSource(), route->getGroup()); 01306 route->setGrt(timer); 01307 } 01308 else 01309 route->removeFlag(P); 01310 } 01311 } 01312 } 01313 mrt->generateShowIPMroute(); 01314 } 01315 01328 void pimDM::newMulticast(MulticastIPRoute *newRoute) 01329 { 01330 EV << "pimDM::newMulticast" << endl; 01331 01332 // only outgoing interfaces are missing 01333 PimInterface *rpfInt = pimIft->getInterfaceByIntID(newRoute->getInIntId()); 01334 bool pruned = true; 01335 01336 // insert all PIM interfaces except rpf int 01337 for (int i = 0; i < pimIft->getNumInterface(); i++) 01338 { 01339 PimInterface *pimIntTemp = pimIft->getInterface(i); 01340 int intId = pimIntTemp->getInterfaceID(); 01341 01342 //check if PIM interface is not RPF interface 01343 if (pimIntTemp == rpfInt) 01344 continue; 01345 01346 // create new outgoing interface 01347 outInterface newOutInt; 01348 newOutInt.intId = pimIntTemp->getInterfaceID(); 01349 newOutInt.intPtr = pimIntTemp->getInterfacePtr(); 01350 newOutInt.pruneTimer = NULL; 01351 01352 switch (pimIntTemp->getMode()) 01353 { 01354 case Dense: 01355 newOutInt.mode = Densemode; 01356 break; 01357 case Sparse: 01358 newOutInt.mode = Sparsemode; 01359 break; 01360 } 01361 01362 // if there are neighbors on interface, we will forward 01363 if((pimNbt->getNeighborsByIntID(intId)).size() > 0) 01364 { 01365 newOutInt.forwarding = Forward; 01366 pruned = false; 01367 newRoute->addOutInt(newOutInt); 01368 } 01369 // if there is member of group, we will forward 01370 else if (pimIntTemp->isLocalIntMulticastAddress(newRoute->getGroup())) 01371 { 01372 newOutInt.forwarding = Forward; 01373 pruned = false; 01374 newRoute->addFlag(C); 01375 newRoute->addOutInt(newOutInt); 01376 } 01377 // in any other case interface is not involved 01378 } 01379 01380 // directly connected to source, set State Refresh Timer 01381 if (newRoute->isFlagSet(A)) 01382 { 01383 //FIXME record TTL (I do not know why???) 01384 PIMsrt* timerSrt = createStateRefreshTimer(newRoute->getSource(), newRoute->getGroup()); 01385 newRoute->setSrt(timerSrt); 01386 } 01387 01388 // set Source Active Timer (liveness of route) 01389 PIMsat* timerSat = createSourceActiveTimer(newRoute->getSource(), newRoute->getGroup()); 01390 newRoute->setSat(timerSat); 01391 01392 // if there is no outgoing interface, prune from multicast tree 01393 if (pruned) 01394 { 01395 EV << "pimDM::newMulticast: There is no outgoing interface for multicast, send Prune msg to upstream" << endl; 01396 newRoute->addFlag(P); 01397 01398 if (!newRoute->isFlagSet(A)) 01399 sendPimJoinPrune(newRoute->getInIntNextHop(), newRoute->getSource(), newRoute->getGroup(), newRoute->getInIntId()); 01400 01401 // FIXME set timer which I do not use 01402 } 01403 01404 // add new route record to multicast routing table 01405 mrt->addRoute(newRoute); 01406 EV << "PimSplitter::newMulticast: New route was added to the multicast routing table." << endl; 01407 } 01408