NS-3 based Named Data Networking (NDN) simulator
ndnSIM: NDN, CCN, CCNx, content centric networks
Overall ndnSIM documentation

Forwarding Strategies

ndnSIM provides simple ways to experiment with custom Interest/Data forwarding strategies. A new forwarding strategy can be implement completely different processing or override just specific actions/events of the forwarding strategy interface. Please refer to API documentation of the forwarding strategy interface, which lists all default actions/events.

Available forwarding strategies

Basic forwarding strategies

Flooding

Interests will be forwarded to all available faces available for a route (FIB entry). If there are no available GREEN or YELLOW faces, interests is dropped.

Implementation name: ns3::ndn::fw::Flooding (default)

Usage example:

ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::Flooding");
...
ndnHelper.Install (nodes);

SmartFlooding

If GREEN face is available, Interest will be sent to the highest-ranked GREEN face. If not, Interest will be forwarded to all available faces available for a route (FIB entry)/ If there are no available GREEN or YELLOW faces, interests is dropped.

Implementation name ns3::ndn::fw::SmartFlooding

Usage example:

ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::SmartFlooding");
...
ndnHelper.Install (nodes);

BestRoute

If GREEN face is available, Interest will be sent to the highest-ranked GREEN face. If not, Interest will be forwarded to the highest-ranked YELLOW face. If there are no available GREEN or YELLOW faces, interests is dropped.

Implementation name: ns3::ndn::fw::BestRoute

Usage example:

ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::BestRoute");
...
ndnHelper.Install (nodes);

Strategies with Interest limits

The following strategies enforce different granularities of Interest limits. Each strategy is an extension of the basic one (custom strategies can also be extended with limits, refer to the source code).

Currently, ndnSIM implements two types of Interest limit enforcements, both based on a Token Bucket approach:

  • ns3::ndn::Limits::Window (default)

    Interest token is borrowed when Interest is send out. The token is returned only when Interest is satisfied or times out.

  • ns3::ndn::Limits::Rate

    Interest token is borrowed when Interest is send out. The token is returned periodically based on link capacity.

In both cases, limit is set according to the following equation:

\[\mathrm{Interest\ Limit} = Delay\ [s] \cdot \frac{\mathrm{Bandwidth\ [Bytes/s]}} {\mathrm{Data\ packet\ size\ [Bytes]} + \mathrm{Interest\ packet\ size\ [Bytes]}}\]

To configure packet sizes and delay parameters, use the following ndn::StackHelper method:

// ndnHelper.EnableLimits (true, <delay>, <average interest packet size>, <average data packet size>);
ndnHelper.EnableLimits (true, Seconds (0.2), 40, 1100);
...
ndnHelper.Install (nodes);

Usage examples

Per outgoing Face limits
  • ns3::ndn::fw::Flooding::PerOutFaceLimits

    With Limits::Window:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::Flooding::PerOutFaceLimits"
                                     "Limit", "ns3::ndn::Limits::Window");
    ...
    ndnHelper.Install (nodes);
    

    With Limits::Rate:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::Flooding::PerOutFaceLimits"
                                     "Limit", "ns3::ndn::Limits::Rate");
    ...
    ndnHelper.Install (nodes);
    
  • ns3::ndn::fw::SmartFlooding::PerOutFaceLimits

    With Limits::Window:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::SmartFlooding::PerOutFaceLimits"
                                     "Limit", "ns3::ndn::Limits::Window");
    ...
    ndnHelper.Install (nodes);
    

    With Limits::Rate:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::SmartFlooding::PerOutFaceLimits"
                                     "Limit", "ns3::ndn::Limits::Rate");
    ...
    ndnHelper.Install (nodes);
    
  • ns3::ndn::fw::BestRoute::PerOutFaceLimits

    With Limits::Window:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::BestRoute::PerOutFaceLimits"
                                     "Limit", "ns3::ndn::Limits::Window");
    ...
    ndnHelper.Install (nodes);
    

    With Limits::Rate:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::BestRoute::PerOutFaceLimits"
                                     "Limit", "ns3::ndn::Limits::Rate");
    ...
    ndnHelper.Install (nodes);
    
Per FIB entry, per outgoing face limits
  • ns3::ndn::fw::Flooding::PerOutFaceLimits::PerFibLimits

    With Limits::Window:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::Flooding::PerOutFaceLimits::PerFibLimits"
                                     "Limit", "ns3::ndn::Limits::Window");
    ...
    ndnHelper.Install (nodes);
    

    With Limits::Rate:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::Flooding::PerOutFaceLimits::PerFibLimits"
                                     "Limit", "ns3::ndn::Limits::Rate");
    ...
    ndnHelper.Install (nodes);
    
  • ns3::ndn::fw::SmartFlooding::PerOutFaceLimits::PerFibLimits

    With Limits::Window:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::SmartFlooding::PerOutFaceLimits::PerFibLimits"
                                     "Limit", "ns3::ndn::Limits::Window");
    ...
    ndnHelper.Install (nodes);
    

    With Limits::Rate:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::SmartFlooding::PerOutFaceLimits::PerFibLimits"
                                     "Limit", "ns3::ndn::Limits::Rate");
    ...
    ndnHelper.Install (nodes);
    
  • ns3::ndn::fw::BestRoute::PerOutFaceLimits::PerFibLimits

    With Limits::Window:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::BestRoute::PerOutFaceLimits::PerFibLimits"
                                     "Limit", "ns3::ndn::Limits::Window");
    ...
    ndnHelper.Install (nodes);
    

    With Limits::Rate:

    ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::BestRoute::PerOutFaceLimits::PerFibLimits"
                                     "Limit", "ns3::ndn::Limits::Rate");
    ...
    ndnHelper.Install (nodes);
    

