Examples

Note

!!! This page only shows up examples of how to config topology and perform basic operations in ndnSIM (an example equivalent to “Hello, world1”) !!! These are **NOT** examples of real experimentations (just like “Hello, world!” is not a real program).

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

Note

A few mobile simulation scenarios are available. The project code may require a custom version of ndnSIM (see project commits for further details).

Simple scenario

The first example (ndn-simple.cpp) shows very basics of ndnSIM. In the simulated topology there are 3 nodes, connected with point-to-point links, one NDN consumer, and one NDN producer:

Consumer is simulated using ConsumerCbr reference application and generates Interests towards the producer with frequency of 10 Interests per second (see ndnSIM applications).

Producer is simulated using Producer class, which is used to satisfy all incoming Interests with virtual payload data (1024 bytes).

FIB on every node is populated using default routes (see ndnSIM helpers) and the content store structure of the original ndnSIM is used.

The following code represents all that is necessary to run such a simple scenario

 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
// ndn-simple.cpp

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

namespace ns3 {

int
main(int argc, char* argv[])
{
  // setting default parameters for PointToPoint links and channels
  Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps"));
  Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
  Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("20p"));

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

  // Creating nodes
  NodeContainer nodes;
  nodes.Create(3);

  // Connecting nodes using two links
  PointToPointHelper p2p;
  p2p.Install(nodes.Get(0), nodes.Get(1));
  p2p.Install(nodes.Get(1), nodes.Get(2));

  // Install NDN stack on all nodes
  ndn::StackHelper ndnHelper;
  ndnHelper.SetDefaultRoutes(true);
  ndnHelper.InstallAll();

  // Choosing forwarding strategy
  ndn::StrategyChoiceHelper::InstallAll("/prefix", "/localhost/nfd/strategy/multicast");

  // Installing applications

  // Consumer
  ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  // Consumer will request /prefix/0, /prefix/1, ...
  consumerHelper.SetPrefix("/prefix");
  consumerHelper.SetAttribute("Frequency", StringValue("10")); // 10 interests a second
  auto apps = consumerHelper.Install(nodes.Get(0));                        // first node
  apps.Stop(Seconds(10.0)); // stop the consumer app at 10 seconds mark

  // Producer
  ndn::AppHelper producerHelper("ns3::ndn::Producer");
  // Producer will reply to all requests starting with /prefix
  producerHelper.SetPrefix("/prefix");
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.Install(nodes.Get(2)); // last node

  Simulator::Stop(Seconds(20.0));

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

  return 0;
}

} // namespace ns3

int
main(int argc, char* argv[])
{
  return ns3::main(argc, argv);
}

If this code is placed into scratch/ndn-simple.cpp and NS-3 is compiled in debug mode, you can run and see progress of the simulation using the following command (in optimized mode nothing will be printed out):

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-simple

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

9-node grid example

This scenario (ndn-grid.cpp) simulates a grid topology, which is constructed using PointToPointLayout NS-3 module.

FIB is populated using GlobalRoutingHelper (see ndnSIM helpers). The content store structure of NFD is used in all the nodes.

Consumer is simulated using ConsumerCbr reference application and generates Interests towards the producer with frequency of 100 interests per second (see ndnSIM applications).

Producer is simulated using Producer class, which is used to satisfy all incoming Interests with virtual payload data (1024 bytes).

The following code represents all that is necessary to run such a simple scenario

 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
// ndn-grid.cpp

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

namespace ns3 {

int
main(int argc, char* argv[])
{
  // Setting default parameters for PointToPoint links and channels
  Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps"));
  Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
  Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("10p"));

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

  // Creating 3x3 topology
  PointToPointHelper p2p;
  PointToPointGridHelper grid(3, 3, p2p);
  grid.BoundingBox(100, 100, 200, 200);

  // Install NDN stack on all nodes
  ndn::StackHelper ndnHelper;
  ndnHelper.InstallAll();

  // Set BestRoute strategy
  ndn::StrategyChoiceHelper::InstallAll("/", "/localhost/nfd/strategy/best-route");

  // Installing global routing interface on all nodes
  ndn::GlobalRoutingHelper ndnGlobalRoutingHelper;
  ndnGlobalRoutingHelper.InstallAll();

  // Getting containers for the consumer/producer
  Ptr<Node> producer = grid.GetNode(2, 2);
  NodeContainer consumerNodes;
  consumerNodes.Add(grid.GetNode(0, 0));

  // Install NDN applications
  std::string prefix = "/prefix";

  ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  consumerHelper.SetPrefix(prefix);
  consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  consumerHelper.Install(consumerNodes);

