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

ndnSIM applications

ndnSIM includes a few reference applications that can be used as a base for NDN simulations.

Reference applications

ConsumerCbr

ConsumerCbr an application that generates Interest traffic with predefined pattern (constant frequency, constant average rate with inter-Interest gap distributed uniformly at random, exponentially at random, etc.).

// Create application using the app helper
ndn::AppHelper helper ("ns3::ndn::ConsumerCbr");

This applications has the following attributes:

  • Frequency

    Note

    default: 1.0 (1 per second)

    Either exact (for contant version) or expected (for randomized version) frequency with which Interests are generated

    // Set attribute using the app helper
    helper.SetAttribute ("Frequency", DoubleValue (1.0));
    
  • Randomize

    Note

    default: "none"

    Specify whether to do randomization for inter-Interest gap or not. The following variants are currently supported:

    • "none": no randomization
    • "uniform": uniform distribution in range (0, 1/Frequency)
    • "exponential": exponential distribution with mean 1/Frequency
    // Set attribute using the app helper
    helper.SetAttribute ("Randomize", StringValue ("uniform"));
    

ConsumerZipfMandelbrot

Note

Author: Xiaoke Jiang

An app that requests contents (names in the requests) following Zipf-Mandelbrot distribution (number of Content frequency Distribution). This class is a subclass of ConsumerCbr.

// Create application using the app helper
ndn::AppHelper helper ("ns3::ndn::ConsumerZipfMandelbrot");

Frequency and Randomize attributes can be used in the same way as in the base ConsumerCbr applications.

Additional attributes:

  • NumberOfContents

    Note

    default: 100

    Number of different content (sequence numbers) that will be requested by the applications

THE following pictures show basic comparison of the generated stream of Interests versus theoretical Zipf-Mandelbrot function (NumberOfContents set to 100 and Frequency set to 100)

Comparsion between simulation and theory with simulation duration 10 seconds Comparsion between simulation and theory with simulation duration 50 seconds Comparsion between simulation and theory with simulation duration 100 seconds Comparsion between simulation and theory with simulation duration 1000 seconds

ConsumerBatches

ConsumerBatches is an on-off-style application gen- erating a specified number of Interests at specified points of simulation.

// Create application using the app helper
ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerBatches");

This applications has the following attributes:

  • Batches

    Note

    default: Empty

    Specify exact pattern of Interest packets, specifying when and how many Interest packets should be sent. The following example defines that 1 Interest should be requested at time 1s, 5 Interests at time 5s, and 2 Interests at time 10s.:

    // Set attribute using the app helper
    helper.SetAttribute ("Batches", StringValue ("1s 1 2s 5 10s 2"));
    

ConsumerWindow

ConsumerWindow is an application generating a variable rate Interest traffic. It relies on an optional NACK-Interest feature and implements a simple sliding-window-based Interest generation mechanism.

// Create application using the app helper
ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerWindow");

This applications has the following attributes:

  • Window

    Note

    default: 1

    Initial number of Interests that will be send out without waiting for the data (number of outstanding Interests)

  • PayloadSize

    Note

    default: 1040

    Expected size of the Data payload (necessary only when Size is specified)

  • Size

    Note

    default: -1

    Amount of data to be requested (will stop issuing Interests after Size data is received)

    If Size is set to -1, Interests will be requested till the end of the simulation.

Producer

Producer a simple Interest-sink application, which replying every incoming Interest with Data packet with a specified size and name same as in Interest.

// Create application using the app helper
ndn::AppHelper consumerHelper ("ns3::ndn::Producer");

Custom applications

Applications interact with the core of the system using AppFace realization of Face abstraction. To simplify implementation of specific NDN application, ndnSIM provides a base App class that takes care of creating AppFace and registering it inside the NDN protocol stack, as well as provides default processing for incoming Interest and Data packets.

Customer example

The following code shows how a simple ndnSIM application can be created, and how an application can send Interests and respond with ContentObjects to incoming interests.

When this application starts it sets “interest filter” (install FIB entry) for /prefix/sub, as well as sends Interest for this prefix. When an Interest is received, it is replied with a ContentObject with 1024-byte fake payload.

