INET Framework for OMNeT++/OMNEST
inet::PimDm Class Reference

Implementation of PIM-DM protocol (RFC 3973). More...

#include <PimDm.h>

Inheritance diagram for inet::PimDm:
inet::PimBase inet::RoutingProtocolBase inet::OperationalBase inet::OperationalMixin< cSimpleModule > inet::ILifecycle

Classes

struct  DownstreamInterface
 
class  PimDmOutInterface
 
struct  Route
 
struct  UpstreamInterface
 

Public Member Functions

 PimDm ()
 
virtual ~PimDm ()
 
- Public Member Functions inherited from inet::PimBase
 PimBase (PimInterface::PimMode mode)
 
virtual ~PimBase ()
 
- Public Member Functions inherited from inet::RoutingProtocolBase
 RoutingProtocolBase ()
 
- Public Member Functions inherited from inet::OperationalMixin< cSimpleModule >
virtual ~OperationalMixin ()
 }@ More...
 
- Public Member Functions inherited from inet::ILifecycle
virtual ~ILifecycle ()
 

Static Public Member Functions

const static std::string graftPruneStateString (UpstreamInterface::GraftPruneState ps)
 
const static std::string originatorStateString (UpstreamInterface::OriginatorState os)
 
const static std::string pruneStateString (DownstreamInterface::PruneState ps)
 

Protected Member Functions

virtual int numInitStages () const override
 
virtual void handleMessageWhenUp (cMessage *msg) override
 
virtual void initialize (int stage) override
 
virtual void handleStartOperation (LifecycleOperation *operation) override
 
virtual void handleStopOperation (LifecycleOperation *operation) override
 
virtual void handleCrashOperation (LifecycleOperation *operation) override
 
virtual void stopPIMRouting ()
 
- Protected Member Functions inherited from inet::PimBase
void sendHelloPackets ()
 
void sendHelloPacket (PimInterface *pimInterface)
 
void processHelloTimer (cMessage *timer)
 
void processHelloPacket (Packet *pk)
 
- Protected Member Functions inherited from inet::RoutingProtocolBase
virtual bool isInitializeStage (int stage) const override
 
virtual bool isModuleStartStage (int stage) const override
 
virtual bool isModuleStopStage (int stage) const override
 
- Protected Member Functions inherited from inet::OperationalMixin< cSimpleModule >
virtual int numInitStages () const override
 
virtual void refreshDisplay () const override
 
virtual void handleMessage (cMessage *msg) override
 
virtual void handleMessageWhenDown (cMessage *msg)
 
virtual bool handleOperationStage (LifecycleOperation *operation, IDoneCallback *doneCallback) override
 Perform one stage of a lifecycle operation. More...
 
virtual State getInitialOperationalState () const
 Returns initial operational state: OPERATING or NOT_OPERATING. More...
 
virtual void handleActiveOperationTimeout (cMessage *message)
 
virtual bool isUp () const
 utility functions More...
 
virtual bool isDown () const
 
virtual void setOperationalState (State newState)
 
virtual void scheduleOperationTimeout (simtime_t timeout)
 
virtual void setupActiveOperation (LifecycleOperation *operation, IDoneCallback *doneCallback, State)
 
virtual void delayActiveOperationFinish (simtime_t timeout)
 
virtual void startActiveOperationExtraTime (simtime_t delay=SIMTIME_ZERO)
 
virtual void startActiveOperationExtraTimeOrFinish (simtime_t extraTime)
 
virtual void finishActiveOperation ()
 

Private Types

typedef std::map< SourceAndGroup, Route * > RoutingTable
 

Private Member Functions

void receiveSignal (cComponent *source, simsignal_t signalID, cObject *obj, cObject *details) override
 
void unroutableMulticastPacketArrived (Ipv4Address srcAddress, Ipv4Address destAddress, unsigned short ttl)
 The method process notification about new multicast data stream. More...
 
void multicastPacketArrivedOnNonRpfInterface (Ipv4Address group, Ipv4Address source, int interfaceId)
 The method has to solve the problem when multicast data appears on non-RPF interface. More...
 
void multicastPacketArrivedOnRpfInterface (int interfaceId, Ipv4Address group, Ipv4Address source, unsigned short ttl)
 
void multicastReceiverAdded (NetworkInterface *ie, Ipv4Address newAddr)
 
void multicastReceiverRemoved (NetworkInterface *ie, Ipv4Address oldAddr)
 The method process notification about multicast groups removed from interface. More...
 
void rpfInterfaceHasChanged (Ipv4MulticastRoute *route, Ipv4Route *routeToSource)
 The method process notification about interface change. More...
 
void processPruneTimer (cMessage *timer)
 
void processPrunePendingTimer (cMessage *timer)
 
void processGraftRetryTimer (cMessage *timer)
 
void processOverrideTimer (cMessage *timer)
 
void processSourceActiveTimer (cMessage *timer)
 
void processStateRefreshTimer (cMessage *timer)
 
void processAssertTimer (cMessage *timer)
 
void processJoinPrunePacket (Packet *pk)
 
void processGraftPacket (Packet *pk)
 
void processGraftAckPacket (Packet *pk)
 
void processStateRefreshPacket (Packet *pk)
 The method is used to process PimStateRefresh packet. More...
 
void processAssertPacket (Packet *pk)
 
void processPrune (Route *route, int intId, int holdTime, int numRpfNeighbors, Ipv4Address upstreamNeighborField)
 The method process PIM Prune packet. More...
 
void processJoin (Route *route, int intId, int numRpfNeighbors, Ipv4Address upstreamNeighborField)
 
void processGraft (Ipv4Address source, Ipv4Address group, Ipv4Address sender, int intId)
 The method is used to process PimGraft packet. More...
 
void processAssert (Interface *downstream, AssertMetric receivedMetric, int stateRefreshInterval)
 
void processOlistEmptyEvent (Route *route)
 
void processOlistNonEmptyEvent (Route *route)
 
void sendPrunePacket (Ipv4Address nextHop, Ipv4Address src, Ipv4Address grp, int holdTime, int intId)
 
void sendJoinPacket (Ipv4Address nextHop, Ipv4Address source, Ipv4Address group, int interfaceId)
 
void sendGraftPacket (Ipv4Address nextHop, Ipv4Address src, Ipv4Address grp, int intId)
 
void sendGraftAckPacket (Packet *pk, const Ptr< const PimGraft > &graftPacket)
 
void sendStateRefreshPacket (Ipv4Address originator, Route *route, DownstreamInterface *downstream, unsigned short ttl)
 
void sendAssertPacket (Ipv4Address source, Ipv4Address group, AssertMetric metric, NetworkInterface *ie)
 
void sendToIP (Packet *packet, Ipv4Address source, Ipv4Address dest, int outInterfaceId)
 
void restartTimer (cMessage *timer, double interval)
 
void cancelAndDeleteTimer (cMessage *&timer)
 
PimInterfacegetIncomingInterface (NetworkInterface *fromIE)
 
Ipv4MulticastRoutefindIpv4MulticastRoute (Ipv4Address group, Ipv4Address source)
 
RoutefindRoute (Ipv4Address source, Ipv4Address group)
 
void deleteRoute (Ipv4Address source, Ipv4Address group)
 
void clearRoutes ()
 

Private Attributes

double pruneInterval = 0
 
double pruneLimitInterval = 0
 
double overrideInterval = 0
 
double propagationDelay = 0
 
double graftRetryInterval = 0
 
double sourceActiveInterval = 0
 
double stateRefreshInterval = 0
 
double assertTime = 0
 
RoutingTable routes
 

Static Private Attributes

static simsignal_t sentGraftPkSignal = registerSignal("sentGraftPk")
 
static simsignal_t rcvdGraftPkSignal = registerSignal("rcvdGraftPk")
 
static simsignal_t sentGraftAckPkSignal = registerSignal("sentGraftAckPk")
 
static simsignal_t rcvdGraftAckPkSignal = registerSignal("rcvdGraftAckPk")
 
static simsignal_t sentJoinPrunePkSignal = registerSignal("sentJoinPrunePk")
 
static simsignal_t rcvdJoinPrunePkSignal = registerSignal("rcvdJoinPrunePk")
 
static simsignal_t sentAssertPkSignal = registerSignal("sentAssertPk")
 
static simsignal_t rcvdAssertPkSignal = registerSignal("rcvdAssertPk")
 
static simsignal_t sentStateRefreshPkSignal = registerSignal("sentStateRefreshPk")
 
static simsignal_t rcvdStateRefreshPkSignal = registerSignal("rcvdStateRefreshPk")
 

Friends

std::ostream & operator<< (std::ostream &out, const PimDm::Route &sourceGroup)
 

Additional Inherited Members

- Protected Types inherited from inet::PimBase
enum  PimTimerKind {
  HelloTimer = 1, TriggeredHelloDelay, AssertTimer, PruneTimer,
  PrunePendingTimer, GraftRetryTimer, UpstreamOverrideTimer, PruneLimitTimer,
  SourceActiveTimer, StateRefreshTimer, KeepAliveTimer, RegisterStopTimer,
  ExpiryTimer, JoinTimer
}
 
- Protected Types inherited from inet::OperationalMixin< cSimpleModule >
enum  State
 
- Protected Attributes inherited from inet::PimBase
ModuleRefByPar< IIpv4RoutingTablert
 
ModuleRefByPar< IInterfaceTableift
 
ModuleRefByPar< PimInterfaceTablepimIft
 
ModuleRefByPar< PimNeighborTablepimNbt
 
opp_component_ptr< PimpimModule
 
bool isUp = false
 
bool isEnabled = false
 
const char * hostname = nullptr
 
double helloPeriod = 0
 
double holdTime = 0
 
int designatedRouterPriority = 0
 
PimInterface::PimMode mode = static_cast<PimInterface::PimMode>(0)
 
uint32_t generationID = 0
 
cMessage * helloTimer = nullptr
 
- Protected Attributes inherited from inet::OperationalMixin< cSimpleModule >
State operationalState
 
simtime_t lastChange
 
Operation activeOperation
 
cMessage * activeOperationTimeout
 
cMessage * activeOperationExtraTimer
 
- Static Protected Attributes inherited from inet::PimBase
static const Ipv4Address ALL_PIM_ROUTERS_MCAST
 
static simsignal_t sentHelloPkSignal = registerSignal("sentHelloPk")
 
static simsignal_t rcvdHelloPkSignal = registerSignal("rcvdHelloPk")
 

Detailed Description

Implementation of PIM-DM protocol (RFC 3973).

Member Typedef Documentation

◆ RoutingTable

typedef std::map<SourceAndGroup, Route *> inet::PimDm::RoutingTable
private

Constructor & Destructor Documentation

◆ PimDm()

inet::PimDm::PimDm ( )
inline

◆ ~PimDm()

inet::PimDm::~PimDm ( )
virtual
35 {
36  for (auto& elem : routes)
37  delete elem.second;
38  routes.clear();
39 }

Member Function Documentation

◆ cancelAndDeleteTimer()

void inet::PimDm::cancelAndDeleteTimer ( cMessage *&  timer)
private
1691 {
1692  cancelAndDelete(timer);
1693  timer = nullptr;
1694 }

◆ clearRoutes()

void inet::PimDm::clearRoutes ( )
private
1730 {
1731  // delete Ipv4 routes
1732  bool changed = true;
1733  while (changed) {
1734  changed = false;
1735  for (int i = 0; i < rt->getNumMulticastRoutes(); i++) {
1736  Ipv4MulticastRoute *ipv4Route = rt->getMulticastRoute(i);
1737  if (ipv4Route->getSource() == this) {
1738  rt->deleteMulticastRoute(ipv4Route);
1739  changed = true;
1740  break;
1741  }
1742  }
1743  }
1744 
1745  // clear local table
1746  for (auto& elem : routes)
1747  delete elem.second;
1748  routes.clear();
1749 }

Referenced by stopPIMRouting().

◆ deleteRoute()

void inet::PimDm::deleteRoute ( Ipv4Address  source,
Ipv4Address  group 
)
private
1721 {
1722  auto it = routes.find(SourceAndGroup(source, group));
1723  if (it != routes.end()) {
1724  delete it->second;
1725  routes.erase(it);
1726  }
1727 }

Referenced by processSourceActiveTimer().

◆ findIpv4MulticastRoute()

Ipv4MulticastRoute * inet::PimDm::findIpv4MulticastRoute ( Ipv4Address  group,
Ipv4Address  source 
)
private
1704 {
1705  int numRoutes = rt->getNumMulticastRoutes();
1706  for (int i = 0; i < numRoutes; i++) {
1707  Ipv4MulticastRoute *route = rt->getMulticastRoute(i);
1708  if (route->getSource() == this && route->getMulticastGroup() == group && route->getOrigin() == source)
1709  return route;
1710  }
1711  return nullptr;
1712 }

Referenced by processSourceActiveTimer().

◆ findRoute()

PimDm::Route * inet::PimDm::findRoute ( Ipv4Address  source,
Ipv4Address  group 
)
private

◆ getIncomingInterface()

PimInterface * inet::PimDm::getIncomingInterface ( NetworkInterface fromIE)
private
1697 {
1698  if (fromIE)
1699  return pimIft->getInterfaceById(fromIE->getInterfaceId());
1700  return nullptr;
1701 }

Referenced by receiveSignal().

◆ graftPruneStateString()

const std::string inet::PimDm::graftPruneStateString ( UpstreamInterface::GraftPruneState  ps)
static
1967 {
1969  return "FORWARDING";
1970  else if (ps == UpstreamInterface::PRUNED)
1971  return "PRUNED";
1972  else if (ps == UpstreamInterface::ACK_PENDING)
1973  return "ACK_PENDING";
1974 
1975  return "UNKNOWN";
1976 }

Referenced by inet::operator<<().

◆ handleCrashOperation()

void inet::PimDm::handleCrashOperation ( LifecycleOperation operation)
overrideprotectedvirtual

Reimplemented from inet::PimBase.

86 {
89 }

◆ handleMessageWhenUp()

void inet::PimDm::handleMessageWhenUp ( cMessage *  msg)
overrideprotectedvirtual

Implements inet::OperationalMixin< cSimpleModule >.

