limits: Introducing modularity for Interest limits

Now ndn::Limits object can be aggregated on a face/FIB entry. A
forwarding strategy module is responsible in creating an appropriate
implementation of the Interest limits module.
diff --git a/apps/ndn-app.cc b/apps/ndn-app.cc
index a46c8ba..8a4a2b8 100644
--- a/apps/ndn-app.cc
+++ b/apps/ndn-app.cc
@@ -151,8 +151,6 @@
 
   // step 2. Remove face from Ndn stack
   GetNode ()->GetObject<L3Protocol> ()->RemoveFace (m_face);
-  GetNode ()->GetObject<Fib> ()->RemoveFromAll (m_face);
-  GetNode ()->GetObject<ForwardingStrategy> ()->RemoveFace (m_face); // notify that face is removed
 
   // step 3. Destroy face
   if (m_face->GetReferenceCount () != 1)
diff --git a/bindings/modulegen__gcc_ILP32.py b/bindings/modulegen__gcc_ILP32.py
index 5ee68b3..92de4db 100644
--- a/bindings/modulegen__gcc_ILP32.py
+++ b/bindings/modulegen__gcc_ILP32.py
@@ -184,8 +184,6 @@
     module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::NameComponents', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::NameComponents>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
     ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::cs::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::cs::Entry> > [class]
     module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::cs::Entry', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::cs::Entry>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
-    ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> > [class]
-    module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::fib::Entry', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::fib::Entry>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
     ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::pit::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::pit::Entry> > [class]
     module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::pit::Entry', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::pit::Entry>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
     ## nstime.h (module 'core'): ns3::Time [class]
@@ -212,10 +210,6 @@
     module.add_class('AttributeChecker', allow_subclassing=False, automatic_type_narrowing=True, import_from_module='ns.core', parent=root_module['ns3::SimpleRefCount< ns3::AttributeChecker, ns3::empty, ns3::DefaultDeleter<ns3::AttributeChecker> >'])
     ## attribute.h (module 'core'): ns3::AttributeValue [class]
     module.add_class('AttributeValue', allow_subclassing=False, automatic_type_narrowing=True, import_from_module='ns.core', parent=root_module['ns3::SimpleRefCount< ns3::AttributeValue, ns3::empty, ns3::DefaultDeleter<ns3::AttributeValue> >'])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesChecker [class]
-    module.add_class('BatchesChecker', parent=root_module['ns3::AttributeChecker'])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue [class]
-    module.add_class('BatchesValue', parent=root_module['ns3::AttributeValue'])
     ## boolean.h (module 'core'): ns3::BooleanChecker [class]
     module.add_class('BooleanChecker', import_from_module='ns.core', parent=root_module['ns3::AttributeChecker'])
     ## boolean.h (module 'core'): ns3::BooleanValue [class]
@@ -446,7 +440,7 @@
     root_module = module.get_root()
     
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry [class]
-    module.add_class('Entry', parent=root_module['ns3::SimpleRefCount< ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >'])
+    module.add_class('Entry', parent=root_module['ns3::Object'])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::NoFaces [class]
     module.add_class('NoFaces', outer_class=root_module['ns3::ndn::fib::Entry'])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric [class]
@@ -563,7 +557,6 @@
     register_Ns3SimpleRefCount__Ns3NdnInterestHeader_Ns3Header_Ns3DefaultDeleter__lt__ns3NdnInterestHeader__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::InterestHeader, ns3::Header, ns3::DefaultDeleter<ns3::ndn::InterestHeader> >'])
     register_Ns3SimpleRefCount__Ns3NdnNameComponents_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnNameComponents__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::NameComponents, ns3::empty, ns3::DefaultDeleter<ns3::ndn::NameComponents> >'])
     register_Ns3SimpleRefCount__Ns3NdnCsEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnCsEntry__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::cs::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::cs::Entry> >'])
-    register_Ns3SimpleRefCount__Ns3NdnFibEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnFibEntry__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >'])
     register_Ns3SimpleRefCount__Ns3NdnPitEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnPitEntry__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::pit::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::pit::Entry> >'])
     register_Ns3Time_methods(root_module, root_module['ns3::Time'])
     register_Ns3TopologyReader_methods(root_module, root_module['ns3::TopologyReader'])
@@ -575,8 +568,6 @@
     register_Ns3AttributeAccessor_methods(root_module, root_module['ns3::AttributeAccessor'])
     register_Ns3AttributeChecker_methods(root_module, root_module['ns3::AttributeChecker'])
     register_Ns3AttributeValue_methods(root_module, root_module['ns3::AttributeValue'])
-    register_Ns3BatchesChecker_methods(root_module, root_module['ns3::BatchesChecker'])
-    register_Ns3BatchesValue_methods(root_module, root_module['ns3::BatchesValue'])
     register_Ns3BooleanChecker_methods(root_module, root_module['ns3::BooleanChecker'])
     register_Ns3BooleanValue_methods(root_module, root_module['ns3::BooleanValue'])
     register_Ns3CallbackChecker_methods(root_module, root_module['ns3::CallbackChecker'])
@@ -3103,18 +3094,6 @@
                    is_static=True)
     return
 
-def register_Ns3SimpleRefCount__Ns3NdnFibEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnFibEntry__gt___methods(root_module, cls):
-    ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >::SimpleRefCount() [constructor]
-    cls.add_constructor([])
-    ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >::SimpleRefCount(ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> > const & o) [copy constructor]
-    cls.add_constructor([param('ns3::SimpleRefCount< ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter< ns3::ndn::fib::Entry > > const &', 'o')])
-    ## simple-ref-count.h (module 'core'): static void ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >::Cleanup() [member function]
-    cls.add_method('Cleanup', 
-                   'void', 
-                   [], 
-                   is_static=True)
-    return
-
 def register_Ns3SimpleRefCount__Ns3NdnPitEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnPitEntry__gt___methods(root_module, cls):
     ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::pit::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::pit::Entry> >::SimpleRefCount() [constructor]
     cls.add_constructor([])
@@ -3647,46 +3626,6 @@
                    is_pure_virtual=True, is_const=True, is_virtual=True)
     return
 