  ndn::AppHelper producerHelper("ns3::ndn::Producer");
  producerHelper.SetPrefix(prefix);
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.Install(producer);

  // Add /prefix origins to ndn::GlobalRouter
  ndnGlobalRoutingHelper.AddOrigins(prefix, producer);

  // Calculate and install FIBs
  ndn::GlobalRoutingHelper::CalculateRoutes();

  Simulator::Stop(Seconds(20.0));

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

  return 0;
}

} // namespace ns3

int
main(int argc, char* argv[])
{
  return ns3::main(argc, argv);
}

If this code is placed into scratch/ndn-grid.cpp and NS-3 is compiled in debug mode, you can run and see progress of the simulation using the following command (in optimized mode nothing will be printed out):

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-grid

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

9-node grid example using topology plugin

Instead of defining topology directly as in Simple scenario or using specialized helpers as in 9-node grid example, ndnSIM provides experimental extended versions of TopologyReader classes: AnnotatedTopologyReader and RocketfuelWeightsReader.

While RocketfuelWeightsReader is a specialized version intended to be used with Rocketfuel topology and link weights files (examples will be provided later), AnnotatedTopologyReader is a more general-use class that uses simple user-readable format.

AnnotatedTopologyReader expects the following format:

 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
# topo-grid-3x3.txt

# any empty lines and lines starting with '#' symbol is ignored
#
# The file should contain exactly two sections: router and link, each starting with the corresponding keyword
#
# router section defines topology nodes and their relative positions (e.g., to use in visualizer)
router

# each line in this section represents one router and should have the following data
# node  comment     yPos    xPos
Node0   NA          3       1
Node1   NA          3       2
Node2   NA          3       3
Node3   NA          2       1
Node4   NA          2       2
Node5   NA          2       3
Node6   NA          1       1
Node7   NA          1       2
Node8   NA          1       3
# Note that `node` can be any string. It is possible to access to the node by name using Names::Find, see examples.

# link section defines point-to-point links between nodes and characteristics of these links
link

# Each line should be in the following format (only first two are required, the rest can be omitted)
# srcNode   dstNode     bandwidth   metric  delay   queue
# bandwidth: link bandwidth
# metric: routing metric
# delay:  link delay
# queue:  MaxPackets for transmission queue on the link (both directions)
Node0       Node1       1Mbps       1       10ms    10
Node0       Node3       1Mbps       1       10ms    10
Node1       Node2       1Mbps       1       10ms    10
Node1       Node4       1Mbps       1       10ms    10
Node2       Node5       1Mbps       1       10ms    10
Node3       Node4       1Mbps       1       10ms    10
Node3       Node6       1Mbps       1       10ms    10
Node4       Node5       1Mbps       1       10ms    10
Node4       Node7       1Mbps       1       10ms    10
Node5       Node8       1Mbps       1       10ms    10
Node6       Node7       1Mbps       1       10ms    10
Node7       Node8       1Mbps       1       10ms    10

This scenario (ndn-grid-topo-plugin.cpp) duplicates the functionality of 9-node grid example but with the use of AnnotatedTopologyReader.

 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
// ndn-grid-topo-plugin.cpp

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

namespace ns3 {

int
main(int argc, char* argv[])
{
  CommandLine cmd;
  cmd.Parse(argc, argv);

  AnnotatedTopologyReader topologyReader("", 25);
  topologyReader.SetFileName("src/ndnSIM/examples/topologies/topo-grid-3x3.txt");
  topologyReader.Read();

  // Install NDN stack on all nodes
  ndn::StackHelper ndnHelper;
  ndnHelper.InstallAll();

  // Set BestRoute strategy
  ndn::StrategyChoiceHelper::InstallAll("/", "/localhost/nfd/strategy/best-route");

  // Installing global routing interface on all nodes
  ndn::GlobalRoutingHelper ndnGlobalRoutingHelper;
  ndnGlobalRoutingHelper.InstallAll();

  // Getting containers for the consumer/producer
  Ptr<Node> producer = Names::Find<Node>("Node8");
  NodeContainer consumerNodes;
  consumerNodes.Add(Names::Find<Node>("Node0"));

  // Install NDN applications
  std::string prefix = "/prefix";

  ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  consumerHelper.SetPrefix(prefix);
  consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  consumerHelper.Install(consumerNodes);

  ndn::AppHelper producerHelper("ns3::ndn::Producer");
  producerHelper.SetPrefix(prefix);
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.Install(producer);

  // Add /prefix origins to ndn::GlobalRouter
  ndnGlobalRoutingHelper.AddOrigins(prefix, producer);

  // Calculate and install FIBs
  ndn::GlobalRoutingHelper::CalculateRoutes();

  Simulator::Stop(Seconds(20.0));

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

  return 0;
}

} // namespace ns3

