helper+model: Create helper to select the replacement policy of NFD's CS

Change-Id: I10933b5c96fd95bc395a1d08642a1e07e826dc45
Refs: #3837
diff --git a/helper/ndn-stack-helper.cpp b/helper/ndn-stack-helper.cpp
index 3b5571a..4b9cd90 100644
--- a/helper/ndn-stack-helper.cpp
+++ b/helper/ndn-stack-helper.cpp
@@ -36,6 +36,9 @@
 #include <map>
 #include <boost/lexical_cast.hpp>
 
+#include "ns3/ndnSIM/NFD/daemon/table/cs-policy-priority-fifo.hpp"
+#include "ns3/ndnSIM/NFD/daemon/table/cs-policy-lru.hpp"
+
 NS_LOG_COMPONENT_DEFINE("ndn.StackHelper");
 
 namespace ns3 {
@@ -51,6 +54,11 @@
 {
   setCustomNdnCxxClocks();
 
+  m_csPolicies.insert({"nfd::cs::lru", [] { return make_unique<nfd::cs::LruPolicy>(); }});
+  m_csPolicies.insert({"nfd::cs::priority_fifo", [] () { return make_unique<nfd::cs::PriorityFifoPolicy>(); }});
+
+  m_csPolicyCreationFunc = m_csPolicies["nfd::cs::lru"];
+
   m_ndnFactory.SetTypeId("ns3::ndn::L3Protocol");
   m_contentStoreFactory.SetTypeId("ns3::ndn::cs::Lru");
 
@@ -127,6 +135,22 @@
   m_maxCsSize = maxSize;
 }
 
+void
+StackHelper::setPolicy(const std::string& policy)
+{
+  auto found = m_csPolicies.find(policy);
+  if (found != m_csPolicies.end()) {
+    m_csPolicyCreationFunc = found->second;
+  }
+  else {
+    NS_FATAL_ERROR("Cache replacement policy " << policy << " not found");
+    NS_LOG_DEBUG("Available cache replacement policies: ");
+    for (auto it = m_csPolicies.begin(); it != m_csPolicies.end(); it++) {
+      NS_LOG_DEBUG("    " << it->first);
+    }
+  }
+}
+
 Ptr<FaceContainer>
 StackHelper::Install(const NodeContainer& c) const
 {
@@ -178,6 +202,10 @@
   if (m_maxCsSize == 0) {
     ndn->AggregateObject(m_contentStoreFactory.Create<ContentStore>());
   }
+  // if NFD's CS is enabled, check if a replacement policy has been specified
+  else {
+    ndn->setCsReplacementPolicy(m_csPolicyCreationFunc);
+  }
 
   // Aggregate L3Protocol on node (must be after setting ndnSIM CS)
   node->AggregateObject(ndn);
diff --git a/helper/ndn-stack-helper.hpp b/helper/ndn-stack-helper.hpp
index 0cb3413..bae814f 100644
--- a/helper/ndn-stack-helper.hpp
+++ b/helper/ndn-stack-helper.hpp
@@ -31,6 +31,12 @@
 #include "ndn-fib-helper.hpp"
 #include "ndn-strategy-choice-helper.hpp"
 
+namespace nfd {
+namespace cs {
+class Policy;
+} // namespace cs
+} // namespace nfd
+
 namespace ns3 {
 
 class Node;
@@ -75,6 +81,12 @@
   setCsSize(size_t maxSize);
 
   /**
+   * @brief Set the cache replacement policy for NFD's Content Store
+   */
+  void
+  setPolicy(const std::string& policy);
+
+  /**
    * @brief Set ndnSIM 1.0 content store implementation and its attributes
    * @param contentStoreClass string, representing class of the content store
    * @note ndnSIM 1.0 content store implementation have limited support for Interest selectors
@@ -262,6 +274,11 @@
   bool m_needSetDefaultRoutes;
   size_t m_maxCsSize;
 
+  typedef std::function<std::unique_ptr<nfd::cs::Policy>()> PolicyCreationCallback;
+  PolicyCreationCallback m_csPolicyCreationFunc;
+
+  std::map<std::string, PolicyCreationCallback> m_csPolicies;
+
   typedef std::list<std::pair<TypeId, FaceCreateCallback>> NetDeviceCallbackList;
   NetDeviceCallbackList m_netDeviceCallbacks;
 };
diff --git a/model/ndn-l3-protocol.cpp b/model/ndn-l3-protocol.cpp
index 33e0113..e8f7ccc 100644
--- a/model/ndn-l3-protocol.cpp
+++ b/model/ndn-l3-protocol.cpp
@@ -179,6 +179,7 @@
   nfd::ConfigSection m_config;
 
   Ptr<ContentStore> m_csFromNdnSim;
+  PolicyCreationCallback m_policy;
 };
 
 L3Protocol::L3Protocol()
@@ -239,6 +240,12 @@
 }
 
 void
+L3Protocol::setCsReplacementPolicy(const PolicyCreationCallback& policy)
+{
+  m_impl->m_policy = policy;
+}
+
+void
 L3Protocol::initializeManagement()
 {
   auto& forwarder = m_impl->m_forwarder;
@@ -280,6 +287,12 @@
 
   ConfigFile config(&ConfigFile::ignoreUnknownSection);
 
+  // if we use NFD's CS, we have to specify a replacement policy
+  m_impl->m_csFromNdnSim = GetObject<ContentStore>();
+  if (m_impl->m_csFromNdnSim == nullptr) {
+    forwarder->getCs().setPolicy(m_impl->m_policy());
+  }
+
   TablesConfigSection tablesConfig(forwarder->getCs(),
                                    forwarder->getPit(),
                                    forwarder->getFib(),
diff --git a/model/ndn-l3-protocol.hpp b/model/ndn-l3-protocol.hpp
index a34d36f..cca0277 100644
--- a/model/ndn-l3-protocol.hpp
+++ b/model/ndn-l3-protocol.hpp
@@ -40,6 +40,9 @@
 namespace pit {
 class Entry;
 } // namespace pit
+namespace cs {
+class Policy;
+} // namespace cs
 } // namespace nfd
 
 namespace ns3 {
@@ -153,6 +156,14 @@
   void
   injectInterest(const Interest& interest);
 
+  typedef std::function<std::unique_ptr<nfd::cs::Policy>()> PolicyCreationCallback;
+
+  /**
+   * \brief Set the replacement policy of NFD's CS
+   */
+  void
+  setCsReplacementPolicy(const PolicyCreationCallback& policy);
+
 public: // Workaround for python bindings
   static Ptr<L3Protocol>
   getL3Protocol(Ptr<Object> node);
diff --git a/tests/unit-tests/helper/ndn-stack-helper.t.cpp b/tests/unit-tests/helper/ndn-stack-helper.t.cpp
new file mode 100644
index 0000000..25df0a2
--- /dev/null
+++ b/tests/unit-tests/helper/ndn-stack-helper.t.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2011-2016  Regents of the University of California.
+ *
+ * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
+ * contributors.
+ *
+ * ndnSIM is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndnSIM 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
+ * ndnSIM, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "helper/ndn-stack-helper.hpp"
+#include "../tests-common.hpp"
+
+#include "ns3/point-to-point-module.h"
+
+namespace ns3 {
+namespace ndn {
+
+BOOST_FIXTURE_TEST_SUITE(HelperStackHelper, CleanupFixture)
+
+BOOST_AUTO_TEST_CASE(TestNfdContentStorePolicy)
+{
+  // setting default parameters for PointToPoint links and channels
+  Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("10Mbps"));
+  Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
+  Config::SetDefault("ns3::DropTailQueue::MaxPackets", StringValue("20"));
+
+  // Creating nodes
+  NodeContainer nodes;
+  nodes.Create(2);
+
+  // Connecting nodes using two links
+  PointToPointHelper p2p;
+  p2p.Install(nodes.Get(0), nodes.Get(1));
+
+  // Install NDN stack on all nodes
+  ndn::StackHelper ndnHelper;
+  ndnHelper.SetDefaultRoutes(true);
+  ndnHelper.setPolicy("nfd::cs::lru");
+  ndnHelper.Install(nodes.Get(0));
+
+  // test which CS policy has be selected for node 0
+  Ptr<L3Protocol> protoNode0 = L3Protocol::getL3Protocol(nodes.Get(0));
+  BOOST_CHECK_EQUAL(protoNode0->getForwarder()->getCs().getPolicy()->getName(), "lru");
+
+  ndnHelper.setPolicy("nfd::cs::priority_fifo");
+  ndnHelper.Install(nodes.Get(1));
+
+  Ptr<L3Protocol> protoNode1 = L3Protocol::getL3Protocol(nodes.Get(1));
+  // test that the CS policy for node 0 did not change
+  BOOST_CHECK_EQUAL(protoNode0->getForwarder()->getCs().getPolicy()->getName(), "lru");
+  // test which CS policy has be selected for node 1
+  BOOST_CHECK_EQUAL(protoNode1->getForwarder()->getCs().getPolicy()->getName(), "fifo");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn
+} // namespace ns3