-def register_Ns3BatchesChecker_methods(root_module, cls):
-    ## batches.h (module 'ndnSIM'): ns3::BatchesChecker::BatchesChecker() [constructor]
-    cls.add_constructor([])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesChecker::BatchesChecker(ns3::BatchesChecker const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::BatchesChecker const &', 'arg0')])
-    return
-
-def register_Ns3BatchesValue_methods(root_module, cls):
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue::BatchesValue() [constructor]
-    cls.add_constructor([])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue::BatchesValue(ns3::BatchesValue const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::BatchesValue const &', 'arg0')])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue::BatchesValue(ns3::Batches const & value) [constructor]
-    cls.add_constructor([param('ns3::Batches const &', 'value')])
-    ## batches.h (module 'ndnSIM'): ns3::Ptr<ns3::AttributeValue> ns3::BatchesValue::Copy() const [member function]
-    cls.add_method('Copy', 
-                   'ns3::Ptr< ns3::AttributeValue >', 
-                   [], 
-                   is_const=True, is_virtual=True)
-    ## batches.h (module 'ndnSIM'): bool ns3::BatchesValue::DeserializeFromString(std::string value, ns3::Ptr<ns3::AttributeChecker const> checker) [member function]
-    cls.add_method('DeserializeFromString', 
-                   'bool', 
-                   [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], 
-                   is_virtual=True)
-    ## batches.h (module 'ndnSIM'): ns3::Batches ns3::BatchesValue::Get() const [member function]
-    cls.add_method('Get', 
-                   'ns3::Batches', 
-                   [], 
-                   is_const=True)
-    ## batches.h (module 'ndnSIM'): std::string ns3::BatchesValue::SerializeToString(ns3::Ptr<ns3::AttributeChecker const> checker) const [member function]
-    cls.add_method('SerializeToString', 
-                   'std::string', 
-                   [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], 
-                   is_const=True, is_virtual=True)
-    ## batches.h (module 'ndnSIM'): void ns3::BatchesValue::Set(ns3::Batches const & value) [member function]
-    cls.add_method('Set', 
-                   'void', 
-                   [param('ns3::Batches const &', 'value')])
-    return
-
 def register_Ns3BooleanChecker_methods(root_module, cls):
     ## boolean.h (module 'core'): ns3::BooleanChecker::BooleanChecker() [constructor]
     cls.add_constructor([])
@@ -5323,10 +5262,6 @@
                    'uint32_t', 
                    [], 
                    is_const=True)
-    ## ndn-face.h (module 'ndnSIM'): ns3::ndn::Limits & ns3::ndn::Face::GetLimits() [member function]
-    cls.add_method('GetLimits', 
-                   'ns3::ndn::Limits &', 
-                   [])
     ## ndn-face.h (module 'ndnSIM'): uint16_t ns3::ndn::Face::GetMetric() const [member function]
     cls.add_method('GetMetric', 
                    'uint16_t', 
@@ -5516,6 +5451,11 @@
     cls.add_constructor([param('ns3::ndn::ForwardingStrategy const &', 'arg0')])
     ## ndn-forwarding-strategy.h (module 'ndnSIM'): ns3::ndn::ForwardingStrategy::ForwardingStrategy() [constructor]
     cls.add_constructor([])
+    ## ndn-forwarding-strategy.h (module 'ndnSIM'): void ns3::ndn::ForwardingStrategy::AddFace(ns3::Ptr<ns3::ndn::Face> face) [member function]
+    cls.add_method('AddFace', 
+                   'void', 
+                   [param('ns3::Ptr< ns3::ndn::Face >', 'face')], 
+                   is_virtual=True)
     ## ndn-forwarding-strategy.h (module 'ndnSIM'): static ns3::TypeId ns3::ndn::ForwardingStrategy::GetTypeId() [member function]
     cls.add_method('GetTypeId', 
                    'ns3::TypeId', 
@@ -5896,11 +5836,16 @@
     cls.add_constructor([param('ns3::ndn::Limits const &', 'arg0')])
     ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::Limits() [constructor]
     cls.add_constructor([])
+    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetCurrentLimit() const [member function]
+    cls.add_method('GetCurrentLimit', 
+                   'double', 
+                   [], 
+                   is_const=True)
     ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxLimit() const [member function]
     cls.add_method('GetMaxLimit', 
                    'double', 
                    [], 
-                   is_const=True)
+                   is_const=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): static ns3::TypeId ns3::ndn::Limits::GetTypeId() [member function]
     cls.add_method('GetTypeId', 
                    'ns3::TypeId', 
@@ -5909,30 +5854,22 @@
     ## ndn-limits.h (module 'ndnSIM'): bool ns3::ndn::Limits::IsBelowLimit() [member function]
     cls.add_method('IsBelowLimit', 
                    'bool', 
-                   [])
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): bool ns3::ndn::Limits::IsEnabled() const [member function]
     cls.add_method('IsEnabled', 
                    'bool', 
                    [], 
-                   is_const=True)
-    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::RemoveOutstanding() [member function]
-    cls.add_method('RemoveOutstanding', 
-                   'void', 
-                   [])
+                   is_const=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::SetMaxLimit(double max) [member function]
     cls.add_method('SetMaxLimit', 
                    'void', 
-                   [param('double', 'max')])
+                   [param('double', 'max')], 
+                   is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::UpdateCurrentLimit(double limit) [member function]
     cls.add_method('UpdateCurrentLimit', 
                    'void', 
                    [param('double', 'limit')])
-    ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::m_curMaxLimit [variable]
-    cls.add_instance_attribute('m_curMaxLimit', 'ns3::TracedValue< double >', is_const=False)
-    ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::m_maxLimit [variable]
-    cls.add_instance_attribute('m_maxLimit', 'double', is_const=False)
-    ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::m_outstanding [variable]
-    cls.add_instance_attribute('m_outstanding', 'ns3::TracedValue< double >', is_const=False)
     return
 
 def register_Ns3NdnNameComponents_methods(root_module, cls):
@@ -6274,10 +6211,6 @@
                    'ns3::ndn::fib::FaceMetric const &', 
                    [param('uint32_t', 'skip', default_value='0')], 
                    is_const=True)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::Limits & ns3::ndn::fib::Entry::GetLimits() [member function]
-    cls.add_method('GetLimits', 
-                   'ns3::ndn::Limits &', 
-                   [])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::NameComponents const & ns3::ndn::fib::Entry::GetPrefix() const [member function]
     cls.add_method('GetPrefix', 
                    'ns3::ndn::NameComponents const &', 
@@ -6301,8 +6234,6 @@
                    [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)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_limits [variable]
-    cls.add_instance_attribute('m_limits', 'ns3::Ptr< ns3::ndn::Limits >', 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]
@@ -6554,10 +6485,6 @@
 
 def register_functions(root_module):
     module = root_module
-    ## batches.h (module 'ndnSIM'): extern ns3::Ptr<ns3::AttributeChecker const> ns3::MakeBatchesChecker() [free function]
-    module.add_function('MakeBatchesChecker', 
-                        'ns3::Ptr< ns3::AttributeChecker const >', 
-                        [])
     register_functions_ns3_FatalImpl(module.get_submodule('FatalImpl'), root_module)
     register_functions_ns3_internal(module.get_submodule('internal'), root_module)
     register_functions_ns3_ndn(module.get_submodule('ndn'), root_module)
diff --git a/bindings/modulegen__gcc_LP64.py b/bindings/modulegen__gcc_LP64.py
index 5ee68b3..92de4db 100644
--- a/bindings/modulegen__gcc_LP64.py
+++ b/bindings/modulegen__gcc_LP64.py
@@ -184,8 +184,6 @@
     module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::NameComponents', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::NameComponents>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
     ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::cs::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::cs::Entry> > [class]
     module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::cs::Entry', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::cs::Entry>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
-    ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> > [class]
-    module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::fib::Entry', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::fib::Entry>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
     ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::pit::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::pit::Entry> > [class]
     module.add_class('SimpleRefCount', automatic_type_narrowing=True, template_parameters=['ns3::ndn::pit::Entry', 'ns3::empty', 'ns3::DefaultDeleter<ns3::ndn::pit::Entry>'], parent=root_module['ns3::empty'], memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
     ## nstime.h (module 'core'): ns3::Time [class]
@@ -212,10 +210,6 @@
     module.add_class('AttributeChecker', allow_subclassing=False, automatic_type_narrowing=True, import_from_module='ns.core', parent=root_module['ns3::SimpleRefCount< ns3::AttributeChecker, ns3::empty, ns3::DefaultDeleter<ns3::AttributeChecker> >'])
     ## attribute.h (module 'core'): ns3::AttributeValue [class]
     module.add_class('AttributeValue', allow_subclassing=False, automatic_type_narrowing=True, import_from_module='ns.core', parent=root_module['ns3::SimpleRefCount< ns3::AttributeValue, ns3::empty, ns3::DefaultDeleter<ns3::AttributeValue> >'])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesChecker [class]
-    module.add_class('BatchesChecker', parent=root_module['ns3::AttributeChecker'])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue [class]
-    module.add_class('BatchesValue', parent=root_module['ns3::AttributeValue'])
     ## boolean.h (module 'core'): ns3::BooleanChecker [class]
     module.add_class('BooleanChecker', import_from_module='ns.core', parent=root_module['ns3::AttributeChecker'])
     ## boolean.h (module 'core'): ns3::BooleanValue [class]
@@ -446,7 +440,7 @@
     root_module = module.get_root()
     
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry [class]
-    module.add_class('Entry', parent=root_module['ns3::SimpleRefCount< ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >'])
+    module.add_class('Entry', parent=root_module['ns3::Object'])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::NoFaces [class]
     module.add_class('NoFaces', outer_class=root_module['ns3::ndn::fib::Entry'])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::FaceMetric [class]
@@ -563,7 +557,6 @@
     register_Ns3SimpleRefCount__Ns3NdnInterestHeader_Ns3Header_Ns3DefaultDeleter__lt__ns3NdnInterestHeader__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::InterestHeader, ns3::Header, ns3::DefaultDeleter<ns3::ndn::InterestHeader> >'])
     register_Ns3SimpleRefCount__Ns3NdnNameComponents_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnNameComponents__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::NameComponents, ns3::empty, ns3::DefaultDeleter<ns3::ndn::NameComponents> >'])
     register_Ns3SimpleRefCount__Ns3NdnCsEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnCsEntry__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::cs::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::cs::Entry> >'])
-    register_Ns3SimpleRefCount__Ns3NdnFibEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnFibEntry__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >'])
     register_Ns3SimpleRefCount__Ns3NdnPitEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnPitEntry__gt___methods(root_module, root_module['ns3::SimpleRefCount< ns3::ndn::pit::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::pit::Entry> >'])
     register_Ns3Time_methods(root_module, root_module['ns3::Time'])
     register_Ns3TopologyReader_methods(root_module, root_module['ns3::TopologyReader'])
@@ -575,8 +568,6 @@
     register_Ns3AttributeAccessor_methods(root_module, root_module['ns3::AttributeAccessor'])
     register_Ns3AttributeChecker_methods(root_module, root_module['ns3::AttributeChecker'])
     register_Ns3AttributeValue_methods(root_module, root_module['ns3::AttributeValue'])
-    register_Ns3BatchesChecker_methods(root_module, root_module['ns3::BatchesChecker'])
-    register_Ns3BatchesValue_methods(root_module, root_module['ns3::BatchesValue'])
     register_Ns3BooleanChecker_methods(root_module, root_module['ns3::BooleanChecker'])
     register_Ns3BooleanValue_methods(root_module, root_module['ns3::BooleanValue'])
     register_Ns3CallbackChecker_methods(root_module, root_module['ns3::CallbackChecker'])
@@ -3103,18 +3094,6 @@
                    is_static=True)
     return
 
-def register_Ns3SimpleRefCount__Ns3NdnFibEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnFibEntry__gt___methods(root_module, cls):
-    ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >::SimpleRefCount() [constructor]
-    cls.add_constructor([])
-    ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >::SimpleRefCount(ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> > const & o) [copy constructor]
-    cls.add_constructor([param('ns3::SimpleRefCount< ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter< ns3::ndn::fib::Entry > > const &', 'o')])
-    ## simple-ref-count.h (module 'core'): static void ns3::SimpleRefCount<ns3::ndn::fib::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::fib::Entry> >::Cleanup() [member function]
-    cls.add_method('Cleanup', 
-                   'void', 
-                   [], 
-                   is_static=True)
-    return
-
 def register_Ns3SimpleRefCount__Ns3NdnPitEntry_Ns3Empty_Ns3DefaultDeleter__lt__ns3NdnPitEntry__gt___methods(root_module, cls):
     ## simple-ref-count.h (module 'core'): ns3::SimpleRefCount<ns3::ndn::pit::Entry, ns3::empty, ns3::DefaultDeleter<ns3::ndn::pit::Entry> >::SimpleRefCount() [constructor]
     cls.add_constructor([])
@@ -3647,46 +3626,6 @@
                    is_pure_virtual=True, is_const=True, is_virtual=True)
     return
 
-def register_Ns3BatchesChecker_methods(root_module, cls):
-    ## batches.h (module 'ndnSIM'): ns3::BatchesChecker::BatchesChecker() [constructor]
-    cls.add_constructor([])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesChecker::BatchesChecker(ns3::BatchesChecker const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::BatchesChecker const &', 'arg0')])
-    return
-
-def register_Ns3BatchesValue_methods(root_module, cls):
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue::BatchesValue() [constructor]
-    cls.add_constructor([])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue::BatchesValue(ns3::BatchesValue const & arg0) [copy constructor]
-    cls.add_constructor([param('ns3::BatchesValue const &', 'arg0')])
-    ## batches.h (module 'ndnSIM'): ns3::BatchesValue::BatchesValue(ns3::Batches const & value) [constructor]
-    cls.add_constructor([param('ns3::Batches const &', 'value')])
-    ## batches.h (module 'ndnSIM'): ns3::Ptr<ns3::AttributeValue> ns3::BatchesValue::Copy() const [member function]
-    cls.add_method('Copy', 
-                   'ns3::Ptr< ns3::AttributeValue >', 
-                   [], 
-                   is_const=True, is_virtual=True)
-    ## batches.h (module 'ndnSIM'): bool ns3::BatchesValue::DeserializeFromString(std::string value, ns3::Ptr<ns3::AttributeChecker const> checker) [member function]
-    cls.add_method('DeserializeFromString', 
-                   'bool', 
-                   [param('std::string', 'value'), param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], 
-                   is_virtual=True)
-    ## batches.h (module 'ndnSIM'): ns3::Batches ns3::BatchesValue::Get() const [member function]
-    cls.add_method('Get', 
-                   'ns3::Batches', 
-                   [], 
-                   is_const=True)
-    ## batches.h (module 'ndnSIM'): std::string ns3::BatchesValue::SerializeToString(ns3::Ptr<ns3::AttributeChecker const> checker) const [member function]
-    cls.add_method('SerializeToString', 
-                   'std::string', 
-                   [param('ns3::Ptr< ns3::AttributeChecker const >', 'checker')], 
-                   is_const=True, is_virtual=True)
-    ## batches.h (module 'ndnSIM'): void ns3::BatchesValue::Set(ns3::Batches const & value) [member function]
-    cls.add_method('Set', 
-                   'void', 
-                   [param('ns3::Batches const &', 'value')])
-    return
-
 def register_Ns3BooleanChecker_methods(root_module, cls):
     ## boolean.h (module 'core'): ns3::BooleanChecker::BooleanChecker() [constructor]
     cls.add_constructor([])
@@ -5323,10 +5262,6 @@
                    'uint32_t', 
                    [], 
                    is_const=True)
-    ## ndn-face.h (module 'ndnSIM'): ns3::ndn::Limits & ns3::ndn::Face::GetLimits() [member function]
-    cls.add_method('GetLimits', 
-                   'ns3::ndn::Limits &', 
-                   [])
     ## ndn-face.h (module 'ndnSIM'): uint16_t ns3::ndn::Face::GetMetric() const [member function]
     cls.add_method('GetMetric', 
                    'uint16_t', 
@@ -5516,6 +5451,11 @@
     cls.add_constructor([param('ns3::ndn::ForwardingStrategy const &', 'arg0')])
     ## ndn-forwarding-strategy.h (module 'ndnSIM'): ns3::ndn::ForwardingStrategy::ForwardingStrategy() [constructor]
     cls.add_constructor([])
+    ## ndn-forwarding-strategy.h (module 'ndnSIM'): void ns3::ndn::ForwardingStrategy::AddFace(ns3::Ptr<ns3::ndn::Face> face) [member function]
+    cls.add_method('AddFace', 
+                   'void', 
+                   [param('ns3::Ptr< ns3::ndn::Face >', 'face')], 
+                   is_virtual=True)
     ## ndn-forwarding-strategy.h (module 'ndnSIM'): static ns3::TypeId ns3::ndn::ForwardingStrategy::GetTypeId() [member function]
     cls.add_method('GetTypeId', 
                    'ns3::TypeId', 
@@ -5896,11 +5836,16 @@
     cls.add_constructor([param('ns3::ndn::Limits const &', 'arg0')])
     ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::Limits() [constructor]
     cls.add_constructor([])
+    ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetCurrentLimit() const [member function]
+    cls.add_method('GetCurrentLimit', 
+                   'double', 
+                   [], 
+                   is_const=True)
     ## ndn-limits.h (module 'ndnSIM'): double ns3::ndn::Limits::GetMaxLimit() const [member function]
     cls.add_method('GetMaxLimit', 
                    'double', 
                    [], 
-                   is_const=True)
+                   is_const=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): static ns3::TypeId ns3::ndn::Limits::GetTypeId() [member function]
     cls.add_method('GetTypeId', 
                    'ns3::TypeId', 
@@ -5909,30 +5854,22 @@
     ## ndn-limits.h (module 'ndnSIM'): bool ns3::ndn::Limits::IsBelowLimit() [member function]
     cls.add_method('IsBelowLimit', 
                    'bool', 
-                   [])
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): bool ns3::ndn::Limits::IsEnabled() const [member function]
     cls.add_method('IsEnabled', 
                    'bool', 
                    [], 
-                   is_const=True)
-    ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::RemoveOutstanding() [member function]
-    cls.add_method('RemoveOutstanding', 
-                   'void', 
-                   [])
+                   is_const=True, is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::SetMaxLimit(double max) [member function]
     cls.add_method('SetMaxLimit', 
                    'void', 
-                   [param('double', 'max')])
+                   [param('double', 'max')], 
+                   is_virtual=True)
     ## ndn-limits.h (module 'ndnSIM'): void ns3::ndn::Limits::UpdateCurrentLimit(double limit) [member function]
     cls.add_method('UpdateCurrentLimit', 
                    'void', 
                    [param('double', 'limit')])
-    ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::m_curMaxLimit [variable]
-    cls.add_instance_attribute('m_curMaxLimit', 'ns3::TracedValue< double >', is_const=False)
-    ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::m_maxLimit [variable]
-    cls.add_instance_attribute('m_maxLimit', 'double', is_const=False)
-    ## ndn-limits.h (module 'ndnSIM'): ns3::ndn::Limits::m_outstanding [variable]
-    cls.add_instance_attribute('m_outstanding', 'ns3::TracedValue< double >', is_const=False)
     return
 
 def register_Ns3NdnNameComponents_methods(root_module, cls):
@@ -6274,10 +6211,6 @@
                    'ns3::ndn::fib::FaceMetric const &', 
                    [param('uint32_t', 'skip', default_value='0')], 
                    is_const=True)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::Limits & ns3::ndn::fib::Entry::GetLimits() [member function]