110 {
111  if (msg->isSelfMessage()) {
112  switch (msg->getKind()) {
113  case HelloTimer:
114  processHelloTimer(msg);
115  break;
116 
117  case AssertTimer:
118  processAssertTimer(msg);
119  break;
120 
121  case PruneTimer:
122  processPruneTimer(msg);
123  break;
124 
125  case PrunePendingTimer:
127  break;
128 
129  case GraftRetryTimer:
131  break;
132 
135  break;
136 
137  case PruneLimitTimer:
138  break;
139 
140  case SourceActiveTimer:
142  break;
143 
144  case StateRefreshTimer:
146  break;
147 
148  default:
149  throw cRuntimeError("PimDm: unknown self message: %s (%s)", msg->getName(), msg->getClassName());
150  }
151  }
152  else {
153  Packet *pk = check_and_cast<Packet *>(msg);
154  const auto& pkt = pk->peekAtFront<PimPacket>();
155  if (pkt == nullptr)
156  throw cRuntimeError("PimDm: received unknown message: %s (%s).", msg->getName(), msg->getClassName());
157 
158  if (!isEnabled) {
159  EV_DETAIL << "PIM-DM is disabled, dropping packet.\n";
160  delete msg;
161  return;
162  }
163 
164  switch (pkt->getType()) {
165  case Hello:
166  processHelloPacket(pk);
167  break;
168 
169  case JoinPrune:
171  break;
172 
173  case Assert:
175  break;
176 
177  case Graft:
178  processGraftPacket(pk);
179  break;
180 
181  case GraftAck:
183  break;
184 
185  case StateRefresh:
187  break;
188 
189  default:
190  EV_WARN << "Dropping packet " << pk->getName() << ".\n";
191  delete pk;
192  break;
193  }
194  }
195 }

◆ handleStartOperation()

void inet::PimDm::handleStartOperation ( LifecycleOperation operation)
overrideprotectedvirtual

Reimplemented from inet::PimBase.

58 {
60 
61  // subscribe for notifications
62  if (isEnabled) {
63  cModule *host = findContainingNode(this);
64  if (!host)
65  throw cRuntimeError("PimDm: containing node not found.");
66  host->subscribe(ipv4NewMulticastSignal, this);
67  host->subscribe(ipv4MulticastGroupRegisteredSignal, this);
68  host->subscribe(ipv4MulticastGroupUnregisteredSignal, this);
69  host->subscribe(ipv4DataOnNonrpfSignal, this);
70  host->subscribe(ipv4DataOnRpfSignal, this);
71  host->subscribe(routeAddedSignal, this);
72  host->subscribe(interfaceStateChangedSignal, this);
73 
74  WATCH_PTRMAP(routes);
75  }
76 }

◆ handleStopOperation()

void inet::PimDm::handleStopOperation ( LifecycleOperation operation)
overrideprotectedvirtual

Reimplemented from inet::PimBase.

79 {
80  // TODO send PIM Hellos to neighbors with 0 HoldTime
83 }

◆ initialize()

void inet::PimDm::initialize ( int  stage)
overrideprotectedvirtual

Reimplemented from inet::PimBase.

42 {
43  PimBase::initialize(stage);
44 
45  if (stage == INITSTAGE_LOCAL) {
46  pruneInterval = par("pruneInterval");
47  pruneLimitInterval = par("pruneLimitInterval");
48  overrideInterval = par("overrideInterval");
49  propagationDelay = par("propagationDelay");
50  graftRetryInterval = par("graftRetryInterval");
51  sourceActiveInterval = par("sourceActiveInterval");
52  stateRefreshInterval = par("stateRefreshInterval");
53  assertTime = par("assertTime");
54  }
55 }

◆ multicastPacketArrivedOnNonRpfInterface()

void inet::PimDm::multicastPacketArrivedOnNonRpfInterface ( Ipv4Address  group,
Ipv4Address  source,
int  interfaceId 
)
private

The method has to solve the problem when multicast data appears on non-RPF interface.

It can happen when there is loop in the network. In this case, router has to prune from the neighbor, so it sends Prune message.

1224 {
1225  EV_DETAIL << "Received multicast datagram (source=" << source << ", group=" << group << ") on non-RPF interface: " << interfaceId << ".\n";
1226 
1227  Route *route = findRoute(source, group);
1228  ASSERT(route);
1229 
1230  UpstreamInterface *upstream = route->upstreamInterface;
1231  DownstreamInterface *downstream = route->findDownstreamInterfaceByInterfaceId(interfaceId);
1232  if (!downstream)
1233  return;
1234 
1235  // in case of p2p link, send prune
1236  // FIXME There should be better indicator of P2P link
1237  if (pimNbt->getNumNeighbors(interfaceId) == 1) {
1238  // send Prune msg to the neighbor who sent these multicast data
1239  Ipv4Address nextHop = (pimNbt->getNeighbor(interfaceId, 0))->getAddress();
1240  sendPrunePacket(nextHop, source, group, pruneInterval, interfaceId);
1241 
1242  // the incoming interface has to change its state to Pruned
1243  if (downstream->pruneState == DownstreamInterface::NO_INFO) {
1244  downstream->pruneState = DownstreamInterface::PRUNED;
1245  downstream->startPruneTimer(pruneInterval);
1246 
1247  // if there is no outgoing interface, Prune msg has to be sent on upstream
1248  if (route->isOilistNull()) {
1249  EV << "Route is not forwarding any more, send Prune to upstream" << endl;
1250  upstream->graftPruneState = UpstreamInterface::PRUNED;
1251  if (!upstream->isSourceDirectlyConnected()) {
1252  sendPrunePacket(upstream->rpfNeighbor(), source, group, pruneInterval, upstream->getInterfaceId());
1253  }
1254  }
1255  }
1256  return;
1257  }
1258 
1259  //
1260  // Assert State Machine; event: An (S,G) data packet arrives on downstream interface I
1261  //
1262  if (downstream->assertState == DownstreamInterface::NO_ASSERT_INFO) {
1263  // An (S,G) data packet arrived on a downstream interface. It is
1264  // optimistically assumed that this router will be the Assert winner
1265  // for this (S,G). The Assert state machine MUST transition to the
1266  // "I am Assert Winner" state, send an Assert(S,G) to interface I,
1267  // store its own address and metric as the Assert Winner, and set
1268  // the Assert_Timer (AT(S,G,I) to Assert_Time, thereby initiating
1269  // the Assert negotiation for (S,G).
1270  downstream->assertState = DownstreamInterface::I_WON_ASSERT;
1271  downstream->winnerMetric = route->metric.setAddress(downstream->ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress());
1272  sendAssertPacket(source, group, route->metric, downstream->ie);
1273  downstream->startAssertTimer(assertTime);
1274  }
1275  else if (downstream->assertState == DownstreamInterface::I_WON_ASSERT) {
1276  // An (S,G) data packet arrived on a downstream interface. The
1277  // Assert state machine remains in the "I am Assert Winner" state.
1278  // The router MUST send an Assert(S,G) to interface I and set the
1279  // Assert Timer (AT(S,G,I) to Assert_Time.
1280  sendAssertPacket(source, group, route->metric, downstream->ie);
1281  restartTimer(downstream->assertTimer, assertTime);
1282  }
1283 }

Referenced by receiveSignal().

◆ multicastPacketArrivedOnRpfInterface()

void inet::PimDm::multicastPacketArrivedOnRpfInterface ( int  interfaceId,
Ipv4Address  group,
Ipv4Address  source,
unsigned short  ttl 
)
private
1286 {
1287  EV_DETAIL << "Multicast datagram arrived: source=" << source << ", group=" << group << ".\n";
1288 
1289  Route *route = findRoute(source, group);
1290  ASSERT(route);
1291  UpstreamInterface *upstream = route->upstreamInterface;
1292 
1293  // RFC 3973 4.5.2.2
1294  //
1295  // Receive Data Packet from S addressed to G
1296  // The router remains in the Originator (O) state and MUST reset
1297  // SAT(S,G) to SourceLifetime. The router SHOULD increase its
1298  // recorded TTL to match the TTL of the packet, if the packet's TTL
1299  // is larger than the previously recorded TTL. A router MAY record
1300  // the TTL based on an implementation specific sampling policy to
1301  // avoid examining the TTL of every multicast packet it handles.
1302 
1303  // Is source directly connected?
1304  if (upstream->isSourceDirectlyConnected()) {
1305  // State Refresh Originator state machine event: Receive Data from S AND S directly connected
1306  if (upstream->originatorState == UpstreamInterface::NOT_ORIGINATOR) {
1307  upstream->originatorState = UpstreamInterface::ORIGINATOR;
1308  PimInterface *pimInterface = pimIft->getInterfaceById(upstream->ie->getInterfaceId());
1309  if (pimInterface && pimInterface->getSR())
1310  upstream->startStateRefreshTimer();
1311  }
1312  restartTimer(upstream->sourceActiveTimer, sourceActiveInterval);
1313 
1314  // record max TTL seen, it is used in StateRefresh messages
1315  upstream->maxTtlSeen = std::max(upstream->maxTtlSeen, ttl);
1316  }
1317 
1318  // upstream state transition
1319 
1320  // Data Packet arrives on RPF_Interface(S) AND olist(S,G) == nullptr AND S is NOT directly connected ?
1321  if (upstream->ie->getInterfaceId() == interfaceId && route->isOilistNull() && !upstream->isSourceDirectlyConnected()) {
1322  EV_DETAIL << "Route does not have any outgoing interface and source is not directly connected.\n";
1323 
1324  switch (upstream->graftPruneState) {
1326  // The Upstream(S,G) state machine MUST transition to the Pruned (P)
1327  // state, send a Prune(S,G) to RPF'(S), and set PLT(S,G) to t_limit seconds.
1328  sendPrunePacket(upstream->rpfNeighbor(), source, group, pruneInterval, upstream->getInterfaceId());
1329  upstream->startPruneLimitTimer();
1330  upstream->graftPruneState = UpstreamInterface::PRUNED;
1331  break;
1332 
1334  // Either another router on the LAN desires traffic from S addressed
1335  // to G or a previous Prune was lost. To prevent generating a
1336  // Prune(S,G) in response to every data packet, the PruneLimit Timer
1337  // (PLT(S,G)) is used. Once the PLT(S,G) expires, the router needs
1338  // to send another prune in response to a data packet not received
1339  // directly from the source. A Prune(S,G) MUST be sent to RPF'(S),
1340  // and the PLT(S,G) MUST be set to t_limit.
1341  //
1342  // if GRT is running now, do not send Prune msg
1343  if (!upstream->isPruneLimitTimerRunning()) {
1344  sendPrunePacket(upstream->rpfNeighbor(), source, group, pruneInterval, upstream->getInterfaceId());
1345  upstream->startPruneLimitTimer();
1346  }
1347  break;
1348 
1350  break;
1351  }
1352  }
1353 }

Referenced by receiveSignal().

◆ multicastReceiverAdded()

void inet::PimDm::multicastReceiverAdded ( NetworkInterface ie,
Ipv4Address  newAddr 
)
private
1144 {
1145  EV_DETAIL << "Multicast receiver added for group " << group << ".\n";
1146 
1147  for (int i = 0; i < rt->getNumMulticastRoutes(); i++) {
1148  Ipv4MulticastRoute *ipv4Route = rt->getMulticastRoute(i);
1149 
1150  // check group
1151  if (ipv4Route->getSource() != this || ipv4Route->getMulticastGroup() != group)
1152  continue;
1153 
1154  Route *route = findRoute(ipv4Route->getOrigin(), group);
1155  ASSERT(route);
1156 
1157  // check on RPF interface
1158  UpstreamInterface *upstream = route->upstreamInterface;
1159  if (upstream->ie == ie)
1160  continue;
1161 
1162  // is interface in list of outgoing interfaces?
1163  DownstreamInterface *downstream = route->findDownstreamInterfaceByInterfaceId(ie->getInterfaceId());
1164  if (downstream) {
1165  EV << "Interface is already on list of outgoing interfaces" << endl;
1166  if (downstream->pruneState == DownstreamInterface::PRUNED)
1167  downstream->pruneState = DownstreamInterface::NO_INFO;
1168  }
1169  else {
1170  // create new downstream data
1171  EV << "Interface is not on list of outgoing interfaces yet, it will be added" << endl;
1172  downstream = route->createDownstreamInterface(ie);
1173  ipv4Route->addOutInterface(new PimDmOutInterface(ie, downstream));
1174  }
1175 
1176  downstream->setHasConnectedReceivers(true);
1177 
1178  // fire upstream state machine event
1179  if (upstream->graftPruneState == UpstreamInterface::PRUNED && downstream->isInOlist())
1181  }
1182 }

Referenced by receiveSignal().

◆ multicastReceiverRemoved()

void inet::PimDm::multicastReceiverRemoved ( NetworkInterface ie,
Ipv4Address  group 
)
private

The method process notification about multicast groups removed from interface.

For each old address it tries to find route. If there is route, it finds interface in list of outgoing interfaces. If the interface is in the list it will be removed. If the router was not pruned and there is no outgoing interface, the router will prune from the multicast tree.

1191 {
1192  EV_DETAIL << "No more receiver for group " << group << " on interface '" << ie->getInterfaceName() << "'.\n";
1193 
1194  // delete pimInt from outgoing interfaces of multicast routes for group
1195  for (int i = 0; i < rt->getNumMulticastRoutes(); i++) {
1196  Ipv4MulticastRoute *ipv4Route = rt->getMulticastRoute(i);
1197  if (ipv4Route->getSource() == this && ipv4Route->getMulticastGroup() == group) {
1198  Route *route = findRoute(ipv4Route->getOrigin(), group);
1199  ASSERT(route);
1200 
1201  // remove pimInt from the list of outgoing interfaces
1202  DownstreamInterface *downstream = route->findDownstreamInterfaceByInterfaceId(ie->getInterfaceId());
1203  if (downstream) {
1204  bool wasInOlist = downstream->isInOlist();
1205  downstream->setHasConnectedReceivers(false);
1206  if (wasInOlist && !downstream->isInOlist()) {
1207  EV_DEBUG << "Removed interface '" << ie->getInterfaceName() << "' from the outgoing interface list of route " << route << ".\n";
1208 
1209  // fire upstream state machine event
1210  if (route->isOilistNull())
1211  processOlistEmptyEvent(route);
1212  }
1213  }
1214  }
1215  }
1216 }

Referenced by receiveSignal().

◆ numInitStages()

virtual int inet::PimDm::numInitStages ( ) const
inlineoverrideprotectedvirtual

Reimplemented from inet::PimBase.

240 { return NUM_INIT_STAGES; }

◆ originatorStateString()

const std::string inet::PimDm::originatorStateString ( UpstreamInterface::OriginatorState  os)
static
1979 {
1981  return "NOT_ORIGINATOR";
1982  else if (os == UpstreamInterface::ORIGINATOR)
1983  return "ORIGINATOR";
1984 
1985  return "UNKNOWN";
1986 }

