fw: Forwarder::lookupFib

refs #3664

Change-Id: I0e0cc3de997653c93db9b7c89e81ea73b4fb12ac
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 3578bb7..adcb134 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -186,57 +186,13 @@
   // set PIT unsatisfy timer
   this->setUnsatisfyTimer(pitEntry);
 
-  shared_ptr<fib::Entry> fibEntry;
-  // has Link object?
-  if (!interest.hasLink()) {
-    // FIB lookup with Interest name
-    fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
-    NFD_LOG_TRACE("onContentStoreMiss noLinkObject");
-  }
-  else {
-    const Link& link = interest.getLink();
-
-    // in producer region?
-    if (m_networkRegionTable.isInProducerRegion(link)) {
-      // FIB lookup with Interest name
-      fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
-      NFD_LOG_TRACE("onContentStoreMiss inProducerRegion");
-    }
-    // has SelectedDelegation?
-    else if (interest.hasSelectedDelegation()) {
-      // FIB lookup with SelectedDelegation
-      fibEntry = m_fib.findLongestPrefixMatch(interest.getSelectedDelegation());
-      NFD_LOG_TRACE("onContentStoreMiss hasSelectedDelegation=" << interest.getSelectedDelegation());
-    }
-    else {
-      // FIB lookup with first delegation Name
-      fibEntry = m_fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
-
-      // in default-free zone?
-      bool isDefaultFreeZone = !(fibEntry->getPrefix().size() == 0 && fibEntry->hasNextHops());
-      if (isDefaultFreeZone) {
-        // choose and set SelectedDelegation
-        for (const std::pair<uint32_t, Name>& delegation : link.getDelegations()) {
-          const Name& delegationName = delegation.second;
-          fibEntry = m_fib.findLongestPrefixMatch(delegationName);
-          if (fibEntry->hasNextHops()) {
-            const_cast<Interest&>(interest).setSelectedDelegation(delegationName);
-            NFD_LOG_TRACE("onContentStoreMiss enterDefaultFreeZone"
-                          << " setSelectedDelegation=" << delegationName);
-            break;
-          }
-        }
-      }
-      else {
-        NFD_LOG_TRACE("onContentStoreMiss inConsumerRegion");
-      }
-    }
-  }
-
-  // dispatch to strategy
-  BOOST_ASSERT(fibEntry != nullptr);
-  this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
-                                          cref(inFace), cref(interest), fibEntry, pitEntry));
+  // dispatch to strategy: after incoming Interest
+  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
+  shared_ptr<fib::Entry> fibEntryP = const_cast<fib::Entry&>(fibEntry).shared_from_this();
+  this->dispatchToStrategy(pitEntry,
+    [&] (fw::Strategy* strategy) {
+      strategy->afterReceiveInterest(inFace, interest, fibEntryP, pitEntry);
+    });
 }
 
 void
@@ -328,8 +284,8 @@
   NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
 
   // invoke PIT unsatisfied callback
-  this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
-                                          pitEntry));
+  this->dispatchToStrategy(pitEntry,
+    [&] (fw::Strategy* strategy) { strategy->beforeExpirePendingInterest(pitEntry); });
 
   // goto Interest Finalize pipeline
   this->onInterestFinalize(pitEntry, false);
@@ -396,8 +352,8 @@
     }
 
     // invoke PIT satisfy callback
-    this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyInterest, _1,
-                                            pitEntry, cref(inFace), cref(data)));
+    this->dispatchToStrategy(pitEntry,
+      [&] (fw::Strategy* strategy) { strategy->beforeSatisfyInterest(pitEntry, inFace, data); });
 
     // Dead Nonce List insert if necessary (for out-record of inFace)
     this->insertDeadNonceList(*pitEntry, true, data.getFreshnessPeriod(), &inFace);
@@ -513,9 +469,12 @@
   outRecord->setIncomingNack(nack);
 
   // trigger strategy: after receive NACK
-  shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
-  this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveNack, _1,
-                                          cref(inFace), cref(nack), fibEntry, pitEntry));
+  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
+  shared_ptr<fib::Entry> fibEntryP = const_cast<fib::Entry&>(fibEntry).shared_from_this();
+  this->dispatchToStrategy(pitEntry,
+    [&] (fw::Strategy* strategy) {
+      strategy->afterReceiveNack(inFace, nack, fibEntryP, pitEntry);
+    });
 }
 
 void