Writing your own custom strategy

First step in creating your own strategy is to decide which existing strategy you want to extend. You can either use realize forwarding strategy interface (ndn::ForwardingStrategy::DoPropagateInterest() call must be implemented) or extended one of the available forwarding strategies (fw::BestRoute or fw::Flooding). The following example assumes that we are realizing forwarding strategy interface.

The follwoing are template strategy h/cc files:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */

// custom-strategy.h
        
#ifndef CUSTOM_STRATEGY_H
#define CUSTOM_STRATEGY_H

#include "ns3/log.h"
#include "ns3/ndn-forwarding-strategy.h"
#include "ns3/ndn-l3-protocol.h"
                
namespace ns3 {
namespace ndn {
namespace fw {

typedef ForwardingStrategy BaseStrategy;

class CustomStrategy:
    public BaseStrategy
{
public:
  static TypeId
  GetTypeId ();
        
  static std::string
  GetLogName ();
          
  CustomStrategy ();
        
protected:
  virtual bool
  DoPropagateInterest (Ptr<Face> incomingFace,
                       Ptr<const Interest> interest,
                       Ptr<pit::Entry> pitEntry);

public:
        
// private:
//   std::string m_variable;

private:
        
        
} // namespace fw
} // namespace ndn
} // namespace ns3
                
#endif // CUSTOM_STRATEGY_H
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
// custom-strategy.cc

#include "custom-strategy.h"
#include "ns3/ndn-fib.h"
#include "ns3/ndn-fib-entry.h"
#include "ns3/ndn-pit-entry.h"
#include "ns3/ndn-interest.h"

namespace ns3 {
namespace ndn {
namespace fw {

NS_OBJECT_ENSURE_REGISTERED(CustomStrategy);

LogComponent CustomStrategy::g_log = LogComponent (CustomStrategy::GetLogName ().c_str ());

std::string
CustomStrategy::GetLogName ()
{
  return "ndn.fw.CustomStrategy";
}

TypeId
CustomStrategy::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::ndn::fw::CustomStrategy")
    .SetGroupName ("Ndn")
    .SetParent <BaseStrategy> ()
    .AddConstructor <CustomStrategy> ()

    // .AddAttribute ("Attribute", "Attribute spec",
    //                         StringValue ("DefaultValue"),
    //                         MakeStringAccessor (&BaseStrategy::m_variable),
    //                         MakeStringChecker ())
    ;
  return tid;
}

CustomStrategy::CustomStrategy ()
{
}

bool
CustomStrategy::DoPropagateInterest (Ptr<Face> inFace,
                                     Ptr<const Interest> interest,
                                     Ptr<pit::Entry> pitEntry)
{
  typedef fib::FaceMetricContainer::type::index<fib::i_metric>::type FacesByMetric;

void
} // namespace ns3

After having the template, we can fill the necesasry functionality.

Let us say, that we want Interest be forwarded to first two best-metric faces specified by FIB. That is, if node has two or more alternative paths to forward the Interests, this Interest will be forwarded to the best two neighbors. The following implementation of CustomStrategy::DoPropagateInterest accomplishes the task:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
bool
CustomStrategy::DoPropagateInterest (Ptr<Face> inFace,
                                     Ptr<const Interest> interest,
                                     Ptr<pit::Entry> pitEntry)
{
  typedef fib::FaceMetricContainer::type::index<fib::i_metric>::type FacesByMetric;
  FacesByMetric &faces = pitEntry->GetFibEntry ()->m_faces.get<fib::i_metric> ();
  FacesByMetric::iterator faceIterator = faces.begin ();

  int propagatedCount = 0;

  // forward to best-metric face
  if (faceIterator != faces.end ())
    {
      if (TrySendOutInterest (inFace, faceIterator->GetFace (), interest, pitEntry))
        propagatedCount ++;

      faceIterator ++;
    }

  // forward to second-best-metric face
  if (faceIterator != faces.end ())
    {
      if (TrySendOutInterest (inFace, faceIterator->GetFace (), interest, pitEntry))
        propagatedCount ++;

      faceIterator ++;
    }
  return propagatedCount > 0;
}

After the compilation, you can use "ns3::ndn::fw::CustomStrategy" as a parameter to ndn::StackHelper::SetForwardingStrategy() helper method.

Extending strategy

If you need more customization for the forwarding strategy, there are many forwarding strategy events that can be overriden. For example, if we want to perform special logging of all forwarded, timed out, and satisfied Intersts, we can override the following events (for more events, refer to ForwardingStrategy API documentation):

The highlighted ares of the following code demonstrates how it can be impelmented:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */

// custom-strategy.h
        
#ifndef CUSTOM_STRATEGY_H
#define CUSTOM_STRATEGY_H

#include "ns3/log.h"
#include "ns3/ndn-forwarding-strategy.h"
#include "ns3/ndn-l3-protocol.h"
                
namespace ns3 {
namespace ndn {
namespace fw {

typedef ForwardingStrategy BaseStrategy;

class CustomStrategy:
    public BaseStrategy
{
public:
  static TypeId
  GetTypeId ();
        
  static std::string
  GetLogName ();
          
  CustomStrategy ();
        
protected:
  virtual bool
  DoPropagateInterest (Ptr<Face> incomingFace,
                       Ptr<const Interest> interest,
                       Ptr<pit::Entry> pitEntry);

public:
  virtual void
  DidSendOutInterest (Ptr<Face> inFace, Ptr<Face> outFace,
                      Ptr<const Interest> interest,
                      Ptr<pit::Entry> pitEntry);

  virtual void
  WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry);

