Multicast Routing Modelling In OMNeT++
pimDM.cc
Go to the documentation of this file.
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