model+helper: Converting L3Protocol and StackHelper to use NFD codebase
diff --git a/helper/ndn-face-container.cpp b/helper/ndn-face-container.cpp
index bd03ed0..3be59f8 100644
--- a/helper/ndn-face-container.cpp
+++ b/helper/ndn-face-container.cpp
@@ -22,8 +22,6 @@
 
 #include <algorithm>
 
-#include "ns3/ndn-face.hpp"
-
 namespace ns3 {
 namespace ndn {
 
diff --git a/helper/ndn-face-container.hpp b/helper/ndn-face-container.hpp
index fc90ad6..2da10de 100644
--- a/helper/ndn-face-container.hpp
+++ b/helper/ndn-face-container.hpp
@@ -28,7 +28,7 @@
 
 #include "ns3/ptr.h"
 #include "ns3/simple-ref-count.h"
-#include "ns3/ndn-face.hpp"
+#include "ns3/ndnSIM/model/ndn-face.hpp"
 
 namespace ns3 {
 namespace ndn {
diff --git a/helper/ndn-stack-helper.cpp b/helper/ndn-stack-helper.cpp
index 5d3dcd2..a1a3292 100644
--- a/helper/ndn-stack-helper.cpp
+++ b/helper/ndn-stack-helper.cpp
@@ -19,37 +19,19 @@
  *          Ilya Moiseenko <iliamo@cs.ucla.edu>
  */
 
-#include "ns3/assert.h"
-#include "ns3/log.h"
-#include "ns3/object.h"
-#include "ns3/names.h"
-#include "ns3/packet-socket-factory.h"
-#include "ns3/config.h"
-#include "ns3/simulator.h"
-#include "ns3/string.h"
-#include "ns3/net-device.h"
-#include "ns3/channel.h"
-#include "ns3/callback.h"
-#include "ns3/node.h"
-#include "ns3/core-config.h"
-#include "ns3/point-to-point-net-device.h"
-#include "ns3/point-to-point-helper.h"
-#include "ns3/callback.h"
-
-#include "../model/ndn-net-device-face.hpp"
-#include "../model/ndn-l3-protocol.hpp"
-
-#include "ns3/node-list.h"
-
-#include "ns3/data-rate.h"
-
-#include "ndn-face-container.hpp"
 #include "ndn-stack-helper.hpp"
+
+#include "ns3/log.h"
+#include "ns3/names.h"
+#include "ns3/point-to-point-net-device.h"
+
+#include "model/ndn-l3-protocol.hpp"
+#include "model/ndn-net-device-face.hpp"
+#include "utils/ndn-time.hpp"
 #include "utils/dummy-keychain.hpp"
 
 #include <limits>
 #include <map>
-#include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
 
 NS_LOG_COMPONENT_DEFINE("ndn.StackHelper");
@@ -58,16 +40,11 @@
 namespace ndn {
 
 StackHelper::StackHelper()
-  : m_limitsEnabled(false)
-  , m_needSetDefaultRoutes(false)
 {
   setCustomNdnCxxClocks();
 
   m_ndnFactory.SetTypeId("ns3::ndn::L3Protocol");
-  m_strategyFactory.SetTypeId("ns3::ndn::fw::Flooding");
-  m_contentStoreFactory.SetTypeId("ns3::ndn::cs::Lru");
-  m_fibFactory.SetTypeId("ns3::ndn::fib::Default");
-  m_pitFactory.SetTypeId("ns3::ndn::pit::Persistent");
+  // m_contentStoreFactory.SetTypeId("ns3::ndn::cs::Lru");
 
   m_netDeviceCallbacks.push_back(
     std::make_pair(PointToPointNetDevice::GetTypeId(),
@@ -93,110 +70,6 @@
                                make_shared<ns3::ndn::time::CustomSystemClock>());
 }
 
-void
-StackHelper::SetStackAttributes(const std::string& attr1, const std::string& value1,
-                                const std::string& attr2, const std::string& value2,
-                                const std::string& attr3, const std::string& value3,
-                                const std::string& attr4, const std::string& value4)
-{
-  if (attr1 != "")
-    m_ndnFactory.Set(attr1, StringValue(value1));
-  if (attr2 != "")
-    m_ndnFactory.Set(attr2, StringValue(value2));
-  if (attr3 != "")
-    m_ndnFactory.Set(attr3, StringValue(value3));
-  if (attr4 != "")
-    m_ndnFactory.Set(attr4, StringValue(value4));
-}
-
-void
-StackHelper::SetForwardingStrategy(const std::string& strategy, const std::string& attr1,
-                                   const std::string& value1, const std::string& attr2,
-                                   const std::string& value2, const std::string& attr3,
-                                   const std::string& value3, const std::string& attr4,
-                                   const std::string& value4)
-{
-  m_strategyFactory.SetTypeId(strategy);
-  if (attr1 != "")
-    m_strategyFactory.Set(attr1, StringValue(value1));
-  if (attr2 != "")
-    m_strategyFactory.Set(attr2, StringValue(value2));
-  if (attr3 != "")
-    m_strategyFactory.Set(attr3, StringValue(value3));
-  if (attr4 != "")
-    m_strategyFactory.Set(attr4, StringValue(value4));
-}
-
-void
-StackHelper::SetContentStore(const std::string& contentStore, const std::string& attr1,
-                             const std::string& value1, const std::string& attr2,
-                             const std::string& value2, const std::string& attr3,
-                             const std::string& value3, const std::string& attr4,
-                             const std::string& value4)
-{
-  m_contentStoreFactory.SetTypeId(contentStore);
-  if (attr1 != "")
-    m_contentStoreFactory.Set(attr1, StringValue(value1));
-  if (attr2 != "")
-    m_contentStoreFactory.Set(attr2, StringValue(value2));
-  if (attr3 != "")
-    m_contentStoreFactory.Set(attr3, StringValue(value3));
-  if (attr4 != "")
-    m_contentStoreFactory.Set(attr4, StringValue(value4));
-}
-
-void
-StackHelper::SetPit(const std::string& pitClass, const std::string& attr1,
-                    const std::string& value1, const std::string& attr2, const std::string& value2,
-                    const std::string& attr3, const std::string& value3, const std::string& attr4,
-                    const std::string& value4)
-{
-  m_pitFactory.SetTypeId(pitClass);
-  if (attr1 != "")
-    m_pitFactory.Set(attr1, StringValue(value1));
-  if (attr2 != "")
-    m_pitFactory.Set(attr2, StringValue(value2));
-  if (attr3 != "")
-    m_pitFactory.Set(attr3, StringValue(value3));
-  if (attr4 != "")
-    m_pitFactory.Set(attr4, StringValue(value4));
-}
-
-void
-StackHelper::SetFib(const std::string& fibClass, const std::string& attr1,
-                    const std::string& value1, const std::string& attr2, const std::string& value2,
-                    const std::string& attr3, const std::string& value3, const std::string& attr4,
-                    const std::string& value4)
-{
-  m_fibFactory.SetTypeId(fibClass);
-  if (attr1 != "")
-    m_fibFactory.Set(attr1, StringValue(value1));
-  if (attr2 != "")
-    m_fibFactory.Set(attr2, StringValue(value2));
-  if (attr3 != "")
-    m_fibFactory.Set(attr3, StringValue(value3));
-  if (attr4 != "")
-    m_fibFactory.Set(attr4, StringValue(value4));
-}
-
-void
-StackHelper::SetDefaultRoutes(bool needSet)
-{
-  NS_LOG_FUNCTION(this << needSet);
-  m_needSetDefaultRoutes = needSet;
-}
-
-void
-StackHelper::EnableLimits(bool enable /* = true*/, Time avgRtt /*=Seconds(0.1)*/,
-                          uint32_t avgData /*=1100*/, uint32_t avgInterest /*=40*/)
-{
-  NS_LOG_INFO("EnableLimits: " << enable);
-  m_limitsEnabled = enable;
-  m_avgRtt = avgRtt;
-  m_avgDataSize = avgData;
-  m_avgInterestSize = avgInterest;
-}
-
 Ptr<FaceContainer>
 StackHelper::Install(const NodeContainer& c) const
 {
@@ -216,8 +89,6 @@
 Ptr<FaceContainer>
 StackHelper::Install(Ptr<Node> node) const
 {
-  // NS_ASSERT_MSG (m_forwarding, "SetForwardingHelper() should be set prior calling Install()
-  // method");
   Ptr<FaceContainer> faces = Create<FaceContainer>();
 
   if (node->GetObject<L3Protocol>() != 0) {
@@ -226,25 +97,13 @@
     return 0;
   }
 
-  // Create L3Protocol
   Ptr<L3Protocol> ndn = m_ndnFactory.Create<L3Protocol>();
-
-  // Create and aggregate FIB
-  // Ptr<Fib> fib = m_fibFactory.Create<Fib> ();
-  // ndn->AggregateObject (fib);
-
-  // Create and aggregate PIT
-  // ndn->AggregateObject (m_pitFactory.Create<Pit> ());
-
-  // Create and aggregate forwarding strategy
-  // ndn->AggregateObject (m_strategyFactory.Create<ForwardingStrategy> ());
-
-  // Create and aggregate content store
-  // ndn->AggregateObject (m_contentStoreFactory.Create<ContentStore> ());
-
   // Aggregate L3Protocol on node
   node->AggregateObject(ndn);
 
+  // NFD initialization
+  ndn->initialize();
+
   for (uint32_t index = 0; index < node->GetNDevices(); index++) {
     Ptr<NetDevice> device = node->GetDevice(index);
     // This check does not make sense: LoopbackNetDevice is installed only if IP stack is installed,
@@ -254,26 +113,19 @@
 
     shared_ptr<NetDeviceFace> face;
 
-    for (std::list<std::pair<TypeId, NetDeviceFaceCreateCallback>>::const_iterator item =
-           m_netDeviceCallbacks.begin();
-         item != m_netDeviceCallbacks.end(); item++) {
-      if (device->GetInstanceTypeId() == item->first
-          || device->GetInstanceTypeId().IsChildOf(item->first)) {
-        face = item->second(node, ndn, device);
+    for (const auto& item : m_netDeviceCallbacks) {
+      if (device->GetInstanceTypeId() == item.first ||
+          device->GetInstanceTypeId().IsChildOf(item.first)) {
+        face = item.second(node, ndn, device);
         if (face != 0)
           break;
       }
     }
+
     if (face == 0) {
       face = DefaultNetDeviceCallback(node, ndn, device);
     }
 
-    if (m_needSetDefaultRoutes) {
-      // default route with lowest priority possible
-      AddRoute(node, "/", StaticCast<Face>(face), std::numeric_limits<int32_t>::max());
-    }
-
-    face->SetUp();
     faces->Add(face);
   }
 
@@ -291,10 +143,9 @@
 StackHelper::UpdateNetDeviceFaceCreateCallback(TypeId netDeviceType,
                                                NetDeviceFaceCreateCallback callback)
 {
-  for (NetDeviceCallbackList::iterator i = m_netDeviceCallbacks.begin();
-       i != m_netDeviceCallbacks.end(); i++) {
-    if (i->first == netDeviceType) {
-      i->second = callback;
+  for (auto& i : m_netDeviceCallbacks) {
+    if (i.first == netDeviceType) {
+      i.second = callback;
       return;
     }
   }
@@ -304,13 +155,9 @@
 StackHelper::RemoveNetDeviceFaceCreateCallback(TypeId netDeviceType,
                                                NetDeviceFaceCreateCallback callback)
 {
-  for (NetDeviceCallbackList::iterator i = m_netDeviceCallbacks.begin();
-       i != m_netDeviceCallbacks.end(); i++) {
-    if (i->first == netDeviceType) {
-      m_netDeviceCallbacks.erase(i);
-      return;
-    }
-  }
+  m_netDeviceCallbacks.remove_if([&] (const std::pair<TypeId, NetDeviceFaceCreateCallback>& i) {
+      return (i.first == netDeviceType);
+    });
 }
 
 shared_ptr<NetDeviceFace>
@@ -319,10 +166,11 @@
 {
   NS_LOG_DEBUG("Creating default NetDeviceFace on node " << node->GetId());
 
-  shared_ptr<NetDeviceFace> face = CreateObject<NetDeviceFace>(node, netDevice);
+  shared_ptr<NetDeviceFace> face = std::make_shared<NetDeviceFace>(node, netDevice);
 
-  ndn->AddFace(face);
-  NS_LOG_LOGIC("Node " << node->GetId() << ": added NetDeviceFace as face #" << *face);
+  ndn->addFace(face);
+  NS_LOG_LOGIC("Node " << node->GetId() << ": added NetDeviceFace as face #"
+                       << face->getLocalUri());
 
   return face;
 }
@@ -333,46 +181,11 @@
 {
   NS_LOG_DEBUG("Creating point-to-point NetDeviceFace on node " << node->GetId());
 
-  shared_ptr<NetDeviceFace> face = CreateObject<NetDeviceFace>(node, device);
+  shared_ptr<NetDeviceFace> face = std::make_shared<NetDeviceFace>(node, device);
 
-  ndn->AddFace(face);
-  NS_LOG_LOGIC("Node " << node->GetId() << ": added NetDeviceFace as face #" << *face);
-
-  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) {
-      // Setup bucket filtering
-      // Assume that we know average data packet size, and this size is equal default size
-      // Set maximum buckets (averaging over 1 second)
-
-      DataRateValue dataRate;
-      device->GetAttribute("DataRate", dataRate);
-      TimeValue linkDelay;
-      device->GetChannel()->GetAttribute("Delay", linkDelay);
-
-      NS_LOG_INFO("DataRate for this link is " << dataRate.Get());
-
-      double maxInterestPackets =
-        1.0 * dataRate.Get().GetBitRate() / 8.0 / (m_avgDataSize + m_avgInterestSize);
-      // NS_LOG_INFO ("Max packets per second: " << maxInterestPackets);
-      // NS_LOG_INFO ("Max burst: " << m_avgRtt.ToDouble (Time::S) * maxInterestPackets);
-      //         NS_LOG_INFO ("MaxLimit: " << (int)(m_avgRtt.ToDouble (Time::S) *
-      //         maxInterestPackets));
-      /*
-      // Set max to BDP
-      limits->SetLimits (maxInterestPackets, m_avgRtt.ToDouble (Time::S));
-      limits->SetLinkDelay (linkDelay.Get ().ToDouble (Time::S)); */
-    }
-  }
+  ndn->addFace(face);
+  NS_LOG_LOGIC("Node " << node->GetId() << ": added NetDeviceFace as face #"
+                       << face->getLocalUri());
 
   return face;
 }
@@ -384,94 +197,5 @@
   return Install(node);
 }
 
-void
-StackHelper::AddRoute(Ptr<Node> node, const std::string& prefix, shared_ptr<Face> face, int32_t metric)
-{
-  NS_LOG_LOGIC("[" << node->GetId() << "]$ route add " << prefix << " via " << *face << " metric "
-                   << metric);
-
-  // Ptr<Fib>  fib  = node->GetObject<Fib> ();
-
-  // NameValue prefixValue;
-  // prefixValue.DeserializeFromString (prefix, MakeNameChecker ());
-  ::ndn::Name name(prefix);
-  // fib->Add (name, face, metric);
-}
-
-void
-StackHelper::AddRoute(Ptr<Node> node, const std::string& prefix, uint32_t faceId, int32_t metric)
-{
-  Ptr<L3Protocol> ndn = node->GetObject<L3Protocol>();
-  NS_ASSERT_MSG(ndn != 0, "Ndn stack should be installed on the node");
-
-  shared_ptr<Face> face = ndn->GetFace(faceId);
-  NS_ASSERT_MSG(face != 0, "Face with ID [" << faceId << "] does not exist on node ["
-                                            << node->GetId() << "]");
-
-  AddRoute(node, prefix, face, metric);
-}
-
-void
-StackHelper::AddRoute(const std::string& nodeName, const std::string& prefix, uint32_t faceId,
-                      int32_t metric)
-{
-  Ptr<Node> node = Names::Find<Node>(nodeName);
-  NS_ASSERT_MSG(node != 0, "Node [" << nodeName << "] does not exist");
-
-  Ptr<L3Protocol> ndn = node->GetObject<L3Protocol>();
-  NS_ASSERT_MSG(ndn != 0, "Ndn stack should be installed on the node");
-
-  shared_ptr<Face> face = ndn->GetFace(faceId);
-  NS_ASSERT_MSG(face != 0, "Face with ID [" << faceId << "] does not exist on node [" << nodeName
-                                            << "]");
-
-  AddRoute(node, prefix, face, metric);
-}
-
-void
-StackHelper::AddRoute(Ptr<Node> node, const std::string& prefix, Ptr<Node> otherNode,
-                      int32_t metric)
-{
-  for (uint32_t deviceId = 0; deviceId < node->GetNDevices(); deviceId++) {
-    Ptr<PointToPointNetDevice> netDevice =
-      DynamicCast<PointToPointNetDevice>(node->GetDevice(deviceId));
-    if (netDevice == 0)
-      continue;
-
-    Ptr<Channel> channel = netDevice->GetChannel();
-    if (channel == 0)
-      continue;
-
-    if (channel->GetDevice(0)->GetNode() == otherNode
-        || channel->GetDevice(1)->GetNode() == otherNode) {
-      Ptr<L3Protocol> ndn = node->GetObject<L3Protocol>();
-      NS_ASSERT_MSG(ndn != 0, "Ndn stack should be installed on the node");
-
-      shared_ptr<Face> face = ndn->GetFaceByNetDevice(netDevice);
-      NS_ASSERT_MSG(face != 0, "There is no face associated with the p2p link");
-
-      AddRoute(node, prefix, face, metric);
-
-      return;
-    }
-  }
-
-  NS_FATAL_ERROR("Cannot add route: Node# " << node->GetId() << " and Node# " << otherNode->GetId()
-                                            << " are not connected");
-}
-
-void
-StackHelper::AddRoute(const std::string& nodeName, const std::string& prefix,
-                      const std::string& otherNodeName, int32_t metric)
-{
-  Ptr<Node> node = Names::Find<Node>(nodeName);
-  NS_ASSERT_MSG(node != 0, "Node [" << nodeName << "] does not exist");
-
-  Ptr<Node> otherNode = Names::Find<Node>(otherNodeName);
-  NS_ASSERT_MSG(otherNode != 0, "Node [" << otherNodeName << "] does not exist");
-
-  AddRoute(node, prefix, otherNode, metric);
-}
-
 } // namespace ndn
 } // namespace ns3
diff --git a/helper/ndn-stack-helper.hpp b/helper/ndn-stack-helper.hpp
index b6b4266..2f3ea3b 100644
--- a/helper/ndn-stack-helper.hpp
+++ b/helper/ndn-stack-helper.hpp
@@ -24,10 +24,12 @@
 
 #include "ns3/ndnSIM/model/ndn-common.hpp"
 
-#include "ns3/packet.h"
 #include "ns3/ptr.h"
 #include "ns3/object-factory.h"
-#include "ns3/nstime.h"
+#include "ns3/node.h"
+#include "ns3/node-container.h"
+
+#include "ndn-face-container.hpp"
 
 namespace ns3 {
 
@@ -35,8 +37,6 @@
 
 namespace ndn {
 
-class FaceContainer;
-class Face;
 class NetDeviceFace;
 class L3Protocol;
 
@@ -82,52 +82,6 @@
                      const std::string& attr3 = "", const std::string& value3 = "",
                      const std::string& attr4 = "", const std::string& value4 = "");
 
-  /**
-   * @brief Set forwarding strategy class and its attributes
-   * @param forwardingStrategyClass string containing name of the forwarding strategy class
-   *
-   * Valid options are "ns3::NdnFloodingStrategy" (default) and "ns3::NdnBestRouteStrategy"
-   *
-   * Other strategies can be implemented, inheriting ns3::NdnForwardingStrategy class
-   */
-  void
-  SetForwardingStrategy(const std::string& forwardingStrategyClass, const std::string& attr1 = "",
-                        const std::string& value1 = "", const std::string& attr2 = "",
-                        const std::string& value2 = "", const std::string& attr3 = "",
-                        const std::string& value3 = "", const std::string& attr4 = "",
-                        const std::string& value4 = "");
-
-  /**
-   * @brief Set content store class and its attributes
-   * @param contentStoreClass string, representing class of the content store
-   */
-  void
-  SetContentStore(const std::string& contentStoreClass, const std::string& attr1 = "",
-                  const std::string& value1 = "", const std::string& attr2 = "",
-                  const std::string& value2 = "", const std::string& attr3 = "",
-                  const std::string& value3 = "", const std::string& attr4 = "",
-                  const std::string& value4 = "");
-
-  /**
-   * @brief Set PIT class and its attributes
-   * @param pitClass string, representing class of PIT
-   */
-  void
-  SetPit(const std::string& pitClass, const std::string& attr1 = "", const std::string& value1 = "",
-         const std::string& attr2 = "", const std::string& value2 = "",
-         const std::string& attr3 = "", const std::string& value3 = "",
-         const std::string& attr4 = "", const std::string& value4 = "");
-
-  /**
-   * @brief Set FIB class and its attributes
-   * @param pitClass string, representing class of FIB
-   */
-  void
-  SetFib(const std::string& fibClass, const std::string& attr1 = "", const std::string& value1 = "",
-         const std::string& attr2 = "", const std::string& value2 = "",
-         const std::string& attr3 = "", const std::string& value3 = "",
-         const std::string& attr4 = "", const std::string& value4 = "");
-
   typedef Callback<shared_ptr<NetDeviceFace>, Ptr<Node>, Ptr<L3Protocol>, Ptr<NetDevice>>
     NetDeviceFaceCreateCallback;
 
@@ -137,10 +91,6 @@
    *
    * It is possible to set up several callbacks for different NetDevice types.
    *
-   * Currently, there is only one specialized callback for PointToPointNetDevice, which creates face
-   *and sets limits (if enabled)
-   * based on PointToPoint link parameters
-   *
    * If none of the callbacks fit the TypeId of NetDevice, a default callback is used
    *(DefaultNetDeviceCallback)
    */
@@ -166,28 +116,16 @@
   RemoveNetDeviceFaceCreateCallback(TypeId netDeviceType, NetDeviceFaceCreateCallback callback);
 
   /**
-   * @brief Enable Interest limits (disabled by default)
-   *
-   * @param enable           Enable or disable limits
-   * @param avgRtt           Average RTT
-   * @param avgData Average size of contentObject packets (including all headers)
-   * @param avgInterest      Average size of interest packets (including all headers)
-   */
-  void
-  EnableLimits(bool enable = true, Time avgRtt = Seconds(0.1), uint32_t avgData = 1100,
-               uint32_t avgInterest = 40);
-
-  /**
-   * \brief Install Ndn stack on the node
-   *
-   * This method will assert if called on a node that already has Ndn object
-   * installed on it
-   *
-   * \param nodeName The name of the node on which to install the stack.
-   *
-   * \returns list of installed faces in the form of a smart pointer
-   * to NdnFaceContainer object
-   */
+  * \brief Install Ndn stack on the node
+  *
+  * This method will assert if called on a node that already has Ndn object
+  * installed on it
+  *
+  * \param nodeName The name of the node on which to install the stack.
+  *
+  * \returns list of installed faces in the form of a smart pointer
+  * to NdnFaceContainer object
+  */
   Ptr<FaceContainer>
   Install(const std::string& nodeName) const;
 
@@ -229,69 +167,6 @@
   Ptr<FaceContainer>
   InstallAll() const;
 
-  /**
-   * \brief Add forwarding entry to FIB
-   *
-   * \param nodeName Node name
-   * \param prefix Routing prefix
-   * \param faceId Face index
-   * \param metric Routing metric
-   */
-  static void
-  AddRoute(const std::string& nodeName, const std::string& prefix, uint32_t faceId, int32_t metric);
-
-  /**
-   * \brief Add forwarding entry to FIB
-   *
-   * \param nodeName Node
-   * \param prefix Routing prefix
-   * \param faceId Face index
-   * \param metric Routing metric
-   */
-  static void
-  AddRoute(Ptr<Node> node, const std::string& prefix, uint32_t faceId, int32_t metric);
-
-  /**
-   * \brief Add forwarding entry to FIB
-   *
-   * \param node   Node
-   * \param prefix Routing prefix
-   * \param face   Face
-   * \param metric Routing metric
-   */
-  static void
-  AddRoute(Ptr<Node> node, const std::string& prefix, shared_ptr<Face> face, int32_t metric);
-
-  /**
-   * @brief Add forwarding entry to FIB (work only with point-to-point links)
-   *
-   * \param node Node
-   * \param prefix Routing prefix
-   * \param otherNode The other node, to which interests (will be used to infer face id
-   * \param metric Routing metric
-   */
-  static void
-  AddRoute(Ptr<Node> node, const std::string& prefix, Ptr<Node> otherNode, int32_t metric);
-
-  /**
-   * @brief Add forwarding entry to FIB (work only with point-to-point links)
-   *
-   * \param nodeName Node name (refer to ns3::Names)
-   * \param prefix Routing prefix
-   * \param otherNode The other node name, to which interests (will be used to infer face id (refer
-   *to ns3::Names)
-   * \param metric Routing metric
-   */
-  static void
-  AddRoute(const std::string& nodeName, const std::string& prefix, const std::string& otherNodeName,
-           int32_t metric);
-
-  /**
-   * \brief Set flag indicating necessity to install default routes in FIB
-   */
-  void
-  SetDefaultRoutes(bool needSet);
-
   static KeyChain&
   getKeyChain();
 
@@ -314,15 +189,8 @@
 
 private:
   ObjectFactory m_ndnFactory;
-  ObjectFactory m_strategyFactory;
   ObjectFactory m_contentStoreFactory;
-  ObjectFactory m_pitFactory;
-  ObjectFactory m_fibFactory;
 
-  bool m_limitsEnabled;
-  Time m_avgRtt;
-  uint32_t m_avgDataSize;
-  uint32_t m_avgInterestSize;
   bool m_needSetDefaultRoutes;
 
   typedef std::list<std::pair<TypeId, NetDeviceFaceCreateCallback>> NetDeviceCallbackList;
diff --git a/model/ndn-l3-protocol.cpp b/model/ndn-l3-protocol.cpp
index 4ea8189..f383477 100644
--- a/model/ndn-l3-protocol.cpp
+++ b/model/ndn-l3-protocol.cpp
@@ -1,4 +1,4 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:ni -*- */
 /*
  * Copyright (c) 2011 University of California, Los Angeles
  *
@@ -33,10 +33,24 @@
 #include "ns3/random-variable.h"
 
 #include "ndn-face.hpp"
+
 #include "ndn-net-device-face.hpp"
+#include "../helper/ndn-stack-helper.hpp"
 
 #include <boost/foreach.hpp>
 
+#include "ns3/ndnSIM/NFD/daemon/fw/forwarder.hpp"
+#include "ns3/ndnSIM/NFD/daemon/mgmt/internal-face.hpp"
+#include "ns3/ndnSIM/NFD/daemon/mgmt/fib-manager.hpp"
+#include "ns3/ndnSIM/NFD/daemon/mgmt/face-manager.hpp"
+#include "ns3/ndnSIM/NFD/daemon/mgmt/strategy-choice-manager.hpp"
+#include "ns3/ndnSIM/NFD/daemon/mgmt/status-server.hpp"
+
+#include "ns3/ndnSIM/NFD/daemon/face/null-face.hpp"
+#include "ns3/ndnSIM/NFD/core/config-file.hpp"
+#include "ns3/ndnSIM/NFD/daemon/mgmt/general-config-section.hpp"
+#include "ns3/ndnSIM/NFD/daemon/mgmt/tables-config-section.hpp"
+
 NS_LOG_COMPONENT_DEFINE("ndn.L3Protocol");
 
 namespace ns3 {
@@ -55,14 +69,34 @@
       .SetGroupName("ndn")
       .SetParent<Object>()
       .AddConstructor<L3Protocol>()
-    ;
-      // .AddAttribute("FaceList", "List of faces associated with ndn stack", ObjectVectorValue(),
-      //               MakeObjectVectorAccessor(&L3Protocol::m_faces),
-      //               MakeObjectVectorChecker<Face>());
+
+      .AddTraceSource("OutInterests", "OutInterests",
+                      MakeTraceSourceAccessor(&L3Protocol::m_outInterests))
+      .AddTraceSource("InInterests", "InInterests",
+                      MakeTraceSourceAccessor(&L3Protocol::m_inInterests))
+
+      ////////////////////////////////////////////////////////////////////
+
+      .AddTraceSource("OutData", "OutData", MakeTraceSourceAccessor(&L3Protocol::m_outData))
+      .AddTraceSource("InData", "InData", MakeTraceSourceAccessor(&L3Protocol::m_inData));
   return tid;
 }
 
+class L3Protocol::Impl {
+private:
+  friend class L3Protocol;
+
+  shared_ptr<nfd::Forwarder> m_forwarder;
+
+  shared_ptr<nfd::InternalFace> m_internalFace;
+  shared_ptr<nfd::FibManager> m_fibManager;
+  shared_ptr<nfd::FaceManager> m_faceManager;
+  shared_ptr<nfd::StrategyChoiceManager> m_strategyChoiceManager;
+  shared_ptr<nfd::StatusServer> m_statusServer;
+};
+
 L3Protocol::L3Protocol()
+  : m_impl(new Impl())
 {
   NS_LOG_FUNCTION(this);
 }
@@ -72,6 +106,75 @@
   NS_LOG_FUNCTION(this);
 }
 
+void
+L3Protocol::initialize()
+{
+  m_impl->m_forwarder = make_shared<nfd::Forwarder>();
+
+  initializeManagement();
+
+  m_impl->m_forwarder->getFaceTable().addReserved(make_shared<nfd::NullFace>(), nfd::FACEID_NULL);
+  m_impl->m_forwarder->getFaceTable().addReserved(make_shared<nfd::NullFace>(
+                                                    FaceUri("contentstore://")),
+                                                  nfd::FACEID_CONTENT_STORE);
+}
+
+void
+L3Protocol::initializeManagement()
+{
+  m_impl->m_internalFace = make_shared<nfd::InternalFace>();
+
+  m_impl->m_fibManager =
+    make_shared<nfd::FibManager>(ref(m_impl->m_forwarder->getFib()),
+                                 bind(&nfd::Forwarder::getFace, m_impl->m_forwarder.get(), _1),
+                                 m_impl->m_internalFace, std::ref(StackHelper::getKeyChain()));
+
+  m_impl->m_faceManager =
+    make_shared<nfd::FaceManager>(ref(m_impl->m_forwarder->getFaceTable()), m_impl->m_internalFace,
+                                  std::ref(StackHelper::getKeyChain()));
+
+  m_impl->m_strategyChoiceManager =
+    make_shared<nfd::StrategyChoiceManager>(ref(m_impl->m_forwarder->getStrategyChoice()),
+                                            m_impl->m_internalFace,
+                                            std::ref(StackHelper::getKeyChain()));
+
+  m_impl->m_statusServer =
+    make_shared<nfd::StatusServer>(m_impl->m_internalFace, ref(*m_impl->m_forwarder),
+                                   std::ref(StackHelper::getKeyChain()));
+
+  nfd::TablesConfigSection tablesConfig(m_impl->m_forwarder->getCs(),
+                                        m_impl->m_forwarder->getPit(),
+                                        m_impl->m_forwarder->getFib(),
+                                        m_impl->m_forwarder->getStrategyChoice(),
+                                        m_impl->m_forwarder->getMeasurements());
+
+  m_impl->m_forwarder->getFaceTable().addReserved(m_impl->m_internalFace,
+                                                  nfd::FACEID_INTERNAL_FACE);
+
+  // add FIB entry for NFD Management Protocol
+  shared_ptr<::nfd::fib::Entry> entry =
+    m_impl->m_forwarder->getFib().insert("/localhost/nfd").first;
+  entry->addNextHop(m_impl->m_internalFace, 0);
+}
+
+shared_ptr<nfd::Forwarder>
+L3Protocol::getForwarder()
+{
+  return m_impl->m_forwarder;
+}
+
+shared_ptr<nfd::FibManager>
+L3Protocol::getFibManager()
+{
+  return m_impl->m_fibManager;
+}
+
+shared_ptr<nfd::StrategyChoiceManager>
+L3Protocol::getStrategyChoiceManager()
+{
+  return m_impl->m_strategyChoiceManager;
+}
+
 /*
  * This method is called by AddAgregate and completes the aggregation
  * by setting the node in the ndn stack
@@ -79,14 +182,13 @@
 void
 L3Protocol::NotifyNewAggregate()
 {
-  // not really efficient, but this will work only once
-  if (m_node == 0) {
+  if (m_node == nullptr) {
     m_node = GetObject<Node>();
-    if (m_node != 0) {
+    if (m_node != nullptr) {
     }
   }
 
-  Object::NotifyNewAggregate ();
+  Object::NotifyNewAggregate();
 }
 
 void
@@ -99,43 +201,52 @@
   Object::DoDispose();
 }
 
-uint32_t
-L3Protocol::AddFace(const shared_ptr<Face>& face)
+nfd::FaceId
+L3Protocol::addFace(shared_ptr<Face> face)
 {
-  NS_LOG_FUNCTION(this << &face);
+  NS_LOG_FUNCTION(this << face.get());
 
-  return 0;
+  m_impl->m_forwarder->addFace(face);
+
+  // Connect Signals to TraceSource
+  face->onReceiveInterest +=
+    [this, face](const Interest& interest) { this->m_inInterests(interest, *face); };
+
+  face->onSendInterest +=
+    [this, face](const Interest& interest) { this->m_outInterests(interest, *face); };
+
+  face->onReceiveData += [this, face](const Data& data) { this->m_inData(data, *face); };
+
+  face->onSendData += [this, face](const Data& data) { this->m_outData(data, *face); };
+
+  return face->getId();
 }
 
-void
-L3Protocol::RemoveFace(shared_ptr<Face> face)
+// void
+// L3Protocol::removeFace(shared_ptr<Face> face)
+// {
+//   NS_LOG_FUNCTION(this << std::cref(*face));
+// }
+
+shared_ptr<Face>
+L3Protocol::getFaceById(nfd::FaceId id) const
 {
-  NS_LOG_FUNCTION(this << std::cref(*face));
+  return m_impl->m_forwarder->getFaceTable().get(id);
 }
 
 shared_ptr<Face>
-L3Protocol::GetFace(uint32_t index) const
+L3Protocol::getFaceByNetDevice(Ptr<NetDevice> netDevice) const
 {
-  return nullptr;
-}
+  for (const auto& i : m_impl->m_forwarder->getFaceTable()) {
+    shared_ptr<NetDeviceFace> netDeviceFace = std::dynamic_pointer_cast<NetDeviceFace>(i);
+    if (netDeviceFace == nullptr)
+      continue;
 
-shared_ptr<Face>
-L3Protocol::GetFaceById(uint32_t index) const
-{
+    if (netDeviceFace->GetNetDevice() == netDevice)
+      return i;
+  }
   return nullptr;
 }
 
-shared_ptr<Face>
-L3Protocol::GetFaceByNetDevice(Ptr<NetDevice> netDevice) const
-{
-  return nullptr;
-}
-
-uint32_t
-L3Protocol::GetNFaces(void) const
-{
-  return 0;
-}
-
 } // namespace ndn
 } // namespace ns3
diff --git a/model/ndn-l3-protocol.hpp b/model/ndn-l3-protocol.hpp
index 03618d5..63e4ff2 100644
--- a/model/ndn-l3-protocol.hpp
+++ b/model/ndn-l3-protocol.hpp
@@ -30,6 +30,13 @@
 #include "ns3/ptr.h"
 #include "ns3/net-device.h"
 #include "ns3/nstime.h"
+#include "ns3/traced-callback.h"
+
+namespace nfd {
+class Forwarder;
+class FibManager;
+class StrategyChoiceManager;
+} // namespace nfd
 
 namespace ns3 {
 
@@ -60,7 +67,7 @@
  *
  * \see Face, ForwardingStrategy
  */
-class L3Protocol : public Object {
+class L3Protocol : boost::noncopyable, public Object {
 public:
   /**
    * \brief Interface ID
@@ -81,52 +88,60 @@
   virtual ~L3Protocol();
 
   /**
-   * \brief Add face to Ndn stack
-   *
-   * \param face smart pointer to NdnFace-derived object
-   * (NdnLocalFace, NdnNetDeviceFace, NdnUdpFace) \returns the
-   * index of the Ndn interface added.
-   *
-   * \see NdnLocalFace, NdnNetDeviceFace, NdnUdpFace
+   * \brief Initialize NFD instance
    */
-  virtual uint32_t
-  AddFace(const shared_ptr<Face>& face);
+  void
+  initialize();
 
   /**
-   * \brief Get current number of faces added to Ndn stack
-   *
-   * \returns the number of faces
+   * \brief Get smart pointer to nfd::Forwarder installed on the node
    */
-  virtual uint32_t
-  GetNFaces() const;
+  shared_ptr<nfd::Forwarder>
+  getForwarder();
 
   /**
-   * \brief Get face by face index
-   * \param face The face number (number in face list)
-   * \returns The NdnFace associated with the Ndn face number.
+   * \brief Get smart pointer to nfd::FibManager, used by node's NFD
    */
-  virtual shared_ptr<Face>
-  GetFace(uint32_t face) const;
+  shared_ptr<nfd::FibManager>
+  getFibManager();
+
+  /**
+   * \brief Get smart pointer to nfd::StrategyChoiceManager, used by node's NFD
+   */
+  shared_ptr<nfd::StrategyChoiceManager>
+  getStrategyChoiceManager();
+
+
+  /**
+   * \brief Add face to NDN stack
+   *
+   * \param face smart pointer to Face-derived object (AppFace, NetDeviceFace)
+   * \return nfd::FaceId
+   *
+   * \see AppFace, NetDeviceFace
+   */
+  nfd::FaceId
+  addFace(shared_ptr<Face> face);
 
   /**
    * \brief Get face by face ID
    * \param face The face ID number
-   * \returns The NdnFace associated with the Ndn face number.
+   * \returns The Face associated with the Ndn face number.
    */
-  virtual shared_ptr<Face>
-  GetFaceById(uint32_t face) const;
+  shared_ptr<Face>
+  getFaceById(nfd::FaceId face) const;
 
-  /**
-   * \brief Remove face from ndn stack (remove callbacks)
-   */
-  virtual void
-  RemoveFace(shared_ptr<Face> face);
+  // /**
+  //  * \brief Remove face from ndn stack (remove callbacks)
+  //  */
+  // virtual void
+  // removeFace(shared_ptr<Face> face);
 
   /**
    * \brief Get face for NetDevice
    */
-  virtual shared_ptr<Face>
-  GetFaceByNetDevice(Ptr<NetDevice> netDevice) const;
+  shared_ptr<Face>
+  getFaceByNetDevice(Ptr<NetDevice> netDevice) const;
 
 protected:
   virtual void
@@ -142,13 +157,23 @@
   NotifyNewAggregate();
 
 private:
-  L3Protocol(const L3Protocol&); ///< copy constructor is disabled
-
-  L3Protocol&
-  operator=(const L3Protocol&); ///< copy operator is disabled
+  void
+  initializeManagement();
 
 private:
+  class Impl;
+  std::unique_ptr<Impl> m_impl;
+
+  // These objects are aggregated, but for optimization, get them here
   Ptr<Node> m_node; ///< \brief node on which ndn stack is installed
+
+  TracedCallback<const Interest&, const Face&>
+    m_inInterests; ///< @brief trace of incoming Interests
+  TracedCallback<const Interest&, const Face&>
+    m_outInterests; ///< @brief Transmitted interests trace
+
+  TracedCallback<const Data&, const Face&> m_outData; ///< @brief trace of outgoing Data
+  TracedCallback<const Data&, const Face&> m_inData;  ///< @brief trace of incoming Data
 };
 
 } // namespace ndn
diff --git a/wscript b/wscript
index 0810d72..21e05d3 100644
--- a/wscript
+++ b/wscript
@@ -88,6 +88,8 @@
                                             'apps/*',
                                             'helper/*',
                                             'utils/*/*'])
+    module.source += bld.path.ant_glob(['helper/ndn-face-container.cpp',
+                                        'helper/ndn-stack-helper.cpp'])
 
     module.full_headers = [p.path_from(bld.path) for p in bld.path.ant_glob(
         ['%s/**/*.hpp' % dir for dir in module_dirs])]