For more details refer examples/custom-apps/custom-app.h, examples/custom-apps/custom-app.cc and API documentation of ndnSIM and NS-3.

Header file examples/custom-apps/custom-app.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
// custom-app.h

#ifndef CUSTOM_APP_H_
#define CUSTOM_APP_H_

#include "ns3/ndn-app.h"

namespace ns3 {

class CustomApp : public ndn::App
{
public:
  // register NS-3 type "CustomApp"
  static TypeId
  GetTypeId ();
  
  // (overridden from ndn::App) Processing upon start of the application
  virtual void
  StartApplication ();

  // (overridden from ndn::App) Processing when application is stopped
  virtual void
  StopApplication ();

  // (overridden from ndn::App) Callback that will be called when Interest arrives
  virtual void
  OnInterest (Ptr<const ndn::Interest> interest);

  // (overridden from ndn::App) Callback that will be called when Data arrives
  virtual void
  OnData (Ptr<const ndn::Data> contentObject);

private:
  void
  SendInterest ();
};

} // namespace ns3

#endif // CUSTOM_APP_H_

Source file examples/custom-apps/custom-app.cc:

  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
116
117
118
119
120
121
122
123
124
// custom-app.cc

#include "custom-app.h"
#include "ns3/ptr.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "ns3/packet.h"

#include "ns3/ndn-app-face.h"
#include "ns3/ndn-interest.h"
#include "ns3/ndn-data.h"

#include "ns3/ndn-fib.h"
#include "ns3/random-variable.h"

NS_LOG_COMPONENT_DEFINE ("CustomApp");

namespace ns3 {

NS_OBJECT_ENSURE_REGISTERED (CustomApp);

// register NS-3 type
TypeId
CustomApp::GetTypeId ()
{
  static TypeId tid = TypeId ("CustomApp")
    .SetParent<ndn::App> ()
    .AddConstructor<CustomApp> ()
    ;
  return tid;
}

// Processing upon start of the application
void
CustomApp::StartApplication ()
{
  // initialize ndn::App
  ndn::App::StartApplication ();

  // Create a name components object for name ``/prefix/sub``
  Ptr<ndn::Name> prefix = Create<ndn::Name> (); // now prefix contains ``/``
  prefix->append ("prefix"); // now prefix contains ``/prefix``
  prefix->append ("sub"); // now prefix contains ``/prefix/sub``

  /////////////////////////////////////////////////////////////////////////////
  // Creating FIB entry that ensures that we will receive incoming Interests //
  /////////////////////////////////////////////////////////////////////////////

  // Get FIB object
  Ptr<ndn::Fib> fib = GetNode ()->GetObject<ndn::Fib> ();

  // Add entry to FIB
  // Note that ``m_face`` is cretaed by ndn::App
  Ptr<ndn::fib::Entry> fibEntry = fib->Add (*prefix, m_face, 0);

  Simulator::Schedule (Seconds (1.0), &CustomApp::SendInterest, this);
}

// Processing when application is stopped
void
CustomApp::StopApplication ()
{
  // cleanup ndn::App
  ndn::App::StopApplication ();
}

void
CustomApp::SendInterest ()
{
  /////////////////////////////////////
  // Sending one Interest packet out //
  /////////////////////////////////////
  
  Ptr<ndn::Name> prefix = Create<ndn::Name> ("/prefix/sub"); // another way to create name

  // Create and configure ndn::Interest
  Ptr<ndn::Interest> interest = Create<ndn::Interest> ();
  UniformVariable rand (0,std::numeric_limits<uint32_t>::max ());
  interest->SetNonce            (rand.GetValue ());
  interest->SetName             (prefix);
  interest->SetInterestLifetime (Seconds (1.0));

  NS_LOG_DEBUG ("Sending Interest packet for " << *prefix);
  
  // Call trace (for logging purposes)
  m_transmittedInterests (interest, this, m_face);

  m_face->ReceiveInterest (interest);
}

// Callback that will be called when Interest arrives
void
CustomApp::OnInterest (Ptr<const ndn::Interest> interest)
{
  ndn::App::OnInterest (interest);
  
  NS_LOG_DEBUG ("Received Interest packet for " << interest->GetName ());

  // Create and configure ndn::Data and ndn::DataTail
  // (header is added in front of the packet, tail is added at the end of the packet)

  // Note that Interests send out by the app will not be sent back to the app !
  
  Ptr<ndn::Data> data = Create<ndn::Data> (Create<Packet> (1024));
  data->SetName (Create<ndn::Name> (interest->GetName ())); // data will have the same name as Interests

  NS_LOG_DEBUG ("Sending Data packet for " << data->GetName ());  

  // Call trace (for logging purposes)
  m_transmittedDatas (data, this, m_face);

  m_face->ReceiveData (data); 
}

// Callback that will be called when Data arrives
void
CustomApp::OnData (Ptr<const ndn::Data> contentObject)
{
  NS_LOG_DEBUG ("Receiving Data packet for " << contentObject->GetName ());

  std::cout << "DATA received for name " << contentObject->GetName () << std::endl;
}

} // namespace ns3

