Merge remote-tracking branch 'git.irl/Ilya'
diff --git a/apps/ccnx-app.cc b/apps/ccnx-app.cc
new file mode 100644
index 0000000..7b9c2b9
--- /dev/null
+++ b/apps/ccnx-app.cc
@@ -0,0 +1,142 @@
+/* -*-  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/assert.h"
+#include "ns3/packet.h"
+
+#include "ns3/ccnx-interest-header.h"
+#include "ns3/ccnx-content-object-header.h"
+#include "ns3/ccnx.h"
+#include "ns3/ccnx-fib.h"
+#include "ns3/ccnx-local-face.h"
+
+NS_LOG_COMPONENT_DEFINE ("CcnxApp");
+
+namespace ns3
+{    
+    
+NS_OBJECT_ENSURE_REGISTERED (CcnxApp);
+    
+TypeId
+CcnxApp::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::CcnxApp")
+    .SetParent<Application> ()
+    .AddConstructor<CcnxApp> ()
+    ;
+  return tid;
+}
+    
+CcnxApp::CcnxApp ()
+  : m_protocolHandler (0)
+  , m_active (false)
+  , m_face (0)
+{
+}
+    
+CcnxApp::~CcnxApp ()
+{
+  StopApplication ();
+}
+
+void
+CcnxApp::DoDispose (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  StopApplication ();
+  Application::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 (GetNode ()->GetObject<Ccnx> () != 0,
+                 "Ccnx stack should be installed on the node " << GetNode ());
+
+  // step 1. Create a face
+  m_face = Create<CcnxLocalFace> (/*Ptr<CcnxApp> (this)*/this);
+    
+  // step 2. Add face to the CCNx stack
+  GetNode ()->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 (GetNode ()->GetObject<Ccnx> () != 0);
+
+  m_active = false;
+
+  // step 1. Disable face
+  m_face->SetUp (false);
+
+  // step 2. Remove face from CCNx stack
+  GetNode ()->GetObject<Ccnx> ()->RemoveFace (m_face);
+  GetNode ()->GetObject<CcnxFib> ()->RemoveFromAll (m_face);
+
+  // step 3. Destroy face
+  NS_ASSERT_MSG (m_face->GetReferenceCount ()==1,
+                 "At this point, nobody else should have referenced this face, but we have "
+                 << m_face->GetReferenceCount () << " references");
+  m_face = 0;
+}
+
+}
diff --git a/apps/ccnx-app.h b/apps/ccnx-app.h
new file mode 100644
index 0000000..f94018f
--- /dev/null
+++ b/apps/ccnx-app.h
@@ -0,0 +1,103 @@
+/* -*-  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;
+class CcnxFace;
+
+/**
+ * @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<const Packet>&> 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; 
+  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 8352212..dc54f92 100644
--- a/apps/ccnx-consumer.cc
+++ b/apps/ccnx-consumer.cc
@@ -20,11 +20,21 @@
 
 #include "ccnx-consumer.h"
 #include "ns3/ptr.h"
-#include "ns3/ccnx-local-face.h"
-#include "ns3/ccnx.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
 #include "ns3/callback.h"
+#include "ns3/string.h"
+#include "ns3/boolean.h"
+#include "ns3/uinteger.h"
+
+#include "ns3/ccnx.h"
+#include "ns3/ccnx-local-face.h"
+#include "ns3/ccnx-interest-header.h"
 #include "ns3/ccnx-content-object-header.h"
 
+#include <boost/ref.hpp>
+
 NS_LOG_COMPONENT_DEFINE ("CcnxConsumer");
 
 namespace ns3
@@ -35,172 +45,121 @@
 TypeId
 CcnxConsumer::GetTypeId (void)
 {
-    static TypeId tid = TypeId ("ns3::CcnxConsumer")
-      .SetParent<Application> ()
-      .AddConstructor<CcnxConsumer> ()
-      .AddAttribute ("OffTime", "Time interval between packets",
-                     TimeValue (Seconds (0.001)),
-                     MakeTimeAccessor (&CcnxConsumer::m_offTime),
-                     MakeTimeChecker ())
-      .AddAttribute ("InterestName","CcnxName of the Interest (use CcnxNameComponents)",
-                     CcnxNameComponentsValue (),
-                     MakeCcnxNameComponentsAccessor (&CcnxConsumer::m_interestName),
-                     MakeCcnxNameComponentsChecker ())
-      .AddAttribute ("LifeTime", "LifeTime fo interest packet",
-                     TimeValue (Seconds (0)),
-                     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 ();
-}
-    
-CcnxConsumer::~CcnxConsumer()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-}
-    
-void
-CcnxConsumer::DoDispose (void)
-{
-    NS_LOG_FUNCTION_NOARGS ();
-        
-    Application::DoDispose ();
+  NS_LOG_FUNCTION_NOARGS ();
 }
     
 // 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 ();
     
-    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);
-        
-    NS_LOG_INFO ("Interest: \n" << interestHeader);
+  //
+  Ptr<CcnxNameComponents> nameWithSequence = Create<CcnxNameComponents> (m_interestName);
+  (*nameWithSequence) (m_seq++);
+  //
 
-    Ptr<Packet> packet = Create<Packet> ();
-    packet->AddHeader (interestHeader);
+  CcnxInterestHeader interestHeader;
+  interestHeader.SetNonce               (m_rand.GetValue ());
+  interestHeader.SetName                (nameWithSequence);
+  interestHeader.SetInterestLifetime    (m_interestLifeTime);
+  interestHeader.SetChildSelector       (m_childSelector);
+  if (m_exclude.size ()>0)
+    {
+      interestHeader.SetExclude             (Create<CcnxNameComponents> (m_exclude));
+    }
+  interestHeader.SetMaxSuffixComponents (m_maxSuffixComponents);
+  interestHeader.SetMinSuffixComponents (m_minSuffixComponents);
         
-    m_face->ReceiveFromApplication (packet);
+  NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (interestHeader);
+
+  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: " << boost::cref(*contentObject));
 }
 
-
-}
+} // namespace ns3
diff --git a/apps/ccnx-consumer.h b/apps/ccnx-consumer.h
index 16dbaf7..792c829 100644
--- a/apps/ccnx-consumer.h
+++ b/apps/ccnx-consumer.h
@@ -21,76 +21,47 @@
 #ifndef CCNX_CONSUMER_H
 #define CCNX_CONSUMER_H
 
-#include "ns3/application.h"
-#include "ns3/log.h"
+#include "ccnx-app.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"
 
 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-interest-sender.cc b/apps/ccnx-interest-sender.cc
index bcf3d76..d110978 100644
--- a/apps/ccnx-interest-sender.cc
+++ b/apps/ccnx-interest-sender.cc
@@ -1,161 +1,160 @@
-/* -*-  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: Ilya Moiseenko <iliamo@cs.ucla.edu>
- */
+// /* -*-  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: Ilya Moiseenko <iliamo@cs.ucla.edu>
+//  */
 
-#include "ccnx-interest-sender.h"
+// #include "ccnx-interest-sender.h"
 
-NS_LOG_COMPONENT_DEFINE ("CcnxInterestSender");
+// NS_LOG_COMPONENT_DEFINE ("CcnxInterestSender");
 
-namespace ns3
-{    
+// namespace ns3
+// {    
 
-NS_OBJECT_ENSURE_REGISTERED (CcnxInterestSender);
+// NS_OBJECT_ENSURE_REGISTERED (CcnxInterestSender);
 
-TypeId
-CcnxInterestSender::GetTypeId (void)
-{
-    static TypeId tid = TypeId ("ns3::CcnxInterestSender")
-    .SetParent<Application> ()
-    .AddConstructor<CcnxInterestSender> ()
-    .AddAttribute ("OffTime", "Time interval between packets",
-                   TimeValue (Seconds (0.1)),
-                   MakeTimeAccessor (&CcnxInterestSender::m_offTime),
-                   MakeTimeChecker ())
-    // Alex: this is incorrect. SetNode call is not called if face is created using this accessor
-    // .AddAttribute ("Face","Local face to be used",
-    //                PointerValue (CreateObject<CcnxLocalFace> ()),
-    //                MakePointerAccessor (&CcnxInterestSender::m_face),
-    //                MakePointerChecker<CcnxLocalFace> ())
-    .AddAttribute ("NameComponents","CcnxName of the Interest (use CcnxNameComponents)",
-                   CcnxNameComponentsValue (CcnxNameComponents (/* root */)),
-                   MakeCcnxNameComponentsAccessor (&CcnxInterestSender::m_interestName),
-                   MakeCcnxNameComponentsChecker ())
-    .AddAttribute ("LifeTime", "LifeTime fo interest packet",
-                   TimeValue (Seconds (4.0)),
-                   MakeTimeAccessor (&CcnxInterestSender::m_interestLifeTime),
-                   MakeTimeChecker ())
-    .AddAttribute ("MinSuffixComponents", "MinSuffixComponents",
-                   IntegerValue(-1),
-                   MakeIntegerAccessor(&CcnxInterestSender::m_minSuffixComponents),
-                   MakeIntegerChecker<int32_t>())
-    .AddAttribute ("MaxSuffixComponents", "MaxSuffixComponents",
-                   IntegerValue(-1),
-                   MakeIntegerAccessor(&CcnxInterestSender::m_maxSuffixComponents),
-                   MakeIntegerChecker<int32_t>())
-    .AddAttribute ("ChildSelector", "ChildSelector",
-                   BooleanValue(false),
-                   MakeBooleanAccessor(&CcnxInterestSender::m_childSelector),
-                   MakeBooleanChecker())
-    .AddAttribute ("Exclude","only simple name matching is supported (use CcnxNameComponents)",
-                   CcnxNameComponentsValue (CcnxNameComponents(/* root */)),
-                   MakeCcnxNameComponentsAccessor (&CcnxInterestSender::m_exclude),
-                   MakeCcnxNameComponentsChecker ())
-    .AddAttribute ("Initial Nonce", "If 0 then nonce is not used",
-                   UintegerValue(1),
-                   MakeUintegerAccessor(&CcnxInterestSender::m_initialNonce),
-                   MakeUintegerChecker<uint32_t>())
-    ;
-    /*
-    .AddAttribute ("NoiseModel",
-                   "A pointer to the model of the channel ambient noise.",
-                   PointerValue (CreateObject<UanNoiseModelDefault> ()),
-                   MakePointerAccessor (&UanChannel::m_noise),
-                   MakePointerChecker<UanNoiseModel> ())*/
-    return tid;
-}
+// TypeId
+// CcnxInterestSender::GetTypeId (void)
+// {
+//   static TypeId tid = TypeId ("ns3::CcnxInterestSender")
+//     .SetParent<Application> ()
+//     .AddConstructor<CcnxInterestSender> ()
+//     .AddAttribute ("OffTime", "Time interval between packets",
+//                    TimeValue (Seconds (0.1)),
+//                    MakeTimeAccessor (&CcnxInterestSender::m_offTime),
+//                    MakeTimeChecker ())
+//     // Alex: this is incorrect. SetNode call is not called if face is created using this accessor
+//     // .AddAttribute ("Face","Local face to be used",
+//     //                PointerValue (CreateObject<CcnxLocalFace> ()),
+//     //                MakePointerAccessor (&CcnxInterestSender::m_face),
+//     //                MakePointerChecker<CcnxLocalFace> ())
+//     .AddAttribute ("NameComponents","CcnxName of the Interest (use CcnxNameComponents)",
+//                    CcnxNameComponentsValue (CcnxNameComponents (/* root */)),
+//                    MakeCcnxNameComponentsAccessor (&CcnxInterestSender::m_interestName),
+//                    MakeCcnxNameComponentsChecker ())
+//     .AddAttribute ("LifeTime", "LifeTime fo interest packet",
+//                    TimeValue (Seconds (4.0)),
+//                    MakeTimeAccessor (&CcnxInterestSender::m_interestLifeTime),
+//                    MakeTimeChecker ())
+//     .AddAttribute ("MinSuffixComponents", "MinSuffixComponents",
+//                    IntegerValue(-1),
+//                    MakeIntegerAccessor(&CcnxInterestSender::m_minSuffixComponents),
+//                    MakeIntegerChecker<int32_t>())
+//     .AddAttribute ("MaxSuffixComponents", "MaxSuffixComponents",
+//                    IntegerValue(-1),
+//                    MakeIntegerAccessor(&CcnxInterestSender::m_maxSuffixComponents),
+//                    MakeIntegerChecker<int32_t>())
+//     .AddAttribute ("ChildSelector", "ChildSelector",
+//                    BooleanValue(false),
+//                    MakeBooleanAccessor(&CcnxInterestSender::m_childSelector),
+//                    MakeBooleanChecker())
+//     .AddAttribute ("Exclude","only simple name matching is supported (use CcnxNameComponents)",
+//                    CcnxNameComponentsValue (CcnxNameComponents(/* root */)),
+//                    MakeCcnxNameComponentsAccessor (&CcnxInterestSender::m_exclude),
+//                    MakeCcnxNameComponentsChecker ())
+//     .AddAttribute ("Initial Nonce", "If 0 then nonce is not used",
+//                    UintegerValue(1),
+//                    MakeUintegerAccessor(&CcnxInterestSender::m_initialNonce),
+//                    MakeUintegerChecker<uint32_t>())
+//     ;
+//   /*
+//     .AddAttribute ("NoiseModel",
+//     "A pointer to the model of the channel ambient noise.",
+//     PointerValue (CreateObject<UanNoiseModelDefault> ()),
+//     MakePointerAccessor (&UanChannel::m_noise),
+//     MakePointerChecker<UanNoiseModel> ())*/
+//   return tid;
+// }
     
-CcnxInterestSender::CcnxInterestSender ()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-}
+// CcnxInterestSender::CcnxInterestSender ()
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
+// }
     
-CcnxInterestSender::~CcnxInterestSender()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-}
+// CcnxInterestSender::~CcnxInterestSender()
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
+// }
     
-void
-CcnxInterestSender::DoDispose (void)
-{
-    NS_LOG_FUNCTION_NOARGS ();
+// void
+// CcnxInterestSender::DoDispose (void)
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
         
-    Application::DoDispose ();
-}
+//   Application::DoDispose ();
+// }
     
-// Application Methods
-void 
-CcnxInterestSender::StartApplication () // Called at time specified by Start
-{
-    NS_LOG_FUNCTION_NOARGS ();
-    ScheduleNextTx();
-}
+// // Application Methods
+// void 
+// CcnxInterestSender::StartApplication () // Called at time specified by Start
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
+//   ScheduleNextTx();
+// }
     
-void 
-CcnxInterestSender::StopApplication () // Called at time specified by Stop
-{
-    NS_LOG_FUNCTION_NOARGS ();
+// void 
+// CcnxInterestSender::StopApplication () // Called at time specified by Stop
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
     
-    CancelEvents ();
-}
+//   CancelEvents ();
+// }
     
-void 
-CcnxInterestSender::CancelEvents ()
-{
-    NS_LOG_FUNCTION_NOARGS ();
+// void 
+// CcnxInterestSender::CancelEvents ()
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
         
-    Simulator::Cancel (m_sendEvent);
-}
+//   Simulator::Cancel (m_sendEvent);
+// }
 
-void 
-CcnxInterestSender::ScheduleNextTx ()
-{
-    NS_LOG_FUNCTION_NOARGS ();
+// void 
+// CcnxInterestSender::ScheduleNextTx ()
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
         
-    Time nextTime = Seconds(m_offTime);
-    m_sendEvent = Simulator::Schedule (nextTime, &CcnxInterestSender::SendPacket, this);
-}
+//   Time nextTime = Seconds(m_offTime);
+//   m_sendEvent = Simulator::Schedule (nextTime, &CcnxInterestSender::SendPacket, this);
+// }
     
-void
-CcnxInterestSender::SendPacket ()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-    // NS_LOG_INFO ("Sending Interest at " << Simulator::Now ());
+// void
+// CcnxInterestSender::SendPacket ()
+// {
+//   NS_LOG_FUNCTION_NOARGS ();
+//   // NS_LOG_INFO ("Sending Interest at " << Simulator::Now ());
     
-    uint32_t randomNonce = UniformVariable().GetInteger(1, std::numeric_limits<uint32_t>::max ());
-    CcnxInterestHeader interestHeader;
-    interestHeader.SetNonce(randomNonce);
-    //const Ptr<CcnxNameComponents> name = Create<CcnxNameComponents>(m_interestName);
-    interestHeader.SetName(Create<CcnxNameComponents> (m_interestName)); //making a copy of name
-    interestHeader.SetInterestLifetime(m_interestLifeTime);
-    interestHeader.SetChildSelector(m_childSelector);
-    //const Ptr<CcnxNameComponents> exclude = Create<CcnxNameComponents>(m_exclude);
-    interestHeader.SetExclude(Create<CcnxNameComponents> (m_exclude));
-    interestHeader.SetMaxSuffixComponents(m_maxSuffixComponents);
-    interestHeader.SetMinSuffixComponents(m_minSuffixComponents);
+//   uint32_t randomNonce = UniformVariable().GetInteger(1, std::numeric_limits<uint32_t>::max ());
+//   CcnxInterestHeader interestHeader;
+//   interestHeader.SetNonce(randomNonce);
+//   //const Ptr<CcnxNameComponents> name = Create<CcnxNameComponents>(m_interestName);
+//   interestHeader.SetName(Create<CcnxNameComponents> (m_interestName)); //making a copy of name
+//   interestHeader.SetInterestLifetime(m_interestLifeTime);
+//   interestHeader.SetChildSelector(m_childSelector);
+//   //const Ptr<CcnxNameComponents> exclude = Create<CcnxNameComponents>(m_exclude);
+//   interestHeader.SetExclude(Create<CcnxNameComponents> (m_exclude));
+//   interestHeader.SetMaxSuffixComponents(m_maxSuffixComponents);
+//   interestHeader.SetMinSuffixComponents(m_minSuffixComponents);
     
-    Ptr<Packet> packet = Create<Packet> ();
-    packet->AddHeader (interestHeader);
+//   Ptr<Packet> packet = Create<Packet> ();
+//   packet->AddHeader (interestHeader);
     
-    m_face->Send(packet);
+//   m_face->Send(packet);
     
-    ScheduleNextTx();
-}
-
+//   ScheduleNextTx();
+// }
     
-}
+// }
diff --git a/apps/ccnx-interest-sender.h b/apps/ccnx-interest-sender.h
index ad8de28..cbb54ad 100644
--- a/apps/ccnx-interest-sender.h
+++ b/apps/ccnx-interest-sender.h
@@ -1,106 +1,106 @@
-/* -*-  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: Ilya Moiseenko <iliamo@cs.ucla.edu>
- */
+// /* -*-  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: Ilya Moiseenko <iliamo@cs.ucla.edu>
+//  */
 
-#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/random-variable.h"
-#include <limits> 
-#include "ns3/pointer.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/random-variable.h"
+// #include <limits> 
+// #include "ns3/pointer.h"
 
-namespace ns3 
-{
+// namespace ns3 
+// {
     
-class Socket;
+// class Socket;
     
-class CcnxInterestSender: public Application
-{
-public: 
-  static TypeId GetTypeId (void);
+// class CcnxInterestSender: public Application
+// {
+// public: 
+//   static TypeId GetTypeId (void);
         
-  CcnxInterestSender ();
+//   CcnxInterestSender ();
         
-  virtual ~CcnxInterestSender ();
+//   virtual ~CcnxInterestSender ();
         
-protected:
-  virtual void DoDispose (void);
-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
+// protected:
+//   virtual void DoDispose (void);
+// 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
         
-  //Time m_onTime;
-  Time m_offTime;
-  CcnxNameComponents m_interestName;
+//   //Time m_onTime;
+//   Time m_offTime;
+//   CcnxNameComponents m_interestName;
   
-  Time m_interestLifeTime;
-  int32_t m_minSuffixComponents;
-  int32_t m_maxSuffixComponents;
-  bool m_childSelector;
-  CcnxNameComponents m_exclude;
-  uint32_t m_initialNonce;
+//   Time m_interestLifeTime;
+//   int32_t m_minSuffixComponents;
+//   int32_t m_maxSuffixComponents;
+//   bool m_childSelector;
+//   CcnxNameComponents m_exclude;
+//   uint32_t m_initialNonce;
     
-  //EventId         m_startStopEvent;     // Event id for next start or stop event
-  EventId         m_sendEvent;    // Eventid of pending "send packet" event
-  TypeId          m_tid;
-  Ptr<CcnxLocalFace> m_face;
+//   //EventId         m_startStopEvent;     // Event id for next start or stop event
+//   EventId         m_sendEvent;    // Eventid of pending "send packet" event
+//   TypeId          m_tid;
+//   Ptr<CcnxLocalFace> m_face;
         
-  //helpers
-  void CancelEvents ();
+//   //helpers
+//   void CancelEvents ();
         
-  void Construct (Ptr<Node> n,
-                  std::string tid,
-                  const Time& offtime,
-                  Ptr<CcnxLocalFace> face,
-                  Ptr<CcnxNameComponents> nameComponents,
-                  const Time& lifetime,
-                  const int32_t& minSuffixComponents,
-                  const int32_t& maxSuffixComponents,
-                  const bool childSelector,
-                  Ptr<CcnxNameComponents> exclude,
-                  const uint32_t& initialNonce
-                  );
+//   void Construct (Ptr<Node> n,
+//                   std::string tid,
+//                   const Time& offtime,
+//                   Ptr<CcnxLocalFace> face,
+//                   Ptr<CcnxNameComponents> nameComponents,
+//                   const Time& lifetime,
+//                   const int32_t& minSuffixComponents,
+//                   const int32_t& maxSuffixComponents,
+//                   const bool childSelector,
+//                   Ptr<CcnxNameComponents> exclude,
+//                   const uint32_t& initialNonce
+//                   );
     
-  // Event handlers
-  void StartSending ();
-  void StopSending ();
-  void SendPacket ();
+//   // Event handlers
+//   void StartSending ();
+//   void StopSending ();
+//   void SendPacket ();
         
-private:
-  void ScheduleNextTx ();
-  //void ScheduleStartEvent ();
-  //void ScheduleStopEvent ();
-  void ConnectionSucceeded (Ptr<Socket>);
-  void ConnectionFailed (Ptr<Socket>);
-  void Ignore (Ptr<Socket>);
+// private:
+//   void ScheduleNextTx ();
+//   //void ScheduleStartEvent ();
+//   //void ScheduleStopEvent ();
+//   void ConnectionSucceeded (Ptr<Socket>);
+//   void ConnectionFailed (Ptr<Socket>);
+//   void Ignore (Ptr<Socket>);
         
-};
-}
+// };
+// }
diff --git a/apps/ccnx-producer.cc b/apps/ccnx-producer.cc
index d320a2d..844acd4 100644
--- a/apps/ccnx-producer.cc
+++ b/apps/ccnx-producer.cc
@@ -16,202 +16,97 @@
  * 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/log.h"
+#include "ns3/ccnx-interest-header.h"
+#include "ns3/ccnx-content-object-header.h"
+#include "ns3/string.h"
+#include "ns3/uinteger.h"
+#include "ns3/packet.h"
 
+#include "ns3/ccnx-local-face.h"
+#include "ns3/ccnx-fib.h"
+
+#include <boost/ref.hpp>
 
 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 (1024),
                    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)
-{
-    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);
-    
-   
 
-    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);
-    
-    m_contentObjectsTrace(m_face,outgoingPacket);
-        
-    m_face->ReceiveFromApplication(outgoingPacket);
-   
-}
-    
-void 
-CcnxProducer::CancelEvents ()
-{
-    NS_LOG_FUNCTION_NOARGS ();
-        
-    // Simulator::Cancel (m_sendEvent);
-}
-  
-CcnxNameComponents
-CcnxProducer::GetPrefix() const
-{
-  return m_prefix;
-}
-    
-/*uint32_t
-CcnxProducer::GetStoreCapacity()
-{
-  return m_storeCapacity;
-}
-    
+// inherited from Application base class.
 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)
+CcnxProducer::StartApplication ()
 {
   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_ASSERT (GetNode ()->GetObject<CcnxFib> () != 0);
+
+  CcnxApp::StartApplication ();
+
+  GetNode ()->GetObject<CcnxFib> ()->Add (m_prefix, m_face, 0);
+}
+
+void
+CcnxProducer::StopApplication ()
 {
   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));
-  }
-}*/
+  NS_ASSERT (GetNode ()->GetObject<CcnxFib> () != 0);
+
+  CcnxApp::StopApplication ();
 }
+
+
+void
+CcnxProducer::OnInterest (const Ptr<const CcnxInterestHeader> &interest)
+{
+  NS_LOG_FUNCTION (this << interest);
+
+  if (!m_active) return;
+    
+  static CcnxContentObjectTail tail;
+  Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
+  header->SetName (Create<CcnxNameComponents> (interest->GetName ()));
+
+  NS_LOG_INFO ("Respodning with ContentObject:\n" << boost::cref(*header));
+  
+  Ptr<Packet> packet = Create<Packet> (m_virtualPayloadSize);
+  packet->AddHeader (*header);
+  packet->AddTrailer (tail);
+
+  m_protocolHandler (packet);
+}
+
+} // namespace ns3
diff --git a/apps/ccnx-producer.h b/apps/ccnx-producer.h
index 840400b..ac9a492 100644
--- a/apps/ccnx-producer.h
+++ b/apps/ccnx-producer.h
@@ -16,194 +16,44 @@
  * 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);
-    
+  CcnxProducer ();
+
+  // inherited from CcnxApp
+  void OnInterest (const Ptr<const CcnxInterestHeader> &interest);
+
 protected:
-    virtual void DoDispose (void);
+  // inherited from Application base class.
+  virtual void
+  StartApplication ();    // Called at time specified by Start
+
+  virtual void
+  StopApplication ();     // Called at time specified by Stop
+
 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/examples/annotated-topology-read-example.cc b/examples/annotated-topology-read-example.cc
index 7aff4fe..50c9d13 100644
--- a/examples/annotated-topology-read-example.cc
+++ b/examples/annotated-topology-read-example.cc
@@ -30,7 +30,6 @@
 #include "ns3/ipv4-list-routing-helper.h"
 #include "ns3/annotated-topology-reader.h"
 #include <list>
-#include "ns3/visualizer-module.h"
 #include "ns3/ccnx.h"
 #include "ns3/ipv4-global-routing-helper.h"
 #include "ns3/NDNabstraction-module.h"