-    cls.add_method('GetLimits', 
-                   'ns3::ndn::Limits &', 
-                   [])
     ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::NameComponents const & ns3::ndn::fib::Entry::GetPrefix() const [member function]
     cls.add_method('GetPrefix', 
                    'ns3::ndn::NameComponents const &', 
@@ -6301,8 +6234,6 @@
                    [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)
-    ## ndn-fib-entry.h (module 'ndnSIM'): ns3::ndn::fib::Entry::m_limits [variable]
-    cls.add_instance_attribute('m_limits', 'ns3::Ptr< ns3::ndn::Limits >', 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]
@@ -6554,10 +6485,6 @@
 
 def register_functions(root_module):
     module = root_module
-    ## batches.h (module 'ndnSIM'): extern ns3::Ptr<ns3::AttributeChecker const> ns3::MakeBatchesChecker() [free function]
-    module.add_function('MakeBatchesChecker', 
-                        'ns3::Ptr< ns3::AttributeChecker const >', 
-                        [])
     register_functions_ns3_FatalImpl(module.get_submodule('FatalImpl'), root_module)
     register_functions_ns3_internal(module.get_submodule('internal'), root_module)
     register_functions_ns3_ndn(module.get_submodule('ndn'), root_module)
diff --git a/helper/ndn-global-routing-helper.cc b/helper/ndn-global-routing-helper.cc
index d235185..7acf7d6 100644
--- a/helper/ndn-global-routing-helper.cc
+++ b/helper/ndn-global-routing-helper.cc
@@ -35,6 +35,7 @@
 #include "ns3/names.h"
 #include "ns3/node-list.h"
 #include "ns3/channel-list.h"
+#include "ns3/object-factory.h"
 
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
@@ -279,9 +280,17 @@
 		BOOST_FOREACH (const Ptr<const NameComponents> &prefix, i->first->GetLocalPrefixes ())
 		  {
 		    Ptr<fib::Entry> entry = fib->Add (prefix, i->second.get<0> (), i->second.get<1> ());
-                    if (i->second.get<0> ()->GetLimits ().IsEnabled ())
+                    Ptr<Limits> limits = i->second.get<0> ()->GetObject<Limits> ();
+                    
+                    if (limits != 0 && limits->IsEnabled ())
                       {
-                        entry->GetLimits ().SetMaxLimit (i->second.get<0> ()->GetLimits ().GetMaxLimit ());
+                        ObjectFactory limitsFactory;
+                        limitsFactory.SetTypeId (limits->GetInstanceTypeId ());
+
+                        Ptr<Limits> entryLimits = limitsFactory.Create<Limits> ();
+                        entryLimits->SetMaxLimit (limits->GetMaxLimit ());
+
+                        entry->AggregateObject (entryLimits);
                       }
 		  }
 		}
