Skip to content

Examples

Marc Mosko edited this page Sep 14, 2016 · 44 revisions

CCNx Examples in NS3

The source directory src/ccnx/examples contains all the working examples of using the CCNx module in NS3 scripts. Some of the examples are part of the ccns3Sim.git repository and some are in the ccns3Examples.git repository.

The related github project link:/PARC/ccns3Examples/wiki[ccns3Examples] has numerous examples of working with the code such as:

  • incorporating new PIT, FIB, or Content Stores
  • Using different routing protocols
  • topology examples

If you have setup the ccnx.sh script in your ns3 directory, the easiest way to run an example is ./ccnx.sh example <name>, for example ./ccnx.sh example ccnx-simple.

Python

Currently, we do not support the NS3 python bindings. It is not due to a lack of desire, just a lack of time!

Examples in ccns3Sim

From the ccns3Examples repository:

ccnx-simple

This is a 1-node example. A sink creates a CCNxPortal and calls RegsiterPrefix() to put a FIB entry for its name in the local forwarder. A source application creates its own CCNxPortal and sends several CCNxInterest messages to the sink. No ContentObjects are returned.

ccnx-2node

Same as ccnx-simple, except there are two nodes connected with an ns3::PointToPoint network connection. We use static routing from the source to the sink.

Uses a point-to-point topology. Sink will RegisterPrefix() on n0 which creates a route from n0 to the sink Portal. We add a static route on node n1 -> n0 for ccnx:/name=foo/name=sink.

 sink      source
  |         |
 n0 ------ n1
     5Mbps
     2ms

The example shows how to use the normal NS3 PointToPointHelper to create links:

  NodeContainer nodes;
  nodes.Create (2);

  PointToPointHelper pointToPoint;
  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

  NetDeviceContainer devices;
  devices = pointToPoint.Install (nodes);

  CCNxStackHelper ccnx;
  ccnx.Install (nodes);
  ccnx.AddInterfaces (devices);

The important thing in this example is it shows how to add a static route from n1 to n0 so the Interest from the source to the sink can flow. Lines 20 and 25 retrieve the network interface device from nodes 0 and 1. Using these devices, we can add a neighbor in line 40 from n1 to n0. Line 40 adds the MAC address of n0's network interface as a neighbor on n1's device node1If0. Once we have the CCNxConnectionDevice object, we can use that to add a route on n1 via that connection in line 50.

This calling structure is cumbersome and requires too much manual work on the programmer's part. We will be adding a StaticRouteHelper to fix this problem.

10   Ptr<Node> node0 = nodes.Get (0);
15   Ptr<Node> node1 = nodes.Get (1);
20   Ptr<NetDevice> node0If0 = node0->GetDevice (0);
25   Ptr<NetDevice> node1If0 = node1->GetDevice (0);
30 
35   Ptr<CCNxL3Protocol> node1_ccnx = node1->GetObject<CCNxL3Protocol> ();
40   Ptr<CCNxConnectionDevice> node1ToNode0Connection = node1_ccnx->AddNeighbor (node0If0->GetAddress (), node1If0);
45   Ptr<CCNxName> prefixName = Create<CCNxName> (prefixString);
50   node1_ccnx->GetForwarder ()->AddRoute (node1ToNode0Connection, prefixName);

ccnx-2node-withperhopheaders

This example is essentially identical to ccnx-2node, but includes two per-hop TLV header in the Interest message.

static Ptr<CCNxPacket>
CreatePacket (uint32_t size, Ptr<CCNxName> name, CCNxMessage::MessageType msgType)
{
  Ptr<CCNxBuffer> payload = Create<CCNxBuffer> (size, true);
  Ptr<CCNxPacket> packet;

  switch (msgType)
    {
    // omit ContentObject case

    case  CCNxMessage::Interest:
      {
        Ptr<CCNxInterest> interest = Create<CCNxInterest> (name, payload);
        packet = CCNxPacket::CreateFromMessage (interest);
        // Add per hop header entry
        Ptr<CCNxInterestLifetime> interestLifetime = Create<CCNxInterestLifetime> (Create<CCNxTime>(3600));
        packet->AddPerHopHeaderEntry(interestLifetime);
        Ptr<CCNxCachetime> cachetime = Create<CCNxCachetime> (Create<CCNxTime>(3600));
        packet->AddPerHopHeaderEntry(cachetime);
        break;
      }

    // omit default case
    }
  return packet;
}