Referenced by inet::operator<<().

◆ processAssert()

void inet::PimDm::processAssert ( Interface downstream,
AssertMetric  receivedMetric,
int  stateRefreshInterval 
)
private
923 {
924  Route *route = check_and_cast<Route *>(incomingInterface->owner);
925  UpstreamInterface *upstream = route->upstreamInterface;
926 
927  //
928  // Assert State Machine
929  //
930  AssertMetric currentMetric = incomingInterface->assertState == Interface::NO_ASSERT_INFO ?
931  route->metric.setAddress(incomingInterface->ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress()) :
932  incomingInterface->winnerMetric;
933  bool isEqual = receivedMetric == currentMetric;
934  bool isBetter = receivedMetric < currentMetric;
935  bool couldAssert = incomingInterface != upstream;
936 
937  // event: Received Preferred Assert
938  if (isBetter || isEqual) {
939  if (incomingInterface->assertState == Interface::NO_ASSERT_INFO) {
940  // The received Assert or State Refresh has a better metric than
941  // this router's, and therefore the Assert state machine MUST
942  // transition to the "I am Assert Loser" state and store the Assert
943  // Winner's address and metric. If the metric was received in an
944  // Assert, the router MUST set the Assert Timer (AT(S,G,I)) to
945  // Assert_Time. If the metric was received in a State Refresh, the
946  // router MUST set the Assert Timer (AT(S,G,I)) to three times the
947  // received State Refresh Interval. If CouldAssert(S,G,I) == TRUE,
948  // the router MUST also multicast a Prune(S,G) to the Assert winner
949  // with a Prune Hold Time equal to the Assert Timer and evaluate any
950  // changes in its Upstream(S,G) state machine.
951  ASSERT(isBetter);
952  EV_DEBUG << "Received better metrics, going to I_LOST_ASSERT state.\n";
953  incomingInterface->assertState = Interface::I_LOST_ASSERT;
954  incomingInterface->winnerMetric = receivedMetric;
956  incomingInterface->startAssertTimer(assertTime);
957  if (couldAssert)
958  sendPrunePacket(incomingInterface->winnerMetric.address, route->source, route->group, assertTime, incomingInterface->ie->getInterfaceId());
959 
960  // upstream state machine
961  if (upstream->graftPruneState != UpstreamInterface::PRUNED && route->isOilistNull())
962  processOlistEmptyEvent(route);
963  }
964  else if (incomingInterface->assertState == Interface::I_WON_ASSERT) {
965  // An (S,G) Assert is received that has a better
966  // metric than this router's metric for S on interface I. The
967  // Assert state machine MUST transition to "I am Assert Loser" state
968  // and store the new Assert Winner's address and metric. The router MUST set the Assert
969  // Timer (AT(S,G,I)) to Assert_Time. The router MUST also
970  // multicast a Prune(S,G) to the Assert winner, with a Prune Hold
971  // Time equal to the Assert Timer, and evaluate any changes in its
972  // Upstream(S,G) state machine.
973  ASSERT(isBetter);
974  EV_DEBUG << "Received better metrics, going to I_LOST_ASSERT state.\n";
975  incomingInterface->assertState = DownstreamInterface::I_LOST_ASSERT;
976  incomingInterface->winnerMetric = receivedMetric;
977  restartTimer(incomingInterface->assertTimer, assertTime);
978  sendPrunePacket(incomingInterface->winnerMetric.address, route->source, route->group, assertTime, incomingInterface->ie->getInterfaceId());
979 
980  // upstream state machine
981  if (upstream->graftPruneState != UpstreamInterface::PRUNED && route->isOilistNull())
982  processOlistEmptyEvent(route);
983  }
984  else if (incomingInterface->assertState == Interface::I_LOST_ASSERT) {
985  // An Assert is received that has a metric better
986  // than or equal to that of the current Assert winner. The Assert
987  // state machine remains in Loser (L) state. If the metric was
988  // received in an Assert, the router MUST set the Assert Timer
989  // (AT(S,G,I)) to Assert_Time. The router MUST set the Assert Timer (AT(S,G,I))
990  // to three times the received State Refresh Interval. If the
991  // metric is better than the current Assert Winner, the router MUST
992  // store the address and metric of the new Assert Winner, and if
993  // CouldAssert(S,G,I) == TRUE, the router MUST multicast a
994  // Prune(S,G) to the new Assert winner.
995  EV_DEBUG << "Received better metrics, stay in I_LOST_ASSERT state.\n";
996  restartTimer(incomingInterface->assertTimer, stateRefreshInterval > 0 ? 3 * stateRefreshInterval : assertTime);
997  if (isBetter) {
998  incomingInterface->winnerMetric = receivedMetric;
999  if (couldAssert)
1000  sendPrunePacket(incomingInterface->winnerMetric.address, route->source, route->group, assertTime, incomingInterface->ie->getInterfaceId());
1001  }
1002  }
1003  }
1004  // event: Receive Inferior Assert from Assert Winner
1005  else if (receivedMetric.address == incomingInterface->winnerMetric.address) {
1006  if (incomingInterface->assertState == Interface::I_LOST_ASSERT) {
1007  // An Assert is received from the current Assert
1008  // winner that is worse than this router's metric for S (typically,
1009  // the winner's metric became worse). The Assert state machine MUST
1010  // transition to NoInfo (NI) state and cancel AT(S,G,I). The router
1011  // MUST delete the previous Assert Winner's address and metric and
1012  // evaluate any possible transitions to its Upstream(S,G) state
1013  // machine. Usually this router will eventually re-assert and win
1014  // when data packets from S have started flowing again.
1015  EV_DEBUG << "Assert winner lost best route, going to NO_ASSERT_INFO state.\n";
1016  incomingInterface->deleteAssertInfo();
1017  // upstream state machine
1018  if (upstream->graftPruneState == UpstreamInterface::PRUNED && !route->isOilistNull())
1020  }
1021  }
1022  // event: Receive Inferior Assert from non-Assert Winner AND CouldAssert==TRUE
1023  else if (couldAssert) {
1024  if (incomingInterface->assertState == Interface::NO_ASSERT_INFO) {
1025  // An Assert or State Refresh is received for (S,G) that is inferior
1026  // to our own assert metric on interface I. The Assert state machine
1027  // MUST transition to the "I am Assert Winner" state, send an
1028  // Assert(S,G) to interface I, store its own address and metric as
1029  // the Assert Winner, and set the Assert Timer (AT(S,G,I)) to
1030  // Assert_Time.
1031  EV_DEBUG << "Received inferior assert metrics, going to I_WON_ASSERT state.\n";
1032  incomingInterface->assertState = DownstreamInterface::I_WON_ASSERT;
1033  sendAssertPacket(route->source, route->group, route->metric, incomingInterface->ie);
1034  incomingInterface->startAssertTimer(assertTime);
1035  }
1036  else if (incomingInterface->assertState == DownstreamInterface::I_WON_ASSERT) {
1037  // An (S,G) Assert is received containing a metric for S that is
1038  // worse than this router's metric for S. Whoever sent the Assert
1039  // is in error. The router MUST send an Assert(S,G) to interface I
1040  // and reset the Assert Timer (AT(S,G,I)) to Assert_Time.
1041  EV_DEBUG << "Received inferior assert metrics, stay in I_WON_ASSERT state.\n";
1042  sendAssertPacket(route->source, route->group, route->metric, incomingInterface->ie);
1043  restartTimer(incomingInterface->assertTimer, assertTime);
1044  }
1045  }
1046 }

Referenced by processAssertPacket(), and processStateRefreshPacket().

◆ processAssertPacket()

void inet::PimDm::processAssertPacket ( Packet pk)
private
649 {
650  const auto& pkt = pk->peekAtFront<PimAssert>();
651  int incomingInterfaceId = pk->getTag<InterfaceInd>()->getInterfaceId();
652  Ipv4Address srcAddrFromTag = pk->getTag<L3AddressInd>()->getSrcAddress().toIpv4();
653  Ipv4Address source = pkt->getSourceAddress().unicastAddress.toIpv4();
654  Ipv4Address group = pkt->getGroupAddress().groupAddress.toIpv4();
655  AssertMetric receivedMetric = AssertMetric(pkt->getMetricPreference(), pkt->getMetric(), srcAddrFromTag);
656  Route *route = findRoute(source, group);
657  ASSERT(route); // TODO create S,G state?
658  Interface *incomingInterface = route->upstreamInterface->getInterfaceId() == incomingInterfaceId ?
659  static_cast<Interface *>(route->upstreamInterface) :
660  static_cast<Interface *>(route->findDownstreamInterfaceByInterfaceId(incomingInterfaceId));
661  ASSERT(incomingInterface);
662 
663  EV_INFO << "Received Assert(S=" << source << ", G=" << group
664  << ") packet on interface '" << incomingInterface->ie->getInterfaceName() << "'.\n";
665 
666  emit(rcvdAssertPkSignal, pk);
667 
668  processAssert(incomingInterface, receivedMetric, 0);
669 
670  delete pk;
671 }

Referenced by handleMessageWhenUp().

◆ processAssertTimer()

void inet::PimDm::processAssertTimer ( cMessage *  timer)
private
266 {
267  Interface *interfaceData = static_cast<Interface *>(timer->getContextPointer());
268  ASSERT(timer == interfaceData->assertTimer);
269  ASSERT(interfaceData->assertState != DownstreamInterface::NO_ASSERT_INFO);
270 
271  Route *route = check_and_cast<Route *>(interfaceData->owner);
272  UpstreamInterface *upstream = route->upstreamInterface;
273  EV_DETAIL << "AssertTimer" << route << " interface=" << interfaceData->ie->getInterfaceName() << " has expired.\n";
274 
275  //
276  // Assert State Machine; event: AT(S,G,I) expires
277  //
278 
279  // The Assert state machine MUST transition to NoInfo (NI) state.
280  // The router MUST delete the Assert Winner's address and metric.
281  // If CouldAssert == TRUE, the router MUST evaluate any possible
282  // transitions to its Upstream(S,G) state machine.
283  EV_DEBUG << "Going into NO_ASSERT_INFO state.\n";
284  interfaceData->deleteAssertInfo(); // deletes timer
285 
286  // upstream state machine transition
287  if (interfaceData != upstream) {
288  bool isOlistNull = route->isOilistNull();
289  if (upstream->graftPruneState == UpstreamInterface::PRUNED && !isOlistNull)
291  else if (upstream->graftPruneState != UpstreamInterface::PRUNED && isOlistNull)
292  processOlistEmptyEvent(route);
293  }
294 }

Referenced by handleMessageWhenUp().

◆ processGraft()

void inet::PimDm::processGraft ( Ipv4Address  source,
Ipv4Address  group,
Ipv4Address  sender,
int  incomingInterfaceId 
)
private

The method is used to process PimGraft packet.

Packet means that downstream router wants to join to multicast tree, so the packet cannot come to RPF interface. Router finds correct outgoig interface towards downstream router. Change its state to forward if it was not before and cancel Prune Timer. If route was in pruned state, router will send also Graft message to join multicast tree.

712 {
713  EV_DEBUG << "Processing Graft(S=" << source << ", G=" << group << "), sender=" << sender << "incoming if=" << incomingInterfaceId << endl;
714 
715  Route *route = findRoute(source, group);
716  ASSERT(route);
717 
718  UpstreamInterface *upstream = route->upstreamInterface;
719 
720  // check if message come to non-RPF interface
721  if (upstream->ie->getInterfaceId() == incomingInterfaceId) {
722  EV << "ERROR: Graft message came to RPF interface." << endl;
723  return;
724  }
725 
726  DownstreamInterface *downstream = route->findDownstreamInterfaceByInterfaceId(incomingInterfaceId);
727  if (!downstream)
728  return;
729 
730  //
731  // Downstream Interface State Machine
732  //
733  // Note: GraftAck is sent in processGraftPacket()
734  bool olistChanged = false;
735  switch (downstream->pruneState) {
737  // do nothing
738  break;
739 
741  downstream->stopPrunePendingTimer();
742  downstream->pruneState = DownstreamInterface::NO_INFO;
743  break;
744 
746  EV << "Interface " << downstream->ie->getInterfaceId() << " transit to forwarding state (Graft)." << endl;
747  downstream->stopPruneTimer();
748  downstream->pruneState = DownstreamInterface::NO_INFO;
749  olistChanged = downstream->isInOlist();
750  break;
751  }
752 
753  if (olistChanged)
755 
756  //
757  // Assert State Machine; event: Receive Graft(S,G)
758  //
759  if (downstream->assertState == DownstreamInterface::I_LOST_ASSERT) {
760  // A Graft(S,G) message was received on
761  // interface I with its upstream neighbor address set to the
762  // router's address on I. The router MUST send an Assert(S,G) on
763  // the receiving interface I to initiate an Assert negotiation. The
764  // Assert state machine remains in the Assert Loser(L) state.
765  // The router MUST respond with a GraftAck(S,G).
766  sendAssertPacket(route->source, route->group, route->metric, downstream->ie);
767  }
768 }

Referenced by processGraftPacket().

◆ processGraftAckPacket()

void inet::PimDm::processGraftAckPacket ( Packet pk)
private
771 {
772  const auto& pkt = pk->peekAtFront<PimGraft>();
773  EV_INFO << "Received GraftAck packet.\n";
774 
775  emit(rcvdGraftAckPkSignal, pk);
776 
777  Ipv4Address destAddress = pk->getTag<L3AddressInd>()->getDestAddress().toIpv4();
778 
779  for (unsigned int i = 0; i < pkt->getJoinPruneGroupsArraySize(); i++) {
780  const JoinPruneGroup& group = pkt->getJoinPruneGroups(i);
781  Ipv4Address groupAddr = group.getGroupAddress().groupAddress.toIpv4();
782 
783  for (unsigned int j = 0; j < group.getJoinedSourceAddressArraySize(); j++) {
784  const auto& source = group.getJoinedSourceAddress(j);
785  Route *route = findRoute(source.sourceAddress.toIpv4(), groupAddr);
786  ASSERT(route);
787  UpstreamInterface *upstream = route->upstreamInterface;
788 
789  // If the destination address of the GraftAck packet is not
790  // the address of the upstream interface, then no state transition occur.
791  if (destAddress != upstream->ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress())
792  continue;
793 
794  // upstream state transition
795  // event: Receive GraftAck(S,G) from RPF'(S)
796  if (upstream->graftPruneState == UpstreamInterface::ACK_PENDING) {
797  // A GraftAck is received from RPF'(S). The GraftRetry Timer MUST
798  // be cancelled, and the Upstream(S,G) state machine MUST transition
799  // to the Forwarding(F) state.
800  ASSERT(upstream->graftRetryTimer);
801  cancelAndDelete(upstream->graftRetryTimer);
802  upstream->graftRetryTimer = nullptr;
803  upstream->graftPruneState = UpstreamInterface::FORWARDING;
804  }
805  }
806  }
807 
808  delete pk;
809 }