int
main(int argc, char* argv[])
{
  return ns3::main(argc, argv);
}

As you can see, scenario code became more compact and more readable.

AnnotatedTopologyReader provides two ways to access topology nodes. First, you can use the method AnnotatedTopologyReader::GetNodes() which returns NodeContainer.

Alternatively, nodes can be accessed by name using Names::Find<Node> (“nodename”) call, as in the above example. For this purpose,:ndnsim:AnnotatedTopologyReader automatically registers all created nodes with names specified in topology file. For more information about Names class, please refer to NS-3 documentation.

If the topology file is placed into src/ndnSIM/examples/topologies/topo-grid-3x3.txt and the code is placed into scratch/ndn-grid-topo-plugin.cpp, you can run and see progress of the simulation using the following command (in optimized mode nothing will be printed out):

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-grid-topo-plugin

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

6-node bottleneck topology

This scenario (ndn-congestion-topo-plugin.cpp) can be used for congestion-related scenarios

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# topo-6-node.txt

router

# node  comment     yPos    xPos
Src1   NA        1       3
Src2   NA        3       3
Rtr1   NA        2       5
Rtr2   NA        2       7
Dst1   NA        1       9
Dst2   NA        3       9

link

# srcNode   dstNode     bandwidth   metric  delay   queue
Src1        Rtr1        10Mbps      1        10ms    20
Src2        Rtr1        10Mbps      1        10ms    20
Rtr1        Rtr2        1Mbps       1        10ms    20
Dst1        Rtr2        10Mbps      1        10ms    20
Dst2        Rtr2        10Mbps      1        10ms    20
 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
// ndn-congestion-topo-plugin.cpp

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

namespace ns3 {

int
main(int argc, char* argv[])
{
  CommandLine cmd;
  cmd.Parse(argc, argv);

  AnnotatedTopologyReader topologyReader("", 25);
  topologyReader.SetFileName("src/ndnSIM/examples/topologies/topo-6-node.txt");
  topologyReader.Read();

  // Install NDN stack on all nodes
  ndn::StackHelper ndnHelper;
  ndnHelper.setPolicy("nfd::cs::lru");
  ndnHelper.setCsSize(10000);
  ndnHelper.InstallAll();

  // Choosing forwarding strategy
  ndn::StrategyChoiceHelper::InstallAll("/prefix", "/localhost/nfd/strategy/best-route");

  // Installing global routing interface on all nodes
  ndn::GlobalRoutingHelper ndnGlobalRoutingHelper;
  ndnGlobalRoutingHelper.InstallAll();

  // Getting containers for the consumer/producer
  Ptr<Node> consumer1 = Names::Find<Node>("Src1");
  Ptr<Node> consumer2 = Names::Find<Node>("Src2");

  Ptr<Node> producer1 = Names::Find<Node>("Dst1");
  Ptr<Node> producer2 = Names::Find<Node>("Dst2");

  ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second

  // on the first consumer node install a Consumer application
  // that will express interests in /dst1 namespace
  consumerHelper.SetPrefix("/dst1");
  consumerHelper.Install(consumer1);

  // on the second consumer node install a Consumer application
  // that will express interests in /dst2 namespace
  consumerHelper.SetPrefix("/dst2");
  consumerHelper.Install(consumer2);

  ndn::AppHelper producerHelper("ns3::ndn::Producer");
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));

  // Register /dst1 prefix with global routing controller and
  // install producer that will satisfy Interests in /dst1 namespace
  ndnGlobalRoutingHelper.AddOrigins("/dst1", producer1);
  producerHelper.SetPrefix("/dst1");
  producerHelper.Install(producer1);

  // Register /dst2 prefix with global routing controller and
  // install producer that will satisfy Interests in /dst2 namespace
  ndnGlobalRoutingHelper.AddOrigins("/dst2", producer2);
  producerHelper.SetPrefix("/dst2");
  producerHelper.Install(producer2);

  // Calculate and install FIBs
  ndn::GlobalRoutingHelper::CalculateRoutes();

  Simulator::Stop(Seconds(20.0));

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

  return 0;
}

} // namespace ns3

int
main(int argc, char* argv[])
{
  return ns3::main(argc, argv);
}

To run this scenario and see what is happening, use the following command:

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-congestion-topo-plugin

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

11-node 2-bottleneck topology