ccnx-4node-topo

This is a https://github.com/PARC/ccns3Sim/blob/wiki/wikidocs/3node-topo.png[4 node topology], with multiple producers and a single consumer. The idea was to show how interests can be load balanced with the consumer not being affected. In this example both N0 and N1 are hosting producers with the same prefix. And consumer at n3 is requesting random interests with the prefix that can be served by either n0 or n1.

n0
   \ 5 Mb/s, 2ms
    \          1.5Mb/s, 10ms
     n2 -------------------------n3
    /
   / 5 Mb/s, 2ms
 n1
  • We should expect the number of interests expressed should match with the content objects responses.
  • Bad Packets implies that we could not decode it the content received was interest/content.
  • Missing Interests implies we have some outstanding interests for whom content reception was timed out.
 Consumer  Interest Content    Missing    Bad        Prefix
 Node Id : Sent    :Received  :Interests :Packets   :Name   
 3         1939      1939        0           0       lci:/NAME=simple/NAME=producer/NAME=size64count10
 3         1939      1939        0           0       lci:/NAME=simple/NAME=producer/NAME=size128count20

 Producer  Interest  Content  Missing     Bad        Prefix
 Node Id : Received : Sent   :Content   :Packets    :Name   
 0         1939      1939      0           0         lci:/NAME=simple/NAME=producer/NAME=size64count10
 1         1935      1935      0           0         lci:/NAME=simple/NAME=producer/NAME=size64count10
 0         1939      1939      0           0         lci:/NAME=simple/NAME=producer/NAME=size128count20
 1         1935      1935      0           0         lci:/NAME=simple/NAME=producer/NAME=size128count20

ccnx-6node-topo

This is a https://github.com/PARC/ccns3Sim/blob/wiki/wikidocs/6node-topo.png[6 node topology] , with multiple producers (on n0 and n1) and a multiple consumers (n4 and n5). The idea here is to show how interests can get aggregated at n3 resulting in fewer interest requests forwarded to n2.

 n0                                 n4
   \ 5 Mb/s, 2ms                   /
    \          1.5Mb/s, 10ms      /
     n2 -------------------------n3
    /                             \
   / 5 Mb/s, 2ms                    \
 n1                                  n5
  • Upon building and executing this example the o/p to be expected is as follows. The number of interests sent and received by consumers on nodes 4 and 5 should match. In this example there are 2 sets of prefixes that interests are expressed for.

At the producer end, there will be multiple producers responding back to the interest from consumer.This is because node2 is forwarding the interests to both node0 and node1. When content objects arrive from both node0 and node1 at node3 only one of them will consume the PIT entry, discarding the content object that arrived later.

  • Bad Packets implies that we could not decode it the content received was interest/content.
  • Missing Content implies we have received an interest which cannot be served by the producer.
Consumer  Interest Content    Missing    Bad        Prefix
Node Id : Sent    :Received  :Interests :Packets   :Name   
4         1939      1939        0           0       lci:/NAME=simple/NAME=producer/NAME=size64count10
5         1939      1939        0           0       lci:/NAME=simple/NAME=producer/NAME=size64count10
4         1939      1939        0           0       lci:/NAME=simple/NAME=producer/NAME=size128count20
5         1939      1939        0           0       lci:/NAME=simple/NAME=producer/NAME=size128count20

Producer  Interest  Content  Missing     Bad        Prefix
Node Id : Received : Sent   :Content   :Packets    : Name   
0         3687      3687      0           0         lci:/NAME=simple/NAME=producer/NAME=size64count10
1         3679      3679      0           0         lci:/NAME=simple/NAME=producer/NAME=size64count10
0         3769      3769      0           0         lci:/NAME=simple/NAME=producer/NAME=size128count20
1         3761      3761      0           0         lci:/NAME=simple/NAME=producer/NAME=size128count20

ccnx-consumer-producer

This is the same as the ccnx-2node example, except we install the CCNxConsumer and CCNxProducer applications on the source and sink. It also uses the NfpRoutingHelper for dynamic routing instead of the cumbersome method of adding static routes.

  NfpRoutingHelper nfpHelper;
  nfpHelper.Set ("HelloInterval", TimeValue (Seconds (5)));
  ccnxStack.SetRoutingHelper (nfpHelper);

