Update of BlackholeSprint scenario.  Extending CcnxStackHelper API
(InstallRouteTo can now accept prefix as a parameter)
diff --git a/examples/base-experiment.h b/examples/base-experiment.h
new file mode 100644
index 0000000..7a9e4bf
--- /dev/null
+++ b/examples/base-experiment.h
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2011,2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef BASE_EXPERIMENT_H
+#define BASE_EXPERIMENT_H
+
+#include "ns3/rocketfuel-topology-reader.h"
+
+class BaseExperiment
+{
+public:
+  BaseExperiment ()
+    : m_rand (0,52)
+    , reader (0)
+  { }
+
+  ~BaseExperiment ()
+  {
+    if (reader != 0) delete reader;
+  }
+    
+  void
+  ConfigureTopology ()
+  {
+    Names::Clear ();
+    cout << "Configure Topology\n";
+    if (reader != 0) delete reader;
+    reader = new RocketfuelWeightsReader ("/sprint");
+    
+    string weights   ("./src/NDNabstraction/examples/sprint-pops.weights");
+    string latencies ("./src/NDNabstraction/examples/sprint-pops.latencies");
+    string positions ("./src/NDNabstraction/examples/sprint-pops.positions");
+  
+    reader->SetFileName (positions);
+    reader->SetFileType (RocketfuelWeightsReader::POSITIONS);
+    reader->Read ();
+  
+    reader->SetFileName (weights);
+    reader->SetFileType (RocketfuelWeightsReader::WEIGHTS);    
+    reader->Read ();
+
+    reader->SetFileName (latencies);
+    reader->SetFileType (RocketfuelWeightsReader::LATENCIES);    
+    reader->Read ();
+    
+    reader->Commit ();
+  }
+
+  void InstallCcnxStack ()
+  {
+    InternetStackHelper stack;
+    Ipv4GlobalRoutingHelper ipv4RoutingHelper ("ns3::Ipv4GlobalRoutingOrderedNexthops");
+    stack.SetRoutingHelper (ipv4RoutingHelper);
+    stack.Install (reader->GetNodes ());
+
+    reader->AssignIpv4Addresses (Ipv4Address ("10.0.0.0"));
+    
+    // Install CCNx stack
+    cout << "Installing CCNx stack\n";
+    CcnxStackHelper ccnxHelper;
+    ccnxHelper.SetForwardingStrategy ("ns3::CcnxBestRouteStrategy");
+    ccnxHelper.EnableLimits (true, Seconds(0.1));
+    ccnxHelper.SetDefaultRoutes (false);
+    ccnxHelper.InstallAll ();
+
+    // // Populate FIB based on IPv4 global routing controller
+    ccnxHelper.InstallFakeGlobalRoutes ();
+    ccnxHelper.InstallRoutesToAll ();
+  }
+  
+  void InstallIpStack ()
+  {
+    InternetStackHelper stack;
+    stack.Install (reader->GetNodes ());
+    reader->AssignIpv4Addresses (Ipv4Address ("10.0.0.0"));
+
+    Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+  }
+
+  void
+  GenerateRandomPairs (uint16_t numStreams)
+  {
+    m_pairs.clear ();
+    // map<uint32_t, set<uint32_t> > streams;
+    m_usedNodes.clear ();
+    
+    uint16_t createdStreams = 0;
+    uint16_t guard = 0;
+    while (createdStreams < numStreams && guard < (numeric_limits<uint16_t>::max ()-1))
+      {
+        guard ++;
+
+        uint32_t node1_num = m_rand.GetValue ();
+        uint32_t node2_num = m_rand.GetValue ();
+
+        if (node1_num == node2_num)
+          continue;
+
+        if (m_usedNodes.count (node1_num) > 0 ||
+            m_usedNodes.count (node2_num) > 0 )
+          {
+            continue; // don't reuse nodes
+          }
+
+        m_usedNodes.insert (node1_num);
+        m_usedNodes.insert (node2_num);
+
+        m_pairs.push_back (make_tuple (node1_num, node2_num));
+        createdStreams ++;
+      }
+  }
+
+  void
+  Run (const Time &finishTime)
+  {
+    cout << "Run Simulation.\n";
+    Simulator::Stop (finishTime);
+    // Simulator::Schedule (Seconds (1.0), PrintTime);
+    Simulator::Run ();
+    Simulator::Destroy ();
+    cout << "Done.\n";
+  }
+
+  UniformVariable m_rand;
+  RocketfuelWeightsReader *reader;
+
+  list<tuple<uint32_t,uint32_t> > m_pairs;
+  set<uint32_t> m_usedNodes;
+};
+
+#endif
diff --git a/examples/blackhole-sprint.cc b/examples/blackhole-sprint.cc
index f97be29..a6afb82 100644
--- a/examples/blackhole-sprint.cc
+++ b/examples/blackhole-sprint.cc
@@ -27,7 +27,6 @@
 #include "ns3/ipv4-global-routing-helper.h"
 #include "ns3/random-variable.h"
 
-#include <iostream>
 #include <sstream>
 #include <map>
 #include <list>
@@ -50,209 +49,74 @@
   Simulator::Schedule (Seconds (1.0), PrintTime);
 }
 
+#include "base-experiment.h"
 