Firstly, we define a meaningful topology:

The corresponding topology file (topo-11-node-two-bottlenecks.txt):

 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
# topo-11-node-two-bottlenecks.txt

router

#name   city    latitude  longitude
c1      NA      50        30
c2      NA    	30        30
c3      NA    	10        30
c4      NA    	10        40
n1      NA    	40        40
n12     NA    	30        60
n2      NA    	40        80
p1      NA    	50        90
p2      NA    	30        90
p3      NA    	10        90
p4      NA    	10        80

link

#x      y       capacity(kbps)  OSPF    Delay   MaxPackets
c1      n1      10Mbps          1       50ms    200
c2      n1      10Mbps          1       10ms    200
c3      n1      10Mbps          1       100ms   200
c4      n1      10Mbps          1       1ms     200
n1      n2      1Mbps           1176    20ms    20 
n1      n12     1Mbps           587     1ms     20
n12     n2      1Mbps           846     1ms     20
n2      p1      10Mbps          260     1ms     200
n2      p2      10Mbps          700     1ms     200
n2      p3      10Mbps          1       1ms     200
n2      p4      10Mbps          1       1ms     200

After that, we define the simulation scenario:

Example simulation (ndn-congestion-alt-topo-plugin.cpp) scenario:

 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
// ndn-congestion-alt-topo-plugin.cpp

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

