-
Notifications
You must be signed in to change notification settings - Fork 6
Examples
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.
Currently, we do not support the NS3 python bindings. It is not due to a lack of desire, just a lack of time!
- ccnx-simple
- ccnx-2node
- ccnx-2node-withperhopheaders
- ccnx-4node
- ccnx-6node
- ccnx-consumer-producer
- ccnx-content-store
- ccnx-csma-consumer-producer
- ccnx-csma-simple
- ccnx-layer-delays
- ccnx-lossy-link
- ccnx-multi-prefix-producer-consumer
- ccnx-nfp-routing
- ccnx-nfp-routing-12node
- ccnx-tracing
From the ccns3Examples repository:
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.
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);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;
}
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
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
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));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);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);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"));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);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
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.
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);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
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);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.
Copyright (c) 2016, Xerox Corporation (Xerox) and Palo Alto Research Center (PARC). All rights reserved.