-class Experiment
+class Experiment : public BaseExperiment
 {
 public:
-  Experiment ()
-  : m_reader ("/sprint") { }
-
-  void
-  ConfigureTopology ()
-  {
-    Names::Clear ();
-    
-    string weights   ("./src/NDNabstraction/examples/sprint-pops.weights");
-    string latencies ("./src/NDNabstraction/examples/sprint-pops.latencies");
-    string positions ("./src/NDNabstraction/examples/sprint-pops.positions");
-
-    m_reader.SetFileName (positions);
-    m_reader.SetFileType (RocketfuelWeightsReader::POSITIONS);
-    m_reader.Read ();
-  
-    m_reader.SetFileName (weights);
-    m_reader.SetFileType (RocketfuelWeightsReader::WEIGHTS);    
-    m_reader.Read ();
-
-    m_reader.SetFileName (latencies);
-    m_reader.SetFileType (RocketfuelWeightsReader::LATENCIES);    
-    m_reader.Read ();
-    
-    m_reader.Commit ();
-    NS_ASSERT_MSG (m_reader.LinksSize () != 0, "Problems reading the topology file. Failing.");
-    
-    NS_LOG_INFO("Nodes = " << m_reader.GetNodes ().GetN());
-    NS_LOG_INFO("Links = " << m_reader.LinksSize ());
-  
-    // ------------------------------------------------------------
-    // -- Read topology data.
-    // --------------------------------------------
-        
-    InternetStackHelper stack;
-    Ipv4GlobalRoutingHelper ipv4RoutingHelper ("ns3::Ipv4GlobalRoutingOrderedNexthops");
-    stack.SetRoutingHelper (ipv4RoutingHelper);
-    stack.Install (m_reader.GetNodes ());
-
-    m_reader.AssignIpv4Addresses (Ipv4Address ("10.0.0.0"));
-    
-    // Install CCNx stack
-    NS_LOG_INFO ("Installing CCNx stack");
-    CcnxStackHelper ccnxHelper;
-    ccnxHelper.SetForwardingStrategy ("ns3::CcnxBestRouteStrategy");
-    ccnxHelper.EnableLimits (true, Seconds(0.1));
-    ccnxHelper.SetDefaultRoutes (false);
-    ccnxHelper.InstallAll ();
-    
-    m_rand = UniformVariable (0, m_reader.GetNodes ().GetN());
-    m_linkRand = UniformVariable(0, m_reader.LinksSize());
-  }
-
-  void
-  ConfigureRouting ()
-  {
-    CcnxStackHelper ccnxHelper;
-    // // Populate FIB based on IPv4 global routing controller
-    ccnxHelper.InstallFakeGlobalRoutes ();
-    ccnxHelper.InstallRoutesToAll ();
-  }
-
-public:  
-  void
-  Run (const Time &finishTime)
-  {
-    cout << "Run Simulation.\n";
-    Simulator::Stop (finishTime);
-    //Simulator::Schedule (Seconds (1.0), PrintTime);
-    Simulator::Run ();
-    Simulator::Destroy ();
-    cout << "Done.\n";
-  }
-
   //We are creating 10 pairs of producer-hijacker and everybody else is a consumer
   ApplicationContainer
-  AddApplications(uint32_t numOfPairs)
+  AddApplications ()
   {
-    NS_LOG_INFO("Adding applications");
     ApplicationContainer apps;
-    
-    list<uint32_t > usedNodes;
-    list<uint32_t >::iterator listIterator;
-    list<uint32_t >::iterator listIterator2;
-    
-    uint32_t producerNodeId;
-    uint32_t hijackerNodeId;
 
-    for(uint32_t pairCount = 0; pairCount < numOfPairs; pairCount++)
+    list<string> prefixes;
+
+    // Create Producers/Hijackers
+    for (list<tuple<uint32_t,uint32_t> >::iterator i = m_pairs.begin (); i != m_pairs.end (); i++)
       {
-        NS_LOG_INFO("pairCount = "<<pairCount);
-        while(true)
-          {
-            producerNodeId = m_rand.GetValue ();
-            hijackerNodeId = m_rand.GetValue ();
-        
-            bool unique = true; 
-            for(listIterator=usedNodes.begin(); listIterator != usedNodes.end(); ++listIterator)
-              {
-                if((*listIterator == producerNodeId) || (*listIterator == hijackerNodeId))
-                  {
-                    NS_LOG_INFO("NonUnique");
-                    unique = false;
-                  }
-              }
-        
-            if(unique == true)
-              {
-                usedNodes.push_back(producerNodeId);
-                usedNodes.push_back(hijackerNodeId);
-                break;
-              }
-          }
-      
-        NS_LOG_INFO("Producer #" << producerNodeId);
-        Ptr<Node> node1 = Names::Find<Node> ("/sprint", lexical_cast<string> (producerNodeId));
-        CcnxAppHelper producerHelper ("ns3::CcnxProducer");
-        producerHelper.SetPrefix ("/" + lexical_cast<string> (node1->GetId ()));
-        
-        apps.Add(producerHelper.Install (node1));
+        uint32_t node1_num = i->get<0> ();
+        uint32_t node2_num = i->get<1> ();
 
-        NS_LOG_INFO("Hijacker # "<<hijackerNodeId);
-        Ptr<Node> node2 = Names::Find<Node> ("/sprint", lexical_cast<string> (hijackerNodeId));
-        CcnxAppHelper hijackerHelper ("ns3::CcnxHijacker");
-        hijackerHelper.SetPrefix ("/" + lexical_cast<string> (node1->GetId ()));
-        
-        apps.Add(hijackerHelper.Install (node1));
-        
-        /*NS_LOG_INFO("Consumers");
-        for(uint32_t j = 0; j<m_reader.GetNodes().GetN();j++)
-          {
-            //NS_LOG_INFO("j="<<j);
-            bool consumer = true;
-            for(listIterator=usedNodes.begin(); listIterator != usedNodes.end(); ++listIterator)
-              {
-                if(*listIterator == j)
-                {
-                  consumer = false;
-                  NS_LOG_INFO(j<<" CANNOT be CONSUMER");
-                  break;
-                }
-              }
-        
-            if(consumer == true)
-              {
-                Ptr<Node> node3 = Names::Find<Node> ("/sprint", lexical_cast<string> (j));
-        
-                CcnxAppHelper consumerHelper ("ns3::CcnxConsumer");
-                consumerHelper.SetPrefix ("/" + lexical_cast<string> (node1->GetId ()));
-                consumerHelper.SetAttribute ("MeanRate", StringValue ("1Kbps"));
-                consumerHelper.SetAttribute ("Size", StringValue ("2"));  
-        
-                apps.Add(consumerHelper.Install (node3));
-              }
-          }*/
-        }
-      
-      NS_LOG_INFO("Consumers");
-      for(listIterator=usedNodes.begin(); listIterator != usedNodes.end(); ++listIterator,++listIterator)
-        {
-          for(uint32_t j = 0; j<m_reader.GetNodes().GetN();j++)
-          {
-            //NS_LOG_INFO("j="<<j);
-            bool consumer = true;
-            for(listIterator2=usedNodes.begin(); listIterator2 != usedNodes.end(); ++listIterator2)
-              {
-                if(*listIterator2 == j)
-                {
-                  consumer = false;
-                  NS_LOG_INFO(j<<" CANNOT be a CONSUMER");
-                  break;
-                }
-              }
-        
-            if(consumer == true)
-              {
-                Ptr<Node> node3 = Names::Find<Node> ("/sprint", lexical_cast<string> (j));
-                Ptr<Node> node4 = Names::Find<Node> ("/sprint", lexical_cast<string> (*listIterator));
+        Ptr<Node> node1 = Names::Find<Node> ("/sprint", lexical_cast<string> (node1_num));
+        Ptr<Node> node2 = Names::Find<Node> ("/sprint", lexical_cast<string> (node2_num));
 
-                CcnxAppHelper consumerHelper ("ns3::CcnxConsumer");
-                NS_LOG_INFO("Node = " << *listIterator);
-                consumerHelper.SetPrefix ("/" + lexical_cast<string> (node4->GetId ()));
-                consumerHelper.SetAttribute ("MeanRate", StringValue ("1Kbps"));
-                consumerHelper.SetAttribute ("Size", StringValue ("2"));  
+        // node1 legitimate producer
+        // node2 "fake" producer
+
+        string prefix = "/" + lexical_cast<string> (node1->GetId ());
+
+        CcnxAppHelper legitimateProducerHelper ("ns3::CcnxProducer");
+        legitimateProducerHelper.SetPrefix (prefix);
+        apps.Add
+          (legitimateProducerHelper.Install (node1));
         
-                apps.Add(consumerHelper.Install (node3));
-              }
+        CcnxAppHelper fakeProducerHelper ("ns3::CcnxHijacker");
+        fakeProducerHelper.SetPrefix (prefix);
+        apps.Add
+          (fakeProducerHelper.Install (node2));
+        
+        // one more trick. Need to install route to hijacker (aka "hijacker announces itself as a legitimate producer")
+        CcnxStackHelper::InstallRouteTo (prefix, node2);
+
+        prefixes.push_back (prefix); // remember prefixes that consumers will be requesting
+      }
+
+    // All consumers request exactly 10 packets, to convert number interests packets to requested size:
+    // size = 1040 * (max_number_of_packets-1) / 1024 / 1024
+    double requestSize = 1040.0 * (10 - 1) / 1024.0 / 1024.0;
+    
+    // Create Consumers
+    NodeContainer nodes = reader->GetNodes ();
+    for (NodeContainer::Iterator node = nodes.Begin (); node != nodes.End (); node++)
+      {
+        uint32_t namedId = lexical_cast<uint32_t> (Names::FindName (*node));
+        if (m_usedNodes.count (namedId) > 0)
+          continue;
+
+        CcnxAppHelper consumerHelper ("ns3::CcnxConsumerCbr");
+        BOOST_FOREACH (const string &prefix, prefixes)
+          {
+            consumerHelper.SetPrefix (prefix);
+            consumerHelper.SetAttribute ("MeanRate", StringValue ("8Kbps")); // this is about 1 interest a second
+            consumerHelper.SetAttribute ("Size", DoubleValue(requestSize));
+            
+            apps.Add
+              (consumerHelper.Install (*node));
           }
-        }
-      
-      
+      }
     return apps;
   }
-
-  UniformVariable m_rand;
-  UniformVariable m_linkRand;
-  
-private:
-  RocketfuelWeightsReader m_reader;
 };
 
 int 