namespace ns3 {

int
main(int argc, char* argv[])
{
  CommandLine cmd;
  cmd.Parse(argc, argv);

  AnnotatedTopologyReader topologyReader("", 1);
  topologyReader.SetFileName("src/ndnSIM/examples/topologies/topo-11-node-two-bottlenecks.txt");
  topologyReader.Read();

  // Install NDN stack on all nodes
  ndn::StackHelper ndnHelper;
  ndnHelper.setPolicy("nfd::cs::lru");
  ndnHelper.setCsSize(1);
  ndnHelper.InstallAll();

  // Set BestRoute strategy
  ndn::StrategyChoiceHelper::InstallAll("/", "/localhost/nfd/strategy/best-route");

  // Getting containers for the consumer/producer
  Ptr<Node> consumers[4] = {Names::Find<Node>("c1"), Names::Find<Node>("c2"),
                            Names::Find<Node>("c3"), Names::Find<Node>("c4")};
  Ptr<Node> producers[4] = {Names::Find<Node>("p1"), Names::Find<Node>("p2"),
                            Names::Find<Node>("p3"), Names::Find<Node>("p4")};

  if (consumers[0] == 0 || consumers[1] == 0 || consumers[2] == 0 || consumers[3] == 0
      || producers[0] == 0 || producers[1] == 0 || producers[2] == 0 || producers[3] == 0) {
    NS_FATAL_ERROR("Error in topology: one nodes c1, c2, c3, c4, p1, p2, p3, or p4 is missing");
  }

  for (int i = 0; i < 4; i++) {
    std::string prefix = "/data/" + Names::FindName(producers[i]);

    /////////////////////////////////////////////////////////////////////////////////
    // install consumer app on consumer node c_i to request data from producer p_i //
    /////////////////////////////////////////////////////////////////////////////////

    ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
    consumerHelper.SetAttribute("Frequency", StringValue("10")); // 100 interests a second

    consumerHelper.SetPrefix(prefix);
    ApplicationContainer consumer = consumerHelper.Install(consumers[i]);
    consumer.Start(Seconds(i));     // start consumers at 0s, 1s, 2s, 3s
    consumer.Stop(Seconds(19 - i)); // stop consumers at 19s, 18s, 17s, 16s

    ///////////////////////////////////////////////
    // install producer app on producer node p_i //
    ///////////////////////////////////////////////

    ndn::AppHelper producerHelper("ns3::ndn::Producer");
    producerHelper.SetAttribute("PayloadSize", StringValue("1024"));

    // install producer that will satisfy Interests in /dst1 namespace
    producerHelper.SetPrefix(prefix);
    ApplicationContainer producer = producerHelper.Install(producers[i]);
    // when Start/Stop time is not specified, the application is running throughout the simulation
  }

  // Manually configure FIB routes
  ndn::FibHelper::AddRoute("c1", "/data", "n1", 1); // link to n1
  ndn::FibHelper::AddRoute("c2", "/data", "n1", 1); // link to n1
  ndn::FibHelper::AddRoute("c3", "/data", "n1", 1); // link to n1
  ndn::FibHelper::AddRoute("c4", "/data", "n1", 1); // link to n1

  ndn::FibHelper::AddRoute("n1", "/data", "n2", 1);  // link to n2
  ndn::FibHelper::AddRoute("n1", "/data", "n12", 2); // link to n12

  ndn::FibHelper::AddRoute("n12", "/data", "n2", 1); // link to n2

  ndn::FibHelper::AddRoute("n2", "/data/p1", "p1", 1); // link to p1
  ndn::FibHelper::AddRoute("n2", "/data/p2", "p2", 1); // link to p2
  ndn::FibHelper::AddRoute("n2", "/data/p3", "p3", 1); // link to p3
  ndn::FibHelper::AddRoute("n2", "/data/p4", "p4", 1); // link to p4

  // Schedule simulation time and run the simulation
  Simulator::Stop(Seconds(20.0));
  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

} // namespace ns3

int
main(int argc, char* argv[])
{
  return ns3::main(argc, argv);
}

To run this scenario and see what is happening, use the following command:

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-congestion-alt-topo-plugin

You can also run using visualizer module to verify that both bottleneck links are utilized:

./waf --run=ndn-congestion-alt-topo-plugin --visualize

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

6-node topology with custom NFD forwarding strategy

This scenario simulates a load balancer topology (using topology reader module). The corresponding topology file (topo-load-balancer.txt):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# each line in this section represents one router and should have the following data
# node   comment    yPos    xPos
CSU-1    NA          3       5
CSU-HUB  NA          5       3
UCLA-HUB NA          3       1
UCLA-1   NA          0       0
UCLA-2   NA          0       2
# Each line should be in the following format (only first two are required, the rest can be omitted)
# srcNode   dstNode     bandwidth   metric  delay   queue
# bandwidth: link bandwidth
# metric: routing metric
# delay:  link delay
# queue:  MaxPackets for transmission queue on the link (both directions)
CSU-1       CSU-HUB     1Mbps       1       10ms    10
CSU-HUB     UCLA-HUB    1Mbps       1       10ms    10
UCLA-HUB    UCLA-1      1Mbps       1       10ms    10
UCLA-HUB    UCLA-2      1Mbps       1       10ms    10

After that, we define the simulation scenario:

Example simulation (ndn-load-balancer.cpp) scenario:

 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
// ndn-load-balancer.cpp

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

#include "ndn-load-balancer/random-load-balancer-strategy.hpp"

using ns3::ndn::StackHelper;
using ns3::ndn::AppHelper;
using ns3::ndn::GlobalRoutingHelper;
using ns3::ndn::StrategyChoiceHelper;
using ns3::AnnotatedTopologyReader;

int
main(int argc, char* argv[])
{
  CommandLine cmd;
  cmd.Parse(argc, argv);

  AnnotatedTopologyReader topologyReader("", 25);
  topologyReader.SetFileName("src/ndnSIM/examples/topologies/topo-load-balancer.txt");
  topologyReader.Read();

  // Install NDN stack on all nodes
  StackHelper ndnHelper;
  ndnHelper.InstallAll();

  // Installing global routing interface on all nodes
  GlobalRoutingHelper ndnGlobalRoutingHelper;
  ndnGlobalRoutingHelper.InstallAll();

  // Getting containers for the consumer/producer
  Ptr<Node> producer1 = Names::Find<Node>("UCLA-1");
  Ptr<Node> producer2 = Names::Find<Node>("UCLA-2");
  NodeContainer consumerNodes;
  consumerNodes.Add(Names::Find<Node>("CSU-1"));

  // Install NDN applications
  std::string prefix = "/ucla/hello";

  // Install random-load-balancer forwarding strategy in
  // node UCLA-HUB
  StrategyChoiceHelper::Install<nfd::fw::RandomLoadBalancerStrategy>(Names::Find<Node>("UCLA-HUB"),
                                                                     prefix);

  AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  consumerHelper.SetPrefix(prefix);
  consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  consumerHelper.Install(consumerNodes);

  AppHelper producerHelper("ns3::ndn::Producer");
  producerHelper.SetPrefix(prefix);
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.Install(producer1);
  producerHelper.Install(producer2);

  // Add /prefix origins to ndn::GlobalRouter
  ndnGlobalRoutingHelper.AddOrigins(prefix, producer1);
  ndnGlobalRoutingHelper.AddOrigins(prefix, producer2);

  // Calculate and install FIBs
  GlobalRoutingHelper::CalculateRoutes();

  Simulator::Stop(Seconds(1.0));

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

  return 0;
}

In this simulation scenario, the node called “UCLA-HUB” implements a random load balancing strategy for the name prefix “/ucla/hello”. In this way, the Interest packets will be forwarded randomly either to the producer node called “UCLA-1” or the producer node called “UCLA-2”.

To run this scenario and see what is happening, use the following command:

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-load-balancer

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

9-node grid topology with different forwarding strategies per name prefix

This scenario simulates a grid topology (using PointToPointGrid module). In this scenario, thanks to NFD, we can choose a different forwarding strategy for each prefix in each node.

Consumer requests data from producer with frequency 100 interests per second (interests contain constantly increasing sequence number).

For every received interest, producer replies with a data packet, containing 1024 bytes of virtual payload.

In this scenario, we choose the multicast strategy to be installed for the name prefix “/prefix1” in all the nodes, while for the name prefix “/prefix2”, the best-route strategy will be installed in all the topology nodes.

Example simulation (ndn-different-strategy-per-prefix.cpp) scenario:

 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
// ndn-different-strategy-per-prefix.cpp

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

using namespace ns3;
using ns3::ndn::StackHelper;
using ns3::ndn::AppHelper;
using ns3::ndn::GlobalRoutingHelper;
using ns3::ndn::StrategyChoiceHelper;

int
main(int argc, char* argv[])
{
  // Setting default parameters for PointToPoint links and channels
  Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps"));
  Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
  Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("10p"));

