Modification of CcnxFace interface and unification of CCNx applications via common CcnxApp class

Moving functionality of interest limits from PIT to Face.

!!! Code compiles, but probably doesn't work !!!
diff --git a/apps/ccnx-app.cc b/apps/ccnx-app.cc
new file mode 100644
index 0000000..a23167e
--- /dev/null
+++ b/apps/ccnx-app.cc
@@ -0,0 +1,140 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 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>
+ */
+
+#include "ccnx-app.h"
+#include "ns3/log.h"
+#include "ns3/packet.h"
+#include "ns3/ccnx-interest-header.h"
+#include "ns3/ccnx-content-object-header.h"
+
+NS_LOG_COMPONENT_DEFINE ("CcnxApp");
+
+namespace ns3
+{    
+    
+NS_OBJECT_ENSURE_REGISTERED (CcnxApp);
+    
+TypeId
+CcnxConsumer::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::CcnxApp")
+    .SetParent<Application> ()
+    .AddConstructor<CcnxApp> ()
+    ;
+  return tid;
+}
+    
+CcnxApp::CcnxApp ()
+  : m_protocolHandler (0)
+  , m_active (true)
+  , m_face (0)
+{
+}
+    
+CcnxApp::~CcnxApp ()
+{
+  StopApplication ();
+}
+
+void
+CcnxProducer::DoDispose (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  StopApplication ();
+  CcnxApp::DoDispose ();
+}
+
+void
+CcnxApp::RegisterProtocolHandler (ProtocolHandler handler)
+{
+  m_protocolHandler = handler;
+}
+    
+void
+CcnxApp::OnInterest (const Ptr<const CcnxInterestHeader> &interest)
+{
+  NS_LOG_FUNCTION (this << interest);
+}
+
+void
+CcnxApp::OnNack (const Ptr<const CcnxInterestHeader> &interest)
+{
+  NS_LOG_FUNCTION (this << interest);
+}
+
+void
+CcnxApp::OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
+                          const Ptr<const Packet> &payload)
+{
+  NS_LOG_FUNCTION (this << contentObject << payload);
+}
+
+// Application Methods
+void 
+CcnxApp::StartApplication () // Called at time specified by Start
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  
+  NS_ASSERT (m_active != true);
+  m_active = true;
+
+  NS_ASSERT_MSG (GetObject<Ccnx> () != 0,
+                 "Ccnx stack should be installed on the node " << GetNode ());
+  NS_ASSERT_MSG (GetObject<CcnxFib> () != 0);
+
+  // step 1. Create a face
+  m_face = Create<CcnxLocalFace> (/*Ptr<CcnxApp> (this)*/this);
+    
+  // step 2. Add face to the CCNx stack
+  GetObject<CcnxFib> ()->Add (m_prefix, m_face, 0);
+  GetObject<Ccnx> ()->AddFace (m_face);
+
+  // step 3. Enable face
+  m_face->SetUp (true);
+}
+    
+void 
+CcnxApp::StopApplication () // Called at time specified by Stop
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  if (!m_active) return; //don't assert here, just return
+ 
+  NS_ASSERT (GetObject<Ccnx> () != 0);
+  NS_ASSERT (GetObject<CcnxFib> () != 0);
+
+  m_active = false;
+
+  // step 1. Disable face
+  m_face->SetUp (false);
+
+  // step 2. Remove face from CCNx stack
+  GetObject<Ccnx> ()->RemoveFace (m_face);
+  GetObject<CcnxFib> ()->Add (m_prefix, m_face, 0);
+
+  // step 3. Destroy face
+  NS_ASSERT_MSG (m_face->GetReferenceCount ()==1,
+                 "At this point, nobody else should have referenced this face");
+  m_face = 0;
+}
+
+
+}
diff --git a/apps/ccnx-app.h b/apps/ccnx-app.h
new file mode 100644
index 0000000..4f2cb83
--- /dev/null
+++ b/apps/ccnx-app.h
@@ -0,0 +1,104 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 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 CCNX_APP_H
+#define CCNX_APP_H
+
+#include "ns3/application.h"
+#include "ns3/ptr.h"
+#include "ns3/callback.h"
+
+namespace ns3 
+{
+
+class Packet;
+class CcnxInterestHeader;
+class CcnxContentObjectHeader;
+
+/**
+ * @ingroup ccnx
+ * @brief Base class that all CCNx applications should be derived from.
+ * 
+ * The class implements virtual calls onInterest, onNack, and onContentObject
+ */
+class CcnxApp: public Application
+{
+public:
+  typedef Callback<bool, const Ptr<CcnxFace>&> ProtocolHandler;
+  
+  static TypeId GetTypeId ();
+
+  /**
+   * @brief Default constructor
+   */
+  CcnxApp ();
+  virtual ~CcnxApp ();
+
+  /**
+   * @brief Register lower layer callback (to send interests from the application)
+   */
+  void
+  RegisterProtocolHandler (ProtocolHandler handler);
+  
+  /**
+   * @brief Method that will be called every time new Interest arrives
+   * @param interest Interest header
+   */
+  virtual void
+  OnInterest (const Ptr<const CcnxInterestHeader> &interest);
+
+  /**
+   * @brief Method that will be called every time new NACK arrives
+   * @param interest Interest header
+   */
+  virtual void
+  OnNack (const Ptr<const CcnxInterestHeader> &interest);
+  
+  /**
+   * @brief Method that will be called every time new ContentObject arrives
+   * @param contentObject ContentObject header
+   * @param payload payload (potentially virtual) of the ContentObject packet
+   */
+  virtual void
+  OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
+                   const Ptr<const Packet> &payload);
+        
+protected:
+  virtual void
+  DoDispose ();
+
+  // inherited from Application base class.
+  virtual void
+  StartApplication ();    // Called at time specified by Start
+
+  virtual void
+  StopApplication ();     // Called at time specified by Stop
+
+protected:
+  ProtocolHandler m_protocolHandler;
+  bool m_active; 
+
+private:
+  Ptr<CcnxFace> m_face; // local face that is created 
+};
+
+} // namespace ns3
+
+#endif // CCNX_APP_H
diff --git a/apps/ccnx-consumer.cc b/apps/ccnx-consumer.cc
index ac3950c..01a5b1d 100644
--- a/apps/ccnx-consumer.cc
+++ b/apps/ccnx-consumer.cc
@@ -36,173 +36,132 @@
 TypeId
 CcnxConsumer::GetTypeId (void)
 {
-    static TypeId tid = TypeId ("ns3::CcnxConsumer")
-      .SetParent<Application> ()
-      .AddConstructor<CcnxConsumer> ()
-      .AddAttribute ("OffTime", "Time interval between packets",
-                     StringValue ("100ms"),
-                     MakeTimeAccessor (&CcnxConsumer::m_offTime),
-                     MakeTimeChecker ())
-      .AddAttribute ("InterestName","CcnxName of the Interest (use CcnxNameComponents)",
-                     StringValue ("/"),
-                     MakeCcnxNameComponentsAccessor (&CcnxConsumer::m_interestName),
-                     MakeCcnxNameComponentsChecker ())
-      .AddAttribute ("LifeTime", "LifeTime fo interest packet",
-                     StringValue ("2s"),
-                     MakeTimeAccessor (&CcnxConsumer::m_interestLifeTime),
-                     MakeTimeChecker ())
-      .AddAttribute ("MinSuffixComponents", "MinSuffixComponents",
-                     IntegerValue(-1),
-                     MakeIntegerAccessor(&CcnxConsumer::m_minSuffixComponents),
-                     MakeIntegerChecker<int32_t>())
-      .AddAttribute ("MaxSuffixComponents", "MaxSuffixComponents",
-                     IntegerValue(-1),
-                     MakeIntegerAccessor(&CcnxConsumer::m_maxSuffixComponents),
-                     MakeIntegerChecker<int32_t>())
-      .AddAttribute ("ChildSelector", "ChildSelector",
-                     BooleanValue(false),
-                     MakeBooleanAccessor(&CcnxConsumer::m_childSelector),
-                     MakeBooleanChecker())
-      .AddAttribute ("Exclude", "only simple name matching is supported (use CcnxNameComponents)",
-                     CcnxNameComponentsValue (),
-                     MakeCcnxNameComponentsAccessor (&CcnxConsumer::m_exclude),
-                     MakeCcnxNameComponentsChecker ())
-      .AddAttribute ("Initial Nonce", "If 0 then nonce is not used",
-                     UintegerValue(1),
-                     MakeUintegerAccessor(&CcnxConsumer::m_initialNonce),
-                     MakeUintegerChecker<uint32_t>())
-      .AddTraceSource ("InterestTrace", "Interests that were sent",
-                       MakeTraceSourceAccessor (&CcnxConsumer::m_interestsTrace))
-      .AddTraceSource ("ContentObjectTrace", "ContentObjects that were received",
-                       MakeTraceSourceAccessor (&CcnxConsumer::m_contentObjectsTrace))
-      ;
+  static TypeId tid = TypeId ("ns3::CcnxConsumer")
+    .SetParent<Application> ()
+    .AddConstructor<CcnxConsumer> ()
+    .AddAttribute ("OffTime", "Time interval between packets",
+                   StringValue ("100ms"),
+                   MakeTimeAccessor (&CcnxConsumer::m_offTime),
+                   MakeTimeChecker ())
+    .AddAttribute ("InterestName","CcnxName of the Interest (use CcnxNameComponents)",
+                   StringValue ("/"),
+                   MakeCcnxNameComponentsAccessor (&CcnxConsumer::m_interestName),
+                   MakeCcnxNameComponentsChecker ())
+    .AddAttribute ("LifeTime", "LifeTime fo interest packet",
+                   StringValue ("2s"),
+                   MakeTimeAccessor (&CcnxConsumer::m_interestLifeTime),
+                   MakeTimeChecker ())
+    .AddAttribute ("MinSuffixComponents", "MinSuffixComponents",
+                   IntegerValue(-1),
+                   MakeIntegerAccessor(&CcnxConsumer::m_minSuffixComponents),
+                   MakeIntegerChecker<int32_t>())
+    .AddAttribute ("MaxSuffixComponents", "MaxSuffixComponents",
+                   IntegerValue(-1),
+                   MakeIntegerAccessor(&CcnxConsumer::m_maxSuffixComponents),
+                   MakeIntegerChecker<int32_t>())
+    .AddAttribute ("ChildSelector", "ChildSelector",
+                   BooleanValue(false),
+                   MakeBooleanAccessor(&CcnxConsumer::m_childSelector),
+                   MakeBooleanChecker())
+    .AddAttribute ("Exclude", "only simple name matching is supported (use CcnxNameComponents)",
+                   CcnxNameComponentsValue (),
+                   MakeCcnxNameComponentsAccessor (&CcnxConsumer::m_exclude),
+                   MakeCcnxNameComponentsChecker ())
+    .AddAttribute ("Initial Nonce", "If 0 then nonce is not used",
+                   UintegerValue(1),
+                   MakeUintegerAccessor(&CcnxConsumer::m_initialNonce),
+                   MakeUintegerChecker<uint32_t>())
+    .AddTraceSource ("InterestTrace", "Interests that were sent",
+                     MakeTraceSourceAccessor (&CcnxConsumer::m_interestsTrace))
+    .AddTraceSource ("ContentObjectTrace", "ContentObjects that were received",
+                     MakeTraceSourceAccessor (&CcnxConsumer::m_contentObjectsTrace))
+    ;
 
-    return tid;
+  return tid;
 }
     
 CcnxConsumer::CcnxConsumer ()
