38 const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
39 const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
43 , m_measurements(getMeasurements())
44 , m_probing(m_measurements)
45 , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
55 NDN_THROW(std::invalid_argument(
56 "AsfStrategy does not support version " + to_string(*parsed.
version)));
61 <<
" n-silent-timeouts=" << m_maxSilentTimeouts);
67 static Name strategyName(
"/localhost/nfd/strategy/asf/%FD%03");
75 if (!value.empty() && value[0] ==
'-')
76 NDN_THROW(boost::bad_lexical_cast());
78 return boost::lexical_cast<uint64_t>(value);
80 catch (
const boost::bad_lexical_cast&) {
81 NDN_THROW(std::invalid_argument(
"Value of " + param +
" must be a non-negative integer"));
86 AsfStrategy::processParams(
const PartialName& parsed)
88 for (
const auto& component : parsed) {
89 std::string parsedStr(reinterpret_cast<const char*>(component.value()), component.value_size());
90 auto n = parsedStr.find(
"~");
91 if (n == std::string::npos) {
92 NDN_THROW(std::invalid_argument(
"Format is <parameter>~<value>"));
95 auto f = parsedStr.substr(0, n);
96 auto s = parsedStr.substr(n + 1);
97 if (f ==
"probing-interval") {
100 else if (f ==
"n-silent-timeouts") {
104 NDN_THROW(std::invalid_argument(
"Parameter should be probing-interval or n-silent-timeouts"));
111 const shared_ptr<pit::Entry>& pitEntry)
116 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" suppressed");
124 if (nexthops.size() == 0) {
125 NFD_LOG_DEBUG(interest <<
" new-interest from=" << ingress <<
" no-nexthop");
126 sendNoRouteNack(ingress, pitEntry);
130 Face* faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry);
131 if (faceToUse !=
nullptr) {
132 NFD_LOG_DEBUG(interest <<
" new-interest from=" << ingress <<
" forward-to=" << faceToUse->
getId());
133 forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
136 sendProbe(interest, ingress, *faceToUse, fibEntry, pitEntry);
139 NFD_LOG_DEBUG(interest <<
" new-interest from=" << ingress <<
" no-nexthop");
140 sendNoRouteNack(ingress, pitEntry);
145 Face* faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry,
false);
147 if (faceToUse !=
nullptr) {
148 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" forward-to=" << faceToUse->
getId());
149 forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
155 auto it = nexthops.end();
157 if (it == nexthops.end()) {
158 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" no-nexthop");
162 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" retry-to=" << egress);
172 if (namespaceInfo ==
nullptr) {
173 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-measurements");
179 if (faceInfo ==
nullptr) {
180 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-face-info");
184 auto outRecord = pitEntry->getOutRecord(ingress.
face);
185 if (outRecord == pitEntry->out_end()) {
186 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-out-record");
189 faceInfo->
recordRtt(time::steady_clock::now() - outRecord->getLastRenewed());
190 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress
202 const shared_ptr<pit::Entry>& pitEntry)
204 NFD_LOG_DEBUG(nack.getInterest() <<
" nack from=" << ingress <<
" reason=" << nack.getReason());
205 onTimeout(pitEntry->getName(), ingress.
face.
getId());
209 AsfStrategy::forwardInterest(
const Interest& interest,
Face& outFace,
const fib::Entry& fibEntry,
210 const shared_ptr<pit::Entry>& pitEntry,
bool wantNewNonce)
215 Interest probeInterest(interest);
216 probeInterest.refreshNonce();
217 NFD_LOG_TRACE(
"Sending probe for " << probeInterest <<
" to=" << egress);
232 [
this, name = interest.getName(), faceId = egress.face.getId()] {
233 onTimeout(name, faceId);
236 <<
" in " << time::duration_cast<time::milliseconds>(timeout) <<
" ms");
241 AsfStrategy::sendProbe(
const Interest& interest,
const FaceEndpoint& ingress,
const Face& faceToUse,
242 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry)
248 if (faceToProbe ==
nullptr)
251 forwardInterest(interest, *faceToProbe, fibEntry, pitEntry,
true);
258 time::nanoseconds rtt;
259 time::nanoseconds srtt;
263 struct FaceStatsCompare
266 operator()(
const FaceStats& lhs,
const FaceStats& rhs)
const 268 time::nanoseconds lhsValue = getValueForSorting(lhs);
269 time::nanoseconds rhsValue = getValueForSorting(rhs);
272 return std::tie(lhsValue, lhs.cost) < std::tie(rhsValue, rhs.cost);
276 static time::nanoseconds
277 getValueForSorting(
const FaceStats& stats)
282 return time::nanoseconds::max();
285 return time::nanoseconds::max() / 2;
294 AsfStrategy::getBestFaceForForwarding(
const Interest& interest,
const Face& inFace,
295 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry,
298 std::set<FaceStats, FaceStatsCompare> rankedFaces;
300 auto now = time::steady_clock::now();
306 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, nh.getFace().getId());
307 if (info ==
nullptr) {
312 rankedFaces.insert({&nh.getFace(), info->
getLastRtt(), info->
getSrtt(), nh.getCost()});
316 auto it = rankedFaces.begin();
317 return it != rankedFaces.end() ? it->face :
nullptr;
321 AsfStrategy::onTimeout(
const Name& interestName,
FaceId faceId)
323 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
324 if (namespaceInfo ==
nullptr) {
325 NFD_LOG_TRACE(interestName <<
" FibEntry has been removed since timeout scheduling");
330 if (fiPtr ==
nullptr) {
331 NFD_LOG_TRACE(interestName <<
" FaceInfo id=" << faceId <<
" has been removed since timeout scheduling");
335 auto& faceInfo = *fiPtr;
337 faceInfo.setNSilentTimeouts(nTimeouts);
339 if (nTimeouts <= m_maxSilentTimeouts) {
340 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts <<
" ignoring");
343 faceInfo.cancelTimeout(interestName);
346 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts);
347 faceInfo.recordTimeout(interestName);
352 AsfStrategy::sendNoRouteNack(
const FaceEndpoint& ingress,
const shared_ptr<pit::Entry>& pitEntry)
354 lp::NackHeader nackHeader;
355 nackHeader.setReason(lp::NackReason::NO_ROUTE);
356 this->
sendNack(pitEntry, ingress, nackHeader);
void cancelTimeout(const Name &prefix)
Main class of NFD's forwarding engine.
void setInstanceName(const Name &name)
set strategy instance name
static const time::nanoseconds RTT_NO_MEASUREMENT
static const time::nanoseconds RTT_TIMEOUT
void afterForwardingProbe(const fib::Entry &fibEntry, const Interest &interest)
void extendFaceInfoLifetime(FaceInfo &info, FaceId faceId)
size_t getNSilentTimeouts() const
static const Name & getStrategyName()
NamespaceInfo * getNamespaceInfo(const Name &prefix)
void sendNack(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &egress, const lp::NackHeader &header)
send Nack to egress
fib::NextHopList::const_iterator findEligibleNextHopWithEarliestOutRecord(const Face &inFace, const Interest &interest, const fib::NextHopList &nexthops, const shared_ptr< pit::Entry > &pitEntry)
pick an eligible NextHop with earliest out-record
NFD_REGISTER_STRATEGY(AsfStrategy)
void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data) override
trigger before PIT entry is satisfied
FaceInfo & getOrCreateFaceInfo(const fib::Entry &fibEntry, const Interest &interest, FaceId faceId)
Interest is retransmission and should be suppressed.
static uint64_t getParamValue(const std::string ¶m, const std::string &value)
static Name makeInstanceName(const Name &input, const Name &strategyName)
construct a strategy instance name
const fib::Entry & lookupFib(const pit::Entry &pitEntry) const
performs a FIB lookup, considering Link object if present
time::milliseconds getProbingInterval() const
void sendInterest(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &egress, const Interest &interest)
send Interest to egress
void afterReceiveNack(const FaceEndpoint &ingress, const lp::Nack &nack, const shared_ptr< pit::Entry > &pitEntry) override
trigger after Nack is received
Represents a face-endpoint pair in the forwarder.
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
time::nanoseconds getLastRtt() const
Interest is new (not a retransmission)
time::nanoseconds scheduleTimeout(const Name &interestName, scheduler::EventCallback cb)
bool isNextHopEligible(const Face &inFace, const Interest &interest, const fib::NextHop &nexthop, const shared_ptr< pit::Entry > &pitEntry, bool wantUnused, time::steady_clock::TimePoint now)
determines whether a NextHop is eligible i.e.
const Name & getPrefix() const
a retransmission suppression decision algorithm that suppresses retransmissions using exponential bac...
NamespaceInfo & getOrCreateNamespaceInfo(const fib::Entry &fibEntry, const Interest &interest)
generalization of a network interface
bool isProbingNeeded(const fib::Entry &fibEntry, const Interest &interest)
Represents a collection of nexthops.
PartialName parameters
parameter components
Stores strategy information about each face in this namespace.
RetxSuppressionResult decidePerPitEntry(pit::Entry &pitEntry)
determines whether Interest is a retransmission per pit entry and if so, whether it shall be forwarde...
represents a forwarding strategy
This file contains common algorithms used by forwarding strategies.
const NextHopList & getNextHops() const
#define NFD_LOG_INIT(name)
static ParsedInstanceName parseInstanceName(const Name &input)
parse a strategy instance name
void setProbingInterval(size_t probingInterval)
Face * getFaceToProbe(const Face &inFace, const Interest &interest, const fib::Entry &fibEntry, const Face &faceUsed)
void afterReceiveInterest(const FaceEndpoint &ingress, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry) override
trigger after Interest is received
void recordRtt(time::nanoseconds rtt)
uint64_t FaceId
Identifies a face.
bool isTimeoutScheduled() const
void rejectPendingInterest(const shared_ptr< pit::Entry > &pitEntry)
schedule the PIT entry for immediate deletion
Strategy information for each face in a namespace.
AsfStrategy(Forwarder &forwarder, const Name &name=getStrategyName())
optional< uint64_t > version
whether strategyName contains a version component
FaceInfo * getFaceInfo(FaceId faceId)
time::nanoseconds getSrtt() const