The consumer/producer applications use a CCNxContentRepository to represent the ContentObject corpus of the example.

  Ptr <const CCNxName> prefix = Create <CCNxName> ("ccnx:/name=ccnx/name=consumer/name=producer");
  uint32_t size = 124;
  uint32_t count = 1000;
  Ptr <CCNxContentRepository> globalContentRepository = Create <CCNxContentRepository> (prefix,size,count);

The repository is then serviced by one Producer app that will start immediately. Notice that we use the normal NS3 Application idiom, so applications are configured and created via a Helper and you can then set start and stop times on the application.

  CCNxProducerHelper producerHelper (globalContentRepository);
  ApplicationContainer producerApps = producerHelper.Install (nodes.Get (0));
  producerApps.Start (Seconds (0.0));
  producerApps.Stop (Seconds (13.0));

The consumer app follows the same coding style. It is also created via a reference to the repository because it uses the repository to generate the names it uses in Interest messages.

  CCNxConsumerHelper consumerHelper (globalContentRepository);
  consumerHelper.SetAttribute ("RequestInterval", TimeValue (MilliSeconds (5)));
  ApplicationContainer consumerApps = consumerHelper.Install (nodes.Get (1));
  consumerApps.Start (Seconds (2.0));
  consumerApps.Stop (Seconds (12.0));

ccnx-content-store

This is the same as the ccnx-consumer-producer example, except we enable the Content Store in the CCNx forwarder. The default behavior of CCNxStandardForwarder is to not enable the ContentStore.

The CCNxStandardContentStoreFactory uses the normal NS3 ns3::ObjectFactory mechanisms we can set parameters with the normal NS3 Attribute system. In this case, we can set the ObjectCapacity to be 10,000 ContentObjects. All ContentStores created from this factory will have that capacity. By installing the ContentStoreFactory in a forwarder, it enables the forwarder helper to call the factory for each forwarder it will create.

  CCNxStandardForwarderHelper standardHelper;
  CCNxStandardContentStoreFactory contentStoreFactory;
  contentStoreFactory.Set("ObjectCapacity", IntegerValue(10000));
  standardHelper.SetContentStoreFactory(contentStoreFactory);

  CCNxStackHelper ccnxStack;
  ccnxStack.SetForwardingHelper (standardHelper);

ccnx-csma-consumer-producer

This is the same as the ccnx-consumer-producer example, except we use a CSMA (Ethernet) network instead of point-to-point links:

  CsmaHelper etherNet;
  etherNet.SetChannelAttribute ("DataRate", DataRateValue (DataRate (1000000000)));
  etherNet.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (10)));
  etherNet.SetDeviceAttribute ("Mtu", UintegerValue (1500));

  NetDeviceContainer devices = etherNet.Install (nodes);
  // ... skip ...
  ccnxStack.AddInterfaces (devices);

ccnx-csma-simple

The same as ccnx-2node, except we use a CSMA (Ethernet) link and enable PCAP tracing. This uses the normal NS3 pcap facility to dump the traffic to the named file ccnx-csma-broadcast-<nodeid>-<interfaceid>.pcap. You can then view the pcap files, for example, using tcpdump -tt -r.

  CsmaHelper etherNet;
  etherNet.SetChannelAttribute ("DataRate", DataRateValue (DataRate (1000000000)));
  etherNet.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (10)));
  etherNet.SetDeviceAttribute ("Mtu", UintegerValue (1500));

  NetDeviceContainer devices = etherNet.Install (nodes);
  // ... skip ...
  ccnxStack.AddInterfaces (devices);
  // ... skip ...
  etherNet.EnablePcapAll ("ccnx-csma-broadcast", false);

If you would prefer to see an ASCII packet dump, one could use the normal NS3 calls:

  AsciiTraceHelper ascii;
  etherNet.EnableAsciiAll (ascii.CreateFileStream ("ccnx-csma-1bcast.tr"));

ccnx-layer-delays

The same as ccnx-consumer-producer, except we introduce processing delays. See the [ccnx3Sim Paper](The paper) for a detailed description of the delay model. We will add the following delays:

  • forwarder: 10 usec + 1 usec/byte, up to 2 parallel forwarding operations
  • PIT: 10 usec + 3 usec/name_bytes, up to 4 parallel lookups
  • FIB: 8 usec + 7 usec/name_bytes, up to 2 parallel looksup

