NS-3 based Named Data Networking (NDN) simulator
ndnSIM: NDN, CCN, CCNx, content centric networks
|
Overall ndnSIM documentation |
ndnSIM includes a few reference applications that can be used as a base for NDN simulations.
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:
// Set attribute using the app helper
helper.SetAttribute ("Randomize", StringValue ("uniform"));
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)
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 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.
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.
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
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);
...
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
|