fw: rename BestRouteStrategy2 class to BestRouteStrategy

Also rename ad-hoc-forwarding.t.cpp to strategy-ad-hoc-face.t.cpp
and broadcast-medium.t.cpp to strategy-broadcast-medium.t.cpp,
for consistency with the other strategy-*.t.cpp test suites.

Change-Id: Ia8f5257260563732d74c7d58e35481b73a231f06
diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp
new file mode 100644
index 0000000..11ae600
--- /dev/null
+++ b/daemon/fw/best-route-strategy.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2021,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "best-route-strategy.hpp"
+#include "algorithm.hpp"
+#include "common/logger.hpp"
+
+namespace nfd {
+namespace fw {
+
+NFD_LOG_INIT(BestRouteStrategy);
+NFD_REGISTER_STRATEGY(BestRouteStrategy);
+
+const time::milliseconds BestRouteStrategy::RETX_SUPPRESSION_INITIAL(10);
+const time::milliseconds BestRouteStrategy::RETX_SUPPRESSION_MAX(250);
+
+BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
+  : Strategy(forwarder)
+  , ProcessNackTraits(this)
+  , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
+                      RetxSuppressionExponential::DEFAULT_MULTIPLIER,
+                      RETX_SUPPRESSION_MAX)
+{
+  ParsedInstanceName parsed = parseInstanceName(name);
+  if (!parsed.parameters.empty()) {
+    NDN_THROW(std::invalid_argument("BestRouteStrategy does not accept parameters"));
+  }
+  if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
+    NDN_THROW(std::invalid_argument(
+      "BestRouteStrategy does not support version " + to_string(*parsed.version)));
+  }
+  this->setInstanceName(makeInstanceName(name, getStrategyName()));
+}
+
+const Name&
+BestRouteStrategy::getStrategyName()
+{
+  static Name strategyName("/localhost/nfd/strategy/best-route/%FD%05");
+  return strategyName;
+}
+
+void
+BestRouteStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
+                                        const shared_ptr<pit::Entry>& pitEntry)
+{
+  RetxSuppressionResult suppression = m_retxSuppression.decidePerPitEntry(*pitEntry);
+  if (suppression == RetxSuppressionResult::SUPPRESS) {
+    NFD_LOG_DEBUG(interest << " from=" << ingress << " suppressed");
+    return;
+  }
+
+  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
+  const fib::NextHopList& nexthops = fibEntry.getNextHops();
+  auto it = nexthops.end();
+
+  if (suppression == RetxSuppressionResult::NEW) {
+    // forward to nexthop with lowest cost except downstream
+    it = std::find_if(nexthops.begin(), nexthops.end(), [&] (const auto& nexthop) {
+      return isNextHopEligible(ingress.face, interest, nexthop, pitEntry);
+    });
+
+    if (it == nexthops.end()) {
+      NFD_LOG_DEBUG(interest << " from=" << ingress << " noNextHop");
+
+      lp::NackHeader nackHeader;
+      nackHeader.setReason(lp::NackReason::NO_ROUTE);
+      this->sendNack(pitEntry, ingress.face, nackHeader);
+
+      this->rejectPendingInterest(pitEntry);
+      return;
+    }
+
+    Face& outFace = it->getFace();
+    NFD_LOG_DEBUG(interest << " from=" << ingress << " newPitEntry-to=" << outFace.getId());
+    this->sendInterest(pitEntry, outFace, interest);
+    return;
+  }
+
+  // find an unused upstream with lowest cost except downstream
+  it = std::find_if(nexthops.begin(), nexthops.end(),
+                    [&, now = time::steady_clock::now()] (const auto& nexthop) {
+                      return isNextHopEligible(ingress.face, interest, nexthop, pitEntry, true, now);
+                    });
+
+  if (it != nexthops.end()) {
+    Face& outFace = it->getFace();
+    this->sendInterest(pitEntry, outFace, interest);
+    NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-unused-to=" << outFace.getId());
+    return;
+  }
+
+  // find an eligible upstream that is used earliest
+  it = findEligibleNextHopWithEarliestOutRecord(ingress.face, interest, nexthops, pitEntry);
+  if (it == nexthops.end()) {
+    NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmitNoNextHop");
+  }
+  else {
+    Face& outFace = it->getFace();
+    this->sendInterest(pitEntry, outFace, interest);
+    NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-retry-to=" << outFace.getId());
+  }
+}
+
+void
+BestRouteStrategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
+                                    const shared_ptr<pit::Entry>& pitEntry)
+{
+  this->processNack(ingress.face, nack, pitEntry);
+}
+
+} // namespace fw
+} // namespace nfd