@@ -260,48 +124,45 @@
 {
   cout << "Begin blackhole scenario\n";
   
-  Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("2Mbps"));
-  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("100"));
+  Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("100Mbps"));
+  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("2000"));
 
-  Time finishTime = Seconds (20.0);
-  
-   
+  Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("attributes.xml"));
+  Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
+  Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
+
+  uint32_t maxRuns = 1;
+  uint32_t startRun = 0;
   CommandLine cmd;
-  cmd.AddValue ("finish", "Finish time", finishTime);
+  cmd.AddValue ("start", "Initial run number", startRun);
+  cmd.AddValue ("runs", "Number of runs", maxRuns);
   cmd.Parse (argc, argv);
 
-  Experiment experiment;
+  // ConfigStore config;
+  // config.ConfigureDefaults ();
 
+  Experiment experiment;
   for (uint32_t i = 0; i < 80; i++)
     {
       Config::SetGlobal ("RngRun", IntegerValue (i));
       cout << "seed = " << SeedManager::GetSeed () << ", run = " << SeedManager::GetRun () << endl;
 
       Experiment experiment;
+      experiment.GenerateRandomPairs (10);
       cout << "Run " << i << endl;
       
       string prefix = "run-" + lexical_cast<string> (i) + "-";
   
       experiment.ConfigureTopology ();
-      ApplicationContainer apps = experiment.AddApplications (10);
-      experiment.ConfigureRouting ();
-      
-      /*ApplicationContainer apps = experiment.AddApplications ();
-
-      for (uint32_t i = 0; i < apps.GetN () / 2; i++) 
-        {
-          cout << "From " << apps.Get (i*2)->GetNode ()->GetId ()
-               << " to "  << apps.Get (i*2 + 1)->GetNode ()->GetId ();
-          cout << "\n";
-        }
-      */
-      
+      experiment.InstallCcnxStack ();
+      ApplicationContainer apps = experiment.AddApplications ();
+            
       //tracing
       CcnxTraceHelper traceHelper;
-      traceHelper.EnableRateL3All (prefix + "rate-trace.log");
+      // traceHelper.EnableRateL3All (prefix + "rate-trace.log");
       traceHelper.EnableSeqsAppAll ("ns3::CcnxConsumer", prefix + "consumers-seqs.log");
       
-      experiment.Run (finishTime);
+      experiment.Run (Seconds(20.0));
     }
 
   cout << "Finish blackhole scenario\n";