Referenced by handleMessageWhenUp().

◆ processGraftPacket()

void inet::PimDm::processGraftPacket ( Packet pk)
private
674 {
675  const auto& pkt = pk->peekAtFront<PimGraft>();
676  EV_INFO << "Received Graft packet.\n";
677 
678  emit(rcvdGraftPkSignal, pk);
679 
680  Ipv4Address sender = pk->getTag<L3AddressInd>()->getSrcAddress().toIpv4();
681  NetworkInterface *incomingInterface = ift->getInterfaceById(pk->getTag<InterfaceInd>()->getInterfaceId());
682 
683  // does packet belong to this router?
684  if (pkt->getUpstreamNeighborAddress().unicastAddress != incomingInterface->getProtocolData<Ipv4InterfaceData>()->getIPAddress()) {
685  delete pk;
686  return;
687  }
688 
689  for (unsigned int i = 0; i < pkt->getJoinPruneGroupsArraySize(); i++) {
690  const JoinPruneGroup& group = pkt->getJoinPruneGroups(i);
691  Ipv4Address groupAddr = group.getGroupAddress().groupAddress.toIpv4();
692 
693  for (unsigned int j = 0; j < group.getJoinedSourceAddressArraySize(); j++) {
694  const auto& source = group.getJoinedSourceAddress(j);
695  processGraft(source.sourceAddress.toIpv4(), groupAddr, sender, incomingInterface->getInterfaceId());
696  }
697  }
698 
699  // Send GraftAck for this Graft message
700  sendGraftAckPacket(pk, pkt);
701 
702  delete pk;
703 }

Referenced by handleMessageWhenUp().

◆ processGraftRetryTimer()

void inet::PimDm::processGraftRetryTimer ( cMessage *  timer)
private
365 {
366  EV_INFO << "GraftRetryTimer expired.\n";
367  UpstreamInterface *upstream = static_cast<UpstreamInterface *>(timer->getContextPointer());
368  ASSERT(upstream->graftPruneState == UpstreamInterface::ACK_PENDING);
369  ASSERT(timer == upstream->graftRetryTimer);
370 
371  Route *route = upstream->route();
372  EV_INFO << "GraftRetryTimer" << route << " expired.\n";
373 
374  // The Upstream(S,G) state machine stays in the AckPending (AP)
375  // state. Another Graft message for (S,G) SHOULD be unicast to
376  // RPF'(S) and the GraftRetry Timer (GRT(S,G)) reset to
377  // Graft_Retry_Period. It is RECOMMENDED that the router retry a
378  // configured number of times before ceasing retries.
379  sendGraftPacket(upstream->rpfNeighbor(), route->source, route->group, upstream->getInterfaceId());
380  scheduleAfter(graftRetryInterval, timer);
381 }

Referenced by handleMessageWhenUp().

◆ processJoin()

void inet::PimDm::processJoin ( Route route,
int  intId,
int  numRpfNeighbors,
Ipv4Address  upstreamNeighborField 
)
private
518 {
519  UpstreamInterface *upstream = route->upstreamInterface;
520 
521  // See join to RPF'(S,G) ?
522  if (upstream->ie->getInterfaceId() == intId && numRpfNeighbors > 1) {
523  // TODO check that destAddress == upstream->nextHop
524  if (upstream->graftPruneState == UpstreamInterface::FORWARDING || upstream->graftPruneState == UpstreamInterface::ACK_PENDING) {
525  // If the OT(S,G) is running, then it
526  // means that the router had scheduled a Join to override a
527  // previously received Prune. Another router has responded more
528  // quickly with a Join, so the local router SHOULD cancel its
529  // OT(S,G), if it is running.
530  cancelAndDelete(upstream->overrideTimer);
531  upstream->overrideTimer = nullptr;
532  }
533  }
534 
535  //
536  // Downstream Interface State Machine
537  //
538  DownstreamInterface *downstream = route->findDownstreamInterfaceByInterfaceId(intId);
539  if (!downstream)
540  return;
541 
542  // does packet belong to this router?
543  if (upstreamNeighborField != downstream->ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress())
544  return;
545 
546  if (downstream->pruneState == DownstreamInterface::PRUNE_PENDING)
547  downstream->stopPrunePendingTimer();
548  else if (downstream->pruneState == DownstreamInterface::PRUNED)
549  downstream->stopPruneTimer();
550 
551  downstream->pruneState = DownstreamInterface::NO_INFO;
552 
553  if (upstream->graftPruneState == UpstreamInterface::PRUNED && !route->isOilistNull())
554  processOlistNonEmptyEvent(route); // will send Graft upstream
555 
556  //
557  // Assert State Machine; event: Receive Join(S,G)
558  //
559  if (downstream->assertState == DownstreamInterface::I_LOST_ASSERT) {
560  // A Join(S,G) message was received on
561  // interface I with its upstream neighbor address set to the
562  // router's address on I. The router MUST send an Assert(S,G) on
563  // the receiving interface I to initiate an Assert negotiation. The
564  // Assert state machine remains in the Assert Loser(L) state.
565  sendAssertPacket(route->source, route->group, route->metric, downstream->ie);
566  }
567 }

Referenced by processJoinPrunePacket().

◆ processJoinPrunePacket()

void inet::PimDm::processJoinPrunePacket ( Packet pk)
private
476 {
477  const auto& pkt = pk->peekAtFront<PimJoinPrune>();
478  EV_INFO << "Received JoinPrune packet.\n";
479 
480  emit(rcvdJoinPrunePkSignal, pk);
481 
482  auto ifTag = pk->getTag<InterfaceInd>();
483  NetworkInterface *incomingInterface = ift->getInterfaceById(ifTag->getInterfaceId());
484 
485  if (!incomingInterface) {
486  delete pk;
487  return;
488  }
489 
490  Ipv4Address upstreamNeighborAddress = pkt->getUpstreamNeighborAddress().unicastAddress.toIpv4();
491  int numRpfNeighbors = pimNbt->getNumNeighbors(incomingInterface->getInterfaceId());
492 
493  for (unsigned int i = 0; i < pkt->getJoinPruneGroupsArraySize(); i++) {
494  JoinPruneGroup group = pkt->getJoinPruneGroups(i);
495  Ipv4Address groupAddr = group.getGroupAddress().groupAddress.toIpv4();
496 
497  // go through list of joined sources
498  for (unsigned int j = 0; j < group.getJoinedSourceAddressArraySize(); j++) {
499  const auto& source = group.getJoinedSourceAddress(j);
500  Route *route = findRoute(source.sourceAddress.toIpv4(), groupAddr);
501  ASSERT(route);
502  processJoin(route, incomingInterface->getInterfaceId(), numRpfNeighbors, upstreamNeighborAddress);
503  }
504 
505  // go through list of pruned sources
506  for (unsigned int j = 0; j < group.getPrunedSourceAddressArraySize(); j++) {
507  const auto& source = group.getPrunedSourceAddress(j);
508  Route *route = findRoute(source.sourceAddress.toIpv4(), groupAddr);
509  ASSERT(route);
510  processPrune(route, incomingInterface->getInterfaceId(), pkt->getHoldTime(), numRpfNeighbors, upstreamNeighborAddress);
511  }
512  }
513 
514  delete pk;
515 }

Referenced by handleMessageWhenUp().

◆ processOlistEmptyEvent()

void inet::PimDm::processOlistEmptyEvent ( Route route)
private
1631 {
1632  UpstreamInterface *upstream = route->upstreamInterface;
1633 
1634  // upstream state transitions
1635 
1636  // olist(S,G) -> nullptr AND S NOT directly connected?
1637  if (!upstream->isSourceDirectlyConnected()) {
1638  if (upstream->graftPruneState == UpstreamInterface::FORWARDING || upstream->graftPruneState == UpstreamInterface::ACK_PENDING) {
1639  // The Upstream(S,G) state machine MUST
1640  // transition to the Pruned (P) state. A Prune(S,G) MUST be
1641  // multicast to the RPF_interface(S), with RPF'(S) named in the
1642  // upstream neighbor field. The GraftRetry Timer (GRT(S,G)) MUST be
1643  // cancelled, and PLT(S,G) MUST be set to t_limit seconds.
1644  sendPrunePacket(upstream->rpfNeighbor(), route->source, route->group, pruneInterval, upstream->getInterfaceId());
1645  upstream->startPruneLimitTimer();
1646  if (upstream->graftPruneState == UpstreamInterface::ACK_PENDING) {
1647  cancelAndDelete(upstream->graftRetryTimer);
1648  upstream->graftRetryTimer = nullptr;
1649  }
1650  }
1651  }
1652 
1653  upstream->graftPruneState = UpstreamInterface::PRUNED;
1654 }

Referenced by multicastReceiverRemoved(), processAssert(), processAssertTimer(), and processPrunePendingTimer().

◆ processOlistNonEmptyEvent()

void inet::PimDm::processOlistNonEmptyEvent ( Route route)
private
1657 {
1658  // upstream state transition: Pruned->AckPending if olist is not empty
1659  // if all route was pruned, remove prune flag
1660  // if upstrem is not source, send Graft message
1661  UpstreamInterface *upstream = route->upstreamInterface;
1662  if (upstream->graftPruneState == UpstreamInterface::PRUNED) {
1663  // olist(S,G)->non-nullptr AND S NOT directly connected
1664  //
1665  // The set of interfaces defined by the olist(S,G) macro becomes
1666  // non-empty, indicating that traffic from S addressed to group G
1667  // must be forwarded. The Upstream(S,G) state machine MUST cancel
1668  // PLT(S,G), transition to the AckPending (AP) state and unicast a
1669  // Graft message to RPF'(S). The Graft Retry Timer (GRT(S,G)) MUST
1670  // be set to Graft_Retry_Period.
1671 
1672  if (!upstream->isSourceDirectlyConnected()) {
1673  EV << "Route is not pruned any more, send Graft to upstream" << endl;
1674  sendGraftPacket(upstream->rpfNeighbor(), route->source, route->group, upstream->getInterfaceId());
1675  upstream->stopPruneLimitTimer();
1676  upstream->startGraftRetryTimer();
1677  upstream->graftPruneState = UpstreamInterface::ACK_PENDING;
1678  }
1679  else {
1680  upstream->graftPruneState = UpstreamInterface::FORWARDING;
1681  }
1682  }
1683 }

Referenced by multicastReceiverAdded(), processAssert(), processAssertTimer(), processGraft(), processJoin(), and processPruneTimer().

◆ processOverrideTimer()

void inet::PimDm::processOverrideTimer ( cMessage *  timer)
private
384 {
385  UpstreamInterface *upstream = static_cast<UpstreamInterface *>(timer->getContextPointer());
386  ASSERT(timer == upstream->overrideTimer);
387  ASSERT(upstream->graftPruneState != UpstreamInterface::PRUNED);
388 
389  Route *route = upstream->route();
390  EV_INFO << "OverrideTimer" << route << " expired.\n";
391 
392  // send a Join(S,G) to RPF'(S)
393  sendJoinPacket(upstream->rpfNeighbor(), route->source, route->group, upstream->getInterfaceId());
394 
395  upstream->overrideTimer = nullptr;
396  delete timer;
397 }

Referenced by handleMessageWhenUp().

◆ processPrune()

void inet::PimDm::processPrune ( Route route,
int  intId,
int  holdTime,
int  numRpfNeighbors,
Ipv4Address  upstreamNeighborField 
)
private

The method process PIM Prune packet.

First the method has to find correct outgoing interface where PIM Prune packet came to. The method also checks if there is still any forwarding outgoing interface. Forwarding interfaces, where Prune packet come to, goes to prune state. If all outgoing interfaces are pruned, the router will prune from multicast tree.

576 {
577  EV_INFO << "Processing Prune" << route << ".\n";
578 
579  //
580  // Upstream Interface State Machine; event: See Prune(S,G)
581  //
582 
583  // See Prune(S,G) AND S is NOT directly connected ?
584  UpstreamInterface *upstream = route->upstreamInterface;
585  if (upstream->ie->getInterfaceId() == intId && !upstream->isSourceDirectlyConnected()) {
586  // This event is only relevant if RPF_interface(S) is a shared
587  // medium. This router sees another router on RPF_interface(S) send
588  // a Prune(S,G). When this router is in Forwarding/AckPending state, it must
589  // override the Prune after a short random interval. If OT(S,G) is
590  // not running, the router MUST set OT(S,G) to t_override seconds.
591  // The Upstream(S,G) state machine remains in Forwarding/AckPending state.
592  if (upstream->graftPruneState == UpstreamInterface::FORWARDING || upstream->graftPruneState == UpstreamInterface::ACK_PENDING) {
593  if (!upstream->overrideTimer)
594  upstream->startOverrideTimer();
595  }
596  }
597 
598  // we find correct outgoing interface
599  DownstreamInterface *downstream = route->findDownstreamInterfaceByInterfaceId(intId);
600  if (!downstream)
601  return;
602 
603  // does packet belong to this router?
604  if (upstreamNeighborField != downstream->ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress())
605  return;
606 
607  //
608  // Downstream Interface State Machine; event: Receive Prune(S,G)
609  //
610 
611  // A Prune(S,G) is received on interface I with the upstream
612  // neighbor field set to the router's address on I.
613  if (downstream->pruneState == DownstreamInterface::NO_INFO) {
614  // The Prune(S,G) Downstream state machine on interface I MUST transition to the
615  // PrunePending (PP) state. The PrunePending Timer (PPT(S,G,I))
616  // MUST be set to J/P_Override_Interval if the router has more than
617  // one neighbor on I. If the router has only one neighbor on
618  // interface I, then it SHOULD set the PPT(S,G,I) to zero,
619  // effectively transitioning immediately to the Pruned (P) state.
620  double prunePendingInterval = numRpfNeighbors > 1 ? overrideInterval + propagationDelay : 0;
621  downstream->startPrunePendingTimer(prunePendingInterval);
622  downstream->pruneState = DownstreamInterface::PRUNE_PENDING;
623  }
624  else if (downstream->pruneState == DownstreamInterface::PRUNED) {
625  // The Prune(S,G) Downstream state machine on interface I remains in the Pruned (P)
626  // state. The Prune Timer (PT(S,G,I)) SHOULD be reset to the
627  // holdtime contained in the Prune(S,G) message if it is greater
628  // than the current value.
629  EV << "Outgoing interface is already pruned, restart Prune Timer." << endl;
630  if (downstream->pruneTimer->getArrivalTime() < simTime() + holdTime)
631  restartTimer(downstream->pruneTimer, holdTime);
632  }
633 
634  //
635  // Assert state machine; event: Receive Prune(S,G)
636  //
637  if (downstream->assertState == DownstreamInterface::I_LOST_ASSERT) {
638  // Receive Prune(S,G)
639  // A Prune(S,G) message was received on
640  // interface I with its upstream neighbor address set to the
641  // router's address on I. The router MUST send an Assert(S,G) on
642  // the receiving interface I to initiate an Assert negotiation. The
643  // Assert state machine remains in the Assert Loser(L) state.
644  sendAssertPacket(route->source, route->group, route->metric, downstream->ie);
645  }
646 }