diff --git a/helper/ndn-stack-helper.cc b/helper/ndn-stack-helper.cc
index 72bec65..9c29bf9 100644
--- a/helper/ndn-stack-helper.cc
+++ b/helper/ndn-stack-helper.cc
@@ -254,6 +254,13 @@
       
       if (m_limitsEnabled)
         {
+          Ptr<Limits> limits = face->GetObject<Limits> ();
+          if (limits == 0)
+            {
+              NS_FATAL_ERROR ("Limits are enabled, but the selected forwarding strategy does not support limits. Please revise your scenario");
+              exit (1);
+            }
+          
           NS_LOG_INFO ("Limits are enabled");
           Ptr<PointToPointNetDevice> p2p = DynamicCast<PointToPointNetDevice> (device);
           if (p2p != 0)
@@ -272,7 +279,7 @@
               NS_LOG_INFO ("MaxLimit: " << (int)(m_avgRtt.ToDouble (Time::S) * maxInterestPackets));
 
               // Set max to BDP
-              face->GetLimits ().SetMaxLimit (m_avgRtt.ToDouble (Time::S) * maxInterestPackets);
+              limits->SetMaxLimit (m_avgRtt.ToDouble (Time::S) * maxInterestPackets);
             }
         }
         
diff --git a/model/fib/ndn-fib-entry.h b/model/fib/ndn-fib-entry.h
index c8072f4..272d801 100644
--- a/model/fib/ndn-fib-entry.h
+++ b/model/fib/ndn-fib-entry.h
@@ -165,7 +165,7 @@
  * \brief Structure for FIB table entry, holding indexed list of
  *        available faces and their respective metrics
  */
-class Entry : public SimpleRefCount<Entry>
+class Entry : public Object
 {
 public:
   class NoFaces {}; ///< @brief Exception class for the case when FIB entry is not found
@@ -178,7 +178,6 @@
   : m_prefix (prefix)
   , m_needsProbing (false)
   {
-    m_limits = CreateObject<Limits> ();
   }
   
   /**
@@ -231,15 +230,6 @@
     m_faces.erase (face);
   }
 
-  /**
-   * @brief Get reference to limits object
-   */
-  Limits &
-  GetLimits ()
-  {
-    return *m_limits;
-  }
-    
 private:
   friend std::ostream& operator<< (std::ostream& os, const Entry &entry);
 
@@ -248,8 +238,6 @@
   FaceMetricContainer::type m_faces; ///< \brief Indexed list of faces
 
   bool m_needsProbing;      ///< \brief flag indicating that probing should be performed
-
-  Ptr<Limits> m_limits;
 };
 
 std::ostream& operator<< (std::ostream& os, const Entry &entry);
diff --git a/model/fw/ndn-forwarding-strategy.cc b/model/fw/ndn-forwarding-strategy.cc
index 9fc4d29..b04d48e 100644
--- a/model/fw/ndn-forwarding-strategy.cc
+++ b/model/fw/ndn-forwarding-strategy.cc
@@ -528,6 +528,11 @@
   // do nothing for now. may be need to do some logging
 }
 
+void
+ForwardingStrategy::AddFace (Ptr<Face> face)
+{
+  // do nothing here
+}
 
 void
 ForwardingStrategy::RemoveFace (Ptr<Face> face)
diff --git a/model/fw/ndn-forwarding-strategy.h b/model/fw/ndn-forwarding-strategy.h
index 3f0a147..fbf2295 100644
--- a/model/fw/ndn-forwarding-strategy.h
+++ b/model/fw/ndn-forwarding-strategy.h
@@ -90,6 +90,13 @@
   WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry);
 
   /**
+   * @brief Event fired every time face is added to NDN stack
+   * @param face face to be removed
+   */
+  virtual void
+  AddFace (Ptr<Face> face);
+  
+  /**
    * @brief Event fired every time face is removed from NDN stack
    * @param face face to be removed
    *
diff --git a/model/fw/simple-limits.cc b/model/fw/simple-window-limits.cc
similarity index 68%
rename from model/fw/simple-limits.cc
rename to model/fw/simple-window-limits.cc
index 803d608..8939fa9 100644
--- a/model/fw/simple-limits.cc
+++ b/model/fw/simple-window-limits.cc
@@ -18,7 +18,7 @@
  * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
-#include "simple-limits.h"
+#include "simple-window-limits.h"
 
 #include "ns3/ndn-l3-protocol.h"
 #include "ns3/ndn-interest-header.h"
@@ -32,20 +32,23 @@
 namespace ndn {
 namespace fw {
 
-typedef SimpleLimits<BestRoute> SimpleLimitsBestRoute;
+template class SimpleWindowLimits<BestRoute>;
+typedef SimpleWindowLimits<BestRoute> SimpleLimitsBestRoute;
 NS_OBJECT_ENSURE_REGISTERED (SimpleLimitsBestRoute);
 
-typedef SimpleLimits<Flooding> SimpleLimitsFlooding;
+template class SimpleWindowLimits<Flooding>;
+typedef SimpleWindowLimits<Flooding> SimpleLimitsFlooding;
 NS_OBJECT_ENSURE_REGISTERED (SimpleLimitsFlooding);
 
-typedef SimpleLimits<SmartFlooding> SimpleLimitsSmartFlooding;
+template class SimpleWindowLimits<SmartFlooding>;
+typedef SimpleWindowLimits<SmartFlooding> SimpleLimitsSmartFlooding;
 NS_OBJECT_ENSURE_REGISTERED (SimpleLimitsSmartFlooding);
 
 #ifdef DOXYGEN
 
-class SimpleLimitsBestRoute : public SimpleLimits<BestRoute> { };
-class SimpleLimitsFlooding : public SimpleLimits<Flooding> { };
-class SimpleLimitsSmartFlooding : public SimpleLimits<SmartFlooding> { };
+class SimpleWindowLimitsBestRoute : public SimpleWindowLimits<BestRoute> { };
+class SimpleWindowLimitsFlooding : public SimpleWindowLimits<Flooding> { };
+class SimpleWindowLimitsSmartFlooding : public SimpleWindowLimits<SmartFlooding> { };
 
 #endif
 
diff --git a/model/fw/simple-limits.h b/model/fw/simple-window-limits.h
similarity index 71%
rename from model/fw/simple-limits.h
rename to model/fw/simple-window-limits.h
index 22a94ed..69fcd19 100644
--- a/model/fw/simple-limits.h
+++ b/model/fw/simple-window-limits.h
@@ -19,8 +19,8 @@
  */
 
 
-#ifndef NDNSIM_SIMPLE_LIMITS_H
-#define NDNSIM_SIMPLE_LIMITS_H
+#ifndef NDNSIM_SIMPLE_WINDOW_LIMITS_H
+#define NDNSIM_SIMPLE_WINDOW_LIMITS_H
 
 #include "ns3/event-id.h"
 #include "ns3/ndn-pit.h"
@@ -29,6 +29,9 @@
 
 #include "ns3/ndn-forwarding-strategy.h"
 
+#include "../../utils/ndn-limits-window.h"
+
+
 namespace ns3 {
 namespace ndn {
 namespace fw {
@@ -38,7 +41,7 @@
  * \brief Strategy implementing per-FIB entry limits
  */
 template<class Parent>
-class SimpleLimits :
+class SimpleWindowLimits :
     public Parent
 {
 private:
@@ -51,13 +54,21 @@
   /**
    * @brief Default constructor
    */
-  SimpleLimits ()
-  {
-  }
+  SimpleWindowLimits ()
+  { }
   
   virtual void
   WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry);
 
+  virtual void
+  AddFace (Ptr<Face> face)
+  {
+    Ptr<Limits> limits = CreateObject<LimitsWindow> ();
+    face->AggregateObject (limits);
+
+    super::AddFace (face);
+  }
+  
 protected:
   virtual bool
   TrySendOutInterest (Ptr<Face> inFace,
@@ -74,23 +85,23 @@
 
 template<class Parent>
 TypeId
-SimpleLimits<Parent>::GetTypeId (void)
+SimpleWindowLimits<Parent>::GetTypeId (void)
 {
-  static TypeId tid = TypeId ((super::GetTypeId ().GetName ()+"::SimpleLimits").c_str ())
+  static TypeId tid = TypeId ((super::GetTypeId ().GetName ()+"::SimpleWindowLimits").c_str ())
     .SetGroupName ("Ndn")
     .template SetParent <super> ()
-    .template AddConstructor <SimpleLimits> ()
+    .template AddConstructor <SimpleWindowLimits> ()
     ;
   return tid;
 }
 
 template<class Parent>
 bool
-SimpleLimits<Parent>::TrySendOutInterest (Ptr<Face> inFace,
-                                          Ptr<Face> outFace,
-                                          Ptr<const InterestHeader> header,
-                                          Ptr<const Packet> origPacket,
-                                          Ptr<pit::Entry> pitEntry)
+SimpleWindowLimits<Parent>::TrySendOutInterest (Ptr<Face> inFace,
+                                                Ptr<Face> outFace,
+                                                Ptr<const InterestHeader> header,
+                                                Ptr<const Packet> origPacket,
+                                                Ptr<pit::Entry> pitEntry)
 {
   // NS_LOG_FUNCTION (this << pitEntry->GetPrefix ());
   // totally override all (if any) parent processing
@@ -104,7 +115,7 @@
       return false;
     }
 
-  if (outFace->GetLimits ().IsBelowLimit ())
+  if (outFace->template GetObject<LimitsWindow> ()->IsBelowLimit ())
     {
       pitEntry->AddOutgoing (outFace);
 
@@ -125,7 +136,7 @@
 
 template<class Parent>
 void
-SimpleLimits<Parent>::WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry)
+SimpleWindowLimits<Parent>::WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry)
 {
   // NS_LOG_FUNCTION (this << pitEntry->GetPrefix ());
 
@@ -133,7 +144,7 @@
        face != pitEntry->GetOutgoing ().end ();
        face ++)
     {
-      face->m_face->GetLimits ().RemoveOutstanding ();
+      face->m_face->GetObject<LimitsWindow> ()->RemoveOutstanding ();
     }
 
   super::WillEraseTimedOutPendingInterest (pitEntry);
@@ -142,8 +153,8 @@
 
 template<class Parent>
 void
-SimpleLimits<Parent>::WillSatisfyPendingInterest (Ptr<Face> inFace,
-                                                  Ptr<pit::Entry> pitEntry)
+SimpleWindowLimits<Parent>::WillSatisfyPendingInterest (Ptr<Face> inFace,
+                                                        Ptr<pit::Entry> pitEntry)
 {
   // NS_LOG_FUNCTION (this << pitEntry->GetPrefix ());
 
@@ -151,7 +162,7 @@
        face != pitEntry->GetOutgoing ().end ();
        face ++)
     {
-      face->m_face->GetLimits ().RemoveOutstanding ();
+      face->m_face->GetObject<LimitsWindow> ()->RemoveOutstanding ();
     }
   
   super::WillSatisfyPendingInterest (inFace, pitEntry);
@@ -161,4 +172,4 @@
 } // namespace ndn
 } // namespace ns3
 
-#endif // NDNSIM_SIMPLE_LIMITS_H
+#endif // NDNSIM_SIMPLE_WINDOW_LIMITS_H
diff --git a/model/ndn-face.cc b/model/ndn-face.cc
index d709cfc..f91fc19 100644
--- a/model/ndn-face.cc
+++ b/model/ndn-face.cc
@@ -55,12 +55,6 @@
                    MakeUintegerAccessor (&Face::m_id),
                    MakeUintegerChecker<uint32_t> ())
 
-    .AddAttribute ("Limits", "Limits object",
-                   TypeId::ATTR_GET, // allow only getting it.
-                   PointerValue (0), // this is not really used, but needed for the compiler... so sad
-                   MakePointerAccessor (&Face::m_limits),
-                   MakePointerChecker<Limits> ())
-
     // .AddAttribute ("MetricTagging", "Enable metric tagging (path-stretch calculation)",
     //                BooleanValue (false),
     //                MakeBooleanAccessor (&Face::m_enableMetricTagging),
@@ -87,7 +81,6 @@
   , m_ifup (false)
   , m_id ((uint32_t)-1)
   , m_metric (0)
-  , m_limits (CreateObject<Limits> ())
   // , m_enableMetricTagging (false)
 {
   NS_LOG_FUNCTION (this);
diff --git a/model/ndn-face.h b/model/ndn-face.h
index 7741c1e..78c65a7 100644
--- a/model/ndn-face.h
+++ b/model/ndn-face.h
@@ -90,12 +90,6 @@
   RegisterProtocolHandler (ProtocolHandler handler);
 
   /**
-   * @brief Get reference to Limits object
-   */
-  inline Limits&
-  GetLimits ();    
-  
-  /**
    * \brief Send packet on a face
    *
    * This method will be called by lower layers to send data to device or application
@@ -221,7 +215,6 @@
   uint32_t m_id; ///< \brief id of the interface in Ndn stack (per-node uniqueness)
   uint32_t m_metric; ///< \brief metric of the face
 
-  Ptr<Limits> m_limits;
   // bool m_enableMetricTagging;
 
   TracedCallback<Ptr<const Packet> > m_txTrace;
@@ -255,13 +248,6 @@
   return !(*this == face);
 }
 
-inline Limits&
-Face::GetLimits ()
-{
-  return *m_limits;
-}
-
-
 } // namespace ndn
 } // namespace ns3
 
diff --git a/model/ndn-l3-protocol.cc b/model/ndn-l3-protocol.cc
index 372df77..850f84f 100644
--- a/model/ndn-l3-protocol.cc
+++ b/model/ndn-l3-protocol.cc
@@ -164,6 +164,8 @@
 
   m_faces.push_back (face);
   m_faceCounter++;
+
+  m_forwardingStrategy->AddFace (face); // notify that face is added    
   return face->GetId ();
 }
 
@@ -196,6 +198,9 @@
   FaceList::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);
+
+  GetObject<Fib> ()->RemoveFromAll (face);
+  m_forwardingStrategy->RemoveFace (face); // notify that face is removed  
 }
 
 Ptr<Face>
diff --git a/utils/ndn-limits-window.cc b/utils/ndn-limits-window.cc
new file mode 100644
index 0000000..6f371b4
--- /dev/null
+++ b/utils/ndn-limits-window.cc
@@ -0,0 +1,83 @@
+/* -*- 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 "ndn-limits-window.h"
+
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/random-variable.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.Limits.Window");
+
+namespace ns3 {
+namespace ndn {
+
+NS_OBJECT_ENSURE_REGISTERED (Limits);
+
+TypeId
+LimitsWindow::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::ndn::Limits::Window")
+    .SetGroupName ("Ndn")
+    .SetParent <Limits> () 
+    .AddConstructor <LimitsWindow> ()
+    
+    .AddTraceSource ("Outstanding",
+                     "Number of outstanding interests",
+                     MakeTraceSourceAccessor (&LimitsWindow::m_outstanding))
+    ;
+  return tid;
+}
+
+bool
+LimitsWindow::IsBelowLimit ()
+{
+  if (!IsEnabled ()) return true;
+
+  if (m_curMaxLimit - m_outstanding >= 1.0)
+    {
+      // static UniformVariable acceptanceProbability (0, m_curMaxLimit);
+      // double value = acceptanceProbability.GetValue ();
+      double value = m_outstanding + 1;
+      
+      if (m_outstanding < value)
+        {
+          m_outstanding += 1.0;
+          return true;
+        }
+      else
+        return false;
+    }
+  else
+    return false;
+}
+
+void
+LimitsWindow::RemoveOutstanding ()
+{
+  if (!IsEnabled ()) return; 
+
+  NS_LOG_DEBUG (m_outstanding);
+  NS_ASSERT_MSG (m_outstanding >= (uint32_t)1, "Should not be possible, unless we decreasing this number twice somewhere");
+  m_outstanding -= 1;
+}
+
+} // namespace ndn
+} // namespace ns3
diff --git a/utils/ndn-limits-window.h b/utils/ndn-limits-window.h
new file mode 100644
index 0000000..b1f2208
--- /dev/null
+++ b/utils/ndn-limits-window.h
@@ -0,0 +1,84 @@
+/* -*- 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 _NDN_LIMITS_WINDOW_H_
+#define	_NDN_LIMITS_WINDOW_H_
+
+#include "ndn-limits.h"
+
+namespace ns3 {
+namespace ndn {
+
+/**
+ * \ingroup ndn
+ * \brief Structure to manage limits for outstanding interests
+ */
+class LimitsWindow :
+    public Limits
+{
+public:
+  typedef Limits super;
+  
+  static TypeId
+  GetTypeId ();
+  
+  /**
+   * \brief Constructor
+   * \param prefix smart pointer to the prefix for the FIB entry
+   */
+  LimitsWindow ()
+  : m_outstanding (0)
+  { }
+
+  virtual
+  ~LimitsWindow () { }
+
+
+  // from limits
+  virtual bool
+  IsBelowLimit ();
+
+  ////////////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////////////
+
+  // specific to window-based limits
+  
+  /**
+   * @brief Remove outstanding interests
+   */
+  void
+  RemoveOutstanding ();
+
+  double
+  GetOutstanding () const
+  {
+    return m_outstanding;
+  }
+  
+protected:
+  TracedValue< double > m_outstanding;
+};
+  
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // _NDN_LIMITS_WINDOW_H_
diff --git a/utils/ndn-limits.cc b/utils/ndn-limits.cc
index 2e4a9ec..4e5f48f 100644
--- a/utils/ndn-limits.cc
+++ b/utils/ndn-limits.cc
@@ -29,41 +29,22 @@
 namespace ns3 {
 namespace ndn {
 
-NS_OBJECT_ENSURE_REGISTERED (Limits);
-
 TypeId
 Limits::GetTypeId ()
 {
   static TypeId tid = TypeId ("ns3::ndn::Limits")
     .SetGroupName ("Ndn")
     .SetParent <Object> ()
-    .AddConstructor <Limits> ()
     
     .AddTraceSource ("CurMaxLimit",
                      "Current maximum limit",
                      MakeTraceSourceAccessor (&Limits::m_curMaxLimit))
                      
-    .AddTraceSource ("Outstanding",
-                     "Number of outstanding interests",
-                     MakeTraceSourceAccessor (&Limits::m_outstanding))
     ;
   return tid;
 }
 
 void
-Limits::SetMaxLimit (double max)
-{
-  m_maxLimit = max;
-  m_curMaxLimit = max;
-}
-
-double
-Limits::GetMaxLimit () const
-{
-  return m_maxLimit;
-}
-
-void
 Limits::UpdateCurrentLimit (double limit)
 {
   NS_ASSERT_MSG (limit >= 0.0, "Limit should be greater or equal to zero");
@@ -71,38 +52,5 @@
   m_curMaxLimit = std::min (limit, m_maxLimit);
 }
 
-bool
-Limits::IsBelowLimit ()
-{
-  if (!IsEnabled ()) return true;
-
-  if (m_curMaxLimit - m_outstanding >= 1.0)
-    {
-      // static UniformVariable acceptanceProbability (0, m_curMaxLimit);
-      // double value = acceptanceProbability.GetValue ();
-      double value = m_outstanding + 1;
-      
-      if (m_outstanding < value)
-        {
-          m_outstanding += 1.0;
-          return true;
-        }
-      else
-        return false;
-    }
-  else
-    return false;
-}
-
-void
-Limits::RemoveOutstanding ()
-{
-  if (!IsEnabled ()) return; 
-
-  NS_LOG_DEBUG (m_outstanding);
-  NS_ASSERT_MSG (m_outstanding >= (uint32_t)1, "Should not be possible, unless we decreasing this number twice somewhere");
-  m_outstanding -= 1;
-}
-
 } // namespace ndn
 } // namespace ns3
diff --git a/utils/ndn-limits.h b/utils/ndn-limits.h
index 181059a..14aec50 100644
--- a/utils/ndn-limits.h
+++ b/utils/ndn-limits.h
@@ -23,7 +23,6 @@
 
 #include "ns3/ptr.h"
 #include "ns3/object.h"
-#include "ns3/nstime.h"
 #include "ns3/traced-value.h"
 
 namespace ns3 {
@@ -39,33 +38,38 @@
 public:
   static TypeId
   GetTypeId ();
-  
-  /**
-   * \brief Constructor
-   * \param prefix smart pointer to the prefix for the FIB entry
-   */
+
   Limits ()
   : m_maxLimit (-1)
   , m_curMaxLimit (0)
-  , m_outstanding (0)
   { }
- 
+
+  virtual
+  ~Limits () {}
+  
   /**
    * @brief Set limit for the number of outstanding interests
    */
-  void
-  SetMaxLimit (double max);
+  virtual void
+  SetMaxLimit (double max)
+  {
+    m_maxLimit = max;
+    m_curMaxLimit = max;
+  }    
 
   /**
    * @brief Get limit for the number of outstanding interests
    */
-  double
-  GetMaxLimit () const;
+  virtual double
+  GetMaxLimit () const
+  {
+    return m_maxLimit;
+  }
 
   /**
    * @brief Check whether limits are enabled or not
    */
-  inline bool
+  virtual inline bool
   IsEnabled () const
   {
     return m_maxLimit > 0.0;
@@ -85,7 +89,7 @@
   {
     return m_curMaxLimit;
   }
-
+  
   ////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////
   ////////////////////////////////////////////////////////////////////////////
@@ -93,20 +97,12 @@
   /**
    * @brief Check if new interest can be send out, if yes, number of outstanding will be increased
    */
-  bool
-  IsBelowLimit ();
-
-  /**
-   * @brief Remove outstanding interests
-   */
-  void
-  RemoveOutstanding ();
+  virtual bool
+  IsBelowLimit () = 0;
   
-public:
+protected:
   double m_maxLimit;
-  
   TracedValue< double > m_curMaxLimit;
-  TracedValue< double > m_outstanding;
 };
   
 
diff --git a/wscript b/wscript
index 9b7b52d..8712817 100644
--- a/wscript
+++ b/wscript
@@ -94,7 +94,7 @@
         "model/fw/ndn-forwarding-strategy.h",
         "model/fw/ndn-fw-tag.h",
 
-        "utils/batches.h",
+        # "utils/batches.h",
         "utils/ndn-limits.h",
         # "utils/weights-path-stretch-tag.h",