diff --git a/examples/congestion-pop.cc b/examples/congestion-pop.cc
index fcfcc99..ae28ad8 100644
--- a/examples/congestion-pop.cc
+++ b/examples/congestion-pop.cc
@@ -30,13 +30,6 @@
 #include "ns3/applications-module.h"
 #include "ns3/config-store.h"
 
-#include <iostream>
-#include <sstream>
-#include <map>
-#include <list>
-#include <set>
-#include "ns3/rocketfuel-topology-reader.h"
-
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
 
@@ -53,110 +46,11 @@
 //   Simulator::Schedule (Seconds (1.0), PrintTime);
 // }
 
-class Experiment
+#include "base-experiment.h"
+
+class Experiment : public BaseExperiment
 {
 public:
-  Experiment ()
-    : m_rand (0,52)
-    , reader (0)
-  { }
-
-  ~Experiment ()
-  {
-    if (reader != 0) delete reader;
-  }
-    
-  void
-  ConfigureTopology ()
-  {
-    Names::Clear ();
-    cout << "Configure Topology\n";
-    if (reader != 0) delete reader;
-    reader = new RocketfuelWeightsReader ("/sprint");
-    
-    string weights   ("./src/NDNabstraction/examples/sprint-pops.weights");
-    string latencies ("./src/NDNabstraction/examples/sprint-pops.latencies");
-    string positions ("./src/NDNabstraction/examples/sprint-pops.positions");
-  
-    reader->SetFileName (positions);
-    reader->SetFileType (RocketfuelWeightsReader::POSITIONS);
-    reader->Read ();
-  
-    reader->SetFileName (weights);
-    reader->SetFileType (RocketfuelWeightsReader::WEIGHTS);    
-    reader->Read ();
-
-    reader->SetFileName (latencies);
-    reader->SetFileType (RocketfuelWeightsReader::LATENCIES);    
-    reader->Read ();
-    
-    reader->Commit ();
-  }
-
-  void InstallCcnxStack ()
-  {
-    InternetStackHelper stack;
-    Ipv4GlobalRoutingHelper ipv4RoutingHelper ("ns3::Ipv4GlobalRoutingOrderedNexthops");
-    stack.SetRoutingHelper (ipv4RoutingHelper);
-    stack.Install (reader->GetNodes ());
-
-    reader->AssignIpv4Addresses (Ipv4Address ("10.0.0.0"));
-    
-    // Install CCNx stack
-    cout << "Installing CCNx stack\n";
-    CcnxStackHelper ccnxHelper;
-    ccnxHelper.SetForwardingStrategy ("ns3::CcnxBestRouteStrategy");
-    ccnxHelper.EnableLimits (true, Seconds(0.1));
-    ccnxHelper.SetDefaultRoutes (false);
-    ccnxHelper.InstallAll ();
-
-    // // Populate FIB based on IPv4 global routing controller
-    ccnxHelper.InstallFakeGlobalRoutes ();
-    ccnxHelper.InstallRoutesToAll ();
-  }
-  
-  void InstallIpStack ()
-  {
-    InternetStackHelper stack;
-    stack.Install (reader->GetNodes ());
-    reader->AssignIpv4Addresses (Ipv4Address ("10.0.0.0"));
-
-    Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
-  }
-
-  void
-  GenerateRandomPairs (uint16_t numStreams)
-  {
-    m_pairs.clear ();
-    // map<uint32_t, set<uint32_t> > streams;
-    set<uint32_t> usedNodes;
-    
-    uint16_t createdStreams = 0;
-    uint16_t guard = 0;
-    while (createdStreams < numStreams && guard < (numeric_limits<uint16_t>::max ()-1))
-      {
-        guard ++;
-
-        uint32_t node1_num = m_rand.GetValue ();
-        uint32_t node2_num = m_rand.GetValue ();
-
-        if (node1_num == node2_num)
-          continue;
-
-        if (usedNodes.count (node1_num) > 0 ||
-            usedNodes.count (node2_num) > 0 )
-          {
-            continue; // don't reuse nodes
-          }
-
-        usedNodes.insert (node1_num);
-        usedNodes.insert (node2_num);
-
-        m_pairs.push_back (make_tuple (node1_num, node2_num));
-        createdStreams ++;
-      }
-  }
-  
   ApplicationContainer
   AddCcnxApplications ()
   {
@@ -226,23 +120,6 @@
 
     return apps;
   }
-
-
-  void
-  Run (const Time &finishTime)
-  {
-    cout << "Run Simulation.\n";
-    Simulator::Stop (finishTime);
-    // Simulator::Schedule (Seconds (1.0), PrintTime);
-    Simulator::Run ();
-    Simulator::Destroy ();
-    cout << "Done.\n";
-  }
-
-  UniformVariable m_rand;
-  RocketfuelWeightsReader *reader;
-
-  list<tuple<uint32_t,uint32_t> > m_pairs;
 };
 
 