Referenced by processJoinPrunePacket().

◆ processPrunePendingTimer()

void inet::PimDm::processPrunePendingTimer ( cMessage *  timer)
private
340 {
341  DownstreamInterface *downstream = static_cast<DownstreamInterface *>(timer->getContextPointer());
342  ASSERT(timer == downstream->prunePendingTimer);
343  ASSERT(downstream->pruneState == DownstreamInterface::PRUNE_PENDING);
344 
345  delete timer;
346  downstream->prunePendingTimer = nullptr;
347 
348  Route *route = downstream->route();
349  EV_INFO << "PrunePendingTimer" << route << " has expired.\n";
350 
351  //
352  // go to pruned state
353  downstream->pruneState = DownstreamInterface::PRUNED;
354  double holdTime = pruneInterval - overrideInterval - propagationDelay; // TODO should be received HoldTime - computed override interval;
355  downstream->startPruneTimer(holdTime);
356 
357  // TODO optionally send PruneEcho
358 
359  // upstream state change if olist become nullptr
360  if (route->isOilistNull())
361  processOlistEmptyEvent(route);
362 }

Referenced by handleMessageWhenUp().

◆ processPruneTimer()

void inet::PimDm::processPruneTimer ( cMessage *  timer)
private
304 {
305  DownstreamInterface *downstream = static_cast<DownstreamInterface *>(timer->getContextPointer());
306  ASSERT(timer == downstream->pruneTimer);
307  ASSERT(downstream->pruneState == DownstreamInterface::PRUNED);
308 
309  Route *route = downstream->route();
310  EV_INFO << "PruneTimer" << route << " expired.\n";
311 
312  // state of interface is changed to forwarding
313  downstream->stopPruneTimer();
314  downstream->pruneState = DownstreamInterface::NO_INFO;
315 
316  // upstream state change if olist become non nullptr
317  if (!route->isOilistNull())
319 }

Referenced by handleMessageWhenUp().

◆ processSourceActiveTimer()

void inet::PimDm::processSourceActiveTimer ( cMessage *  timer)
private
405 {
406  UpstreamInterface *upstream = static_cast<UpstreamInterface *>(timer->getContextPointer());
407  ASSERT(timer == upstream->sourceActiveTimer);
408  ASSERT(upstream->originatorState == UpstreamInterface::ORIGINATOR);
409 
410  Route *route = upstream->route();
411  EV_INFO << "SourceActiveTimer" << route << " expired.\n";
412 
413  upstream->originatorState = UpstreamInterface::NOT_ORIGINATOR;
414  cancelAndDelete(upstream->stateRefreshTimer);
415  upstream->stateRefreshTimer = nullptr;
416 
417  // delete the route, because there are no more packets
418  Ipv4Address routeSource = route->source;
419  Ipv4Address routeGroup = route->group;
420  deleteRoute(routeSource, routeGroup);
421  Ipv4MulticastRoute *ipv4Route = findIpv4MulticastRoute(routeGroup, routeSource);
422  if (ipv4Route)
423  rt->deleteMulticastRoute(ipv4Route);
424 }

Referenced by handleMessageWhenUp().

◆ processStateRefreshPacket()

void inet::PimDm::processStateRefreshPacket ( Packet pk)
private

The method is used to process PimStateRefresh packet.

The method checks if there is route in mroute and that packet has came to RPF interface. Then it goes through all outgoing interfaces. If the interface is pruned, it resets Prune Timer. For each interface State Refresh message is copied and correct prune indicator is set according to state of outgoing interface (pruned/forwarding).

State Refresh message is used to stop flooding of network each 3 minutes.

820 {
821  const auto& pkt = pk->peekAtFront<PimStateRefresh>();
822  EV << "pimDM::processStateRefreshPacket" << endl;
823 
824  emit(rcvdStateRefreshPkSignal, pk);
825 
826  // first check if there is route for given group address and source
827  Route *route = findRoute(pkt->getSourceAddress().unicastAddress.toIpv4(), pkt->getGroupAddress().groupAddress.toIpv4());
828  if (route == nullptr) {
829  delete pk;
830  return;
831  }
832 
833  // check if State Refresh msg has came from RPF neighbor
834  auto ifTag = pk->getTag<InterfaceInd>();
835  Ipv4Address srcAddr = pk->getTag<L3AddressInd>()->getSrcAddress().toIpv4();
836  UpstreamInterface *upstream = route->upstreamInterface;
837  if (ifTag->getInterfaceId() != upstream->getInterfaceId() || upstream->rpfNeighbor() != srcAddr) {
838  delete pk;
839  return;
840  }
841 
842  // upstream state transitions
843  bool pruneIndicator = pkt->getP();
844  switch (upstream->graftPruneState) {
846  if (pruneIndicator) {
847  upstream->startOverrideTimer();
848  }
849  break;
850 
852  if (!pruneIndicator) {
853  if (!upstream->isPruneLimitTimerRunning()) {
854  sendPrunePacket(upstream->rpfNeighbor(), route->source, route->group, pruneInterval, upstream->getInterfaceId());
855  upstream->startPruneLimitTimer();
856  }
857  }
858  else
859  upstream->startPruneLimitTimer();
860  break;
861 
863  if (pruneIndicator) {
864  if (!upstream->overrideTimer)
865  upstream->startOverrideTimer();
866  }
867  else {
868  cancelAndDelete(upstream->graftRetryTimer);
869  upstream->graftRetryTimer = nullptr;
870  upstream->graftPruneState = UpstreamInterface::FORWARDING;
871  }
872  break;
873  }
874 
875  //
876  // Forward StateRefresh message downstream
877  //
878 
879  // TODO check StateRefreshRateLimit(S,G)
880 
881  if (pkt->getTtl() == 0) {
882  delete pk;
883  return;
884  }
885 
886  // go through all outgoing interfaces, reser Prune Timer and send out State Refresh msg
887  for (unsigned int i = 0; i < route->downstreamInterfaces.size(); i++) {
888  DownstreamInterface *downstream = route->downstreamInterfaces[i];
889  // TODO check ttl threshold and boundary
890  if (downstream->assertState == DownstreamInterface::I_LOST_ASSERT)
891  continue;
892 
893  if (downstream->pruneState == DownstreamInterface::PRUNED) {
894  // reset PT
895  restartTimer(downstream->pruneTimer, pruneInterval);
896  }
897  sendStateRefreshPacket(pkt->getOriginatorAddress().unicastAddress.toIpv4(), route, downstream, pkt->getTtl() - 1);
898 
899  //
900  // Assert State Machine; event: Send State Refresh
901  //
902  if (downstream->assertState == DownstreamInterface::I_WON_ASSERT) {
903  // The router is sending a State Refresh(S,G) message on interface I.
904  // The router MUST set the Assert Timer (AT(S,G,I)) to three
905  // times the State Refresh Interval contained in the State Refresh(S,G) message.
906  restartTimer(downstream->assertTimer, 3 * stateRefreshInterval);
907  }
908  }
909 
910  //
911  // Assert State Machine; event: Receive State Refresh
912  //
913  AssertMetric receivedMetric(pkt->getMetricPreference(), pkt->getMetric(), srcAddr);
914  processAssert(upstream, receivedMetric, pkt->getInterval());
915 
916  delete pk;
917 }

Referenced by handleMessageWhenUp().

◆ processStateRefreshTimer()

void inet::PimDm::processStateRefreshTimer ( cMessage *  timer)
private
444 {
445  UpstreamInterface *upstream = static_cast<UpstreamInterface *>(timer->getContextPointer());
446  ASSERT(timer == upstream->stateRefreshTimer);
447  ASSERT(upstream->originatorState == UpstreamInterface::ORIGINATOR);
448 
449  Route *route = upstream->route();
450 
451  EV_INFO << "StateRefreshTimer" << route << " expired.\n";
452 
453  EV_DETAIL << "Sending StateRefresh packets on downstream interfaces.\n";
454  for (unsigned int i = 0; i < route->downstreamInterfaces.size(); i++) {
455  DownstreamInterface *downstream = route->downstreamInterfaces[i];
456  // TODO check ttl threshold and boundary
457  if (downstream->assertState == DownstreamInterface::I_LOST_ASSERT)
458  continue;
459 
460  // when sending StateRefresh in Pruned state, then restart PruneTimer
461  bool isPruned = downstream->pruneState == DownstreamInterface::PRUNED;
462  if (isPruned)
463  restartTimer(downstream->pruneTimer, pruneInterval);
464 
465  // Send StateRefresh message downstream
466  Ipv4Address originator = downstream->ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress();
467  sendStateRefreshPacket(originator, route, downstream, upstream->maxTtlSeen);
468  }
469 
470  scheduleAfter(stateRefreshInterval, timer);
471 }

Referenced by handleMessageWhenUp().

◆ pruneStateString()

const std::string inet::PimDm::pruneStateString ( DownstreamInterface::PruneState  ps)
static
1989 {
1991  return "NO_INFO";
1993  return "PRUNE_PENDING";
1994  else if (ps == DownstreamInterface::PRUNED)
1995  return "PRUNED";
1996 
1997  return "UNKNOWN";
1998 }

Referenced by inet::operator<<().

◆ receiveSignal()

void inet::PimDm::receiveSignal ( cComponent *  source,
simsignal_t  signalID,
cObject *  obj,
cObject *  details 
)
overrideprivate
198 {
199  Enter_Method("%s", cComponent::getSignalName(signalID));
200 
201  printSignalBanner(signalID, obj, details);
202  const Ipv4Header *ipv4Header;
203  PimInterface *pimInterface;
204 
205  // new multicast data appears in router
206  // note: this signal is often emitted from Ipv4::forwardMulticastPacket method
207  if (signalID == ipv4NewMulticastSignal) {
208  ipv4Header = check_and_cast<const Ipv4Header *>(obj);
209  pimInterface = getIncomingInterface(check_and_cast<NetworkInterface *>(details));
210  if (pimInterface && pimInterface->getMode() == PimInterface::DenseMode)
211  unroutableMulticastPacketArrived(ipv4Header->getSrcAddress(), ipv4Header->getDestAddress(), ipv4Header->getTimeToLive());
212  }
213  // configuration of interface changed, it means some change from IGMP, address were added.
214  else if (signalID == ipv4MulticastGroupRegisteredSignal) {
215  const Ipv4MulticastGroupInfo *info = check_and_cast<const Ipv4MulticastGroupInfo *>(obj);
216  pimInterface = pimIft->getInterfaceById(info->ie->getInterfaceId());
217  if (pimInterface && pimInterface->getMode() == PimInterface::DenseMode)
218  multicastReceiverAdded(pimInterface->getInterfacePtr(), info->groupAddress);
219  }
220  // configuration of interface changed, it means some change from IGMP, address were removed.
221  else if (signalID == ipv4MulticastGroupUnregisteredSignal) {
222  const Ipv4MulticastGroupInfo *info = check_and_cast<const Ipv4MulticastGroupInfo *>(obj);
223  pimInterface = pimIft->getInterfaceById(info->ie->getInterfaceId());
224  if (pimInterface && pimInterface->getMode() == PimInterface::DenseMode)
225  multicastReceiverRemoved(pimInterface->getInterfacePtr(), info->groupAddress);
226  }
227  // data come to non-RPF interface
228  else if (signalID == ipv4DataOnNonrpfSignal) {
229  ipv4Header = check_and_cast<const Ipv4Header *>(obj);
230  pimInterface = getIncomingInterface(check_and_cast<NetworkInterface *>(details));
231  if (pimInterface && pimInterface->getMode() == PimInterface::DenseMode)
232  multicastPacketArrivedOnNonRpfInterface(ipv4Header->getDestAddress(), ipv4Header->getSrcAddress(), pimInterface->getInterfaceId());
233  }
234  // data come to RPF interface
235  else if (signalID == ipv4DataOnRpfSignal) {
236  ipv4Header = check_and_cast<const Ipv4Header *>(obj);
237  pimInterface = getIncomingInterface(check_and_cast<NetworkInterface *>(details));
238  if (pimInterface && pimInterface->getMode() == PimInterface::DenseMode)
239  multicastPacketArrivedOnRpfInterface(pimInterface->getInterfaceId(), ipv4Header->getDestAddress(), ipv4Header->getSrcAddress(), ipv4Header->getTimeToLive());
240  }
241  // RPF interface has changed
242  else if (signalID == routeAddedSignal) {
243  const Ipv4Route *entry = check_and_cast<const Ipv4Route *>(obj);
244  for (int i = 0; i < rt->getNumMulticastRoutes(); i++) {
245  // find multicast routes whose source are on the destination of the new unicast route
246  Ipv4MulticastRoute *route = rt->getMulticastRoute(i);
247  if (route->getSource() == this && Ipv4Address::maskedAddrAreEqual(route->getOrigin(), entry->getDestination() /*routeSource*/, entry->getNetmask() /*routeNetmask*/)) {
248  Ipv4Address source = route->getOrigin();
249  Ipv4Route *routeToSource = rt->findBestMatchingRoute(source);
250  NetworkInterface *newRpfInterface = routeToSource->getInterface();
251  NetworkInterface *oldRpfInterface = route->getInInterface()->getInterface();
252 
253  // is there any change?
254  if (newRpfInterface != oldRpfInterface)
255  rpfInterfaceHasChanged(route, routeToSource);
256 
257  // TODO update metric
258  }
259  }
260  }
261 }

◆ restartTimer()

void inet::PimDm::restartTimer ( cMessage *  timer,
double  interval 
)
private

◆ rpfInterfaceHasChanged()

void inet::PimDm::rpfInterfaceHasChanged ( Ipv4MulticastRoute ipv4Route,
Ipv4Route routeToSource 
)
private

The method process notification about interface change.

Multicast routing table will be changed if RPF interface has changed. New RPF interface is set to route and is removed from outgoing interfaces. On the other hand, old RPF interface is added to outgoing interfaces. If route was not pruned, the router has to join to the multicast tree again (by different path).

1364 {
1365  NetworkInterface *newRpf = routeToSource->getInterface();
1366  Ipv4Address source = ipv4Route->getOrigin();
1367  Ipv4Address group = ipv4Route->getMulticastGroup();
1368  int rpfId = newRpf->getInterfaceId();
1369 
1370  EV_DETAIL << "New RPF interface for group=" << group << " source=" << source << " is " << newRpf->getInterfaceName() << endl;
1371 
1372  Route *route = findRoute(source, group);
1373  ASSERT(route);
1374 
1375  // delete old upstream interface data
1376  UpstreamInterface *oldUpstreamInterface = route->upstreamInterface;
1377  NetworkInterface *oldRpfInterface = oldUpstreamInterface ? oldUpstreamInterface->ie : nullptr;
1378  delete oldUpstreamInterface;
1379  delete ipv4Route->getInInterface();
1380  ipv4Route->setInInterface(nullptr);
1381 
1382  // set new upstream interface data
1383  bool isSourceDirectlyConnected = routeToSource->getSourceType() == Ipv4Route::IFACENETMASK;
1384  Ipv4Address newRpfNeighbor = pimNbt->getNeighbor(rpfId, 0)->getAddress(); // TODO what happens if no neighbors?
1385  UpstreamInterface *upstream = route->upstreamInterface = new UpstreamInterface(route, newRpf, newRpfNeighbor, isSourceDirectlyConnected);
1386  ipv4Route->setInInterface(new IMulticastRoute::InInterface(newRpf));
1387 
1388  // delete rpf interface from the downstream interfaces
1389  DownstreamInterface *oldDownstreamInterface = route->removeDownstreamInterface(newRpf->getInterfaceId());
1390  if (oldDownstreamInterface) {
1391  ipv4Route->removeOutInterface(newRpf); // will delete downstream data, TODO method should be called deleteOutInterface()
1392  delete oldDownstreamInterface;
1393  }
1394 
1395  // old RPF interface should be now a downstream interface if it is not down
1396  if (oldRpfInterface && oldRpfInterface->isUp()) {
1397  DownstreamInterface *downstream = route->createDownstreamInterface(oldRpfInterface);
1398  ipv4Route->addOutInterface(new PimDmOutInterface(oldRpfInterface, downstream));
1399  }
1400 
1401  bool isOlistNull = route->isOilistNull();
1402 
1403  // upstream state transitions
1404 
1405  // RPF'(S) Changes AND olist(S,G) != nullptr AND S is NOT directly connected?
1406  if (!isOlistNull && !upstream->isSourceDirectlyConnected()) {
1407  // The Upstream(S,G) state
1408  // machine MUST transition to the AckPending (AP) state, unicast a
1409  // Graft to the new RPF'(S), and set the GraftRetry Timer (GRT(S,G))
1410  // to Graft_Retry_Period.
1411 
1412  if (upstream->graftPruneState == UpstreamInterface::PRUNED)
1413  upstream->stopPruneLimitTimer();
1414 
1415  // route was not pruned, join to the multicast tree again
1416  sendGraftPacket(upstream->rpfNeighbor(), source, group, rpfId);
1417  upstream->startGraftRetryTimer();
1418  upstream->graftPruneState = UpstreamInterface::ACK_PENDING;
1419  }
1420  // RPF'(S) Changes AND olist(S,G) == nullptr
1421  else if (isOlistNull) {
1422  if (upstream->graftPruneState == UpstreamInterface::PRUNED) {
1423  upstream->stopPruneLimitTimer();
1424  }
1425  else if (upstream->graftPruneState == UpstreamInterface::ACK_PENDING) {
1426  cancelAndDelete(upstream->graftRetryTimer);
1427  upstream->graftRetryTimer = nullptr;
1428  }
1429 
1430  upstream->graftPruneState = UpstreamInterface::PRUNED;
1431  }
1432 }

Referenced by receiveSignal().

◆ sendAssertPacket()

void inet::PimDm::sendAssertPacket ( Ipv4Address  source,
Ipv4Address  group,
AssertMetric  metric,
NetworkInterface ie 
)
private
1586 {
1587  EV_INFO << "Sending Assert(S= " << source << ", G= " << group << ") message on interface '" << ie->getInterfaceName() << "'\n";
1588 
1589  Packet *packet = new Packet("PimAssert");
1590  const auto& pkt = makeShared<PimAssert>();
1591  pkt->getGroupAddressForUpdate().groupAddress = group;
1592  pkt->getSourceAddressForUpdate().unicastAddress = source;
1593  pkt->setR(false);
1594  pkt->setMetricPreference(metric.preference);
1595  pkt->setMetric(metric.metric);
1596 
1597  pkt->setChunkLength(PIM_HEADER_LENGTH
1600  + B(8));
1601  pkt->setCrcMode(pimModule->getCrcMode());
1602  Pim::insertCrc(pkt);
1603  packet->insertAtFront(pkt);
1604 
1605  emit(sentAssertPkSignal, packet);
1606 
1607  sendToIP(packet, Ipv4Address::UNSPECIFIED_ADDRESS, ALL_PIM_ROUTERS_MCAST, ie->getInterfaceId());
1608 }

Referenced by multicastPacketArrivedOnNonRpfInterface(), processAssert(), processGraft(), processJoin(), and processPrune().

◆ sendGraftAckPacket()

void inet::PimDm::sendGraftAckPacket ( Packet pk,
const Ptr< const PimGraft > &  graftPacket 
)
private
1535 {
1536  EV_INFO << "Sending GraftAck message.\n";
1537 
1538  auto ifTag = pk->getTag<InterfaceInd>();
1539  auto addressInd = pk->getTag<L3AddressInd>();
1540  Ipv4Address destAddr = addressInd->getSrcAddress().toIpv4();
1541  Ipv4Address srcAddr = addressInd->getDestAddress().toIpv4();
1542  int outInterfaceId = ifTag->getInterfaceId();
1543 
1544  Packet *packet = new Packet("PIMGraftAck");
1545  auto msg = dynamicPtrCast<PimGraft>(graftPacket->dupShared());
1546  msg->setType(GraftAck);
1547  msg->setCrcMode(pimModule->getCrcMode());
1548  Pim::insertCrc(msg);
1549  packet->insertAtFront(msg);
1550 
1551  emit(sentGraftAckPkSignal, packet);
1552 
1553  sendToIP(packet, srcAddr, destAddr, outInterfaceId);
1554 }

Referenced by processGraftPacket().

◆ sendGraftPacket()

void inet::PimDm::sendGraftPacket ( Ipv4Address  nextHop,
Ipv4Address  src,
Ipv4Address  grp,
int  intId 
)
private
1503 {
1504  EV_INFO << "Sending Graft(S=" << src << ", G=" << grp << ") message to neighbor '" << nextHop << "' on interface '" << intId << "'\n";
1505 
1506  Packet *packet = new Packet("PimGraft");
1507  const auto& msg = makeShared<PimGraft>();
1508  msg->setHoldTime(0);
1509  msg->getUpstreamNeighborAddressForUpdate().unicastAddress = nextHop;
1510 
1511  msg->setJoinPruneGroupsArraySize(1);
1512  JoinPruneGroup& group = msg->getJoinPruneGroupsForUpdate(0);
1513  group.getGroupAddressForUpdate().groupAddress = grp;
1514  group.setJoinedSourceAddressArraySize(1);
1515  auto& address = group.getJoinedSourceAddressForUpdate(0);
1516  address.sourceAddress = src;
1517 
1519  msg->setCrcMode(pimModule->getCrcMode());
1520  Pim::insertCrc(msg);
1521  packet->insertAtFront(msg);
1522 
1523  emit(sentGraftPkSignal, packet);
1524 
1525  sendToIP(packet, Ipv4Address::UNSPECIFIED_ADDRESS, nextHop, intId);
1526 }

Referenced by processGraftRetryTimer(), processOlistNonEmptyEvent(), and rpfInterfaceHasChanged().

◆ sendJoinPacket()

void inet::PimDm::sendJoinPacket ( Ipv4Address  nextHop,
Ipv4Address  source,
Ipv4Address  group,
int  interfaceId 
)
private
1467 {
1468  ASSERT(!src.isUnspecified());
1469  ASSERT(grp.isMulticast());
1470 
1471  EV_INFO << "Sending Join(S=" << src << ", G=" << grp << ") message to neighbor '" << nextHop << "' on interface '" << intId << "'\n";
1472 
1473  Packet *packet = new Packet("PIMJoin");
1474  const auto& msg = makeShared<PimJoinPrune>();
1475  msg->getUpstreamNeighborAddressForUpdate().unicastAddress = nextHop;
1476  msg->setHoldTime(0); // ignored by the receiver
1477 
1478  // set multicast groups
1479  msg->setJoinPruneGroupsArraySize(1);
1480  JoinPruneGroup& group = msg->getJoinPruneGroupsForUpdate(0);
1481  group.getGroupAddressForUpdate().groupAddress = grp;
1482  group.setJoinedSourceAddressArraySize(1);
1483  auto& address = group.getJoinedSourceAddressForUpdate(0);
1484  address.sourceAddress = src;
1485 
1487  msg->setCrcMode(pimModule->getCrcMode());
1488  Pim::insertCrc(msg);
1489  packet->insertAtFront(msg);
1490 
1491  emit(sentJoinPrunePkSignal, packet);
1492 
1494 }

Referenced by processOverrideTimer().

◆ sendPrunePacket()

void inet::PimDm::sendPrunePacket ( Ipv4Address  nextHop,
Ipv4Address  src,
Ipv4Address  grp,
int  holdTime,
int  intId 
)
private
1437 {
1438  ASSERT(!src.isUnspecified());
1439  ASSERT(grp.isMulticast());
1440 
1441  EV_INFO << "Sending Prune(S=" << src << ", G=" << grp << ") message to neighbor '" << nextHop << "' on interface '" << intId << "'\n";
1442 
1443  Packet *packet = new Packet("PIMPrune");
1444  const auto& msg = makeShared<PimJoinPrune>();
1445  msg->getUpstreamNeighborAddressForUpdate().unicastAddress = nextHop;
1446  msg->setHoldTime(holdTime);
1447 
1448  // set multicast groups
1449  msg->setJoinPruneGroupsArraySize(1);
1450  JoinPruneGroup& group = msg->getJoinPruneGroupsForUpdate(0);
1451  group.getGroupAddressForUpdate().groupAddress = grp;
1452  group.setPrunedSourceAddressArraySize(1);
1453  auto& address = group.getPrunedSourceAddressForUpdate(0);
1454  address.sourceAddress = src;
1455 
1457  msg->setCrcMode(pimModule->getCrcMode());
1458  Pim::insertCrc(msg);
1459  packet->insertAtFront(msg);
1460 
1461  emit(sentJoinPrunePkSignal, packet);
1462 
1464 }

Referenced by multicastPacketArrivedOnNonRpfInterface(), multicastPacketArrivedOnRpfInterface(), processAssert(), processOlistEmptyEvent(), and processStateRefreshPacket().

◆ sendStateRefreshPacket()

void inet::PimDm::sendStateRefreshPacket ( Ipv4Address  originator,
Route route,
DownstreamInterface downstream,
unsigned short  ttl 
)
private
1557 {
1558  EV_INFO << "Sending StateRefresh(S=" << route->source << ", G=" << route->group
1559  << ") message on interface '" << downstream->ie->getInterfaceName() << "'\n";
1560 
1561  Packet *packet = new Packet("PimStateRefresh");
1562  const auto& msg = makeShared<PimStateRefresh>();
1563  msg->getGroupAddressForUpdate().groupAddress = route->group;
1564  msg->getSourceAddressForUpdate().unicastAddress = route->source;
1565  msg->getOriginatorAddressForUpdate().unicastAddress = originator;
1566  msg->setInterval(stateRefreshInterval);
1567  msg->setTtl(ttl);
1568  msg->setP(downstream->pruneState == DownstreamInterface::PRUNED);
1569  // TODO set metric
1570 
1571  msg->setChunkLength(PIM_HEADER_LENGTH
1575  + B(12));
1576  msg->setCrcMode(pimModule->getCrcMode());
1577  Pim::insertCrc(msg);
1578  packet->insertAtFront(msg);
1579 
1580  emit(sentStateRefreshPkSignal, packet);
1581 
1582  sendToIP(packet, Ipv4Address::UNSPECIFIED_ADDRESS, ALL_PIM_ROUTERS_MCAST, downstream->ie->getInterfaceId());
1583 }

Referenced by processStateRefreshPacket(), and processStateRefreshTimer().

◆ sendToIP()

void inet::PimDm::sendToIP ( Packet packet,
Ipv4Address  source,
Ipv4Address  dest,
int  outInterfaceId 
)
private
1611 {
1612  packet->addTagIfAbsent<PacketProtocolTag>()->setProtocol(&Protocol::pim);
1613  packet->addTagIfAbsent<DispatchProtocolInd>()->setProtocol(&Protocol::pim);
1614  packet->addTagIfAbsent<DispatchProtocolReq>()->setProtocol(&Protocol::ipv4);
1615  packet->addTagIfAbsent<InterfaceReq>()->setInterfaceId(outInterfaceId);
1616  auto addresses = packet->addTagIfAbsent<L3AddressReq>();
1617  addresses->setSrcAddress(srcAddr);
1618  addresses->setDestAddress(destAddr);
1619  packet->addTagIfAbsent<HopLimitReq>()->setHopLimit(1);
1620  send(packet, "ipOut");
1621 }

Referenced by sendAssertPacket(), sendGraftAckPacket(), sendGraftPacket(), sendJoinPacket(), sendPrunePacket(), and sendStateRefreshPacket().

◆ stopPIMRouting()

