fw: replace Link with forwarding hint

Forwarding now processes forwarding hint on Interests,
and no longer considers the Link object.

refs #4055

Change-Id: I0331687ee8ec31afa2f1a105e903670689647c4d
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 3263b43..9e0b8bb 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
@@ -73,53 +73,6 @@
 Forwarder::~Forwarder() = default;
 
 void
-Forwarder::startProcessInterest(Face& face, const Interest& interest)
-{
-  // check fields used by forwarding are well-formed
-  try {
-    if (interest.hasLink()) {
-      interest.getLink();
-    }
-  }
-  catch (const tlv::Error&) {
-    NFD_LOG_DEBUG("startProcessInterest face=" << face.getId() <<
-                  " interest=" << interest.getName() << " malformed");
-    // It's safe to call interest.getName() because Name has been fully parsed
-    return;
-  }
-
-  this->onIncomingInterest(face, interest);
-}
-
-void
-Forwarder::startProcessData(Face& face, const Data& data)
-{
-  // check fields used by forwarding are well-formed
-  // (none needed)
-
-  this->onIncomingData(face, data);
-}
-
-void
-Forwarder::startProcessNack(Face& face, const lp::Nack& nack)
-{
-  // check fields used by forwarding are well-formed
-  try {
-    if (nack.getInterest().hasLink()) {
-      nack.getInterest().getLink();
-    }
-  }
-  catch (const tlv::Error&) {
-    NFD_LOG_DEBUG("startProcessNack face=" << face.getId() <<
-                  " nack=" << nack.getInterest().getName() <<
-                  "~" << nack.getReason() << " malformed");
-    return;
-  }
-
-  this->onIncomingNack(face, nack);
-}
-
-void
 Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
 {
   // receive Interest
@@ -146,13 +99,12 @@
     return;
   }
 
-  // strip Link object if Interest has reached producer region
-  if (interest.hasLink() && m_networkRegionTable.isInProducerRegion(interest.getLink())) {
+  // strip forwarding hint if Interest has reached producer region
+  if (!interest.getForwardingHint().empty() &&
+      m_networkRegionTable.isInProducerRegion(interest.getForwardingHint())) {
     NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
                   " interest=" << interest.getName() << " reaching-producer-region");
-    Interest& interestRef = const_cast<Interest&>(interest);
-    interestRef.unsetLink();
-    interestRef.unsetSelectedDelegation();
+    const_cast<Interest&>(interest).setForwardingHint({});
   }
 
   // PIT insert
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index b0cc156..d2e73a8 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
@@ -106,24 +106,33 @@
 public: // forwarding entrypoints and tables
   /** \brief start incoming Interest processing
    *  \param face face on which Interest is received
-   *  \param interest the incoming Interest, must be created with make_shared
+   *  \param interest the incoming Interest, must be well-formed and created with make_shared
    */
   void
-  startProcessInterest(Face& face, const Interest& interest);
+  startProcessInterest(Face& face, const Interest& interest)
+  {
+    this->onIncomingInterest(face, interest);
+  }
 
   /** \brief start incoming Data processing
    *  \param face face on which Data is received
-   *  \param data the incoming Data, must be created with make_shared
+   *  \param data the incoming Data, must be well-formed and created with make_shared
    */
   void
-  startProcessData(Face& face, const Data& data);
+  startProcessData(Face& face, const Data& data)
+  {
+    this->onIncomingData(face, data);
+  }
 
   /** \brief start incoming Nack processing
    *  \param face face on which Nack is received
-   *  \param nack the incoming Nack, must be created with make_shared
+   *  \param nack the incoming Nack, must be well-formed
    */
   void
-  startProcessNack(Face& face, const lp::Nack& nack);
+  startProcessNack(Face& face, const lp::Nack& nack)
+  {
+    this->onIncomingNack(face, nack);
+  }
 
   NameTree&
   getNameTree()
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index 0419a22..fea2164 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
@@ -198,54 +198,36 @@
   const Fib& fib = m_forwarder.getFib();
 
   const Interest& interest = pitEntry.getInterest();
-  // has Link object?
-  if (!interest.hasLink()) {
+  // has forwarding hint?
+  if (interest.getForwardingHint().empty()) {
     // FIB lookup with Interest name
     const fib::Entry& fibEntry = fib.findLongestPrefixMatch(pitEntry);
-    NFD_LOG_TRACE("lookupFib noLinkObject found=" << fibEntry.getPrefix());
+    NFD_LOG_TRACE("lookupFib noForwardingHint found=" << fibEntry.getPrefix());
     return fibEntry;
   }
 
-  const Link& link = interest.getLink();
+  const DelegationList& fh = interest.getForwardingHint();
+  // Forwarding hint should have been stripped by incoming Interest pipeline when reaching producer region
+  BOOST_ASSERT(!m_forwarder.getNetworkRegionTable().isInProducerRegion(fh));
 
-  // Link should have been stripped by incoming Interest pipeline when reaching producer region
-  BOOST_ASSERT(!m_forwarder.getNetworkRegionTable().isInProducerRegion(link));
-
-  // has SelectedDelegation?
-  if (interest.hasSelectedDelegation()) {
-    // FIB lookup with SelectedDelegation
-    Name selectedDelegation = interest.getSelectedDelegation();
-    const fib::Entry& fibEntry = fib.findLongestPrefixMatch(selectedDelegation);
-    NFD_LOG_TRACE("lookupFib hasSelectedDelegation=" << selectedDelegation << " found=" << fibEntry.getPrefix());
-    return fibEntry;
-  }
-
-  // FIB lookup with first delegation Name
-  const fib::Entry& fibEntry0 = fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
-  // in default-free zone?
-  bool isDefaultFreeZone = !(fibEntry0.getPrefix().size() == 0 && fibEntry0.hasNextHops());
-  if (!isDefaultFreeZone) {
-    NFD_LOG_TRACE("lookupFib 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 = 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("lookupFib enterDefaultFreeZone setSelectedDelegation=" << delegationName);
-      return fibEntry;
+  const fib::Entry* fibEntry = nullptr;
+  for (const Delegation& del : fh) {
+    fibEntry = &fib.findLongestPrefixMatch(del.name);
+    if (fibEntry->hasNextHops()) {
+      if (fibEntry->getPrefix().size() == 0) {
+        // in consumer region, return the default route
+        NFD_LOG_TRACE("lookupFib inConsumerRegion found=" << fibEntry->getPrefix());
+      }
+      else {
+        // in default-free zone, use the first delegation that finds a FIB entry
+        NFD_LOG_TRACE("lookupFib delegation=" << del.name << " found=" << fibEntry->getPrefix());
+      }
+      return *fibEntry;
     }
+    BOOST_ASSERT(fibEntry->getPrefix().size() == 0); // only ndn:/ FIB entry can have zero nexthop
   }
-  BOOST_ASSERT(false);
-  return fibEntry0;
+  BOOST_ASSERT(fibEntry != nullptr && fibEntry->getPrefix().size() == 0);
+  return *fibEntry; // only occurs if no delegation finds a FIB nexthop
 }
 
 } // namespace fw