diff --git a/helper/ccnx-stack-helper.cc b/helper/ccnx-stack-helper.cc
index 62c5f82..3714f64 100644
--- a/helper/ccnx-stack-helper.cc
+++ b/helper/ccnx-stack-helper.cc
@@ -19,41 +19,6 @@
  *          Ilya Moiseenko <iliamo@cs.ucla.edu> 
  */
 
-/**
- * \ingroup ccnx
- * \defgroup CcnxStackModel Ccnx Stack Model
- *
- * \section CcnxStackTracingModel Tracing in the Ccnx Stack
- *
- * The ccnx stack provides a number of trace sources in its various
- * protocol implementations.  These trace sources can be hooked using your own 
- * custom trace code, or you can use our helper functions in some cases to 
- * arrange for tracing to be enabled.
- *
- * \subsection CcnxStackCcnxTracingModel Tracing in Ccnx
- *
- * The Ccnx layer three protocol provides three trace hooks.  These are the 
- * "Tx" (ns3::CcnxL3Protocol::m_txTrace), "Rx" (ns3::CcnxL3Protocol::m_rxTrace) 
- * and "Drop" (ns3::CcnxL3Protocol::m_dropTrace) trace sources.
- *
- * The "Tx" trace is fired in a number of situations, all of which indicate that
- * a given packet is about to be sent down to a given ns3::CcnxFace.
- *
- * - \todo list Tx trace events
- *
- * The "Rx" trace is fired when a packet is passed from the device up to the
- * ns3::CcnxL3Protocol::Receive function.
- *
- * - In the receive function, the CcnxFaceList is iterated, and if the
- *   CcnxFace corresponding to the receiving device is found to be in the
- *   UP state, the trace is fired.
- *
- * The "Drop" trace is fired in any case where the packet is dropped (in both
- * the transmit and receive paths).
- *
- * - \todo list Drop trace events
- */
-
 #include "ns3/assert.h"
 #include "ns3/log.h"
 #include "ns3/object.h"
@@ -91,43 +56,11 @@
 #include <limits>
 #include <map>
 #include <boost/foreach.hpp>