  // Read optional command-line parameters
  CommandLine cmd;
  cmd.Parse(argc, argv);

  // Creating 3x3 topology
  PointToPointHelper p2p;
  PointToPointGridHelper grid(3, 3, p2p);
  grid.BoundingBox(100, 100, 200, 200);

  // Install NDN stack on all nodes
  StackHelper ndnHelper;
  ndnHelper.InstallAll();

  // Installing global routing interface on all nodes
  GlobalRoutingHelper ndnGlobalRoutingHelper;
  ndnGlobalRoutingHelper.InstallAll();

  // Getting pointers to the producer/consumer nodes
  Ptr<Node> producer1 = grid.GetNode(2, 2);
  Ptr<Node> producer2 = grid.GetNode(0, 2);
  Ptr<Node> consumer1 = grid.GetNode(0, 0);
  Ptr<Node> consumer2 = grid.GetNode(2, 0);

  // Define two name prefixes
  std::string prefix1 = "/prefix1";
  std::string prefix2 = "/prefix2";

  // Install different forwarding strategies for prefix1, prefix2
  StrategyChoiceHelper::InstallAll(prefix1, "/localhost/nfd/strategy/multicast");
  StrategyChoiceHelper::InstallAll(prefix2, "/localhost/nfd/strategy/best-route");

  // Install NDN applications
  AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  consumerHelper.SetPrefix(prefix1);
  consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  consumerHelper.Install(consumer1);

  consumerHelper.SetPrefix(prefix2);
  consumerHelper.Install(consumer2);

  AppHelper producerHelper("ns3::ndn::Producer");
  producerHelper.SetPrefix(prefix1);
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.Install(producer1);

  producerHelper.SetPrefix(prefix2);
  producerHelper.Install(producer2);

  // Add /prefix1 and /prefix2 origins to ndn::GlobalRouter
  ndnGlobalRoutingHelper.AddOrigins(prefix1, producer1);
  ndnGlobalRoutingHelper.AddOrigins(prefix2, producer2);

  // Calculate and install FIBs
  GlobalRoutingHelper::CalculateRoutes();

  Simulator::Stop(Seconds(20.0));
  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

To run this scenario and see what is happening, use the following command:

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-different-strategy-per-prefix

9-node grid topology with different forwarding strategy for each node

This scenario simulates a grid topology (using PointToPointGrid module). The first six nodes use the best route forwarding strategy, whereas the three remaining nodes use the multicast forwarding strategy.

Consumer requests data from producer with frequency 100 interests per second (interests contain constantly increasing sequence number).

For every received interest, producer replies with a data packet, containing 1024 bytes of virtual payload.

Example simulation (ndn-grid-multiple-strategies.cpp) scenario:

 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
// ndn-grid-multiple-strategies.cpp

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

using namespace ns3;
using ns3::ndn::StackHelper;
using ns3::ndn::AppHelper;
using ns3::ndn::GlobalRoutingHelper;
using ns3::ndn::StrategyChoiceHelper;

int
main(int argc, char* argv[])
{
  // Setting default parameters for PointToPoint links and channels
  Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps"));
  Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
  Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("10p"));

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

  // Creating 3x3 topology
  PointToPointHelper p2p;
  PointToPointGridHelper grid(3, 3, p2p);
  grid.BoundingBox(100, 100, 200, 200);