@@ -564,6 +523,66 @@
   ++m_counters.nOutNacks;
 }
 
+const fib::Entry&
+Forwarder::lookupFib(const pit::Entry& pitEntry) const
+{
+  const Interest& interest = pitEntry.getInterest();
+  // has Link object?
+  if (!interest.hasLink()) {
+    // FIB lookup with Interest name
+    const fib::Entry& fibEntry = *m_fib.findLongestPrefixMatch(pitEntry);
+    NFD_LOG_TRACE("lookupFib noLinkObject found=" << fibEntry.getPrefix());
+    return fibEntry;
+  }
+
+  const Link& link = interest.getLink();
+
+  // in producer region?
+  if (m_networkRegionTable.isInProducerRegion(link)) {
+    // FIB lookup with Interest name
+    const fib::Entry& fibEntry = *m_fib.findLongestPrefixMatch(pitEntry);
+    NFD_LOG_TRACE("lookupFib inProducerRegion found=" << fibEntry.getPrefix());
+    return fibEntry;
+  }
+
+  // has SelectedDelegation?
+  if (interest.hasSelectedDelegation()) {
+    // FIB lookup with SelectedDelegation
+    Name selectedDelegation = interest.getSelectedDelegation();
+    const fib::Entry& fibEntry = *m_fib.findLongestPrefixMatch(selectedDelegation);
+    NFD_LOG_TRACE("lookupFib hasSelectedDelegation=" << selectedDelegation << " found=" << fibEntry.getPrefix());
+    return fibEntry;
+  }
+
+  // FIB lookup with first delegation Name
+  const fib::Entry& fibEntry0 = *m_fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
+  // in default-free zone?
+  bool isDefaultFreeZone = !(fibEntry0.getPrefix().size() == 0 && fibEntry0.hasNextHops());
+  if (!isDefaultFreeZone) {
+    NFD_LOG_TRACE("onContentStoreMiss inConsumerRegion found=" << fibEntry0.getPrefix());
+    return fibEntry0;
+  }
+
+  // choose and set SelectedDelegation
+  for (const std::pair<uint32_t, Name>& delegation : link.getDelegations()) {
+    const Name& delegationName = delegation.second;
+    const fib::Entry& fibEntry = *m_fib.findLongestPrefixMatch(delegationName);
+    if (fibEntry.hasNextHops()) {
+      /// \todo Don't modify in-record Interests.
+      ///       Set SelectedDelegation in outgoing Interest pipeline.
+      std::for_each(pitEntry.in_begin(), pitEntry.in_end(),
+        [&delegationName] (const pit::InRecord& inR) {
+          const_cast<Interest&>(inR.getInterest()).setSelectedDelegation(delegationName);
+        });
+      NFD_LOG_TRACE("onContentStoreMiss enterDefaultFreeZone"
+                    << " setSelectedDelegation=" << delegationName);
+      return fibEntry;
+    }
+  }
+  BOOST_ASSERT(false);
+  return fibEntry0;
+}
+
 static inline bool
 compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
 {
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index 99838bb..bf95d98 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -123,6 +123,11 @@
   NetworkRegionTable&
   getNetworkRegionTable();
 
+  /** \brief performs a FIB lookup, considering Link object if present
+   */
+  const fib::Entry&
+  lookupFib(const pit::Entry& pitEntry) const;
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
   /** \brief incoming Interest pipeline
    */
diff --git a/daemon/table/fib-entry.hpp b/daemon/table/fib-entry.hpp
index 9106d9f..0536fc5 100644
--- a/daemon/table/fib-entry.hpp
+++ b/daemon/table/fib-entry.hpp
@@ -50,7 +50,7 @@
 /** \class Entry
  *  \brief represents a FIB entry
  */
-class Entry : noncopyable
+class Entry : public enable_shared_from_this<Entry>, noncopyable
 {
 public:
   explicit
diff --git a/tests/daemon/fw/forwarder.t.cpp b/tests/daemon/fw/forwarder.t.cpp
index d716988..1a4de92 100644
--- a/tests/daemon/fw/forwarder.t.cpp
+++ b/tests/daemon/fw/forwarder.t.cpp
@@ -749,22 +749,10 @@
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
-  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
-  auto strategyP = make_shared<DummyStrategy>(ref(forwarder), "ndn:/strategyP");
-  strategyP->wantAfterReceiveInterestCalls = true;
-  strategyChoice.install(strategyP);
-  strategyChoice.insert("ndn:/" , strategyP->getName());
-
   Fib& fib = forwarder.getFib();
   Pit& pit = forwarder.getPit();
   NetworkRegionTable& nrt = forwarder.getNetworkRegionTable();
 
-  // returns prefix of FIB entry during last afterReceiveInterest trigger
-  auto getLastFibPrefix = [strategyP] () -> Name {
-    BOOST_REQUIRE(!strategyP->afterReceiveInterestCalls.empty());
-    return std::get<2>(strategyP->afterReceiveInterestCalls.back())->getPrefix();
-  };
-
   shared_ptr<Link> link = makeLink("/net/ndnsim", {{10, "/telia/terabits"}, {20, "/ucla/cs"}});
 
   // consumer region
@@ -778,8 +766,7 @@
   shared_ptr<pit::Entry> pit1 = pit.insert(*interest1).first;
   pit1->insertOrUpdateInRecord(face1, *interest1);
 
-  forwarder.onContentStoreMiss(*face1, pit1, *interest1);
-  BOOST_CHECK_EQUAL(getLastFibPrefix(), "/");
+  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit1).getPrefix(), "/");
   BOOST_CHECK_EQUAL(interest1->hasSelectedDelegation(), false);
 
   fibRoot->removeNextHop(face2);