-
-#define NDN_DEFAULT_DATA_SIZE      1024
+#include <boost/lexical_cast.hpp>
 
 NS_LOG_COMPONENT_DEFINE ("CcnxStackHelper");
 
 namespace ns3 {
-
-// Things are going to work differently here with respect to trace
-// file handling than in most places because the Tx and Rx trace
-// sources we are interested in are going to multiplex receive and
-// transmit callbacks for all Ccnx and face pairs through one
-// callback.  We want packets to or from each distinct pair to go to
-// an individual file, so we have got to demultiplex the Ccnx and face
-// pair into a corresponding Ptr<PcapFileWrapper> at the callback.
-//
-// A complication in this situation is that the trace sources are
-// hooked on a protocol basis.  There is no trace source hooked by an
-// Ccnx and face pair.  This means that if we naively proceed to hook,
-// say, a drop trace for a given Ccnx with face 0, and then hook for
-// Ccnx with face 1 we will hook the drop trace twice and get two
-// callbacks per event.  What we need to do is to hook the event once,
-// and that will result in a single callback per drop event, and the
-// trace source will provide the face which we filter on in the trace
-// sink.
-// 
-// This has got to continue to work properly after the helper has been
-// destroyed; but must be cleaned up at the end of time to avoid
-// leaks.  Global maps of protocol/face pairs to file objects seems to
-// fit the bill.
-//
-// typedef std::pair<Ptr<Ccnx>, uint32_t> FacePairCcnx; 
-// typedef std::map<FacePairCcnx, Ptr<PcapFileWrapper> > FaceFileMapCcnx;
-// typedef std::map<FacePairCcnx, Ptr<OutputStreamWrapper> > FaceStreamMapCcnx;
-
-// static FaceFileMapCcnx g_faceFileMapCcnx; /**< A mapping of Ccnx/face pairs to pcap files */
-// static FaceStreamMapCcnx g_faceStreamMapCcnx; /**< A mapping of Ccnx/face pairs to ascii streams */
-
     
 CcnxStackHelper::CcnxStackHelper ()
   : m_limitsEnabled (false)
@@ -265,7 +198,7 @@
 
 
 void
-CcnxStackHelper::AddRoute (Ptr<Node> node, std::string prefix, Ptr<CcnxFace> face, int32_t metric) const
+CcnxStackHelper::AddRoute (Ptr<Node> node, std::string prefix, Ptr<CcnxFace> face, int32_t metric)
 {
   NS_LOG_LOGIC ("[" << node->GetId () << "]$ route add " << prefix << " via " << *face << " metric " << metric);
 
@@ -277,7 +210,7 @@
 }
 
 void
-CcnxStackHelper::AddRoute (std::string nodeName, std::string prefix, uint32_t faceId, int32_t metric) const
+CcnxStackHelper::AddRoute (std::string nodeName, std::string prefix, uint32_t faceId, int32_t metric)
 {
   Ptr<Node> node = Names::Find<Node> (nodeName);
   NS_ASSERT_MSG (node != 0, "Node [" << nodeName << "] does not exist");
@@ -291,275 +224,6 @@
   AddRoute (node, prefix, face, metric);
 }
 
-/*
-  void
-  CcnxStackHelper::AddRoute (Ptr<Node> node, std::string prefix, uint32_t faceId, int32_t metric)
-  {
-  NS_LOG_LOGIC ("[" << nodeName << "]$ route add " << prefix << " via " << faceId << " metric " << metric);
-    
-  NS_ASSERT_MSG (node != 0, "Node does not exist");
-        
-  Ptr<Ccnx>     ccnx = node->GetObject<Ccnx> ();
-  Ptr<CcnxFib>  fib  = node->GetObject<CcnxFib> ();
-  Ptr<CcnxFace> face = ccnx->GetFace (faceId);
-  NS_ASSERT_MSG (node != 0, "Face with ID [" << faceId << "] does not exist on node [" << nodeName << "]");
-        
-  CcnxNameComponentsValue prefixValue;
-  prefixValue.DeserializeFromString (prefix, MakeCcnxNameComponentsChecker ());
-  fib->Add (prefixValue.Get (), face, metric);
-  }
-*/
-
-// static void
-// CcnxL3ProtocolRxTxSink (Ptr<const Packet> p, Ptr<Ccnx> ccnx, uint32_t face)
-// {
-//   NS_LOG_FUNCTION (p << ccnx << face);
-
-//   //
-//   // Since trace sources are independent of face, if we hook a source
-//   // on a particular protocol we will get traces for all of its faces.
-//   // We need to filter this to only report faces for which the user 
-//   // has expressed interest.
-//   //
-//   FacePairCcnx pair = std::make_pair (ccnx, face);
-//   if (g_faceFileMapCcnx.find (pair) == g_faceFileMapCcnx.end ())
-//     {
-//       NS_LOG_INFO ("Ignoring packet to/from face " << face);
-//       return;
-//     }
-
-//   Ptr<PcapFileWrapper> file = g_faceFileMapCcnx[pair];
-//   file->Write (Simulator::Now (), p);
-// }
-
-// bool
-// CcnxStackHelper::PcapHooked (Ptr<Ccnx> ccnx)
-// {
-//   for (FaceFileMapCcnx::const_iterator i = g_faceFileMapCcnx.begin (); 
-//        i != g_faceFileMapCcnx.end (); 
-//        ++i)
-//     {
-//       if ((*i).first.first == ccnx)
-//         {
-//           return true;
-//         }
-//     }
-//   return false;
-// }
-
-// void 
-// CcnxStackHelper::EnablePcapCcnxInternal (std::string prefix, Ptr<Ccnx> ccnx, uint32_t face, bool explicitFilename)
-// {
-//   NS_LOG_FUNCTION (prefix << ccnx << face);
-
-//   //
-//   // We have to create a file and a mapping from protocol/face to file 
-//   // irrespective of how many times we want to trace a particular protocol.
-//   //
-//   PcapHelper pcapHelper;
-
-//   std::string filename;
-//   if (explicitFilename)
-//     {
-//       filename = prefix;
-//     }
-//   else
-//     {
-//       filename = pcapHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
-//     }
-
-//   Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_RAW);
-
-//   //
-//   // However, we only hook the trace source once to avoid multiple trace sink
-//   // calls per event (connect is independent of face).
-//   //
-//   if (!PcapHooked (ccnx))
-//     {
-//       //
-//       // Ptr<Ccnx> is aggregated to node and CcnxL3Protocol is aggregated to 
-//       // node so we can get to CcnxL3Protocol through Ccnx.
-//       //
-//       Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
-//       NS_ASSERT_MSG (ccnxL3Protocol, "CcnxStackHelper::EnablePcapCcnxInternal(): "
-//                      "m_ccnxEnabled and ccnxL3Protocol inconsistent");
-
-//       bool result = ccnxL3Protocol->TraceConnectWithoutContext ("Tx", MakeCallback (&CcnxL3ProtocolRxTxSink));
-//       NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal():  "
-//                      "Unable to connect ccnxL3Protocol \"Tx\"");
-
-//       result = ccnxL3Protocol->TraceConnectWithoutContext ("Rx", MakeCallback (&CcnxL3ProtocolRxTxSink));
-//       NS_ASSERT_MSG (result == true, "CcnxStackHelper::EnablePcapCcnxInternal():  "
-//                      "Unable to connect ccnxL3Protocol \"Rx\"");
-//       // cast result to void, to suppress ‘result’ set but not used compiler-warning
-//       // for optimized builds
-//       (void) result;
-//     }
-
-//   g_faceFileMapCcnx[std::make_pair (ccnx, face)] = file;
-// }
-
-// static void
-// CcnxL3ProtocolDropSinkWithoutContext (
-//   Ptr<OutputStreamWrapper> stream,
-//   Ptr<const Packet> packet,
-//   CcnxL3Protocol::DropReason reason, 
-//   Ptr<Ccnx> ccnx, 
-//   uint32_t face)
-// {
-//   //
-//   // Since trace sources are independent of face, if we hook a source
-//   // on a particular protocol we will get traces for all of its faces.
-//   // We need to filter this to only report faces for which the user 
-//   // has expressed interest.
-//   //
-//   FacePairCcnx pair = std::make_pair (ccnx, face);
-//   if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
-//     {
-//       NS_LOG_INFO ("Ignoring packet to/from face " << face);
-//       return;
-//     }
-
-//   *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << *packet << std::endl;
-// }
-
-// static void
-// CcnxL3ProtocolDropSinkWithContext (
-//   Ptr<OutputStreamWrapper> stream,
-//   std::string context,
-//   Ptr<const Packet> packet,
-//   CcnxL3Protocol::DropReason reason, 
-//   Ptr<Ccnx> ccnx, 
-//   uint32_t face)
-// {
-//   //
-//   // Since trace sources are independent of face, if we hook a source
-//   // on a particular protocol we will get traces for all of its faces.
-//   // We need to filter this to only report faces for which the user 
-//   // has expressed interest.
-//   //
-//   FacePairCcnx pair = std::make_pair (ccnx, face);
-//   if (g_faceStreamMapCcnx.find (pair) == g_faceStreamMapCcnx.end ())
-//     {
-//       NS_LOG_INFO ("Ignoring packet to/from face " << face);
-//       return;
-//     }
-
-//   *stream->GetStream () << "d " << Simulator::Now ().GetSeconds () << " " << context << "(" << face << ") " 
-//                         << *packet << std::endl;
-// }
-
-// bool
-// CcnxStackHelper::AsciiHooked (Ptr<Ccnx> ccnx)
-// {
-//   for (  FaceStreamMapCcnx::const_iterator i = g_faceStreamMapCcnx.begin (); 
-//          i != g_faceStreamMapCcnx.end (); 
-//          ++i)
-//     {
-//       if ((*i).first.first == ccnx)
-//         {
-//           return true;
-//         }
-//     }
-//   return false;
-// }
-
-// void 
-// CcnxStackHelper::EnableAsciiCcnxInternal (
-//   Ptr<OutputStreamWrapper> stream, 
-//   std::string prefix, 
-//   Ptr<Ccnx> ccnx, 
-//   uint32_t face,
-//   bool explicitFilename)
-// {
-//   //
-//   // Our trace sinks are going to use packet printing, so we have to 
-//   // make sure that is turned on.
-//   //
-//   Packet::EnablePrinting ();
-
-//   //
-//   // If we are not provided an OutputStreamWrapper, we are expected to create 
-//   // one using the usual trace filename conventions and hook WithoutContext
-//   // since there will be one file per context and therefore the context would
-//   // be redundant.
-//   //
-//   if (stream == 0)
-//     {
-//       //
-//       // Set up an output stream object to deal with private ofstream copy 
-//       // constructor and lifetime issues.  Let the helper decide the actual
-//       // name of the file given the prefix.
-//       //
-//       // We have to create a stream and a mapping from protocol/face to 
-//       // stream irrespective of how many times we want to trace a particular 
-//       // protocol.
-//       //
-//       AsciiTraceHelper asciiTraceHelper;
-
-//       std::string filename;
-//       if (explicitFilename)
-//         {
-//           filename = prefix;
-//         }
-//       else
-//         {
-//           filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
-//         }
-
-//       Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
-
-//       //
-//       // However, we only hook the trace sources once to avoid multiple trace sink
-//       // calls per event (connect is independent of face).
-//       //
-//       if (!AsciiHooked (ccnx))
-//         {
-//           //
-//           // The drop sink for the CcnxL3Protocol uses a different signature than
-//           // the default sink, so we have to cook one up for ourselves.  We can get
-//           // to the Ptr<CcnxL3Protocol> through our Ptr<Ccnx> since they must both 
-//           // be aggregated to the same node.
-//           //
-//           Ptr<CcnxL3Protocol> ccnxL3Protocol = ccnx->GetObject<CcnxL3Protocol> ();
-//           bool __attribute__ ((unused)) result = ccnxL3Protocol->TraceConnectWithoutContext ("Drop", 
-//                                                                                              MakeBoundCallback (&CcnxL3ProtocolDropSinkWithoutContext, theStream));
-//           NS_ASSERT_MSG (result == true, "CcnxStackHelper::EanableAsciiCcnxInternal():  "
-//                          "Unable to connect ccnxL3Protocol \"Drop\"");
-//         }
-
-//       g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = theStream;
-//       return;
-//     }
-
-//   //
-//   // If we are provided an OutputStreamWrapper, we are expected to use it, and
-//   // to provide a context.  We are free to come up with our own context if we
-//   // want, and use the AsciiTraceHelper Hook*WithContext functions, but for 
-//   // compatibility and simplicity, we just use Config::Connect and let it deal
-//   // with the context.
-//   //
-//   // We need to associate the ccnx/face with a stream to express interest
-//   // in tracing events on that pair, however, we only hook the trace sources 
-//   // once to avoid multiple trace sink calls per event (connect is independent
-//   // of face).
-//   //
-//   if (!AsciiHooked (ccnx))
-//     {
-//       Ptr<Node> node = ccnx->GetObject<Node> ();
-//       std::ostringstream oss;
-
-//       //
-//       // This has all kinds of parameters coming with, so we have to cook up our
-//       // own sink.
-//       //
-//       oss.str ("");
-//       oss << "/NodeList/" << node->GetId () << "/$ns3::CcnxL3Protocol/Drop";
-//       Config::Connect (oss.str (), MakeBoundCallback (&CcnxL3ProtocolDropSinkWithContext, stream));
-//     }
-
-//   g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = stream;
-// }
 
 void
 CcnxStackHelper::InstallFakeGlobalRoutesImpl ()
@@ -599,9 +263,12 @@
 void
 CcnxStackHelper::InstallRouteTo (Ptr<Node> destNode)
 {
-  std::ostringstream destPrefix;
-  destPrefix << "/" << destNode->GetId ();
+  InstallRouteTo (boost::lexical_cast<std::string> (destNode->GetId ()), destNode);
+}
 
+void
+CcnxStackHelper::InstallRouteTo (const std::string &prefix, Ptr<Node> destNode)
+{
   Ipv4Address destIpv4 = Ipv4Address(destNode->GetId ());
   
   for (NodeList::Iterator node = NodeList::Begin ();
@@ -634,11 +301,12 @@
           Ptr<CcnxFace> face = ccnx->GetFaceByNetDevice (netDevice);
           NS_ASSERT_MSG (face != 0, "Definitely should never happen. Call the president");
             
-          AddRoute (*node, destPrefix.str(), face, entry.GetMetric ());
+          AddRoute (*node, prefix, face, entry.GetMetric ());
         }
     }
 }
 
