fw: refine pipelines, dispatch to strategy
refs #1345 #1255
Change-Id: If1cfc26049f87318103fc09c3b211ebf1eb3ebaa
diff --git a/daemon/fw/available-strategies.cpp b/daemon/fw/available-strategies.cpp
new file mode 100644
index 0000000..ec29cdd
--- /dev/null
+++ b/daemon/fw/available-strategies.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "best-route-strategy.hpp"
+#include "broadcast-strategy.hpp"
+#include "client-control-strategy.hpp"
+#include "ncc-strategy.hpp"
+
+namespace nfd {
+namespace fw {
+
+shared_ptr<Strategy>
+makeDefaultStrategy(Forwarder& forwarder)
+{
+ return make_shared<BestRouteStrategy>(boost::ref(forwarder));
+}
+
+template<typename S>
+inline void
+installStrategy(Forwarder& forwarder)
+{
+ StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
+ if (!strategyChoice.hasStrategy(S::STRATEGY_NAME)) {
+ strategyChoice.install(make_shared<S>(boost::ref(forwarder)));
+ }
+}
+
+void
+installStrategies(Forwarder& forwarder)
+{
+ installStrategy<BestRouteStrategy>(forwarder);
+ installStrategy<BroadcastStrategy>(forwarder);
+ installStrategy<ClientControlStrategy>(forwarder);
+ installStrategy<NccStrategy>(forwarder);
+}
+
+} // namespace fw
+} // namespace nfd
diff --git a/daemon/fw/available-strategies.hpp b/daemon/fw/available-strategies.hpp
new file mode 100644
index 0000000..db1422b
--- /dev/null
+++ b/daemon/fw/available-strategies.hpp
@@ -0,0 +1,24 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_FW_AVAILABLE_STRATEGIES_HPP
+#define NFD_FW_AVAILABLE_STRATEGIES_HPP
+
+#include "strategy.hpp"
+
+namespace nfd {
+namespace fw {
+
+shared_ptr<Strategy>
+makeDefaultStrategy(Forwarder& forwarder);
+
+void
+installStrategies(Forwarder& forwarder);
+
+} // namespace fw
+} // namespace nfd
+
+#endif // NFD_FW_AVAILABLE_STRATEGIES_HPP
diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp
index 19458e9..8f87270 100644
--- a/daemon/fw/best-route-strategy.cpp
+++ b/daemon/fw/best-route-strategy.cpp
@@ -9,8 +9,10 @@
namespace nfd {
namespace fw {
-BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder)
- : Strategy(forwarder, "ndn:/localhost/nfd/strategy/best-route")
+const Name BestRouteStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route");
+
+BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
+ : Strategy(forwarder, name)
{
}
diff --git a/daemon/fw/best-route-strategy.hpp b/daemon/fw/best-route-strategy.hpp
index 4d7a5b0..0f087f8 100644
--- a/daemon/fw/best-route-strategy.hpp
+++ b/daemon/fw/best-route-strategy.hpp
@@ -19,8 +19,7 @@
class BestRouteStrategy : public Strategy
{
public:
- explicit
- BestRouteStrategy(Forwarder& forwarder);
+ BestRouteStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
virtual
~BestRouteStrategy();
@@ -30,6 +29,9 @@
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry);
+
+public:
+ static const Name STRATEGY_NAME;
};
} // namespace fw
diff --git a/daemon/fw/broadcast-strategy.cpp b/daemon/fw/broadcast-strategy.cpp
index 4cc4e5f..3e8c2bf 100644
--- a/daemon/fw/broadcast-strategy.cpp
+++ b/daemon/fw/broadcast-strategy.cpp
@@ -9,8 +9,10 @@
namespace nfd {
namespace fw {
-BroadcastStrategy::BroadcastStrategy(Forwarder& forwarder)
- : Strategy(forwarder, "ndn:/localhost/nfd/strategy/broadcast")
+const Name BroadcastStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/broadcast");
+
+BroadcastStrategy::BroadcastStrategy(Forwarder& forwarder, const Name& name)
+ : Strategy(forwarder, name)
{
}
diff --git a/daemon/fw/broadcast-strategy.hpp b/daemon/fw/broadcast-strategy.hpp
index 41868ed..69c6ce6 100644
--- a/daemon/fw/broadcast-strategy.hpp
+++ b/daemon/fw/broadcast-strategy.hpp
@@ -19,8 +19,7 @@
class BroadcastStrategy : public Strategy
{
public:
- explicit
- BroadcastStrategy(Forwarder& forwarder);
+ BroadcastStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
virtual
~BroadcastStrategy();
@@ -30,6 +29,9 @@
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry);
+
+public:
+ static const Name STRATEGY_NAME;
};
} // namespace fw
diff --git a/daemon/fw/client-control-strategy.cpp b/daemon/fw/client-control-strategy.cpp
index eacd604..5028879 100644
--- a/daemon/fw/client-control-strategy.cpp
+++ b/daemon/fw/client-control-strategy.cpp
@@ -11,8 +11,10 @@
NFD_LOG_INIT("ClientControlStrategy");
-ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder)
- : BestRouteStrategy(forwarder)
+const Name ClientControlStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/client-control");
+
+ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder, const Name& name)
+ : BestRouteStrategy(forwarder, name)
{
}
diff --git a/daemon/fw/client-control-strategy.hpp b/daemon/fw/client-control-strategy.hpp
index 48f45b3..e5e8539 100644
--- a/daemon/fw/client-control-strategy.hpp
+++ b/daemon/fw/client-control-strategy.hpp
@@ -18,8 +18,7 @@
class ClientControlStrategy : public BestRouteStrategy
{
public:
- explicit
- ClientControlStrategy(Forwarder& forwarder);
+ ClientControlStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
virtual
~ClientControlStrategy();
@@ -29,6 +28,9 @@
const Interest& interest,
shared_ptr<fib::Entry> fibEntry,
shared_ptr<pit::Entry> pitEntry);
+
+public:
+ static const Name STRATEGY_NAME;
};
} // namespace fw
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 6c9f3ce..3a8a91f 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -5,14 +5,16 @@
*/
#include "forwarder.hpp"
-#include "core/logger.hpp"
-#include "best-route-strategy.hpp"
+#include "available-strategies.hpp"
namespace nfd {
NFD_LOG_INIT("Forwarder");
-const Name Forwarder::s_localhostName("ndn:/localhost");
+using fw::Strategy;
+
+const ndn::Milliseconds Forwarder::DEFAULT_INTEREST_LIFETIME(static_cast<ndn::Milliseconds>(4000));
+const Name Forwarder::LOCALHOST_NAME("ndn:/localhost");
Forwarder::Forwarder()
: m_faceTable(*this)
@@ -20,24 +22,29 @@
, m_fib(m_nameTree)
, m_pit(m_nameTree)
, m_measurements(m_nameTree)
- , m_strategyChoice(m_nameTree, make_shared<fw::BestRouteStrategy>(boost::ref(*this)))
+ , m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
{
- m_strategy = make_shared<fw::BestRouteStrategy>(boost::ref(*this));
+ fw::installStrategies(*this);
}
void
Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
{
// receive Interest
- NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() << " interest=" << interest.getName());
+ NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
+ " interest=" << interest.getName());
const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
+ if (interest.getInterestLifetime() < 0) {
+ const_cast<Interest&>(interest).setInterestLifetime(DEFAULT_INTEREST_LIFETIME);
+ }
// /localhost scope control
- bool violatesLocalhost = !inFace.isLocal() &&
- s_localhostName.isPrefixOf(interest.getName());
- if (violatesLocalhost) {
- NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId()
- << " interest=" << interest.getName() << " violates /localhost");
+ bool isViolatingLocalhost = !inFace.isLocal() &&
+ LOCALHOST_NAME.isPrefixOf(interest.getName());
+ if (isViolatingLocalhost) {
+ NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
+ " interest=" << interest.getName() << " violates /localhost");
+ // (drop)
return;
}
@@ -55,9 +62,9 @@
// cancel unsatisfy & straggler timer
this->cancelUnsatisfyAndStragglerTimer(pitEntry);
+ // is pending?
const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
bool isPending = inRecords.begin() == inRecords.end();
-
if (!isPending) {
// CS lookup
const Data* csMatch = m_cs.find(interest);
@@ -73,46 +80,71 @@
// insert InRecord
pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
- // app chosen nexthops
- bool isAppChosenNexthops = false; // TODO get from local control header
- if (isAppChosenNexthops) {
- // TODO foreach chosen nexthop: goto outgoing Interest pipeline
- return;
- }
-
// FIB lookup
shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
// dispatch to strategy
- this->dispatchToStrategy(inFace, interest, fibEntry, pitEntry);
+ this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
+ boost::cref(inFace), boost::cref(interest), fibEntry, pitEntry));
}
void
Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
shared_ptr<pit::Entry> pitEntry)
{
- NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() << " interest=" << interest.getName());
+ NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
+ " interest=" << interest.getName());
- // do nothing, which means Interest is dropped
+ // (drop)
+}
+
+/** \brief compare two InRecords for picking outgoing Interest
+ * \return true if b is preferred over a
+ *
+ * This function should be passed to std::max_element over InRecordCollection.
+ * The outgoing Interest picked is the last incoming Interest
+ * that does not come from outFace.
+ * If all InRecords come from outFace, it's fine to pick that. This happens when
+ * there's only one InRecord that comes from outFace. The legit use is for
+ * vehicular network; otherwise, strategy shouldn't send to the sole inFace.
+ */
+static inline bool
+compare_pickInterest(const pit::InRecord& a, const pit::InRecord& b, const Face* outFace)
+{
+ bool isOutFaceA = a.getFace().get() == outFace;
+ bool isOutFaceB = b.getFace().get() == outFace;
+
+ if (!isOutFaceA && isOutFaceB) {
+ return false;
+ }
+ if (isOutFaceA && !isOutFaceB) {
+ return true;
+ }
+
+ return a.getLastRenewed() > b.getLastRenewed();
}
void
Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
{
- NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() << " interest=" << pitEntry->getName());
+ NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
+ " interest=" << pitEntry->getName());
// /localhost scope control
- bool violatesLocalhost = !outFace.isLocal() &&
- s_localhostName.isPrefixOf(pitEntry->getName());
- if (violatesLocalhost) {
- NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId()
- << " interest=" << pitEntry->getName() << " violates /localhost");
+ bool isViolatingLocalhost = !outFace.isLocal() &&
+ LOCALHOST_NAME.isPrefixOf(pitEntry->getName());
+ if (isViolatingLocalhost) {
+ NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
+ " interest=" << pitEntry->getName() << " violates /localhost");
return;
}
// pick Interest
- const Interest& interest = pitEntry->getInterest();
- // TODO pick the last incoming Interest
+ const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
+ pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
+ inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
+ BOOST_ASSERT(pickedInRecord != inRecords.end());
+ const Interest& interest = pickedInRecord->getInterest();
// insert OutRecord
pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
@@ -139,9 +171,10 @@
NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
// invoke PIT unsatisfied callback
- // TODO
+ this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
+ pitEntry));
- // PIT erase
+ // PIT delete
m_pit.erase(pitEntry);
}
@@ -153,11 +186,12 @@
const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
// /localhost scope control
- bool violatesLocalhost = !inFace.isLocal() &&
- s_localhostName.isPrefixOf(data.getName());
- if (violatesLocalhost) {
- NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId()
- << " data=" << data.getName() << " violates /localhost");
+ bool isViolatingLocalhost = !inFace.isLocal() &&
+ LOCALHOST_NAME.isPrefixOf(data.getName());
+ if (isViolatingLocalhost) {
+ NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
+ " data=" << data.getName() << " violates /localhost");
+ // (drop)
return;
}
@@ -199,7 +233,8 @@
this->setStragglerTimer(pitEntry);
// invoke PIT satisfy callback
- // TODO
+ this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyPendingInterest, _1,
+ pitEntry, boost::cref(inFace), boost::cref(data)));
}
// foreach pending downstream
@@ -214,13 +249,15 @@
Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
{
// accept to cache?
- bool acceptToCache = false;// TODO decision
+ bool acceptToCache = inFace.isLocal();
if (acceptToCache) {
// CS insert
- m_cs.insert(data);
+ m_cs.insert(data, true);
}
- NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() << " data=" << data.getName() << " acceptToCache=" << acceptToCache);
+ NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
+ " data=" << data.getName() <<
+ (acceptToCache ? " cached" : " not cached"));
}
void
@@ -229,16 +266,16 @@
NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
// /localhost scope control
- bool violatesLocalhost = !outFace.isLocal() &&
- s_localhostName.isPrefixOf(data.getName());
- if (violatesLocalhost) {
- NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId()
- << " data=" << data.getName() << " violates /localhost");
+ bool isViolatingLocalhost = !outFace.isLocal() &&
+ LOCALHOST_NAME.isPrefixOf(data.getName());
+ if (isViolatingLocalhost) {
+ NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
+ " data=" << data.getName() << " violates /localhost");
+ // (drop)
return;
}
- // traffic manager
- // pass through
+ // TODO traffic manager
// send Data
outFace.sendData(data);
@@ -284,14 +321,4 @@
scheduler::cancel(pitEntry->m_stragglerTimer);
}
-void
-Forwarder::dispatchToStrategy(const Face& inFace,
- const Interest& interest,
- shared_ptr<fib::Entry> fibEntry,
- shared_ptr<pit::Entry> pitEntry)
-{
- m_strategy->afterReceiveInterest(inFace, interest, fibEntry, pitEntry);
- // TODO dispatch according to fibEntry
-}
-
} // namespace nfd
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index d9d23bc..8e7c0d2 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -130,11 +130,15 @@
VIRTUAL_WITH_TESTS void
cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry);
- VIRTUAL_WITH_TESTS void
- dispatchToStrategy(const Face& inFace,
- const Interest& interest,
- shared_ptr<fib::Entry> fibEntry,
- shared_ptr<pit::Entry> pitEntry);
+ /// call trigger (method) on the effective strategy of pitEntry
+#ifdef WITH_TESTS
+ virtual void
+ dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, function<void(fw::Strategy*)> trigger);
+#else
+ template<class Function>
+ void
+ dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, Function trigger);
+#endif
private:
FaceTable m_faceTable;
@@ -147,10 +151,8 @@
Measurements m_measurements;
StrategyChoice m_strategyChoice;
- /// the active strategy (only one strategy in mock)
- shared_ptr<fw::Strategy> m_strategy;
-
- static const Name s_localhostName;
+ static const ndn::Milliseconds DEFAULT_INTEREST_LIFETIME;
+ static const Name LOCALHOST_NAME;
// allow Strategy (base class) to enter pipelines
friend class fw::Strategy;
@@ -222,6 +224,19 @@
return m_strategyChoice;
}
+#ifdef WITH_TESTS
+inline void
+Forwarder::dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, function<void(fw::Strategy*)> trigger)
+#else
+template<class Function>
+inline void
+Forwarder::dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, Function trigger)
+#endif
+{
+ fw::Strategy& strategy = m_strategyChoice.findEffectiveStrategy(*pitEntry);
+ trigger(&strategy);
+}
+
} // namespace nfd
#endif // NFD_FW_FORWARDER_HPP
diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp
index 101e847..d8928f5 100644
--- a/daemon/fw/ncc-strategy.cpp
+++ b/daemon/fw/ncc-strategy.cpp
@@ -9,8 +9,10 @@
namespace nfd {
namespace fw {
-NccStrategy::NccStrategy(Forwarder& forwarder)
- : Strategy(forwarder, "ndn:/localhost/nfd/strategy/ncc")
+const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc");
+
+NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
+ : Strategy(forwarder, name)
{
}
diff --git a/daemon/fw/ncc-strategy.hpp b/daemon/fw/ncc-strategy.hpp
index 6e915aa..ff9bcf3 100644
--- a/daemon/fw/ncc-strategy.hpp
+++ b/daemon/fw/ncc-strategy.hpp
@@ -17,8 +17,7 @@
class NccStrategy : public Strategy
{
public:
- explicit
- NccStrategy(Forwarder& forwarder);
+ NccStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
virtual
~NccStrategy();
@@ -102,6 +101,9 @@
void
timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak);
+public:
+ static const Name STRATEGY_NAME;
+
protected:
static const time::Duration DEFER_FIRST_WITHOUT_BEST_FACE;
static const time::Duration DEFER_RANGE_WITHOUT_BEST_FACE;
diff --git a/daemon/table/pit-face-record.hpp b/daemon/table/pit-face-record.hpp
index 2068729..3ad0462 100644
--- a/daemon/table/pit-face-record.hpp
+++ b/daemon/table/pit-face-record.hpp
@@ -38,7 +38,7 @@
getLastRenewed() const;
/** \brief gives the time point this record expires
- * \return{ getLastRenewed() + InterestLifetime }
+ * \return getLastRenewed() + InterestLifetime
*/
time::Point
getExpiry() const;
diff --git a/daemon/table/pit-in-record.cpp b/daemon/table/pit-in-record.cpp
index 6963da2..573ee85 100644
--- a/daemon/table/pit-in-record.cpp
+++ b/daemon/table/pit-in-record.cpp
@@ -19,6 +19,12 @@
{
}
+void
+InRecord::update(const Interest& interest)
+{
+ this->FaceRecord::update(interest);
+ m_interest = const_cast<Interest&>(interest).shared_from_this();
+}
} // namespace pit
} // namespace nfd
diff --git a/daemon/table/pit-in-record.hpp b/daemon/table/pit-in-record.hpp
index 1f4e1e1..3dd7420 100644
--- a/daemon/table/pit-in-record.hpp
+++ b/daemon/table/pit-in-record.hpp
@@ -20,10 +20,26 @@
public:
explicit
InRecord(shared_ptr<Face> face);
-
+
InRecord(const InRecord& other);
+
+ void
+ update(const Interest& interest);
+
+ const Interest&
+ getInterest() const;
+
+private:
+ shared_ptr<Interest> m_interest;
};
+inline const Interest&
+InRecord::getInterest() const
+{
+ BOOST_ASSERT(static_cast<bool>(m_interest));
+ return *m_interest;
+}
+
} // namespace pit
} // namespace nfd