@@ -42,155 +41,156 @@
 
 int main (int argc, char *argv[])
 {
-    GlobalValue::Bind ("SimulatorImplementationType", StringValue
-                       ("ns3::VisualSimulatorImpl"));
-    Packet::EnableChecking();
-    Packet::EnablePrinting();
-    string input ("/Users/iliamo/ns3-abstract-ndn/ns-3.11/src/NDNabstraction/examples/simpletopology.txt");
+  Packet::EnableChecking();
+  Packet::EnablePrinting();
+  string input ("/Users/iliamo/ns3-abstract-ndn/ns-3.11/src/NDNabstraction/examples/simpletopology.txt");
     
-    // Set up command line parameters used to control the experiment.
-    //CommandLine cmd;
-    //cmd.AddValue ("input", "Name of the input file.",
-    //              input);
-    //cmd.Parse (argc, argv);
+  // Set up command line parameters used to control the experiment.
+  //CommandLine cmd;
+  //cmd.AddValue ("input", "Name of the input file.",
+  //              input);
+  //cmd.Parse (argc, argv);
     
     
-    // ------------------------------------------------------------
-    // -- Read topology data.
-    // --------------------------------------------
+  // ------------------------------------------------------------
+  // -- Read topology data.
+  // --------------------------------------------
     
     
-    Ptr<AnnotatedTopologyReader> reader = CreateObject<AnnotatedTopologyReader> ();
-    reader->SetFileName (input);
+  Ptr<AnnotatedTopologyReader> reader = CreateObject<AnnotatedTopologyReader> ();
+  reader->SetFileName (input);
     
-    NodeContainer nodes;
-    if (reader != 0)
+  NodeContainer nodes;
+  if (reader != 0)
     {
-        nodes = reader->Read ();
+      nodes = reader->Read ();
     }
     
-    if (reader->LinksSize () == 0)
+  if (reader->LinksSize () == 0)
     {
-        NS_LOG_ERROR ("Problems reading the topology file. Failing.");
-        return -1;
+      NS_LOG_ERROR ("Problems reading the topology file. Failing.");
+      return -1;
     }
     
     
-    for(uint32_t j=0; j<nodes.GetN(); j++)
+  for(uint32_t j=0; j<nodes.GetN(); j++)
     {
-        uint32_t name = j+1;
-        std::stringstream ss;
-        ss<<name;
-        Names::Add (ss.str(), nodes.Get (j));
-        NS_LOG_INFO("Name = " << ss.str());
+      uint32_t name = j+1;
+      std::stringstream ss;
+      ss<<name;
+      Names::Add (ss.str(), nodes.Get (j));
+      NS_LOG_INFO("Name = " << ss.str());
     }
  
-    // ------------------------------------------------------------
-    // -- Create nodes and network stacks
-    // --------------------------------------------
-    NS_LOG_INFO ("creating internet stack");
-    InternetStackHelper stack;
+  // ------------------------------------------------------------
+  // -- Create nodes and network stacks
+  // --------------------------------------------
+  NS_LOG_INFO ("creating internet stack");
+  InternetStackHelper stack;
     
     
-    //routing
-    //Ipv4StaticRoutingHelper staticRouting;
-    //Ipv4ListRoutingHelper listRH;
-    //listRH.Add (staticRouting, 0);
-    //stack.SetRoutingHelper (listRH);  // has effect on the next Install ()
-    //stack.Install (nodes);
+  //routing
+  //Ipv4StaticRoutingHelper staticRouting;
+  //Ipv4ListRoutingHelper listRH;
+  //listRH.Add (staticRouting, 0);
+  //stack.SetRoutingHelper (listRH);  // has effect on the next Install ()
+  //stack.Install (nodes);
     
-    Ipv4GlobalRoutingHelper ipv4RoutingHelper;
-    // Ptr<Ipv4RoutingHelper> ipv4RoutingHelper = stack.GetRoutingHelper ();
-    stack.SetRoutingHelper (ipv4RoutingHelper);
-    stack.Install(nodes);
+  Ipv4GlobalRoutingHelper ipv4RoutingHelper;
+  // Ptr<Ipv4RoutingHelper> ipv4RoutingHelper = stack.GetRoutingHelper ();
+  stack.SetRoutingHelper (ipv4RoutingHelper);
+  stack.Install(nodes);
     
-    NS_LOG_INFO ("creating ip4 addresses");
-    Ipv4AddressHelper address;
-    address.SetBase ("10.0.0.0", "255.255.255.252");
+  NS_LOG_INFO ("creating ip4 addresses");
+  Ipv4AddressHelper address;
+  address.SetBase ("10.0.0.0", "255.255.255.252");
    
-    // // Create router nodes, initialize routing database and set up the routing
-    // // tables in the nodes.
-    Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+  // // Create router nodes, initialize routing database and set up the routing
+  // // tables in the nodes.
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
     
-    /*grid.AssignIpv4Addresses (
-                              Ipv4AddressHelper("10.1.0.0", "255.255.255.0"),
-                              Ipv4AddressHelper("10.2.0.0", "255.255.255.0")
-                              );
-*/
+  /*grid.AssignIpv4Addresses (
+    Ipv4AddressHelper("10.1.0.0", "255.255.255.0"),
+    Ipv4AddressHelper("10.2.0.0", "255.255.255.0")
+    );
+  */
     
-    int totlinks = reader->LinksSize ();
+  int totlinks = reader->LinksSize ();
     
     
-    ///*** applying settings
-    NS_LOG_INFO ("creating node containers");
-    NodeContainer* nc = new NodeContainer[totlinks];
-    TopologyReader::ConstLinksIterator iter;
-    int i = 0;
-    for ( iter = reader->LinksBegin (); iter != reader->LinksEnd (); iter++, i++ )
+  ///*** applying settings
+  NS_LOG_INFO ("creating node containers");
+  NodeContainer* nc = new NodeContainer[totlinks];
+  TopologyReader::ConstLinksIterator iter;
+  int i = 0;
+  for ( iter = reader->LinksBegin (); iter != reader->LinksEnd (); iter++, i++ )
     {
-        nc[i] = NodeContainer (iter->GetFromNode (), iter->GetToNode ());
+      nc[i] = NodeContainer (iter->GetFromNode (), iter->GetToNode ());
     }
     
-    NetDeviceContainer* ndc = new NetDeviceContainer[totlinks];
-    reader->ApplySettings(ndc,nc);
-    ///*** settings applied
+  NetDeviceContainer* ndc = new NetDeviceContainer[totlinks];
+  reader->ApplySettings(ndc,nc);
+  ///*** settings applied
     
-    NS_LOG_INFO("installing ccnx stack");
-    CcnxStackHelper ccnx(Ccnx::NDN_FLOODING);
-    Ptr<CcnxFaceContainer> cf = ccnx.Install (nodes);
+  NS_LOG_INFO("installing ccnx stack");
+  CcnxStackHelper ccnx;
+  ccnx.SetForwardingStrategy ("ns3::CcnxFloodingStrategy");
+  ccnx.EnableLimits (false);
+    
+  Ptr<CcnxFaceContainer> cf = ccnx.Install (nodes);
      
-    NS_LOG_INFO ("Installing Applications");
-    CcnxConsumerHelper helper ("/3");
-    ApplicationContainer app = helper.Install (nodes.Get(1));
-    app.Start (Seconds (1.0));
-    app.Stop (Seconds (1000.05));
+  NS_LOG_INFO ("Installing Applications");
+  CcnxConsumerHelper helper ("/3");
+  ApplicationContainer app = helper.Install (nodes.Get(1));
+  app.Start (Seconds (1.0));
+  app.Stop (Seconds (1000.05));
     
-    /*CcnxConsumerHelper helper2 ("/4");
-     ApplicationContainer app2 = helper2.Install(c.Get(5));
-     app2.Start (Seconds (1.0));
-     app2.Stop (Seconds (1000.05));
-     */
-    CcnxProducerHelper helper3 ("/3",120);
-    ApplicationContainer app3 = helper3.Install(nodes.Get(6));
-    app3.Start(Seconds(0.0));
-    app3.Stop(Seconds(1500.0));
-    /*
-     CcnxProducerHelper helper4 ("/4",150);
-     ApplicationContainer app4 = helper4.Install(c.Get(0));
-     app4.Start(Seconds(0.0));
-     app4.Stop(Seconds(1500.0));
-     */
+  /*CcnxConsumerHelper helper2 ("/4");
+    ApplicationContainer app2 = helper2.Install(c.Get(5));
+    app2.Start (Seconds (1.0));
+    app2.Stop (Seconds (1000.05));
+  */
+  CcnxProducerHelper helper3 ("/3",120);
+  ApplicationContainer app3 = helper3.Install(nodes.Get(6));
+  app3.Start(Seconds(0.0));
+  app3.Stop(Seconds(1500.0));
+  /*
+    CcnxProducerHelper helper4 ("/4",150);
+    ApplicationContainer app4 = helper4.Install(c.Get(0));
+    app4.Start(Seconds(0.0));
+    app4.Stop(Seconds(1500.0));
+  */
 
-    NS_LOG_INFO("Routes");
-    ccnx.AddRoute("1","/3",0,1);
-    ccnx.AddRoute("3","/3",1,1);
-    ccnx.AddRoute("3","/3",2,2);
-    /*ccnx.AddRoute("4","/3",1,1);
+  NS_LOG_INFO("Routes");
+  ccnx.AddRoute("1","/3",0,1);
+  ccnx.AddRoute("3","/3",1,1);
+  ccnx.AddRoute("3","/3",2,2);
+  /*ccnx.AddRoute("4","/3",1,1);
     ccnx.AddRoute("5","/3",2,1);
-*/
+  */
     
-    // it creates little subnets, one for each couple of nodes.
-    NS_LOG_INFO ("creating ipv4 interfaces");
-    Ipv4InterfaceContainer* ipic = new Ipv4InterfaceContainer[totlinks];
-    for (int i = 0; i < totlinks; i++)
+  // it creates little subnets, one for each couple of nodes.
+  NS_LOG_INFO ("creating ipv4 interfaces");
+  Ipv4InterfaceContainer* ipic = new Ipv4InterfaceContainer[totlinks];
+  for (int i = 0; i < totlinks; i++)
     {
-        ipic[i] = address.Assign (ndc[i]);
-        address.NewNetwork ();
+      ipic[i] = address.Assign (ndc[i]);
+      address.NewNetwork ();
     }
     
-    // ------------------------------------------------------------
-    // -- Run the simulation
-    // --------------------------------------------
-    NS_LOG_INFO ("Run Simulation.");
-    Simulator::Stop (Seconds (20));
-    Simulator::Run ();
-    Simulator::Destroy ();
+  // ------------------------------------------------------------
+  // -- Run the simulation
+  // --------------------------------------------
+  NS_LOG_INFO ("Run Simulation.");
+  Simulator::Stop (Seconds (20));
+  Simulator::Run ();
+  Simulator::Destroy ();
     
-    delete[] ipic;
-    delete[] ndc;
-    delete[] nc;
+  delete[] ipic;
+  delete[] ndc;
+  delete[] nc;
     
-    NS_LOG_INFO ("Done.");
+  NS_LOG_INFO ("Done.");
     
-    return 0;
+  return 0;
 }
diff --git a/examples/ccnx-grid.cc b/examples/ccnx-grid.cc
index 0050805..51d7858 100644
--- a/examples/ccnx-grid.cc
+++ b/examples/ccnx-grid.cc
@@ -24,16 +24,17 @@
 #include "ns3/NDNabstraction-module.h"
 #include "ns3/point-to-point-grid.h"
 #include "ns3/ipv4-global-routing-helper.h"
+#include "ns3/netanim-module.h"
 
 #include <iostream>
 #include <sstream>
-#include "ns3/visualizer-module.h"
 
 using namespace ns3;
 
 NS_LOG_COMPONENT_DEFINE ("CcnxGrid");
 
 uint32_t nGrid = 3;
+Time finishTime = Seconds (20.0); 
 
 void PrintTime ()
 {
@@ -42,19 +43,41 @@
   Simulator::Schedule (Seconds (10.0), PrintTime);
 }
 
+void PrintFIBs ()
+{
+  NS_LOG_INFO ("Outputing FIBs into [fibs.log]");
+  Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> ("fibs.log", std::ios::out);
+  for (NodeList::Iterator node = NodeList::Begin ();
+       node != NodeList::End ();
+       node++)
+    {
+      *routingStream->GetStream () << "Node " << (*node)->GetId () << "\n";
+
+      Ptr<CcnxFib> fib = (*node)->GetObject<CcnxFib> ();
+      NS_ASSERT_MSG (fib != 0, "Fire alarm");
+      *routingStream->GetStream () << *fib << "\n\n";
+    }
+}
+
 int 
 main (int argc, char *argv[])
 {
-  //GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::VisualSimulatorImpl"));
-    
   Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("1Mbps"));
-  Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("1ms"));
+  Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("10ms"));
+  Config::SetDefault ("ns3::CcnxConsumer::OffTime", StringValue ("1s"));
+  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("20"));
     
   Packet::EnableChecking();
   Packet::EnablePrinting();
 
+  std::string animationFile = "";
+  std::string strategy = "ns3::CcnxFloodingStrategy";
+
   CommandLine cmd;
   cmd.AddValue ("nGrid", "Number of grid nodes", nGrid);
+  cmd.AddValue ("finish", "Finish time", finishTime);
+  cmd.AddValue ("netanim", "NetAnim filename", animationFile);
+  cmd.AddValue ("strategy", "CCNx forwarding strategy", strategy);
   cmd.Parse (argc, argv);
 
   PointToPointHelper p2p;
@@ -68,7 +91,9 @@
 
   // Install CCNx stack
   NS_LOG_INFO ("Installing CCNx stack");
-  CcnxStackHelper ccnxHelper(/*Ccnx::NDN_FLOODING*/Ccnx::NDN_BESTROUTE);
+  CcnxStackHelper ccnxHelper;
+  ccnxHelper.SetForwardingStrategy (strategy);
+  ccnxHelper.EnableLimits (true, Seconds(0.1));
   ccnxHelper.InstallAll ();
 
   // Install IP stack (necessary to populate FIB)
@@ -94,39 +119,38 @@
   CcnxConsumerHelper consumerHelper (prefix.str ());
   ApplicationContainer consumers = consumerHelper.Install (consumerNodes);
   
-  consumers.Start (Seconds (0));
-  consumers.Stop (Seconds (2000));
+  // consumers.Start (Seconds (0.0));
+  // consumers.Stop (finishTime);
     
-  CcnxProducerHelper producerHelper (prefix.str (),120);
+  CcnxProducerHelper producerHelper (prefix.str (),1024);
   ApplicationContainer producers = producerHelper.Install (producer);
   
-  producers.Start(Seconds(0.0));
-  producers.Stop(Seconds(2000.0));
+  // producers.Start(Seconds(0.0));
+  // producers.Stop(finishTime);
 
-  NS_LOG_INFO ("Outputing FIBs into [fibs.log]");
-  Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> ("fibs.log", std::ios::out);
-  for (NodeList::Iterator node = NodeList::Begin ();
-       node != NodeList::End ();
-       node++)
-    {
-      *routingStream->GetStream () << "Node " << (*node)->GetId () << "\n";
-
-      Ptr<CcnxFib> fib = (*node)->GetObject<CcnxFib> ();
-      NS_ASSERT_MSG (fib != 0, "Fire alarm");
-      *routingStream->GetStream () << *fib << "\n\n";
-    }
+  Simulator::Schedule (Seconds (1.0), PrintFIBs);
 
   Simulator::Schedule (Seconds (10.0), PrintTime);
   
   // NS_LOG_INFO ("FIB dump:\n" << *c.Get(0)->GetObject<CcnxFib> ());
   // NS_LOG_INFO ("FIB dump:\n" << *c.Get(1)->GetObject<CcnxFib> ());
     
-  Simulator::Stop (Seconds (2000));
+  Simulator::Stop (finishTime);
     
+  AnimationInterface *anim = 0;
+  if (animationFile != "")
+    {
+      anim = new AnimationInterface (animationFile);
+      anim->SetMobilityPollInterval (Seconds (1));
+    }
+
   NS_LOG_INFO ("Run Simulation.");
   Simulator::Run ();
   Simulator::Destroy ();
   NS_LOG_INFO ("Done!");
     
+  if (anim != 0)
+    delete anim;
+  
   return 0;
 }
diff --git a/examples/content-object-example.cc b/examples/content-object-example.cc
index fa9700e..8272e86 100644
--- a/examples/content-object-example.cc
+++ b/examples/content-object-example.cc
@@ -19,38 +19,38 @@
 int
 main (int argc, char *argv[])
 {
-	LogComponentEnable ("ContentObjectHeaderExample", LOG_ALL);
-	LogComponentEnable ("Packet", LOG_ALL);
+  LogComponentEnable ("ContentObjectHeaderExample", LOG_ALL);
+  LogComponentEnable ("Packet", LOG_ALL);
 	
-    NS_LOG_INFO ("Test started");
+  NS_LOG_INFO ("Test started");
 
-	Packet::EnablePrinting ();
-	Packet::EnableChecking (); 
-	Packet packet (10);
+  Packet::EnablePrinting ();
+  Packet::EnableChecking (); 
+  Packet packet (10);
 	
-    CcnxContentObjectHeader header;
-	CcnxContentObjectTail   trailer;
+  CcnxContentObjectHeader header;
+  CcnxContentObjectTail   trailer;
 	
-    Ptr<CcnxNameComponents> testname = Create<CcnxNameComponents> ();
-    (*testname) ("1");
-    header.SetName(testname);
+  Ptr<CcnxNameComponents> testname = Create<CcnxNameComponents> ();
+  (*testname) ("1");
+  header.SetName(testname);
 
-	NS_LOG_INFO ("Source: \n" << header << trailer);
+  NS_LOG_INFO ("Source: \n" << header << trailer);
 
-	packet.AddHeader (header);
-	packet.AddTrailer (trailer);
+  packet.AddHeader (header);
+  packet.AddTrailer (trailer);
 
-	// NS_LOG_INFO ("Deserialized packet: \n" << packet);
+  // NS_LOG_INFO ("Deserialized packet: \n" << packet);
 
-	NS_LOG_INFO ("Removing and deserializing individual headers");
+  NS_LOG_INFO ("Removing and deserializing individual headers");
 	
-    CcnxContentObjectHeader dst_header;
-	CcnxContentObjectTail   dst_trailer;
+  CcnxContentObjectHeader dst_header;
+  CcnxContentObjectTail   dst_trailer;
 
-	packet.RemoveHeader (dst_header);
-	packet.RemoveTrailer (dst_trailer);
+  packet.RemoveHeader (dst_header);
+  packet.RemoveTrailer (dst_trailer);
 	
-	NS_LOG_INFO ("Target: \n" << dst_header << dst_trailer);
+  NS_LOG_INFO ("Target: \n" << dst_header << dst_trailer);
 
-	return 0;
+  return 0;
 }
diff --git a/examples/interest-header-example.cc b/examples/interest-header-example.cc
index a93da9a..6964440 100644
--- a/examples/interest-header-example.cc
+++ b/examples/interest-header-example.cc
@@ -1,3 +1,21 @@
+/* -*- 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
+ *
+ */
 #include "ns3/test.h"
 #include "ns3/annotated-topology-reader.h"
 #include "ns3/ccnx-interest-header.h"
@@ -19,54 +37,53 @@
 int
 main (int argc, char *argv[])
 {
-	LogComponentEnable ("InterestHeaderExample", LOG_ALL);
-	LogComponentEnable ("Packet", LOG_ALL);
+  // LogComponentEnable ("InterestHeaderExample", LOG_ALL);
+  // LogComponentEnable ("Packet", LOG_ALL);
 	
-    NS_LOG_INFO ("Test started");
+  NS_LOG_INFO ("Test started");
 
-	Packet::EnablePrinting ();
-	Packet::EnableChecking (); 
-	Packet packet (0);
+  Packet::EnablePrinting ();
+  Packet::EnableChecking (); 
+  Packet packet (0);
 
-    CcnxInterestHeader interestHeader;
+  CcnxInterestHeader interestHeader;
 	
-    Ptr<CcnxNameComponents> testname = Create<CcnxNameComponents> ();
-    (*testname) ("first") ("second");
-    interestHeader.SetName(testname);
+  Ptr<CcnxNameComponents> testname = Create<CcnxNameComponents> ();
+  (*testname) ("first") ("second");
+  interestHeader.SetName(testname);
 	
-    uint32_t minSuffixComponents = 20;
-    interestHeader.SetMinSuffixComponents(minSuffixComponents);
+  uint32_t minSuffixComponents = 20;
+  interestHeader.SetMinSuffixComponents(minSuffixComponents);
 	
-    uint32_t maxSuffixComponents = 40;
-    interestHeader.SetMaxSuffixComponents(maxSuffixComponents);
+  uint32_t maxSuffixComponents = 40;
+  interestHeader.SetMaxSuffixComponents(maxSuffixComponents);
 	
-    Time lifetime = Seconds(661777) + MicroSeconds(1234);
-    interestHeader.SetInterestLifetime(lifetime);
+  Time lifetime = Seconds(661777) + MicroSeconds(1234);
+  interestHeader.SetInterestLifetime(lifetime);
 
-    bool child = true;
-    interestHeader.SetChildSelector(child);
+  bool child = true;
+  interestHeader.SetChildSelector(child);
 
-    Ptr<CcnxNameComponents> exclude = Create<CcnxNameComponents> ();
-    (*exclude) ("exclude1") ("exclude2");
-    interestHeader.SetExclude(exclude);
+  Ptr<CcnxNameComponents> exclude = Create<CcnxNameComponents> ();
+  (*exclude) ("exclude1") ("exclude2");
+  interestHeader.SetExclude(exclude);
 
-	UniformVariable random(1, std::numeric_limits<uint32_t>::max ());
-    uint32_t randomNonce = static_cast<uint32_t> (random.GetValue());
-    interestHeader.SetNonce(randomNonce);
+  UniformVariable random(1, std::numeric_limits<uint32_t>::max ());
+  uint32_t randomNonce = static_cast<uint32_t> (random.GetValue());
+  interestHeader.SetNonce(randomNonce);
     
-    interestHeader.SetNack(true);
-    interestHeader.SetCongested(true);
-	NS_LOG_INFO ("Source: \n" << interestHeader);
+  interestHeader.SetNack(CcnxInterestHeader::NACK_CONGESTION);
+  NS_LOG_INFO ("Source: \n" << interestHeader);
     
-	packet.AddHeader (interestHeader);
-	NS_LOG_INFO ("Deserialized packet: " << packet);
+  packet.AddHeader (interestHeader);
+  NS_LOG_INFO ("Deserialized packet: " << packet);
 
-	NS_LOG_INFO ("Removing and deserializing individual headers");
+  NS_LOG_INFO ("Removing and deserializing individual headers");
 	
-    CcnxInterestHeader target;
-	packet.RemoveHeader (target);
+  CcnxInterestHeader target;
+  packet.RemoveHeader (target);
 
-	NS_LOG_INFO ("Target: \n" << target);
+  // NS_LOG_INFO ("Target: \n" << target);
 
-	return 0;
+  return 0;
 }
diff --git a/examples/packet-sizes.cc b/examples/packet-sizes.cc
new file mode 100644
index 0000000..041cac6
--- /dev/null
+++ b/examples/packet-sizes.cc
@@ -0,0 +1,126 @@
+/* -*- 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 "ns3/core-module.h"
+#include "ns3/ccnx-content-object-header.h"
+#include "ns3/ccnx-interest-header.h"
+#include "ns3/ccnx-header-helper.h"
+#include "ns3/header.h"
+#include "ns3/ccnx-name-components.h"
+#include "ns3/nstime.h"
+#include "ns3/string.h"
+#include "ns3/buffer.h"
+#include "ns3/packet.h"
+#include "ns3/log.h"
+
+using namespace ns3;
+#include <fstream>
+
+NS_LOG_COMPONENT_DEFINE ("PacketSizes");
+
+int
+main (int argc, char *argv[])
+{
+  NS_LOG_INFO ("Test started");
+
+  uint32_t size = 1024;
+  std::string namePrefixStr = "/1";
+  uint32_t start=0, end=100;
+
+  CommandLine	cmd;
+  cmd.AddValue ("size",  "ContentObject payload size", size);
+  cmd.AddValue ("name",  "Prefix",                     namePrefixStr);
+  cmd.AddValue ("start", "Range start", start);
+  cmd.AddValue ("end",   "Range end",   end);
+  cmd.Parse (argc, argv);
+ 
+  CcnxNameComponents namePrefixValue;
+  std::istringstream is (namePrefixStr);
+  is >> namePrefixValue;
+
+  Packet::EnablePrinting ();
+  Packet::EnableChecking ();
+
+  double interestSize = 0.0;
+  double nackSize = 0.0;
+  double contentObjectSize = 0.0;
+
+  double progress = start;
+  double step = (end-start)/100.0;
+
+  progress += step;
+
+  NS_LOG_INFO (progress << ", " << step);
+
+  for (uint32_t currentSize = start; currentSize < end; currentSize++)
+    {
+      Ptr<CcnxNameComponents> namePrefix = Create<CcnxNameComponents> (namePrefixValue);
+      namePrefix->Add (currentSize);
+
+      NS_LOG_LOGIC (boost::cref (*namePrefix));
+
+      // Interest Packet (doesn't have a payload)
+      CcnxInterestHeader interestHeader;
+
+      interestHeader.SetName (namePrefix);
+      interestHeader.SetInterestLifetime (Seconds (4.0));
+      interestHeader.SetNonce (10101010);
+      
+      Ptr<Packet> interestPacket =  Create<Packet> (0);
+      interestPacket->AddHeader (interestHeader);
+
+      interestSize = interestSize + (1.0*interestPacket->GetSize () - interestSize) / (currentSize - start + 1);
+
+      
+
+      // NACK
+      interestHeader.SetNack (CcnxInterestHeader::NACK_GIVEUP_PIT);
+
+      Ptr<Packet> nackPacket = Create<Packet> (0);
+      nackPacket->AddHeader (interestHeader);
+      
+      nackSize = nackSize + (1.0*nackPacket->GetSize () - nackSize) / (currentSize - start + 1);
+
+      // ContentObject
+      CcnxContentObjectHeader coHeader;
+      CcnxContentObjectTail   coTrailer;
+      
+      coHeader.SetName (namePrefix);
+      
+      Ptr<Packet> contentObject = Create<Packet> (size);
+
+      contentObject->AddHeader (coHeader);
+      contentObject->AddTrailer (coTrailer);
+
+      contentObjectSize = contentObjectSize + (1.0*contentObject->GetSize () - contentObjectSize ) / (currentSize - start + 1);
+
+      NS_LOG_DEBUG (interestSize << ", " << nackSize << ", " << contentObjectSize);
+
+      if (currentSize >= progress) 
+	{
+	  NS_LOG_INFO ("Current: " << currentSize << "/" << end);
+	  progress += step;
+	}
+    }
+
+  NS_LOG_INFO ("Avg interest: " << interestSize << ", avg nack: " << nackSize << ", avg contentObject: " << contentObjectSize);
+
+  return 0;
+}
diff --git a/examples/syntactic-topology-ndnabstraction.cc b/examples/syntactic-topology-ndnabstraction.cc
index 61f5c49..3fc04a1 100644
--- a/examples/syntactic-topology-ndnabstraction.cc
+++ b/examples/syntactic-topology-ndnabstraction.cc
@@ -28,7 +28,6 @@
 #include <iostream>
 #include <sstream>
 
-#include "ns3/visualizer-module.h"
 #include "ns3/ccnx.h"
 
 
@@ -39,16 +38,13 @@
 int 
 main (int argc, char *argv[])
 {
-  GlobalValue::Bind ("SimulatorImplementationType", StringValue
-                       ("ns3::VisualSimulatorImpl"));
-    
   // Set up some default values for the simulation.  Use the 
   
   Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (210));
   Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("448kb/s"));
   
-    Packet::EnableChecking();
-    Packet::EnablePrinting();
+  Packet::EnableChecking();
+  Packet::EnablePrinting();
 
   // Allow the user to override any of the defaults and the above
   // DefaultValue::Bind ()s at run-time, via command-line arguments
@@ -59,13 +55,13 @@
   NS_LOG_INFO ("Create nodes.");
   NodeContainer c;
   c.Create (7);
-    Names::Add ("1", c.Get (0));
-    Names::Add ("2", c.Get (1));
-    Names::Add ("3", c.Get (2));
-    Names::Add ("4", c.Get (3));
-    Names::Add ("5", c.Get (4));
-    Names::Add ("6", c.Get (5));
-    Names::Add ("7", c.Get (6));
+  Names::Add ("1", c.Get (0));
+  Names::Add ("2", c.Get (1));
+  Names::Add ("3", c.Get (2));
+  Names::Add ("4", c.Get (3));
+  Names::Add ("5", c.Get (4));
+  Names::Add ("6", c.Get (5));
+  Names::Add ("7", c.Get (6));
     
     
   NodeContainer n13 = NodeContainer (c.Get (0), c.Get (2));
@@ -108,14 +104,14 @@
   p2p.SetChannelAttribute ("Delay", StringValue ("50ms"));
   NetDeviceContainer nd35 = p2p.Install (n35);
   
-    InternetStackHelper stack;
-    Ipv4GlobalRoutingHelper ipv4RoutingHelper;
-    // Ptr<Ipv4RoutingHelper> ipv4RoutingHelper = stack.GetRoutingHelper ();
-    stack.SetRoutingHelper (ipv4RoutingHelper);
-    stack.Install(c);
-    // // Create router nodes, initialize routing database and set up the routing
-    // // tables in the nodes.
-    Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
+  InternetStackHelper stack;
+  Ipv4GlobalRoutingHelper ipv4RoutingHelper;
+  // Ptr<Ipv4RoutingHelper> ipv4RoutingHelper = stack.GetRoutingHelper ();
+  stack.SetRoutingHelper (ipv4RoutingHelper);
+  stack.Install(c);
+  // // Create router nodes, initialize routing database and set up the routing
+  // // tables in the nodes.
+  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
     
   // Later, we add IP addresses.
   NS_LOG_INFO ("Assign IP Addresses.");
@@ -132,38 +128,40 @@
     
     
     
-    CcnxStackHelper ccnx(Ccnx::NDN_FLOODING/*Ccnx::NDN_BESTROUTE*/);
-    Ptr<CcnxFaceContainer> cf = ccnx.Install (c);
+  CcnxStackHelper ccnx;
+  ccnx.SetForwardingStrategy ("ns3::CcnxFloodingStrategy");
+  ccnx.EnableLimits (false);
+  Ptr<CcnxFaceContainer> cf = ccnx.Install (c);
     
-    NS_LOG_INFO ("Installing Applications");
-    CcnxConsumerHelper helper ("/3");
-    ApplicationContainer app = helper.Install (c.Get(1));
-    app.Start (Seconds (1.0));
-    app.Stop (Seconds (1000.05));
+  NS_LOG_INFO ("Installing Applications");
+  CcnxConsumerHelper helper ("/3");
+  ApplicationContainer app = helper.Install (c.Get(1));
+  app.Start (Seconds (1.0));
+  app.Stop (Seconds (1000.05));
     
-    /*CcnxConsumerHelper helper2 ("/4");
+  /*CcnxConsumerHelper helper2 ("/4");
     ApplicationContainer app2 = helper2.Install(c.Get(5));
     app2.Start (Seconds (1.0));
     app2.Stop (Seconds (1000.05));
-    */
-    CcnxProducerHelper helper3 ("/3",120);
-    ApplicationContainer app3 = helper3.Install(c.Get(6));
-    app3.Start(Seconds(0.0));
-    app3.Stop(Seconds(1500.0));
-    /*
+  */
+  CcnxProducerHelper helper3 ("/3",120);
+  ApplicationContainer app3 = helper3.Install(c.Get(6));
+  app3.Start(Seconds(0.0));
+  app3.Stop(Seconds(1500.0));
+  /*
     CcnxProducerHelper helper4 ("/4",150);
     ApplicationContainer app4 = helper4.Install(c.Get(0));
     app4.Start(Seconds(0.0));
     app4.Stop(Seconds(1500.0));
   */
     
-    ccnx.AddRoute("1","/3",0,1);
-    ccnx.AddRoute("3","/3",2,1);
-    ccnx.AddRoute("3","/3",3,1);
-    ccnx.AddRoute("4","/3",1,1);
-    ccnx.AddRoute("5","/3",2,1);
+  ccnx.AddRoute("1","/3",0,1);
+  ccnx.AddRoute("3","/3",2,1);
+  ccnx.AddRoute("3","/3",3,1);
+  ccnx.AddRoute("4","/3",1,1);
+  ccnx.AddRoute("5","/3",2,1);
     
-    /*ccnx.AddRoute ("1", "/3", 0, 1);
+  /*ccnx.AddRoute ("1", "/3", 0, 1);
     ccnx.AddRoute ("1", "/3", 1, 1);
     
     ccnx.AddRoute ("2", "/3", 1, 1);
@@ -182,40 +180,40 @@
   // Create the OnOff application to send UDP datagrams of size
   // 210 bytes at a rate of 448 Kb/s from n0 to n4
   /*NS_LOG_INFO ("Create Applications.");
-  uint16_t port = 9;   // Discard port (RFC 863)
+    uint16_t port = 9;   // Discard port (RFC 863)
   
-  std::string sendsizeattr = "SendSize";
-  //flow2 7-->2
-  BulkSendHelper bulksend0 ("ns3::UdpSocketFactory", InetSocketAddress (i23.GetAddress (0), port));
-  //bulksend0.SetAttribute(sendsizeattr, AttributeValue(ConstantVariable(2560)));
-  bulksend0.SetAttribute("MaxBytes", UintegerValue(2560));
-  ApplicationContainer apps = bulksend0.Install(c.Get(6));
-  apps.Start(Seconds (1.0));
-  apps.Stop(Seconds (10.0));
+    std::string sendsizeattr = "SendSize";
+    //flow2 7-->2
+    BulkSendHelper bulksend0 ("ns3::UdpSocketFactory", InetSocketAddress (i23.GetAddress (0), port));
+    //bulksend0.SetAttribute(sendsizeattr, AttributeValue(ConstantVariable(2560)));
+    bulksend0.SetAttribute("MaxBytes", UintegerValue(2560));
+    ApplicationContainer apps = bulksend0.Install(c.Get(6));
+    apps.Start(Seconds (1.0));
+    apps.Stop(Seconds (10.0));
   
-  // Create a packet sink to receive these packets
-  PacketSinkHelper sink0 ("ns3::UdpSocketFactory", InetSocketAddress(Ipv4Address::GetAny (), port));
-  apps = sink0.Install(c.Get(1));
-  apps.Start(Seconds(0.0));
-  apps.Stop(Seconds(20.0));
+    // Create a packet sink to receive these packets
+    PacketSinkHelper sink0 ("ns3::UdpSocketFactory", InetSocketAddress(Ipv4Address::GetAny (), port));
+    apps = sink0.Install(c.Get(1));
+    apps.Start(Seconds(0.0));
+    apps.Stop(Seconds(20.0));
   
-  //flow1 1-->6
-  BulkSendHelper bulksend ("ns3::UdpSocketFactory", InetSocketAddress (i56.GetAddress (1), port));
-  //bulksend.SetAttribute(sendsizeattr, AttributeValue( ConstantVariable(2560)));
-  bulksend0.SetAttribute("MaxBytes", UintegerValue(2560));
-  apps = bulksend.Install (c.Get (0));
-  apps.Start (Seconds (6.0));
-  apps.Stop (Seconds (20.0));
+    //flow1 1-->6
+    BulkSendHelper bulksend ("ns3::UdpSocketFactory", InetSocketAddress (i56.GetAddress (1), port));
+    //bulksend.SetAttribute(sendsizeattr, AttributeValue( ConstantVariable(2560)));
+    bulksend0.SetAttribute("MaxBytes", UintegerValue(2560));
+    apps = bulksend.Install (c.Get (0));
+    apps.Start (Seconds (6.0));
+    apps.Stop (Seconds (20.0));
   
-  // Create a packet sink to receive these packets
-  PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port));
-  apps = sink.Install (c.Get (5));
-  apps.Start(Seconds(0.0));
-  apps.Stop(Seconds(20.0));
+    // Create a packet sink to receive these packets
+    PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port));
+    apps = sink.Install (c.Get (5));
+    apps.Start(Seconds(0.0));
+    apps.Stop(Seconds(20.0));
   
-  AsciiTraceHelper ascii;
-  p2p.EnableAsciiAll (ascii.CreateFileStream ("sync-topology-ndnabstraction.tr"));
-  p2p.EnablePcapAll ("sync-topology-ndnabstraction");*/
+    AsciiTraceHelper ascii;
+    p2p.EnableAsciiAll (ascii.CreateFileStream ("sync-topology-ndnabstraction.tr"));
+    p2p.EnablePcapAll ("sync-topology-ndnabstraction");*/
   
   Simulator::Stop (Seconds (2000));
   
@@ -224,5 +222,5 @@
   Simulator::Destroy ();
   NS_LOG_INFO ("Done.");
   
-	return 0;
+  return 0;
 }
diff --git a/helper/ccnb-parser/ccnb-parser-common.h b/helper/ccnb-parser/ccnb-parser-common.h
index 847a6b8..528bcb0 100644
--- a/helper/ccnb-parser/ccnb-parser-common.h
+++ b/helper/ccnb-parser/ccnb-parser-common.h
@@ -168,8 +168,7 @@
   CCN_DTAG_StatusResponse = 112,
   CCN_DTAG_StatusCode = 113,
   CCN_DTAG_StatusText = 114,
-  NDN_DTAG_Nack = 115,
-  NDN_DTAG_Congested = 116,
+  CCN_DTAG_Nack = 200,
   CCN_DTAG_SequenceNumber = 256,
   CCN_DTAG_CCNProtocolDataUnit = 17702112
 };
diff --git a/helper/ccnb-parser/syntax-tree/ccnb-parser-base-tag.h b/helper/ccnb-parser/syntax-tree/ccnb-parser-base-tag.h
index 6b7fe76..15310a5 100644
--- a/helper/ccnb-parser/syntax-tree/ccnb-parser-base-tag.h
+++ b/helper/ccnb-parser/syntax-tree/ccnb-parser-base-tag.h
@@ -39,7 +39,7 @@
 public:
   std::list<Ptr<Block> > m_attrs;      ///< \brief List of attributes, associated with this tag
   std::list<Ptr<Block> > m_nestedTags; ///< \brief List of nested tags
-
+  
 protected:
   /**
    * \brief Default constructor
diff --git a/helper/ccnb-parser/syntax-tree/ccnb-parser-block.cc b/helper/ccnb-parser/syntax-tree/ccnb-parser-block.cc
index d0f795f..29e3fac 100644
--- a/helper/ccnb-parser/syntax-tree/ccnb-parser-block.cc
+++ b/helper/ccnb-parser/syntax-tree/ccnb-parser-block.cc
@@ -28,6 +28,10 @@
 #include "ccnb-parser-dattr.h"
 #include "ccnb-parser-ext.h"
 
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CcnbParserBlock");
+
 namespace ns3 {
 namespace CcnbParser {
 
@@ -57,7 +61,7 @@
   
   value <<= 4;
   value += ( (byte&(~CCN_TT_HBIT)) >> 3);
-
+  
   /**
    * Huh. After fighting with NS-3, it became apparent that Create<T>(...) construct
    * doesn't work with references.  Just simply doesn't work.  wtf?
@@ -65,23 +69,27 @@
   switch (byte & CCN_TT_MASK)
     {
     case CCN_BLOB:
-      return Ptr<Blob> (new Blob(start, value));
+      return Ptr<Blob> (new Blob(start, value), false);
     case CCN_UDATA:
-      return Ptr<Udata> (new Udata(start, value));
+      return Ptr<Udata> (new Udata(start, value), false);
     case CCN_TAG:
-      return Ptr<Tag> (new Tag(start, value));
+      return Ptr<Tag> (new Tag(start, value), false);
     case CCN_ATTR:
-      return Ptr<Attr> (new Attr(start, value));
+      return Ptr<Attr> (new Attr(start, value), false);
     case CCN_DTAG:
-      return Ptr<Dtag> (new Dtag(start, value));
+      return Ptr<Dtag> (new Dtag(start, value), false);
     case CCN_DATTR:
-      return Ptr<Dattr> (new Dattr(start, value));
+      return Ptr<Dattr> (new Dattr(start, value), false);
     case CCN_EXT:
-      return Ptr<Ext> (new Ext(start, value));
+      return Ptr<Ext> (new Ext(start, value), false);
     default:
       throw CcnbDecodingException ();
     }
 }
 
+Block::~Block ()
+{
+}
+
 }
 }
diff --git a/helper/ccnb-parser/syntax-tree/ccnb-parser-block.h b/helper/ccnb-parser/syntax-tree/ccnb-parser-block.h
index 59ccf02..a188597 100644
--- a/helper/ccnb-parser/syntax-tree/ccnb-parser-block.h
+++ b/helper/ccnb-parser/syntax-tree/ccnb-parser-block.h
@@ -56,6 +56,8 @@
    */
   static Ptr<Block>
   ParseBlock (Buffer::Iterator &start);
+
+  virtual ~Block ();
   
   virtual void accept( VoidNoArguVisitor &v )               = 0;
   virtual void accept( VoidVisitor &v, boost::any param )   = 0;
diff --git a/helper/ccnb-parser/visitors/ccnb-parser-interest-visitor.cc b/helper/ccnb-parser/visitors/ccnb-parser-interest-visitor.cc
index 992fae5..c436923 100644
--- a/helper/ccnb-parser/visitors/ccnb-parser-interest-visitor.cc
+++ b/helper/ccnb-parser/visitors/ccnb-parser-interest-visitor.cc
@@ -34,6 +34,10 @@
 
 #include <boost/foreach.hpp>
 
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CcnbParserInterestVisitor");
+
 namespace ns3 {
 namespace CcnbParser {
 
@@ -50,10 +54,12 @@
   static NonceVisitor              nonceVisitor;
   
   CcnxInterestHeader &interest = *(boost::any_cast<CcnxInterestHeader*> (param));
-  
+
   switch (n.m_dtag)
     {
     case CCN_DTAG_Interest:
+      NS_LOG_DEBUG ("Interest");
+  
       // process nested blocks
       BOOST_FOREACH (Ptr<Block> block, n.m_nestedTags)
         {
@@ -62,6 +68,8 @@
       break;
     case CCN_DTAG_Name:
       {
+        NS_LOG_DEBUG ("Name");
+
         // process name components
         Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
         
@@ -73,6 +81,7 @@
         break;
       }
     case CCN_DTAG_MinSuffixComponents:
+      NS_LOG_DEBUG ("MinSuffixComponents");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
       interest.SetMinSuffixComponents (
@@ -82,6 +91,7 @@
                                                                            )));
       break;
     case CCN_DTAG_MaxSuffixComponents:
+      NS_LOG_DEBUG ("MaxSuffixComponents");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
       interest.SetMaxSuffixComponents (
@@ -92,6 +102,7 @@
       break;
     case CCN_DTAG_Exclude:
       {
+        NS_LOG_DEBUG ("Exclude");
         // process exclude components
         Ptr<CcnxNameComponents> exclude = Create<CcnxNameComponents> ();
         
@@ -103,6 +114,7 @@
         break;
       }
     case CCN_DTAG_ChildSelector:
+      NS_LOG_DEBUG ("ChildSelector");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
 
@@ -113,6 +125,7 @@
                                                                            )));
       break;
     case CCN_DTAG_AnswerOriginKind:
+      NS_LOG_DEBUG ("AnswerOriginKind");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
       interest.SetAnswerOriginKind (
@@ -122,6 +135,7 @@
                                                                            )));
       break;
     case CCN_DTAG_Scope: 
+      NS_LOG_DEBUG ("Scope");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
       interest.SetScope (
@@ -131,16 +145,18 @@
                                                                            )));
       break;
     case CCN_DTAG_InterestLifetime:
+      NS_LOG_DEBUG ("InterestLifetime");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
 
       interest.SetInterestLifetime (
                boost::any_cast<Time> (
-                                          (*n.m_nestedTags.begin())->accept(
-                                                                           timestampVisitor
-                                                                           )));
+                                      (*n.m_nestedTags.begin())->accept(
+                                                                        timestampVisitor
+                                                                        )));
       break;
     case CCN_DTAG_Nonce:
+      NS_LOG_DEBUG ("Nonce");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
 
@@ -152,22 +168,14 @@
       break;
     
             
-    case NDN_DTAG_Nack:
+    case CCN_DTAG_Nack:
+      NS_LOG_DEBUG ("Nack");
       if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
         throw CcnbDecodingException ();
             
       interest.SetNack (
-              1 == boost::any_cast<uint32_t> (
-                      (*n.m_nestedTags.begin())->accept(nonNegativeIntegerVisitor)));
-      break;
-            
-    case NDN_DTAG_Congested:
-      if (n.m_nestedTags.size()!=1) // should be exactly one UDATA inside this tag
-        throw CcnbDecodingException ();
-            
-      interest.SetCongested (
-              1 == boost::any_cast<uint32_t> (
-                      (*n.m_nestedTags.begin())->accept(nonNegativeIntegerVisitor)));
+               boost::any_cast<uint32_t> (
+                                          (*n.m_nestedTags.begin())->accept(nonNegativeIntegerVisitor)));
       break;
     }
 }
diff --git a/helper/ccnb-parser/visitors/ccnb-parser-no-argu-visitor.h b/helper/ccnb-parser/visitors/ccnb-parser-no-argu-visitor.h
index 6f6bcc2..ce3e712 100644
--- a/helper/ccnb-parser/visitors/ccnb-parser-no-argu-visitor.h
+++ b/helper/ccnb-parser/visitors/ccnb-parser-no-argu-visitor.h
@@ -44,6 +44,8 @@
   virtual boost::any visit (Dtag& )=0; ///< \brief Method accepting DTAG block  
   virtual boost::any visit (Dattr&)=0; ///< \brief Method accepting DATTR block 
   virtual boost::any visit (Ext&  )=0; ///< \brief Method accepting EXT block
+
+  virtual ~NoArguVisitor () { }
 };
   
 }
diff --git a/helper/ccnb-parser/visitors/ccnb-parser-timestamp-visitor.cc b/helper/ccnb-parser/visitors/ccnb-parser-timestamp-visitor.cc
index 22965aa..ea4ab00 100644
--- a/helper/ccnb-parser/visitors/ccnb-parser-timestamp-visitor.cc
+++ b/helper/ccnb-parser/visitors/ccnb-parser-timestamp-visitor.cc
@@ -44,7 +44,6 @@
     }
   uint8_t combo = start[n.m_blobSize-2]; // 4 most significant bits hold 4 least significant bits of number of seconds
   seconds = (seconds << 4) | (combo >> 4);
-  std::cout << std::hex << (int) start[n.m_blobSize-2] << "\n";
 
   nanoseconds = combo & 0x0F; /*00001111*/ // 4 least significant bits hold 4 most significant bits of number of
   nanoseconds = (nanoseconds << 8) | start[n.m_blobSize-1];
diff --git a/helper/ccnb-parser/visitors/ccnb-parser-visitor.h b/helper/ccnb-parser/visitors/ccnb-parser-visitor.h
index 24212d4..e0fac3a 100644
--- a/helper/ccnb-parser/visitors/ccnb-parser-visitor.h
+++ b/helper/ccnb-parser/visitors/ccnb-parser-visitor.h
@@ -44,6 +44,8 @@
   virtual boost::any visit (Dtag&,  boost::any)=0; ///< \brief Method accepting DTAG block  
   virtual boost::any visit (Dattr&, boost::any)=0; ///< \brief Method accepting DATTR block 
   virtual boost::any visit (Ext&,   boost::any)=0; ///< \brief Method accepting EXT block
+
+  virtual ~Visitor () { }
 };                                                
                                                   
 }                                                 
diff --git a/helper/ccnb-parser/visitors/ccnb-parser-void-no-argu-visitor.h b/helper/ccnb-parser/visitors/ccnb-parser-void-no-argu-visitor.h
index 975c0c6..ad0ff74 100644
--- a/helper/ccnb-parser/visitors/ccnb-parser-void-no-argu-visitor.h
+++ b/helper/ccnb-parser/visitors/ccnb-parser-void-no-argu-visitor.h
@@ -43,6 +43,8 @@
   virtual void visit (Dtag& )=0; ///< \brief Method accepting DTAG block
   virtual void visit (Dattr&)=0; ///< \brief Method accepting DATTR block
   virtual void visit (Ext&  )=0; ///< \brief Method accepting EXT block
+
+  virtual ~VoidNoArguVisitor () { }
 };
   
 }
diff --git a/helper/ccnb-parser/visitors/ccnb-parser-void-visitor.h b/helper/ccnb-parser/visitors/ccnb-parser-void-visitor.h
index 9b45836..4fd228d 100644
--- a/helper/ccnb-parser/visitors/ccnb-parser-void-visitor.h
+++ b/helper/ccnb-parser/visitors/ccnb-parser-void-visitor.h
@@ -44,6 +44,8 @@
   virtual void visit (Dtag&,  boost::any)=0; ///< \brief Method accepting DTAG block  
   virtual void visit (Dattr&, boost::any)=0; ///< \brief Method accepting DATTR block 
   virtual void visit (Ext&,   boost::any)=0; ///< \brief Method accepting EXT block
+
+  virtual ~VoidVisitor () { }
 };
 
 }
diff --git a/helper/ccnx-decoding-helper.cc b/helper/ccnx-decoding-helper.cc
index 52061ab..408190b 100644
--- a/helper/ccnx-decoding-helper.cc
+++ b/helper/ccnx-decoding-helper.cc
@@ -29,6 +29,10 @@
 
 #include "ns3/ccnb-parser-dtag.h"
 
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("CcnxDecodingHelper");
+
 namespace ns3 {
 
 size_t
@@ -39,7 +43,7 @@
   Buffer::Iterator i = start;
   Ptr<CcnbParser::Block> root = CcnbParser::Block::ParseBlock (i);
   root->accept (interestVisitor, &interest);
-
+  
   return i.GetDistanceFrom (start);
 }
 
diff --git a/helper/ccnx-encoding-helper.cc b/helper/ccnx-encoding-helper.cc
index 20ea101..15757fc 100644
--- a/helper/ccnx-encoding-helper.cc
+++ b/helper/ccnx-encoding-helper.cc
@@ -78,7 +78,7 @@
   if (!interest.GetInterestLifetime().IsZero())
     {
       written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_InterestLifetime, CcnbParser::CCN_DTAG);
-      written += AppendTimestampBlob (start, interest.GetInterestLifetime());
+      written += AppendTimestampBlob (start, interest.GetInterestLifetime ());
       written += AppendCloser (start);
     }
   if (interest.GetNonce()>0)
@@ -89,16 +89,10 @@
                                    sizeof(nonce));
     }
     
-  if (interest.IsNack ())
+  if (interest.GetNack ()>0)
     {
-      written += AppendBlockHeader (start, CcnbParser::NDN_DTAG_Nack, CcnbParser::CCN_DTAG);
-      written += AppendNumber (start, 1);
-      written += AppendCloser (start);
-    }
-  if (interest.IsCongested ())
-    {
-      written += AppendBlockHeader (start, CcnbParser::NDN_DTAG_Congested, CcnbParser::CCN_DTAG);
-      written += AppendNumber (start, 1);
+      written += AppendBlockHeader (start, CcnbParser::CCN_DTAG_Nack, CcnbParser::CCN_DTAG);
+      written += AppendNumber (start, interest.GetNack ());
       written += AppendCloser (start);
     }
   written += AppendCloser (start); // </Interest>
@@ -162,16 +156,10 @@
     {
       written += EstimateTaggedBlob (CcnbParser::CCN_DTAG_Nonce, sizeof(uint32_t));
     }
-  if (interest.IsNack () )
+  if (interest.GetNack ()>0)
     {
-        written += EstimateBlockHeader (CcnbParser::NDN_DTAG_Nack);
-        written += EstimateNumber (1);
-        written += 1;
-    }
-  if (interest.IsCongested () )
-    {
-        written += EstimateBlockHeader (CcnbParser::NDN_DTAG_Congested);
-        written += EstimateNumber (1);
+        written += EstimateBlockHeader (CcnbParser::CCN_DTAG_Nack);
+        written += EstimateNumber (interest.GetNack ());
         written += 1;
     }
 
diff --git a/helper/ccnx-forwarding-helper.cc b/helper/ccnx-forwarding-helper.cc
index 6a8d3fb..0e74e97 100644
--- a/helper/ccnx-forwarding-helper.cc
+++ b/helper/ccnx-forwarding-helper.cc
@@ -26,43 +26,11 @@
 #include "ccnx-forwarding-helper.h"
 
 namespace ns3 {
-
-CcnxForwardingHelper::CcnxForwardingHelper()
-{
-    m_strategy = Ccnx::NDN_FLOODING;
-}
     
-CcnxForwardingHelper::CcnxForwardingHelper(Ccnx::ForwardingStrategy strategy)
+CcnxForwardingHelper::CcnxForwardingHelper ()
 {
-    m_strategy = strategy;
 }
 
-CcnxForwardingHelper::~CcnxForwardingHelper ()
-{
-   
-}
-
-void 
-CcnxForwardingHelper::SetForwarding(Ptr<Ccnx> ccnx, Ptr<CcnxPit> pit) const
-{
-    if(m_strategy == Ccnx::NDN_FLOODING)
-    {
-        Ptr<CcnxFloodingStrategy> ccnxForwarding = CreateObject<CcnxFloodingStrategy> ();
-        //ccnxForwarding->SetCcnx(ccnx);
-        ccnxForwarding->SetPit(pit);
-        ccnx->SetForwardingStrategy (ccnxForwarding);
-    }
-    else if(m_strategy == Ccnx::NDN_BESTROUTE)
-    {
-        Ptr<CcnxBestRouteStrategy> ccnxForwarding = CreateObject<CcnxBestRouteStrategy> ();
-        //ccnxForwarding->SetCcnx(ccnx);
-        ccnxForwarding->SetPit(pit);
-        ccnx->SetForwardingStrategy (ccnxForwarding);
-    }
-    else if (m_strategy == Ccnx::NDN_RANKING)
-    {}
-}
-    
 // void
 // CcnxForwardingHelper::PrintForwardingTableAllAt (Time printTime, Ptr<OutputStreamWrapper> stream) const
 // {
diff --git a/helper/ccnx-forwarding-helper.h b/helper/ccnx-forwarding-helper.h
index fe9f9d4..5a59381 100644
--- a/helper/ccnx-forwarding-helper.h
+++ b/helper/ccnx-forwarding-helper.h
@@ -42,77 +42,60 @@
 class CcnxForwardingHelper
 {
 public:
-    
   /*
-   * \brief Default constructor, which sets NDN_FLOODING forwarding strategy
+   * \brief Default constructor
    */
   CcnxForwardingHelper();
-  
-  /*
-   * \brief This constructor sets a specified forwarding strategy 
-   */
-  CcnxForwardingHelper(Ccnx::ForwardingStrategy strategy);
-  
-  /*
-   * Destroy an instance of an CcnxForwardingHelper
-   */
-  ~CcnxForwardingHelper ();
-
-  /*
-   * \brief creates a specified ForwardingStrategy object and binds it to Pit
-   */
-  void SetForwarding(Ptr<Ccnx> ccnx, Ptr<CcnxPit> pit) const;
     
-  /**
-   * \brief prints the forwarding tables of all nodes at a particular time.
-   * \param printTime the time at which the forwarding table is supposed to be printed.
-   * \param stream The output stream object to use 
-   *
-   * This method calls the PrintForwardingTable() method of the 
-   * CcnxForwardingStrategy stored in the Ccnx object, for all nodes at the
-   * specified time; the output format is forwarding protocol-specific.
-   */
-  void PrintForwardingTableAllAt (Time printTime, Ptr<OutputStreamWrapper> stream) const;
+  // /**
+  //  * \brief prints the forwarding tables of all nodes at a particular time.
+  //  * \param printTime the time at which the forwarding table is supposed to be printed.
+  //  * \param stream The output stream object to use 
+  //  *
+  //  * This method calls the PrintForwardingTable() method of the 
+  //  * CcnxForwardingStrategy stored in the Ccnx object, for all nodes at the
+  //  * specified time; the output format is forwarding protocol-specific.
+  //  */
+  // void PrintForwardingTableAllAt (Time printTime, Ptr<OutputStreamWrapper> stream) const;
 
-  /**
-   * \brief prints the forwarding tables of all nodes at regular intervals specified by user.
-   * \param printInterval the time interval for which the forwarding table is supposed to be printed.
-   * \param stream The output stream object to use
-   *
-   * This method calls the PrintForwardingTable() method of the 
-   * CcnxForwardingStrategy stored in the Ccnx object, for all nodes at the
-   * specified time interval; the output format is forwarding protocol-specific.
-   */
-  void PrintForwardingTableAllEvery (Time printInterval, Ptr<OutputStreamWrapper> stream) const;
+  // /**
+  //  * \brief prints the forwarding tables of all nodes at regular intervals specified by user.
+  //  * \param printInterval the time interval for which the forwarding table is supposed to be printed.
+  //  * \param stream The output stream object to use
+  //  *
+  //  * This method calls the PrintForwardingTable() method of the 
+  //  * CcnxForwardingStrategy stored in the Ccnx object, for all nodes at the
+  //  * specified time interval; the output format is forwarding protocol-specific.
+  //  */
+  // void PrintForwardingTableAllEvery (Time printInterval, Ptr<OutputStreamWrapper> stream) const;
 
-  /**
-   * \brief prints the forwarding tables of a node at a particular time.
-   * \param printTime the time at which the forwarding table is supposed to be printed.
-   * \param node The node ptr for which we need the forwarding table to be printed
-   * \param stream The output stream object to use
-   *
-   * This method calls the PrintForwardingTable() method of the 
-   * CcnxForwardingStrategy stored in the Ccnx object, for the selected node 
-   * at the specified time; the output format is forwarding protocol-specific.
-   */
-  void PrintForwardingTableAt (Time printTime, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
+  // /**
+  //  * \brief prints the forwarding tables of a node at a particular time.
+  //  * \param printTime the time at which the forwarding table is supposed to be printed.
+  //  * \param node The node ptr for which we need the forwarding table to be printed
+  //  * \param stream The output stream object to use
+  //  *
+  //  * This method calls the PrintForwardingTable() method of the 
+  //  * CcnxForwardingStrategy stored in the Ccnx object, for the selected node 
+  //  * at the specified time; the output format is forwarding protocol-specific.
+  //  */
+  // void PrintForwardingTableAt (Time printTime, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
 
-  /**
-   * \brief prints the forwarding tables of a node at regular intervals specified by user.
-   * \param printInterval the time interval for which the forwarding table is supposed to be printed.
-   * \param node The node ptr for which we need the forwarding table to be printed
-   * \param stream The output stream object to use
-   *
-   * This method calls the PrintForwardingTable() method of the 
-   * CcnxForwardingStrategy stored in the Ccnx object, for the selected node 
-   * at the specified interval; the output format is forwarding protocol-specific.
-   */
-  void PrintForwardingTableEvery (Time printInterval, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
+  // /**
+  //  * \brief prints the forwarding tables of a node at regular intervals specified by user.
+  //  * \param printInterval the time interval for which the forwarding table is supposed to be printed.
+  //  * \param node The node ptr for which we need the forwarding table to be printed
+  //  * \param stream The output stream object to use
+  //  *
+  //  * This method calls the PrintForwardingTable() method of the 
+  //  * CcnxForwardingStrategy stored in the Ccnx object, for the selected node 
+  //  * at the specified interval; the output format is forwarding protocol-specific.
+  //  */
+  // void PrintForwardingTableEvery (Time printInterval, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
 
 private:
-  Ccnx::ForwardingStrategy m_strategy;
-  void Print (Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
-  void PrintEvery (Time printInterval, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
+  // void Print (Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
+  // void PrintEvery (Time printInterval, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const;
 };
 
 } // namespace ns3
diff --git a/helper/ccnx-stack-helper.cc b/helper/ccnx-stack-helper.cc
index f8f0405..d9f9d6b 100644
--- a/helper/ccnx-stack-helper.cc
+++ b/helper/ccnx-stack-helper.cc
@@ -71,11 +71,14 @@
 #include "ns3/ccnx-l3-protocol.h"
 #include "ns3/ccnx-fib.h"
 #include "ns3/node-list.h"
-#include "ns3/ipv4.h"
-#include "ns3/ipv4-routing-helper.h"
-#include "ns3/ipv4-global-routing-ordered-nexthops.h"
+#include "ns3/loopback-net-device.h"
 #include "ns3/global-router-interface.h"
+#include "ns3/ipv4.h"
+#include "ns3/ipv4-global-routing.h"
+#include "ns3/ipv4-global-routing-ordered-nexthops.h"
+#include "ns3/ipv4-routing-helper.h"
 #include "ns3/ipv4-global-routing-helper.h"
+#include "ns3/data-rate.h"
 
 #include "ccnx-face-container.h"
 #include "ccnx-stack-helper.h"
@@ -85,6 +88,8 @@
 #include <map>
 #include <boost/foreach.hpp>
 
+#define NDN_DEFAULT_DATA_SIZE      1024
+
 NS_LOG_COMPONENT_DEFINE ("CcnxStackHelper");
 
 namespace ns3 {
@@ -112,47 +117,37 @@
 // 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;
+// 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 */
+// 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_forwardingHelper (Ccnx::NDN_FLOODING)
 {
-}
-    
-CcnxStackHelper::CcnxStackHelper (Ccnx::ForwardingStrategy strategy)
-    : m_forwardingHelper (strategy)
-{
+  m_strategyFactory.SetTypeId ("ns3::CcnxFloodingStrategy");
 }
     
 CcnxStackHelper::~CcnxStackHelper ()
 {
 }
 
-CcnxStackHelper::CcnxStackHelper (const CcnxStackHelper &o)
-{
-}
-
-CcnxStackHelper &
-CcnxStackHelper::operator = (const CcnxStackHelper &o)
-{
-  if (this == &o)
-    {
-      return *this;
-    }
-  return *this;
-}
-
 void 
-CcnxStackHelper::SetForwardingStrategy (Ccnx::ForwardingStrategy strategy)
+CcnxStackHelper::SetForwardingStrategy (std::string strategy)
 {
-  CcnxForwardingHelper newForwardingHelper (strategy);
-  m_forwardingHelper = newForwardingHelper;
+  m_strategyFactory.SetTypeId (strategy);
+}
+
+void
+CcnxStackHelper::EnableLimits (bool enable/* = true*/, Time avgRtt/*=Seconds(0.1)*/, uint32_t avgContentObject/*=1100*/, uint32_t avgInterest/*=40*/)
+{
+  NS_LOG_INFO ("EnableLimits: " << enable);
+  m_limitsEnabled = enable;
+  m_avgContentObjectSize = avgContentObject;
+  m_avgInterestSize = avgInterest;
+  m_avgRtt = avgRtt;
 }
 
 Ptr<CcnxFaceContainer>
@@ -172,15 +167,6 @@
   return Install (NodeContainer::GetGlobal ());
 }
 
-// void
-// CcnxStackHelper::CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId)
-// {
-//   ObjectFactory factory;
-//   factory.SetTypeId (typeId);
-//   Ptr<Object> protocol = factory.Create <Object> ();
-//   node->AggregateObject (protocol);
-// }
-
 Ptr<CcnxFaceContainer>
 CcnxStackHelper::Install (Ptr<Node> node) const
 {
@@ -200,42 +186,50 @@
   Ptr<CcnxL3Protocol> ccnx = CreateObject<CcnxL3Protocol> ();
   node->AggregateObject (ccnx);
 
-  Ptr<CcnxPit> pit = ccnx->GetPit();
-  NS_LOG_INFO("NODE->GetNDevices()="<<node->GetNDevices());
-    
+  ccnx->SetForwardingStrategy
+    (DynamicCast<CcnxForwardingStrategy> (m_strategyFactory.Create<Object> ()));
+  
   for (uint32_t index=0; index < node->GetNDevices (); index++)
     {
-      Ptr<PointToPointNetDevice> device = DynamicCast<PointToPointNetDevice>(node->GetDevice(index));
-      if(device == 0)
-        continue;
-        
-      Ptr<CcnxNetDeviceFace> face = Create<CcnxNetDeviceFace> (node->GetDevice (index));
-      face->SetNode (node);
+      Ptr<NetDevice> device = node->GetDevice (index);
+      if (DynamicCast<LoopbackNetDevice> (device) != 0)
+        continue; // don't create face for a LoopbackNetDevice
+
+      Ptr<CcnxNetDeviceFace> face = Create<CcnxNetDeviceFace> (node, device);
+
       uint32_t __attribute__ ((unused)) face_id = ccnx->AddFace (face);
       NS_LOG_LOGIC ("Node " << node->GetId () << ": added CcnxNetDeviceFace as face #" << face_id);
-      // Setup bucket filtering
-      // Assume that we know average data packet size, and this size is equal default size
-      // Set maximum buckets (averaging over 1 second)
+
+      if (m_limitsEnabled)
+        {
+          NS_LOG_INFO ("Limits are enabled");
+          Ptr<PointToPointNetDevice> p2p = DynamicCast<PointToPointNetDevice> (device);
+          if (p2p == 0)
+            {
+              NS_LOG_INFO ("Non p2p interface");
+              continue; // only PointToPointNetDevice supports limits
+            }
+
+          // Setup bucket filtering
+          // Assume that we know average data packet size, and this size is equal default size
+          // Set maximum buckets (averaging over 1 second)
       
-      DataRateValue dataRate;
-      device->GetAttribute ("DataRate", dataRate);
-      NS_LOG_INFO("DataRate for this link is " << dataRate.Get());
-      pit->maxBucketsPerFace[face->GetId()] = 0.1 * dataRate.Get().GetBitRate () /(NDN_DEFAULT_DATA_SIZE + sizeof(CcnxInterestHeader));
-      NS_LOG_INFO("maxBucketsPerFace["<<face->GetId()<<"] = " << pit->maxBucketsPerFace[face->GetId()]); 
-      pit->leakSize[face->GetId()] = 0.97 * NDN_INTEREST_RESET_PERIOD / SECOND * dataRate.Get().GetBitRate () / (NDN_DEFAULT_DATA_SIZE + sizeof(CcnxInterestHeader));
-      NS_LOG_INFO("pit->leakSize["<<face->GetId()<<"] = " << pit->leakSize[face->GetId()]);
+          DataRateValue dataRate; device->GetAttribute ("DataRate", dataRate);
+          
+          NS_LOG_INFO("DataRate for this link is " << dataRate.Get());
+
+          double maxInterestPackets = 1.0  * dataRate.Get ().GetBitRate () / 8.0 / m_avgContentObjectSize;
+          NS_LOG_INFO ("BucketMax: " << maxInterestPackets);
+
+          // Set bucket max to BDP
+          face->SetBucketMax (m_avgRtt.ToDouble (Time::S) * maxInterestPackets); // number of interests allowed
+          face->SetBucketLeak (maxInterestPackets);
+        }
         
-        
-      if(face->IsLocal()==true)
-        NS_LOG_INFO("Face #" << face_id << " is turned on");
       face->SetUp ();
       faces->Add (face);
     }
     
-  m_forwardingHelper.SetForwarding (ccnx, pit);
-
-  ccnx->ScheduleLeakage ();
-    
   return faces;
 }
 
@@ -274,10 +268,10 @@
   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);
+  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");
         
@@ -289,259 +283,259 @@
   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);
+// 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;
-    }
+//   //
+//   // 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);
-}
+//   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;
-}
+// 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);
+// 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;
+//   //
+//   // 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);
-    }
+//   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);
+//   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");
+//   //
+//   // 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\"");
+//       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;
-    }
+//       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;
-}
+//   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;
-    }
+// 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;
-}
+//   *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;
-    }
+// 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;
-}
+//   *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;
-}
+// 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 ();
+// 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;
+//   //
+//   // 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);
-        }
+//       std::string filename;
+//       if (explicitFilename)
+//         {
+//           filename = prefix;
+//         }
+//       else
+//         {
+//           filename = asciiTraceHelper.GetFilenameFromInterfacePair (prefix, ccnx, face);
+//         }
 
-      Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
+//       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\"");
-        }
+//       //
+//       // 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;
-    }
+//       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;
+//   //
+//   // 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));
-    }
+//       //
+//       // 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;
-}
+//   g_faceStreamMapCcnx[std::make_pair (ccnx, face)] = stream;
+// }
 
 void
 CcnxStackHelper::InstallFakeGlobalRoutes ()
@@ -556,7 +550,7 @@
       NS_ASSERT_MSG (Ipv4RoutingHelper::GetRouting<Ipv4GlobalRoutingOrderedNexthops>
                      (
                       (*node)->GetObject<Ipv4> ()->GetRoutingProtocol ()
-                     ),
+                      ),
                      "InternetStack should have Ipv4GlobalRoutingOrderedNexthops as routing protocol");
       // Example:
       //
diff --git a/helper/ccnx-stack-helper.h b/helper/ccnx-stack-helper.h
index 1a76201..ee166fc 100644
--- a/helper/ccnx-stack-helper.h
+++ b/helper/ccnx-stack-helper.h
@@ -29,8 +29,8 @@
 #include "ccnx-trace-helper.h"
 #include "ns3/ccnx-forwarding-helper.h"
 #include "ns3/ccnx.h"
-#include "ns3/data-rate.h"
 #include "ns3/ccnx-interest-header.h"
+#include "ns3/nstime.h"
 
 namespace ns3 {
 
@@ -58,7 +58,7 @@
  * attribute or a set of functionality that may be of interest to many other
  * classes.
  */
-class CcnxStackHelper : public PcapHelperForCcnx, public AsciiTraceHelperForCcnx
+class CcnxStackHelper //: public PcapHelperForCcnx, public AsciiTraceHelperForCcnx
 {
 public:
   /**
@@ -67,19 +67,12 @@
   CcnxStackHelper();
   
   /**
-   * \brief Create a new CcnxStackHelper with a specified forwarding strategy
-   */
-  CcnxStackHelper (Ccnx::ForwardingStrategy);
-
-  /**
    * \brief Destroy the CcnxStackHelper
    */
   virtual ~CcnxStackHelper ();
-  CcnxStackHelper (const CcnxStackHelper &);
-  CcnxStackHelper &operator = (const CcnxStackHelper &o);
 
   /**
-   * Set forwarding strategy helper
+   * @brief Set forwarding strategy helper
    *
    * \param forwarding a new forwarding helper
    *
@@ -89,9 +82,20 @@
    * a single ns3::Ccnx object through its ns3::Ccnx::SetforwardingProtocol.
    */
   void
-  SetForwardingStrategy (Ccnx::ForwardingStrategy strategy);
+  SetForwardingStrategy (std::string forwardingStrategy);
 
   /**
+   * @brief Enable Interest limits (disabled by default)
+   *
+   * @param enable           Enable or disable limits
+   * @param avgRtt           Average RTT
+   * @param avgContentObject Average size of contentObject packets (including all headers)
+   * @param avgInterest      Average size of interest packets (including all headers)
+   */
+  void
+  EnableLimits (bool enable = true, Time avgRtt=Seconds(0.1), uint32_t avgContentObject=1100, uint32_t avgInterest=40);
+  
+  /**
    * \brief Install CCNx stack on the node
    *
    * This method will assert if called on a node that already has Ccnx object
@@ -192,58 +196,66 @@
    */
   void
   InstallRoutesToAll ();
+
+private:
+  CcnxStackHelper (const CcnxStackHelper &);
+  CcnxStackHelper &operator = (const CcnxStackHelper &o);
   
 private:
-   CcnxForwardingHelper m_forwardingHelper;
-    
-  /**
-   * @brief Enable pcap output the indicated Ccnx and interface pair.
-   * @internal
-   *
-   * @param prefix Filename prefix to use for pcap files.
-   * @param ccnx Ptr to the Ccnx interface on which you want to enable tracing.
-   * @param interface Interface ID on the Ccnx on which you want to enable tracing.
-   */
-  virtual void EnablePcapCcnxInternal (std::string prefix, 
-                                       Ptr<Ccnx> ccnx, 
-                                       uint32_t interface,
-                                       bool explicitFilename);
+  ObjectFactory m_strategyFactory;
+  bool m_limitsEnabled;
+  Time     m_avgRtt;
+  uint32_t m_avgContentObjectSize;
+  uint32_t m_avgInterestSize;
+  
+  // /**
+  //  * @brief Enable pcap output the indicated Ccnx and interface pair.
+  //  * @internal
+  //  *
+  //  * @param prefix Filename prefix to use for pcap files.
+  //  * @param ccnx Ptr to the Ccnx interface on which you want to enable tracing.
+  //  * @param interface Interface ID on the Ccnx on which you want to enable tracing.
+  //  */
+  // virtual void EnablePcapCcnxInternal (std::string prefix, 
+  //                                      Ptr<Ccnx> ccnx, 
+  //                                      uint32_t interface,
+  //                                      bool explicitFilename);
 
-  /**
-   * @brief Enable ascii trace output on the indicated Ccnx and interface pair.
-   * @internal
-   *
-   * @param stream An OutputStreamWrapper representing an existing file to use
-   *               when writing trace data.
-   * @param prefix Filename prefix to use for ascii trace files.
-   * @param ccnx Ptr to the Ccnx interface on which you want to enable tracing.
-   * @param interface Interface ID on the Ccnx on which you want to enable tracing.
-   */
-  virtual void EnableAsciiCcnxInternal (Ptr<OutputStreamWrapper> stream, 
-                                        std::string prefix, 
-                                        Ptr<Ccnx> ccnx, 
-                                        uint32_t interface,
-                                        bool explicitFilename);
+  // /**
+  //  * @brief Enable ascii trace output on the indicated Ccnx and interface pair.
+  //  * @internal
+  //  *
+  //  * @param stream An OutputStreamWrapper representing an existing file to use
+  //  *               when writing trace data.
+  //  * @param prefix Filename prefix to use for ascii trace files.
+  //  * @param ccnx Ptr to the Ccnx interface on which you want to enable tracing.
+  //  * @param interface Interface ID on the Ccnx on which you want to enable tracing.
+  //  */
+  // virtual void EnableAsciiCcnxInternal (Ptr<OutputStreamWrapper> stream, 
+  //                                       std::string prefix, 
+  //                                       Ptr<Ccnx> ccnx, 
+  //                                       uint32_t interface,
+  //                                       bool explicitFilename);
+
+  // // /**
+  // //  * \internal
+  // //  */
+  // // static void CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId);
 
   // /**
   //  * \internal
   //  */
-  // static void CreateAndAggregateObjectFromTypeId (Ptr<Node> node, const std::string typeId);
+  // static void Cleanup (void);
 
-  /**
-   * \internal
-   */
-  static void Cleanup (void);
+  // /**
+  //  * \internal
+  //  */
+  // bool PcapHooked (Ptr<Ccnx> ccnx);
 
-  /**
-   * \internal
-   */
-  bool PcapHooked (Ptr<Ccnx> ccnx);
-
-  /**
-   * \internal
-   */
-  bool AsciiHooked (Ptr<Ccnx> ccnx);
+  // /**
+  //  * \internal
+  //  */
+  // bool AsciiHooked (Ptr<Ccnx> ccnx);
 };
 
 } // namespace ns3
diff --git a/model/ccnx-bestroute-strategy.cc b/model/ccnx-bestroute-strategy.cc
index 625b6d7..b850d08 100644
--- a/model/ccnx-bestroute-strategy.cc
+++ b/model/ccnx-bestroute-strategy.cc
@@ -19,30 +19,31 @@
  */
 
 #include "ccnx-bestroute-strategy.h"
+#include "ccnx-interest-header.h"
+
 #include "ns3/assert.h"
+#include "ns3/log.h"
 
-#include "ccnx-route.h"
-
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
 
 NS_LOG_COMPONENT_DEFINE ("CcnxBestRouteStrategy");
-namespace __ccnx_private {
-    
-    struct CcnxFibFaceMetricByFace;
-}
 
 namespace ns3 
 {
-    
+
 using namespace __ccnx_private;
-    
+
 NS_OBJECT_ENSURE_REGISTERED (CcnxBestRouteStrategy);
   
 TypeId CcnxBestRouteStrategy::GetTypeId (void)
 {
   static TypeId tid = TypeId ("ns3::CcnxBestRouteStrategy")
-  .SetGroupName ("Ccnx")
-  .SetParent<Object> ()
-  ;
+    .SetGroupName ("Ccnx")
+    .SetParent <CcnxForwardingStrategy> ()
+    .AddConstructor <CcnxBestRouteStrategy> ()
+    ;
   return tid;
 }
     
@@ -50,50 +51,58 @@
 {
 }
     
-    
 bool
-CcnxBestRouteStrategy::PropagateInterest (CcnxPitEntryContainer::type::iterator pitEntry, 
-                                          CcnxFibEntryContainer::type::iterator fibEntry,
+CcnxBestRouteStrategy::PropagateInterest (const CcnxPitEntry  &pitEntry, 
                                           const Ptr<CcnxFace> &incomingFace,
                                           Ptr<CcnxInterestHeader> &header,
-                                          const Ptr<const Packet> &packet,
-                                          SendCallback ucb)
+                                          const Ptr<const Packet> &packet)
 {
-  //NS_LOG_FUNCTION(this);
-  //NS_LOG_INFO(*fibEntry);
-    
-  Ptr<CcnxFace> bestFace = fibEntry->FindBestCandidate(0);
-   
-  if( bestFace == NULL )
+  NS_LOG_FUNCTION (this);
+
+  // Try to work out with just green faces
+  bool greenOk = PropagateInterestViaGreen (pitEntry, incomingFace, header, packet);
+  if (greenOk)
+    return true;
+
+  int propagatedCount = 0;
+
+  BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry.m_fibEntry.m_faces.get<i_metric> ())
     {
-      return false;
+      if (metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_RED) // all non-read faces are in front
+        break;
+      
+      if (metricFace.m_face == incomingFace) 
+        continue; // same face as incoming, don't forward
+
+      if (pitEntry.m_incoming.find (metricFace.m_face) != pitEntry.m_incoming.end ()) 
+        continue; // don't forward to face that we received interest from
+
+      CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+        pitEntry.m_outgoing.find (metricFace.m_face);
+      
+      if (outgoing != pitEntry.m_outgoing.end () &&
+          outgoing->m_retxCount >= pitEntry.m_maxRetxCount)
+        {
+          continue; // already forwarded before during this retransmission cycle
+        }
+
+      bool faceAvailable = metricFace.m_face->IsBelowLimit ();
+      if (!faceAvailable) // huh...
+        {
+          continue;
+        }
+
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind(&CcnxPitEntry::AddOutgoing, ll::_1, metricFace.m_face));
+
+      metricFace.m_face->Send (packet->Copy ());
+      
+      propagatedCount++;
+      break; // do only once
     }
-  else
-    {
-      bool tryResult = GetPit ()->TryAddOutgoing (pitEntry, bestFace);
-      if (tryResult == false)
-      {
-          NS_LOG_INFO("!!!!!!!!!!!!!Trying different face!!!!!!!!!!!!!!!!");
-          for(uint32_t i = 1; i<fibEntry->m_faces.size(); i++ )
-          {
-            bestFace = fibEntry->FindBestCandidate(i);
-            tryResult = GetPit ()->TryAddOutgoing (pitEntry, bestFace);
-            if(tryResult == true)
-              break;
-              NS_LOG_INFO("Trying different face");
-          }
-          
-          if(tryResult == false)
-          {
-              NS_LOG_INFO("FAILURE");
-              return false;
-          }
-      }
-          
-      ucb (bestFace, header, packet->Copy());
-    }
-     
-  return true;
+
+  NS_LOG_INFO ("Propagated to " << propagatedCount << " faces");
+  return propagatedCount > 0;
 }
     
 } //namespace ns3
diff --git a/model/ccnx-bestroute-strategy.h b/model/ccnx-bestroute-strategy.h
index 8abaae9..f2d591b 100644
--- a/model/ccnx-bestroute-strategy.h
+++ b/model/ccnx-bestroute-strategy.h
@@ -22,14 +22,7 @@
 #ifndef CCNX_BESTROUTE_STRATEGY_H
 #define CCNX_BESTROUTE_STRATEGY_H
 
-#include "ns3/packet.h"
-#include "ns3/callback.h"
-#include "ns3/object.h"
-#include "ns3/log.h"
-
 #include "ccnx-forwarding-strategy.h"
-#include "ccnx.h"
-#include "ccnx-fib.h"
 
 namespace ns3 
 {
@@ -40,21 +33,25 @@
 /**
  * \ingroup ccnx
  * \brief Best route strategy
+ *
+ * \todo Describe
  */
-    
 class CcnxBestRouteStrategy : public CcnxForwardingStrategy
 {
 public:
-    static TypeId GetTypeId (void);
+  static TypeId GetTypeId (void);
+
+  /**
+   * @brief Default constructor
+   */
+  CcnxBestRouteStrategy ();
         
-    CcnxBestRouteStrategy ();
-        
-    bool PropagateInterest  (CcnxPitEntryContainer::type::iterator pitEntry,
-                             CcnxFibEntryContainer::type::iterator fibEntry,
-                             const Ptr<CcnxFace> &incomingFace,
-                             Ptr<CcnxInterestHeader> &header,
-                             const Ptr<const Packet> &packet,
-                             SendCallback ucb);
+  // inherited from  CcnxForwardingStrategy
+  virtual bool
+  PropagateInterest (const CcnxPitEntry  &pitEntry, 
+                     const Ptr<CcnxFace> &incomingFace,
+                     Ptr<CcnxInterestHeader> &header,
+                     const Ptr<const Packet> &packet);
 };
 
 } //namespace ns3
diff --git a/model/ccnx-content-store.cc b/model/ccnx-content-store.cc
index 110e7ac..4875386 100644
--- a/model/ccnx-content-store.cc
+++ b/model/ccnx-content-store.cc
@@ -150,7 +150,7 @@
 }
 
 
-Ptr<Packet>
+boost::tuple<Ptr<Packet>, Ptr<const CcnxContentObjectHeader> >
 CcnxContentStore::Lookup (Ptr<const CcnxInterestHeader> interest)
 {
   NS_LOG_FUNCTION_NOARGS ();
@@ -162,9 +162,9 @@
                                            m_contentStore.project<i_mru> (it));
 
       // return fully formed CCNx packet
-      return it->GetFullyFormedCcnxPacket ();
+      return boost::make_tuple (it->GetFullyFormedCcnxPacket (), it->GetHeader ());
     }
-  return 0;
+  return boost::tuple<Ptr<Packet>, Ptr<CcnxContentObjectHeader> > (0, 0);
 }   
     
 void 
diff --git a/model/ccnx-content-store.h b/model/ccnx-content-store.h
index 0bd8fb9..dd0f884 100644
--- a/model/ccnx-content-store.h
+++ b/model/ccnx-content-store.h
@@ -35,6 +35,7 @@
 #include <boost/multi_index/sequenced_index.hpp>
 #include <boost/multi_index/hashed_index.hpp>
 #include <boost/multi_index/mem_fun.hpp>
+#include <boost/tuple/tuple.hpp>
 
 #include "ccnx.h"
 #include "hash-helper.h"
@@ -173,7 +174,7 @@
    * If an entry is found, it is promoted to the top of most recent
    * used entries index, \see m_contentStore
    */
-  Ptr<Packet>
+  boost::tuple<Ptr<Packet>, Ptr<const CcnxContentObjectHeader> >
   Lookup (Ptr<const CcnxInterestHeader> interest);
             
   /**
diff --git a/model/ccnx-face.cc b/model/ccnx-face.cc
index 7821055..40ac57b 100644
--- a/model/ccnx-face.cc
+++ b/model/ccnx-face.cc
@@ -21,38 +21,34 @@
 
 #include "ccnx-face.h"
 
+#include "ns3/packet.h"
 #include "ns3/log.h"
 #include "ns3/node.h"
 #include "ns3/assert.h"
 
+#include <boost/ref.hpp>
+
 NS_LOG_COMPONENT_DEFINE ("CcnxFace");
 
 namespace ns3 {
 
-// NS_OBJECT_ENSURE_REGISTERED (CcnxFace);
-
-// TypeId 
-// CcnxFace::GetTypeId (void)
-// {
-//   static TypeId tid = TypeId ("ns3::CcnxFace")
-//     .SetGroupName ("Ccnx")
-//     .SetParent<Object> ()
-//   ;
-//   return tid;
-// }
-
 /** 
  * By default, Ccnx face are created in the "down" state
  *  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 (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)
 {
   NS_LOG_FUNCTION (this);
+
+  NS_ASSERT_MSG (node != 0, "node cannot be NULL. Check the code");
 }
 
 CcnxFace::~CcnxFace ()
@@ -69,19 +65,94 @@
   return *this;
 }
 
-  
-// void
-// CcnxFace::DoDispose (void)
-// {
-//   NS_LOG_FUNCTION_NOARGS ();
-//   m_node = 0;
-//   Object::DoDispose ();
-// }
-
-void 
-CcnxFace::SetNode (Ptr<Node> node)
+void
+CcnxFace::RegisterProtocolHandler (ProtocolHandler handler)
 {
-  m_node = node;
+  NS_LOG_FUNCTION_NOARGS ();
+
+  m_protocolHandler = handler;
+}
+
+bool
+CcnxFace::IsBelowLimit ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+
+  /// \todo Implement tracing, if requested
+  if (!IsUp ())
+    return false;
+  
+  if (m_bucketMax > 0)
+    {
+      //NS_LOG_DEBUG ("Limits enabled: " << m_bucketMax << ", current: " << m_bucket);
+      if (m_bucket+1.0 > m_bucketMax)
+        {
+          //NS_LOG_DEBUG ("Returning false");
+          return false;
+        }
+      
+      m_bucket += 1.0;
+    }
+
+  return true;
+}
+
+void
+CcnxFace::LeakBucket (const Time &interval)
+{
+  const double leak = m_bucketLeak * interval.ToDouble (Time::S);
+  m_bucket = std::max (0.0, m_bucket - leak);
+
+  // NS_LOG_DEBUG ("max: " << m_bucketMax << ", Current bucket: " << m_bucket << ", leak size: " << leak << ", interval: " << interval << ", " << m_bucketLeak);
+}
+
+void
+CcnxFace::SetBucketMax (double bucket)
+{
+  NS_LOG_FUNCTION (this << bucket);
+  m_bucketMax = bucket;
+}
+
+void
+CcnxFace::SetBucketLeak (double leak)
+{
+  NS_LOG_FUNCTION (this << leak);
+  m_bucketLeak = leak;
+}
+
+void
+CcnxFace::LeakBucketByOnePacket ()
+{
+  m_bucket = std::max (0.0, m_bucket-1.0); 
+}
+
+bool
+CcnxFace::Send (Ptr<Packet> packet)
+{
+  NS_LOG_FUNCTION (boost::cref (*this) << packet << packet->GetSize ());
+
+  /// \todo Implement tracing, if requested
+
+  if (!IsUp ())
+    return false;
+
+  SendImpl (packet);
+  return true;
+}
+
+bool
+CcnxFace::Receive (const Ptr<const Packet> &packet)
+{
+  NS_LOG_FUNCTION (boost::cref (*this) << packet << packet->GetSize ());
+
+  /// \todo Implement tracing, if requested
+
+  if (!IsUp ())
+    return false;
+
+  m_protocolHandler (this, packet);
+  
+  return true;
 }
 
 // void
@@ -110,37 +181,18 @@
   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;
-}
-
-bool
-CcnxFace::IsLocal() const
-{
-    return m_isLocal;
+  m_ifup = up;
 }
 
 bool
 CcnxFace::operator== (const CcnxFace &face) const
 {
-  NS_ASSERT_MSG (m_node->GetId () == face.m_node->GetId (), "Faces of different nodes should not be compared to each other");
+  NS_ASSERT_MSG (m_node->GetId () == face.m_node->GetId (),
+                 "Faces of different nodes should not be compared to each other");
 
   return (m_id == face.m_id);
 }
@@ -148,7 +200,8 @@
 bool
 CcnxFace::operator< (const CcnxFace &face) const
 {
-  NS_ASSERT_MSG (m_node->GetId () == face.m_node->GetId (), "Faces of different nodes should not be compared to each other");
+  NS_ASSERT_MSG (m_node->GetId () == face.m_node->GetId (),
+                 "Faces of different nodes should not be compared to each other");
 
   return (m_id < face.m_id);
 }
diff --git a/model/ccnx-face.h b/model/ccnx-face.h
index 481a55d..0499abb 100644
--- a/model/ccnx-face.h
+++ b/model/ccnx-face.h
@@ -22,16 +22,16 @@
 #define CCNX_FACE_H
 
 #include <ostream>
+#include <algorithm>
 
 #include "ns3/ptr.h"
-#include "ns3/simple-ref-count.h"
-#include "ns3/callback.h"
+#include "ns3/ccnx.h"
+#include "ns3/nstime.h"
 
 namespace ns3 {
 
 class Packet;
 class Node;
-
   
 /**
  * \ingroup ccnx
@@ -54,21 +54,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 Interface ID
-  //  *
-  //  * \return interface ID
-  //  */
-  // static TypeId GetTypeId (void);
 
   /**
    * \brief Default constructor
    */
-  CcnxFace ();
+  CcnxFace (Ptr<Node> node);
   virtual ~CcnxFace();
 
   ////////////////////////////////////////////////////////////////////
@@ -78,23 +71,39 @@
    *
    * This method should call protocol-dependent registration function
    */
-  virtual void RegisterProtocolHandler (ProtocolHandler handler) = 0;
+  virtual void
+  RegisterProtocolHandler (ProtocolHandler handler);
+
+  /**
+   * @brief Check if Interest limit is reached
+   *
+   * Side effect: if limit is not yet reached, the number of outstanding packets will be increased
+   *
+   * @returns true if Interest limit is not yet reached
+   */
+  bool
+  IsBelowLimit ();
   
   /**
    * \brief Send packet on a face
    *
+   * 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
    */ 
-  virtual void Send (Ptr<Packet> p) = 0;
-
-  ////////////////////////////////////////////////////////////////////
+  bool
+  Send (Ptr<Packet> p);
 
   /**
-   * \brief Associate Node object with face
+   * \brief Receive packet from application or another node and forward it to the CCNx stack
    *
-   * \param node smart pointer to a Node object
+   * \todo The only reason for this call is to handle tracing, if requested
    */
-  virtual void SetNode (Ptr<Node> node);
+  bool
+  Receive (const Ptr<const Packet> &p);
+  ////////////////////////////////////////////////////////////////////
 
   // /**
   //  * \Brief Assign routing/forwarding metric with face
@@ -117,29 +126,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;
-
-  /**
-   * \brief Return true for LocalFace, otherwise false
-   */
-  virtual bool IsLocal () const;
+  virtual bool
+  IsUp () const;
   
   virtual std::ostream&
   Print (std::ostream &os) const;
@@ -165,6 +161,31 @@
   GetId () const;
 
   /**
+   * @brief Set maximum value for Interest allowance
+   *
+   * @param bucket maximum value for Interest allowance. If < 0, then limit will be disabled
+   */
+  void
+  SetBucketMax (double bucket);
+
+  /**
+   * @brief Set a normalized value (one second) for Interest allowance bucket leak
+   */
+   void
+  SetBucketLeak (double leak);
+  
+  /**
+   * @brief Leak the Interest allowance bucket by (1/interval) * m_bucketMax amount
+   *
+   * @param interval Time interval with which the bucket is leaked
+   */
+  void
+  LeakBucket (const Time &interval);
+
+  void
+  LeakBucketByOnePacket ();
+  
+  /**
    * \brief Compare two faces. Only two faces on the same node could be compared.
    *
    * Internal index is used for comparison.
@@ -179,9 +200,15 @@
    */
   bool
   operator< (const CcnxFace &face) const;
-  
-// protected:
-//   virtual void DoDispose (void);
+
+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
@@ -190,12 +217,15 @@
 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
-  bool m_isLocal;
-private:
-  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)
+
+  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)  
 };
 
 std::ostream& operator<< (std::ostream& os, const CcnxFace &face);
diff --git a/model/ccnx-fib.cc b/model/ccnx-fib.cc
index f8c5956..0df2ded 100644
--- a/model/ccnx-fib.cc
+++ b/model/ccnx-fib.cc
@@ -33,10 +33,10 @@
 #define NDN_RTO_BETA 0.25
 #define NDN_RTO_K 4
 
-//#define NDN_DEBUG_OSPF	0
-//#define NDN_DEBUG_OSPF_NODES 0
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
 
-//#define NDN_DUMP_FIB		0
 namespace ns3 {
 
 
@@ -51,48 +51,6 @@
   type;
 };
 
-struct ChangeStatus
-{
-  ChangeStatus (CcnxFibFaceMetric::Status status) : m_status (status) { }
-  void operator() (CcnxFibFaceMetric &entry)
-  {
-    entry.m_status = m_status;
-  }
-private:
-  CcnxFibFaceMetric::Status m_status;
-};
-
-struct ChangeMetric
-{
-  ChangeMetric (int32_t metric) : m_metric (metric) { }
-  void operator() (CcnxFibFaceMetric &entry)
-  {
-    entry.m_routingCost = m_metric;
-  }
-private:
-  int32_t m_metric;
-};
-
-// struct SearchByFace {
-//   /**
-//    * \brief To perform effective searches by CcnxFace
-//    */
-//   bool
-//   operator() (const CcnxFibFaceMetric &m, const Ptr<CcnxFace> &face) const
-//   {
-//     return *(m.m_face) < *face;
-//   } 
-
-//   /**
-//    * \brief To perform effective searches by CcnxFace
-//    */
-//   bool
-//   operator() (const Ptr<CcnxFace> &face, const CcnxFibFaceMetric &m) const
-//   {
-//     return *face < *(m.m_face);
-//   } 
-// };
-
 }
 //////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////
@@ -112,74 +70,88 @@
   return tid;
 }
 
+/////////////////////////////////////////////////////////////////////
+
 void
-CcnxFibFaceMetric::UpdateRtt::operator() (CcnxFibFaceMetric &entry)
+CcnxFibFaceMetric::UpdateRtt (const Time &rttSample)
 {
   // const Time & this->m_rttSample
   
   //update srtt and rttvar (RFC 2988)
-  if (entry.m_sRtt.IsZero ())
+  if (m_sRtt.IsZero ())
     {
       //first RTT measurement
-      NS_ASSERT_MSG (entry.m_rttVar.IsZero (), "SRTT is zero, but variation is not");
+      NS_ASSERT_MSG (m_rttVar.IsZero (), "SRTT is zero, but variation is not");
       
-      entry.m_sRtt = m_rttSample;
-      entry.m_rttVar = Time (entry.m_sRtt / 2.0);
+      m_sRtt = rttSample;
+      m_rttVar = Time (m_sRtt / 2.0);
     }
   else
     {
-      entry.m_rttVar = Time ((1 - NDN_RTO_BETA) * entry.m_rttVar + NDN_RTO_BETA * Abs(entry.m_sRtt - m_rttSample));
-      entry.m_sRtt = Time ((1 - NDN_RTO_ALPHA) * entry.m_sRtt + NDN_RTO_ALPHA * m_rttSample);
+      m_rttVar = Time ((1 - NDN_RTO_BETA) * m_rttVar + NDN_RTO_BETA * Abs(m_sRtt - rttSample));
+      m_sRtt = Time ((1 - NDN_RTO_ALPHA) * m_sRtt + NDN_RTO_ALPHA * rttSample);
     }
 }
 
+/////////////////////////////////////////////////////////////////////
+
 void
-CcnxFibEntry::UpdateStatus::operator () (CcnxFibEntry &entry)
+CcnxFibEntry::UpdateFaceRtt (Ptr<CcnxFace> face, const Time &sample)
 {
-  CcnxFibFaceMetricByFace::type::iterator record = entry.m_faces.get<i_face> ().find (m_face);
-  NS_ASSERT_MSG (record != entry.m_faces.get<i_face> ().end (),
+  CcnxFibFaceMetricByFace::type::iterator record = m_faces.get<i_face> ().find (face);
+  NS_ASSERT_MSG (record != m_faces.get<i_face> ().end (),
                  "Update status can be performed only on existing faces of CcxnFibEntry");
 
-  entry.m_faces.modify (record, ChangeStatus (m_status));
+  m_faces.modify (record,
+                  ll::bind (&CcnxFibFaceMetric::UpdateRtt, ll::_1, sample));
 
   // reordering random access index same way as by metric index
-  entry.m_faces.get<i_nth> ().rearrange (entry.m_faces.get<i_metric> ().begin ());
+  m_faces.get<i_nth> ().rearrange (m_faces.get<i_metric> ().begin ());
 }
 
 void
-CcnxFibEntry::AddOrUpdateRoutingMetric::operator () (CcnxFibEntry &entry)
+CcnxFibEntry::UpdateStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status)
 {
-  NS_LOG_FUNCTION(this);
-  NS_ASSERT_MSG (m_face != NULL, "Trying to Add or Update NULL face");
+  NS_LOG_FUNCTION (this << boost::cref(*face) << status);
 
-  CcnxFibFaceMetricByFace::type::iterator record = entry.m_faces.get<i_face> ().find (m_face);
-  if (record == entry.m_faces.get<i_face> ().end ())
+  CcnxFibFaceMetricByFace::type::iterator record = m_faces.get<i_face> ().find (face);
+  NS_ASSERT_MSG (record != m_faces.get<i_face> ().end (),
+                 "Update status can be performed only on existing faces of CcxnFibEntry");
+
+  m_faces.modify (record,
+                  (&ll::_1)->*&CcnxFibFaceMetric::m_status = status);
+
+  // reordering random access index same way as by metric index
+  m_faces.get<i_nth> ().rearrange (m_faces.get<i_metric> ().begin ());
+}
+
+void
+CcnxFibEntry::AddOrUpdateRoutingMetric (Ptr<CcnxFace> face, int32_t metric)
+{
+  NS_LOG_FUNCTION (this);
+  NS_ASSERT_MSG (face != NULL, "Trying to Add or Update NULL face");
+
+  CcnxFibFaceMetricByFace::type::iterator record = m_faces.get<i_face> ().find (face);
+  if (record == m_faces.get<i_face> ().end ())
     {
-      entry.m_faces.insert (CcnxFibFaceMetric (m_face, m_metric));
+      m_faces.insert (CcnxFibFaceMetric (face, metric));
     }
   else
   {
-      entry.m_faces.modify (record, ChangeMetric (m_metric));
-    }
+    m_faces.modify (record,
+                    (&ll::_1)->*&CcnxFibFaceMetric::m_routingCost = metric);
+  }
+  
   // reordering random access index same way as by metric index
-  entry.m_faces.get<i_nth> ().rearrange (entry.m_faces.get<i_metric> ().begin ());
+  m_faces.get<i_nth> ().rearrange (m_faces.get<i_metric> ().begin ());
 }
 
-void
-CcnxFibEntry::UpdateFaceRtt::operator() (CcnxFibEntry &entry)
+const CcnxFibFaceMetric &
+CcnxFibEntry::FindBestCandidate (uint32_t skip/* = 0*/) const
 {
-  CcnxFibFaceMetricContainer::type::iterator metric = entry.m_faces.find (m_face);
-  NS_ASSERT_MSG (metric != entry.m_faces.end (),
-                 "Something wrong. Cannot find entry for the face in FIB");
-
-  entry.m_faces.modify (metric, CcnxFibFaceMetric::UpdateRtt (m_rttSample));
-}
-    
-Ptr<CcnxFace>
-CcnxFibEntry::FindBestCandidate (int skip/* = 0*/) const
-{
+  if (m_faces.size () == 0) throw CcnxFibEntry::NoFaces ();
   skip = skip % m_faces.size();
-  return m_faces.get<i_nth> () [skip].GetFace ();
+  return m_faces.get<i_nth> () [skip];
 }
 
 
@@ -198,7 +170,9 @@
 void 
 CcnxFib::DoDispose (void)
 {
+  clear ();
   m_node = 0;
+  clear ();
   Object::DoDispose ();
 }
 
@@ -234,11 +208,37 @@
     }
 
   NS_ASSERT_MSG (face != NULL, "Trying to modify NULL face");
-  modify (entry, CcnxFibEntry::AddOrUpdateRoutingMetric (face, metric));
+  modify (entry,
+          ll::bind (&CcnxFibEntry::AddOrUpdateRoutingMetric, ll::_1, face, metric));
     
   return entry;
 }
     
+void
+CcnxFib::Remove (const CcnxFibEntry &entry, Ptr<CcnxFace> face)
+{
+  NS_LOG_FUNCTION (this);
+
+  modify (iterator_to (entry),
+          ll::bind (&CcnxFibEntry::RemoveFace, ll::_1, face));
+  if (entry.m_faces.size () == 0)
+    {
+      erase (iterator_to (entry));
+    }
+}
+
+void
+CcnxFib::RemoveFromAll (Ptr<CcnxFace> face)
+{
+  NS_LOG_FUNCTION (this);
+
+  for_each (begin (), end (), ll::bind (&CcnxFib::Remove, this, ll::_1, face));
+  // BOOST_FOREACH (const CcnxFibEntry &entry, *this)
+  //   {
+  //     Remove (entry, face);
+  //   }
+}
+
 
 std::ostream& operator<< (std::ostream& os, const CcnxFib &fib)
 {
diff --git a/model/ccnx-fib.h b/model/ccnx-fib.h
index afb86a3..3e7807b 100644
--- a/model/ccnx-fib.h
+++ b/model/ccnx-fib.h
@@ -81,16 +81,11 @@
   GetFace () const { return m_face; }
 
   /**
-   * \brief Unary function to recalculate smoothed RTT and RTT variation
+   * \brief Recalculate smoothed RTT and RTT variation
    * \param rttSample RTT sample
    */
-  struct UpdateRtt
-  {
-    UpdateRtt (const Time &rttSample) : m_rttSample (rttSample) {};
-    void operator() (CcnxFibFaceMetric &entry);
-  private:
-    const Time &m_rttSample;
-  };
+  void
+  UpdateRtt (const Time &rttSample);
   
 private:
   friend std::ostream& operator<< (std::ostream& os, const CcnxFibFaceMetric &metric);
@@ -98,9 +93,9 @@
   Ptr<CcnxFace> m_face; ///< Face
   
   Status m_status;		///< \brief Status of the next hop: 
-						///<		- NDN_FIB_GREEN
-						///<		- NDN_FIB_YELLOW
-						///<		- NDN_FIB_RED
+				///<		- NDN_FIB_GREEN
+				///<		- NDN_FIB_YELLOW
+				///<		- NDN_FIB_RED
   
   int32_t m_routingCost; ///< \brief routing protocol cost (interpretation of the value depends on the underlying routing protocol)
 
@@ -155,6 +150,8 @@
 class CcnxFibEntry : public SimpleRefCount<CcnxFibEntry>
 {
 public:
+  class NoFaces {};
+  
   /**
    * \brief Constructor
    * \param prefix Prefix for the FIB entry
@@ -165,47 +162,24 @@
   { }
 	
   /**
-   * \brief Unary function to update status of FIB next hop
+   * \brief Update status of FIB next hop
+   * \param status Status to set on the FIB entry
    */
-  struct UpdateStatus
-  {
-    UpdateStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status)
-      : m_face (face), m_status (status) {}
-    void operator () (CcnxFibEntry &entry);
-  private:
-    Ptr<CcnxFace> m_face;
-    CcnxFibFaceMetric::Status m_status;
-  };
+  void UpdateStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status);
 
   /**
-   * \brief Unary function to add or update routing metric of FIB next hop
+   * \brief Add or update routing metric of FIB next hop
    *
    * Initial status of the next hop is set to YELLOW
    */
-  struct AddOrUpdateRoutingMetric
-  {
-    AddOrUpdateRoutingMetric (Ptr<CcnxFace> face, int32_t metric)
-      : m_face (face), m_metric (metric) {}
-    void operator () (CcnxFibEntry &entry);
-  private:
-    Ptr<CcnxFace> m_face;
-    int32_t m_metric;
-  };
+  void AddOrUpdateRoutingMetric (Ptr<CcnxFace> face, int32_t metric);
 
   /**
-   * \brief Unary function to recalculate smoothed RTT and RTT variation
-   * \param rttSample RTT sample
+   * @brief Update RTT averages for the face
    */
-  struct UpdateFaceRtt
-  {
-    UpdateFaceRtt (Ptr<CcnxFace> face, const Time &rttSample)
-      : m_face (face), m_rttSample (rttSample) {};
-    void operator() (CcnxFibEntry &entry);
-  private:
-    Ptr<CcnxFace> m_face;
-    const Time &m_rttSample;
-  };
-
+  void
+  UpdateFaceRtt (Ptr<CcnxFace> face, const Time &sample);
+  
   /**
    * \brief Get prefix for the FIB entry
    */
@@ -214,9 +188,20 @@
 
   /**
    * \brief Find "best route" candidate, skipping `skip' first candidates (modulo # of faces)
+   *
+   * throws CcnxFibEntry::NoFaces if m_faces.size()==0
    */
-  Ptr<CcnxFace>
-    FindBestCandidate (int skip = 0) const;
+  const CcnxFibFaceMetric &
+  FindBestCandidate (uint32_t skip = 0) const;
+
+  /**
+   * @brief Remove record associated with `face`
+   */
+  void
+  RemoveFace (const Ptr<CcnxFace> &face)
+  {
+    m_faces.erase (face);
+  }
 	
 private:
   friend std::ostream& operator<< (std::ostream& os, const CcnxFibEntry &entry);
@@ -276,15 +261,6 @@
   CcnxFib ();
    // * \param node smart pointer to Ccnx stack associated with particular node
 
-  // // Invalidate entries in FIB
-  // // Will leave FIB records in hash, but assign metric=NETWORK_UNREACHABLE
-  // void invalidate( );
-
-  // //Find corresponding FIB entry for the given content name
-  // //Longest match is performed
-  // FibIterator lookup( const string &name );
-  // bool isValid( const FibIterator &it ) { return it!=_fib.end(); }
-
   /**
    * \brief Perform longest prefix match
    *
@@ -309,23 +285,20 @@
    */
   CcnxFibEntryContainer::type::iterator
   Add (const CcnxNameComponents &prefix, Ptr<CcnxFace> face, int32_t metric);
-  // bool update( const string &name, int interfaceIndex, int metric);
-  // bool update( NodeAddress nodeId, int interfaceIndex, int metric);
-  // Bool update( NodeAddress nodeId, int metric, NodeAddress nextHop );
 
-  // // Update Fib from OSPF routing table (through a hack in OSPF algorithm)
-  // void updateFibFromOSPFv2( int interface );
+  /**
+   * @brief Remove reference to a face from the entry. If entry had only this face, the whole
+   * entry will be removed
+   */
+  void
+  Remove (const CcnxFibEntry &entry, Ptr<CcnxFace> face);
 
-  // // Update Fib from BGP routing table (using info from RibIn)
-  // void updateFibFromBGP( );
-
-  // // Update Fib from IP routing table
-  // void updateFibFromIpRouting( );
-
-  // void dump( );
-  // void dump( const FibIterator &fib );
-
-  // void resetProbing();    //reset needsProbing field for every FibEntry
+  /**
+   * @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
+  RemoveFromAll (Ptr<CcnxFace> face);
 
 protected:
   // inherited from Object class
diff --git a/model/ccnx-flooding-strategy.cc b/model/ccnx-flooding-strategy.cc
index 83ddd7e..4a8dd50 100644
--- a/model/ccnx-flooding-strategy.cc
+++ b/model/ccnx-flooding-strategy.cc
@@ -20,128 +20,106 @@
 
 #include "ccnx-flooding-strategy.h"
 #include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ccnx-interest-header.h"
 
-#include "ccnx-route.h"
+#include <boost/ref.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
 
 NS_LOG_COMPONENT_DEFINE ("CcnxFloodingStrategy");
 
 namespace ns3 
 {
-    
+
+using namespace __ccnx_private;
+
 NS_OBJECT_ENSURE_REGISTERED (CcnxFloodingStrategy);
     
 TypeId CcnxFloodingStrategy::GetTypeId (void)
 {
-    static TypeId tid = TypeId ("ns3::CcnxFloodingStrategy")
+  static TypeId tid = TypeId ("ns3::CcnxFloodingStrategy")
     .SetGroupName ("Ccnx")
-    .SetParent<Object> ()
+    .SetParent <CcnxForwardingStrategy> ()
+    .AddConstructor <CcnxFloodingStrategy> ()
     ;
-    return tid;
+  return tid;
 }
     
 CcnxFloodingStrategy::CcnxFloodingStrategy ()
 {
 }
-    
-    
+
 bool
-CcnxFloodingStrategy::PropagateInterest  (CcnxPitEntryContainer::type::iterator pitEntry, 
-                                          CcnxFibEntryContainer::type::iterator fibEntry,
-                                          const Ptr<CcnxFace> &incomingFace,
-                                          Ptr<CcnxInterestHeader> &header,
-                                          const Ptr<const Packet> &packet,
-                                          SendCallback ucb)
+CcnxFloodingStrategy::PropagateInterest (const CcnxPitEntry  &pitEntry, 
+                                         const Ptr<CcnxFace> &incomingFace,
+                                         Ptr<CcnxInterestHeader> &header,
+                                         const Ptr<const Packet> &packet)
 {
-    //CcnxFibEntryContainer::type::iterator fibEntryArray = GetFib()->LongestPrefixMatch(*header);
-    NS_LOG_FUNCTION(this);
-    
-    //CcnxFibEntryContainer::type::iterator fibEntryArray = GetCcnx()->GetObject<CcnxFib>()->LongestPrefixMatch(*header);
-    NS_LOG_INFO(*fibEntry);
-    
-    int count = 0;
-    for(CcnxFibFaceMetricContainer::type::iterator face = fibEntry->m_faces.begin ();
-        face != fibEntry->m_faces.end ();
-        face++)
+  NS_LOG_FUNCTION (this);
+
+  // Try to work out with just green faces
+  bool greenOk = PropagateInterestViaGreen (pitEntry, incomingFace, header, packet);
+  if (greenOk)
+    return true;
+
+  // boo... :(
+  int propagatedCount = 0;
+
+  BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry.m_fibEntry.m_faces.get<i_metric> ())
     {
-        if(face->m_face == incomingFace)
-            continue;
-        NS_LOG_INFO ("JUST before try add outgoing");
-        //Add new outgoing interest to pit entry
-		// If PIT entry cannot be created (limit reached or interest already sent), nothing will be forwarded
-		//if( _pit.add(VALUE(info.pe), PitOutgoingInterest( *iface, getSimTime(_node), pkt->nonce )) )
-		//{
-        //GetPit()->Add(*header,fibEntry,face->m_face);
-        //GetPit()->modify (GetPit()->end (), CcnxPitEntry::AddOutgoing(face->m_face));
-        bool tryResult = GetPit ()->TryAddOutgoing (pitEntry, face->m_face);
-        if ( tryResult == false )
-        {NS_LOG_INFO("false");
-            continue;
+      NS_LOG_DEBUG ("Trying " << boost::cref(metricFace));
+      if (metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_RED) // all non-read faces are in front
+        break;
+      
+      if (metricFace.m_face == incomingFace) 
+        {
+          NS_LOG_DEBUG ("continue (same as incoming)");
+          continue; // same face as incoming, don't forward
         }
-        else
-            NS_LOG_INFO("true");
-        
-        NS_LOG_INFO("count="<<count);
-        ucb (face->m_face, header, packet->Copy());
-        count++;
+
+      if (pitEntry.m_incoming.find (metricFace.m_face) != pitEntry.m_incoming.end ()) 
+        {
+          NS_LOG_DEBUG ("continue (same as previous incoming)");
+          continue; // don't forward to face that we received interest from
+        }
+
+      CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+        pitEntry.m_outgoing.find (metricFace.m_face);
+      
+      if (outgoing != pitEntry.m_outgoing.end () &&
+          outgoing->m_retxCount >= pitEntry.m_maxRetxCount)
+        {
+          NS_LOG_DEBUG ("continue (same as previous outgoing)");
+          continue; // already forwarded before during this retransmission cycle
+        }
+      NS_LOG_DEBUG ("max retx count: " << pitEntry.m_maxRetxCount);
+
+      bool faceAvailable = metricFace.m_face->IsBelowLimit ();
+      if (!faceAvailable) // huh...
+        {
+          continue;
+        }
+
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind(&CcnxPitEntry::AddOutgoing, ll::_1, metricFace.m_face));
+
+      // if (Simulator::GetContext ()==2)
+      //   {
+      //     NS_LOG_ERROR ("new outgoing entry for " << boost::cref (*metricFace.m_face));
+      //     NS_LOG_ERROR ("size: " << pitEntry.m_outgoing.size ());
+      //   }
+
+      metricFace.m_face->Send (packet->Copy ());
+      
+      propagatedCount++;
     }
-    
-    /*const CcnxFibEntryContainer& s,
-    
-    for (CcnxFibEntryContainer::type::iterator entry = fibEntryArray.begin ();
-         entry != fibEntryArray.end ();
-         entry++)
-    {
-    
-        const typename boost::multi_index::index<CcnxFibEntryContainer, Tag>::type& i = get<Tag>(s);
-        
-        typedef typename CcnxFibEntryContainer::value_type value_type;
-        
-        for(const CcnxFibEntryContainer& c = i.begin(); c != i.end (); c++)
-        {
-                c->
-        }
-        
-        for(nth_index<CcnxFibEntryContainer,1>::type::iterator it1=get<i_prefix>(entry).begin();
-            it1!=get<i_prefix>(entry).end();++it1)
-        {
-            //std::cout<<it1->name()<<std::endl;
-            
-           CcnxFibFaceMetricContainer faceContainer = it1->m_faces;
-            
-            const typename boost::multi_index::index<CcnxFibFaceMetricContainer, __ccnx_private::i_face>::type& i = get<__ccnx_private::i_face>(faceContainer);
-             
-             //typedef typename CcnxFibEntryContainer::value_type value_type;
-             
-             for(const CcnxFibFaceMetricContainer& c = i.begin(); c != i.end (); c++)
-             {
-                 Ptr<CcnxFace> face = c->m_face;
-                 
-                 typedef
-                 Callback<void, const Ptr<CcnxFace> &, const Ptr<CcnxInterestHeader> &, const Ptr<Packet> &>
-                 SendCallback;
-                 
-                 ucb (face, header, packet);
-             }
-            
-        }
-        
-        
-        // obtain a reference to the index tagged by Tag
-        
-        const typename boost::multi_index::index<MultiIndexContainer,Tag>::type& i=
-        get<Tag>(s);
-        
-        typedef typename MultiIndexContainer::value_type value_type;
-        
-        // dump the elements of the index to cout 
-        
-        std::copy(i.begin(),i.end(),std::ostream_iterator<value_type>(std::cout));
-        */
-    
-    if(count == 0)
-        return false;
-    else
-        return true;
+
+  NS_LOG_INFO ("Propagated to " << propagatedCount << " faces");
+  return propagatedCount > 0;
 }
     
 } //namespace ns3
diff --git a/model/ccnx-flooding-strategy.h b/model/ccnx-flooding-strategy.h
index 5eb7a5d..8be12e9 100644
--- a/model/ccnx-flooding-strategy.h
+++ b/model/ccnx-flooding-strategy.h
@@ -18,18 +18,10 @@
  * Author: Ilya Moiseenko <iliamo@cs.ucla.edu>
  */
 
-
 #ifndef CCNX_FLOODING_STRATEGY_H
 #define CCNX_FLOODING_STRATEGY_H
 
-#include "ns3/packet.h"
-#include "ns3/callback.h"
-#include "ns3/object.h"
-#include "ns3/log.h"
-
 #include "ccnx-forwarding-strategy.h"
-#include "ccnx.h"
-#include "ccnx-fib.h"
 
 namespace ns3 
 {
@@ -38,23 +30,27 @@
 class CcnxInterestHeader;
     
 /**
-* \ingroup ccnx
-* \brief Flooding strategy
-*/
-
+ * \ingroup ccnx
+ * \brief Flooding strategy
+ *
+ * \todo Describe
+ */
 class CcnxFloodingStrategy : public CcnxForwardingStrategy
 {
 public:
-    static TypeId GetTypeId (void);
-        
-    CcnxFloodingStrategy ();
-          
-    bool PropagateInterest  (CcnxPitEntryContainer::type::iterator pitEntry,
-                             CcnxFibEntryContainer::type::iterator fibEntry,
-                             const Ptr<CcnxFace> &incomingFace,
-                             Ptr<CcnxInterestHeader> &header,
-                             const Ptr<const Packet> &packet,
-                             SendCallback ucb);
+  static TypeId GetTypeId (void);
+
+  /**
+   * @brief Default constructor
+   */
+  CcnxFloodingStrategy ();
+
+  // inherited from  CcnxForwardingStrategy
+  virtual bool
+  PropagateInterest (const CcnxPitEntry  &pitEntry, 
+                     const Ptr<CcnxFace> &incomingFace,
+                     Ptr<CcnxInterestHeader> &header,
+                     const Ptr<const Packet> &packet);
 };
     
 } //namespace ns3
diff --git a/model/ccnx-forwarding-strategy.cc b/model/ccnx-forwarding-strategy.cc
index f048e6e..4a1c3a8 100644
--- a/model/ccnx-forwarding-strategy.cc
+++ b/model/ccnx-forwarding-strategy.cc
@@ -21,11 +21,23 @@
 
 #include "ns3/assert.h"
 
-#include "ccnx-route.h"
 #include "ccnx-forwarding-strategy.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ccnx-interest-header.h"
+
+#include <boost/ref.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
+
+NS_LOG_COMPONENT_DEFINE ("CcnxForwardingStrategy");
 
 namespace ns3 {
 
+using namespace __ccnx_private;
+
 NS_OBJECT_ENSURE_REGISTERED (CcnxForwardingStrategy);
 
 TypeId CcnxForwardingStrategy::GetTypeId (void)
@@ -33,7 +45,7 @@
   static TypeId tid = TypeId ("ns3::CcnxForwardingStrategy")
     .SetGroupName ("Ccnx")
     .SetParent<Object> ()
-  ;
+    ;
   return tid;
 }
 
@@ -41,16 +53,69 @@
 {
 }
 
+CcnxForwardingStrategy::~CcnxForwardingStrategy ()
+{
+}
+
 void
-CcnxForwardingStrategy::SetPit(Ptr<CcnxPit> pit)
+CcnxForwardingStrategy::SetPit (Ptr<CcnxPit> pit)
 {
-    m_pit = pit;
+  m_pit = pit;
 }
-    
-Ptr<CcnxPit>
-CcnxForwardingStrategy::GetPit()
+
+bool
+CcnxForwardingStrategy::PropagateInterestViaGreen (const CcnxPitEntry  &pitEntry, 
+                                                   const Ptr<CcnxFace> &incomingFace,
+                                                   Ptr<CcnxInterestHeader> &header,
+                                                   const Ptr<const Packet> &packet)
 {
-    return m_pit;
+  // NS_LOG_FUNCTION (this);
+
+  int propagatedCount = 0;
+  
+  BOOST_FOREACH (const CcnxFibFaceMetric &metricFace, pitEntry.m_fibEntry.m_faces.get<i_metric> ())
+    {
+      if (metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_RED ||
+          metricFace.m_status == CcnxFibFaceMetric::NDN_FIB_YELLOW)
+        break; //propagate only to green faces
+
+      if (pitEntry.m_incoming.find (metricFace.m_face) != pitEntry.m_incoming.end ()) 
+        continue; // don't forward to face that we received interest from
+
+      CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+        pitEntry.m_outgoing.find (metricFace.m_face);
+      
+      if (outgoing != pitEntry.m_outgoing.end () &&
+          outgoing->m_retxCount >= pitEntry.m_maxRetxCount)
+        {
+          continue;
+        }
+      
+      bool faceAvailable = metricFace.m_face->IsBelowLimit ();
+      if (!faceAvailable) // huh...
+        {
+          // let's try different green face
+          continue;
+        }
+
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind(&CcnxPitEntry::AddOutgoing, ll::_1, metricFace.m_face));
+
+      metricFace.m_face->Send (packet->Copy ());
+      
+      propagatedCount++;
+      break; // propagate only one interest
+    }
+
+  // if (Simulator::GetContext ()==1)
+  //   {
+  //     if (propagatedCount > 0)
+  //       NS_LOG_DEBUG ("Propagate via a green face");
+  //     else 
+  //       NS_LOG_DEBUG ("Can't :(");
+  //   }
+  return propagatedCount > 0;
 }
-    
+
+
 } //namespace ns3
diff --git a/model/ccnx-forwarding-strategy.h b/model/ccnx-forwarding-strategy.h
index 3f0f8ae..aff0909 100644
--- a/model/ccnx-forwarding-strategy.h
+++ b/model/ccnx-forwarding-strategy.h
@@ -37,30 +37,64 @@
 
 /**
  * \ingroup ccnx
- * \brief Abstract base class for Ccnx forwarding protocols
+ * \brief Abstract base class for CCNx forwarding strategies
  */
 class CcnxForwardingStrategy : public Object
 {
 public:
   static TypeId GetTypeId (void);
 
+  /**
+   * @brief Default constructor
+   */
   CcnxForwardingStrategy ();
-    
-  void SetPit(Ptr<CcnxPit> pit);
-    
-  typedef
-  Callback<void, const Ptr<CcnxFace> &, const Ptr<CcnxInterestHeader> &, const Ptr<Packet> &>
-  SendCallback;
+  virtual ~CcnxForwardingStrategy ();
 
-  virtual bool PropagateInterest  (CcnxPitEntryContainer::type::iterator pitEntry, 
-                                   CcnxFibEntryContainer::type::iterator fibEntry,
-                                   const Ptr<CcnxFace> &incomingFace,
-                                   Ptr<CcnxInterestHeader> &header,
-                                   const Ptr<const Packet> &packet,
-                                   SendCallback ucb) = 0;
-  Ptr<CcnxPit> GetPit();
+  /**
+   * @brief Base method to propagate the insterest according to the forwarding strategy
+   *
+   * @param pitEntry      Reference to PIT entry (reference to corresponding FIB entry inside)
+   * @param incomingFace  Incoming face
+   * @param header        CcnxInterestHeader
+   * @param packet        Original Interest packet
+   * @param sendCallback  Send callback
+   *
+   * @return true if interest was successfully propagated, false if all options have failed
+   */
+  virtual bool
+  PropagateInterest (const CcnxPitEntry  &pitEntry, 
+                     const Ptr<CcnxFace> &incomingFace,
+                     Ptr<CcnxInterestHeader> &header,
+                     const Ptr<const Packet> &packet) = 0;
     
-private:  
+  /**
+   * @brief Set link to PIT for the forwarding strategy
+   *
+   * @param pit pointer to PIT
+   */
+  void
+  SetPit (Ptr<CcnxPit> pit);
+
+protected:
+  /**
+   * @brief Propage interest vie a green interface. Fail, if no green interfaces available
+   *
+   * @param pitEntry      Reference to PIT entry (reference to corresponding FIB entry inside)
+   * @param incomingFace  Incoming face
+   * @param header        CcnxInterestHeader
+   * @param packet        Original Interest packet
+   * @param sendCallback  Send callback
+   * @return true if interest was successfully propagated, false if all options have failed
+   *
+   * \see PropagateInterest
+   */
+  bool
+  PropagateInterestViaGreen (const CcnxPitEntry  &pitEntry, 
+                             const Ptr<CcnxFace> &incomingFace,
+                             Ptr<CcnxInterestHeader> &header,
+                             const Ptr<const Packet> &packet);
+  
+protected:  
   Ptr<CcnxPit> m_pit;
 };
 
diff --git a/model/ccnx-interest-header.cc b/model/ccnx-interest-header.cc
index f6295aa..6539ff8 100644
--- a/model/ccnx-interest-header.cc
+++ b/model/ccnx-interest-header.cc
@@ -56,8 +56,7 @@
   , m_scope (-1)
   , m_interestLifetime (Seconds (0))
   , m_nonce (0)
-  , m_nack (false)
-  , m_congested (false)
+  , m_nackType (NORMAL_INTEREST)
 {
 }
 
@@ -178,27 +177,15 @@
 }
 
 void
-CcnxInterestHeader::SetNack (bool isNack)
+CcnxInterestHeader::SetNack (uint32_t nackType)
 {
-  m_nack = isNack;
+  m_nackType = nackType;
 }
-    
-bool
-CcnxInterestHeader::IsNack () const
+
+uint32_t
+CcnxInterestHeader::GetNack () const
 {
-  return m_nack;
-}
- 
-void
-CcnxInterestHeader::SetCongested (bool IsCongested)
-{
-  m_congested = IsCongested;
-}
-    
-bool
-CcnxInterestHeader::IsCongested () const
-{
-  return m_congested;
+  return m_nackType;
 }
 
 uint32_t
@@ -232,10 +219,23 @@
 CcnxInterestHeader::Print (std::ostream &os) const
 {
   os << "<Interest>\n  <Name>" << GetName () << "</Name>\n";
-  if (IsNack ())
-    os << "  <NACK />\n";
-  if(IsCongested())
-    os << "  <CONGESTED />\n";
+  if (GetNack ()>0)
+    {
+      os << "  <NACK>";
+      switch (GetNack ())
+        {
+        case NACK_LOOP:
+          os << "loop";
+          break;
+        case NACK_CONGESTION:
+          os << "congestion";
+          break;
+        default:
+          os << "unknown";
+          break;
+        }
+      os << "</NACK>\n";
+    }
   if (GetMinSuffixComponents () >= 0)
     os << "  <MinSuffixComponents>" << GetMinSuffixComponents () << "</MinSuffixComponents>\n";
   if (GetMaxSuffixComponents () >= 0)
diff --git a/model/ccnx-interest-header.h b/model/ccnx-interest-header.h
index 4bfebe3..979dfdd 100644
--- a/model/ccnx-interest-header.h
+++ b/model/ccnx-interest-header.h
@@ -202,17 +202,19 @@
   uint32_t
   GetNonce () const;
     
+  enum
+    {
+      NORMAL_INTEREST = 0,
+      NACK_LOOP = 10,
+      NACK_CONGESTION = 11,
+      NACK_GIVEUP_PIT = 12,
+    };
+
   void
-  SetNack (bool isNack);
+  SetNack (uint32_t nackType);
     
-  bool
-  IsNack () const;
-    
-  void
-  SetCongested (bool IsCongested);
-    
-  bool
-  IsCongested () const;
+  uint32_t
+  GetNack () const;
 
   //////////////////////////////////////////////////////////////////
   
@@ -233,8 +235,7 @@
   int8_t m_scope;            ///< -1 not set, 0 local scope, 1 this host, 2 immediate neighborhood
   Time  m_interestLifetime;
   uint32_t m_nonce; ///< Nonce. not used if zero
-  bool m_nack; ///< is Negative ACK
-  bool m_congested; ///< NACK because of congestion 
+  uint32_t m_nackType; 
 };
 
 class CcnxInterestHeaderException {};
diff --git a/model/ccnx-l3-protocol.cc b/model/ccnx-l3-protocol.cc
index 6a4fae6..17dc335 100644
--- a/model/ccnx-l3-protocol.cc
+++ b/model/ccnx-l3-protocol.cc
@@ -33,7 +33,6 @@
 #include "ns3/ccnx-header-helper.h"
 
 #include "ccnx-face.h"
-#include "ccnx-route.h"
 #include "ccnx-forwarding-strategy.h"
 #include "ccnx-interest-header.h"
 #include "ccnx-content-object-header.h"
@@ -41,6 +40,11 @@
 #include "ccnx-net-device-face.h"
 
 #include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+
+using namespace boost::tuples;
+namespace ll = boost::lambda;
 
 NS_LOG_COMPONENT_DEFINE ("CcnxL3Protocol");
 
@@ -57,20 +61,12 @@
     .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 (&CcnxL3Protocol::GetBucketLeakInterval,
+                                     &CcnxL3Protocol::SetBucketLeakInterval),
+                   MakeTimeChecker ())
   ;
   return tid;
 }
@@ -80,7 +76,6 @@
 {
   NS_LOG_FUNCTION (this);
   
-  m_rit = CreateObject<CcnxRit> ();
   m_pit = CreateObject<CcnxPit> ();
   m_contentStore = CreateObject<CcnxContentStore> ();
 }
@@ -125,12 +120,22 @@
 {
   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;
     }
   m_faces.clear ();
   m_node = 0;
+
+  // Force delete on objects
+  m_forwardingStrategy = 0; // there is a reference to PIT stored in here
+  m_pit = 0;
+  m_contentStore = 0;
+  m_fib = 0;
+
   // m_forwardingStrategy = 0;
   Object::DoDispose ();
 }
@@ -140,7 +145,7 @@
 {
   NS_LOG_FUNCTION (this);
   m_forwardingStrategy = forwardingStrategy;
-  // m_forwardingStrategy->SetCcnx (this);
+  m_forwardingStrategy->SetPit (m_pit);
 }
 
 Ptr<CcnxForwardingStrategy>
@@ -154,14 +159,13 @@
 {
   NS_LOG_FUNCTION (this << &face);
 
-  face->SetNode (m_node);
   face->SetId (m_faceCounter); // sets a unique ID of the face. This ID serves only informational purposes
 
   // ask face to register in lower-layer stack
   face->RegisterProtocolHandler (MakeCallback (&CcnxL3Protocol::Receive, this));
 
   m_faces.push_back (face);
-  m_faceCounter ++;
+  m_faceCounter++;
   return face->GetId ();
 }
 
@@ -170,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
+  std::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 (pitEntry.m_fibEntry.m_faces.size () == 1 &&
+          pitEntry.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);
@@ -206,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)
@@ -249,8 +256,11 @@
             // Deserialization. Exception may be thrown
             packet->RemoveHeader (*header);
             NS_ASSERT_MSG (packet->GetSize () == 0, "Payload of Interests should be zero");
-            
-            OnInterest (face, header, p/*original packet*/);  
+
+            if (header->GetNack () > 0)
+              OnNack (face, header, p/*original packet*/);
+            else
+              OnInterest (face, header, p/*original packet*/);  
             break;
           }
         case CcnxHeaderHelper::CONTENT_OBJECT:
@@ -276,387 +286,266 @@
     }
 }
 
+void
+CcnxL3Protocol::OnNack (const Ptr<CcnxFace> &incomingFace,
+                        Ptr<CcnxInterestHeader> &header,
+                        const Ptr<const Packet> &packet)
+{
+  NS_LOG_FUNCTION (incomingFace << header << packet);
+
+  tuple<const CcnxPitEntry&,bool,bool> ret = m_pit->Lookup (*header);
+  CcnxPitEntry const& pitEntry = ret.get<0> ();
+  bool isNew = ret.get<1> ();
+  bool isDuplicated = ret.get<2> ();
+
+  // NS_ASSERT_MSG (isDuplicated,
+  //                "NACK should be a duplicated interest");
+  if (isNew || !isDuplicated) // potential flow
+    {
+      // somebody is doing something bad
+      return;
+    }
+  
+  // CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry.m_incoming.find (incomingFace);
+  CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry.m_outgoing.find (incomingFace);
+
+  if (outFace == pitEntry.m_outgoing.end ())
+    {
+      NS_ASSERT_MSG (false,
+                     "Node " << GetObject<Node> ()->GetId () << ", outgoing entry should exist for face " << boost::cref(*incomingFace) << "\n" <<
+                     "size: " << pitEntry.m_outgoing.size ());
+      
+      return;
+    }
+
+  // This was done in error. Never, never do anything, except normal leakage. This way we ensure that we will not have losses,
+  // at least when there is only one client
+  //
+  // incomingFace->LeakBucketByOnePacket ();
+
+  NS_LOG_ERROR ("Nack on " << boost::cref(*incomingFace));
+
+  m_pit->modify (m_pit->iterator_to (pitEntry),
+                 ll::bind (&CcnxPitEntry::SetWaitingInVain, ll::_1, outFace));
+  
+  // m_droppedInterestsTrace (header, DROP_CONGESTION, m_node->GetObject<Ccnx> (), incomingFace);
+
+  // If NACK is NACK_GIVEUP_PIT, then neighbor gave up trying to and removed it's PIT entry.
+  // So, if we had an incoming entry to this neighbor, then we can remove it now
+
+  if (header->GetNack () == CcnxInterestHeader::NACK_GIVEUP_PIT)
+    {
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind (&CcnxPitEntry::RemoveIncoming, ll::_1, incomingFace));
+    }
+
+  m_fib->modify (m_fib->iterator_to (pitEntry.m_fibEntry),
+                 ll::bind (&CcnxFibEntry::UpdateStatus,
+                           ll::_1, incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+
+  if (pitEntry.m_incoming.size () == 0) // interest was actually satisfied
+    {
+      // no need to do anything
+      return;
+    }
+
+  if (!pitEntry.AreAllOutgoingInVain ()) // not all ougtoing are in vain
+    {
+      NS_LOG_DEBUG ("Not all outgoing are in vain");
+      // suppress
+      // Don't do anything, we are still expecting data from some other face
+      return;
+    }
+  
+  NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
+
+  Ptr<Packet> nonNackInterest = Create<Packet> ();
+  header->SetNack (CcnxInterestHeader::NORMAL_INTEREST);
+  nonNackInterest->AddHeader (*header);
+  
+  bool propagated = m_forwardingStrategy->
+    PropagateInterest (pitEntry, incomingFace, header, nonNackInterest);
+
+  // // 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
+  // // ForwardingStrategy failed to find it. 
+  if (!propagated)
+     GiveUpInterest (pitEntry, header);
+}
+
 // Processing Interests
+//
+// !!! Key point.
+// !!! All interests should be answerred!!! Either later with data, immediately with data, or immediately with NACK
 void CcnxL3Protocol::OnInterest (const Ptr<CcnxFace> &incomingFace,
                                  Ptr<CcnxInterestHeader> &header,
                                  const Ptr<const Packet> &packet)
 {
-  NS_LOG_LOGIC ("Receiving interest from " << &incomingFace);
-  m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> (), incomingFace);
+  NS_LOG_FUNCTION (incomingFace << header << packet);
+  // m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> (), incomingFace);
 
-    
-    if( header->IsNack () )
-    {
-        NS_LOG_INFO("============");
-        NS_LOG_INFO("NACK");
-        NS_LOG_INFO("==========");
-        /*if( header->IsCongested () == false )
-            m_pit->LeakBucket(incomingFace,1);
-        
-        
-        m_droppedInterestsTrace (header, DROP_CONGESTION,
-                                 m_node->GetObject<Ccnx> (), incomingFace);
-        
-        m_pit->modify(pitEntry, CcnxPitEntry::DeleteOutgoing(incomingFace));*/
-    }
+  // Lookup of Pit (and associated Fib) entry for this Interest 
+  tuple<const CcnxPitEntry&,bool,bool> ret = m_pit->Lookup (*header);
+  CcnxPitEntry const& pitEntry = ret.get<0> ();
+  // bool isNew = ret.get<1> ();
+  bool isDuplicated = ret.get<2> ();
 
-    
-    
-    
-  // Lookup of Pit and Fib entries for this Interest 
-  CcnxFibEntryContainer::type::iterator fibEntry;
-  CcnxPitEntryContainer::type::iterator pitEntry = m_pit->Lookup (*header, fibEntry);  
-    
-  // No matter is it duplicate or not, if it is a NACK message, remove all possible incoming
-  // entries for this interface (NACK means that neighbor gave up trying and there is no
-  // point of sending data in this direction)
-    NS_LOG_INFO("Before (header->IsNack()) && (pitEntry != m_pit->end ())");
-  if ((header->IsNack()) && (pitEntry != m_pit->end ()))
+  if (isDuplicated) 
     {
-      //m_pit->erase (pitEntry);
-        NS_LOG_INFO("TRUE");
-        m_pit->modify(pitEntry, CcnxPitEntry::DeleteIncoming(incomingFace));
-    }
-    
-    NS_LOG_INFO("Before WasRecentlySatisfied");
-    /*if (m_rit->WasRecentlySatisfied (*header))
-    {
-        return;
-    }*/
-  if (m_rit->WasRecentlySatisfied (*header))
-    {
-        NS_LOG_INFO("------------");
-        NS_LOG_INFO("Entering WasRecentlySatisfied");
-        NS_LOG_INFO("------------");
-      // duplicate interests (same nonce) from applications are just ignored
-      if (incomingFace->IsLocal() == true) 
-          return;
-        
-      // Update metric status for the incoming interface in the corresponding FIB entry
-      /*if (fibEntry != m_fib->end())
-        m_fib->modify (m_fib->iterator_to (pitEntry->m_fibEntry),
-                       CcnxFibEntry::UpdateStatus(incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+      /**
+       * This condition will handle "routing" loops and also recently satisfied interests.
+       * Every time interest is satisfied, PIT entry (with empty incoming and outgoing faces)
+       * is kept for another small chunk of time.
+       */
       
-      //Trace duplicate interest  
-      m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
-                               m_node->GetObject<Ccnx> (), incomingFace);
-        
-      bool isMine = false;
-      //TypeId tid = TypeId ("ns3::CcnxProducer");
-      for(uint32_t i=0; i<m_node->GetNApplications();i++)
-        {
-            Ptr<Application> app = m_node->GetApplication(i);
-            NS_LOG_INFO("ApplicationName = " << app->GetTypeId().GetName());
-            if(app->GetTypeId().GetName() == "ns3::CcnxProducer")
-              {
-                if((DynamicCast<CcnxProducer>(app))->GetPrefix () == header->GetName ())
-                {
-                    isMine = true;
-                    break;
-                }
-              }
-        }
-    
-      Ptr<Packet> contentObject = m_contentStore->Lookup (header);
-      if ((isMine == true) || (contentObject != NULL))
-        {
-            //never respond with NACK to NACK
-            if(header->IsNack () )
-                return;
-            
-            // always return a duplicate packet
-            header->SetNack(true);
-            //Trace duplicate interest  
-            m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
-                                     m_node->GetObject<Ccnx> (), incomingFace);
+      // //Trace duplicate interest  
+      // m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST, m_node->GetObject<Ccnx> (), incomingFace);
 
-            SendInterest(incomingFace, header, packet->Copy());
-			
-			return;
-        }  
-           
-        
-      // check PIT.  or there is no outgoing entry for this interface,
-      // silently drop the duplicate packet
-        
-      // If no entry found, silently drop
-      if( pitEntry == m_pit->end() ) 
-        return;
-        
-      // If PIT entry timed out, silently drop
-      if( pitEntry->m_timerExpired == true ) 
-        return;
-        
-      // loop?
-        
-      // Check if there is no outgoing entry for the interface or different nonce
-      // (i.e., got a duplicate packet, but we haven't sent interest to this
-      // interface)
-      //
-      // This case means that there is a loop in the network.
-      // So, prune this link, but do not remove PIT entry
-        
-      // Alex, check this condition!!
-      if(pitEntry->m_outgoing.size () == 0)
-        {
-            //never respond with NACK to NACK
-            if(header->IsNack () )
-                return;
-            
-            // always return a duplicate packet
-            header->SetNack(true);
-            //Trace duplicate interest  
-            m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
-                                     m_node->GetObject<Ccnx> (), incomingFace);
+      NS_LOG_DEBUG ("Sending NACK_LOOP");
+      header->SetNack (CcnxInterestHeader::NACK_LOOP);
+      Ptr<Packet> nack = Create<Packet> ();
+      nack->AddHeader (*header);
 
-            SendInterest(incomingFace, header, packet->Copy());
-            return;
-        }
+      incomingFace->Send (nack);
       
-        
-        // At this point:
-		// - there is a non-expired PIT entry,
-		// - there is an outgoing interest to the interface, and
-		// - a nonce in outgoing entry is equal to a nonce in the received duplicate packet
-        
-		// Should perform:
-		// Cleaning outgoing entry
-		// If there are no outgoing interests and available interfaces left (pe->availableInterfaces),
-		// prune all incoming interests, otherwise allow forwarding of the interest
-		if( header->IsNack () )
-		{
-			if( header->IsCongested () == false )
-                m_pit->LeakBucket(incomingFace,1);
-            
-            m_pit->modify(pitEntry, CcnxPitEntry::DeleteOutgoing(incomingFace));
-        }
-		else
-		{
-			//poit->waitingInVain = true;
-		}
-
-        
-        // prune all incoming interests
-        if((pitEntry->m_outgoing.size() ==0) && (pitEntry->m_fibEntry.m_faces.size() == 0))
-        {
-            BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry->m_incoming)
-            {
-                if(face.m_face->IsLocal() == false)
-                {
-                  // check all entries if the name of RIT entry matches the name of interest
-                  for (CcnxRitByNonce::type::iterator it = m_rit->begin(); it != m_rit->end(); it++)
-                  {
-                    if (it->m_prefix == pitEntry->GetPrefix() )
-                      {
-                        
-                        header->SetNonce(it->m_nonce);
-                        header->SetNack(true);
-                        SendInterest(face.m_face, header, packet->Copy());
-                        break;
-                      }
-                  }
-                }
-             }
-            
-            // Finally, remote the PIT entry
-            m_pit->erase (pitEntry);
-            
-            return; // stop processing
-        }
-        
-      if(pitEntry->m_fibEntry.m_faces.size() == 0)  
-        return;*/
-        return;
-    }
-    
-    
-    
-  // Otherwise,
-  // propagate the interest
-  //
-  // method `propagateInterest' can/should try different interface
-  // from `availableInterfaces' list
-    
-  NS_LOG_INFO("Before SetRecentlySatisfied");
-  m_rit->SetRecentlySatisfied (*header); 
-
-  NS_LOG_INFO("Cache Lookup for " << header->GetName());
-  Ptr<Packet> contentObject = m_contentStore->Lookup (header);
-  if (contentObject != NULL)
-    {
-      NS_LOG_INFO("Found in cache");
-        
-      TransmittedDataTrace (contentObject, CACHED,
-                            m_node->GetObject<Ccnx> (), incomingFace);
-      incomingFace->Send (contentObject);
+      // //Trace duplicate interest  
+      // m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST, m_node->GetObject<Ccnx> (), incomingFace);
       return;
     }
+
+  Ptr<Packet> contentObject;
+  Ptr<const CcnxContentObjectHeader> contentObjectHeader; // unused for now
+  tie (contentObject, contentObjectHeader) = m_contentStore->Lookup (header);
+  if (contentObject != 0)
+    {
+      NS_ASSERT (contentObjectHeader != 0);
+      
+      NS_LOG_LOGIC("Found in cache");
+        
+      // TransmittedDataTrace (contentObject, CACHED,
+      //                       m_node->GetObject<Ccnx> (), incomingFace);
+      incomingFace->Send (contentObject);
+
+      // Set pruning timout on PIT entry (instead of deleting the record)
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     bind (&CcnxPitEntry::SetExpireTime, ll::_1,
+                           Simulator::Now () + m_pit->GetPitEntryPruningTimeout ()));
+      return;
+    }
+
+  // \todo Detect retransmissions. Not yet sure how...
   
   // Data is not in cache
-  NS_LOG_INFO("Before inFace and OutFace");
-  CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry->m_incoming.find (incomingFace);
-  CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry->m_outgoing.find (incomingFace);
-    
-     NS_LOG_INFO("Before (pitEntry != m_pit->end()) && (pitEntry->m_timerExpired == false)");
-  if ((pitEntry != m_pit->end()) && (pitEntry->m_timerExpired == false))
-    {
-        NS_LOG_INFO("Entering (pitEntry != m_pit->end()) && (pitEntry->m_timerExpired == false)");
-        
-        if(inFace->m_face == NULL)
-            NS_LOG_INFO("in face is null");
-        if(outFace->m_face == NULL)
-            NS_LOG_INFO("outface is null");
-        if(outFace == pitEntry->m_outgoing.end())
-            NS_LOG_INFO("OUTFACE = END");
-        
-        // If we're expecting data from the interface we got the interest from ("producer" asks us for "his own" data)
-        // Give up this interface, but keep a small hope when the returned packet doesn't have PRUNE status
-        if(outFace != pitEntry->m_outgoing.end()) // this is correct
-        {
-            NS_LOG_INFO("Entering outFace != pitEntry->m_outgoing.end()");
-            if( header->IsCongested() == true )
-            {
-                NS_LOG_INFO("Entering header->IsCongested() == true");
-                m_pit->LeakBucket(incomingFace, 1);
-                m_pit->modify (pitEntry, CcnxPitEntry::DeleteOutgoing(outFace->m_face));
-            }
-            //else
-            //    poit->waitingInVain = true;
-            
-            // Update metric status for the incoming interface in the corresponding FIB entry
-            if(fibEntry != m_fib->end())
-                m_fib->modify(m_fib->iterator_to (pitEntry->m_fibEntry),
-                              CcnxFibEntry::UpdateStatus(incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
-        }
-    }
+  CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry.m_incoming.find (incomingFace);
+  CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry.m_outgoing.find (incomingFace);
 
-  NS_LOG_INFO("Before (pitEntry->m_outgoing.size() == 0) && (pitEntry->m_fibEntry.m_faces.size() == 0)");
-  if((pitEntry->m_outgoing.size() == 0) && (pitEntry->m_fibEntry.m_faces.size() == 0))
-      // prune all incoming interests
-    {
-        
-        for(CcnxPitEntryContainer::type::iterator iter = m_pit->begin();
-            iter != m_pit->end(); 
-            iter++)
-        {
-            /*for(CcnxPitEntryIncomingFaceContainer::type::iterator face = iter->m_incoming.begin();
-                face != iter->m_incoming.end();
-                face++)*/
-            BOOST_FOREACH (const CcnxPitEntryIncomingFace face, iter->m_incoming)
-            {
-              if(face.m_face->IsLocal() == true)
-                {
-                    //returnInterestToApp( pkt, -piit->interfaceIndex );
-                    //continue;
-                }
-                
-                // check all entries if the name of RIT entry matches the name of interest
-                for (CcnxRitByNonce::type::iterator it = m_rit->begin(); it != m_rit->end(); it++)
-              {
-                if (it->m_prefix == iter->GetPrefix() )
-                  {
-                    header->SetNonce(it->m_nonce);
-                    header->SetNack(true);
-                    SendInterest(face.m_face, header, packet->Copy());
-                  }
-              }
-            }
-
-        }
-            
-        m_pit->erase(pitEntry);
-        
-        return; // there is nothing else to do
-    }
-
-    // Suppress this interest only if we're still expecting data from some other interface
-    if( pitEntry->m_outgoing.size() > 0 ) 
-    {
-        return; //ok. Now we can suppress this interest
-    }
-    
-    
-    // Prune and delete PIT entry if there are no available interfaces to propagate interest
-    if( pitEntry->m_fibEntry.m_faces.size() == 0)
-    {
-        //if no match is found in the FIB, drop packet
-        //printf( "Node %d: cannot process Interest packet %s (no interfaces left)\n", _node->nodeId, pkt->contentName );
-		
-        if(incomingFace->IsLocal() == false)
-        {
-            header->SetNack(true);
-            m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
-                                     m_node->GetObject<Ccnx> (), incomingFace);
-            SendInterest(incomingFace, header, packet->Copy());
-        }
-        
-        m_pit->erase(pitEntry);
-        
-    }
-
-    
-    
-    // otherwise, try one of the available interfaces
-    
-  // suppress interest if 
-  /*if (pitEntry->m_incoming.size () != 0 && // not a new PIT entry and
-      inFace != pitEntry->m_incoming.end ()) // existing entry, but interest received via different face
-    {
-      m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
-                                m_node->GetObject<Ccnx> (), incomingFace);
-      return;
-    }*/
-    
-    
-    //just in case of bug
-    header->SetNack(false);
-    header->SetCongested(false);
+  bool isRetransmitted = false;
   
-    NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
+  if (inFace != pitEntry.m_incoming.end ())
+    {
+      // CcnxPitEntryIncomingFace.m_arrivalTime keeps track arrival time of the first packet... why?
 
-    m_pit->modify (pitEntry, CcnxPitEntry::AddIncoming(incomingFace));
-    
-    bool propagated = m_forwardingStrategy->
-                      PropagateInterest (pitEntry, fibEntry,incomingFace, header, packet,
-                                         MakeCallback (&CcnxL3Protocol::SendInterest, this)
-                                        );
-
-    // If interest wasn't propagated further (probably, a limit is reached),
-    // prune and delete PIT entry if there are no outstanding interests.
-    // Stop processing otherwise.
-    if( (!propagated) && (pitEntry->m_outgoing.size() == 0)) // this line works
-      {
-        BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry->m_incoming)
-          {
-            header->SetNack(true);
-            header->SetCongested(true);
-            NS_LOG_INFO("Sending CONGESTION packet");
-            SendInterest (face.m_face, header, packet->Copy());
-                
-            m_droppedInterestsTrace (header, DROP_CONGESTION,
-                                         m_node->GetObject<Ccnx> (), incomingFace);
-          }
-      
-          m_pit->erase (pitEntry);
-      }
-    /*}
+      isRetransmitted = true;
+      // this is almost definitely a retransmission. But should we trust the user on that?
+    }
   else
     {
-      m_droppedInterestsTrace (header, NDN_PIT_TIMER_EXPIRED,
-                                 m_node->GetObject<Ccnx> (), incomingFace);
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::var(inFace) = ll::bind (&CcnxPitEntry::AddIncoming, ll::_1, incomingFace));
+    }
+
+  // update PIT entry lifetime
+  m_pit->modify (m_pit->iterator_to (pitEntry),
+                 ll::bind (&CcnxPitEntry::UpdateLifetime, ll::_1,
+                           header->GetInterestLifetime ()));
+  
+  if (outFace != pitEntry.m_outgoing.end ())
+    {
+      // got a non-duplicate interest from the face we have sent interest to
+      // Probably, there is no point in waiting data from that face... Not sure yet
+
+      // If we're expecting data from the interface we got the interest from ("producer" asks us for "his own" data)
+      // Mark interface YELLOW, but keep a small hope that data will come eventually.
+
+      // ?? not sure if we need to do that ?? ...
+      
+      m_fib->modify(m_fib->iterator_to (pitEntry.m_fibEntry),
+                    ll::bind (&CcnxFibEntry::UpdateStatus,
+                              ll::_1, incomingFace, CcnxFibFaceMetric::NDN_FIB_YELLOW));
+    }
+
+  if (!isRetransmitted &&
+      pitEntry.AreTherePromisingOutgoingFacesExcept (incomingFace))
+    { // Suppress this interest if we're still expecting data from some other face
+      
+      // We are already expecting data later in future. Suppress the interest
+      // m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST, m_node->GetObject<Ccnx> (), incomingFace);
       return;
-    }*/
+    }
+  
+  /////////////////////////////////////////////////////////////////////
+  // Propagate
+  /////////////////////////////////////////////////////////////////////
+  
+  NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
+  
+  bool propagated = m_forwardingStrategy->
+    PropagateInterest (pitEntry, incomingFace, header, packet);
+
+  if (isRetransmitted) //give another chance if retransmitted
+    {
+      // increase max number of allowed retransmissions
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind (&CcnxPitEntry::IncreaseAllowedRetxCount, ll::_1));
+
+      // try again
+      propagated = m_forwardingStrategy->
+        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
+  // ForwardingStrategy failed to find it. 
+  if (!propagated)
+    GiveUpInterest (pitEntry, header);
 }
 
+void
+CcnxL3Protocol::GiveUpInterest (const CcnxPitEntry &pitEntry,
+                                Ptr<CcnxInterestHeader> header)
+{
+  Ptr<Packet> packet = Create<Packet> ();
+  header->SetNack (CcnxInterestHeader::NACK_GIVEUP_PIT);
+  packet->AddHeader (*header);
+
+  BOOST_FOREACH (const CcnxPitEntryIncomingFace &incoming, pitEntry.m_incoming)
+    {
+      incoming.m_face->Send (packet->Copy ());
+
+      // m_droppedInterestsTrace (header, DROP_CONGESTION,
+      //                          m_node->GetObject<Ccnx> (), incomingFace);
+    }
+  // All incoming interests cannot be satisfied. Remove them
+  m_pit->modify (m_pit->iterator_to (pitEntry),
+                 ll::bind (&CcnxPitEntry::ClearIncoming, ll::_1));
+
+  // Set pruning timout on PIT entry (instead of deleting the record)
+  m_pit->modify (m_pit->iterator_to (pitEntry),
+                 ll::bind (&CcnxPitEntry::SetExpireTime, ll::_1,
+                           Simulator::Now () + m_pit->GetPitEntryPruningTimeout ()));
+}
+
+
 // Processing ContentObjects
-void CcnxL3Protocol::OnData (const Ptr<CcnxFace> &incomingFace,
-                             Ptr<CcnxContentObjectHeader> &header,
-                             Ptr<Packet> &payload,
-                             const Ptr<const Packet> &packet)
+void
+CcnxL3Protocol::OnData (const Ptr<CcnxFace> &incomingFace,
+                        Ptr<CcnxContentObjectHeader> &header,
+                        Ptr<Packet> &payload,
+                        const Ptr<const Packet> &packet)
 {
     
-  NS_LOG_LOGIC ("Receiving contentObject from " << &incomingFace);
-  m_receivedDataTrace (header, payload, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+  NS_LOG_FUNCTION (incomingFace << header << payload << packet);
+  // m_receivedDataTrace (header, payload, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
 
   // 1. Lookup PIT entry
   try
@@ -664,49 +553,55 @@
       const CcnxPitEntry &pitEntry = m_pit->Lookup (*header);
 
       // Note that with MultiIndex we need to modify entries indirectly
-  
-      // Update metric status for the incoming interface in the corresponding FIB entry
-      m_fib->modify (m_fib->iterator_to (pitEntry.m_fibEntry),
-                     CcnxFibEntry::UpdateStatus (incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN));
-  
-      // Add or update entry in the content store
-      NS_LOG_INFO("Cached " << header->GetName());
-      m_contentStore->Add (header, payload);
 
-      CcnxPitEntryOutgoingFaceContainer::type::iterator
-        out = pitEntry.m_outgoing.find (incomingFace);
+      CcnxPitEntryOutgoingFaceContainer::type::iterator out = pitEntry.m_outgoing.find (incomingFace);
   
       // If we have sent interest for this data via this face, then update stats.
       if (out != pitEntry.m_outgoing.end ())
         {
-          m_pit->modify (m_pit->iterator_to (pitEntry),
-                         CcnxPitEntry::EstimateRttAndRemoveFace(out, m_fib));
-          // face will be removed in the above call
+          m_fib->modify (m_fib->iterator_to (pitEntry.m_fibEntry),
+                         ll::bind (&CcnxFibEntry::UpdateFaceRtt,
+                                   ll::_1,
+                                   incomingFace,
+                                   Simulator::Now () - out->m_sendTime));
         }
       else
         {
-          NS_LOG_WARN ("Node "<< m_node->GetId() <<
-                          ". PIT entry for "<< header->GetName ()<<" is valid, "
-                          "but outgoing entry for interface "<< incomingFace <<" doesn't exist\n");
+          // Unsolicited data, but we're interested in it... should we get it?
+          // Potential hole for attacks
+          
+          NS_LOG_ERROR ("Node "<< m_node->GetId() <<
+                       ". PIT entry for "<< header->GetName ()<<" is valid, "
+                        "but outgoing entry for interface "<< boost::cref(*incomingFace) <<" doesn't exist\n");
+
+          // ignore unsolicited data
+          return;
         }
 
+      // Update metric status for the incoming interface in the corresponding FIB entry
+      m_fib->modify (m_fib->iterator_to (pitEntry.m_fibEntry),
+                     ll::bind (&CcnxFibEntry::UpdateStatus, ll::_1,
+                               incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN));
+  
+      // Add or update entry in the content store
+      m_contentStore->Add (header, payload);
+
       //satisfy all pending incoming Interests
-      BOOST_FOREACH (const CcnxPitEntryIncomingFace &interest, pitEntry.m_incoming)
+      BOOST_FOREACH (const CcnxPitEntryIncomingFace &incoming, pitEntry.m_incoming)
         {
-          if (interest.m_face == incomingFace) continue; 
+          if (incoming.m_face != incomingFace)
+            incoming.m_face->Send (packet->Copy ());
 
-          // may not work either because of 'const' thing
-          interest.m_face->Send (packet->Copy ()); // unfortunately, we have to copy packet... 
-          m_transmittedDataTrace (header, payload, FORWARDED, m_node->GetObject<Ccnx> (), interest.m_face);
+          // successfull forwarded data trace
         }
-
-      m_pit->modify (m_pit->iterator_to (pitEntry), CcnxPitEntry::ClearIncoming()); // satisfy all incoming interests
-
-      if( pitEntry.m_outgoing.size()==0 ) // remove PIT when all outgoing interests are "satisfied"
-        {
-          m_pit->erase (m_pit->iterator_to (pitEntry));
-        }
-
+      // All incoming interests are satisfied. Remove them
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind (&CcnxPitEntry::ClearIncoming, ll::_1));
+      
+      // Set pruning timout on PIT entry (instead of deleting the record)
+      m_pit->modify (m_pit->iterator_to (pitEntry),
+                     ll::bind (&CcnxPitEntry::SetExpireTime, ll::_1,
+                                  Simulator::Now () + m_pit->GetPitEntryPruningTimeout ()));
     }
   catch (CcnxPitEntryNotFound)
     {
@@ -714,66 +609,42 @@
       //    (unsolicited data packets should not "poison" content store)
       
       //drop dulicated or not requested data packet
-      m_droppedDataTrace (header, payload, NDN_UNSOLICITED_DATA, m_node->GetObject<Ccnx> (), incomingFace);
+      // m_droppedDataTrace (header, payload, NDN_UNSOLICITED_DATA, m_node->GetObject<Ccnx> (), incomingFace);
       return; // do not process unsoliced data packets
     }
 }
 
 void
-CcnxL3Protocol::SendInterest (const Ptr<CcnxFace> &face,
-                              const Ptr<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");
-
-  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);
-    }
-}
-
-void
-CcnxL3Protocol::SendContentObject (const Ptr<CcnxFace> &face,
-                                   const Ptr<CcnxContentObjectHeader> &header,
-                                   const Ptr<Packet> &packet)
-{
-  NS_LOG_FUNCTION (this << "packet: " << &packet << ", face: "<< &face);
-  NS_ASSERT_MSG (face != 0, "Face should never be NULL");
-
-  NS_ASSERT_MSG (false, "Should not be called for now");
+  m_bucketLeakInterval = interval;
   
-  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);
-    }
+  if (m_bucketLeakEvent.IsRunning ())
+    m_bucketLeakEvent.Cancel ();
+
+  m_bucketLeakEvent = Simulator::Schedule (m_bucketLeakInterval,
+                                           &CcnxL3Protocol::LeakBuckets, this);
 }
 
-Ptr<CcnxPit>
-CcnxL3Protocol::GetPit()
+Time
+CcnxL3Protocol::GetBucketLeakInterval () const
 {
-    return m_pit;
+  return m_bucketLeakInterval;
 }
 
-void
-CcnxL3Protocol::ScheduleLeakage()
+void 
+CcnxL3Protocol::LeakBuckets ()
 {
-    m_pit->LeakBuckets();
-    Time interval = MilliSeconds (NDN_INTEREST_RESET_PERIOD);
-    Simulator::Schedule (interval, &CcnxL3Protocol::ScheduleLeakage, this);
+  // NS_LOG_FUNCTION (this);
+
+  BOOST_FOREACH (const Ptr<CcnxFace> &face, m_faces)
+    {
+      face->LeakBucket (m_bucketLeakInterval);
+    }
+
+  m_bucketLeakEvent = Simulator::Schedule (m_bucketLeakInterval,
+                                           &CcnxL3Protocol::LeakBuckets,
+                                           this);
 }
+
 } //namespace ns3
diff --git a/model/ccnx-l3-protocol.h b/model/ccnx-l3-protocol.h
index 3e2c870..f5c19d9 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<CcnxInterestHeader> &header,
-                             const Ptr<Packet> &packet);
-  virtual void SendContentObject (const Ptr<CcnxFace> &face,
-                                  const Ptr<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);
@@ -152,8 +151,11 @@
   
   Ptr<CcnxPit> GetPit();
   
-  void ScheduleLeakage();
-protected:
+  // void ScheduleLeakage();
+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,11 +164,23 @@
    * @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);
 
+  /**
+   * \brief Processing of incoming CCNx NACKs. Note, these packets, like interests, do not have payload
+   * 
+   * Processing NACK packets
+   * @param face    incoming face
+   * @param header  deserialized Interest header
+   * @param packet  original packet
+   */
+  void
+  OnNack (const Ptr<CcnxFace> &face,
+          Ptr<CcnxInterestHeader> &header,
+          const Ptr<const Packet> &p);
   
   /**
    * \brief Actual processing of incoming CCNx content objects
@@ -177,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,
@@ -196,20 +210,22 @@
   CcnxL3Protocol(const CcnxL3Protocol &); ///< copy constructor is disabled
   CcnxL3Protocol &operator = (const CcnxL3Protocol &); ///< copy operator is disabled
 
-  // /**
-  //  * \brief Fake function. should never be called. Just to trick C++ to compile
-  //  */
-  // virtual void
-  // ReceiveAndProcess (const Ptr<CcnxFace> face, Ptr<Header> header, Ptr<Packet> p);
+  /// \brief Set buckets leak interval
+  void
+  SetBucketLeakInterval (Time interval);
 
-  /**
-   * \brief A helper function
-   */
-  void TransmittedDataTrace (Ptr<Packet>,
-                             ContentObjectSource,
-                             Ptr<Ccnx>, Ptr<const CcnxFace>);
+  /// \brief Get buckets leak interval
+  Time
+  GetBucketLeakInterval () const;
   
-  
+  /// \brief Periodically generate pre-calculated number of tokens (leak buckets)
+  void
+  LeakBuckets ();
+
+  void
+  GiveUpInterest (const CcnxPitEntry &pitEntry,
+                  Ptr<CcnxInterestHeader> header);
+
 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;
@@ -218,36 +234,33 @@
   Ptr<Node> m_node; ///< \brief node on which ccnx stack is installed
   Ptr<CcnxForwardingStrategy> m_forwardingStrategy; ///< \brief smart pointer to the selected forwarding strategy
 
-  Ptr<CcnxRit> m_rit; ///< \brief RIT (recently interest table)
+  // Ptr<CcnxRit> m_rit; ///< \brief RIT (recently interest table)
   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 5020877..0f8ef27 100644
--- a/model/ccnx-local-face.cc
+++ b/model/ccnx-local-face.cc
@@ -25,10 +25,11 @@
 #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"
+#include "ns3/ccnx-app.h"
+
 #include "ccnx-interest-header.h"
 #include "ccnx-content-object-header.h"
 
@@ -37,24 +38,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->GetNode ())
+  , m_app (app)
 {
-  NS_LOG_FUNCTION (this);
-  m_isLocal = true;
+  NS_LOG_FUNCTION (this << app);
+  
+  NS_ASSERT (m_app != 0);
 }
 
 CcnxLocalFace::~CcnxLocalFace ()
@@ -65,30 +55,17 @@
 void
 CcnxLocalFace::RegisterProtocolHandler (ProtocolHandler handler)
 {
-  m_protocolHandler = handler;
-}
+  NS_LOG_FUNCTION (this);
 
-void
-CcnxLocalFace::SetInterestHandler (InterestHandler onInterest)
-{
-  m_onInterest = onInterest;
-}
+  CcnxFace::RegisterProtocolHandler (handler);
 
-void
-CcnxLocalFace::SetContentObjectHandler (ContentObjectHandler onContentObject)
-{
-  m_onContentObject = onContentObject;
+  m_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
     {
@@ -96,23 +73,27 @@
       switch (type)
         {
         case CcnxHeaderHelper::INTEREST:
-          if (!m_onInterest.IsNull ())
-            {
-              Ptr<CcnxInterestHeader> header = Create<CcnxInterestHeader> ();
-              p->RemoveHeader (*header);
-              m_onInterest (header);
-            }
-          break;
+          {
+            Ptr<CcnxInterestHeader> header = Create<CcnxInterestHeader> ();
+            p->RemoveHeader (*header);
+
+            if (header->GetNack () > 0)
+              m_app->OnNack (header);
+            else
+              m_app->OnInterest (header);
+          
+            break;
+          }
         case CcnxHeaderHelper::CONTENT_OBJECT:
-          if (!m_onContentObject.IsNull ())
-            {
-              static CcnxContentObjectTail tail;
-              Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
-              p->RemoveHeader (*header);
-              p->RemoveTrailer (tail);
-              m_onContentObject (header, p/*payload*/);
-            }
-          break;
+          {
+            static CcnxContentObjectTail tail;
+            Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
+            p->RemoveHeader (*header);
+            p->RemoveTrailer (tail);
+            m_app->OnContentObject (header, p/*payload*/);
+          
+            break;
+          }
         }
     }
   catch (CcnxUnknownHeaderException)
@@ -121,13 +102,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..c8c4515 100644
--- a/model/ccnx-local-face.h
+++ b/model/ccnx-local-face.h
@@ -30,6 +30,7 @@
 class CcnxInterestHeader;
 class CcnxContentObjectHeader;
 class Packet;
+class CcnxApp;
 
 /**
  * \ingroup ccnx-face
@@ -44,61 +45,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_app;
 };
 
 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..fdffe91 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<>
+// void
+// CcnxNameComponents::Add (const std::string &string)
+// {
+//   m_prefix.push_back (string);
+// }
+
+template<class T>
+void
+CcnxNameComponents::Add (const T &value)
+{
+  std::ostringstream os;
+  os << value;
+  m_prefix.push_back (os.str ());
 }
 
 bool
diff --git a/model/ccnx-net-device-face.cc b/model/ccnx-net-device-face.cc
index e06a741..468d8f1 100644
--- a/model/ccnx-net-device-face.cc
+++ b/model/ccnx-net-device-face.cc
@@ -32,28 +32,17 @@
 
 namespace ns3 {
 
-// NS_OBJECT_ENSURE_REGISTERED (CcnxNetDeviceFace);
-
-// TypeId 
-// CcnxNetDeviceFace::GetTypeId ()
-// {
-//   static TypeId tid = TypeId ("ns3::CcnxNetDeviceFace")
-//     .SetGroupName ("Ccnx")
-//     .SetParent<CcnxFace> ()
-//   ;
-//   return tid;
-// }
-
 /** 
  * 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;
-  m_isLocal = false;
+  NS_ASSERT_MSG (m_netDevice != 0, "CcnxNetDeviceFace needs to be assigned a valid NetDevice");
 }
 
 CcnxNetDeviceFace::~CcnxNetDeviceFace ()
@@ -61,11 +50,6 @@
   NS_LOG_FUNCTION_NOARGS ();
 }
 
-CcnxNetDeviceFace::CcnxNetDeviceFace (const CcnxNetDeviceFace &)
-{
-    m_isLocal = false;
-}
-
 CcnxNetDeviceFace& CcnxNetDeviceFace::operator= (const CcnxNetDeviceFace &)
 {
   return *this;
@@ -80,31 +64,26 @@
 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);
 
+  CcnxFace::RegisterProtocolHandler (handler);
+  
   m_node->RegisterProtocolHandler (MakeCallback (&CcnxNetDeviceFace::ReceiveFromNetDevice, this),
                                    CcnxL3Protocol::ETHERNET_FRAME_TYPE, m_netDevice, true/*promiscuous mode*/);
 }
 
 void
-CcnxNetDeviceFace::Send (Ptr<Packet> packet)
+CcnxNetDeviceFace::SendImpl (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->GetMtu ()
+                 << " for Ccnx; fragmentation not supported");
 
   m_netDevice->Send (packet, m_netDevice->GetBroadcast (), 
-                  CcnxL3Protocol::ETHERNET_FRAME_TYPE);
+                     CcnxL3Protocol::ETHERNET_FRAME_TYPE);
 }
 
 // callback
@@ -116,7 +95,8 @@
                                          const Address &to,
                                          NetDevice::PacketType packetType)
 {
-  m_protocolHandler (Ptr<CcnxFace>(this), p);
+  NS_LOG_FUNCTION (device << p << protocol << from << to << packetType);
+  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-outgoing-face.cc b/model/ccnx-pit-entry-outgoing-face.cc
index ccdfb08..8527779 100644
--- a/model/ccnx-pit-entry-outgoing-face.cc
+++ b/model/ccnx-pit-entry-outgoing-face.cc
@@ -27,11 +27,17 @@
 CcnxPitEntryOutgoingFace::CcnxPitEntryOutgoingFace (Ptr<CcnxFace> face)
   : m_face (face)
   , m_sendTime (Simulator::Now ())
-  , m_retxNum (0)
-  // , m_nonce (nonce)
-  // , m_outstanding (true)
-  // , m_waitingInVain (false)
+  , m_retxCount (0)
+  , m_waitingInVain (false)
 {
 }
 
+void
+CcnxPitEntryOutgoingFace::UpdateOnRetransmit ()
+{
+  m_sendTime = Simulator::Now ();
+  m_retxCount++;
+  m_waitingInVain = false;
+}
+
 } // namespace ns3
diff --git a/model/ccnx-pit-entry-outgoing-face.h b/model/ccnx-pit-entry-outgoing-face.h
index 502f333..c0fe80f 100644
--- a/model/ccnx-pit-entry-outgoing-face.h
+++ b/model/ccnx-pit-entry-outgoing-face.h
@@ -38,14 +38,18 @@
   Time m_sendTime;          ///< \brief time when the first outgoing interest is sent (for RTT measurements)
                             ///< \todo handle problem of retransmitted interests... Probably, we should include something similar
                             ///<       to TimeStamp TCP option for retransmitted (i.e., only lost interests will suffer)
-  uint32_t m_retxNum;       ///< \brief number of retransmission
-  // int m_nonce;              ///< \brief nonce of the outgoing Interest
-  // bool m_outstanding;		///< \brief flag to indicate that this interest is currently pending
-  // bool m_waitingInVain;		///< \brief when flag is set, we do not expect data for this interest, only a small hope that it will happen
+  uint32_t m_retxCount;     ///< \brief number of retransmission
+  bool m_waitingInVain;     ///< \brief when flag is set, we do not expect data for this interest, only a small hope that it will happen
 	
 public:
   CcnxPitEntryOutgoingFace (Ptr<CcnxFace> face);
 
+  /**
+   * @brief Update outgoing entry upon retransmission
+   */
+  void
+  UpdateOnRetransmit ();
+
   bool operator== (const CcnxPitEntryOutgoingFace &dst) { return *m_face==*dst.m_face; }
   bool operator== (Ptr<CcnxFace> face) { return *m_face==*face; }
 
diff --git a/model/ccnx-pit-entry.cc b/model/ccnx-pit-entry.cc
index ddc471e..76c7997 100644
--- a/model/ccnx-pit-entry.cc
+++ b/model/ccnx-pit-entry.cc
@@ -23,135 +23,124 @@
 #include "ccnx-fib.h"
 
 #include "ns3/simulator.h"
+#include "ns3/log.h"
+
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
+
+NS_LOG_COMPONENT_DEFINE ("CcnxPitEntry");
 
 namespace ns3
 {
 
-// struct SearchByFace
-// {
-//   /**
-//    * \brief To perform effective searches by CcnxFace
-//    */
-//   bool
-//   operator() (const CcnxPitIncomingInterest &m, const Ptr<CcnxFace> &face) const
-//   {
-//     return *(m.m_face) < *face;
-//   } 
-
-//   /**
-//    * \brief To perform effective searches by CcnxFace
-//    */
-//   bool
-//   operator() (const Ptr<CcnxFace> &face, const CcnxPitIncomingInterest &m) const
-//   {
-//     return *face < *(m.m_face);
-//   } 
-
-//   /**
-//    * \brief To perform effective searches by CcnxFace
-//    */
-//   bool
-//   operator() (const CcnxPitOutgoingInterest &m, const Ptr<CcnxFace> &face) const
-//   {
-//     return *(m.m_face) < *face;
-//   } 
-
-//   /**
-//    * \brief To perform effective searches by CcnxFace
-//    */
-//   bool
-//   operator() (const Ptr<CcnxFace> &face, const CcnxPitOutgoingInterest &m) const
-//   {
-//     return *face < *(m.m_face);
-//   } 
-// };
-
-
-CcnxPitEntry::CcnxPitEntry (Ptr<CcnxNameComponents> prefix, const CcnxFibEntry &fibEntry)
+CcnxPitEntry::CcnxPitEntry (Ptr<CcnxNameComponents> prefix,
+                            const Time &expireTime,
+                            const CcnxFibEntry &fibEntry)
   : m_prefix (prefix)
   , m_fibEntry (fibEntry)
-  // , m_expireTime (?)
-  , m_timerExpired (false)
-  , m_counterExpirations (0)
-{
-}
-
-const CcnxNameComponents &
-CcnxPitEntry::GetPrefix () const
-{
-  return *m_prefix;
-}
-
-// CcnxPitEntry::SetFibEntry::SetFibEntry (Ptr<CcnxFibEntry> fib)
-//   : m_fib (fib)
-// {
-// }
-
-// void
-// CcnxPitEntry::SetFibEntry::operator() (CcnxPitEntry &entry)
-// {
-//   entry.m_fib = m_fib;
-// }
-
-void
-CcnxPitEntry::AddIncoming::operator() (CcnxPitEntry &entry)
-{
-  entry.m_incoming.insert (CcnxPitEntryIncomingFace (m_face));
-}
-
-void
-CcnxPitEntry::DeleteIncoming::operator() (CcnxPitEntry &entry)
-{
-  entry.m_incoming.erase (m_face);
-}
-
-void
-CcnxPitEntry::AddOutgoing::operator() (CcnxPitEntry &entry)
-{
-  entry.m_outgoing.insert (CcnxPitEntryOutgoingFace (m_face));
-}
-
-void
-CcnxPitEntry::DeleteOutgoing::operator() (CcnxPitEntry &entry)
-{
-  entry.m_outgoing.erase (m_face);
-}
-
-void
-CcnxPitEntry::ClearIncoming::operator() (CcnxPitEntry &entry)
-{
-  entry.m_incoming.clear ();
-}
-
-CcnxPitEntry::UpdateFibStatus::UpdateFibStatus (Ptr<CcnxFace> face,
-                                                CcnxFibFaceMetric::Status status,
-                                                Ptr<CcnxFib> fib)
-  : m_face (face)
-  , m_status (status)
-  , m_fib (fib)
+  , m_expireTime (Simulator::Now () + expireTime)
+  // , m_timerExpired (false)
+  // , m_counterExpirations (0)
+  , m_maxRetxCount (0)
 {
 }
 
 void
-CcnxPitEntry::UpdateFibStatus::operator() (CcnxPitEntry &entry)
+CcnxPitEntry::UpdateLifetime (const Time &offsetTime)
 {
-  NS_ASSERT_MSG (false, "Broken");
-  m_fib->modify (m_fib->iterator_to (entry.m_fibEntry),
-                 CcnxFibEntry::UpdateStatus (m_face, m_status));
+  Time newExpireTime = Simulator::Now () + offsetTime;
+  if (newExpireTime > m_expireTime)
+    m_expireTime = newExpireTime;
+}
+
+CcnxPitEntryIncomingFaceContainer::type::iterator
+CcnxPitEntry::AddIncoming (Ptr<CcnxFace> face)
+{
+  std::pair<CcnxPitEntryIncomingFaceContainer::type::iterator,bool> ret = 
+    m_incoming.insert (CcnxPitEntryIncomingFace (face));
+
+  NS_ASSERT_MSG (ret.second, "Something is wrong");
+
+  return ret.first;
 }
 
 void
-CcnxPitEntry::EstimateRttAndRemoveFace::operator() (CcnxPitEntry &entry)
+CcnxPitEntry::RemoveIncoming (Ptr<CcnxFace> face)
 {
-  // similar to Karn's Algorithm, we don't use RTT measurements for retx packets
-  if (m_outFace->m_retxNum>0)
-    return;
-
-  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);
+  m_incoming.erase (face);
 }
 