Example how to use custom app in a scenario (ndn-simple-with-custom-app.cc):

 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
// ndn-simple-with-custom-app.cc

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/ndnSIM-module.h"

using namespace ns3;

int 
main (int argc, char *argv[])
{
  // Read optional command-line parameters (e.g., enable visualizer with ./waf --run=<> --visualize
  CommandLine cmd;
  cmd.Parse (argc, argv);

  // Creating nodes
  Ptr<Node> node = CreateObject<Node> ();

  // Install CCNx stack on all nodes
  ndn::StackHelper ccnxHelper;
  ccnxHelper.InstallAll ();

  // Installing applications

  // Consumer
  ndn::AppHelper consumerHelper ("CustomApp");
  ApplicationContainer app1 = consumerHelper.Install (node); 
  ApplicationContainer app2 = consumerHelper.Install (node);

  app1.Start (Seconds (1.0)); // will send out Interest, which nobody will receive (Interests generated by an app will not got back to the app)
  app2.Start (Seconds (2.0)); // will send out an Interests, which will be received and satisfied by app1
  
  Simulator::Stop (Seconds (3.0));

  Simulator::Run ();
  Simulator::Destroy ();

  return 0;
}

To run this scenario, use the following command:

NS_LOG=CustomApp ./waf --run=ndn-simple-with-custom-app

Producer example (Interest hijacker)

The following code demonstrates how to implement a basic producer application that “hijacks” all incoming Interests.

Header file examples/custom-apps/hijacker.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
// hijacker.h

#ifndef HIJACKER_H_
#define HIJACKER_H_

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/ndnSIM-module.h"

namespace ns3 {

class Hijacker : public ndn::App
{
public:
  static TypeId
  GetTypeId ();

  Hijacker ();

  // Receive all Interests but do nothing in response
  void
  OnInterest (Ptr<const ndn::Interest> interest);

protected:
  // inherited from Application base class.
  virtual void
  StartApplication ();

  virtual void
  StopApplication ();
};

} // namespace ns3

#endif // HIJACKER_H_

Source file examples/custom-apps/hijacker.cc:

 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
// hijacker.cc

#include "hijacker.h"
#include "ns3/ndn-name.h"

NS_LOG_COMPONENT_DEFINE ("Hijacker");

namespace ns3 {

// Necessary if you are planning to use ndn::AppHelper
NS_OBJECT_ENSURE_REGISTERED (Hijacker);

TypeId
Hijacker::GetTypeId ()
{
  static TypeId tid = TypeId ("Hijacker")
    .SetParent<ndn::App> ()
    .AddConstructor<Hijacker> ()
    ;

  return tid;
}

Hijacker::Hijacker ()
{
}

void
Hijacker::OnInterest (Ptr<const ndn::Interest> interest)
{
  ndn::App::OnInterest (interest); // forward call to perform app-level tracing
  // do nothing else (hijack interest)

  NS_LOG_DEBUG ("Do nothing for incoming interest for" << interest->GetName ());
}

void
Hijacker::StartApplication ()
{
  App::StartApplication ();

  // equivalent to setting interest filter for "/" prefix
  Ptr<ndn::Fib> fib = GetNode ()->GetObject<ndn::Fib> ();
  Ptr<ndn::fib::Entry> fibEntry = fib->Add (ndn::Name ("/"), m_face, 0);
  fibEntry->UpdateStatus (m_face, ndn::fib::FaceMetric::NDN_FIB_GREEN);
}

void
Hijacker::StopApplication ()
{
  App::StopApplication ();
}

} // namespace ns3