  virtual void
  WillSatisfyPendingInterest (Ptr<Face> inFace,
                              Ptr<pit::Entry> pitEntry);
        
protected:
  static LogComponent g_log;
        
// private:
//   std::string m_variable;

private:
  uint32_t m_counter;
};
        
        
        
} // namespace fw
} // namespace ndn
} // namespace ns3
                
#endif // CUSTOM_STRATEGY_H
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
// custom-strategy.cc

#include "custom-strategy.h"
#include "ns3/ndn-fib.h"
#include "ns3/ndn-fib-entry.h"
#include "ns3/ndn-pit-entry.h"
#include "ns3/ndn-interest.h"

namespace ns3 {
namespace ndn {
namespace fw {

NS_OBJECT_ENSURE_REGISTERED(CustomStrategy);

LogComponent CustomStrategy::g_log = LogComponent (CustomStrategy::GetLogName ().c_str ());

std::string
CustomStrategy::GetLogName ()
{
  return "ndn.fw.CustomStrategy";
}

TypeId
CustomStrategy::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::ndn::fw::CustomStrategy")
    .SetGroupName ("Ndn")
    .SetParent <BaseStrategy> ()
    .AddConstructor <CustomStrategy> ()

    // .AddAttribute ("Attribute", "Attribute spec",
    //                         StringValue ("DefaultValue"),
    //                         MakeStringAccessor (&BaseStrategy::m_variable),
    //                         MakeStringChecker ())
    ;
  return tid;
}

CustomStrategy::CustomStrategy ()
  : m_counter (0)
{
}

bool
CustomStrategy::DoPropagateInterest (Ptr<Face> inFace,
                                     Ptr<const Interest> interest,
                                     Ptr<pit::Entry> pitEntry)
{
  typedef fib::FaceMetricContainer::type::index<fib::i_metric>::type FacesByMetric;
  FacesByMetric &faces = pitEntry->GetFibEntry ()->m_faces.get<fib::i_metric> ();
  FacesByMetric::iterator faceIterator = faces.begin ();

  int propagatedCount = 0;

  // forward to best-metric face
  if (faceIterator != faces.end ())
    {
      if (TrySendOutInterest (inFace, faceIterator->GetFace (), interest, pitEntry))
        propagatedCount ++;

      faceIterator ++;
    }

  // forward to second-best-metric face
  if (faceIterator != faces.end ())
    {
      if (TrySendOutInterest (inFace, faceIterator->GetFace (), interest, pitEntry))
        propagatedCount ++;

      faceIterator ++;
    }
  return propagatedCount > 0;
}

void
CustomStrategy::DidSendOutInterest (Ptr<Face> inFace, Ptr<Face> outFace,
                                    Ptr<const Interest> interest,
                                    Ptr<pit::Entry> pitEntry)
{
  m_counter ++;
}

void
CustomStrategy::WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry)
{
  for (pit::Entry::out_container::iterator face = pitEntry->GetOutgoing ().begin ();
       face != pitEntry->GetOutgoing ().end ();
       face ++)
    {
      m_counter --;
    }

  BaseStrategy::WillEraseTimedOutPendingInterest (pitEntry);
}


void
CustomStrategy::WillSatisfyPendingInterest (Ptr<Face> inFace,
                                            Ptr<pit::Entry> pitEntry)
{
  for (pit::Entry::out_container::iterator face = pitEntry->GetOutgoing ().begin ();
       face != pitEntry->GetOutgoing ().end ();
       face ++)
    {
      m_counter --;
    }

  BaseStrategy::WillSatisfyPendingInterest (inFace, pitEntry);
}


} // namespace fw
} // namespace ndn
} // namespace ns3

Example of using custom strategy

Please refer to this example.