NFD: Keep both the CS of NFD and ndnSIM

Ref: #2231
diff --git a/NFD/daemon/fw/forwarder.cpp b/NFD/daemon/fw/forwarder.cpp
index 1cd1d16..4066e3f 100644
--- a/NFD/daemon/fw/forwarder.cpp
+++ b/NFD/daemon/fw/forwarder.cpp
@@ -92,7 +92,14 @@
   bool isPending = inRecords.begin() != inRecords.end();
   if (!isPending) {
     // CS lookup
-    const Data* csMatch = m_cs.find(interest);
+    const Data* csMatch;
+    shared_ptr<Data> match;
+    if (m_csFromNdnSim == nullptr)
+      csMatch = m_cs.find(interest);
+    else {
+      match = m_csFromNdnSim->Lookup(interest.shared_from_this());
+      csMatch = match.get();
+    }
     if (csMatch != 0) {
       const_cast<Data*>(csMatch)->setIncomingFaceId(FACEID_CONTENT_STORE);
       // XXX should we lookup PIT for other Interests that also match csMatch?
@@ -268,7 +275,10 @@
   }
 
   // CS insert
-  m_cs.insert(data);
+  if (m_csFromNdnSim == nullptr)
+    m_cs.insert(data);
+  else
+    m_csFromNdnSim->Add(data.shared_from_this());
 
   std::set<shared_ptr<Face> > pendingDownstreams;
   // foreach PitEntry
@@ -321,7 +331,10 @@
   bool acceptToCache = inFace.isLocal();
   if (acceptToCache) {
     // CS insert
-    m_cs.insert(data, true);
+    if (m_csFromNdnSim == nullptr)
+      m_cs.insert(data, true);
+    else
+      m_csFromNdnSim->Add(data.shared_from_this());
   }
 
   NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
diff --git a/NFD/daemon/fw/forwarder.hpp b/NFD/daemon/fw/forwarder.hpp
index a753f15..627148e 100644
--- a/NFD/daemon/fw/forwarder.hpp
+++ b/NFD/daemon/fw/forwarder.hpp
@@ -37,6 +37,8 @@
 #include "table/strategy-choice.hpp"
 #include "table/dead-nonce-list.hpp"
 
+#include "ns3/ndnSIM/model/cs/ndn-content-store.hpp"
+
 namespace nfd {
 
 namespace fw {
@@ -104,6 +106,10 @@
   DeadNonceList&
   getDeadNonceList();
 
+public: // allow enabling ndnSIM content store (will be removed in the future)
+  void
+  setCsFromNdnSim(ns3::Ptr<ns3::ndn::ContentStore> cs);
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
   /** \brief incoming Interest pipeline
    */
@@ -199,6 +205,8 @@
   StrategyChoice m_strategyChoice;
   DeadNonceList  m_deadNonceList;
 
+  ns3::Ptr<ns3::ndn::ContentStore> m_csFromNdnSim;
+
   static const Name LOCALHOST_NAME;
 
   // allow Strategy (base class) to enter pipelines
@@ -283,6 +291,12 @@
   return m_deadNonceList;
 }
 
+inline void
+Forwarder::setCsFromNdnSim(ns3::Ptr<ns3::ndn::ContentStore> cs)
+{
+  m_csFromNdnSim = cs;
+}
+
 #ifdef WITH_TESTS
 inline void
 Forwarder::dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, function<void(fw::Strategy*)> trigger)
diff --git a/helper/ndn-stack-helper.cpp b/helper/ndn-stack-helper.cpp
index 2413fb9..1916104 100644
--- a/helper/ndn-stack-helper.cpp
+++ b/helper/ndn-stack-helper.cpp
@@ -23,12 +23,14 @@
 
 #include "ns3/log.h"
 #include "ns3/names.h"
+#include "ns3/string.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 "model/cs/ndn-content-store.hpp"
 
 #include <limits>
 #include <map>
@@ -41,11 +43,12 @@
 
 StackHelper::StackHelper()
   : m_needSetDefaultRoutes(false)
+  , m_shouldUseNfdCs(true)
 {
   setCustomNdnCxxClocks();
 
   m_ndnFactory.SetTypeId("ns3::ndn::L3Protocol");
-  // m_contentStoreFactory.SetTypeId("ns3::ndn::cs::Lru");
+  m_contentStoreFactory.SetTypeId("ns3::ndn::cs::Lru");
 
   m_netDeviceCallbacks.push_back(
     std::make_pair(PointToPointNetDevice::GetTypeId(),
@@ -78,6 +81,55 @@
   m_needSetDefaultRoutes = needSet;
 }
 
+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::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)
+{
+  NS_ASSERT_MSG(m_shouldUseNfdCs == false,
+                "First choose not to use NFD's CS and then select the replacement policy");
+
+  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::SetContentStoreChoice(bool shouldUseNfdCs)
+{
+  m_shouldUseNfdCs = shouldUseNfdCs;
+}
+
+bool
+StackHelper::shouldUseNfdCs() const
+{
+  return m_shouldUseNfdCs;
+}
+
 Ptr<FaceContainer>
 StackHelper::Install(const NodeContainer& c) const
 {
@@ -106,11 +158,16 @@
   }
 
   Ptr<L3Protocol> ndn = m_ndnFactory.Create<L3Protocol>();
-  // Aggregate L3Protocol on node
-  node->AggregateObject(ndn);
 
   // NFD initialization
-  ndn->initialize();
+  ndn->initialize(m_shouldUseNfdCs);
+
+  // Create and aggregate content store if NFD's contest store has been disabled
+  if (!m_shouldUseNfdCs)
+    ndn->AggregateObject(m_contentStoreFactory.Create<ContentStore>());
+
+  // Aggregate L3Protocol on node (must be after setting ndnSIM CS)
+  node->AggregateObject(ndn);
 
   for (uint32_t index = 0; index < node->GetNDevices(); index++) {
     Ptr<NetDevice> device = node->GetDevice(index);
diff --git a/helper/ndn-stack-helper.hpp b/helper/ndn-stack-helper.hpp
index 77d3b5c..1ba66d8 100644
--- a/helper/ndn-stack-helper.hpp
+++ b/helper/ndn-stack-helper.hpp
@@ -84,6 +84,31 @@
                      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 to use native NFD's content store or ndnSIM provided CS implementations
+   *
+   * @note ndnSIM CS implementations have limited support for NDN selectors
+   */
+  void
+  SetContentStoreChoice(const bool shouldUseNfdCs);
+
+  /**
+   * @brief Check if stack is using native NFD content store implementation
+   */
+  bool
+  shouldUseNfdCs() const;
+
   typedef Callback<shared_ptr<NetDeviceFace>, Ptr<Node>, Ptr<L3Protocol>, Ptr<NetDevice>>
     NetDeviceFaceCreateCallback;
 
@@ -200,6 +225,7 @@
   ObjectFactory m_contentStoreFactory;
 
   bool m_needSetDefaultRoutes;
+  bool m_shouldUseNfdCs;
 
   typedef std::list<std::pair<TypeId, NetDeviceFaceCreateCallback>> NetDeviceCallbackList;
   NetDeviceCallbackList m_netDeviceCallbacks;
diff --git a/model/cs/custom-policies/freshness-policy.hpp b/model/cs/custom-policies/freshness-policy.hpp
index ae10862..663ec5b 100644
--- a/model/cs/custom-policies/freshness-policy.hpp
+++ b/model/cs/custom-policies/freshness-policy.hpp
@@ -104,15 +104,14 @@
       inline bool
       insert(typename parent_trie::iterator item)
       {
-        // get_time (item) = Simulator::Now ();
-        Time freshness = MilliSeconds(item->payload()->GetData()->getFreshnessPeriod().count());
-        if (!freshness.IsZero()) {
-          get_freshness(item) = Simulator::Now() + freshness;
+        time::milliseconds freshness = item->payload()->GetData()->getFreshnessPeriod();
+        if (freshness > time::milliseconds::zero()) {
+          get_freshness(item) = Simulator::Now() + MilliSeconds(freshness.count());
 
-          // push item only if freshness is non zero. otherwise, this payload is not controlled by
-          // the policy
-          // note that .size() on this policy would return only number of items with non-infinite
-          // freshness policy
+          // push item only if freshness is non zero. otherwise, this payload is not
+          // controlled by the policy.
+          // Note that .size() on this policy would return only the number of items with
+          // non-infinite freshness policy
           policy_container::insert(*item);
         }
 
@@ -128,8 +127,9 @@
       inline void
       erase(typename parent_trie::iterator item)
       {
-        if (item->payload()->GetData()->getFreshnessPeriod() != time::milliseconds::zero()) {
-          // erase only if freshness is non zero (otherwise an item is not in the policy
+        time::milliseconds freshness = item->payload()->GetData()->getFreshnessPeriod();
+        if (freshness > time::milliseconds::zero()) {
+          // erase only if freshness is positive (otherwise an item is not in the policy)
           policy_container::erase(policy_container::s_iterator_to(*item));
         }
       }
diff --git a/model/ndn-l3-protocol.cpp b/model/ndn-l3-protocol.cpp
index f383477..7412e2c 100644
--- a/model/ndn-l3-protocol.cpp
+++ b/model/ndn-l3-protocol.cpp
@@ -36,6 +36,7 @@
 
 #include "ndn-net-device-face.hpp"
 #include "../helper/ndn-stack-helper.hpp"
+#include "cs/ndn-content-store.hpp"
 
 #include <boost/foreach.hpp>
 
@@ -93,6 +94,8 @@
   shared_ptr<nfd::FaceManager> m_faceManager;
   shared_ptr<nfd::StrategyChoiceManager> m_strategyChoiceManager;
   shared_ptr<nfd::StatusServer> m_statusServer;
+
+  Ptr<ContentStore> m_csFromNdnSim;
 };
 
 L3Protocol::L3Protocol()
@@ -107,11 +110,11 @@
 }
 
 void
-L3Protocol::initialize()
+L3Protocol::initialize(bool shouldUseNfdCs)
 {
   m_impl->m_forwarder = make_shared<nfd::Forwarder>();
 
-  initializeManagement();
+  initializeManagement(shouldUseNfdCs);
 
   m_impl->m_forwarder->getFaceTable().addReserved(make_shared<nfd::NullFace>(), nfd::FACEID_NULL);
   m_impl->m_forwarder->getFaceTable().addReserved(make_shared<nfd::NullFace>(
@@ -120,7 +123,7 @@
 }
 
 void
-L3Protocol::initializeManagement()
+L3Protocol::initializeManagement(bool shouldUseNfdCs)
 {
   m_impl->m_internalFace = make_shared<nfd::InternalFace>();
 
@@ -185,6 +188,11 @@
   if (m_node == nullptr) {
     m_node = GetObject<Node>();
     if (m_node != nullptr) {
+      NS_ASSERT(m_impl->m_forwarder != nullptr);
+      m_impl->m_csFromNdnSim = GetObject<ContentStore>();
+      if (m_impl->m_csFromNdnSim != nullptr) {
+        m_impl->m_forwarder->setCsFromNdnSim(m_impl->m_csFromNdnSim);
+      }
     }
   }
 
diff --git a/model/ndn-l3-protocol.hpp b/model/ndn-l3-protocol.hpp
index 63e4ff2..9ec320f 100644
--- a/model/ndn-l3-protocol.hpp
+++ b/model/ndn-l3-protocol.hpp
@@ -91,7 +91,7 @@
    * \brief Initialize NFD instance
    */
   void
-  initialize();
+  initialize(bool shouldUseNfdCs);
 
   /**
    * \brief Get smart pointer to nfd::Forwarder installed on the node
@@ -158,7 +158,7 @@
 
 private:
   void
-  initializeManagement();
+  initializeManagement(bool isNfd);
 
 private:
   class Impl;