+
 void
 CcnxStackHelper::InstallRoutesToAll ()
 {
diff --git a/helper/ccnx-stack-helper.h b/helper/ccnx-stack-helper.h
index b4cdbc6..6cd3745 100644
--- a/helper/ccnx-stack-helper.h
+++ b/helper/ccnx-stack-helper.h
@@ -151,8 +151,8 @@
    * \param faceId Face index
    * \param metric Routing metric
    */
-  void
-  AddRoute (std::string nodeName, std::string prefix, uint32_t faceId, int32_t metric) const;
+  static void
+  AddRoute (std::string nodeName, std::string prefix, uint32_t faceId, int32_t metric);
 
   /**
    * \brief Add forwarding entry in FIB
@@ -162,8 +162,8 @@
    * \param face   Face
    * \param metric Routing metric
    */
-  void
-  AddRoute (Ptr<Node> node, std::string prefix, Ptr<CcnxFace> face, int32_t metric) const;
+  static void
+  AddRoute (Ptr<Node> node, std::string prefix, Ptr<CcnxFace> face, int32_t metric);
 
   /**
    * \brief Set flag indicating necessity to install default routes in FIB
@@ -177,28 +177,36 @@
    * This method adds fake routes to all nodes, where each route is /32 and IPv4 address equal to node number.
    * For example, node 5 will have direct route to 0.0.0.5.
    */
-  void
+  static void
   InstallFakeGlobalRoutes ();
 
-  void
+  static void
   InstallFakeGlobalRoutesImpl ();
   
   /**
-   * \brief Installs CCNx route to `node` based on fake IPv4 routes
+   * \brief Install CCNx route to `node` based on fake IPv4 routes
    *
    * Actual route is "/<nodeId>"
    *
    * \param node Pointer to a node, which should be reached from all other nodes
    */
-  void
+  static void
   InstallRouteTo (Ptr<Node> node);
 
   /**
-   * \brief Installs CCNx route to all nodes based on fake IPv4 routes
+   * \brief Install CCNx route to /prefix which is installed on `node'
+   *
+   * Normally, prefix is  /<node->GetId()>.  Other values may be used in black-holing scenarios
+   */
+  static void
+  InstallRouteTo (const std::string &prefix, Ptr<Node> node);
+
+  /**
+   * \brief Install CCNx route to all nodes based on fake IPv4 routes
    *
    * \see InstallRouteTo
    */
-  void
+  static void
   InstallRoutesToAll ();
 
 private: