Merge feature branch 'feature-l2-tracer'
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..4d180c0
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,6 @@
+Alex Afanasyev <alexander.afanasyev@ucla.edu>
+Ilya Moiseenko <iliamo@ucla.edu>
+Lucas <lucas@cs.ucla.edu>
+Cheng Yi <yic@email.arizona.edu>
+Xiaoke Jiang <shock.jiang@gmail.com>
+Saran Tarnoi <sarantarnoi@gmail.com>
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..854f6d0
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+ndnSIM version 0.2.8
diff --git a/apps/ndn-consumer.cc b/apps/ndn-consumer.cc
index 3a14e48..1b85cfb 100644
--- a/apps/ndn-consumer.cc
+++ b/apps/ndn-consumer.cc
@@ -33,6 +33,7 @@
 #include "ns3/ndn-interest.h"
 #include "ns3/ndn-content-object.h"
 #include "ns3/ndnSIM/utils/ndn-fw-hop-count-tag.h"
+#include "ns3/ndnSIM/utils/ndn-rtt-mean-deviation.h"
 
 #include <boost/ref.hpp>
 #include <boost/lexical_cast.hpp>
diff --git a/apps/ndn-consumer.h b/apps/ndn-consumer.h
index 970da4c..75705cd 100644
--- a/apps/ndn-consumer.h
+++ b/apps/ndn-consumer.h
@@ -27,8 +27,7 @@
 #include "ns3/ndn-name-components.h"
 #include "ns3/nstime.h"
 #include "ns3/data-rate.h"
-//#include "ns3/internet-module.h"
-#include "ns3/rtt-estimator.h"
+#include "ns3/ndn-rtt-estimator.h"
 
 #include <set>
 #include <map>
diff --git a/bindings/modulegen__gcc_ILP32.py b/bindings/modulegen__gcc_ILP32.py
index 9ca7dea..bf1a2af 100644
--- a/bindings/modulegen__gcc_ILP32.py
+++ b/bindings/modulegen__gcc_ILP32.py
@@ -5946,7 +5946,7 @@
                    'void', 
                    [param('ns3::Ptr< ns3::ndn::Face >', 'face'), param('ns3::ndn::fib::FaceMetric::Status', 'status')])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_faces [variable]
-    cls.add_instance_attribute('m_faces', 'boost::multi_index::multi_index_container< ns3::ndn::fib::FaceMetric, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< ns3::ndn::fib::i_face, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::member< ns3::ndn::fib::FaceMetric, ns3::Ptr< ns3::ndn::Face >, & ( ns3::ndn::fib::FaceMetric::m_face ) >, mpl_::na >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ns3::ndn::fib::i_metric, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::composite_key< ns3::ndn::fib::FaceMetric, boost::multi_index::member< ns3::ndn::fib::FaceMetric, ns3::ndn::fib::FaceMetric::Status, & ( ns3::ndn::fib::FaceMetric::m_status ) >, boost::multi_index::member< ns3::ndn::fib::FaceMetric, int, & ( ns3::ndn::fib::FaceMetric::m_routingCost ) >, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type >, mpl_::na >, boost::multi_index::random_access< boost::multi_index::tag< ns3::ndn::fib::i_nth, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na > >, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, std::allocator< ns3::ndn::fib::FaceMetric > >', is_const=False)
+    cls.add_instance_attribute('m_faces', 'boost::multi_index::multi_index_container< ns3::ndn::fib::FaceMetric, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< ns3::ndn::fib::i_face, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::const_mem_fun< ns3::ndn::fib::FaceMetric, ns3::Ptr< ns3::ndn::Face >, & ( ns3::ndn::fib::FaceMetric::GetFace (  ) const ) >, mpl_::na >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ns3::ndn::fib::i_metric, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::composite_key< ns3::ndn::fib::FaceMetric, boost::multi_index::const_mem_fun< ns3::ndn::fib::FaceMetric, ns3::ndn::fib::FaceMetric::Status, & ( ns3::ndn::fib::FaceMetric::GetStatus (  ) const ) >, boost::multi_index::const_mem_fun< ns3::ndn::fib::FaceMetric, int, & ( ns3::ndn::fib::FaceMetric::GetRoutingCost (  ) const ) >, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type >, mpl_::na >, boost::multi_index::random_access< boost::multi_index::tag< ns3::ndn::fib::i_nth, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na > >, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, std::allocator< ns3::ndn::fib::FaceMetric > >', is_const=False)
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_needsProbing [variable]
     cls.add_instance_attribute('m_needsProbing', 'bool', is_const=False)
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_prefix [variable]
@@ -5972,22 +5972,37 @@
                    'ns3::Ptr< ns3::ndn::Face >', 
                    [], 
                    is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::Time ns3::ndn::fib::FaceMetric::GetRealDelay() const [member function]