After defining this class, you can use it with ndn::AppHelper. For example:

...
ndn::AppHelper producerHelper ("Hijacker");
producerHelper.Install (producerNode);
...

Dumb requester

This application continually requests the same Data packet.

Header file examples/custom-apps/dumb-requester.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
// dumb-requester.h

#ifndef DUMB_REQUESTER_H_
#define DUMB_REQUESTER_H_

#include "ns3/ndn-app.h"
#include "ns3/ndn-name.h"

namespace ns3 {

/**
 * @brief A dumb requester application
 *
 * This app keeps requesting every second the same content object 
 */
class DumbRequester : public ndn::App
{
public:
  // register NS-3 type "DumbRequester"
  static TypeId
  GetTypeId ();

  DumbRequester ();
  
  // (overridden from ndn::App) Processing upon start of the application
  virtual void
  StartApplication ();

  // (overridden from ndn::App) Processing when application is stopped
  virtual void
  StopApplication ();

  // (overridden from ndn::App) Callback that will be called when Data arrives
  virtual void
  OnData (Ptr<const ndn::Data> contentObject);
  
private:
  void
  SendInterest ();

private:
  bool m_isRunning;
  ndn::Name m_name;
};

} // namespace ns3

#endif // DUMB_REQUESTER_H_

Source file examples/custom-apps/dumb-requester.cc:

 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
// dumb-requester.cc

#include "dumb-requester.h"
#include "ns3/ptr.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "ns3/packet.h"
#include "ns3/random-variable.h"
#include "ns3/string.h"

#include "ns3/ndn-app-face.h"
#include "ns3/ndn-interest.h"
#include "ns3/ndn-data.h"

NS_LOG_COMPONENT_DEFINE ("DumbRequester");

namespace ns3 {

NS_OBJECT_ENSURE_REGISTERED (DumbRequester);

// register NS-3 type
TypeId
DumbRequester::GetTypeId ()
{
  static TypeId tid = TypeId ("DumbRequester")
    .SetParent<ndn::App> ()
    .AddConstructor<DumbRequester> ()

    .AddAttribute ("Prefix", "Requested name",
                   StringValue ("/dumb-interest"),
                   ndn::MakeNameAccessor (&DumbRequester::m_name),
                   ndn::MakeNameChecker ())
    ;
  return tid;
}

DumbRequester::DumbRequester ()
  : m_isRunning (false)
{
}

// Processing upon start of the application
void
DumbRequester::StartApplication ()
{
  // initialize ndn::App
  ndn::App::StartApplication ();

  m_isRunning = true;
  Simulator::ScheduleNow (&DumbRequester::SendInterest, this);
}

// Processing when application is stopped
void
DumbRequester::StopApplication ()
{
  m_isRunning = false;
  // cleanup ndn::App
  ndn::App::StopApplication ();
}

void
DumbRequester::SendInterest ()
{
  if (!m_isRunning) return;
  
  /////////////////////////////////////
  // Sending one Interest packet out //
  /////////////////////////////////////
  
  Ptr<ndn::Name> prefix = Create<ndn::Name> (m_name); // another way to create name

  // Create and configure ndn::Interest
  Ptr<ndn::Interest> interest = Create<ndn::Interest> ();
  UniformVariable rand (0,std::numeric_limits<uint32_t>::max ());
  interest->SetNonce            (rand.GetValue ());
  interest->SetName             (prefix);
  interest->SetInterestLifetime (Seconds (1.0));

  NS_LOG_DEBUG ("Sending Interest packet for " << *prefix);
  

  // Call trace (for logging purposes)
  m_transmittedInterests (interest, this, m_face);

  // Forward packet to lower (network) layer
  m_face->ReceiveInterest (interest);

  Simulator::Schedule (Seconds (1.0), &DumbRequester::SendInterest, this);
}

void
DumbRequester::OnData (Ptr<const ndn::Data> contentObject)
{
  NS_LOG_DEBUG ("Receiving Data packet for " << contentObject->GetName ());
}


} // namespace ns3