We do this by explicitly creating a PIT factory and FIB factory with the layer delay attributes set, then pass those to the CCNxForwarderHelper so it will create PIT and FIB tables with those attributes.

  CCNxStandardForwarderHelper forwarderHelper;
  forwarderHelper.SetLayerDelayConstant (MicroSeconds (10));
  forwarderHelper.SetLayerDelaySlope (NanoSeconds (1));
  forwarderHelper.SetLayerDelayServers (2);

  CCNxStandardPitFactory pitFactory;
  pitFactory.SetLayerDelayConstant (MicroSeconds (10));
  pitFactory.SetLayerDelaySlope (NanoSeconds (3));
  pitFactory.SetLayerDelayServers (4);
  forwarderHelper.SetPitFactory (pitFactory);

  CCNxStandardFibFactory fibFactory;
  fibFactory.SetLayerDelayConstant (MicroSeconds (8));
  fibFactory.SetLayerDelaySlope (NanoSeconds (7));
  fibFactory.SetLayerDelayServers (2);
  forwarderHelper.SetFibFactory (fibFactory);

  ccnxStack.SetForwardingHelper (forwarderHelper);

This example also hows how to print periodic statistics. In this case, we dump the forwarding table statistics every 5 seconds:

  Ptr<OutputStreamWrapper> trace = Create<OutputStreamWrapper> (&std::cout);
  forwarderHelper.PrintForwardingStatisticsAllNodesWithInterval(Seconds(5), trace);

ccnx-lossy-link

This example shows how to use the normal NS3 mechanisms to introduce link loss.

 producer  relay     consumer
  |         |        |
 n0 ------ n1 ------ n2
   Lossy        Lossless
   link         Link
   1Gbps        100Mbps
   20ms         10ms

The configuration of PPP links is as before, and we can add both PPP links to a single NetDeviceContainer:

  NodeContainer lossyNodes = NodeContainer (nodes.Get (0), nodes.Get (1));
  NodeContainer losslessNodes = NodeContainer (nodes.Get (1), nodes.Get (2));

  PointToPointHelper p2pLossyLink;
  p2pLossyLink.SetDeviceAttribute ("DataRate", StringValue ("1Gbps"));
  p2pLossyLink.SetChannelAttribute ("Delay", StringValue ("20ms"));

  PointToPointHelper p2pLosslessLink;
  p2pLosslessLink.SetDeviceAttribute ("DataRate", StringValue ("100Mbps"));
  p2pLosslessLink.SetChannelAttribute ("Delay", StringValue ("10ms"));

  NetDeviceContainer lossyDevices = p2pLossyLink.Install(lossyNodes);
  
  NetDeviceContainer pppDevices;
  pppDevices.Add(lossyDevices);
  pppDevices.Add(p2pLosslessLink.Install(losslessNodes));

We can now create an NS3 ErrorModel and attach it to each device on the lossy link. In this example, we add a 5% packet loss rate.

  Ptr<RateErrorModel> error = CreateObject<RateErrorModel>();
  error->SetUnit(RateErrorModel::ERROR_UNIT_PACKET);
  error->SetRate(0.05);
  error->Enable();
  
  for (int i = 0; i < lossyDevices.GetN(); ++i) {
      Ptr<NetDevice> dev = lossyDevices.Get(i);
      dev->SetAttribute("ReceiveErrorModel", PointerValue(error));
  }

You should then see output like this that shows that the consumer sent 1999 Interests but only received 1747 Content Objects. That's about a 12.6% loss rate, which is a little higher than expected. We would expect 95% Interests received and 95% of those received interests received as ContentObjects, for an overall receive rate of 90.25% (9.75% loss rate). As this is a small sample of a random process, 12.6% is within reason.

Consumer  Interest Content    Missing    Bad        Average   Std Dev    Total     Repository
Node Id : Sent    :Received  :Interests :Packets   :Delay(Ms):Delay(Ms) :Count     :Prefix   
2         1999      1747        252         0       52        20.2731    1999      ccnx:/NAME=ccnx/NAME=link/NAME=loss