void inet::PimDm::stopPIMRouting ( )
protectedvirtual
92 {
93  if (isEnabled) {
94  cModule *host = findContainingNode(this);
95  if (!host)
96  throw cRuntimeError("PimDm: containing node not found.");
97  host->unsubscribe(ipv4NewMulticastSignal, this);
98  host->unsubscribe(ipv4MulticastGroupRegisteredSignal, this);
99  host->unsubscribe(ipv4MulticastGroupUnregisteredSignal, this);
100  host->unsubscribe(ipv4DataOnNonrpfSignal, this);
101  host->unsubscribe(ipv4DataOnRpfSignal, this);
102  host->unsubscribe(routeAddedSignal, this);
103  host->unsubscribe(interfaceStateChangedSignal, this);
104  }
105 
106  clearRoutes();
107 }

Referenced by handleCrashOperation(), and handleStopOperation().

◆ unroutableMulticastPacketArrived()

void inet::PimDm::unroutableMulticastPacketArrived ( Ipv4Address  source,
Ipv4Address  group,
unsigned short  ttl 
)
private

The method process notification about new multicast data stream.

It goes through all PIM interfaces and tests them if they can be added to the list of outgoing interfaces. If there is no interface on the list at the end, the router will prune from the multicast tree.

1056 {
1057  ASSERT(!source.isUnspecified());
1058  ASSERT(group.isMulticast());
1059 
1060  EV_DETAIL << "New multicast source observed: source=" << source << ", group=" << group << ".\n";
1061 
1062  Ipv4Route *routeToSrc = rt->findBestMatchingRoute(source);
1063  if (!routeToSrc || !routeToSrc->getInterface()) {
1064  EV << "ERROR: PimDm::newMulticast(): cannot find RPF interface, routing information is missing.";
1065  return;
1066  }
1067 
1068  PimInterface *rpfInterface = pimIft->getInterfaceById(routeToSrc->getInterface()->getInterfaceId());
1069  if (!rpfInterface || rpfInterface->getMode() != PimInterface::DenseMode)
1070  return;
1071 
1072  // gateway is unspecified for directly connected destinations
1073  bool isSourceDirectlyConnected = routeToSrc->getSourceType() == Ipv4Route::IFACENETMASK;
1074  Ipv4Address rpfNeighbor = routeToSrc->getGateway().isUnspecified() ? source : routeToSrc->getGateway();
1075 
1076  Route *route = new Route(this, source, group);
1077  routes[SourceAndGroup(source, group)] = route;
1078  route->metric = AssertMetric(routeToSrc->getAdminDist(), routeToSrc->getMetric(), Ipv4Address::UNSPECIFIED_ADDRESS);
1079  route->upstreamInterface = new UpstreamInterface(route, rpfInterface->getInterfacePtr(), rpfNeighbor, isSourceDirectlyConnected);
1080 
1081  // if the source is directly connected, then go to the Originator state
1082  if (isSourceDirectlyConnected) {
1083  route->upstreamInterface->originatorState = UpstreamInterface::ORIGINATOR;
1084  if (rpfInterface->getSR())
1085  route->upstreamInterface->startStateRefreshTimer();
1086  route->upstreamInterface->startSourceActiveTimer();
1087  route->upstreamInterface->maxTtlSeen = ttl;
1088  }
1089 
1090  bool allDownstreamInterfacesArePruned = true;
1091 
1092  // insert all PIM interfaces except rpf int
1093  for (int i = 0; i < pimIft->getNumInterfaces(); i++) {
1094  PimInterface *pimInterface = pimIft->getInterface(i);
1095 
1096  // check if PIM-DM interface and it is not RPF interface
1097  if (pimInterface == rpfInterface || pimInterface->getMode() != PimInterface::DenseMode) // TODO original code added downstream if data for PIM-SM interfaces too
1098  continue;
1099 
1100  bool hasPIMNeighbors = pimNbt->getNumNeighbors(pimInterface->getInterfaceId()) > 0;
1101  bool hasConnectedReceivers = pimInterface->getInterfacePtr()->getProtocolData<Ipv4InterfaceData>()->hasMulticastListener(group);
1102 
1103  // if there are neighbors on interface, we will forward
1104  if (hasPIMNeighbors || hasConnectedReceivers) {
1105  // create new outgoing interface
1106  DownstreamInterface *downstream = route->createDownstreamInterface(pimInterface->getInterfacePtr());
1107  downstream->setHasConnectedReceivers(hasConnectedReceivers);
1108  allDownstreamInterfacesArePruned = false;
1109  }
1110  }
1111 
1112  // if there is no outgoing interface, prune from multicast tree
1113  if (allDownstreamInterfacesArePruned) {
1114  EV_DETAIL << "There is no outgoing interface for multicast, will send Prune message to upstream.\n";
1115  route->upstreamInterface->graftPruneState = UpstreamInterface::PRUNED;
1116 
1117  // Prune message is sent from the forwarding hook (ipv4DataOnRpfSignal), see multicastPacketArrivedOnRpfInterface()
1118  }
1119 
1120  // create new multicast route
1121  Ipv4MulticastRoute *newRoute = new Ipv4MulticastRoute();
1122  newRoute->setOrigin(source);
1123  newRoute->setOriginNetmask(Ipv4Address::ALLONES_ADDRESS);
1124  newRoute->setMulticastGroup(group);
1125  newRoute->setSourceType(IMulticastRoute::PIM_DM);
1126  newRoute->setSource(this);
1127  newRoute->setInInterface(new IMulticastRoute::InInterface(route->upstreamInterface->ie));
1128  for (auto& elem : route->downstreamInterfaces) {
1129  DownstreamInterface *downstream = elem;
1130  newRoute->addOutInterface(new PimDmOutInterface(downstream->ie, downstream));
1131  }
1132 
1133  rt->addMulticastRoute(newRoute);
1134  EV_DETAIL << "New route was added to the multicast routing table.\n";
1135 }

Referenced by receiveSignal().

Friends And Related Function Documentation

◆ operator<<

std::ostream& operator<< ( std::ostream &  out,
const PimDm::Route sourceGroup 
)
friend
1929 {
1930  out << "Upstream interface ";
1931  if (!route.upstreamInterface)
1932  out << "(empty) ";
1933  else {
1934  out << "(name: " << route.upstreamInterface->ie->getInterfaceName() << " ";
1935  out << "RpfNeighbor: " << route.upstreamInterface->rpfNeighbor() << " ";
1936  out << "graftPruneState: " << PimDm::graftPruneStateString(route.upstreamInterface->getGraftPruneState()) << " ";
1937  auto t1 = route.upstreamInterface->getGraftRetryTimer();
1938  out << "graftRetryTimer: " << (t1 ? t1->getArrivalTime() : 0) << " ";
1939  auto t2 = route.upstreamInterface->getOverrideTimer();
1940  out << "overrideTimer: " << (t2 ? t2->getArrivalTime() : 0) << " ";
1941  out << "lastPruneSentTime: " << route.upstreamInterface->getLastPruneSentTime() << " ";
1942  out << "originatorState: " << PimDm::originatorStateString(route.upstreamInterface->getOriginatorState()) << " ";
1943  auto t3 = route.upstreamInterface->getSourceActiveTimer();
1944  out << "sourceActiveTimer: " << (t3 ? t3->getArrivalTime() : 0) << " ";
1945  auto t4 = route.upstreamInterface->getStateRefreshTimer();
1946  out << "stateRefreshTimer: " << (t4 ? t4->getArrivalTime() : 0) << " ";
1947  out << "maxTtlSeen: " << route.upstreamInterface->getMaxTtlSeen() << ") ";
1948  }
1949 
1950  out << "Downstream interfaces ";
1951  if (route.downstreamInterfaces.empty())
1952  out << "(empty) ";
1953  for (unsigned int i = 0; i < route.downstreamInterfaces.size(); ++i) {
1954  out << "(name: " << route.downstreamInterfaces[i]->ie->getInterfaceName() << " ";
1955  out << "pruneState: " << PimDm::pruneStateString(route.downstreamInterfaces[i]->getPruneState()) << " ";
1956  auto t1 = route.downstreamInterfaces[i]->getPruneTimer();
1957  out << "pruneTimer: " << (t1 ? t1->getArrivalTime() : 0) << " ";
1958  auto t2 = route.downstreamInterfaces[i]->getPrunePendingTimer();
1959  out << "prunePendingTimer: " << (t2 ? t2->getArrivalTime() : 0) << ") ";
1960  }
1961 
1962  return out;
1963 
1964 }

Member Data Documentation

◆ assertTime

double inet::PimDm::assertTime = 0
private

◆ graftRetryInterval

double inet::PimDm::graftRetryInterval = 0
private

◆ overrideInterval

◆ propagationDelay

double inet::PimDm::propagationDelay = 0
private

◆ pruneInterval

◆ pruneLimitInterval

double inet::PimDm::pruneLimitInterval = 0
private

Referenced by initialize().

◆ rcvdAssertPkSignal

simsignal_t inet::PimDm::rcvdAssertPkSignal = registerSignal("rcvdAssertPk")
staticprivate

Referenced by processAssertPacket().

◆ rcvdGraftAckPkSignal

simsignal_t inet::PimDm::rcvdGraftAckPkSignal = registerSignal("rcvdGraftAckPk")
staticprivate

Referenced by processGraftAckPacket().

◆ rcvdGraftPkSignal

simsignal_t inet::PimDm::rcvdGraftPkSignal = registerSignal("rcvdGraftPk")
staticprivate

Referenced by processGraftPacket().

◆ rcvdJoinPrunePkSignal

simsignal_t inet::PimDm::rcvdJoinPrunePkSignal = registerSignal("rcvdJoinPrunePk")
staticprivate

Referenced by processJoinPrunePacket().

◆ rcvdStateRefreshPkSignal

simsignal_t inet::PimDm::rcvdStateRefreshPkSignal = registerSignal("rcvdStateRefreshPk")
staticprivate

◆ routes

◆ sentAssertPkSignal

simsignal_t inet::PimDm::sentAssertPkSignal = registerSignal("sentAssertPk")
staticprivate

Referenced by sendAssertPacket().

◆ sentGraftAckPkSignal

simsignal_t inet::PimDm::sentGraftAckPkSignal = registerSignal("sentGraftAckPk")
staticprivate

Referenced by sendGraftAckPacket().

◆ sentGraftPkSignal

simsignal_t inet::PimDm::sentGraftPkSignal = registerSignal("sentGraftPk")
staticprivate

Referenced by sendGraftPacket().

◆ sentJoinPrunePkSignal

simsignal_t inet::PimDm::sentJoinPrunePkSignal = registerSignal("sentJoinPrunePk")
staticprivate

Referenced by sendJoinPacket(), and sendPrunePacket().

◆ sentStateRefreshPkSignal

simsignal_t inet::PimDm::sentStateRefreshPkSignal = registerSignal("sentStateRefreshPk")
staticprivate

Referenced by sendStateRefreshPacket().

◆ sourceActiveInterval

double inet::PimDm::sourceActiveInterval = 0
private

◆ stateRefreshInterval


The documentation for this class was generated from the following files:
inet::PimDm::findIpv4MulticastRoute
Ipv4MulticastRoute * findIpv4MulticastRoute(Ipv4Address group, Ipv4Address source)
Definition: PimDm.cc:1703
inet::findContainingNode
cModule * findContainingNode(const cModule *from)
Find the node containing the given module.
Definition: ModuleAccess.cc:31
inet::PimDm::processAssert
void processAssert(Interface *downstream, AssertMetric receivedMetric, int stateRefreshInterval)
Definition: PimDm.cc:922
inet::ipv4DataOnRpfSignal
simsignal_t ipv4DataOnRpfSignal
Definition: Simsignals.cc:58
inet::PimDm::UpstreamInterface::FORWARDING
@ FORWARDING
Definition: PimDm.h:40
inet::PimDm::assertTime
double assertTime
Definition: PimDm.h:161
inet::PimBase::Interface::NO_ASSERT_INFO
@ NO_ASSERT_INFO
Definition: PimBase.h:74
inet::PimDm::rpfInterfaceHasChanged
void rpfInterfaceHasChanged(Ipv4MulticastRoute *route, Ipv4Route *routeToSource)
The method process notification about interface change.
Definition: PimDm.cc:1363
inet::PimDm::sendToIP
void sendToIP(Packet *packet, Ipv4Address source, Ipv4Address dest, int outInterfaceId)
Definition: PimDm.cc:1610
inet::PimDm::UpstreamInterface::ORIGINATOR
@ ORIGINATOR
Definition: PimDm.h:45
inet::Hello
@ Hello
Definition: PimPacket_m.h:93
inet::PimDm::sendJoinPacket
void sendJoinPacket(Ipv4Address nextHop, Ipv4Address source, Ipv4Address group, int interfaceId)
Definition: PimDm.cc:1466
inet::PimDm::processGraft
void processGraft(Ipv4Address source, Ipv4Address group, Ipv4Address sender, int intId)
The method is used to process PimGraft packet.
Definition: PimDm.cc:711
inet::PimDm::sendAssertPacket
void sendAssertPacket(Ipv4Address source, Ipv4Address group, AssertMetric metric, NetworkInterface *ie)
Definition: PimDm.cc:1585
inet::PimDm::processSourceActiveTimer
void processSourceActiveTimer(cMessage *timer)
Definition: PimDm.cc:404
inet::PimDm::originatorStateString
const static std::string originatorStateString(UpstreamInterface::OriginatorState os)
Definition: PimDm.cc:1978
inet::PIM_HEADER_LENGTH
const B PIM_HEADER_LENGTH
Definition: PimPacket_m.h:68
inet::PimBase::ift
ModuleRefByPar< IInterfaceTable > ift
Definition: PimBase.h:147
inet::PimBase::handleCrashOperation
virtual void handleCrashOperation(LifecycleOperation *operation) override
Definition: PimBase.cc:88
inet::PimDm::processOlistNonEmptyEvent
void processOlistNonEmptyEvent(Route *route)
Definition: PimDm.cc:1656
inet::PimDm::UpstreamInterface::ACK_PENDING
@ ACK_PENDING
Definition: PimDm.h:42
inet::PimDm::sentJoinPrunePkSignal
static simsignal_t sentJoinPrunePkSignal
Definition: PimDm.h:168
inet::PimBase::SourceActiveTimer
@ SourceActiveTimer
Definition: PimBase.h:133
inet::PimDm::propagationDelay
double propagationDelay
Definition: PimDm.h:157
inet::Protocol::ipv4
static const Protocol ipv4
Definition: Protocol.h:93
inet::PimDm::restartTimer
void restartTimer(cMessage *timer, double interval)
Definition: PimDm.cc:1685
inet::PimDm::sentStateRefreshPkSignal
static simsignal_t sentStateRefreshPkSignal
Definition: PimDm.h:172
inet::PimDm::deleteRoute
void deleteRoute(Ipv4Address source, Ipv4Address group)
Definition: PimDm.cc:1720
inet::ENCODED_GROUP_ADDRESS_LENGTH
const B ENCODED_GROUP_ADDRESS_LENGTH
Definition: PimPacket_m.h:70
inet::PimInterface::DenseMode
@ DenseMode
Definition: PimInterfaceTable.h:25
inet::PimBase::Interface::I_WON_ASSERT
@ I_WON_ASSERT
Definition: PimBase.h:74
inet::PimDm::processAssertTimer
void processAssertTimer(cMessage *timer)
Definition: PimDm.cc:265
inet::IMulticastRoute::PIM_DM
@ PIM_DM
managed by PIM-DM router
Definition: IRoute.h:168
inet::PimBase::isEnabled
bool isEnabled
Definition: PimBase.h:153
InterfaceReq
removed InterfaceReq
Definition: IUdp-gates.txt:11
inet::PimDm::routes
RoutingTable routes
Definition: PimDm.h:176
DispatchProtocolReq
removed DscpReq Ipv4ControlInfo Ipv6ControlInfo up L3AddressInd DispatchProtocolReq L4PortInd Ipv4ControlInfo Ipv6ControlInfo down DispatchProtocolReq
Definition: IUdp-gates.txt:25
inet::printSignalBanner
void printSignalBanner(simsignal_t signalID, const cObject *obj, const cObject *details)
Utility function.
Definition: Simsignals.cc:126
inet::PimDm::rcvdStateRefreshPkSignal
static simsignal_t rcvdStateRefreshPkSignal
Definition: PimDm.h:173
L3AddressInd
removed DscpReq Ipv4ControlInfo Ipv6ControlInfo up L3AddressInd L3AddressInd
Definition: IUdp-gates.txt:20
inet::PimDm::rcvdAssertPkSignal
static simsignal_t rcvdAssertPkSignal
Definition: PimDm.h:171
inet::PimBase::pimModule
opp_component_ptr< Pim > pimModule
Definition: PimBase.h:150
inet::PimDm::multicastReceiverAdded
void multicastReceiverAdded(NetworkInterface *ie, Ipv4Address newAddr)
Definition: PimDm.cc:1143
inet::PimDm::clearRoutes
void clearRoutes()
Definition: PimDm.cc:1729
inet::PimBase::UpstreamOverrideTimer
@ UpstreamOverrideTimer
Definition: PimBase.h:131
inet::PimDm::DownstreamInterface::NO_INFO
@ NO_INFO
Definition: PimDm.h:96
inet::PimDm::UpstreamInterface::PRUNED
@ PRUNED
Definition: PimDm.h:41
inet::PimDm::multicastPacketArrivedOnRpfInterface
void multicastPacketArrivedOnRpfInterface(int interfaceId, Ipv4Address group, Ipv4Address source, unsigned short ttl)
Definition: PimDm.cc:1285
inet::PimDm::processGraftAckPacket
void processGraftAckPacket(Packet *pk)
Definition: PimDm.cc:770
inet::PimDm::rcvdGraftAckPkSignal
static simsignal_t rcvdGraftAckPkSignal
Definition: PimDm.h:167
inet::Pim::insertCrc
static void insertCrc(const Ptr< PimPacket > &pimPacket)
Definition: Pim.cc:103
inet::PimDm::getIncomingInterface
PimInterface * getIncomingInterface(NetworkInterface *fromIE)
Definition: PimDm.cc:1696
inet::PimBase::PrunePendingTimer
@ PrunePendingTimer
Definition: PimBase.h:127
inet::PimBase::ALL_PIM_ROUTERS_MCAST
static const Ipv4Address ALL_PIM_ROUTERS_MCAST
Definition: PimBase.h:143
inet::PimDm::findRoute
Route * findRoute(Ipv4Address source, Ipv4Address group)
Definition: PimDm.cc:1714
inet::PimDm::sourceActiveInterval
double sourceActiveInterval
Definition: PimDm.h:159
inet::PimBase::handleStartOperation
virtual void handleStartOperation(LifecycleOperation *operation) override
Definition: PimBase.cc:60
PacketProtocolTag
removed DscpReq Ipv4ControlInfo Ipv6ControlInfo up L3AddressInd DispatchProtocolReq L4PortInd Ipv4ControlInfo Ipv6ControlInfo down PacketProtocolTag
Definition: IUdp-gates.txt:25
inet::ipv4NewMulticastSignal
simsignal_t ipv4NewMulticastSignal
Definition: Simsignals.cc:56
inet::Ipv4Address::ALLONES_ADDRESS
static const Ipv4Address ALLONES_ADDRESS
255.255.255.255
Definition: Ipv4Address.h:94
inet::StateRefresh
@ StateRefresh
Definition: PimPacket_m.h:102
inet::PimBase::PruneLimitTimer
@ PruneLimitTimer
Definition: PimBase.h:132
inet::PimDm::sendGraftAckPacket
void sendGraftAckPacket(Packet *pk, const Ptr< const PimGraft > &graftPacket)
Definition: PimDm.cc:1534
inet::Protocol::pim
static const Protocol pim
Definition: Protocol.h:103
inet::PimDm::processAssertPacket
void processAssertPacket(Packet *pk)
Definition: PimDm.cc:648
inet::PimBase::StateRefreshTimer
@ StateRefreshTimer
Definition: PimBase.h:134
inet::PimBase::PimBase
PimBase(PimInterface::PimMode mode)
Definition: PimBase.h:170
inet::units::units::B
intscale< b, 1, 8 > B
Definition: Units.h:1168
inet::PimBase::PruneTimer
@ PruneTimer
Definition: PimBase.h:126
inet::PimDm::rcvdGraftPkSignal
static simsignal_t rcvdGraftPkSignal
Definition: PimDm.h:165
inet::PimDm::DownstreamInterface::PRUNE_PENDING
@ PRUNE_PENDING
Definition: PimDm.h:97
inet::PimBase::Interface::I_LOST_ASSERT
@ I_LOST_ASSERT
Definition: PimBase.h:74
inet::PimDm::sendStateRefreshPacket
void sendStateRefreshPacket(Ipv4Address originator, Route *route, DownstreamInterface *downstream, unsigned short ttl)
Definition: PimDm.cc:1556
inet::Ipv4Address::maskedAddrAreEqual
static bool maskedAddrAreEqual(const Ipv4Address &addr1, const Ipv4Address &addr2, const Ipv4Address &netmask)
Test if the masked addresses (ie the mask is applied to addr1 and addr2) are equal.
Definition: Ipv4Address.cc:249
inet::PimDm::pruneStateString
const static std::string pruneStateString(DownstreamInterface::PruneState ps)
Definition: PimDm.cc:1988
inet::ipv4MulticastGroupRegisteredSignal
simsignal_t ipv4MulticastGroupRegisteredSignal
Definition: Simsignals.cc:52
inet::PimDm::processOlistEmptyEvent
void processOlistEmptyEvent(Route *route)
Definition: PimDm.cc:1630
HopLimitReq
removed HopLimitReq
Definition: IUdp-gates.txt:11
inet::PimDm::sentGraftPkSignal
static simsignal_t sentGraftPkSignal
Definition: PimDm.h:164
inet::PimBase::pimIft
ModuleRefByPar< PimInterfaceTable > pimIft
Definition: PimBase.h:148
inet::PimDm::multicastReceiverRemoved
void multicastReceiverRemoved(NetworkInterface *ie, Ipv4Address oldAddr)
The method process notification about multicast groups removed from interface.
Definition: PimDm.cc:1190
inet::PimDm::processStateRefreshPacket
void processStateRefreshPacket(Packet *pk)
The method is used to process PimStateRefresh packet.
Definition: PimDm.cc:819
inet::PimDm::processPrune
void processPrune(Route *route, int intId, int holdTime, int numRpfNeighbors, Ipv4Address upstreamNeighborField)
The method process PIM Prune packet.
Definition: PimDm.cc:575
inet::interfaceStateChangedSignal
simsignal_t interfaceStateChangedSignal
Definition: Simsignals.cc:32
inet::INITSTAGE_LOCAL
INET_API InitStage INITSTAGE_LOCAL
Initialization of local state that don't use or affect other modules includes:
inet::Graft
@ Graft
Definition: PimPacket_m.h:99
inet::routeAddedSignal
simsignal_t routeAddedSignal
Definition: Simsignals.cc:41
inet::PimDm::pruneInterval
double pruneInterval
Definition: PimDm.h:154
inet::ENCODED_SOURCE_ADDRESS_LENGTH
const B ENCODED_SOURCE_ADDRESS_LENGTH
Definition: PimPacket_m.h:71
inet::PimDm::processJoinPrunePacket
void processJoinPrunePacket(Packet *pk)
Definition: PimDm.cc:475
NUM_INIT_STAGES
#define NUM_INIT_STAGES
Definition: InitStageRegistry.h:73
inet::ipv4DataOnNonrpfSignal
simsignal_t ipv4DataOnNonrpfSignal
Definition: Simsignals.cc:57
inet::sctp::max
double max(const double a, const double b)
Returns the maximum of a and b.
Definition: SctpAssociation.h:266
inet::PimBase::holdTime
double holdTime
Definition: PimBase.h:158
inet::PimDm::processPruneTimer
void processPruneTimer(cMessage *timer)
Definition: PimDm.cc:303
inet::PimDm::DownstreamInterface::PRUNED
@ PRUNED
Definition: PimDm.h:98
inet::PimBase::processHelloTimer
void processHelloTimer(cMessage *timer)
Definition: PimBase.cc:95
inet::PimDm::sentGraftAckPkSignal
static simsignal_t sentGraftAckPkSignal
Definition: PimDm.h:166
inet::PimDm::processJoin
void processJoin(Route *route, int intId, int numRpfNeighbors, Ipv4Address upstreamNeighborField)
Definition: PimDm.cc:517
inet::PimBase::pimNbt
ModuleRefByPar< PimNeighborTable > pimNbt
Definition: PimBase.h:149
inet::PimDm::sendGraftPacket
void sendGraftPacket(Ipv4Address nextHop, Ipv4Address src, Ipv4Address grp, int intId)
Definition: PimDm.cc:1502
inet::PimDm::unroutableMulticastPacketArrived
void unroutableMulticastPacketArrived(Ipv4Address srcAddress, Ipv4Address destAddress, unsigned short ttl)
The method process notification about new multicast data stream.
Definition: PimDm.cc:1055
inet::PimDm::processGraftPacket
void processGraftPacket(Packet *pk)
Definition: PimDm.cc:673
inet::PimDm::stateRefreshInterval
double stateRefreshInterval
Definition: PimDm.h:160
inet::Ipv4Address::UNSPECIFIED_ADDRESS
static const Ipv4Address UNSPECIFIED_ADDRESS
0.0.0.0
Definition: Ipv4Address.h:91
Enter_Method
#define Enter_Method(...)
Definition: SelfDoc.h:71
inet::units::units::ps
pico< s >::type ps
Definition: Units.h:1073
inet::ipv4MulticastGroupUnregisteredSignal
simsignal_t ipv4MulticastGroupUnregisteredSignal
Definition: Simsignals.cc:53
inet::PimDm::pruneLimitInterval
double pruneLimitInterval
Definition: PimDm.h:155
inet::PimDm::sentAssertPkSignal
static simsignal_t sentAssertPkSignal
Definition: PimDm.h:170
inet::PimDm::graftRetryInterval
double graftRetryInterval
Definition: PimDm.h:158
inet::PimDm::processPrunePendingTimer
void processPrunePendingTimer(cMessage *timer)
Definition: PimDm.cc:339
inet::PimDm::rcvdJoinPrunePkSignal
static simsignal_t rcvdJoinPrunePkSignal
Definition: PimDm.h:169
inet::PimDm::sendPrunePacket
void sendPrunePacket(Ipv4Address nextHop, Ipv4Address src, Ipv4Address grp, int holdTime, int intId)
Definition: PimDm.cc:1436
inet::PimDm::processGraftRetryTimer
void processGraftRetryTimer(cMessage *timer)
Definition: PimDm.cc:364
inet::PimBase::AssertTimer
@ AssertTimer
Definition: PimBase.h:125
inet::PimDm::stopPIMRouting
virtual void stopPIMRouting()
Definition: PimDm.cc:91
inet::PimDm::overrideInterval
double overrideInterval
Definition: PimDm.h:156
inet::Assert
@ Assert
Definition: PimPacket_m.h:98
inet::PimBase::GraftRetryTimer
@ GraftRetryTimer
Definition: PimBase.h:130
inet::ENCODED_UNICODE_ADDRESS_LENGTH
const B ENCODED_UNICODE_ADDRESS_LENGTH
Definition: PimPacket_m.h:69
inet::PimDm::processOverrideTimer
void processOverrideTimer(cMessage *timer)
Definition: PimDm.cc:383
inet::PimBase::handleStopOperation
virtual void handleStopOperation(LifecycleOperation *operation) override
Definition: PimBase.cc:81
inet::PimDm::multicastPacketArrivedOnNonRpfInterface
void multicastPacketArrivedOnNonRpfInterface(Ipv4Address group, Ipv4Address source, int interfaceId)
The method has to solve the problem when multicast data appears on non-RPF interface.
Definition: PimDm.cc:1223
inet::IRoute::IFACENETMASK
@ IFACENETMASK
comes from an interface's netmask
Definition: IRoute.h:30
inet::PimBase::initialize
virtual void initialize(int stage) override
Definition: PimBase.cc:37
inet::PimDm::graftPruneStateString
const static std::string graftPruneStateString(UpstreamInterface::GraftPruneState ps)
Definition: PimDm.cc:1966
inet::PimDm::processStateRefreshTimer
void processStateRefreshTimer(cMessage *timer)
Definition: PimDm.cc:443
inet::PimBase::processHelloPacket
void processHelloPacket(Packet *pk)
Definition: PimBase.cc:153
inet::PimBase::HelloTimer
@ HelloTimer
Definition: PimBase.h:121
inet::PimDm::UpstreamInterface::NOT_ORIGINATOR
@ NOT_ORIGINATOR
Definition: PimDm.h:45
inet::GraftAck
@ GraftAck
Definition: PimPacket_m.h:100
inet::JoinPrune
@ JoinPrune
Definition: PimPacket_m.h:96
inet::PimBase::rt
ModuleRefByPar< IIpv4RoutingTable > rt
Definition: PimBase.h:146