+    cls.add_method('GetRealDelay', 
+                   'ns3::Time', 
+                   [], 
+                   is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): int32_t ns3::ndn::fib::FaceMetric::GetRoutingCost() const [member function]
+    cls.add_method('GetRoutingCost', 
+                   'int32_t', 
+                   [], 
+                   is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::Status ns3::ndn::fib::FaceMetric::GetStatus() const [member function]
+    cls.add_method('GetStatus', 
+                   'ns3::ndn::fib::FaceMetric::Status', 
+                   [], 
+                   is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::SetRealDelay(ns3::Time realDelay) [member function]
+    cls.add_method('SetRealDelay', 
+                   'void', 
+                   [param('ns3::Time', 'realDelay')])
+    ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::SetRoutingCost(int32_t routingCost) [member function]
+    cls.add_method('SetRoutingCost', 
+                   'void', 
+                   [param('int32_t', 'routingCost')])
+    ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::SetStatus(ns3::ndn::fib::FaceMetric::Status status) [member function]
+    cls.add_method('SetStatus', 
+                   'void', 
+                   [param('ns3::ndn::fib::FaceMetric::Status', 'status')])
     ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::UpdateRtt(ns3::Time const & rttSample) [member function]
     cls.add_method('UpdateRtt', 
                    'void', 
                    [param('ns3::Time const &', 'rttSample')])
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_face [variable]
-    cls.add_instance_attribute('m_face', 'ns3::Ptr< ns3::ndn::Face >', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_realDelay [variable]
-    cls.add_instance_attribute('m_realDelay', 'ns3::Time', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_routingCost [variable]
-    cls.add_instance_attribute('m_routingCost', 'int32_t', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_rttVar [variable]
-    cls.add_instance_attribute('m_rttVar', 'ns3::Time', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_sRtt [variable]
-    cls.add_instance_attribute('m_sRtt', 'ns3::Time', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_status [variable]
-    cls.add_instance_attribute('m_status', 'ns3::ndn::fib::FaceMetric::Status', is_const=False)
     return
 
 def register_Ns3NdnFibFaceMetricContainer_methods(root_module, cls):
diff --git a/bindings/modulegen__gcc_LP64.py b/bindings/modulegen__gcc_LP64.py
index 9ca7dea..bf1a2af 100644
--- a/bindings/modulegen__gcc_LP64.py
+++ b/bindings/modulegen__gcc_LP64.py
@@ -5946,7 +5946,7 @@
                    'void', 
                    [param('ns3::Ptr< ns3::ndn::Face >', 'face'), param('ns3::ndn::fib::FaceMetric::Status', 'status')])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_faces [variable]
-    cls.add_instance_attribute('m_faces', 'boost::multi_index::multi_index_container< ns3::ndn::fib::FaceMetric, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< ns3::ndn::fib::i_face, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::member< ns3::ndn::fib::FaceMetric, ns3::Ptr< ns3::ndn::Face >, & ( ns3::ndn::fib::FaceMetric::m_face ) >, mpl_::na >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ns3::ndn::fib::i_metric, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::composite_key< ns3::ndn::fib::FaceMetric, boost::multi_index::member< ns3::ndn::fib::FaceMetric, ns3::ndn::fib::FaceMetric::Status, & ( ns3::ndn::fib::FaceMetric::m_status ) >, boost::multi_index::member< ns3::ndn::fib::FaceMetric, int, & ( ns3::ndn::fib::FaceMetric::m_routingCost ) >, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type >, mpl_::na >, boost::multi_index::random_access< boost::multi_index::tag< ns3::ndn::fib::i_nth, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na > >, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, std::allocator< ns3::ndn::fib::FaceMetric > >', is_const=False)
+    cls.add_instance_attribute('m_faces', 'boost::multi_index::multi_index_container< ns3::ndn::fib::FaceMetric, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< ns3::ndn::fib::i_face, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::const_mem_fun< ns3::ndn::fib::FaceMetric, ns3::Ptr< ns3::ndn::Face >, & ( ns3::ndn::fib::FaceMetric::GetFace (  ) const ) >, mpl_::na >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ns3::ndn::fib::i_metric, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, boost::multi_index::composite_key< ns3::ndn::fib::FaceMetric, boost::multi_index::const_mem_fun< ns3::ndn::fib::FaceMetric, ns3::ndn::fib::FaceMetric::Status, & ( ns3::ndn::fib::FaceMetric::GetStatus (  ) const ) >, boost::multi_index::const_mem_fun< ns3::ndn::fib::FaceMetric, int, & ( ns3::ndn::fib::FaceMetric::GetRoutingCost (  ) const ) >, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type >, mpl_::na >, boost::multi_index::random_access< boost::multi_index::tag< ns3::ndn::fib::i_nth, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na > >, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na >, std::allocator< ns3::ndn::fib::FaceMetric > >', is_const=False)
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_needsProbing [variable]
     cls.add_instance_attribute('m_needsProbing', 'bool', is_const=False)
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_prefix [variable]
@@ -5972,22 +5972,37 @@
                    'ns3::Ptr< ns3::ndn::Face >', 
                    [], 
                    is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::Time ns3::ndn::fib::FaceMetric::GetRealDelay() const [member function]
+    cls.add_method('GetRealDelay', 
+                   'ns3::Time', 
+                   [], 
+                   is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): int32_t ns3::ndn::fib::FaceMetric::GetRoutingCost() const [member function]
+    cls.add_method('GetRoutingCost', 
+                   'int32_t', 
+                   [], 
+                   is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::Status ns3::ndn::fib::FaceMetric::GetStatus() const [member function]
+    cls.add_method('GetStatus', 
+                   'ns3::ndn::fib::FaceMetric::Status', 
+                   [], 
+                   is_const=True)
+    ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::SetRealDelay(ns3::Time realDelay) [member function]
+    cls.add_method('SetRealDelay', 
+                   'void', 
+                   [param('ns3::Time', 'realDelay')])
+    ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::SetRoutingCost(int32_t routingCost) [member function]
+    cls.add_method('SetRoutingCost', 
+                   'void', 
+                   [param('int32_t', 'routingCost')])
+    ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::SetStatus(ns3::ndn::fib::FaceMetric::Status status) [member function]
+    cls.add_method('SetStatus', 
+                   'void', 
+                   [param('ns3::ndn::fib::FaceMetric::Status', 'status')])
     ## ndn-fib-entry.h (module 'ndnSIM'): void ns3::ndn::fib::FaceMetric::UpdateRtt(ns3::Time const & rttSample) [member function]
     cls.add_method('UpdateRtt', 
                    'void', 
                    [param('ns3::Time const &', 'rttSample')])
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_face [variable]
-    cls.add_instance_attribute('m_face', 'ns3::Ptr< ns3::ndn::Face >', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_realDelay [variable]
-    cls.add_instance_attribute('m_realDelay', 'ns3::Time', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_routingCost [variable]
-    cls.add_instance_attribute('m_routingCost', 'int32_t', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_rttVar [variable]
-    cls.add_instance_attribute('m_rttVar', 'ns3::Time', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_sRtt [variable]
-    cls.add_instance_attribute('m_sRtt', 'ns3::Time', is_const=False)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric::m_status [variable]
-    cls.add_instance_attribute('m_status', 'ns3::ndn::fib::FaceMetric::Status', is_const=False)
     return
 
 def register_Ns3NdnFibFaceMetricContainer_methods(root_module, cls):
diff --git a/docs/source/examples.rst b/docs/source/examples.rst
index 98c8314..e8bb522 100644
--- a/docs/source/examples.rst
+++ b/docs/source/examples.rst
@@ -288,6 +288,27 @@
 
 :ref:`Custom applications`
 
+Simple scenario with pcap dump
+------------------------------
+
+The following example (``ndn-simple-with-pcap.cc``) demonstrates how to dump all simulated traffic
+in pcap-formatted data, which can be used for later analysis by conventional tools, like tcpdump and wireshark.
+
+.. literalinclude:: ../../examples/ndn-simple-with-pcap.cc
+   :language: c++
+   :linenos:
+   :lines: 20-
+   :emphasize-lines: 7-29,70-72
+
+If this code is placed into ``scratch/ndn-simple-with-pcap.cc`` and NS-3 is compiled in debug mode, you can run and see progress of the
+simulation using the following command (in optimized mode nothing will be printed out)::
+
+     NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-simple-with-pcap
+
+This will generate ``ndn-simple-trace.pcap``, which can be fed to tcpdump::
+
+     tcpdump -r ndn-simple-trace.pcap
+
 25-node tree topology with L2Tracer
 -----------------------------------
 
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
index c03e341..c660492 100644
--- a/docs/source/faq.rst
+++ b/docs/source/faq.rst
@@ -4,7 +4,7 @@
 Boost libraries
 ---------------
 
-.. note:: 
+.. note::
     **My ubuntu/redhat/freebsd have an old version of boost libraries.  How can I get the latest one?**
 
 .. _Installing boost libraries:
@@ -14,10 +14,10 @@
 
 .. role:: red
 
-.. note:: 
+.. note::
     **The following instructions are for those who want to install latest version of boost libraries** :red:`and has root access`.
 
-The following commands would install the latest version of boost libraries (at the time of writing, version 1.52) ot ``/usr/local``, assuming you have a root access to your machine. 
+The following commands would install the latest version of boost libraries (at the time of writing, version 1.53) ot ``/usr/local``, assuming you have a root access to your machine.
 If you don't have root access, please refer to section :ref:`Installing boost libraries to a non-privileged location`.
 
 .. note::
@@ -26,9 +26,9 @@
 .. code-block:: bash
    :linenos:
 
-    wget http://downloads.sourceforge.net/project/boost/boost/1.52.0/boost_1_52_0.tar.bz2
-    tar jxf boost_1_52_0.tar.bz2
-    cd boost_1_52_0
+    wget http://downloads.sourceforge.net/project/boost/boost/1.53.0/boost_1_53_0.tar.bz2
+    tar jxf boost_1_53_0.tar.bz2
+    cd boost_1_53_0
     ./bootstrap.sh
     sudo ./b2 --prefix=/usr/local install
 
@@ -51,18 +51,18 @@
 Installing boost libraries to a non-privileged location
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-.. note:: 
+.. note::
     **Follow these general instructions if you are trying to installboost libraries to a non-privileged location** :red:`(i.e., you do not have root access),` **but something is going wrong.**
 
-Normally, to compile and install boost libraries in non-privileged mode, you would need to issue following commands (e.g., for boost version 1.52.0):
+Normally, to compile and install boost libraries in non-privileged mode, you would need to issue following commands (e.g., for boost version 1.53.0):
 
 .. code-block:: bash
    :linenos:
 
     export BOOSTDIR=/home/non-privileged-user/boost
-    wget http://downloads.sourceforge.net/project/boost/boost/1.52.0/boost_1_52_0.tar.bz2
-    tar jxf boost_1_52_0.tar.bz2
-    cd boost_1_52_0
+    wget http://downloads.sourceforge.net/project/boost/boost/1.53.0/boost_1_53_0.tar.bz2
+    tar jxf boost_1_53_0.tar.bz2
+    cd boost_1_53_0
     ./bootstrap.sh
     ./b2 --prefix=$BOOSTDIR install
 
@@ -119,7 +119,7 @@
         Waf: Entering directory `/ndnSIM/ns-3/build'
         Could not find a task generator for the name 'ns3-visualizer'..
 
-Something is wrong with your python bindings and python bindings dependencies. 
+Something is wrong with your python bindings and python bindings dependencies.
 Please follow the :ref:`requirements` section that lists what should be installed in order to run visualizer.
 
 Code questions
@@ -143,37 +143,37 @@
     {
       Ptr<ndn::L3Protocol> ndn1 = node1->GetObject<ndn::L3Protocol> ();
       Ptr<ndn::L3Protocol> ndn2 = node2->GetObject<ndn::L3Protocol> ();
-    
+
       // iterate over all faces to find the right one
       for (uint32_t faceId = 0; faceId < ndn1->GetNFaces (); faceId++)
         {
           Ptr<ndn::NetDeviceFace> ndFace = ndn1->GetFace (faceId)->GetObject<ndn::NetDeviceFace> ();
           if (ndFace == 0) continue;
-     
+
           Ptr<PointToPointNetDevice> nd1 = ndFace->GetNetDevice ()->GetObject<PointToPointNetDevice> ();
           if (nd1 == 0) continue;
-     
+
           Ptr<Channel> channel = nd1->GetChannel ();
           if (channel == 0) continue;
-     
+
           Ptr<PointToPointChannel> ppChannel = DynamicCast<PointToPointChannel> (channel);
-     
+
           Ptr<NetDevice> nd2 = ppChannel->GetDevice (0);
           if (nd2->GetNode () == node1)
             nd2 = ppChannel->GetDevice (1);
-     
+
           if (nd2->GetNode () == node2)
             {
               Ptr<ndn::Face> face1 = ndn1->GetFaceByNetDevice (nd1);
               Ptr<ndn::Face> face2 = ndn2->GetFaceByNetDevice (nd2);
-     
+
               face1->SetUp (false);
               face2->SetUp (false);
               break;
             }
         }
     }
-     
+
 
 General questions
 -----------------
diff --git a/docs/source/getting-started.rst b/docs/source/getting-started.rst
index 698e6d3..ec76405 100644
--- a/docs/source/getting-started.rst
+++ b/docs/source/getting-started.rst
@@ -15,54 +15,83 @@
 
 2. Boost libraries should be installed on the system:
 
-   * For Ubuntu::
+   * For Ubuntu (for Ubuntu 12.10 and later only):
 
-       sudo aptitude install libboost-all-dev
+       .. code-block:: bash
 
-   * For MacOS (macports)::
+           sudo aptitude install libboost-all-dev
 
-       sudo port instal boost
+   * For Fedora (for Fedora 18 and later only):
+
+       .. code-block:: bash
+
+           sudo yum install boost-devel
+
+   * For MacOS (macports):
+
+       .. code-block:: bash
+
+           sudo port instal boost
 
 .. role:: red
 
 .. note::
-   :red:`!!! ndnSIM requires boost version at least 1.48.`   Many linux distribution (including Ubuntu 12.04.1 at the time of this writing) ship an old version of boost, making it impossible to compile ndnSIM out-of-the-box.  Please install the latest version, following :ref:`these simple instructions <Installing boost libraries>`.
+   :red:`!!! ndnSIM requires boost version at least 1.48.`   Many linux distribution (including Ubuntu 12.04.1 and Fedore 16, 17 at the time of this writing) ship an old version of boost, making it impossible to compile ndnSIM out-of-the-box.  Please install the latest version, following :ref:`these simple instructions <Installing boost libraries>`.
 
 .. note::
-   !!! If you do not have root permissions to install boost, you can install it in your home folder.  However, you need to be make sure that `libboost_iostreams` library is successfully compiled and is installed.  Please refer to :ref:`the following example <Installing boost libraries>` for the hints how to successfully compile and install boost libraries on Ubuntu Linux. 
+   !!! If you do not have root permissions to install boost, you can install it in your home folder.  However, you need to be make sure that `libboost_iostreams` library is successfully compiled and is installed.  Please refer to :ref:`the following example <Installing boost libraries>` for the hints how to successfully compile and install boost libraries on Ubuntu Linux.
 
 
 3. If you are planning to use other modules, like visualizer, a number of additional dependencies should be installed.  For example, in
 order to run `visualizer`_ module, the following should be installed:
 
-   * For Ubuntu::
+   * For Ubuntu (tested on Ubuntu 12.04.1):
 
-       sudo apt-get install python-dev python-pygraphviz python-kiwi
-       sudo apt-get install python-pygoocanvas python-gnome2
-       sudo apt-get install python-gnomedesktop python-rsvg ipython
+       .. code-block:: bash
 
-   * For MacOS (macports)::
+           sudo apt-get install python-dev python-pygraphviz python-kiwi
+           sudo apt-get install python-pygoocanvas python-gnome2
+           sudo apt-get install python-gnomedesktop python-rsvg ipython
 
-       sudo port install  py27-pygraphviz py27-goocanvas
+   * For Fedora (tested on Fedora 16):
 
-.. py27-kiwi 
+       .. code-block:: bash
+
+           sudo yum install pygoocanvas python-kiwi graphviz-python
+
+           # easy_install method, since pygraphviz is not yet packaged into Fedora (https://bugzilla.redhat.com/show_bug.cgi?id=740687)
+           sudo yum install graphviz-devel
+           sudo yum install python-pip
+           sudo easy_install pygraphviz
+
+   * For MacOS (macports):
+
+       .. code-block:: bash
+
+           sudo port install  py27-pygraphviz py27-goocanvas
+
+.. py27-kiwi
 
 .. _visualizer: http://www.nsnam.org/wiki/index.php/PyViz
 
 Downloading ndnSIM source
 -------------------------
 
-Download a custom branch of NS-3 that contains all necessary patches and more::
+Download a custom branch of NS-3 that contains all necessary patches and more:
+
+.. code-block:: bash
 
 	mkdir ndnSIM
 	cd ndnSIM
 	git clone git://github.com/cawka/ns-3-dev-ndnSIM.git ns-3
 	git clone git://github.com/cawka/pybindgen.git pybindgen
 
-The first command is to create a directory, which will contain everything NS-3 related.  The bare minimum is just base NS-3 (the first clone above). The second clone gets a module necessary to build python bindings, which are necessary for the visualizer module.  
+The first command is to create a directory, which will contain everything NS-3 related.  The bare minimum is just base NS-3 (the first clone above). The second clone gets a module necessary to build python bindings, which are necessary for the visualizer module.
 
 Finally, clone actual ndnSIM code and place it in src/ folder::
 
+.. code-block:: bash
+
 	git clone git://github.com/NDN-Routing/ndnSIM.git ns-3/src/ndnSIM
 
 There are quite a few modification to the base NS-3 code that are necessary to run ndnSIM, and the code is periodically synchronized with the official developer branch.  Eventually, all the changes will be merged to the official branch, but for the time being, it is necessary to use the customized branch.
@@ -70,19 +99,25 @@
 Compiling and running ndnSIM
 ----------------------------
 
-ndnSIM uses standard NS-3 compilation procedure.  Normally the following commands should be sufficient to configure and build ndnSIM with python bindings enabled::
+ndnSIM uses standard NS-3 compilation procedure.  Normally the following commands should be sufficient to configure and build ndnSIM with python bindings enabled:
+
+.. code-block:: bash
 
 	cd <ns-3-folder>
 	./waf configure --enable-examples
 	./waf
 
-On MacOS (with macports), you may need to modify the configure command to use macports version of python::
+On MacOS (with macports), you may need to modify the configure command to use macports version of python:
+
+.. code-block:: bash
 
 	cd <ns-3-folder>
 	./waf configure --with-python=/opt/local/bin/python2.7 --enable-examples
 	./waf
 
-Python bindings is an optional and not very stable feature of NS-3 simulator.  It is possible to disable python bindings compilation either to speed up compilation or to avoid certain compilation errors (e.g., "Could not find a task generator for the name 'ns3-visualizer'")::
+Python bindings is an optional and not very stable feature of NS-3 simulator.  It is possible to disable python bindings compilation either to speed up compilation or to avoid certain compilation errors (e.g., "Could not find a task generator for the name 'ns3-visualizer'"):
+
+.. code-block:: bash
 
 	cd <ns-3-folder>
 	./waf configure --disable-python --enable-examples
@@ -90,19 +125,27 @@
 
 For more configuration options, please refer to ``./waf --help``.
 
-To run :doc:`sample ndnSIM simulations <examples>`::
+To run :doc:`sample ndnSIM simulations <examples>`:
+
+.. code-block:: bash
 
 	./waf --run=ndn-simple
 
-or::
+or:
+
+.. code-block:: bash
 
 	./waf --run=ndn-grid
 
-If you have compiled with python bindings, then you can try to run these simulations with visualizer::
+If you have compiled with python bindings, then you can try to run these simulations with visualizer:
+
+.. code-block:: bash
 
 	./waf --run=ndn-simple --vis
 
-or::
+or:
+
+.. code-block:: bash
 
 	./waf --run=ndn-grid --vis
 
diff --git a/examples/custom-strategies/custom-strategy.cc b/examples/custom-strategies/custom-strategy.cc
index be1f25b..5812ca3 100644
--- a/examples/custom-strategies/custom-strategy.cc
+++ b/examples/custom-strategies/custom-strategy.cc
@@ -14,13 +14,13 @@
 NS_OBJECT_ENSURE_REGISTERED(CustomStrategy);
 
 LogComponent CustomStrategy::g_log = LogComponent (CustomStrategy::GetLogName ().c_str ());
-    
+
 std::string
 CustomStrategy::GetLogName ()
 {
   return "ndn.fw.CustomStrategy";
 }
-    
+
 TypeId
 CustomStrategy::GetTypeId (void)
 {
@@ -28,11 +28,11 @@
     .SetGroupName ("Ndn")
     .SetParent <BaseStrategy> ()
     .AddConstructor <CustomStrategy> ()
-        
+
     // .AddAttribute ("Attribute", "Attribute spec",
     //                         StringValue ("DefaultValue"),
     //                         MakeStringAccessor (&BaseStrategy::m_variable),
-    //                         MakeStringChecker ())    
+    //                         MakeStringChecker ())
     ;
   return tid;
 }
@@ -57,7 +57,7 @@
   // forward to best-metric face
   if (faceIterator != faces.end ())
     {
-      if (TrySendOutInterest (inFace, faceIterator->m_face, header, origPacket, pitEntry))
+      if (TrySendOutInterest (inFace, faceIterator->GetFace (), header, origPacket, pitEntry))
         propagatedCount ++;
 
       faceIterator ++;
@@ -66,7 +66,7 @@
   // forward to second-best-metric face
   if (faceIterator != faces.end ())
     {
-      if (TrySendOutInterest (inFace, faceIterator->m_face, header, origPacket, pitEntry))
+      if (TrySendOutInterest (inFace, faceIterator->GetFace (), header, origPacket, pitEntry))
         propagatedCount ++;
 
       faceIterator ++;
@@ -92,11 +92,11 @@
     {
       m_counter --;
     }
-        
+
   BaseStrategy::WillEraseTimedOutPendingInterest (pitEntry);
 }
-        
-        
+
+
 void
 CustomStrategy::WillSatisfyPendingInterest (Ptr<Face> inFace,
                                             Ptr<pit::Entry> pitEntry)
@@ -107,11 +107,11 @@
     {
       m_counter --;
     }
-          
+
   BaseStrategy::WillSatisfyPendingInterest (inFace, pitEntry);
 }
 
-        
+
 } // namespace fw
 } // namespace ndn
 } // namespace ns3
diff --git a/examples/ndn-simple-with-pcap.cc b/examples/ndn-simple-with-pcap.cc
index ea2f318..03f3ef4 100644
--- a/examples/ndn-simple-with-pcap.cc
+++ b/examples/ndn-simple-with-pcap.cc
@@ -1,4 +1,23 @@
-
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+// ndn-simple-with-pcap.cc
 #include "ns3/core-module.h"
 #include "ns3/network-module.h"
 #include "ns3/point-to-point-module.h"
@@ -14,13 +33,13 @@
     PcapHelper helper;
     m_pcap = helper.CreateFile (file, std::ios::out, PcapHelper::DLT_PPP);
   }
-  
+
   void
   TracePacket (Ptr<const Packet> packet)
   {
     static PppHeader pppHeader;
     pppHeader.SetProtocol (0x0077);
-    
+
     m_pcap->Write (Simulator::Now (), pppHeader, packet);
   }
 
@@ -37,8 +56,6 @@
   Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("10ms"));
   Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("20"));
 
-  Config::SetDefault ("ns3::ndn::Producer::SignatureBits", StringValue ("1"));
-  
   // Creating nodes
   NodeContainer nodes;
   nodes.Create (3);
@@ -72,7 +89,7 @@
   PcapWriter trace ("ndn-simple-trace.pcap");
   Config::ConnectWithoutContext ("/NodeList/*/$ns3::ndn::L3Protocol/FaceList/*/NdnTx",
 				 MakeCallback (&PcapWriter::TracePacket, &trace));
-  
+
   Simulator::Stop (Seconds (20.0));
 
   Simulator::Run ();
diff --git a/examples/wscript b/examples/wscript
index af34ee6..965eb25 100644
--- a/examples/wscript
+++ b/examples/wscript
@@ -53,3 +53,6 @@
 
     obj = bld.create_ns3_program('ndn-simple-with-cs-lfu', ['ndnSIM'])
     obj.source = 'ndn-simple-with-cs-lfu.cc'
+
+    obj = bld.create_ns3_program('ndn-simple-with-pcap', ['ndnSIM'])
+    obj.source = 'ndn-simple-with-pcap.cc'
diff --git a/helper/ndn-global-routing-helper.cc b/helper/ndn-global-routing-helper.cc
index 135cd4c..122bffb 100644
--- a/helper/ndn-global-routing-helper.cc
+++ b/helper/ndn-global-routing-helper.cc
@@ -317,6 +317,132 @@
     }
 }
 
+void
+GlobalRoutingHelper::CalculateAllPossibleRoutes ()
+{
+  /**
+   * Implementation of route calculation is heavily based on Boost Graph Library
+   * See http://www.boost.org/doc/libs/1_49_0/libs/graph/doc/table_of_contents.html for more details
+   */
+
+  BOOST_CONCEPT_ASSERT(( VertexListGraphConcept< NdnGlobalRouterGraph > ));
+  BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept< NdnGlobalRouterGraph > ));
+
+  NdnGlobalRouterGraph graph;
+  typedef graph_traits < NdnGlobalRouterGraph >::vertex_descriptor vertex_descriptor;
+
+  // For now we doing Dijkstra for every node.  Can be replaced with Bellman-Ford or Floyd-Warshall.
+  // Other algorithms should be faster, but they need additional EdgeListGraph concept provided by the graph, which
+  // is not obviously how implement in an efficient manner
+  for (NodeList::Iterator node = NodeList::Begin (); node != NodeList::End (); node++)
+    {
+      Ptr<GlobalRouter> source = (*node)->GetObject<GlobalRouter> ();
+      if (source == 0)
+	{
+	  NS_LOG_DEBUG ("Node " << (*node)->GetId () << " does not export GlobalRouter interface");
+	  continue;
+	}
+
+      Ptr<Fib>  fib  = source->GetObject<Fib> ();
+      fib->InvalidateAll ();
+      NS_ASSERT (fib != 0);
+
+      NS_LOG_DEBUG ("===========");
+      NS_LOG_DEBUG ("Reachability from Node: " << source->GetObject<Node> ()->GetId () << " (" << Names::FindName (source->GetObject<Node> ()) << ")");
+
+      Ptr<L3Protocol> l3 = source->GetObject<L3Protocol> ();
+      NS_ASSERT (l3 != 0);
+
+      // remember interface statuses
+      std::vector<uint16_t> originalMetric (l3->GetNFaces ());
+      for (uint32_t faceId = 0; faceId < l3->GetNFaces (); faceId++)
+        {
+          originalMetric[faceId] = l3->GetFace (faceId)->GetMetric ();
+          l3->GetFace (faceId)->SetMetric (std::numeric_limits<int16_t>::max ()-1); // value std::numeric_limits<int16_t>::max () MUST NOT be used (reserved)
+        }
+
+      for (uint32_t enabledFaceId = 0; enabledFaceId < l3->GetNFaces (); enabledFaceId++)
+        {
+          if (DynamicCast<ndn::NetDeviceFace> (l3->GetFace (enabledFaceId)) == 0)
+            continue;
+
+          // enabling only faceId
+          l3->GetFace (enabledFaceId)->SetMetric (originalMetric[enabledFaceId]);
+
+          DistancesMap    distances;
+
+          NS_LOG_DEBUG ("-----------");
+
+          dijkstra_shortest_paths (graph, source,
+                                   // predecessor_map (boost::ref(predecessors))
+                                   // .
+                                   distance_map (boost::ref(distances))
+                                   .
+                                   distance_inf (WeightInf)
+                                   .
+                                   distance_zero (WeightZero)
+                                   .
+                                   distance_compare (boost::WeightCompare ())
+                                   .
+                                   distance_combine (boost::WeightCombine ())
+                                   );
+
+          // NS_LOG_DEBUG (predecessors.size () << ", " << distances.size ());
+
+          for (DistancesMap::iterator i = distances.begin ();
+               i != distances.end ();
+               i++)
+            {
+              if (i->first == source)
+                continue;
+              else
+                {
+                  // cout << "  Node " << i->first->GetObject<Node> ()->GetId ();
+                  if (i->second.get<0> () == 0)
+                    {
+                      // cout << " is unreachable" << endl;
+                    }
+                  else
+                    {
+                      BOOST_FOREACH (const Ptr<const NameComponents> &prefix, i->first->GetLocalPrefixes ())
+                        {
+                          NS_LOG_DEBUG (" prefix " << *prefix << " reachable via face " << *i->second.get<0> ()
+                                        << " with distance " << i->second.get<1> ()
+                                        << " with delay " << i->second.get<2> ());
+
+                          if (i->second.get<0> ()->GetMetric () == std::numeric_limits<uint16_t>::max ()-1)
+                            continue;
+
+                          Ptr<fib::Entry> entry = fib->Add (prefix, i->second.get<0> (), i->second.get<1> ());
+                          entry->SetRealDelayToProducer (i->second.get<0> (), Seconds (i->second.get<2> ()));
+
+                          Ptr<Limits> faceLimits = i->second.get<0> ()->GetObject<Limits> ();
+
+                          Ptr<Limits> fibLimits = entry->GetObject<Limits> ();
+                          if (fibLimits != 0)
+                            {
+                              // if it was created by the forwarding strategy via DidAddFibEntry event
+                              fibLimits->SetLimits (faceLimits->GetMaxRate (), 2 * i->second.get<2> () /*exact RTT*/);
+                              NS_LOG_DEBUG ("Set limit for prefix " << *prefix << " " << faceLimits->GetMaxRate () << " / " <<
+                                            2*i->second.get<2> () << "s (" << faceLimits->GetMaxRate () * 2 * i->second.get<2> () << ")");
+                            }
+                        }
+                    }
+                }
+            }
+
+          // disabling the face again
+          l3->GetFace (enabledFaceId)->SetMetric (std::numeric_limits<uint16_t>::max ()-1);
+        }
+
+      // recover original interface statuses
+      for (uint32_t faceId = 0; faceId < l3->GetNFaces (); faceId++)
+        {
+          l3->GetFace (faceId)->SetMetric (originalMetric[faceId]);
+        }
+    }
+}
+
 
 } // namespace ndn
 } // namespace ns3
diff --git a/helper/ndn-global-routing-helper.h b/helper/ndn-global-routing-helper.h
index 983c7b0..f233e89 100644
--- a/helper/ndn-global-routing-helper.h
+++ b/helper/ndn-global-routing-helper.h
@@ -98,9 +98,19 @@
   /**
    * @brief Calculate for every node shortest path trees and install routes to all prefix origins
    */
-  void
+  static void
   CalculateRoutes ();
 
+  /**
+   * @brief Calculate all possible next-hop independent alternative routes
+   *
+   * Refer to the implementation for more details.
+   *
+   * Note that this method is highly experimental and should be used with caution (very time consuming).
+   */
+  static void
+  CalculateAllPossibleRoutes ();
+
 private:
   void
   Install (Ptr<Channel> channel);
diff --git a/model/fib/ndn-fib-entry.cc b/model/fib/ndn-fib-entry.cc
index c04e43b..35b3a99 100644
--- a/model/fib/ndn-fib-entry.cc
+++ b/model/fib/ndn-fib-entry.cc
@@ -54,13 +54,13 @@
 FaceMetric::UpdateRtt (const Time &rttSample)
 {
   // const Time & this->m_rttSample
-  
+
   //update srtt and rttvar (RFC 2988)
   if (m_sRtt.IsZero ())
     {
       //first RTT measurement
       NS_ASSERT_MSG (m_rttVar.IsZero (), "SRTT is zero, but variation is not");
-      
+
       m_sRtt = rttSample;
       m_rttVar = Time (m_sRtt / 2.0);
     }
@@ -97,7 +97,7 @@
                  "Update status can be performed only on existing faces of CcxnFibEntry");
 
   m_faces.modify (record,
-                  (&ll::_1)->*&FaceMetric::m_status = status);
+                  ll::bind (&FaceMetric::SetStatus, ll::_1, status));
 
   // reordering random access index same way as by metric index
   m_faces.get<i_nth> ().rearrange (m_faces.get<i_metric> ().begin ());
@@ -117,16 +117,16 @@
   else
   {
     // don't update metric to higher value
-    if (record->m_routingCost > metric || record->m_status == FaceMetric::NDN_FIB_RED)
+    if (record->GetRoutingCost () > metric || record->GetStatus () == FaceMetric::NDN_FIB_RED)
       {
         m_faces.modify (record,
-                        (&ll::_1)->*&FaceMetric::m_routingCost = metric);
+                        ll::bind (&FaceMetric::SetRoutingCost, ll::_1, metric));
 
         m_faces.modify (record,
-                        (&ll::_1)->*&FaceMetric::m_status = FaceMetric::NDN_FIB_YELLOW);
+                        ll::bind (&FaceMetric::SetStatus, ll::_1, FaceMetric::NDN_FIB_YELLOW));
       }
   }
-  
+
   // reordering random access index same way as by metric index
   m_faces.get<i_nth> ().rearrange (m_faces.get<i_metric> ().begin ());
 }
@@ -141,7 +141,7 @@
   if (record != m_faces.get<i_face> ().end ())
     {
       m_faces.modify (record,
-                      (&ll::_1)->*&FaceMetric::m_realDelay = delay);
+                      ll::bind (&FaceMetric::SetRealDelay, ll::_1, delay));
     }
 }
 
@@ -154,10 +154,10 @@
        face++)
     {
       m_faces.modify (face,
-                      (&ll::_1)->*&FaceMetric::m_routingCost = std::numeric_limits<uint16_t>::max ());
+                      ll::bind (&FaceMetric::SetRoutingCost, ll::_1, std::numeric_limits<uint16_t>::max ()));
 
       m_faces.modify (face,
-                      (&ll::_1)->*&FaceMetric::m_status = FaceMetric::NDN_FIB_RED);
+                      ll::bind (&FaceMetric::SetStatus, ll::_1, FaceMetric::NDN_FIB_RED));
     }
 }
 
diff --git a/model/fib/ndn-fib-entry.h b/model/fib/ndn-fib-entry.h
index 214b0eb..93fa2aa 100644
--- a/model/fib/ndn-fib-entry.h
+++ b/model/fib/ndn-fib-entry.h
@@ -26,6 +26,7 @@
 #include "ns3/ndn-face.h"
 #include "ns3/ndn-name-components.h"
 #include "ns3/ndn-limits.h"
+#include "ns3/traced-value.h"
 
 #include <boost/multi_index_container.hpp>
 #include <boost/multi_index/tag.hpp>
@@ -82,7 +83,7 @@
    * @brief Comparison between FaceMetric and Face
    */
   bool
-  operator< (const Ptr<Face> &face) const { return *m_face < *face; } 
+  operator< (const Ptr<Face> &face) const { return *m_face < *face; }
 
   /**
    * @brief Return Face associated with FaceMetric
@@ -96,17 +97,81 @@
    */
   void
   UpdateRtt (const Time &rttSample);
-  
+
+  /**
+   * @brief Get current status of FIB entry
+   */
+  Status
+  GetStatus () const
+  {
+    return m_status;
+  }
+
+  /**
+   * @brief Set current status of FIB entry
+   */
+  void
+  SetStatus (Status status)
+  {
+    m_status.Set (status);
+  }
+
+  /**
+   * @brief Get current routing cost
+   */
+  int32_t
+  GetRoutingCost () const
+  {
+    return m_routingCost;
+  }
+
+  /**
+   * @brief Set routing cost
+   */
+  void
+  SetRoutingCost (int32_t routingCost)
+  {
+    m_routingCost = routingCost;
+  }
+
+  /**
+   * @brief Get real propagation delay to the producer, calculated based on NS-3 p2p link delays
+   */
+  Time
+  GetRealDelay () const
+  {
+    return m_realDelay;
+  }
+
+  /**
+   * @brief Set real propagation delay to the producer, calculated based on NS-3 p2p link delays
+   */
+  void
+  SetRealDelay (Time realDelay)
+  {
+    m_realDelay = realDelay;
+  }
+
+  /**
+   * @brief Get direct access to status trace
+   */
+  TracedValue<Status> &
+  GetStatusTrace ()
+  {
+    return m_status;
+  }
+
 private:
   friend std::ostream& operator<< (std::ostream& os, const FaceMetric &metric);
-public:
+
+private:
   Ptr<Face> m_face; ///< Face
-  
-  Status m_status;		///< \brief Status of the next hop: 
+
+  TracedValue<Status> m_status; ///< \brief Status of the next hop:
 				///<		- 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)
 
   Time m_sRtt;         ///< \brief smoothed round-trip time
@@ -141,7 +206,7 @@
       // For fast access to elements using Face
       boost::multi_index::ordered_unique<
         boost::multi_index::tag<i_face>,
-        boost::multi_index::member<FaceMetric,Ptr<Face>,&FaceMetric::m_face>
+        boost::multi_index::const_mem_fun<FaceMetric,Ptr<Face>,&FaceMetric::GetFace>
       >,
 
       // List of available faces ordered by (status, m_routingCost)
@@ -149,8 +214,8 @@
         boost::multi_index::tag<i_metric>,
         boost::multi_index::composite_key<
           FaceMetric,
-          boost::multi_index::member<FaceMetric,FaceMetric::Status,&FaceMetric::m_status>,
-          boost::multi_index::member<FaceMetric,int32_t,&FaceMetric::m_routingCost>
+          boost::multi_index::const_mem_fun<FaceMetric,FaceMetric::Status,&FaceMetric::GetStatus>,
+          boost::multi_index::const_mem_fun<FaceMetric,int32_t,&FaceMetric::GetRoutingCost>
         >
       >,
 
@@ -172,10 +237,10 @@
 {
 public:
   typedef Entry base_type;
-  
+
 public:
   class NoFaces {}; ///< @brief Exception class for the case when FIB entry is not found
-  
+
   /**
    * \brief Constructor
    * \param prefix smart pointer to the prefix for the FIB entry
@@ -185,7 +250,7 @@
   , m_needsProbing (false)
   {
   }
-  
+
   /**
    * \brief Update status of FIB next hop
    * \param status Status to set on the FIB entry
@@ -204,7 +269,7 @@
    */
   void
   SetRealDelayToProducer (Ptr<Face> face, Time delay);
-  
+
   /**
    * @brief Invalidate face
    *
@@ -218,7 +283,7 @@
    */
   void
   UpdateFaceRtt (Ptr<Face> face, const Time &sample);
-  
+
   /**
    * \brief Get prefix for the FIB entry
    */
diff --git a/model/fw/best-route.cc b/model/fw/best-route.cc
index 03400b7..08bbd7c 100644
--- a/model/fw/best-route.cc
+++ b/model/fw/best-route.cc
@@ -58,11 +58,11 @@
     ;
   return tid;
 }
-    
+
 BestRoute::BestRoute ()
 {
 }
-    
+
 bool
 BestRoute::DoPropagateInterest (Ptr<Face> inFace,
                                 Ptr<const InterestHeader> header,
@@ -77,14 +77,14 @@
     return true;
 
   int propagatedCount = 0;
-  
+
   BOOST_FOREACH (const fib::FaceMetric &metricFace, pitEntry->GetFibEntry ()->m_faces.get<fib::i_metric> ())
     {
       NS_LOG_DEBUG ("Trying " << boost::cref(metricFace));
-      if (metricFace.m_status == fib::FaceMetric::NDN_FIB_RED) // all non-read faces are in front
+      if (metricFace.GetStatus () == fib::FaceMetric::NDN_FIB_RED) // all non-read faces are in front
         break;
 
-      if (!TrySendOutInterest (inFace, metricFace.m_face, header, origPacket, pitEntry))
+      if (!TrySendOutInterest (inFace, metricFace.GetFace (), header, origPacket, pitEntry))
         {
           continue;
         }
diff --git a/model/fw/flooding.cc b/model/fw/flooding.cc
index 80b863a..0c369b7 100644
--- a/model/fw/flooding.cc
+++ b/model/fw/flooding.cc
@@ -59,7 +59,7 @@
     ;
   return tid;
 }
-    
+
 Flooding::Flooding ()
 {
 }
@@ -77,14 +77,14 @@
   BOOST_FOREACH (const fib::FaceMetric &metricFace, pitEntry->GetFibEntry ()->m_faces.get<fib::i_metric> ())
     {
       NS_LOG_DEBUG ("Trying " << boost::cref(metricFace));
-      if (metricFace.m_status == fib::FaceMetric::NDN_FIB_RED) // all non-read faces are in the front of the list
+      if (metricFace.GetStatus () == fib::FaceMetric::NDN_FIB_RED) // all non-read faces are in the front of the list
         break;
-      
-      if (!TrySendOutInterest (inFace, metricFace.m_face, header, origPacket, pitEntry))
+
+      if (!TrySendOutInterest (inFace, metricFace.GetFace (), header, origPacket, pitEntry))
         {
           continue;
         }
-      
+
       propagatedCount++;
     }
 
diff --git a/model/fw/green-yellow-red.cc b/model/fw/green-yellow-red.cc
index 52acc68..3b5fd13 100644
--- a/model/fw/green-yellow-red.cc
+++ b/model/fw/green-yellow-red.cc
@@ -72,18 +72,18 @@
   NS_ASSERT_MSG (m_pit != 0, "PIT should be aggregated with forwarding strategy");
 
   int propagatedCount = 0;
-  
+
   BOOST_FOREACH (const fib::FaceMetric &metricFace, pitEntry->GetFibEntry ()->m_faces.get<fib::i_metric> ())
     {
-      if (metricFace.m_status == fib::FaceMetric::NDN_FIB_RED ||
-          metricFace.m_status == fib::FaceMetric::NDN_FIB_YELLOW)
+      if (metricFace.GetStatus () == fib::FaceMetric::NDN_FIB_RED ||
+          metricFace.GetStatus () == fib::FaceMetric::NDN_FIB_YELLOW)
         break; //propagate only to green faces
 
-      if (!TrySendOutInterest (inFace, metricFace.m_face, header, origPacket, pitEntry))
+      if (!TrySendOutInterest (inFace, metricFace.GetFace (), header, origPacket, pitEntry))
         {
           continue;
         }
-      
+
       propagatedCount++;
       break; // propagate only one interest
     }
@@ -105,6 +105,22 @@
 }
 
 void
+GreenYellowRed::WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry)
+{
+  NS_LOG_DEBUG ("WillEraseTimedOutPendingInterest for " << pitEntry->GetPrefix ());
+
+  for (pit::Entry::out_container::iterator face = pitEntry->GetOutgoing ().begin ();
+       face != pitEntry->GetOutgoing ().end ();
+       face ++)
+    {
+      // NS_LOG_DEBUG ("Face: " << face->m_face);
+      pitEntry->GetFibEntry ()->UpdateStatus (face->m_face, fib::FaceMetric::NDN_FIB_YELLOW);
+    }
+
+  super::WillEraseTimedOutPendingInterest (pitEntry);
+}
+
+void
 GreenYellowRed::DidReceiveValidNack (Ptr<Face> inFace,
                                      uint32_t nackCode,
                                      Ptr<const InterestHeader> header,
diff --git a/model/fw/green-yellow-red.h b/model/fw/green-yellow-red.h
index 371f7fd..e82c93b 100644
--- a/model/fw/green-yellow-red.h
+++ b/model/fw/green-yellow-red.h
@@ -47,13 +47,16 @@
                        Ptr<const InterestHeader> header,
                        Ptr<const Packet> origPacket,
                        Ptr<pit::Entry> pitEntry);
+
+  virtual void
+  WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry);
+
   virtual void
   DidReceiveValidNack (Ptr<Face> incomingFace,
                        uint32_t nackCode,
                        Ptr<const InterestHeader> header,
                        Ptr<const Packet> origPacket,
                        Ptr<pit::Entry> pitEntry);
-
 private:
   typedef Nacks super;
 };
diff --git a/model/fw/nacks.cc b/model/fw/nacks.cc
index 8c24157..00bf840 100644
--- a/model/fw/nacks.cc
+++ b/model/fw/nacks.cc
@@ -27,6 +27,7 @@
 #include "ns3/ndn-pit.h"
 #include "ns3/ndn-fib.h"
 #include "ns3/ndn-content-store.h"
+#include "ns3/ndnSIM/utils/ndn-fw-hop-count-tag.h"
 
 #include "ns3/assert.h"
 #include "ns3/ptr.h"
@@ -118,6 +119,16 @@
       Ptr<Packet> nack = Create<Packet> ();
       nack->AddHeader (*nackHeader);
 
+      FwHopCountTag hopCountTag;
+      if (origPacket->PeekPacketTag (hopCountTag))
+        {
+     	  nack->AddPacketTag (hopCountTag);
+        }
+      else
+        {
+          NS_LOG_DEBUG ("No FwHopCountTag tag associated with received duplicated Interest");
+        }
+
       inFace->Send (nack);
       m_outNacks (nackHeader, inFace);
     }
@@ -136,6 +147,16 @@
       nackHeader->SetNack (InterestHeader::NACK_GIVEUP_PIT);
       packet->AddHeader (*nackHeader);
 
+      FwHopCountTag hopCountTag;
+      if (origPacket->PeekPacketTag (hopCountTag))
+        {
+     	  packet->AddPacketTag (hopCountTag);
+        }
+      else
+        {
+          NS_LOG_DEBUG ("No FwHopCountTag tag associated with original Interest");
+        }
+
       BOOST_FOREACH (const pit::IncomingFace &incoming, pitEntry->GetIncoming ())
         {
           NS_LOG_DEBUG ("Send NACK for " << boost::cref (nackHeader->GetName ()) << " to " << boost::cref (*incoming.m_face));
@@ -186,6 +207,16 @@
       nonNackHeader->SetNack (InterestHeader::NORMAL_INTEREST);
       nonNackInterest->AddHeader (*nonNackHeader);
 
+      FwHopCountTag hopCountTag;
+      if (origPacket->PeekPacketTag (hopCountTag))
+        {
+     	  nonNackInterest->AddPacketTag (hopCountTag);
+        }
+      else
+        {
+          NS_LOG_DEBUG ("No FwHopCountTag tag associated with received NACK");
+        }
+
       bool propagated = DoPropagateInterest (inFace, nonNackHeader, nonNackInterest, pitEntry);
       if (!propagated)
         {
diff --git a/model/fw/per-fib-limits.h b/model/fw/per-fib-limits.h
index 47f9ee6..4affec9 100644
--- a/model/fw/per-fib-limits.h
+++ b/model/fw/per-fib-limits.h
@@ -57,13 +57,13 @@
    */
   static std::string
   GetLogName ();
-  
+
   /**
    * @brief Default constructor
    */
   PerFibLimits ()
   { }
-  
+
   /// \copydoc ForwardingStrategy::WillEraseTimedOutPendingInterest
   virtual void
   WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry);
@@ -86,14 +86,14 @@
   DidAddFibEntry (Ptr<fib::Entry> fibEntry)
   {
     ObjectFactory factory;
-    factory.SetTypeId (fibEntry->m_faces.begin ()->m_face->GetObject<Limits> ()->GetInstanceTypeId ());
-    
+    factory.SetTypeId (fibEntry->m_faces.begin ()->GetFace ()->GetObject<Limits> ()->GetInstanceTypeId ());
+
     Ptr<Limits> limits = factory.template Create<Limits> ();
     fibEntry->AggregateObject (limits);
 
     super::DidAddFibEntry (fibEntry);
   }
-  
+
 protected:
   /// \copydoc ForwardingStrategy::CanSendOutInterest
   virtual bool
@@ -102,7 +102,7 @@
                       Ptr<const InterestHeader> header,
                       Ptr<const Packet> origPacket,
                       Ptr<pit::Entry> pitEntry);
-  
+
   /// \copydoc ForwardingStrategy::WillSatisfyPendingInterest
   virtual void
   WillSatisfyPendingInterest (Ptr<Face> inFace,
@@ -110,7 +110,7 @@
 
 protected:
   static LogComponent g_log; ///< @brief Logging variable
-  
+
 private:
   std::string m_limitType;
 };
@@ -149,7 +149,7 @@
 
   Ptr<Limits> fibLimits = pitEntry->GetFibEntry ()->template GetObject<Limits> ();
   // no checks for the limit here. the check should be somewhere elese
-  
+
   if (fibLimits->IsBelowLimit ())
     {
       if (super::CanSendOutInterest (inFace, outFace, header, origPacket, pitEntry))
@@ -158,7 +158,7 @@
           return true;
         }
     }
-  
+
   return false;
 }
 
@@ -184,7 +184,7 @@
 
   Ptr<Limits> fibLimits = pitEntry->GetFibEntry ()->template GetObject<Limits> ();
   fibLimits->ReturnLimit ();
-  
+
   super::WillSatisfyPendingInterest (inFace, pitEntry);
 }
 
diff --git a/model/fw/smart-flooding.cc b/model/fw/smart-flooding.cc
index 3777739..c8b8406 100644
--- a/model/fw/smart-flooding.cc
+++ b/model/fw/smart-flooding.cc
@@ -59,7 +59,7 @@
     ;
   return tid;
 }
-    
+
 SmartFlooding::SmartFlooding ()
 {
 }
@@ -82,14 +82,14 @@
   BOOST_FOREACH (const fib::FaceMetric &metricFace, pitEntry->GetFibEntry ()->m_faces.get<fib::i_metric> ())
     {
       NS_LOG_DEBUG ("Trying " << boost::cref(metricFace));
-      if (metricFace.m_status == fib::FaceMetric::NDN_FIB_RED) // all non-read faces are in the front of the list
+      if (metricFace.GetStatus () == fib::FaceMetric::NDN_FIB_RED) // all non-read faces are in the front of the list
         break;
-      
-      if (!TrySendOutInterest (inFace, metricFace.m_face, header, origPacket, pitEntry))
+
+      if (!TrySendOutInterest (inFace, metricFace.GetFace (), header, origPacket, pitEntry))
         {
           continue;
         }
-      
+
       propagatedCount++;
     }
 
diff --git a/model/ndn-l3-protocol.cc b/model/ndn-l3-protocol.cc
index b0957c5..28d337b 100644
--- a/model/ndn-l3-protocol.cc
+++ b/model/ndn-l3-protocol.cc
@@ -69,7 +69,7 @@
 }
 
 
-TypeId 
+TypeId
 L3Protocol::GetTypeId (void)
 {
   static TypeId tid = TypeId ("ns3::ndn::L3Protocol")
@@ -134,7 +134,7 @@
   Object::NotifyNewAggregate ();
 }
 
-void 
+void
 L3Protocol::DoDispose (void)
 {
   NS_LOG_FUNCTION (this);
@@ -152,7 +152,7 @@
   Object::DoDispose ();
 }
 
-uint32_t 
+uint32_t
 L3Protocol::AddFace (const Ptr<Face> &face)
 {
   NS_LOG_FUNCTION (this << &face);
@@ -165,7 +165,7 @@
   m_faces.push_back (face);
   m_faceCounter++;
 
-  m_forwardingStrategy->AddFace (face); // notify that face is added    
+  m_forwardingStrategy->AddFace (face); // notify that face is added
   return face->GetId ();
 }
 
@@ -181,11 +181,11 @@
   for (Ptr<pit::Entry> pitEntry = pit->Begin (); pitEntry != 0; pitEntry = pit->Next (pitEntry))
     {
       pitEntry->RemoveAllReferencesToFace (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->GetFibEntry ()->m_faces.size () == 1 &&
-          pitEntry->GetFibEntry ()->m_faces.begin ()->m_face == face)
+          pitEntry->GetFibEntry ()->m_faces.begin ()->GetFace () == face)
         {
           entriesToRemoves.push_back (pitEntry);
         }
@@ -200,7 +200,7 @@
   m_faces.erase (face_it);
 
   GetObject<Fib> ()->RemoveFromAll (face);
-  m_forwardingStrategy->RemoveFace (face); // notify that face is removed  
+  m_forwardingStrategy->RemoveFace (face); // notify that face is removed
 }
 
 Ptr<Face>
@@ -235,21 +235,21 @@
   return 0;
 }
 
-uint32_t 
+uint32_t
 L3Protocol::GetNFaces (void) const
 {
   return m_faces.size ();
 }
 
 // Callback from lower layer
-void 
+void
 L3Protocol::Receive (const Ptr<Face> &face, const Ptr<const Packet> &p)
 {
   if (!face->IsUp ())
     return;
 
   NS_LOG_DEBUG (*p);
-  
+
   NS_LOG_LOGIC ("Packet from face " << *face << " received on node " <<  m_node->GetId ());
 
   Ptr<Packet> packet = p->Copy (); // give upper layers a rw copy of the packet
@@ -271,21 +271,21 @@
             // if (header->GetNack () > 0)
             //   OnNack (face, header, p/*original packet*/);
             // else
-            //   OnInterest (face, header, p/*original packet*/);  
+            //   OnInterest (face, header, p/*original packet*/);
             break;
           }
         case HeaderHelper::CONTENT_OBJECT_NDNSIM:
           {
             s_dataCounter ++;
             Ptr<ContentObjectHeader> header = Create<ContentObjectHeader> ();
-            
+
             static ContentObjectTail contentObjectTrailer; //there is no data in this object
 
             // Deserialization. Exception may be thrown
             packet->RemoveHeader (*header);
             packet->RemoveTrailer (contentObjectTrailer);
 
-            m_forwardingStrategy->OnData (face, header, packet/*payload*/, p/*original packet*/);  
+            m_forwardingStrategy->OnData (face, header, packet/*payload*/, p/*original packet*/);
             break;
           }
         case HeaderHelper::INTEREST_CCNB:
@@ -293,7 +293,7 @@
           NS_FATAL_ERROR ("ccnb support is broken in this implementation");
           break;
         }
-      
+
       // exception will be thrown if packet is not recognized
     }
   catch (UnknownHeaderException)
diff --git a/test/ndnSIM-fib-entry.cc b/test/ndnSIM-fib-entry.cc
new file mode 100644
index 0000000..2fbdb85
--- /dev/null
+++ b/test/ndnSIM-fib-entry.cc
@@ -0,0 +1,154 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011,2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ndnSIM-fib-entry.h"
+#include "ns3/core-module.h"
+#include "ns3/ndnSIM-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/node-list.h"
+
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+
+#include "ns3/ndn-fib-entry.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.FibEntryTest");
+
+namespace ns3
+{
+
+class Client : public ndn::App
+{
+protected:
+  void
+  StartApplication ()
+  {
+    ndn::App::StartApplication ();
+
+    // add default route
+    Ptr<ndn::fib::Entry> fibEntry = GetNode ()->GetObject<ndn::Fib> ()->Add (ndn::NameComponents ("/"), m_face, 0);
+    fibEntry->UpdateStatus (m_face, ndn::fib::FaceMetric::NDN_FIB_GREEN);
+
+    Simulator::Schedule (Seconds (0.5), &Client::SendPacket, this, std::string("/1"), 1);
+    Simulator::Schedule (Seconds (4.0), &Client::SendPacket, this, std::string("/2"), 1);
+  }
+
+  void
+  StopApplication ()
+  {
+    ndn::App::StopApplication ();
+  }
+
+private:
+  void
+  SendPacket (const std::string &prefix, uint32_t nonce)
+  {
+    Ptr<Packet> pkt = Create<Packet> (0);
+    ndn::InterestHeader i;
+    i.SetName (Create<ndn::NameComponents> (prefix));
+    i.SetNonce (nonce);
+    i.SetInterestLifetime (Seconds (0.5));
+
+    pkt->AddHeader (i);
+    m_protocolHandler (pkt);
+  }
+};
+
+struct StatusRecorder
+{
+  StatusRecorder (Ptr<Node> node, Ptr<ndn::fib::Entry> fibEntry, Ptr<ndn::Face> face)
+    : m_node (node)
+    , m_fibEntry (fibEntry)
+    , m_face (face)
+  {
+    count = 0;
+  }
+
+  void
+  StatusChange (ndn::fib::FaceMetric::Status oldStatus, ndn::fib::FaceMetric::Status newStatus)
+  {
+    count ++;
+    // std::cout << Simulator::Now ().ToDouble (Time::S) << "s\tnode " << m_node->GetId () << " has changed fibEntry " << m_fibEntry->GetPrefix () << " face " << *m_face << " to " << newStatus << " from " << oldStatus << std::endl;
+  }
+
+  int count;
+
+private:
+  Ptr<Node> m_node;
+  Ptr<ndn::fib::Entry> m_fibEntry;
+  Ptr<ndn::Face> m_face;
+};
+
+void
+FibEntryTest::DoRun ()
+{
+  Ptr<Node> node = CreateObject<Node> ();
+  Ptr<Node> nodeSink = CreateObject<Node> ();
+  PointToPointHelper p2p;
+  p2p.Install (node, nodeSink);
+
+  ndn::StackHelper ndn;
+  ndn.SetForwardingStrategy ("ns3::ndn::fw::BestRoute");
+  ndn.Install (node);
+  ndn.Install (nodeSink);
+
+  ndn::StackHelper::AddRoute (node, "/", 0, 0);
+
+  Ptr<Client> app1 = CreateObject<Client> ();
+  node->AddApplication (app1);
+
+  ndn::AppHelper sinkHelper ("ns3::ndn::Producer");
+  sinkHelper.SetPrefix ("/");
+  sinkHelper.Install (nodeSink)
+    .Stop (Seconds (2.0));
+
+  std::list< boost::shared_ptr<StatusRecorder> > recorders;
+
+  for (NodeList::Iterator anode = NodeList::Begin ();
+       anode != NodeList::End ();
+       anode ++)
+    {
+      Ptr<ndn::Fib> fib = (*anode)->GetObject<ndn::Fib> ();
+
+      for (Ptr<ndn::fib::Entry> entry = fib->Begin ();
+           entry != fib->End ();
+           entry = fib->Next (entry))
+        {
+          BOOST_FOREACH (const ndn::fib::FaceMetric & faceMetric, entry->m_faces)
+            {
+              boost::shared_ptr<StatusRecorder> recorder = boost::make_shared<StatusRecorder> (*anode, entry, faceMetric.GetFace ());
+              recorders.push_back (recorder);
+
+              const_cast<ndn::fib::FaceMetric &> (faceMetric).GetStatusTrace ().ConnectWithoutContext (MakeCallback (&StatusRecorder::StatusChange, recorder.get ()));
+            }
+        }
+    }
+
+  Simulator::Stop (Seconds (10.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  NS_TEST_ASSERT_MSG_EQ (recorders.size (), 1, "only one recorder should be: only one real FIB record should have existed");
+  NS_TEST_ASSERT_MSG_EQ (recorders.front ()->count, 2, "two events should have been reported");
+}
+
+}
diff --git a/test/ndnSIM-fib-entry.h b/test/ndnSIM-fib-entry.h
new file mode 100644
index 0000000..4f78f53
--- /dev/null
+++ b/test/ndnSIM-fib-entry.h
@@ -0,0 +1,48 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011-2013 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 NDNSIM_TEST_FIB_ENTRY_H
+#define NDNSIM_TEST_FIB_ENTRY_H
+
+#include "ns3/test.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+namespace ndn {
+class Fib;
+class Pit;
+}
+
+class FibEntryTest : public TestCase
+{
+public:
+  FibEntryTest ()
+    : TestCase ("FIB entry test")
+  {
+  }
+
+private:
+  virtual void DoRun ();
+};
+
+}
+
+#endif // NDNSIM_TEST_FIB_ENTRY_H
diff --git a/test/ndnSIM-tests.cc b/test/ndnSIM-tests.cc
index 3f0c319..688fca4 100644
--- a/test/ndnSIM-tests.cc
+++ b/test/ndnSIM-tests.cc
@@ -23,6 +23,7 @@
 
 #include "ndnSIM-serialization.h"
 #include "ndnSIM-pit.h"
+#include "ndnSIM-fib-entry.h"
 
 namespace ns3
 {
@@ -34,9 +35,10 @@
     : TestSuite ("ndnSIM-suite", UNIT)
   {
     SetDataDir (NS_TEST_SOURCEDIR);
-    
+
     AddTestCase (new InterestSerializationTest ());
     AddTestCase (new ContentObjectSerializationTest ());
+    AddTestCase (new FibEntryTest ());
     // AddTestCase (new PitTest ());
   }
 };
diff --git a/tools/rocketfuel-maps-cch-to-annotaded.cc b/tools/rocketfuel-maps-cch-to-annotaded.cc
index d9fa17e..193d6f5 100644
--- a/tools/rocketfuel-maps-cch-to-annotaded.cc
+++ b/tools/rocketfuel-maps-cch-to-annotaded.cc
@@ -135,7 +135,11 @@
   topologyReader.SaveGraphviz (graph);
   if (buildGraphvizGraph)
     {
-      system (("neato -Tpdf \"" + graph + "\" > \"" + graph_pdf + "\"").c_str ());
+      int ret = system (("neato -Tpdf \"" + graph + "\" > \"" + graph_pdf + "\"").c_str ());
+      if (ret != 0)
+        {
+          std::cerr << "WARN: failed to build a graph for the topology. Check if `neato' command is installed (part of graphviz package)" << std::endl;
+        }
     }
 
   topologyReader.SaveTopology (output);
diff --git a/utils/ndn-rtt-estimator.cc b/utils/ndn-rtt-estimator.cc
new file mode 100644
index 0000000..93193d2
--- /dev/null
+++ b/utils/ndn-rtt-estimator.cc
@@ -0,0 +1,248 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//
+// 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: Rajib Bhattacharjea<raj.b@gatech.edu>
+//
+
+// THIS IS A COPY OF rtt-estimator.cc from internet module with minor modifications
+
+// Ported from:
+// Georgia Tech Network Simulator - Round Trip Time Estimation Class
+// George F. Riley.  Georgia Tech, Spring 2002
+
+// Implements several variations of round trip time estimators
+
+#include <iostream>
+
+#include "ndn-rtt-estimator.h"
+#include "ns3/simulator.h"
+#include "ns3/double.h"
+#include "ns3/integer.h"
+#include "ns3/uinteger.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.RttEstimator");
+
+namespace ns3 {
+
+namespace ndn {
+
+NS_OBJECT_ENSURE_REGISTERED (RttEstimator);
+
+TypeId
+RttEstimator::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ndn::RttEstimator")
+    .SetParent<Object> ()
+    .AddAttribute ("MaxMultiplier",
+                   "Maximum RTO Multiplier",
+                   UintegerValue (64),
+                   MakeUintegerAccessor (&RttEstimator::m_maxMultiplier),
+                   MakeUintegerChecker<uint16_t> ())
+    .AddAttribute ("InitialEstimation",
+                   "Initial RTT estimation",
+                   TimeValue (Seconds (1.0)),
+                   MakeTimeAccessor (&RttEstimator::m_initialEstimatedRtt),
+                   MakeTimeChecker ())
+    .AddAttribute ("MinRTO",
+                   "Minimum retransmit timeout value",
+                   TimeValue (Seconds (0.2)), // RFC2988 says min RTO=1 sec, but Linux uses 200ms. See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
+                   MakeTimeAccessor (&RttEstimator::SetMinRto,
+                                     &RttEstimator::GetMinRto),
+                   MakeTimeChecker ())
+    .AddAttribute ("MaxRTO",
+                   "Maximum retransmit timeout value",
+                   TimeValue (Seconds (200.0)),
+                   MakeTimeAccessor (&RttEstimator::SetMaxRto,
+                                     &RttEstimator::GetMaxRto),
+                   MakeTimeChecker ())
+  ;
+  return tid;
+}
+
+void
+RttEstimator::SetMinRto (Time minRto)
+{
+  NS_LOG_FUNCTION (this << minRto);
+  m_minRto = minRto;
+}
+Time
+RttEstimator::GetMinRto (void) const
+{
+  return m_minRto;
+}
+
+void
+RttEstimator::SetMaxRto (Time maxRto)
+{
+  NS_LOG_FUNCTION (this << maxRto);
+  m_maxRto = maxRto;
+}
+Time
+RttEstimator::GetMaxRto (void) const
+{
+  return m_maxRto;
+}
+
+void
+RttEstimator::SetCurrentEstimate (Time estimate)
+{
+  NS_LOG_FUNCTION (this << estimate);
+  m_currentEstimatedRtt = estimate;
+}
+Time
+RttEstimator::GetCurrentEstimate (void) const
+{
+  return m_currentEstimatedRtt;
+}
+
+
+//RttHistory methods
+RttHistory::RttHistory (SequenceNumber32 s, uint32_t c, Time t)
+  : seq (s), count (c), time (t), retx (false)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+RttHistory::RttHistory (const RttHistory& h)
+  : seq (h.seq), count (h.count), time (h.time), retx (h.retx)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+// Base class methods
+
+RttEstimator::RttEstimator ()
+  : m_next (1),
+    m_nSamples (0),
+    m_multiplier (1),
+    m_history ()
+{
+  NS_LOG_FUNCTION (this);
+  //note next=1 everywhere since first segment will have sequence 1
+
+  // We need attributes initialized here, not later, so use the
+  // ConstructSelf() technique documented in the manual
+  ObjectBase::ConstructSelf (AttributeConstructionList ());
+  m_currentEstimatedRtt = m_initialEstimatedRtt;
+  NS_LOG_DEBUG ("Initialize m_currentEstimatedRtt to " << m_currentEstimatedRtt.GetSeconds () << " sec.");
+}
+
+RttEstimator::RttEstimator (const RttEstimator& c)
+  : Object (c), m_next (c.m_next),
+    m_maxMultiplier (c.m_maxMultiplier),
+    m_initialEstimatedRtt (c.m_initialEstimatedRtt),
+    m_currentEstimatedRtt (c.m_currentEstimatedRtt), m_minRto (c.m_minRto), m_maxRto (c.m_maxRto),
+    m_nSamples (c.m_nSamples), m_multiplier (c.m_multiplier),
+    m_history (c.m_history)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+RttEstimator::~RttEstimator ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+void RttEstimator::SentSeq (SequenceNumber32 seq, uint32_t size)
+{
+  NS_LOG_FUNCTION (this << seq << size);
+  // Note that a particular sequence has been sent
+  if (seq == m_next)
+    { // This is the next expected one, just log at end
+      m_history.push_back (RttHistory (seq, size, Simulator::Now () ));
+      m_next = seq + SequenceNumber32 (size); // Update next expected
+    }
+  else
+    { // This is a retransmit, find in list and mark as re-tx
+      for (RttHistory_t::iterator i = m_history.begin (); i != m_history.end (); ++i)
+        {
+          if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32 (i->count))))
+            { // Found it
+              i->retx = true;
+              // One final test..be sure this re-tx does not extend "next"
+              if ((seq + SequenceNumber32 (size)) > m_next)
+                {
+                  m_next = seq + SequenceNumber32 (size);
+                  i->count = ((seq + SequenceNumber32 (size)) - i->seq); // And update count in hist
+                }
+              break;
+            }
+        }
+    }
+}
+
+Time RttEstimator::AckSeq (SequenceNumber32 ackSeq)
+{
+  NS_LOG_FUNCTION (this << ackSeq);
+  // An ack has been received, calculate rtt and log this measurement
+  // Note we use a linear search (O(n)) for this since for the common
+  // case the ack'ed packet will be at the head of the list
+  Time m = Seconds (0.0);
+  if (m_history.size () == 0) return (m);    // No pending history, just exit
+  RttHistory& h = m_history.front ();
+  if (!h.retx && ackSeq >= (h.seq + SequenceNumber32 (h.count)))
+    { // Ok to use this sample
+      m = Simulator::Now () - h.time; // Elapsed time
+      Measurement (m);                // Log the measurement
+      ResetMultiplier ();             // Reset multiplier on valid measurement
+    }
+  // Now delete all ack history with seq <= ack
+  while(m_history.size () > 0)
+    {
+      RttHistory& h = m_history.front ();
+      if ((h.seq + SequenceNumber32 (h.count)) > ackSeq) break;               // Done removing
+      m_history.pop_front (); // Remove
+    }
+  return m;
+}
+
+void RttEstimator::ClearSent ()
+{
+  NS_LOG_FUNCTION (this);
+  // Clear all history entries
+  m_next = 1;
+  m_history.clear ();
+}
+
+void RttEstimator::IncreaseMultiplier ()
+{
+  NS_LOG_FUNCTION (this);
+  m_multiplier = (m_multiplier*2 < m_maxMultiplier) ? m_multiplier*2 : m_maxMultiplier;
+  NS_LOG_DEBUG ("Multiplier increased to " << m_multiplier);
+}
+
+void RttEstimator::ResetMultiplier ()
+{
+  NS_LOG_FUNCTION (this);
+  m_multiplier = 1;
+}
+
+void RttEstimator::Reset ()
+{
+  NS_LOG_FUNCTION (this);
+  // Reset to initial state
+  m_next = 1;
+  m_currentEstimatedRtt = m_initialEstimatedRtt;
+  m_history.clear ();         // Remove all info from the history
+  m_nSamples = 0;
+  ResetMultiplier ();
+}
+
+
+} // namespace ndn
+} // namespace ns3
diff --git a/utils/ndn-rtt-estimator.h b/utils/ndn-rtt-estimator.h
new file mode 100644
index 0000000..6bf6aa8
--- /dev/null
+++ b/utils/ndn-rtt-estimator.h
@@ -0,0 +1,172 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//
+// 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: Rajib Bhattacharjea<raj.b@gatech.edu>
+//
+
+// Georgia Tech Network Simulator - Round Trip Time Estimation Class
+// George F. Riley.  Georgia Tech, Spring 2002
+
+// THIS IS A COPY OF rtt-estimator.h from internet module with minor modifications
+
+#ifndef NDN_RTT_ESTIMATOR_H
+#define NDN_RTT_ESTIMATOR_H
+
+#include <deque>
+#include "ns3/sequence-number.h"
+#include "ns3/nstime.h"
+#include "ns3/object.h"
+
+namespace ns3 {
+
+namespace ndn {
+
+/**
+ * \ingroup tcp
+ *
+ * \brief Helper class to store RTT measurements
+ */
+class RttHistory {
+public:
+  RttHistory (SequenceNumber32 s, uint32_t c, Time t);
+  RttHistory (const RttHistory& h); // Copy constructor
+public:
+  SequenceNumber32  seq;  // First sequence number in packet sent
+  uint32_t        count;  // Number of bytes sent
+  Time            time;   // Time this one was sent
+  bool            retx;   // True if this has been retransmitted
+};
+
+typedef std::deque<RttHistory> RttHistory_t;
+
+/**
+ * \ingroup tcp
+ *
+ * \brief Base class for all RTT Estimators
+ */
+class RttEstimator : public Object {
+public:
+  static TypeId GetTypeId (void);
+
+  RttEstimator();
+  RttEstimator (const RttEstimator&);
+
+  virtual ~RttEstimator();
+
+  /**
+   * \brief Note that a particular sequence has been sent
+   * \param seq the packet sequence number.
+   * \param size the packet size.
+   */
+  virtual void SentSeq (SequenceNumber32 seq, uint32_t size);
+
+  /**
+   * \brief Note that a particular ack sequence has been received
+   * \param ackSeq the ack sequence number.
+   * \return The measured RTT for this ack.
+   */
+  virtual Time AckSeq (SequenceNumber32 ackSeq);
+
+  /**
+   * \brief Clear all history entries
+   */
+  virtual void ClearSent ();
+
+  /**
+   * \brief Add a new measurement to the estimator. Pure virtual function.
+   * \param t the new RTT measure.
+   */
+  virtual void  Measurement (Time t) = 0;
+
+  /**
+   * \brief Returns the estimated RTO. Pure virtual function.
+   * \return the estimated RTO.
+   */
+  virtual Time RetransmitTimeout () = 0;
+
+  virtual Ptr<RttEstimator> Copy () const = 0;
+
+  /**
+   * \brief Increase the estimation multiplier up to MaxMultiplier.
+   */
+  virtual void IncreaseMultiplier ();
+
+  /**
+   * \brief Resets the estimation multiplier to 1.
+   */
+  virtual void ResetMultiplier ();
+
+  /**
+   * \brief Resets the estimation to its initial state.
+   */
+  virtual void Reset ();
+
+  /**
+   * \brief Sets the Minimum RTO.
+   * \param minRto The minimum RTO returned by the estimator.
+   */
+  void SetMinRto (Time minRto);
+
+  /**
+   * \brief Get the Minimum RTO.
+   * \return The minimum RTO returned by the estimator.
+   */
+  Time GetMinRto (void) const;
+
+  /**
+   * \brief Sets the Maximum RTO.
+   * \param minRto The maximum RTO returned by the estimator.
+   */
+  void SetMaxRto (Time maxRto);
+
+  /**
+   * \brief Get the Maximum RTO.
+   * \return The maximum RTO returned by the estimator.
+   */
+  Time GetMaxRto (void) const;
+
+  /**
+   * \brief Sets the current RTT estimate (forcefully).
+   * \param estimate The current RTT estimate.
+   */
+  void SetCurrentEstimate (Time estimate);
+
+  /**
+   * \brief gets the current RTT estimate.
+   * \return The current RTT estimate.
+   */
+  Time GetCurrentEstimate (void) const;
+
+private:
+  SequenceNumber32 m_next;    // Next expected sequence to be sent
+  uint16_t m_maxMultiplier;
+  Time m_initialEstimatedRtt;
+
+protected:
+  Time         m_currentEstimatedRtt;     // Current estimate
+  Time         m_minRto;                  // minimum value of the timeout
+  Time         m_maxRto;                  // maximum value of the timeout
+  uint32_t     m_nSamples;                // Number of samples
+  uint16_t     m_multiplier;              // RTO Multiplier
+  RttHistory_t m_history;     // List of sent packet
+};
+
+} // namespace ndn
+
+} // namespace ns3
+
+#endif /* RTT_ESTIMATOR_H */
diff --git a/utils/ndn-rtt-mean-deviation.cc b/utils/ndn-rtt-mean-deviation.cc
new file mode 100644
index 0000000..c05ad75
--- /dev/null
+++ b/utils/ndn-rtt-mean-deviation.cc
@@ -0,0 +1,181 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//           (c) 2013 University of Arizona
+//           (c) 2013 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: Rajib Bhattacharjea<raj.b@gatech.edu>
+//         Cheng Yi <yic@email.arizona.edu>
+//         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+//
+
+// Georgia Tech Network Simulator - Round Trip Time Estimation Class
+// George F. Riley.  Georgia Tech, Spring 2002
+
+#include "ndn-rtt-mean-deviation.h"
+#include "ns3/simulator.h"
+#include "ns3/double.h"
+#include "ns3/integer.h"
+#include "ns3/uinteger.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.RttMeanDeviation");
+
+namespace ns3 {
+namespace ndn {
+
+//---------------------------------------------------------------------------------
+// A modified version of Mean-Deviation Estimator optimized for NDN packet delivery
+
+NS_OBJECT_ENSURE_REGISTERED (RttMeanDeviation);
+
+TypeId
+RttMeanDeviation::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ndn::RttMeanDeviation")
+    .SetParent<RttEstimator> ()
+    .AddConstructor<RttMeanDeviation> ()
+    .AddAttribute ("Gain",
+                   "Gain used in estimating the RTT (smoothed RTT), must be 0 < Gain < 1",
+                   DoubleValue (0.125),
+                   MakeDoubleAccessor (&RttMeanDeviation::m_gain),
+                   MakeDoubleChecker<double> ())
+    .AddAttribute ("Gain2",
+                   "Gain2 used in estimating the RTT (variance), must be 0 < Gain2 < 1",
+                   DoubleValue (0.25),
+                   MakeDoubleAccessor (&RttMeanDeviation::m_gain2),
+                   MakeDoubleChecker<double> ())
+  ;
+  return tid;
+}
+
+RttMeanDeviation::RttMeanDeviation() :
+  m_variance (0)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+RttMeanDeviation::RttMeanDeviation (const RttMeanDeviation& c)
+  : RttEstimator (c), m_gain (c.m_gain), m_gain2 (c.m_gain2), m_variance (c.m_variance)
+{
+  NS_LOG_FUNCTION (this);
+}
+
+void RttMeanDeviation::Measurement (Time m)
+{
+  NS_LOG_FUNCTION (this << m);
+  if (m_nSamples)
+    { // Not first
+      Time err (m - m_currentEstimatedRtt);
+      double gErr = err.ToDouble (Time::S) * m_gain;
+      m_currentEstimatedRtt += Time::FromDouble (gErr, Time::S);
+      Time difference = Abs (err) - m_variance;
+      NS_LOG_DEBUG ("m_variance += " << Time::FromDouble (difference.ToDouble (Time::S) * m_gain2, Time::S));
+      m_variance += Time::FromDouble (difference.ToDouble (Time::S) * m_gain2, Time::S);
+    }
+  else
+    { // First sample
+      m_currentEstimatedRtt = m;             // Set estimate to current
+      //variance = sample / 2;               // And variance to current / 2
+      // m_variance = m; // try this  why????
+      m_variance = Seconds (m.ToDouble (Time::S) / 2);
+      NS_LOG_DEBUG ("(first sample) m_variance += " << m);
+    }
+  m_nSamples++;
+}
+
+Time RttMeanDeviation::RetransmitTimeout ()
+{
+  NS_LOG_FUNCTION (this);
+
+  double retval = std::min (m_maxRto.ToDouble (Time::S),
+                            std::max (m_multiplier*m_minRto.ToDouble (Time::S),
+                                      m_multiplier*(m_currentEstimatedRtt.ToDouble (Time::S) + 4 * m_variance.ToDouble (Time::S))));
+
+  NS_LOG_DEBUG ("RetransmitTimeout:  return " << retval);
+
+  return Seconds (retval);
+}
+
+Ptr<RttEstimator> RttMeanDeviation::Copy () const
+{
+  NS_LOG_FUNCTION (this);
+  return CopyObject<RttMeanDeviation> (this);
+}
+
+void RttMeanDeviation::Reset ()
+{
+  NS_LOG_FUNCTION (this);
+  // Reset to initial state
+  m_variance = Seconds (0);
+  RttEstimator::Reset ();
+}
+
+void RttMeanDeviation::Gain (double g)
+{
+  NS_LOG_FUNCTION (this);
+  NS_ASSERT_MSG( (g > 0) && (g < 1), "RttMeanDeviation: Gain must be less than 1 and greater than 0" );
+  m_gain = g;
+}
+
+void RttMeanDeviation::SentSeq (SequenceNumber32 seq, uint32_t size)
+{ 
+  NS_LOG_FUNCTION (this << seq << size);
+
+  RttHistory_t::iterator i;
+  for (i = m_history.begin (); i != m_history.end (); ++i)
+  {
+      if (seq == i->seq)
+      { // Found it
+          i->retx = true;
+          break;
+      }
+  }
+
+  // Note that a particular sequence has been sent
+  if (i == m_history.end())
+      m_history.push_back (RttHistory (seq, size, Simulator::Now () ));
+}
+
+Time RttMeanDeviation::AckSeq (SequenceNumber32 ackSeq)
+{
+  NS_LOG_FUNCTION (this << ackSeq);
+  // An ack has been received, calculate rtt and log this measurement
+  // Note we use a linear search (O(n)) for this since for the common
+  // case the ack'ed packet will be at the head of the list
+  Time m = Seconds (0.0);
+  if (m_history.size () == 0) return (m);    // No pending history, just exit
+
+  for (RttHistory_t::iterator i = m_history.begin (); i != m_history.end (); ++i)
+  {
+      if (ackSeq == i->seq)
+      { // Found it
+          if (!i->retx) {
+              m = Simulator::Now () - i->time;// Elapsed time
+              Measurement (m);                // Log the measurement
+              ResetMultiplier ();             // Reset multiplier on valid measurement
+          }
+          m_history.erase(i);
+          break;
+      }
+  }
+
+  return m;
+}
+
+} // namespace ndn
+} // namespace ns3
+
diff --git a/utils/ndn-rtt-mean-deviation.h b/utils/ndn-rtt-mean-deviation.h
new file mode 100644
index 0000000..e8b419c
--- /dev/null
+++ b/utils/ndn-rtt-mean-deviation.h
@@ -0,0 +1,71 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2006 Georgia Tech Research Corporation
+//           (c) 2013 University of Arizona
+//           (c) 2013 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: Rajib Bhattacharjea<raj.b@gatech.edu>
+//         Cheng Yi <yic@email.arizona.edu>
+//         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+//
+
+// Georgia Tech Network Simulator - Round Trip Time Estimation Class
+// George F. Riley.  Georgia Tech, Spring 2002
+
+
+#ifndef NDN_RTT_MEAN_DEVIATION_H
+#define NDN_RTT_MEAN_DEVIATION_H
+
+#include <ns3/ndnSIM/utils/ndn-rtt-estimator.h>
+
+namespace ns3 {
+namespace ndn {
+
+/**
+ * \ingroup ndn
+ *
+ * \brief The modified version of "Mean--Deviation" RTT estimator, as discussed by Van Jacobson that better suits NDN communication model
+ *
+ * This class implements the "Mean--Deviation" RTT estimator, as discussed
+ * by Van Jacobson and Michael J. Karels, in
+ * "Congestion Avoidance and Control", SIGCOMM 88, Appendix A
+ *
+ */
+class RttMeanDeviation : public RttEstimator {
+public:
+  static TypeId GetTypeId (void);
+
+  RttMeanDeviation ();
+  RttMeanDeviation (const RttMeanDeviation&);
+
+  void SentSeq (SequenceNumber32 seq, uint32_t size);
+  Time AckSeq (SequenceNumber32 ackSeq);
+  void Measurement (Time measure);
+  Time RetransmitTimeout ();
+  Ptr<RttEstimator> Copy () const;
+  void Reset ();
+  void Gain (double g);
+
+private:
+  double       m_gain;       // Filter gain
+  double       m_gain2;      // Filter gain
+  Time         m_variance;   // Current variance
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_RTT_MEAN_DEVIATION
diff --git a/wscript b/wscript
index ae00638..835cdaf 100644
--- a/wscript
+++ b/wscript
@@ -128,6 +128,7 @@
 
         # "utils/batches.h",
         "utils/ndn-limits.h",
+        "utils/ndn-rtt-estimator.h",
         # "utils/weights-path-stretch-tag.h",
 
         ]