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 <<
" max-timeouts=" << m_nMaxTimeouts);
67 static const auto strategyName = Name(
"/localhost/nfd/strategy/asf").appendVersion(4);
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 ==
"max-timeouts") {
102 if (m_nMaxTimeouts <= 0)
103 NDN_THROW(std::invalid_argument(
"max-timeouts should be greater than 0"));
106 NDN_THROW(std::invalid_argument(
"Parameter should be probing-interval or max-timeouts"));
113 const shared_ptr<pit::Entry>& pitEntry)
115 const auto& fibEntry = this->
lookupFib(*pitEntry);
119 auto* faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry);
120 if (faceToUse ==
nullptr) {
121 NFD_LOG_DEBUG(interest <<
" new-interest from=" << ingress <<
" no-nexthop");
122 sendNoRouteNack(ingress.
face, pitEntry);
125 NFD_LOG_DEBUG(interest <<
" new-interest from=" << ingress <<
" forward-to=" << faceToUse->getId());
126 forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
127 sendProbe(interest, ingress, *faceToUse, fibEntry, pitEntry);
132 auto* faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry,
false);
133 if (faceToUse !=
nullptr) {
134 auto suppressResult = m_retxSuppression.
decidePerUpstream(*pitEntry, *faceToUse);
138 <<
" forward-to=" << faceToUse->getId() <<
" suppressed");
143 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" forward-to=" << faceToUse->getId());
144 auto* outRecord = forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
154 const auto& nexthops = fibEntry.getNextHops();
156 if (it == nexthops.end()) {
157 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" no eligible nexthop");
160 auto& outFace = it->getFace();
164 <<
" retry-to=" << outFace.getId() <<
" suppressed");
167 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" retry-to=" << outFace.getId());
170 auto* outRecord =
sendInterest(interest, outFace, pitEntry);
179 const shared_ptr<pit::Entry>& pitEntry)
182 if (namespaceInfo ==
nullptr) {
183 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-measurements");
189 if (faceInfo ==
nullptr) {
190 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-face-info");
194 auto outRecord = pitEntry->getOutRecord(ingress.
face);
195 if (outRecord == pitEntry->out_end()) {
196 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-out-record");
199 faceInfo->
recordRtt(time::steady_clock::now() - outRecord->getLastRenewed());
200 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress
213 const shared_ptr<pit::Entry>& pitEntry)
215 NFD_LOG_DEBUG(nack.getInterest() <<
" nack from=" << ingress <<
" reason=" << nack.getReason());
216 onTimeoutOrNack(pitEntry->getName(), ingress.
face.
getId(),
true);
220 AsfStrategy::forwardInterest(
const Interest& interest,
Face& outFace,
const fib::Entry& fibEntry,
221 const shared_ptr<pit::Entry>& pitEntry)
223 const auto& interestName = interest.getName();
224 auto faceId = outFace.
getId();
226 auto* outRecord =
sendInterest(interest, outFace, pitEntry);
236 [
this, name = interestName, faceId] {
237 onTimeoutOrNack(name, faceId,
false);
240 <<
" in " << time::duration_cast<time::milliseconds>(timeout));
247 AsfStrategy::sendProbe(
const Interest& interest,
const FaceEndpoint& ingress,
const Face& faceToUse,
248 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry)
253 Face* faceToProbe = m_probing.
getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
254 if (faceToProbe ==
nullptr)
257 Interest probeInterest(interest);
258 probeInterest.refreshNonce();
259 NFD_LOG_TRACE(
"Sending probe " << probeInterest <<
" to=" << faceToProbe->getId());
260 forwardInterest(probeInterest, *faceToProbe, fibEntry, pitEntry);
268 time::nanoseconds rtt;
269 time::nanoseconds srtt;
273 struct FaceStatsCompare
276 operator()(
const FaceStats& lhs,
const FaceStats& rhs)
const
278 time::nanoseconds lhsValue = getValueForSorting(lhs);
279 time::nanoseconds rhsValue = getValueForSorting(rhs);
282 return std::tie(lhsValue, lhs.cost) < std::tie(rhsValue, rhs.cost);
286 static time::nanoseconds
287 getValueForSorting(
const FaceStats& stats)
292 return time::nanoseconds::max();
295 return time::nanoseconds::max() / 2;
304 AsfStrategy::getBestFaceForForwarding(
const Interest& interest,
const Face& inFace,
305 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry,
308 std::set<FaceStats, FaceStatsCompare> rankedFaces;
310 auto now = time::steady_clock::now();
311 for (
const auto& nh : fibEntry.getNextHops()) {
316 const FaceInfo* info = m_measurements.
getFaceInfo(fibEntry, interest.getName(), nh.getFace().getId());
317 if (info ==
nullptr) {
322 rankedFaces.insert({&nh.getFace(), info->getLastRtt(), info->getSrtt(), nh.getCost()});
326 auto it = rankedFaces.begin();
327 return it != rankedFaces.end() ? it->face :
nullptr;
331 AsfStrategy::onTimeoutOrNack(
const Name& interestName,
FaceId faceId,
bool isNack)
333 NamespaceInfo* namespaceInfo = m_measurements.
getNamespaceInfo(interestName);
334 if (namespaceInfo ==
nullptr) {
335 NFD_LOG_TRACE(interestName <<
" FibEntry has been removed since timeout scheduling");
339 FaceInfo* fiPtr = namespaceInfo->getFaceInfo(faceId);
340 if (fiPtr ==
nullptr) {
341 NFD_LOG_TRACE(interestName <<
" FaceInfo id=" << faceId <<
" has been removed since timeout scheduling");
345 auto& faceInfo = *fiPtr;
349 if (nTimeouts < m_nMaxTimeouts && !isNack) {
350 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts <<
" ignoring");
352 namespaceInfo->extendFaceInfoLifetime(faceInfo, faceId);
356 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts);
362 AsfStrategy::sendNoRouteNack(Face& face,
const shared_ptr<pit::Entry>& pitEntry)
364 lp::NackHeader nackHeader;
365 nackHeader.setReason(lp::NackReason::NO_ROUTE);
366 this->
sendNack(nackHeader, face, pitEntry);
Represents a face-endpoint pair in the forwarder.
Main class of NFD's forwarding engine.
generalization of a network interface
const Name & getPrefix() const
a retransmission suppression decision algorithm that suppresses retransmissions using exponential bac...
void incrementIntervalForOutRecord(pit::OutRecord &outRecord)
Increment the suppression interval for out record.
RetxSuppressionResult decidePerUpstream(pit::Entry &pitEntry, Face &outFace)
determines whether Interest is a retransmission per upstream and if so, whether it shall be forwarded...
Represents a forwarding strategy.
void setInstanceName(const Name &name)
Set strategy instance name.
void rejectPendingInterest(const shared_ptr< pit::Entry > &pitEntry)
Schedule the PIT entry for immediate deletion.
const fib::Entry & lookupFib(const pit::Entry &pitEntry) const
Performs a FIB lookup, considering Link object if present.
bool sendNack(const lp::NackHeader &header, Face &egress, const shared_ptr< pit::Entry > &pitEntry)
Send a Nack packet.
pit::OutRecord * sendInterest(const Interest &interest, Face &egress, const shared_ptr< pit::Entry > &pitEntry)
Send an Interest packet.
static ParsedInstanceName parseInstanceName(const Name &input)
Parse a strategy instance name.
void setExpiryTimer(const shared_ptr< pit::Entry > &pitEntry, time::milliseconds duration)
Schedule the PIT entry to be erased after duration.
static Name makeInstanceName(const Name &input, const Name &strategyName)
Construct a strategy instance name.
NamespaceInfo & getOrCreateNamespaceInfo(const fib::Entry &fibEntry, const Name &prefix)
FaceInfo & getOrCreateFaceInfo(const fib::Entry &fibEntry, const Name &interestName, FaceId faceId)
FaceInfo * getFaceInfo(const fib::Entry &fibEntry, const Name &interestName, FaceId faceId)
NamespaceInfo * getNamespaceInfo(const Name &prefix)
Adaptive SRTT-based Forwarding Strategy.
static const Name & getStrategyName()
void afterReceiveNack(const lp::Nack &nack, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger after a Nack is received.
AsfStrategy(Forwarder &forwarder, const Name &name=getStrategyName())
void afterReceiveInterest(const Interest &interest, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger after an Interest is received.
void beforeSatisfyInterest(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger before a PIT entry is satisfied.
Strategy information for each face in a namespace.
void cancelTimeout(const Name &prefix)
bool isTimeoutScheduled() const
size_t getNTimeouts() const
time::nanoseconds getSrtt() const
void setNTimeouts(size_t nTimeouts)
time::nanoseconds getLastRtt() const
static const time::nanoseconds RTT_TIMEOUT
void recordTimeout(const Name &interestName)
static const time::nanoseconds RTT_NO_MEASUREMENT
void recordRtt(time::nanoseconds rtt)
time::nanoseconds scheduleTimeout(const Name &interestName, scheduler::EventCallback cb)
Stores strategy information about each face in this namespace.
FaceInfo * getFaceInfo(FaceId faceId)
void extendFaceInfoLifetime(FaceInfo &info, FaceId faceId)
Face * getFaceToProbe(const Face &inFace, const Interest &interest, const fib::Entry &fibEntry, const Face &faceUsed)
bool isProbingNeeded(const fib::Entry &fibEntry, const Name &interestName)
time::milliseconds getProbingInterval() const
void setProbingInterval(size_t probingInterval)
void afterForwardingProbe(const fib::Entry &fibEntry, const Name &interestName)
Contains information about an Interest toward an outgoing face.
This file contains common algorithms used by forwarding strategies.
#define NFD_LOG_INIT(name)
uint64_t FaceId
Identifies a face.
NFD_REGISTER_STRATEGY(AsfStrategy)
static uint64_t getParamValue(const std::string ¶m, const std::string &value)
@ SUPPRESS
Interest is retransmission and should be suppressed.
@ FORWARD
Interest is retransmission and should be forwarded.
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
bool isNextHopEligible(const Face &inFace, const Interest &interest, const fib::NextHop &nexthop, const shared_ptr< pit::Entry > &pitEntry, bool wantUnused, time::steady_clock::time_point now)
bool hasPendingOutRecords(const pit::Entry &pitEntry)
determine whether pitEntry has any pending out-records
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents,...
optional< uint64_t > version
whether strategyName contains a version component
PartialName parameters
parameter components