@@ -797,8 +784,7 @@
   shared_ptr<pit::Entry> pit2 = pit.insert(*interest2).first;
   pit2->insertOrUpdateInRecord(face1, *interest2);
 
-  forwarder.onContentStoreMiss(*face1, pit2, *interest2);
-  BOOST_CHECK_EQUAL(getLastFibPrefix(), "/telia");
+  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit2).getPrefix(), "/telia");
   BOOST_REQUIRE_EQUAL(interest2->hasSelectedDelegation(), true);
   BOOST_CHECK_EQUAL(interest2->getSelectedDelegation(), "/telia/terabits");
 
@@ -816,8 +802,7 @@
   shared_ptr<pit::Entry> pit3 = pit.insert(*interest3).first;
   pit3->insertOrUpdateInRecord(face1, *interest3);
 
-  forwarder.onContentStoreMiss(*face1, pit3, *interest3);
-  BOOST_CHECK_EQUAL(getLastFibPrefix(), "/ucla");
+  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit3).getPrefix(), "/ucla");
   BOOST_REQUIRE_EQUAL(interest3->hasSelectedDelegation(), true);
   BOOST_CHECK_EQUAL(interest3->getSelectedDelegation(), "/ucla/cs");
 
@@ -837,8 +822,7 @@
   shared_ptr<pit::Entry> pit4 = pit.insert(*interest4).first;
   pit4->insertOrUpdateInRecord(face1, *interest4);
 
-  forwarder.onContentStoreMiss(*face1, pit4, *interest4);
-  BOOST_CHECK_EQUAL(getLastFibPrefix(), "/ucla");
+  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit4).getPrefix(), "/ucla");
   BOOST_REQUIRE_EQUAL(interest4->hasSelectedDelegation(), true);
   BOOST_CHECK_EQUAL(interest4->getSelectedDelegation(), "/ucla/cs");
 
@@ -860,8 +844,7 @@
   shared_ptr<pit::Entry> pit5 = pit.insert(*interest5).first;
   pit5->insertOrUpdateInRecord(face1, *interest5);
 
-  forwarder.onContentStoreMiss(*face1, pit5, *interest5);
-  BOOST_CHECK_EQUAL(getLastFibPrefix(), "/net/ndnsim");
+  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit1).getPrefix(), "/net/ndnsim");
   BOOST_REQUIRE_EQUAL(interest5->hasSelectedDelegation(), true);
   BOOST_CHECK_EQUAL(interest5->getSelectedDelegation(), "/ucla/cs");