-    : m_seq (0)
+  : m_rand (0, std::numeric_limits<uint32_t>::max ())
+  , m_seq (0)
 {
-    NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION_NOARGS ();
 }
     
 CcnxConsumer::~CcnxConsumer()
 {
-    NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION_NOARGS ();
 }
     
 void
 CcnxConsumer::DoDispose (void)
 {
-    NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION_NOARGS ();
         
-    Application::DoDispose ();
+  Application::DoDispose ();
 }
     
 // Application Methods
 void 
 CcnxConsumer::StartApplication () // Called at time specified by Start
 {
-    NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_FUNCTION_NOARGS ();
 
-    NS_ASSERT_MSG (m_face == 0, "Face should not exist");
-    m_face = Create<CcnxLocalFace> ();
-
-    // step 1. Set up forwarding from face to application
-    m_face->SetNode (GetNode ());
-    m_face->SetContentObjectHandler (MakeCallback (&CcnxConsumer::OnContentObject, this));
-
-    // step 2. Set up forwarding to and from ccnx
-    NS_ASSERT_MSG (GetNode ()->GetObject<Ccnx> () !=0,
-                   "Ccnx stack should be installed on the node " << GetNode ());
-    GetNode ()->GetObject<Ccnx> ()->AddFace (m_face);
-
-    // step 3. Enable face
-    m_face->SetUp ();
-
-    // Send first packet immediately
-    m_sendEvent = Simulator::Schedule (Seconds(0.0), &CcnxConsumer::SendPacket, this);
+  // do base stuff
+  CcnxApp::StartApplication ();
+  
+  // schedule periodic packet generation
+  m_sendEvent = Simulator::Schedule (Seconds(0.0), &CcnxConsumer::SendPacket, this);
 }
     
 void 
 CcnxConsumer::StopApplication () // Called at time specified by Stop
 {
-    NS_LOG_FUNCTION_NOARGS ();
-        
-    CancelEvents ();
+  NS_LOG_FUNCTION_NOARGS ();
 
-    // step 1. Disable face
-    m_face->SetDown ();
+  // cancel periodic packet generation
+  Simulator::Cancel (m_sendEvent);
 
-    // step 2. Remove face from ccnx stack
-    GetNode ()->GetObject<Ccnx> ()->RemoveFace (m_face);
-
-    // step 3. Disable callbacks
-    m_face->SetContentObjectHandler (MakeNullCallback<void,
-                                                      const Ptr<const CcnxContentObjectHeader> &,
-                                                      const Ptr<const Packet> &> ());
-}
-    
-void 
-CcnxConsumer::CancelEvents ()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-        
-    Simulator::Cancel (m_sendEvent);
+  // cleanup base stuff
+  CcnxApp::StopApplication ();
 }
     
 void
 CcnxConsumer::SendPacket ()
 {
-    NS_LOG_FUNCTION_NOARGS ();
-    NS_LOG_INFO ("Sending Interest at " << Simulator::Now ());
+  NS_LOG_FUNCTION_NOARGS ();
+  NS_LOG_INFO ("Sending Interest at " << Simulator::Now ());
     
-    UniformVariable rand(1, std::numeric_limits<uint32_t>::max ());
-    uint32_t randomNonce = rand.GetValue();
-    
-    CcnxInterestHeader interestHeader;
-    interestHeader.SetNonce(randomNonce);
-    
-    Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> (m_interestName);
-    std::ostringstream os;
-    os << m_seq++;
-    (*name) (os.str ());
-    
-    interestHeader.SetName (name);
-    interestHeader.SetInterestLifetime(m_interestLifeTime);
-    interestHeader.SetChildSelector(m_childSelector);
-    interestHeader.SetExclude(Create<CcnxNameComponents> (m_exclude));
-    interestHeader.SetMaxSuffixComponents(m_maxSuffixComponents);
-    interestHeader.SetMinSuffixComponents(m_minSuffixComponents);
+  //
+  Ptr<CcnxNameComponents> nameWithSequence = Create<CcnxNameComponents> (m_interestName);
+  (*name) (m_seq++);
+  //
+
+  CcnxInterestHeader interestHeader;
+  interestHeader.SetNonce               (m_rand.GetValue ());
+  interestHeader.SetName                (nameWithSequence);
+  interestHeader.SetInterestLifetime    (m_interestLifeTime);
+  interestHeader.SetChildSelector       (m_childSelector);
+  interestHeader.SetExclude             (Create<CcnxNameComponents> (m_exclude));
+  interestHeader.SetMaxSuffixComponents (m_maxSuffixComponents);
+  interestHeader.SetMinSuffixComponents (m_minSuffixComponents);
         
-    NS_LOG_INFO ("Interest: \n" << interestHeader);
+  NS_LOG_INFO ("Interest: \n" << interestHeader);
 
-    Ptr<Packet> packet = Create<Packet> ();
-    packet->AddHeader (interestHeader);
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (interestHeader);
 
-    NS_LOG_INFO ("Packet: " << packet);
-    m_face->ReceiveFromApplication (packet);
+  m_protocolHandler (packet);
     
-    m_interestsTrace (m_face,packet);
-    
-    NS_LOG_INFO("time = " << m_offTime);
-    m_sendEvent = Simulator::Schedule (m_offTime, &CcnxConsumer::SendPacket, this);
+  m_sendEvent = Simulator::Schedule (m_offTime, &CcnxConsumer::SendPacket, this);
 }
-    
-// void
-// CcnxConsumer::OnInterest (const Ptr<const CcnxInterestHeader> &interest)
-// {
-// }
 
 void
 CcnxConsumer::OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
                                const Ptr<const Packet> &payload)
 {
-  // do stuff
-  NS_LOG_FUNCTION ("Received contentObject " << contentObject );
-    NS_LOG_INFO ("Preved!");
-  m_contentObjectsTrace (m_face,payload);
+  NS_LOG_FUNCTION (this << contentObject << payload);
+
+  NS_LOG_INFO ("Received content object: " << cref(*contentObject));
 }
 
-
-}
+} // namespace ns3
diff --git a/apps/ccnx-consumer.h b/apps/ccnx-consumer.h
index 16dbaf7..b2c115b 100644
--- a/apps/ccnx-consumer.h
+++ b/apps/ccnx-consumer.h
@@ -21,76 +21,45 @@
 #ifndef CCNX_CONSUMER_H
 #define CCNX_CONSUMER_H
 
-#include "ns3/application.h"
-#include "ns3/log.h"
-#include "ns3/random-variable.h"
-#include "ns3/nstime.h"
-#include "ns3/event-id.h"
-#include "ns3/ptr.h"
-#include "ns3/simulator.h"
-#include "ns3/ccnx-interest-header.h"
-#include "ns3/ccnx-local-face.h"
-#include "ns3/ccnx-name-components.h"
-#include "ns3/packet.h"
-#include "ns3/boolean.h"
-#include "ns3/integer.h"
-#include "ns3/uinteger.h"
-#include "ns3/pointer.h"
-#include "ns3/traced-callback.h"
-#include "ns3/ccnx-header-helper.h"
-
-#include "ns3/packet.h"
-#include "ns3/header.h"
+#include "ccnx-app.h"
 
 namespace ns3 
 {
 
-class CcnxConsumer: public Application
+class CcnxConsumer: public CcnxApp
 {
 public: 
   static TypeId GetTypeId ();
         
   CcnxConsumer ();
-  virtual ~CcnxConsumer ();
 
   void OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
                         const Ptr<const Packet> &payload);
-        
+
 protected:
-  virtual void DoDispose (void);
+  // from CcnxApp
+  virtual void
+  StartApplication ();
+
+  virtual void
+  StopApplication ();
   
 private:
-  // inherited from Application base class.
-  virtual void StartApplication (void);    // Called at time specified by Start
-  virtual void StopApplication (void);     // Called at time specified by Stop
-        
   //helpers
-  void CancelEvents ();
-
-  // Event handlers
-  // void StartSending ();
-  // void StopSending ();
   void SendPacket ();
-  //typedef Callback<void,const Ptr<CcnxFace>&,const Ptr<const Packet>& > ProtocolHandler;
      
 private:
-  TracedCallback<const Ptr<CcnxFace>&,const Ptr<const Packet>& > m_interestsTrace;
-  TracedCallback<const Ptr<CcnxFace>&,const Ptr<const Packet>& > m_contentObjectsTrace;
+  UniformVariable m_rand;
+  uint32_t        m_seq;
+  EventId         m_sendEvent; // Eventid of pending "send packet" event
 
-  Time m_offTime;
+  Time               m_offTime;
   CcnxNameComponents m_interestName;
-  Time m_interestLifeTime;
-  int32_t m_minSuffixComponents;
-  int32_t m_maxSuffixComponents;
-  bool m_childSelector;
+  Time               m_interestLifeTime;
+  int32_t            m_minSuffixComponents;
+  int32_t            m_maxSuffixComponents;
+  bool               m_childSelector;
   CcnxNameComponents m_exclude;
-  uint32_t m_initialNonce;
-        
-  EventId         m_sendEvent;    // Eventid of pending "send packet" event
-  TypeId          m_tid;
-  Ptr<CcnxLocalFace> m_face;
-    
-  uint32_t m_seq;
 };
 
 } // namespace ns3
diff --git a/apps/ccnx-producer.cc b/apps/ccnx-producer.cc
index d320a2d..1cec691 100644
--- a/apps/ccnx-producer.cc
+++ b/apps/ccnx-producer.cc
@@ -16,202 +16,67 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * Author: Ilya Moiseenko <iliamo@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
 #include "ccnx-producer.h"
+#include "ns3/ccnx-interest-header.h"
+#include "ns3/string.h"
+#include "ns3/integer.h"
 
+#include "ns3/ccnx-local-face.h"
 
 NS_LOG_COMPONENT_DEFINE ("CcnxProducer");
 
 namespace ns3
 {    
-    
+
 NS_OBJECT_ENSURE_REGISTERED (CcnxProducer);
     
 TypeId
 CcnxProducer::GetTypeId (void)
 {
-    static TypeId tid = TypeId ("ns3::CcnxProducer")
-    .SetParent<Application> ()
+  static TypeId tid = TypeId ("ns3::CcnxProducer")
+    .SetParent<CcnxApp> ()
     .AddConstructor<CcnxProducer> ()
-    /*.AddAttribute ("Capacity", "Capacity of the ContentStore",
-                    UintegerValue(100),
-                    MakeUintegerAccessor(&CcnxProducer::m_storeCapacity),
-                    MakeUintegerChecker<uint32_t>())*/
     .AddAttribute ("Prefix","Prefix, for which producer has the data",
-                   CcnxNameComponentsValue (),
+                   StringValue ("/"),
                    MakeCcnxNameComponentsAccessor (&CcnxProducer::m_prefix),
                    MakeCcnxNameComponentsChecker ())
     .AddAttribute ("PayloadSize", "Virtual payload size for Content packets",
-                   UintegerValue(100),
+                   UintegerValue (100),
                    MakeUintegerAccessor(&CcnxProducer::m_virtualPayloadSize),
                    MakeUintegerChecker<uint32_t>())
-    .AddTraceSource ("InterestTrace", "Interests that were received",
-                    MakeTraceSourceAccessor (&CcnxProducer::m_interestsTrace))
-    .AddTraceSource ("ContentObjectTrace", "ContentObjects that were sent",
-                    MakeTraceSourceAccessor (&CcnxProducer::m_contentObjectsTrace))
+    // .AddTraceSource ("InterestTrace", "Interests that were received",
+    //                 MakeTraceSourceAccessor (&CcnxProducer::m_interestsTrace))
+    // .AddTraceSource ("ContentObjectTrace", "ContentObjects that were sent",
+    //                 MakeTraceSourceAccessor (&CcnxProducer::m_contentObjectsTrace))
     ;
         
-    return tid;
+  return tid;
 }
     
 CcnxProducer::CcnxProducer ()
 {
-    NS_LOG_FUNCTION_NOARGS ();
+  // NS_LOG_FUNCTION_NOARGS ();
 }
-    
-CcnxProducer::~CcnxProducer()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-}
-    
+       
 void