  // Install NDN stack on all nodes
  StackHelper ndnHelper;
  ndnHelper.InstallAll();

  // Installing global routing interface on all nodes
  GlobalRoutingHelper ndnGlobalRoutingHelper;
  ndnGlobalRoutingHelper.InstallAll();

  // Getting containers for the consumer/producer
  Ptr<Node> producer = grid.GetNode(2, 2);
  NodeContainer consumerNodes;
  consumerNodes.Add(grid.GetNode(0, 0));

  // Install NDN applications
  std::string prefix = "/prefix";

  // Install different forwarding strategies
  for (int row = 0; row < 3; row++) {
    for (int column = 0; column < 3; column++) {
      if (row < 2)
        StrategyChoiceHelper::Install(grid.GetNode(row, column), "/prefix",
                                      "/localhost/nfd/strategy/best-route");
      else
        StrategyChoiceHelper::Install(grid.GetNode(row, column), "/prefix",
                                      "/localhost/nfd/strategy/multicast");
    }
  }

  AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  consumerHelper.SetPrefix(prefix);
  consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  consumerHelper.Install(consumerNodes);

  AppHelper producerHelper("ns3::ndn::Producer");
  producerHelper.SetPrefix(prefix);
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.Install(producer);

  // Add /prefix origins to ndn::GlobalRouter
  ndnGlobalRoutingHelper.AddOrigins(prefix, producer);

  // Calculate and install FIBs
  GlobalRoutingHelper::CalculateRoutes();

  Simulator::Stop(Seconds(20.0));
  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

To run this scenario and see what is happening, use the following command:

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-grid-multiple-strategies

Simple parallel scenario using MPI

Simple parallel scenario using MPI

3-level binary tree with packet-level trace helpers

Example of packet-level trace helpers

3-level binary tree with content store trace helper

Example of content store trace helper

3-level binary tree with application-level Interest-Data delay tracer

Example of application-level trace helper

1-node topology with custom application

Custom applications

Simple scenario with pcap dump

The following example (ndn-simple-with-pcap.cpp) demonstrates how to dump all simulated traffic in pcap-formatted data, which can be used for later analysis by conventional tools, like tcpdump and wireshark.

  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
// ndn-simple-with-pcap.cpp

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

/**
 * This scenario demonstrates how to dump raw NDN packets into tcpdump-format
 *
 * Run scenario:
 *
 *     ./waf --run ndn-simple-with-pcap
 *
 * After simulation finishes, it produces `ndn-simple-trace.pcap` that can be read
 * using tcpdump or ndndump tools:
 *
 *    ndndump -r ndn-simple-trace.pcap not ip
 *    tcpdump -r ndn-simple-trace.pcap
 */

namespace ns3 {

class PcapWriter {
public:
  PcapWriter(const std::string& file)
  {
    PcapHelper helper;
    m_pcap = helper.CreateFile(file, std::ios::out, PcapHelper::DLT_PPP);
  }

  void
  TracePacket(Ptr<const Packet> packet)
  {
    static PppHeader pppHeader;
    pppHeader.SetProtocol(0x0077);

    m_pcap->Write(Simulator::Now(), pppHeader, packet);
  }

private:
  Ptr<PcapFileWrapper> m_pcap;
};

int
main(int argc, char* argv[])
{
  // setting default parameters for PointToPoint links and channels
  Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("1Mbps"));
  Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
  Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("20p"));

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

  // Creating nodes
  NodeContainer nodes;
  nodes.Create(3);

  // Connecting nodes using two links
  PointToPointHelper p2p;
  p2p.Install(nodes.Get(0), nodes.Get(1));
  p2p.Install(nodes.Get(1), nodes.Get(2));

  // Install NDN stack on all nodes
  ndn::StackHelper ndnHelper;
  ndnHelper.SetDefaultRoutes(true);
  ndnHelper.InstallAll();

  // Installing applications

  // Consumer
  ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
  // Consumer will request /prefix/0, /prefix/1, ...
  consumerHelper.SetPrefix("/prefix");
  consumerHelper.SetAttribute("Frequency", StringValue("10")); // 10 interests a second
  consumerHelper.Install(nodes.Get(0));                        // first node

  // Producer
  ndn::AppHelper producerHelper("ns3::ndn::Producer");
  // Producer will reply to all requests starting with /prefix
  producerHelper.SetPrefix("/prefix");
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.SetAttribute("Signature", UintegerValue(100));
  producerHelper.SetAttribute("KeyLocator", StringValue("/unique/key/locator"));
  producerHelper.Install(nodes.Get(2)); // last node