Producer  Interest  Content  Missing     Bad        Repository
Node Id : Received : Sent   :Content   :Packets    : Prefix   
0         1885      1885      0           0         ccnx:/NAME=ccnx/NAME=link/NAME=loss

ccnx-multi-prefix-producer-consumer

Like ccnx-csma-consumer-producer, except we create 4 different prefixes and a repository, producer, and consumer for each, all on nodes n0 and n1.

As long as each repository gets a distinct prefix to put in the routing table, you can setup as many producers on a node as you want, each servicing a different repository. You can have multiple producers on different nodes servicing the same repository.

ccnx-nfp-routing

A small topology that illustrates how to use the NfpRouting protocol.

 sink                        source
  |                            |
 n0 ----------- n1     n2      n3
     5Mbps      |      |       |
     2ms      |--------- LAN ----------|
                    100 Mbps / 1 usec

As we've seen before, it is easy to create the NfpRoutingHelper and install on each node. In this example, we set some additional parameters on the routing helper to print the neighbor table and routing table on all nodes every 5 seconds:

  Ptr<OutputStreamWrapper> trace = Create<OutputStreamWrapper> (&std::cout);

  NfpRoutingHelper nfpHelper;
  nfpHelper.Set ("HelloInterval", TimeValue (Seconds (1)));
  nfpHelper.PrintNeighborTableAllNodesWithInterval (Time (Seconds (5)), trace);
  nfpHelper.PrintRoutingTableAllNodesWithInterval (Time (Seconds (5)), trace);

  CCNxStackHelper ccnxStack;
  ccnxStack.SetRoutingHelper (nfpHelper);

ccnx-nfp-routing-12node

A small topology that illustrates how to use the NfpRouting protocol.

 Uses a point-to-point topology.  Sink is on n0, source is n10 for ccnx:/name=foo/name=sink.

                             -----------n11
                             |           |
                n4 --  n5 -- n6 --- n7 \ |
                |      |     |   x  |   n9 -- n10
 n0 ----------- n1     n2    n3 --- n8 /
     5Mbps      |      |     |
     2ms      |------ LAN -----|
                    100 Mbps / 1 usec

From the ccns3Examples repository

acme-forwarder

This example uses the AcmeFlatForwarder defined in the model/flat-forwarder directory. This forwarder, used only for purposes of example, has a very differing behavior from the CCNxStandardForwarder. It does not do LPM to find routes, but only does exact match on the FIB. Note that it does not have a PIT, so cannot be used for actually returning data.

The Acme forwarder inherits as class AcmeFlatForwarder : public ccnx::CCNxForwarder so it will fit in to the normal CCNxForwarder model and plug right in to the CCNxL3Protocol.

The AcmeFlatForwarderHelper takes care of instantiating an AcmeForwarder and can be used in place of the CCNxStandardForwarderHelper in a script, which is pretty much how this example deviates from ccnx-simple.

  CCNxStackHelper ccnx;

  AcmeFlatForwarderHelper forwarder;
  ccnx.SetForwardingHelper(forwarder);

large-consumer-producer

parc-paper

This example generated the data used in the [ccnx3Sim Paper](The paper). It differs significantly from the other examples, as it takes its own command line and can execute different types of simulations. You can see the paper for a complete description of the different simulation types, which we only summarize here.

usage: ./waf --run parc-paper --command-template="%s --seed=10 --test=[prefix_delete, link_failure, link_recovery, add_replicas] [--replicas=n] [detailed]"

  • seed: the random number see to use to initialize the RNG streams.
  • prefix_delete: Measure the time it takes to remove an anchor's prefix advertisement.
  • link_failure: Measure the convergence time after a link goes away.
  • link_recovery: Measure the convergence time after a link is restored.
  • add_replicas: Measure the convergence time when a new advertisement goes out.
  • replicas: the number of producers for each prefix.
  • detailed: Print detailed simulation information.

This example also needs to read a topology file, topo.txt, that is in the RocketFuel format.

  • Home
  • [Getting Started](Getting Started)
  • Developer
    • [Node Architecture](Node Architecture)
    • [Header doc format](Header doc format)
    • [Unit Tests](Unit Tests)
    • [Overriding Implementations](Overriding Implementations)
    • [Code Coverage](Code Coverage)

Clone this wiki locally