-CcnxProducer::DoDispose (void)
+CcnxProducer::OnInterest (const Ptr<const CcnxInterestHeader> &interest)
 {
-    NS_LOG_FUNCTION_NOARGS ();
-        
-    Application::DoDispose ();
-}
-    
-    // Application Methods
-void 
-CcnxProducer::StartApplication () // Called at time specified by Start
-{
-    NS_LOG_FUNCTION_NOARGS ();
-    
-    NS_ASSERT_MSG (m_face == 0, "Face should not exist");
-    m_face = Create<CcnxLocalFace> ();
-    
-    // step 1. Set up forwarding from face to application
-    m_face->SetNode (GetNode ());
-    m_face->SetInterestHandler (MakeCallback (&CcnxProducer::OnInterest, this));
-    
-    // step 2. Set up forwarding to and from ccnx
-    NS_ASSERT_MSG (GetNode ()->GetObject<Ccnx> () !=0,
-                   "Ccnx stack should be installed on the node " << GetNode ());
-    GetNode ()->GetObject<Ccnx> ()->AddFace (m_face);
-    //Add (const CcnxNameComponents &prefix, Ptr<CcnxFace> face, int32_t metric);
-    GetNode ()->GetObject<Ccnx> ()->GetObject<CcnxFib> ()->Add(m_prefix, m_face, 0);
-    // step 3. Enable face
-    m_face->SetUp ();
-}
-    
-void 
-CcnxProducer::StopApplication () // Called at time specified by Stop
-{
-    NS_LOG_FUNCTION_NOARGS ();
-}
-    
-void
-CcnxProducer::OnInterest(const Ptr<const CcnxInterestHeader> &interest)
-{
-    NS_LOG_FUNCTION (this);
-    
-    
-    
-    //Ptr<Packet> data = Lookup (interest);
-    
-    
-    
-    Ptr<Packet> incomingPacket = Create<Packet>(m_virtualPayloadSize);
-    incomingPacket->AddHeader (*interest);
-    m_interestsTrace(m_face,incomingPacket);
-    
-   
+  NS_LOG_FUNCTION (this << interest);
 
-    static CcnxContentObjectTail tail; ///< \internal for optimization purposes
-    Ptr<Packet> outgoingPacket = Create<Packet> (m_virtualPayloadSize);
-    Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader>();
-    header->SetName(Create<CcnxNameComponents>(interest->GetName()));
-    outgoingPacket->AddHeader(*header);
-    outgoingPacket->AddTrailer (tail);
+  if (!m_active) return;
     
-    m_contentObjectsTrace(m_face,outgoingPacket);
-        
-    m_face->ReceiveFromApplication(outgoingPacket);
-   
-}
-    
-void 
-CcnxProducer::CancelEvents ()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-        
-    // Simulator::Cancel (m_sendEvent);
-}
+  static CcnxContentObjectTail tail;
+  Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
+  header->SetName (Create<CcnxNameComponents> (interest->GetName ()));
   
-CcnxNameComponents
-CcnxProducer::GetPrefix() const
-{
-  return m_prefix;
+  Ptr<Packet> packet = Create<Packet> (m_virtualPayloadSize);
+  outgoingPacket->AddHeader (*header);
+  outgoingPacket->AddTrailer (tail);
+
+  m_protocolHandler (outgoingPacket);
 }
-    
-/*uint32_t
-CcnxProducer::GetStoreCapacity()
-{
-  return m_storeCapacity;
-}
-    
-void
-CcnxProducer::SetStoreCapacity(uint32_t capacity)
-{
-  m_storeCapacity = capacity;
-}
-  */  
-/*void
-CcnxProducer::HandlePacket(const Ptr<CcnxFace> &face, const Ptr<const Packet> &packet)
-{
-    uint8_t type[2];
-    uint32_t read = packet->CopyData (type,2);
-    if (read!=2)
-    {
-        NS_LOG_INFO ("Unknown CcnxPacket");
-        return;
-    }
-        
-    if (type[0] == INTEREST_BYTE0 && type[1] == INTEREST_BYTE1)
-    {
-        m_interestsTrace(face,packet);
-    }
-    else if (type[0] == CONTENT_OBJECT_BYTE0 && type[1] == CONTENT_OBJECT_BYTE1)
-    {
-        m_contentObjectsTrace(face,packet);
-    }
-}*/
-    
-/*Ptr<Packet>
-CcnxProducer::Lookup (Ptr<const CcnxInterestHeader> interest)
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  DataStoreContainer::type::iterator it = m_availableData.get<i_prefix> ().find (interest->GetName ());
-        
-  if (it != m_availableData.end ())
-  {
-    // return fully formed CCNx packet
-    return it->GetFullyFormedCcnxPacket ();
-  }
-    
-  return 0;
-}   
-    
-void 
-CcnxProducer::Add (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet)
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  DataStoreContainer::type::iterator it = m_availableData.get<i_prefix> ().find (header->GetName ());
-        
-  if (it == m_availableData.end ())
-  { // add entry to the top
-    m_availableData.get<i_mru> ().push_front (DataStoreEntry (header, packet));
-            
-    if (m_availableData.size () > m_storeCapacity)
-      m_availableData.get<i_mru> ().pop_back ();
-  }
-  else
-  {
-    // promote entry to the top
-    //m_contentStore.get<i_mru> ().relocate (m_contentStore.get<i_mru> ().begin (),
-      //                                             m_contentStore.project<i_mru> (it));
-  }
-}*/
-}
+
+} // namespace ns3
diff --git a/apps/ccnx-producer.h b/apps/ccnx-producer.h
index 840400b..289c22e 100644
--- a/apps/ccnx-producer.h
+++ b/apps/ccnx-producer.h
@@ -16,194 +16,36 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * Author: Ilya Moiseenko <iliamo@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
 #ifndef CCNX_PRODUCER_H
 #define CCNX_PRODUCER_H
 
-#include "ns3/application.h"
-#include "ns3/log.h"
-#include "ns3/random-variable.h"
-#include "ns3/nstime.h"
-#include "ns3/event-id.h"
+#include "ccnx-app.h"
+
 #include "ns3/ptr.h"
-#include "ns3/simulator.h"
-#include "ns3/ccnx-interest-header.h"
-#include "ns3/ccnx-local-face.h"
 #include "ns3/ccnx-name-components.h"
-#include "ns3/packet.h"
-#include "ns3/boolean.h"
-#include "ns3/integer.h"
-#include "ns3/uinteger.h"
-#include "ns3/random-variable.h"
-#include <limits> 
-#include "ns3/pointer.h"
-#include "ns3/traced-callback.h"
-#include "ns3/ccnx-header-helper.h"
-
-#include "ns3/packet.h"
-#include "ns3/header.h"
-#include "ns3/ccnx.h"
-#include "ns3/ccnx-content-object-header.h"
-#include "ns3/ccnx-name-components.h"
-#include "ns3/ccnx-fib.h"
-
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/tag.hpp>
-#include <boost/multi_index/ordered_index.hpp>
-#include <boost/multi_index/sequenced_index.hpp>
-#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index/mem_fun.hpp>
 
 namespace ns3 
 {
-    
-    class DataStoreEntry
-    {
-    public:
-        /**
-         * \brief Construct data store entry
-         *
-         * \param header Parsed CcnxContentObject header
-         * \param packet Original CCNx packet
-         *
-         * The constructor will make a copy of the supplied packet and calls
-         * RemoveHeader and RemoveTail on the copy.
-         */
-        DataStoreEntry (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet);
-        
-        /**
-         * \brief Get prefix of the stored entry
-         * \returns prefix of the stored entry
-         */
-        inline const CcnxNameComponents&
-        GetName () const;
-        
-        /**
-         * \brief Get CcnxContentObjectHeader of the stored entry
-         * \returns CcnxContentObjectHeader of the stored entry
-         */
-        inline Ptr<const CcnxContentObjectHeader>
-        GetHeader () const;
-        
-        /**
-         * \brief Get content of the stored entry
-         * \returns content of the stored entry
-         */
-        inline Ptr<const Packet>
-        GetPacket () const;
-        
-        /**
-         * \brief Convenience method to create a fully formed CCNx packet from stored header and content
-         * \returns A read-write copy of the packet with CcnxContentObjectHeader and CcxnContentObjectTail
-         */
-        Ptr<Packet>
-        GetFullyFormedCcnxPacket () const;
-        
-        // Copy constructor is required by the container. Though, we're
-        // storing only two pointers, so shouldn't be a problem
-        // private:
-        //   CcnxContentStoreEntry (const CcnxContentStoreEntry &); ///< disabled copy constructor
-        //   CcnxContentStoreEntry& operator= (const CcnxContentStoreEntry&); ///< disabled copy operator
-        
-    private:
-        //Ptr<CcnxContentObjectHeader> m_header; ///< \brief non-modifiable CcnxContentObjectHeader
-        //Ptr<Packet> m_packet; ///< \brief non-modifiable content of the ContentObject packet
-    };
 
-    
-class CcnxProducer: public Application
+class CcnxProducer : public CcnxApp
 {
 public: 
-    static TypeId GetTypeId (void);
+  static TypeId
+  GetTypeId (void);
         
-    CcnxProducer ();
-        
-    virtual ~CcnxProducer ();
-        
-    //void HandlePacket (const Ptr<CcnxFace> &face, const Ptr<const Packet> &packet);
-    //uint32_t GetStoreCapacity();
-    //void SetStoreCapacity(uint32_t capacity);
-    //void AddContentStoreEntry (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet);
-    
-    void OnInterest(const Ptr<const CcnxInterestHeader> &interest);
-    
-    CcnxNameComponents GetPrefix() const;  
-    /**
-     * \brief Add a new content to the data store.
-     *
-     * \param header Fully parsed CcnxContentObjectHeader
-     * \param packet Fully formed CCNx packet to add to content store
-     * (will be copied and stripped down of headers)
-     *
-     * If entry with the same prefix exists, the old entry will be
-     * promoted to the top of the MRU hash
-     */
-    //void
-    //Add (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet);
-    
-protected:
-    virtual void DoDispose (void);
+  CcnxProducer ();
+
+  // inherited from CcnxApp
+  void OnInterest (const Ptr<const CcnxInterestHeader> &interest);
+
 private:
-    // inherited from Application base class.
-    virtual void StartApplication (void);    // Called at time specified by Start
-    virtual void StopApplication (void);     // Called at time specified by Stop
-        
-    /**
-     * \brief Find corresponding CS entry for the given interest
-     *
-     * \param interest Interest for which matching content store entry
-     * will be searched
-     *
-     * If an entry is found, it is promoted to the top of most recent
-     * used entries index, \see m_contentStore
-     */
-    //Ptr<Packet>
-    //Lookup (Ptr<const CcnxInterestHeader> interest);
-
-    
-    Ptr<Ccnx> m_ccnx;
-    Time m_offTime;
-           
-    //EventId         m_sendEvent;    // Eventid of pending "send packet" event
-    TypeId          m_tid;
-    Ptr<CcnxLocalFace> m_face;
-    
-    /*struct DataStoreContainer
-    {
-        typedef
-        boost::multi_index::multi_index_container<
-          DataStoreEntry,
-          boost::multi_index::indexed_by<
-            boost::multi_index::hashed_unique<
-              boost::multi_index::tag<__ccnx_private::i_prefix>,
-              boost::multi_index::const_mem_fun<DataStoreEntry,
-                                                const CcnxNameComponents&,
-                                                &DataStoreEntry::GetName>,
-              CcnxPrefixHash>,
-          boost::multi_index::sequenced<boost::multi_index::tag<__ccnx_private::i_mru> >
-#ifdef _DEBUG
-          ,
-          boost::multi_index::ordered_unique<
-          boost::multi_index::tag<__ccnx_private::i_ordered>,
-          boost::multi_index::const_mem_fun<DataStoreEntry,
-          const CcnxNameComponents&,
-          &CcnxContentStoreEntry::GetName>
-          >
-#endif
-        >
-      > type;
-    };*/
-
-    //helpers
-    void CancelEvents ();
-    
-    //DataStoreContainer::type m_availableData;
-    //uint32_t m_storeCapacity;
-    uint32_t m_virtualPayloadSize;
-    CcnxNameComponents m_prefix;
-    TracedCallback<const Ptr<CcnxFace>&,const Ptr<const Packet>& > m_interestsTrace;
-    TracedCallback<const Ptr<CcnxFace>&,const Ptr<const Packet>& > m_contentObjectsTrace;
+  CcnxNameComponents m_prefix;
+  uint32_t m_virtualPayloadSize;
 };
+
 }
-#endif
+
+#endif // CCNX_PRODUCER_H
diff --git a/model/ccnx-bestroute-strategy.cc b/model/ccnx-bestroute-strategy.cc
index 4e592c7..cad2d67 100644
--- a/model/ccnx-bestroute-strategy.cc
+++ b/model/ccnx-bestroute-strategy.cc
@@ -48,8 +48,7 @@
 CcnxBestRouteStrategy::PropagateInterest (const CcnxPitEntry  &pitEntry, 
                                           const Ptr<CcnxFace> &incomingFace,
                                           Ptr<CcnxInterestHeader> &header,
-                                          const Ptr<const Packet> &packet,
-                                          SendCallback sendCallback)
+                                          const Ptr<const Packet> &packet)
 {
   NS_LOG_FUNCTION (this);
   bool forwardedCount = 0;
@@ -66,11 +65,13 @@
           if (pitEntry.m_outgoing.find (bestMetric.m_face) != pitEntry.m_outgoing.end ()) // already forwarded before
             continue;
 
-          bool faceAvailable = m_pit->TryAddOutgoing (pitEntry, bestMetric.m_face);
+          bool faceAvailable = bestMetric.m_face->SendWithLimit (packet->Copy ());
           if (!faceAvailable) // huh...
             continue;
 
-          sendCallback (bestMetric.m_face, header, packet->Copy());
+          m_pit->modify (m_pit->iterator_to (pitEntry),
+                         bind(&CcnxPitEntry::AddOutgoing, lambda::_1, bestMetric.m_face));
+
           forwardedCount++;
           break; // if we succeeded in sending one packet, stop
         }
diff --git a/model/ccnx-bestroute-strategy.h b/model/ccnx-bestroute-strategy.h
index 4e5eb6c..f2d591b 100644
--- a/model/ccnx-bestroute-strategy.h
+++ b/model/ccnx-bestroute-strategy.h
@@ -51,8 +51,7 @@
   PropagateInterest (const CcnxPitEntry  &pitEntry, 
                      const Ptr<CcnxFace> &incomingFace,
                      Ptr<CcnxInterestHeader> &header,
-                     const Ptr<const Packet> &packet,
-                     SendCallback sendCallback);
+                     const Ptr<const Packet> &packet);
 };
 
 } //namespace ns3
diff --git a/model/ccnx-face.cc b/model/ccnx-face.cc
index 19eb21d..1bb55ab 100644
--- a/model/ccnx-face.cc
+++ b/model/ccnx-face.cc
@@ -34,9 +34,12 @@
  *  with no IP addresses.  Before becoming useable, the user must 
  * invoke SetUp on them once an Ccnx address and mask have been set.
  */
-CcnxFace::CcnxFace () 
-  // : m_metric (1)
-  : m_node (0)
+CcnxFace::CcnxFace (Ptr<Node> node) 
+  : m_node (Ptr<Node> node)
+  , m_bucket (0.0)
+  , m_bucketMax (-1.0)
+  , m_bucketLeak (0.0)
+  , m_protocolHandler (MakeNullCallback<void,const Ptr<CcnxFace>&,const Ptr<const Packet>&> ())
   , m_ifup (false)
   , m_id ((uint32_t)-1)
 {
@@ -57,10 +60,53 @@
   return *this;
 }
 
-void 
-CcnxFace::SetNode (Ptr<Node> node)
+void
+CcnxFace::RegisterProtocolHandler (ProtocolHandler handler)
 {
-  m_node = node;
+  m_protocolHandler = handler;
+}
+
+bool
+CcnxFace::SendWithLimit (Ptr<Packet> packet)
+{
+  /// \todo Implement tracing, if requested
+  
+  if (!IsUp ())
+    return false;
+
+  if (m_bucketMax > 0)
+    {
+      if (m_bucket+1.0 > m_bucketMax)
+        return false;
+      
+      m_bucket += 1.0;
+    }
+
+  SendImpl (packet);
+  return true;
+}
+
+bool
+CcnxFace::SendWithoutLimits (Ptr<Packet> packet)
+{
+  /// \todo Implement tracing, if requested
+
+  if (!IsUp ())
+    return false;
+
+  SendImpl (packet);
+  return true;
+}
+
+bool
+CcnxFace::Receive (Ptr<const Packet> packet)
+{
+  /// \todo Implement tracing, if requested
+
+  if (!IsUp ())
+    return false;
+
+  m_protocolHandler (this, packet);
 }
 
 // void
@@ -89,25 +135,11 @@
   return m_ifup;
 }
 
-bool 
-CcnxFace::IsDown (void) const
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  return !m_ifup;
-}
-
 void 
-CcnxFace::SetUp (void)
+CcnxFace::SetUp (bool up/* = true*/)
 {
   NS_LOG_FUNCTION_NOARGS ();
-  m_ifup = true;
-}
-
-void 
-CcnxFace::SetDown (void)
-{
-  NS_LOG_FUNCTION_NOARGS ();
-  m_ifup = false;
+  m_ifup = up;
 }
 
 bool
diff --git a/model/ccnx-face.h b/model/ccnx-face.h
index 81700df..bc6769e 100644
--- a/model/ccnx-face.h
+++ b/model/ccnx-face.h
@@ -24,14 +24,12 @@
 #include <ostream>
 
 #include "ns3/ptr.h"
-#include "ns3/simple-ref-count.h"
-#include "ns3/callback.h"
+#include "ns3/ccnx.h"
 
 namespace ns3 {
 
 class Packet;
 class Node;
-
   
 /**
  * \ingroup ccnx
@@ -54,14 +52,14 @@
    * \brief Ccnx protocol hanler
    *
    * \param face Face from which packet has been received
-   * \param packet Received packet
+   * \param packet Original packet
    */
   typedef Callback<void,const Ptr<CcnxFace>&,const Ptr<const Packet>& > ProtocolHandler;
 
   /**
    * \brief Default constructor
    */
-  CcnxFace ();
+  CcnxFace (Ptr<Node> node);
   virtual ~CcnxFace();
 
   ////////////////////////////////////////////////////////////////////
@@ -71,23 +69,43 @@
    *
    * This method should call protocol-dependent registration function
    */
-  virtual void RegisterProtocolHandler (ProtocolHandler handler) = 0;
+  virtual void
+  RegisterProtocolHandler (ProtocolHandler handler);
   
   /**
-   * \brief Send packet on a face
+   * \brief Send packet on a face with regard Interest limits
+   *
+   * This method will be called by lower layers to send data to device or application
    *
    * \param p smart pointer to a packet to send
+   *
+   * @return false if either limit is reached or face is down
    */ 
-  virtual void Send (Ptr<Packet> p) = 0;
-
-  ////////////////////////////////////////////////////////////////////
+  bool
+  SendWithLimit (Ptr<Packet> p);
 
   /**
-   * \brief Associate Node object with face
+   * \brief Send content packet on a face without regard to limits
    *
-   * \param node smart pointer to a Node object
+   * This method will be called by lower layers to send data to device or application
+   *
+   * !!! The only difference between this call and SendInterest is that the former check Interest limit !!!
+   *
+   * \param p smart pointer to a packet to send
+   *
+   * @return false if face is down
+   */ 
+  bool
+  SendWithoutLimits (Ptr<Packet> p);
+
+  /**
+   * \brief Receive packet from application or another node and forward it to the CCNx stack
+   *
+   * \todo The only reason for this call is to handle tracing, if requested
    */
-  virtual void SetNode (Ptr<Node> node);
+  void
+  Receive (Ptr<const Packet> p);
+  ////////////////////////////////////////////////////////////////////
 
   // /**
   //  * \Brief Assign routing/forwarding metric with face
@@ -110,24 +128,16 @@
    */
   
   /**
-   * \brief Enable this face
+   * \brief Enable or disable this face
    */
-  virtual void SetUp ();
-
-  /**
-   * \brief Disable this face
-   */
-  virtual void SetDown (void);
+  virtual void
+  SetUp (bool up = true);
 
   /**
    * \brief Returns true if this face is enabled, false otherwise.
    */
-  virtual bool IsUp () const;
-
-  /**
-   * \brief Returns true if this face is disabled, false otherwise.
-   */
-  virtual bool IsDown () const;
+  virtual bool
+  IsUp () const;
   
   virtual std::ostream&
   Print (std::ostream &os) const;
@@ -153,6 +163,22 @@
   GetId () const;
 
   /**
+   * @brief Set maximum value for Interest allowance
+   *
+   * @param bucket maximum value for Interest allowance. If < 0, then limit will be disabled
+   */
+  inline void
+  SetBucketMax (double bucket);
+
+  /**
+   * @brief Leak the Interest allowance bucket by (1/interval) * m_bucketMax amount
+   *
+   * @param interval Time interval with which the bucket is leaked
+   */
+  inline void
+  LeakBucket (const Time &interval);
+  
+  /**
    * \brief Compare two faces. Only two faces on the same node could be compared.
    *
    * Internal index is used for comparison.
@@ -168,6 +194,15 @@
   bool
   operator< (const CcnxFace &face) const;
 
+protected:
+  /**
+   * \brief Send packet on a face (actual implementation)
+   *
+   * \param p smart pointer to a packet to send
+   */
+  virtual void
+  SendImpl (Ptr<Packet> p) = 0;  
+
 private:
   CcnxFace (const CcnxFace &); ///< \brief Disabled copy constructor
   CcnxFace& operator= (const CcnxFace &); ///< \brief Disabled copy operator
@@ -175,9 +210,13 @@
 protected:
   // uint16_t m_metric; ///< \brief Routing/forwarding metric
   Ptr<Node> m_node; ///< \brief Smart pointer to Node
-  ProtocolHandler m_protocolHandler; ///< Callback via which packets are getting send to CCNx stack
 
+  double m_bucket; ///< \brief Value representing current size of the Interest allowance for this face
+  double m_bucketMax;  ///< \brief Maximum Interest allowance for this face
+  double m_bucketLeak; ///< \brief Normalized amount that should be leaked every second
+  
 private:
+  ProtocolHandler m_protocolHandler; ///< Callback via which packets are getting send to CCNx stack
   bool m_ifup; ///< \brief flag indicating that the interface is UP 
   uint32_t m_id; ///< \brief id of the interface in CCNx stack (per-node uniqueness)  
 };
@@ -202,6 +241,20 @@
   return m_id;
 }
 
+void
+CcnxFace::SetBucketMax (double bucket)
+{
+  m_bucketMax = bucket;
+}
+
+void
+CcnxFace::LeakBucket (const Time &interval)
+{
+  const double leak = m_bucketLeak * 1.0 / interval.ToDouble (Time::S);
+  m_bucket -= std::max (0, m_bucket-leak); 
+}
+
+
 } // namespace ns3
 
 #endif //CCNX_FACE_H
diff --git a/model/ccnx-fib.cc b/model/ccnx-fib.cc
index a2d8b4b..bd3cd67 100644
--- a/model/ccnx-fib.cc
+++ b/model/ccnx-fib.cc
@@ -216,6 +216,27 @@
   return entry;
 }
     
+void
+CcnxFib::Delete (const CcnxNameComponents &prefix, Ptr<CcnxFace> face)
+{
+  NS_LOG_FUNCTION (this << prefix << face);
+
+  CcnxFibEntryContainer::type::iterator entry = find (prefix);
+  if (entry == end ())
+    return;
+
+  modify (entry,
+          bind (&CcnxFibEntry::RemoveFace, _1, face));
+  if (entry->m_faces.size () == 0)
+    {
+      erase (entry);
+    }
+}
+
+void
+CcnxFib::DeleteFromAll (Ptr<CcnxFace> face)
+{
+}
 
 std::ostream& operator<< (std::ostream& os, const CcnxFib &fib)
 {
diff --git a/model/ccnx-fib.h b/model/ccnx-fib.h
index 2bd131c..84d618d 100644
--- a/model/ccnx-fib.h
+++ b/model/ccnx-fib.h
@@ -277,7 +277,19 @@
   CcnxFibEntryContainer::type::iterator
   Add (const CcnxNameComponents &prefix, Ptr<CcnxFace> face, int32_t metric);
 
-  // void resetProbing();    //reset needsProbing field for every FibEntry
+  /**
+   * @brief Remove reference to a face from the entry for `prefix`. If entry had only this face, the whole
+   * entry will be removed
+   */
+  void
+  Delete (const CcnxNameComponents &prefix, Ptr<CcnxFace> face);
+
+  /**
+   * @brief Remove all references to a face from FIB.  If for some enty that face was the only element,
+   * this FIB entry will be removed.
+   */
+  void
+  DeleteFromAll (Ptr<CcnxFace> face);
 
 protected:
   // inherited from Object class
diff --git a/model/ccnx-flooding-strategy.cc b/model/ccnx-flooding-strategy.cc
index d7f6827..1fa7a93 100644
--- a/model/ccnx-flooding-strategy.cc
+++ b/model/ccnx-flooding-strategy.cc
@@ -49,8 +49,7 @@
 CcnxFloodingStrategy::PropagateInterest (const CcnxPitEntry  &pitEntry, 
                                          const Ptr<CcnxFace> &incomingFace,
                                          Ptr<CcnxInterestHeader> &header,
-                                         const Ptr<const Packet> &packet,
-                                         SendCallback sendCallback)
+                                         const Ptr<const Packet> &packet)
 {
   NS_LOG_FUNCTION (this);
     
@@ -66,11 +65,13 @@
       if (pitEntry.m_outgoing.find (metricFace.m_face) != pitEntry.m_outgoing.end ()) // already forwarded before
         continue;
 
-      bool faceAvailable = m_pit->TryAddOutgoing (pitEntry, metricFace.m_face);
+      bool faceAvailable = metricFace.m_face->SendWithLimit (packet->Copy ());
       if (!faceAvailable) // huh...
-          continue;
+        continue;
+
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     bind(&CcnxPitEntry::AddOutgoing, lambda::_1, metricFace.m_face));
         
-      sendCallback (metricFace.m_face, header, packet->Copy());
       propagatedCount++;
     }
 
diff --git a/model/ccnx-flooding-strategy.h b/model/ccnx-flooding-strategy.h
index 0d43b6a..8be12e9 100644
--- a/model/ccnx-flooding-strategy.h
+++ b/model/ccnx-flooding-strategy.h
@@ -50,8 +50,7 @@
   PropagateInterest (const CcnxPitEntry  &pitEntry, 
                      const Ptr<CcnxFace> &incomingFace,
                      Ptr<CcnxInterestHeader> &header,
-                     const Ptr<const Packet> &packet,
-                     SendCallback sendCallback);
+                     const Ptr<const Packet> &packet);
 };
     
 } //namespace ns3
diff --git a/model/ccnx-forwarding-strategy.h b/model/ccnx-forwarding-strategy.h
index b8bbc5b..d7a5ab5 100644
--- a/model/ccnx-forwarding-strategy.h
+++ b/model/ccnx-forwarding-strategy.h
@@ -42,10 +42,6 @@
 class CcnxForwardingStrategy : public Object
 {
 public:
-  typedef
-  Callback<void, const Ptr<CcnxFace> &, const Ptr<const CcnxInterestHeader> &, const Ptr<Packet> &>
-  SendCallback;
-
   static TypeId GetTypeId (void);
 
   /**
@@ -69,8 +65,7 @@
   PropagateInterest (const CcnxPitEntry  &pitEntry, 
                      const Ptr<CcnxFace> &incomingFace,
                      Ptr<CcnxInterestHeader> &header,
-                     const Ptr<const Packet> &packet,
-                     SendCallback sendCallback) = 0;
+                     const Ptr<const Packet> &packe) = 0;
     
   /**
    * @brief Set link to PIT for the forwarding strategy
diff --git a/model/ccnx-l3-protocol.cc b/model/ccnx-l3-protocol.cc
index b719e99..1d4c548 100644
--- a/model/ccnx-l3-protocol.cc
+++ b/model/ccnx-l3-protocol.cc
@@ -61,20 +61,11 @@
     .SetParent<Ccnx> ()
     .SetGroupName ("Ccnx")
     .AddConstructor<CcnxL3Protocol> ()
-    // .AddTraceSource ("Tx", "Send ccnx packet to outgoing interface.",
-    //                  MakeTraceSourceAccessor (&CcnxL3Protocol::m_txTrace))
-    // .AddTraceSource ("Rx", "Receive ccnx packet from incoming interface.",
-    //                  MakeTraceSourceAccessor (&CcnxL3Protocol::m_rxTrace))
-    // .AddTraceSource ("Drop", "Drop ccnx packet",
-    //                  MakeTraceSourceAccessor (&CcnxL3Protocol::m_dropTrace))
-    // .AddAttribute ("InterfaceList", "The set of Ccnx interfaces associated to this Ccnx stack.",
-    //                ObjectVectorValue (),
-    //                MakeObjectVectorAccessor (&CcnxL3Protocol::m_faces),
-    //                MakeObjectVectorChecker<CcnxFace> ())
-
-    // .AddTraceSource ("SendOutgoing", "A newly-generated packet by this node is about to be queued for transmission",
-    //                  MakeTraceSourceAccessor (&CcnxL3Protocol::m_sendOutgoingTrace))
-
+    .AddAttribute ("BucketLeakInterval",
+                   "Interval to leak buckets",
+                   StringValue ("10ms"),
+                   MakeTimeAccessor (&CcnxPit::GetBucketLeakInterval, &CcnxPit::SetBucketLeakInterval),
+                   MakeTimeChecker ())
   ;
   return tid;
 }
@@ -128,6 +119,9 @@
 {
   NS_LOG_FUNCTION (this);
 
+  if (m_bucketLeakEvent.IsRunning ())
+    m_bucketLeakEvent.Cancel ();
+  
   for (CcnxFaceList::iterator i = m_faces.begin (); i != m_faces.end (); ++i)
     {
       *i = 0;
@@ -171,7 +165,7 @@
   face->RegisterProtocolHandler (MakeCallback (&CcnxL3Protocol::Receive, this));
 
   m_faces.push_back (face);
-  m_faceCounter ++;
+  m_faceCounter++;
   return face->GetId ();
 }
 
@@ -180,6 +174,27 @@
 {
   // ask face to register in lower-layer stack
   face->RegisterProtocolHandler (MakeNullCallback<void,const Ptr<CcnxFace>&,const Ptr<const Packet>&> ());
+
+  // just to be on a safe side. Do the process in two steps
+  list<CcnxPitEntryContainer::type::iterator> entriesToRemoves; 
+  BOOST_FOREACH (const CcnxPitEntry &pitEntry, *m_pit)
+    {
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind (CcnxPitEntry::RemoveAllReferencesToFace, ll::_1, face));
+
+      // If this face is the only for the associated FIB entry, then FIB entry will be removed soon.
+      // Thus, we have to remove the whole PIT entry
+      if (m_pit->m_fibEntry.size () == 1 &&
+          m_pit->m_fibEntry.m_faces.begin ()->m_face == face)
+        {
+          entriesToRemoves.push_back (m_pit->iterator_to (pitEntry));
+        }
+    }
+  BOOST_FOREACH (CcnxPitEntryContainer::type::iterator entry, entriesToRemoves)
+    {
+      m_pit->erase (entry);
+    }
+
   CcnxFaceList::iterator face_it = find (m_faces.begin(), m_faces.end(), face);
   NS_ASSERT_MSG (face_it != m_faces.end (), "Attempt to remove face that doesn't exist");
   m_faces.erase (face_it);
@@ -216,24 +231,6 @@
   return m_faces.size ();
 }
 
-void
-CcnxL3Protocol::TransmittedDataTrace (Ptr<Packet> packet,
-                                      ContentObjectSource type,
-                                      Ptr<Ccnx> ccnx, Ptr<const CcnxFace> face)
-{
-  // a "small" inefficiency for logging purposes
-  Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
-  static CcnxContentObjectTail tail;
-  packet->RemoveHeader (*header);
-  packet->RemoveTrailer (tail);
-      
-  m_transmittedDataTrace (header, packet/*payload*/, type, ccnx, face);
-  
-  packet->AddHeader (*header);
-  packet->AddTrailer (tail);
-}
-
-
 // Callback from lower layer
 void 
 CcnxL3Protocol::Receive (const Ptr<CcnxFace> &face, const Ptr<const Packet> &p)
@@ -333,7 +330,7 @@
   //               {
   //                 header->SetNonce(it->m_nonce);
   //                 header->SetNack(true);
-  //                 SendInterest(face.m_face, header, packet->Copy());
+  //                 face.m_face->SendWithoutLimit (packet->Copy());
   //               }
   //           }
   //       }
@@ -376,7 +373,7 @@
       Ptr<Packet> packet = Create<Packet> ();
       packet->AddHeader (*header);
 
-      SendInterest (incomingFace, header, packet);
+      incomingFace->SendWithoutLimit (packet);
       
       // //Trace duplicate interest  
       // m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST, m_node->GetObject<Ccnx> (), incomingFace);
@@ -384,19 +381,17 @@
     }
 
   Ptr<Packet> contentObject;
-  Ptr<const CcnxContentObjectHeader> contentObjectHeader;
+  Ptr<const CcnxContentObjectHeader> contentObjectHeader; // unused for now
   tie (contentObject, contentObjectHeader) = m_contentStore->Lookup (header);
   if (contentObject != 0)
     {
-      // NS_ASSERT_MSG (pitEntry.m_incoming.size () == 0,
-      //                "Something strange. Data is cached, but size of incoming interests is not zero...");
       NS_ASSERT (contentObjectHeader != 0);
       
       NS_LOG_LOGIC("Found in cache");
         
       // TransmittedDataTrace (contentObject, CACHED,
       //                       m_node->GetObject<Ccnx> (), incomingFace);
-      SendContentObject (incomingFace, contentObjectHeader, contentObject);
+      incomingFace->SendWithoutLimit (contentObject);
 
       // Set pruning timout on PIT entry (instead of deleting the record)
       m_pit->modify (m_pit->iterator_to (pitEntry),
@@ -454,9 +449,7 @@
   NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
   
   bool propagated = m_forwardingStrategy->
-    PropagateInterest (pitEntry, incomingFace, header, packet,
-                       MakeCallback (&CcnxL3Protocol::SendInterest, this)
-                       );
+    PropagateInterest (pitEntry, incomingFace, header, packet);
 
   // ForwardingStrategy will try its best to forward packet to at least one interface.
   // If no interests was propagated, then there is not other option for forwarding or
@@ -469,7 +462,7 @@
 
       BOOST_FOREACH (const CcnxPitEntryIncomingFace &incoming, pitEntry.m_incoming)
         {
-          SendInterest (incoming.m_face, header, packet->Copy ());
+          incoming.m_face->SendWithoutLimit (packet->Copy ());
 
           // m_droppedInterestsTrace (header, DROP_CONGESTION,
           //                          m_node->GetObject<Ccnx> (), incomingFace);
@@ -537,7 +530,7 @@
       BOOST_FOREACH (const CcnxPitEntryIncomingFace &incoming, pitEntry.m_incoming)
         {
           if (incoming.m_face != incomingFace)
-            SendContentObject (incoming.m_face, header, packet->Copy ());
+            incoming.m_face->SendWithoutLimit (packet->Copy ());
 
           // successfull forwarded data trace
         }
@@ -562,59 +555,33 @@
 }
 
 void
-CcnxL3Protocol::SendInterest (const Ptr<CcnxFace> &face,
-                              const Ptr<const CcnxInterestHeader> &header,
-                              const Ptr<Packet> &packet)
+CcnxL3Protocol::SetBucketLeakInterval (Time interval)
 {
-  NS_LOG_FUNCTION (this << "packet: " << &packet << ", face: "<< &face);
-  NS_ASSERT_MSG (face != 0, "Face should never be NULL");
+  m_bucketLeakInterval = interval;
+  
+  if (m_bucketLeakEvent.IsRunning ())
+    m_bucketLeakEvent.Cancel ();
 
-  if (face->IsUp ())
-    {
-      NS_LOG_LOGIC ("Sending via face " << &face); //
-      // m_transmittedInterestsTrace (header, m_node->GetObject<Ccnx> (), face);
-      face->Send (packet);
-    }
-  else
-    {
-      NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << &face);
-      // m_droppedInterestsTrace (header, INTERFACE_DOWN, m_node->GetObject<Ccnx> (), face);
-    }
+  m_bucketLeakEvent = Simulator::Schedule (m_bucketLeakInterval,
+                                           &CcnxL3Protocol::LeakBuckets, this);
 }
 
-void
-CcnxL3Protocol::SendContentObject (const Ptr<CcnxFace> &face,
-                                   const Ptr<const CcnxContentObjectHeader> &header,
-                                   const Ptr<Packet> &packet)
+Time
+CcnxL3Protocol::GetBucketLeakInterval () const
 {
-  NS_LOG_FUNCTION (this << "packet: " << &packet << ", face: "<< &face);
-  NS_ASSERT_MSG (face != 0, "Face should never be NULL");
-
-  if (face->IsUp ())
-    {
-      NS_LOG_LOGIC ("Sending via face " << &face); //
-      // m_txTrace (packet, m_node->GetObject<Ccnx> (), face);
-      face->Send (packet);
-    }
-  else
-    {
-      NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << &face);
-      // m_dropTrace (packet, INTERFACE_DOWN, m_node->GetObject<Ccnx> (), face);
-    }
+  return m_bucketLeakInterval;
 }
 
-Ptr<CcnxPit>
-CcnxL3Protocol::GetPit()
+void 
+CcnxPit::LeakBuckets ()
 {
-    return m_pit;
+  BOOST_FOREACH (const Ptr<CcnxFace> &face, m_faces)
+    {
+      face->LeakBucket (m_bucketLeakInterval);
+    }
+
+  m_bucketLeakEvent = Simulator::Schedule (m_bucketLeakInterval,
+                                           &CcnxL3Protocol::LeakBuckets, this);
 }
 
-// void
-// CcnxL3Protocol::ScheduleLeakage()
-// {
-//     m_pit->LeakBuckets();
-//     Time interval = MilliSeconds (NDN_INTEREST_RESET_PERIOD);
-    
-//     Simulator::Schedule (interval, &CcnxL3Protocol::ScheduleLeakage, this);
-// }
 } //namespace ns3
diff --git a/model/ccnx-l3-protocol.h b/model/ccnx-l3-protocol.h
index c470959..272a0be 100644
--- a/model/ccnx-l3-protocol.h
+++ b/model/ccnx-l3-protocol.h
@@ -127,13 +127,12 @@
   void SetForwardingStrategy (Ptr<CcnxForwardingStrategy> forwardingStrategy);
   Ptr<CcnxForwardingStrategy> GetForwardingStrategy () const;
 
-  virtual void SendInterest (const Ptr<CcnxFace> &face,
-                             const Ptr<const CcnxInterestHeader> &header,
-                             const Ptr<Packet> &packet);
-  virtual void SendContentObject (const Ptr<CcnxFace> &face,
-                                  const Ptr<const CcnxContentObjectHeader> &header,
-                                  const Ptr<Packet> &packet);
-  virtual void Receive (const Ptr<CcnxFace> &face, const Ptr<const Packet> &p);
+  // virtual void SendInterest (const Ptr<CcnxFace> &face,
+  //                            const Ptr<const CcnxInterestHeader> &header,
+  //                            const Ptr<Packet> &packet);
+  // virtual void SendContentObject (const Ptr<CcnxFace> &face,
+  //                                 const Ptr<const CcnxContentObjectHeader> &header,
+  //                                 const Ptr<Packet> &packet);
 
   virtual uint32_t
   AddFace (const Ptr<CcnxFace> &face);
@@ -153,7 +152,10 @@
   Ptr<CcnxPit> GetPit();
   
   // void ScheduleLeakage();
-protected:
+private:
+  void
+  Receive (const Ptr<CcnxFace> &face, const Ptr<const Packet> &p);
+
   /**
    * \brief Actual processing of incoming CCNx interests. Note, interests do not have payload
    * 
@@ -162,7 +164,7 @@
    * @param header  deserialized Interest header
    * @param packet  original packet
    */
-  virtual void
+  void
   OnInterest (const Ptr<CcnxFace> &face,
               Ptr<CcnxInterestHeader> &header,
               const Ptr<const Packet> &p);
@@ -175,7 +177,7 @@
    * @param header  deserialized Interest header
    * @param packet  original packet
    */
-  virtual void
+  void
   OnNack (const Ptr<CcnxFace> &face,
           Ptr<CcnxInterestHeader> &header,
           const Ptr<const Packet> &p);
@@ -189,7 +191,7 @@
    * @param payload data packet payload
    * @param packet  original packet
    */
-  virtual void
+  void
   OnData (const Ptr<CcnxFace> &face,
           Ptr<CcnxContentObjectHeader> &header,
           Ptr<Packet> &payload,
@@ -208,14 +210,17 @@
   CcnxL3Protocol(const CcnxL3Protocol &); ///< copy constructor is disabled
   CcnxL3Protocol &operator = (const CcnxL3Protocol &); ///< copy operator is disabled
 
-  /**
-   * \brief A helper function
-   */
-  void TransmittedDataTrace (Ptr<Packet>,
-                             ContentObjectSource,
-                             Ptr<Ccnx>, Ptr<const CcnxFace>);
+  /// \brief Set buckets leak interval
+  void
+  SetBucketLeakInterval (Time interval);
+
+  /// \brief Get buckets leak interval
+  Time
+  GetBucketLeakInterval () const;
   
-  
+  /// \brief Periodically generate pre-calculated number of tokens (leak buckets)
+  void LeakBuckets( );
+
 private:
   uint32_t m_faceCounter; ///< \brief counter of faces. Increased every time a new face is added to the stack
   typedef std::vector<Ptr<CcnxFace> > CcnxFaceList;
@@ -228,32 +233,29 @@
   Ptr<CcnxPit> m_pit; ///< \brief PIT (pending interest table)
   Ptr<CcnxFib> m_fib; ///< \brief FIB  
   Ptr<CcnxContentStore> m_contentStore; ///< \brief Content store (for caching purposes only)
-  
-  TracedCallback<Ptr<const CcnxInterestHeader>,
-                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedInterestsTrace;
-  TracedCallback<Ptr<const CcnxInterestHeader>,
-                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedInterestsTrace;
-  TracedCallback<Ptr<const CcnxInterestHeader>,
-                 DropReason,
-                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppedInterestsTrace;
 
-  TracedCallback<Ptr<const CcnxContentObjectHeader>,
-                 Ptr<const Packet>,/*payload*/
-                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedDataTrace;
-  TracedCallback<Ptr<const CcnxContentObjectHeader>,
-                 Ptr<const Packet>,/*payload*/
-                 ContentObjectSource,
-                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedDataTrace;
-  TracedCallback<Ptr<const CcnxContentObjectHeader>,
-                 Ptr<const Packet>,/*payload*/
-                 DropReason,
-                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppedDataTrace;
+  Time    m_bucketLeakInterval;
+  EventId m_bucketLeakEvent;
   
-  /**
-   * \brief Trace of dropped packets, including reason and all headers
-   * \internal
-   */
-  // TracedCallback<Ptr<const Packet>, DropReason, Ptr<const Ccnx>, Ptr<const CcnxFace> > m_dropTrace;
+  // TracedCallback<Ptr<const CcnxInterestHeader>,
+  //                Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedInterestsTrace;
+  // TracedCallback<Ptr<const CcnxInterestHeader>,
+  //                Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedInterestsTrace;
+  // TracedCallback<Ptr<const CcnxInterestHeader>,
+  //                DropReason,
+  //                Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppedInterestsTrace;
+
+  // TracedCallback<Ptr<const CcnxContentObjectHeader>,
+  //                Ptr<const Packet>,/*payload*/
+  //                Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedDataTrace;
+  // TracedCallback<Ptr<const CcnxContentObjectHeader>,
+  //                Ptr<const Packet>,/*payload*/
+  //                ContentObjectSource,
+  //                Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedDataTrace;
+  // TracedCallback<Ptr<const CcnxContentObjectHeader>,
+  //                Ptr<const Packet>,/*payload*/
+  //                DropReason,
+  //                Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppedDataTrace;
 };
   
 } // Namespace ns3
diff --git a/model/ccnx-local-face.cc b/model/ccnx-local-face.cc
index fc4dd11..4a7c777 100644
--- a/model/ccnx-local-face.cc
+++ b/model/ccnx-local-face.cc
@@ -25,7 +25,6 @@
 #include "ns3/log.h"
 #include "ns3/packet.h"
 #include "ns3/node.h"
-#include "ns3/pointer.h"
 #include "ns3/assert.h"
 
 #include "ns3/ccnx-header-helper.h"
@@ -37,23 +36,13 @@
 namespace ns3 
 {
 
-// NS_OBJECT_ENSURE_REGISTERED (CcnxLocalFace);
-
-// TypeId 
-// CcnxLocalFace::GetTypeId (void)
-// {
-//   static TypeId tid = TypeId ("ns3::CcnxLocalFace")
-//     .SetGroupName ("Ccnx")
-//     .SetParent<CcnxFace> ()
-//   ;
-//   return tid;
-// }
-
-CcnxLocalFace::CcnxLocalFace () 
-  : m_onInterest (0)
-  , m_onContentObject (0)
+CcnxLocalFace::CcnxLocalFace (Ptr<CcnxApp> app)
+  : CcnxFace (app->GetObject<Node> ())
+  , m_app (app)
 {
-  NS_LOG_FUNCTION (this);
+  NS_LOG_FUNCTION (this << app);
+  
+  NS_ASSERT (app != 0);
 }
 
 CcnxLocalFace::~CcnxLocalFace ()
@@ -64,30 +53,17 @@
 void
 CcnxLocalFace::RegisterProtocolHandler (ProtocolHandler handler)
 {
-  m_protocolHandler = handler;
-}
+  NS_LOG_FUNCTION (this << handler);
 
-void
-CcnxLocalFace::SetInterestHandler (InterestHandler onInterest)
-{
-  m_onInterest = onInterest;
-}
+  CcnxFace::RegisterProtocolHandler (handler);
 
-void
-CcnxLocalFace::SetContentObjectHandler (ContentObjectHandler onContentObject)
-{
-  m_onContentObject = onContentObject;
+  app->RegisterProtocolHandler (MakeCallback (&CcnxFace::Receive, this));
 }
     
 void
-CcnxLocalFace::Send (Ptr<Packet> p)
+CcnxLocalFace::SendImpl (Ptr<Packet> p)
 {
-  NS_LOG_FUNCTION("Local face send");
-  NS_LOG_FUNCTION (*p);
-  if (!IsUp ())
-    {
-      return;
-    }
+  NS_LOG_FUNCTION (this << p);
 
   try
     {
@@ -99,7 +75,7 @@
             {
               Ptr<CcnxInterestHeader> header = Create<CcnxInterestHeader> ();
               p->RemoveHeader (*header);
-              m_onInterest (header);
+              app->OnInterest (header);
             }
           break;
         case CcnxHeaderHelper::CONTENT_OBJECT:
@@ -109,7 +85,7 @@
               Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
               p->RemoveHeader (*header);
               p->RemoveTrailer (tail);
-              m_onContentObject (header, p/*payload*/);
+              app->OnContentObject (header, p/*payload*/);
             }
           break;
         }
@@ -120,13 +96,6 @@
     }
 }
 
-// propagate interest down to ccnx stack
-void
-CcnxLocalFace::ReceiveFromApplication (Ptr<Packet> p)
-{
-  m_protocolHandler (Ptr<CcnxFace>(this), p);
-}
-
 std::ostream& CcnxLocalFace::Print (std::ostream& os) const
 {
   os << "dev=local(" << GetId() << ")";
diff --git a/model/ccnx-local-face.h b/model/ccnx-local-face.h
index 664130c..a7705ed 100644
--- a/model/ccnx-local-face.h
+++ b/model/ccnx-local-face.h
@@ -44,61 +44,32 @@
 class CcnxLocalFace  : public CcnxFace
 {
 public:
-  typedef Callback<void,const Ptr<const CcnxInterestHeader> &> InterestHandler;
-  typedef Callback<void,const Ptr<const CcnxContentObjectHeader> &,
-                        const Ptr<const Packet> &> ContentObjectHandler;
-
   /**
    * \brief Default constructor
    */
-  CcnxLocalFace ();
+  CcnxLocalFace (Ptr<CcnxApp> app);
   virtual ~CcnxLocalFace();
   
   ////////////////////////////////////////////////////////////////////
   // methods overloaded from CcnxFace
-
-  /**
-   * \brief This method should be called to establish link with lower layers
-   */
   virtual void
   RegisterProtocolHandler (ProtocolHandler handler);
 
-  /**
-   * \brief This method will be called by lower layers to send data to *application*
-   */
+protected:
   virtual void
-  Send (Ptr<Packet> p);
-    
+  SendImpl (Ptr<Packet> p);
+
+public:
   virtual std::ostream&
   Print (std::ostream &os) const;
   ////////////////////////////////////////////////////////////////////
-
-   /**
-   * \brief This method will be called by higher layers to send data to *ccnx stack*
-   */
-  void ReceiveFromApplication (Ptr<Packet> p);
-
-  /**
-   * \brief Set callback to application
-   *
-   * \param onInterest InterestHandler to be called when interest arrives on the face. Will be disabled if 0
-   */
-  void SetInterestHandler (InterestHandler onInterest);
-
-    /**
-   * \brief Set callback to application
-   *
-   * \param onContentObject ContentObjectHandler to be called when data arrives. Will be disabled if 0
-   */
-  void SetContentObjectHandler (ContentObjectHandler onContentObject);
  
 private:
   CcnxLocalFace (const CcnxLocalFace &); ///< \brief Disabled copy constructor
   CcnxLocalFace& operator= (const CcnxLocalFace &); ///< \brief Disabled copy operator
 
 private:
-  InterestHandler m_onInterest;
-  ContentObjectHandler m_onContentObject;
+  Ptr<CcnxApp> m_application;
 };
 
 std::ostream& operator<< (std::ostream& os, const CcnxLocalFace &localFace);
diff --git a/model/ccnx-name-components.cc b/model/ccnx-name-components.cc
index 438e179..b551733 100644
--- a/model/ccnx-name-components.cc
+++ b/model/ccnx-name-components.cc
@@ -69,25 +69,6 @@
     
   return subComponents;
 }
-  
-// const ccn_charbuf*
-// Components::GetName () const
-// {
-//   return m_value;
-// }
-
-CcnxNameComponents&
-CcnxNameComponents::operator () (const string &s)
-{
-  // ccn_name_append_str (m_value,s.c_str());
-  m_prefix.push_back (s);
-  return *this;
-}
-
-// Components::operator const unsigned char* ()
-// {
-//   return m_value->buf;
-// }
 
 void
 CcnxNameComponents::Print (std::ostream &os) const
diff --git a/model/ccnx-name-components.h b/model/ccnx-name-components.h
index ea64635..5dafcfc 100644
--- a/model/ccnx-name-components.h
+++ b/model/ccnx-name-components.h
@@ -43,12 +43,14 @@
   CcnxNameComponents ();
   // CcnxNameComponents (const std::string &s);
   CcnxNameComponents (const std::list<boost::reference_wrapper<const std::string> > &components);
-  
+
+  template<class T>
   inline void
-  Add (const std::string &s);
-       
-  CcnxNameComponents&
-  operator () (const std::string &s);
+  Add (const T &value);
+  
+  template<class T>
+  inline CcnxNameComponents&
+  operator () (const T &value);
 
   const std::list<std::string> &
   GetComponents () const;
@@ -108,11 +110,29 @@
 {
   return m_prefix.size ();
 }
-  
-void
-CcnxNameComponents::Add (const std::string &s)
+
+template<class T>
+CcnxNameComponents&
+CcnxNameComponents::operator () (const T &value)
 {
-  (*this) (s);
+  Add (value);
+  return *this;
+}
+
+template<class T>
+void
+CcnxNameComponents::Add (const T &value)
+{
+  std::ostringstream os;
+  os << value;
+  m_prefix.push_back (os.str ());
+}
+
+template<class T=std::string>
+void
+CcnxNameComponents::Add (const T &string)
+{
+  m_prefix.push_back (string);
 }
 
 bool
diff --git a/model/ccnx-net-device-face.cc b/model/ccnx-net-device-face.cc
index 12cb272..72aa14a 100644
--- a/model/ccnx-net-device-face.cc
+++ b/model/ccnx-net-device-face.cc
@@ -36,11 +36,13 @@
  * By default, Ccnx face are created in the "down" state.  Before
  * becoming useable, the user must invoke SetUp on the face
  */
-CcnxNetDeviceFace::CcnxNetDeviceFace (const Ptr<NetDevice> &netDevice) 
+CcnxNetDeviceFace::CcnxNetDeviceFace (Ptr<Node> node, const Ptr<NetDevice> &netDevice)
+  : CcnxFace (node)
+  , m_netDevice (netDevice)
 {
-  NS_LOG_FUNCTION (this);
+  NS_LOG_FUNCTION (this << netDevice);
 
-  m_netDevice = netDevice;
+  NS_ASSERT_MSG (m_netDevice != 0, "CcnxNetDeviceFace needs to be assigned a valid NetDevice");
 }
 
 CcnxNetDeviceFace::~CcnxNetDeviceFace ()
@@ -66,11 +68,10 @@
 void
 CcnxNetDeviceFace::RegisterProtocolHandler (ProtocolHandler handler)
 {
-  NS_LOG_FUNCTION(this);
-  NS_ASSERT_MSG (m_netDevice != 0, "CcnxNetDeviceFace needs to be assigned NetDevice first");
-  
-  m_protocolHandler = handler;
+  NS_LOG_FUNCTION (this << handler);
 
+  CcnxFace::RegisterProtocolHandler (handler);
+  
   m_node->RegisterProtocolHandler (MakeCallback (&CcnxNetDeviceFace::ReceiveFromNetDevice, this),
                                    CcnxL3Protocol::ETHERNET_FRAME_TYPE, m_netDevice, true/*promiscuous mode*/);
 }
@@ -78,17 +79,13 @@
 void
 CcnxNetDeviceFace::Send (Ptr<Packet> packet)
 {
+  NS_LOG_FUNCTION (this << packet);
+  
   NS_ASSERT_MSG (packet->GetSize () <= m_netDevice->GetMtu (), 
                  "Packet size " << packet->GetSize () << " exceeds device MTU "
                  << m_netDevice->GetMtu ()
                  << " for Ccnx; fragmentation not supported");
 
-  NS_LOG_FUNCTION (*packet);
-  if (!IsUp ())
-    {
-      return;
-    }
-
   m_netDevice->Send (packet, m_netDevice->GetBroadcast (), 
                      CcnxL3Protocol::ETHERNET_FRAME_TYPE);
 }
@@ -102,7 +99,7 @@
                                          const Address &to,
                                          NetDevice::PacketType packetType)
 {
-  m_protocolHandler (Ptr<CcnxFace>(this), p);
+  Receive (p);
 }
 
 
diff --git a/model/ccnx-net-device-face.h b/model/ccnx-net-device-face.h
index e6fbc12..482d5d3 100644
--- a/model/ccnx-net-device-face.h
+++ b/model/ccnx-net-device-face.h
@@ -45,31 +45,26 @@
 class CcnxNetDeviceFace  : public CcnxFace
 {
 public:
-  // /**
-  //  * \brief Interface ID
-  //  *
-  //  * \return interface ID
-  //  */
-  // static TypeId GetTypeId (void);
-
   /**
    * \brief Constructor
    *
    * \param netDevice a smart pointer to NetDevice object to which
    * this face will be associate
    */
-  CcnxNetDeviceFace (const Ptr<NetDevice> &netDevice);
+  CcnxNetDeviceFace (Ptr<Node> node, const Ptr<NetDevice> &netDevice);
   virtual ~CcnxNetDeviceFace();
 
   ////////////////////////////////////////////////////////////////////
   // methods overloaded from CcnxFace
-  
   virtual void
   RegisterProtocolHandler (ProtocolHandler handler);
 
+protected:
+  // also from CcnxFace
   virtual void
-  Send (Ptr<Packet> p);
-  
+  SendImpl (Ptr<Packet> p);
+
+public:
   virtual std::ostream&
   Print (std::ostream &os) const;
   ////////////////////////////////////////////////////////////////////
diff --git a/model/ccnx-pit-entry.cc b/model/ccnx-pit-entry.cc
index 7b8f489..cd6d854 100644
--- a/model/ccnx-pit-entry.cc
+++ b/model/ccnx-pit-entry.cc
@@ -66,27 +66,20 @@
   return ret.first;
 }
 
+void
+CcnxPitEntry::RemoveAllReferencesToFace (Ptr<CcnxFace> face)
+{
+  CcnxPitEntryIncomingFaceContainer::type::iterator incoming =
+    m_incoming.find (face);
 
-// void
-// CcnxPitEntry::UpdateFibStatus::operator() (CcnxPitEntry &entry)
-// {
-//   NS_ASSERT_MSG (false, "Broken");
-//   m_fib->modify (m_fib->iterator_to (entry.m_fibEntry),
-//                  CcnxFibEntry::UpdateStatus (m_face, m_status));
-// }
+  if (incoming != m_incoming.end ())
+    m_incoming.erase (incoming);
 
-// void
-// CcnxPitEntry::EstimateRttAndRemoveFace::operator() (CcnxPitEntry &entry)
-// {
-//   // similar to Karn's Algorithm, we don't use RTT measurements for retx packets
-//   if (m_outFace->m_retxNum>0)
-//     return;
+  CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+    m_outgoing.find (face);
 
-//   m_fib->modify (m_fib->iterator_to (entry.m_fibEntry),
-//                 CcnxFibEntry::UpdateFaceRtt (m_outFace->m_face,
-//                                              Simulator::Now() - m_outFace->m_sendTime));
-
-//   entry.m_outgoing.erase (m_outFace);
-// }
+  if (outgoing != m_outgoing.end ())
+    m_outgoing.erase (outgoing);
+}
 
 }  
diff --git a/model/ccnx-pit-entry.h b/model/ccnx-pit-entry.h
index ac1b277..52e7921 100644
--- a/model/ccnx-pit-entry.h
+++ b/model/ccnx-pit-entry.h
@@ -108,36 +108,84 @@
   // // Get number of outgoing interests that we're expecting data from
   // inline size_t numberOfPromisingInterests( ) const; 
 
-  const CcnxNameComponents &
-  GetPrefix () const;
+  // const CcnxNameComponents &
+  // GetPrefix () const;
 
+  /**
+   * @brief Get current expiration time of the record
+   *
+   * @returns current expiration time of the record
+   */
   const Time &
   GetExpireTime () const
   { return m_expireTime; }
 
+  /**
+   * @brief Set expiration time on record as `expireTime` (absolute time)
+   *
+   * @param expireTime absolute simulation time of when the record should expire
+   */
   void
   SetExpireTime (const Time &expireTime)
   {
     m_expireTime = expireTime;
   }
   
+  /**
+   * @brief Check if nonce `nonce` for the same prefix has already been seen
+   *
+   * @param nonce Nonce to check
+   */
   bool
   IsNonceSeen (uint32_t nonce) const
   { return m_seenNonces.find (nonce) != m_seenNonces.end (); }
 
+  /**
+   * @brief Add `nonce` to the list of seen nonces
+   *
+   * @param nonce nonce to add to the list of seen nonces
+   *
+   * All nonces are stored for the lifetime of the PIT entry
+   */
   void
   AddSeenNonce (uint32_t nonce)
   { m_seenNonces.insert (nonce); }
 
+  /**
+   * @brief Add `face` to the list of incoming faces
+   *
+   * @param face Face to add to the list of incoming faces
+   * @returns iterator to the added entry
+   */
   CcnxPitEntryIncomingFaceContainer::type::iterator
   AddIncoming (Ptr<CcnxFace> face);
 
+  /**
+   * @brief Clear all incoming faces either after all of them were satisfied or NACKed
+   */
   void
   ClearIncoming ()
   { m_incoming.clear (); }
 
+  /**
+   * @brief Add `face` to the list of outgoing faces
+   *
+   * @param face Face to add to the list of outgoing faces
+   * @returns iterator to the added entry
+   */
   CcnxPitEntryOutgoingFaceContainer::type::iterator
   AddOutgoing (Ptr<CcnxFace> face);
+
+  /**
+   * @brief Remove all references to face.
+   * 
+   * This method should be called before face is completely removed from the stack.
+   * Face is removed from the lists of incoming and outgoing faces
+   */
+  void
+  RemoveAllReferencesToFace (Ptr<CcnxFace> face);
+
+protected:
   
 private:
   friend std::ostream& operator<< (std::ostream& os, const CcnxPitEntry &entry);
diff --git a/model/ccnx-pit.cc b/model/ccnx-pit.cc
index 85b4ecb..63e1db8 100644
--- a/model/ccnx-pit.cc
+++ b/model/ccnx-pit.cc
@@ -48,7 +48,7 @@
     .AddConstructor<CcnxPit> ()
     .AddAttribute ("CleanupTimeout",
                    "Timeout defining how frequent RIT should be cleaned up",
-                   TimeValue (Seconds (1)),
+                   StringValue ("1s"),
                    MakeTimeAccessor (&CcnxPit::GetCleanupTimeout, &CcnxPit::SetCleanupTimeout),
                    MakeTimeChecker ())
     .AddAttribute ("PitEntryPruningTimout",
@@ -72,10 +72,7 @@
 
 CcnxPit::~CcnxPit ()
 {
-  if (m_cleanupEvent.IsRunning ())
-    m_cleanupEvent.Cancel (); // cancel any scheduled cleanup events
-
-  clear ();
+  DoDispose ();
 }
 
 void 
@@ -87,7 +84,10 @@
 CcnxPit::DoDispose ()
 {
   if (m_cleanupEvent.IsRunning ())
-    m_cleanupEvent.Cancel (); // cancel any scheduled cleanup events
+    m_cleanupEvent.Cancel ();
+
+  if (m_PitBucketLeakEvent.IsRunning ())
+    m_PitBucketLeakEvent.Cancel ();
 
   clear ();
 }
@@ -116,11 +116,11 @@
   Time now = Simulator::Now ();
 
   uint32_t count = 0;
-  while( !empty() )
+  while (!empty ())
     {
-      if( get<i_timestamp> ().front ().GetExpireTime () <= now ) // is the record stale?
+      if (get<i_timestamp> ().front ().GetExpireTime () <= now) // is the record stale?
         {
-          get<i_timestamp> ().pop_front( );
+          get<i_timestamp> ().pop_front ();
           count ++;
         }
       else
@@ -140,26 +140,6 @@
   m_fib = fib;
 }
 
-bool
-CcnxPit::TryAddOutgoing (const CcnxPitEntry &pitEntry, Ptr<CcnxFace> face)
-{
-  NS_LOG_FUNCTION ("Face has " << m_bucketsPerFace[face->GetId()] <<
-               " packets with max allowance " << maxBucketsPerFace[face->GetId()]); 
-    
-  if (m_bucketsPerFace[face->GetId()]+1.0 >= maxBucketsPerFace[face->GetId()])
-    {
-      NS_LOG_INFO("************ LIMIT **************");
-      return false;
-    }
-    
-  m_bucketsPerFace[face->GetId()] = m_bucketsPerFace[face->GetId()] + 1.0;
-
-  modify (iterator_to (pitEntry),
-          bind(&CcnxPitEntry::AddOutgoing, lambda::_1, face));
-          
-  return true;
-}
-
 const CcnxPitEntry&
 CcnxPit::Lookup (const CcnxContentObjectHeader &header) const
 {
@@ -217,24 +197,4 @@
   return make_tuple (cref(*entry), isNew, isDuplicate);
 }
 
-///////////////////////////////////////////////////////////////////////////////////////////
-
-void 
-CcnxPit::LeakBuckets ()
-{
-  for (PitBucketIterator it = m_bucketsPerFace.begin(); 
-       it != m_bucketsPerFace.end();
-       it++)
-    {
-      it->second = std::max (0.0, it->second - leakSize[it->first]);
-    }
-}
-    
-void 
-CcnxPit::LeakBucket (Ptr<CcnxFace> face, int amount)
-{
-  m_bucketsPerFace[face->GetId()] = std::max (0.0, m_bucketsPerFace[face->GetId()] - amount);
-}
-
-
 } // namespace ns3
diff --git a/model/ccnx-pit.h b/model/ccnx-pit.h
index 7c8785c..0d1132e 100644
--- a/model/ccnx-pit.h
+++ b/model/ccnx-pit.h
@@ -92,9 +92,8 @@
 // typedef std::map<int,int> PitCounter;
 // typedef std::map<int,int>::iterator PitCounterIterator;
 
- typedef std::map<int,double> PitBucket;
- typedef std::map<int,double>::iterator PitBucketIterator;
-
+typedef std::map<int,double> PitBucket;
+typedef std::map<int,double>::iterator PitBucketIterator;
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
@@ -122,17 +121,6 @@
    * \brief Destructor
    */
   virtual ~CcnxPit ();
-
-  /**
-   * @brief Try to add outgoing entry to PIT entry.
-   * Will fail if there were too much (other) interests forwarded to this face
-   *
-   * @param pitEntry PIT entry
-   * @param face     face
-   * @returns false if rate limit is imposed and no outgoing entry was created. True otherwise
-   */
-  bool
-  TryAddOutgoing(const CcnxPitEntry &pitEntry, Ptr<CcnxFace> face);
   
   /**
    * \brief Find corresponding PIT entry for the given content name
@@ -155,21 +143,25 @@
   boost::tuple<const CcnxPitEntry&, bool, bool>
   Lookup (const CcnxInterestHeader &header);
   
-  // remove a PIT entry
-  //void erase (const string &contentName);
-	
-  // Reset pending state in outgoing interests
-  // void resetPendingState( PitEntry &pe );
+  Time GetPitEntryPruningTimeout () const
+  {
+    return m_PitEntryPruningTimout;
+  }
+  
+  /**
+   * \brief Set FIB table
+   */
+  void SetFib (Ptr<CcnxFib> fib);
 
-  //	// Check if there are any interfaces that we haven't sent data to yet
-  //	bool areFreeInterfaces( PitEntry &pe, int interface );
+protected:
+  // inherited from Object class                                                                                                                                                        
+  virtual void NotifyNewAggregate ();
+  virtual void DoDispose ();
+  	
+private:
+  /** \brief Remove expired records from PIT */
+  void CleanExpired ();
 
-  // Periodically generate pre-calculated number of tokens (leak buckets)
-  void LeakBuckets( );
-	
-  // Selectively leak a bucket
-  void LeakBucket (Ptr<CcnxFace> face, int amount);
-	
   /**
    * \brief Set cleanup timeout
    *
@@ -186,40 +178,26 @@
    */
   Time GetCleanupTimeout () const;
 
-  Time GetPitEntryPruningTimeout () const
-  {
-    return m_PitEntryPruningTimout;
-  }
-  
-  /**
-   * \brief Set FIB table
-   */
-  void SetFib (Ptr<CcnxFib> fib);
-
-protected:
-  // inherited from Object class                                                                                                                                                        
-  virtual void NotifyNewAggregate ();
-  virtual void DoDispose ();
-
-public:
-   PitBucket				 maxBucketsPerFace; // maximum number of buckets. Automatically computed based on link capacity
-  // // averaging over 1 second (bandwidth * 1second)
-   PitBucket				 leakSize;				 // size of a periodic bucket leak
-	
-private:
-  /** \brief Remove expired records from PIT */
-  void CleanExpired ();
-
   friend std::ostream& operator<< (std::ostream& os, const CcnxPit &fib);
   
 private:
   Time    m_cleanupTimeout; ///< \brief Configurable timeout of how often cleanup events are working
   EventId m_cleanupEvent;   ///< \brief Cleanup event
+
+  // configuration variables. Check implementation of GetTypeId for more details
   Time    m_PitEntryPruningTimout;
-  Time    m_PitEntryDefaultLifetime; 
+  Time    m_PitEntryDefaultLifetime;
 
   Ptr<CcnxFib> m_fib; ///< \brief Link to FIB table
-  PitBucket    m_bucketsPerFace; ///< \brief pending interface counter per face
+  // PitBucket    m_bucketsPerFace; ///< \brief pending interface counter per face
+
+  // /**
+  //  * \brief maximum number of buckets. Automatically computed based on link capacity
+  //  * averaging over 1 second (bandwidth * 1second)
+  //  */
+  // PitBucket    maxBucketsPerFace;
+  
+  // PitBucket    leakSize; ///< size of a periodic bucket leak
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/model/ccnx.h b/model/ccnx.h
index 4d6f636..38c2f74 100644
--- a/model/ccnx.h
+++ b/model/ccnx.h
@@ -22,7 +22,6 @@
 #define _CCNX_H_
 
 #include "ns3/object.h"
-#include "ns3/socket.h"
 #include "ns3/callback.h"
 
 namespace ns3 {
@@ -80,13 +79,13 @@
 class Ccnx : public Object
 {
 public:
-    enum ForwardingStrategy
+  enum ForwardingStrategy
     { 
-        NDN_FLOODING = 1,
-        NDN_BESTROUTE = 2,
-        NDN_RANKING = 3 
+      NDN_FLOODING = 1,
+      NDN_BESTROUTE = 2,
+      NDN_RANKING = 3 
     };
-    
+
   /**
    * \brief Interface ID
    *
@@ -95,47 +94,47 @@
   static TypeId GetTypeId ();
   virtual ~Ccnx ();
 
-  /**
-   * \brief Send an Interest packet to a specified face
-   *
-   * \param face face where to send this packet
-   * \param header Interest header
-   * \param packet fully prepared CCNx packet to send
-   *
-   * Higher-level layers (forwarding strategy in particular) call this
-   * method to send a packet down the stack to the MAC and PHY layers.
-   */
-  virtual void
-  SendInterest (const Ptr<CcnxFace> &face,
-                const Ptr<const CcnxInterestHeader> &header,
-                const Ptr<Packet> &packet) = 0;
+  // /**
+  //  * \brief Send an Interest packet to a specified face
+  //  *
+  //  * \param face face where to send this packet
+  //  * \param header Interest header
+  //  * \param packet fully prepared CCNx packet to send
+  //  *
+  //  * Higher-level layers (forwarding strategy in particular) call this
+  //  * method to send a packet down the stack to the MAC and PHY layers.
+  //  */
+  // virtual void
+  // SendInterest (const Ptr<CcnxFace> &face,
+  //               const Ptr<const CcnxInterestHeader> &header,
+  //               const Ptr<Packet> &packet) = 0;
 
-  /**
-   * \brief Send a ContentObject packet to a specified face
-   *
-   * \param face face where to send this packet
-   * \param header ContentObject header
-   * \param packet fully prepared CCNx packet to send
-   *
-   * Higher-level layers (forwarding strategy in particular) call this
-   * method to send a packet down the stack to the MAC and PHY layers.
-   */
-  virtual void
-  SendContentObject (const Ptr<CcnxFace> &face,
-                     const Ptr<const CcnxContentObjectHeader> &header,
-                     const Ptr<Packet> &packet) = 0;
+  // /**
+  //  * \brief Send a ContentObject packet to a specified face
+  //  *
+  //  * \param face face where to send this packet
+  //  * \param header ContentObject header
+  //  * \param packet fully prepared CCNx packet to send
+  //  *
+  //  * Higher-level layers (forwarding strategy in particular) call this
+  //  * method to send a packet down the stack to the MAC and PHY layers.
+  //  */
+  // virtual void
+  // SendContentObject (const Ptr<CcnxFace> &face,
+  //                    const Ptr<const CcnxContentObjectHeader> &header,
+  //                    const Ptr<Packet> &packet) = 0;
 
-  /**
-   * \brief Lower layers calls this method after demultiplexing
-   *
-   * Lower-layer-dependent implementation of CcnxFace will do actual work
-   * to set up demultiplexing and call this function as a callback
-   *
-   * \param face face from which packet came from
-   * \param p the packet
-   */
-  virtual void
-  Receive (const Ptr<CcnxFace> &face, const Ptr<const Packet> &p) = 0;
+  // /**
+  //  * \brief Lower layers calls this method after demultiplexing
+  //  *
+  //  * Lower-layer-dependent implementation of CcnxFace will do actual work
+  //  * to set up demultiplexing and call this function as a callback
+  //  *
+  //  * \param face face from which packet came from
+  //  * \param p the packet
+  //  */
+  // virtual void
+  // Receive (const Ptr<CcnxFace> &face, const Ptr<const Packet> &p) = 0;
 
   /**
    * \brief Register a new forwarding strategy to be used by this Ccnx