  PcapWriter trace("ndn-simple-trace.pcap");
  Config::ConnectWithoutContext("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/MacTx",
                                MakeCallback(&PcapWriter::TracePacket, &trace));

  Simulator::Stop(Seconds(20.0));

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

  return 0;
}

} // namespace ns3

int
main(int argc, char* argv[])
{
  return ns3::main(argc, argv);
}

If this code is placed into scratch/ndn-simple-with-pcap.cpp and NS-3 is compiled in debug mode, you can run and see progress of the simulation using the following command (in optimized mode nothing will be printed out):

NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-simple-with-pcap

This will generate ndn-simple-trace.pcap, which can be fed to tcpdump:

tcpdump -r ndn-simple-trace.pcap

Note

If you compiled ndnSIM with examples (./waf configure --enable-examples) you can directly run the example without putting scenario into scratch/ folder.

25-node tree topology with L2Tracer

Example of packet drop tracer (L2Tracer)

LFID (Loop-Free Inport-Dependent) Routing for ndnSIM

LFID (Loop-Free Inport-Dependent) Routing extends the ndnSIM route calculation to provide loop-free and on average shorter loop-free paths than existing work. For details see the tech report.

LFID provides a better trade-off than the existing route calculation algorithms:

  1. CalculateRoutes(): Only provides a single shortest path nexthop.

  2. CalculateAllPossibleRoutes(): Provides all possible nexthops, but many of them lead to loops.

LFID, on the other hand, maximizes the nexthop choice while also completely avoiding loops.

We provide two example topologies (abilene and grid) to compare against the existing route calculation methods:

 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
int
main(int argc, char* argv[])
{
  bool grid = false; // Use grid topology?
  std::string routing = "lfid";
  CommandLine cmd;
  cmd.AddValue("grid", "use grid topology (instead of abilene)", grid);
  cmd.AddValue("routing", "which route computation to use (lfid, sp, allroutes)", routing);
  cmd.Parse(argc, argv);

  std::string topoName = "abilene";
  if (grid) {
    topoName = "grid";
  }

  std::cout << "Using " << topoName << " topology\n\n";

  AnnotatedTopologyReader topologyReader{};
  topologyReader.SetFileName("src/ndnSIM/examples/topologies/topo-" + topoName + ".txt");
  topologyReader.Read();

  ndn::StackHelper stackHelper{};
  stackHelper.InstallAll();

  // IMPORTANT: Has to be run after StackHelper!
  topologyReader.ApplyOspfMetric();

  const std::string prefix{"/prefix"};

  Ptr<Node> consumerN = Names::Find<Node>("router0");
  Ptr<Node> producerN = Names::Find<Node>("producer");
  NS_ABORT_MSG_UNLESS(consumerN && producerN, "consumer or producer name does not exist in topo file!");

  ndn::GlobalRoutingHelper routingHelper;
  routingHelper.InstallAll(); // Fills GlobalRouter with incidencies.
  routingHelper.AddOrigin(prefix, producerN);

  if (routing == "lfid") {
    routingHelper.CalculateLfidRoutes();
  }
  else if (routing == "sp") {
    routingHelper.CalculateRoutes();
  }
  else if (routing == "allroutes") {
    routingHelper.CalculateAllPossibleRoutes();
  }
  else {
    NS_FATAL_ERROR("Unknown route calculation! Use --routing {lfid|sp|allroutes}");
  }

  // IMPORTANT: Some strategy needs to be installed for displayRoutes() to work.
  ndn::StrategyChoiceHelper strategyHelper;
  strategyHelper.InstallAll<nfd::fw::BestRouteStrategy2>("/");

  // TODO: Needs RandomStrategy for test to work!
  // Uncomment after NFD version has been updated.
  //  strategyHelper.InstallAll<nfd::fw::RandomStrategy>("/");

  displayRoutes(topologyReader.GetNodes(), prefix);

  // Installing applications
  ndn::AppHelper consumerHelperX{"ns3::ndn::ConsumerCbr"};
  consumerHelperX.SetPrefix(prefix);
  consumerHelperX.SetAttribute("Frequency", DoubleValue(100.0));
  consumerHelperX.Install(consumerN);

  ndn::AppHelper producerHelper0{"ns3::ndn::Producer"};
  producerHelper0.SetPrefix(prefix);
  producerHelper0.Install(producerN);

  Simulator::Stop(Seconds(30));
  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

} // namespace ns3

Simply run:

./waf --run "lfid [--grid] [--routing={lfid|sp|allroutes}]"

The output will show the nexthops at each node for the given name prefix, and any loops during forwarding.