-}  
+
+CcnxPitEntryOutgoingFaceContainer::type::iterator
+CcnxPitEntry::AddOutgoing (Ptr<CcnxFace> face)
+{
+  std::pair<CcnxPitEntryOutgoingFaceContainer::type::iterator,bool> ret =
+    m_outgoing.insert (CcnxPitEntryOutgoingFace (face));
+
+  if (!ret.second)
+    { // outgoing face already exists
+      m_outgoing.modify (ret.first,
+                         ll::bind (&CcnxPitEntryOutgoingFace::UpdateOnRetransmit, ll::_1));
+    }
+
+  return ret.first;
+}
+
+void
+CcnxPitEntry::RemoveAllReferencesToFace (Ptr<CcnxFace> face)
+{
+  CcnxPitEntryIncomingFaceContainer::type::iterator incoming =
+    m_incoming.find (face);
+
+  if (incoming != m_incoming.end ())
+    m_incoming.erase (incoming);
+
+  CcnxPitEntryOutgoingFaceContainer::type::iterator outgoing =
+    m_outgoing.find (face);
+
+  if (outgoing != m_outgoing.end ())
+    m_outgoing.erase (outgoing);
+}
+
+void
+CcnxPitEntry::SetWaitingInVain (CcnxPitEntryOutgoingFaceContainer::type::iterator face)
+{
+  NS_LOG_DEBUG (boost::cref (*face->m_face));
+
+  m_outgoing.modify (face,
+                     (&ll::_1)->*&CcnxPitEntryOutgoingFace::m_waitingInVain = true);
+}
+
+bool
+CcnxPitEntry::AreAllOutgoingInVain () const
+{
+  NS_LOG_DEBUG (m_outgoing.size ());
+
+  bool inVain = true;
+  std::for_each (m_outgoing.begin (), m_outgoing.end (),
+                 ll::var(inVain) &= (&ll::_1)->*&CcnxPitEntryOutgoingFace::m_waitingInVain);
+
+  NS_LOG_DEBUG ("inVain " << inVain);
+  return inVain;
+}
+
+bool
+CcnxPitEntry::AreTherePromisingOutgoingFacesExcept (Ptr<CcnxFace> face) const
+{
+  bool inVain = true;
+  std::for_each (m_outgoing.begin (), m_outgoing.end (),
+                 ll::var(inVain) &=
+                 ((&ll::_1)->*&CcnxPitEntryOutgoingFace::m_face == face ||
+                  (&ll::_1)->*&CcnxPitEntryOutgoingFace::m_waitingInVain));
+
+  return !inVain;
+}
+
+void
+CcnxPitEntry::IncreaseAllowedRetxCount ()
+{
+  m_maxRetxCount++;
+}
+
+}
diff --git a/model/ccnx-pit-entry.h b/model/ccnx-pit-entry.h
index fa89b5e..162d7a5 100644
--- a/model/ccnx-pit-entry.h
+++ b/model/ccnx-pit-entry.h
@@ -34,6 +34,7 @@
 #include <boost/multi_index/hashed_index.hpp>
 #include <boost/multi_index/member.hpp>
 #include <boost/multi_index/mem_fun.hpp>
+#include <set>
 
 #include <iostream>
 
@@ -44,7 +45,7 @@
 
 namespace __ccnx_private
 {
-// class i_face {};
+class i_retx {};
 }
 
 /**
@@ -84,7 +85,11 @@
       boost::multi_index::ordered_unique<
         boost::multi_index::tag<__ccnx_private::i_face>,
         boost::multi_index::member<CcnxPitEntryOutgoingFace, Ptr<CcnxFace>, &CcnxPitEntryOutgoingFace::m_face>
-      >
+      >,
+      boost::multi_index::ordered_non_unique<
+        boost::multi_index::tag<__ccnx_private::i_retx>,
+        boost::multi_index::member<CcnxPitEntryOutgoingFace, uint32_t, &CcnxPitEntryOutgoingFace::m_retxCount>
+      >    
     >
    > type;
 };
@@ -100,138 +105,146 @@
   /**
    * \brief PIT entry constructor
    * \param prefix Prefix of the PIT entry
+   * \param offsetTime Relative time to the current moment, representing PIT entry lifetime
    * \param fibEntry A FIB entry associated with the PIT entry
    */
-  CcnxPitEntry (Ptr<CcnxNameComponents> prefix, const CcnxFibEntry &fibEntry);
-  
-  // // Get number of outgoing interests that we're expecting data from
-  // inline size_t numberOfPromisingInterests( ) const; 
-
-  // /**
-  //  * \brief Unary function to set or update FIB entry with this PIT entry
-  //  * \param fib smart pointer to FIB entry
-  //  */
-  // struct SetFibEntry
-  // {
-  //   SetFibEntry (Ptr<CcnxFibEntry> fib);
-  //   void operator() (CcnxPitEntry &entry);
-  // private:
-  //   Ptr<CcnxFibEntry> m_fib;
-  // };
+  CcnxPitEntry (Ptr<CcnxNameComponents> prefix, const Time &offsetTime, const CcnxFibEntry &fibEntry);
   
   /**
-   * \brief Unary Function to add incoming interest to the PIT entry
+   * @brief Update lifetime of PIT entry
    *
-   * \param incomingFace smart pointer to the face of the incoming interest
-   * \returns const iterator to a newly added or updated
-   * CcnxPitIncomingInterest entry
-   */
-  struct AddIncoming
-  {
-    AddIncoming (Ptr<CcnxFace> incomingFace) : m_face (incomingFace) {}
-    void operator() (CcnxPitEntry &entry);
-    
-  private:
-    Ptr<CcnxFace> m_face;
-    Time m_lifeTime;
-  };
-
-  /**
-   * \brief Unary function to delete incoming interest for the interface
-   * \param face face that should be removed from the list of incoming interests
-   */
-  struct DeleteIncoming
-  {
-    DeleteIncoming (Ptr<CcnxFace> face) : m_face (face) {}
-    void operator() (CcnxPitEntry &entry);
-  private:
-    Ptr<CcnxFace> m_face;
-  };
-
-  /**
-   * \brief Unary function to add outgoing interest to PIT entry
+   * This function will update PIT entry lifetime to the maximum of the current lifetime and
+   * the lifetime Simulator::Now () + offsetTime
    *
-   * \param outgoingFace smart pointer to the face of the outgoing interest
-   * \returns const iterator to a newly added or updated
-   * CcnxPitOutgoingInterest entry
+   * @param offsetTime Relative time to the current moment, representing PIT entry lifetime
    */
-  struct AddOutgoing
-  {
-    AddOutgoing (Ptr<CcnxFace> outgoingFace) : m_face (outgoingFace) {}
-    void operator() (CcnxPitEntry &entry);
-  private:
-    Ptr<CcnxFace> m_face;
-  };
-
-  /**
-   * \brief Unary function to delete incoming interest for the interface
-   * \param face face that should be removed from the list of incoming interests
-   */
-  struct DeleteOutgoing
-  {
-    DeleteOutgoing (Ptr<CcnxFace> face) : m_face (face) {}
-    void operator() (CcnxPitEntry &entry);
-  private:
-    Ptr<CcnxFace> m_face;
-  };
-
-  /**
-   * \brief Unary function to remove all incoming interests
-   */
-  struct ClearIncoming
-  {
-    ClearIncoming () {};
-    void operator() (CcnxPitEntry &entry);
-  };
-
-  /**
-   * \brief Unary function to update FIB status
-   */
-  struct UpdateFibStatus
-  {
-    UpdateFibStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status, Ptr<CcnxFib> fib);
-    void operator() (CcnxPitEntry &entry);
-  private:
-    Ptr<CcnxFace> m_face;
-    CcnxFibFaceMetric::Status m_status;
-    Ptr<CcnxFib> m_fib;
-  };
-
-  /**
-   * \brief Unary function to estimate RTT and update smoothed RTT value in FIB
-   * \param outFace iterator of the outgoing face entry
-   */
-  struct EstimateRttAndRemoveFace
-  {
-    EstimateRttAndRemoveFace (CcnxPitEntryOutgoingFaceContainer::type::iterator outFace, Ptr<CcnxFib> fib)
-      : m_outFace (outFace), m_fib (fib) { };
-    void operator() (CcnxPitEntry &entry);
-  private:
-    CcnxPitEntryOutgoingFaceContainer::type::iterator m_outFace;
-    Ptr<CcnxFib> m_fib;
-  };
-
+  void
+  UpdateLifetime (const Time &offsetTime);
+  
   const CcnxNameComponents &
-  GetPrefix () const;
+  GetPrefix () const
+  { return *m_prefix; }
 
+  /**
+   * @brief Get current expiration time of the record
+   *
+   * @returns current expiration time of the record
+   */
   const Time &
-  GetExpireTime () const { return m_expireTime; }
+  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 Remove incoming entry for face `face`
+   */
+  void
+  RemoveIncoming (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);
+
+  /**
+   * @brief Flag outgoing face as hopeless
+   */
+  void
+  SetWaitingInVain (CcnxPitEntryOutgoingFaceContainer::type::iterator face);
+  
+  /**
+   * @brief Check if all outgoing faces are NACKed
+   */
+  bool
+  AreAllOutgoingInVain () const;
+
+  /*
+   * @brief Similar to AreAllOutgoingInVain, but ignores `face`
+   * \see AreAllOutgoingInVain
+   **/
+  bool
+  AreTherePromisingOutgoingFacesExcept (Ptr<CcnxFace> face) const;
+
+  /**
+   * @brief Increase maximum limit of allowed retransmission per outgoing face
+   */
+  void
+  IncreaseAllowedRetxCount ();
+  
+protected:
+  
 private:
   friend std::ostream& operator<< (std::ostream& os, const CcnxPitEntry &entry);
   
 public:
   Ptr<CcnxNameComponents> m_prefix; ///< \brief Prefix of the PIT entry
   const CcnxFibEntry &m_fibEntry; ///< \brief FIB entry related to this prefix
+  std::set<uint32_t> m_seenNonces; ///< \brief map of nonces that were seen for this prefix
   
   CcnxPitEntryIncomingFaceContainer::type m_incoming; ///< \brief container for incoming interests
   CcnxPitEntryOutgoingFaceContainer::type m_outgoing; ///< \brief container for outgoing interests
 
   Time m_expireTime;         ///< \brief Time when PIT entry will be removed
-  bool m_timerExpired;       ///< \brief flag indicating that PIT timer has expired
-  int  m_counterExpirations; ///< \brief whether timer is expired (+ number of times timer expired)
-};
 
+  uint32_t m_maxRetxCount;   ///< @brief Maximum allowed number of retransmissions via outgoing faces
+};
 
 } // namespace ns3
 
diff --git a/model/ccnx-pit.cc b/model/ccnx-pit.cc
index 7e57b19..1cfa3f9 100644
--- a/model/ccnx-pit.cc
+++ b/model/ccnx-pit.cc
@@ -20,37 +20,26 @@
 
 #include "ccnx-pit.h"
 #include "ns3/log.h"
+#include "ns3/string.h"
 #include "ns3/simulator.h"
 #include "ccnx-interest-header.h"
 #include "ccnx-content-object-header.h"
 
+#include <boost/bind.hpp>
+#include <boost/lambda/lambda.hpp>
+
 NS_LOG_COMPONENT_DEFINE ("CcnxPit");
 
+using namespace boost::tuples;
+using namespace boost;
+
 namespace ns3 {
 
-// NS_OBJECT_ENSURE_REGISTERED (CcnxPit);
+NS_OBJECT_ENSURE_REGISTERED (CcnxPit);
 
 using namespace __ccnx_private;
 
-// size_t
-// PitEntry::numberOfPromisingInterests(e_pi ) const
-// {
-//   size_t count = 0;
-
-//   BOOST_FOREACH (const CcnxPitOutgoingInterest &interest, m_outgoingInterests)
-//     {
-//     }
-//   for( PitOutgoingConstIterator i = outgoingInterests.begin();
-// 	   i!=outgoingInterests.end();
-// 	   i++ )
-// 	{
-// 	  if( !i->waitingInVain ) count++;
-// 	}
-
-//   return count;
-// }
-
-TypeId 
+TypeId
 CcnxPit::GetTypeId ()
 {
   static TypeId tid = TypeId ("ns3::CcnxPit")
@@ -59,9 +48,19 @@
     .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",
+                   "Timeout for PIT entry to live after being satisfied. To make sure recently satisfied interest will not be satisfied again",
+                   StringValue ("100ms"),
+                   MakeTimeAccessor (&CcnxPit::m_PitEntryPruningTimout),
+                   MakeTimeChecker ())
+    .AddAttribute ("PitEntryDefaultLifetime",
+                   "Default lifetime of PIT entry (aka default Interest lifetime)",
+                   StringValue("4s"),
+                   MakeTimeAccessor (&CcnxPit::m_PitEntryDefaultLifetime),
+                   MakeTimeChecker ())
     ;
 
   return tid;
@@ -71,6 +70,25 @@
 {
 }
 
+CcnxPit::~CcnxPit ()
+{
+  DoDispose ();
+}
+
+void 
+CcnxPit::NotifyNewAggregate ()
+{
+}
+
+void 
+CcnxPit::DoDispose ()
+{
+  if (m_cleanupEvent.IsRunning ())
+    m_cleanupEvent.Cancel ();
+
+  clear ();
+}
+
 void
 CcnxPit::SetCleanupTimeout (const Time &timeout)
 {
@@ -79,7 +97,7 @@
     m_cleanupEvent.Cancel (); // cancel any scheduled cleanup events
 
   // schedule even with new timeout
-  m_cleanupEvent = Simulator::Schedule (Simulator::Now () + m_cleanupTimeout,
+  m_cleanupEvent = Simulator::Schedule (m_cleanupTimeout,
                                         &CcnxPit::CleanExpired, this); 
 }
 
@@ -91,21 +109,25 @@
 
 void CcnxPit::CleanExpired ()
 {
-  NS_LOG_LOGIC ("Cleaning PIT");
+  NS_LOG_LOGIC ("Cleaning PIT. Total: " << size ());
   Time now = Simulator::Now ();
-  
-  while( !empty() )
+
+  uint32_t count = 0;
+  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
         break; // nothing else to do. All later records will not be stale
     }
-  
+
+  // NS_LOG_LOGIC ("Cleaned " << count << " records. Total: " << size ());
   // schedule next even
-  m_cleanupEvent = Simulator::Schedule (Simulator::Now () + m_cleanupTimeout,
+  
+  m_cleanupEvent = Simulator::Schedule (m_cleanupTimeout,
                                         &CcnxPit::CleanExpired, this); 
 }
 
@@ -115,49 +137,10 @@
   m_fib = fib;
 }
 
-/*CcnxPitEntryContainer::type::iterator
-CcnxPit::Add (const CcnxInterestHeader &header, CcnxFibEntryContainer::type::iterator fibEntry, Ptr<CcnxFace> face)
-{
-    if( m_bucketsPerFace[face->GetId()]+1.0 >= maxBucketsPerFace[face->GetId()] )
-	{
-        //		printf( "DEBUG: bucket overflow. Should not forward anything to interface %d\n", interest.interfaceIndex );
-		return end();
-	}
-    
-    CcnxPitEntryContainer::type::iterator entry = insert (end (),
-                    CcnxPitEntry (Create<CcnxNameComponents> (header.GetName ()),
-                                *fibEntry));
-    return entry;
-}*/
-
-    
-    
-bool
-CcnxPit::TryAddOutgoing(CcnxPitEntryContainer::type::iterator pitEntry, Ptr<CcnxFace> face)
-{
-    NS_LOG_INFO ("Face has " << m_bucketsPerFace[face->GetId()] << " packets with max allowance " << maxBucketsPerFace[face->GetId()]); 
-    
-    if((face->IsLocal() == false) 
-       && (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;
-	
-    NS_LOG_INFO(this->size());
-    NS_LOG_INFO("before modify");
-    NS_LOG_INFO(pitEntry->GetPrefix());
-    modify (pitEntry, CcnxPitEntry::AddOutgoing(face));
-    NS_LOG_INFO("after modify");
-    return true;
-}
-
 const CcnxPitEntry&
 CcnxPit::Lookup (const CcnxContentObjectHeader &header) const
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  // NS_LOG_FUNCTION_NOARGS ();
 
   CcnxPitEntryContainer::type::iterator entry =
     get<i_prefix> ().find (header.GetName ());
@@ -168,51 +151,46 @@
   return *entry;
 }
 
-CcnxPitEntryContainer::type::iterator
-CcnxPit::Lookup (const CcnxInterestHeader &header, CcnxFibEntryContainer::type::iterator &outFibEntry)
+boost::tuple<const CcnxPitEntry&, bool, bool>
+CcnxPit::Lookup (const CcnxInterestHeader &header)
 {
   NS_LOG_FUNCTION_NOARGS ();
   NS_ASSERT_MSG (m_fib != 0, "FIB should be set");
 
+  bool isDuplicate = false;
+  bool isNew = true;
+
   CcnxPitEntryContainer::type::iterator entry =
     get<i_prefix> ().find (header.GetName ());
 
-  CcnxFibEntryContainer::type::iterator fibEntry = m_fib->LongestPrefixMatch (header);
-  if (fibEntry == m_fib->end ())
-    {
-      NS_LOG_WARN ("FIB entry wasn't found. Creating an empty record");
-      fibEntry = m_fib->insert (m_fib->end (), CcnxFibEntry (header.GetName ()));
-    }
-  
   if (entry == end ())
-  {
-      NS_LOG_INFO("entry == end");
-      NS_LOG_INFO(this->size());
-        entry = insert (end (),
-                    CcnxPitEntry (Create<CcnxNameComponents> (header.GetName ()),
-                                  *fibEntry));
-      NS_LOG_INFO(this->size());
-  }
-  outFibEntry = fibEntry;
-  return entry;
-}
-
-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 );
-}
+      CcnxFibEntryContainer::type::iterator fibEntry = m_fib->LongestPrefixMatch (header);
+      NS_ASSERT_MSG (fibEntry != m_fib->end (),
+                     "There should be at least default route set");
 
+      entry = insert (end (),
+                      CcnxPitEntry (Create<CcnxNameComponents> (header.GetName ()),
+                                    header.GetInterestLifetime ().IsZero ()?m_PitEntryDefaultLifetime
+                                    :                                       header.GetInterestLifetime (),
+                                    *fibEntry));
+
+      // isDuplicate = false; // redundant
+      // isNew = true; // also redundant
+    }
+  else
+    {
+      isNew = false;
+      isDuplicate = entry->IsNonceSeen (header.GetNonce ());
+    }
+
+  if (!isDuplicate)
+    {
+      modify (entry,
+              boost::bind(&CcnxPitEntry::AddSeenNonce, boost::lambda::_1, header.GetNonce ()));
+    }
+
+  return make_tuple (cref(*entry), isNew, isDuplicate);
+}
 
 } // namespace ns3
diff --git a/model/ccnx-pit.h b/model/ccnx-pit.h
index ed724fe..0d1132e 100644
--- a/model/ccnx-pit.h
+++ b/model/ccnx-pit.h
@@ -39,6 +39,7 @@
 #include <map>
 #include <iostream>
 #include <algorithm>
+#include <boost/tuple/tuple.hpp>
 
 namespace ns3 {
 
@@ -91,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;
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
@@ -117,11 +117,11 @@
    */
   CcnxPit ();
 
-  /*CcnxPitEntryContainer::type::iterator
-  Add (const CcnxInterestHeader &header, CcnxFibEntryContainer::type::iterator fibEntry, Ptr<CcnxFace> face);*/
+  /**
+   * \brief Destructor
+   */
+  virtual ~CcnxPit ();
   
-  bool
-    TryAddOutgoing(CcnxPitEntryContainer::type::iterator pitEntry, Ptr<CcnxFace> face);
   /**
    * \brief Find corresponding PIT entry for the given content name
    * \param prefix Prefix for which to lookup the entry
@@ -134,26 +134,34 @@
   /**
    * \brief Find corresponding PIT entry for the given content name
    * \param prefix Prefix for which to lookup the entry
-   * \returns const reference to Pit entry. If record does not exist, it will be created
+   * \returns a tuple:
+   * get<0>: `const CcnxPitEntry&`: a valid PIT entry (if record does not exist, it will be created)
+   * get<1>: `bool`: true if a new entry was created
+   * get<2>: `bool`: true if a PIT entry exists and Nonce that present in header has been already seen
+   * 
    */
-  CcnxPitEntryContainer::type::iterator
-  Lookup (const CcnxInterestHeader &header,CcnxFibEntryContainer::type::iterator &outFibEntry);
+  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
    *
@@ -170,28 +178,26 @@
    */
   Time GetCleanupTimeout () const;
 
-  /**
-   * \brief Set FIB table
-   */
-  void SetFib (Ptr<CcnxFib> fib);
-
-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;
+
   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-rit.cc b/model/ccnx-rit.cc
index 6a7e556..2a1b7f0 100644
--- a/model/ccnx-rit.cc
+++ b/model/ccnx-rit.cc
@@ -75,7 +75,29 @@
 {
 }
 
-CcnxRit::~CcnxRit( ) { }
+CcnxRit::~CcnxRit( )
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  
+  if (m_cleanupEvent.IsRunning ())
+    m_cleanupEvent.Cancel (); // cancel any scheduled cleanup events
+
+  clear ();
+}
+
+void
+CcnxRit::NotifyNewAggregate ()
+{
+}
+
+void
+CcnxRit::DoDispose ()
+{
+  if (m_cleanupEvent.IsRunning ())
+    m_cleanupEvent.Cancel (); // cancel any scheduled cleanup events                                                                                                                     
+
+  clear ();
+}
 
 void
 CcnxRit::SetRitTimeout (const Time &timeout)
@@ -97,7 +119,7 @@
     m_cleanupEvent.Cancel (); // cancel any scheduled cleanup events
 
   // schedule even with new timeout
-  m_cleanupEvent = Simulator::Schedule (Simulator::Now () + m_cleanupTimeout,
+  m_cleanupEvent = Simulator::Schedule (m_cleanupTimeout,
                                         &CcnxRit::CleanExpired, this); 
 }
 
@@ -110,8 +132,8 @@
 bool
 CcnxRit::WasRecentlySatisfied (const CcnxInterestHeader &header)
 {
-  NS_LOG_FUNCTION_NOARGS ();
-    std::pair<CcnxRitByNonce::type::iterator,CcnxRitByNonce::type::iterator>
+  // NS_LOG_FUNCTION_NOARGS ();
+  std::pair<CcnxRitByNonce::type::iterator,CcnxRitByNonce::type::iterator>
     entries = get<nonce> ().equal_range (header.GetNonce ());
   
   if (entries.first == end ())
@@ -131,7 +153,7 @@
 void
 CcnxRit::SetRecentlySatisfied (const CcnxInterestHeader &header)
 {
-  NS_LOG_FUNCTION_NOARGS ();
+  // NS_LOG_FUNCTION_NOARGS ();
   NS_ASSERT_MSG (!WasRecentlySatisfied (header), "Duplicate recent interest should not be added to RIT");
   
   get<timestamp> ().push_back (
@@ -144,30 +166,21 @@
 
 void CcnxRit::CleanExpired ()
 {
-  // NS_LOG_LOGIC ("Cleaning RIT");
+  NS_LOG_LOGIC ("Cleaning RIT, total: " << size ());
   Time now = Simulator::Now ();
-// #ifdef _DEBUG
-//   uint32_t count = 0;
-// #endif
   
   while( !empty() )
     {
       if( get<timestamp> ().front ().m_expireTime <= now ) // is the record stale?
         {
          get<timestamp> ().pop_front( );
-// #ifdef _DEBUG
-//          count++;
-// #endif
         }
       else
         break; // nothing else to do. All later records will not be stale
     }
-// #ifdef _DEBUG
-//   NS_LOG_DEBUG (count << " records cleaned");
-// #endif
   
   // schedule next even
-  m_cleanupEvent = Simulator::Schedule (Simulator::Now () + m_cleanupTimeout,
+  m_cleanupEvent = Simulator::Schedule (m_cleanupTimeout,
                                         &CcnxRit::CleanExpired, this); 
 }
 
diff --git a/model/ccnx-rit.h b/model/ccnx-rit.h
index ba5a133..501f409 100644
--- a/model/ccnx-rit.h
+++ b/model/ccnx-rit.h
@@ -188,6 +188,11 @@
    */
   Time GetCleanupTimeout () const;
 
+protected:
+  // inherited from Object class                                                                                                                                                        
+  virtual void NotifyNewAggregate ();
+  virtual void DoDispose ();
+
 private:
   /**
    * \brief Periodic even to clean up stalled entries
diff --git a/model/ccnx.cc b/model/ccnx.cc
index 0fe4b31..af551a6 100644
--- a/model/ccnx.cc
+++ b/model/ccnx.cc
@@ -38,4 +38,8 @@
   return tid;
 }
 
+Ccnx::~Ccnx ()
+{
+}
+
 } // namespace ns3
diff --git a/model/ccnx.h b/model/ccnx.h
index cafa354..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 {
@@ -49,11 +48,10 @@
 class i_mru {};
 }
 
-#define MILLI_SECOND 1
-#define SECOND 1000
 // default data size
-#define NDN_DEFAULT_DATA_SIZE   1024
-#define NDN_INTEREST_RESET_PERIOD	(10*MILLI_SECOND)
+// #define NDN_DEFAULT_DATA_SIZE   1024
+// #define NDN_INTEREST_RESET_PERIOD	(10*MILLI_SECOND)
+
 /**
  * \defgroup ccnx NDN abstraction
  *
@@ -81,61 +79,62 @@
 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
    *
    * \return interface ID
    */
   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<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<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
diff --git a/wscript b/wscript
index f256b39..7da13ff 100644
--- a/wscript
+++ b/wscript
@@ -30,7 +30,7 @@
 def build(bld):
     deps = ['core', 'network', 'point-to-point',
             'topology-read','internet','applications',
-            'point-to-point-layout']
+            'point-to-point-layout', 'netanim']
     if bld.env['ENABLE_PYTHON_BINDINGS']:
         deps.append ('visualizer')
 
@@ -77,13 +77,16 @@
         obj = bld.create_ns3_program('annotated-topology', ['NDNabstraction', 'point-to-point-layout'])
         obj.source = 'examples/annotated-topology-read-example.cc'
 
-        obj = bld.create_ns3_program('interest-header', ['NDNabstraction'])
+        obj = bld.create_ns3_program('interest-header-example', ['NDNabstraction'])
         obj.source = 'examples/interest-header-example.cc'
 
-        obj = bld.create_ns3_program('ccnx-sprint-topology', ['NDNabstraction', 'point-to-point-layout'])
+        obj = bld.create_ns3_program('packet-sizes', ['NDNabstraction'])
+        obj.source = 'examples/packet-sizes.cc'
+
+        obj = bld.create_ns3_program('ccnx-sprint-topology', ['NDNabstraction'])
         obj.source = 'examples/sprint-topology.cc'
 
-        obj = bld.create_ns3_program('ccnx-abilene-topology', ['NDNabstraction', 'point-to-point-layout'])
+        obj = bld.create_ns3_program('ccnx-abilene-topology', ['NDNabstraction'])
         obj.source = 'examples/abilene-topology.cc'
 
     #     for path in ["examples"]: