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_nMaxSilentTimeouts);
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.
face, 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.
face, 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");
161 NFD_LOG_DEBUG(interest <<
" retx-interest from=" << ingress <<
" retry-to=" << it->getFace().getId());
171 if (namespaceInfo ==
nullptr) {
172 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-measurements");
178 if (faceInfo ==
nullptr) {
179 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-face-info");
183 auto outRecord = pitEntry->getOutRecord(ingress.
face);
184 if (outRecord == pitEntry->out_end()) {
185 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress <<
" no-out-record");
188 faceInfo->
recordRtt(time::steady_clock::now() - outRecord->getLastRenewed());
189 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 onTimeoutOrNack(pitEntry->getName(), ingress.
face.
getId(),
true);
209 AsfStrategy::forwardInterest(
const Interest& interest,
Face& outFace,
const fib::Entry& fibEntry,
210 const shared_ptr<pit::Entry>& pitEntry,
bool wantNewNonce)
212 auto faceId = outFace.
getId();
216 Interest probeInterest(interest);
217 probeInterest.refreshNonce();
218 NFD_LOG_TRACE(
"Sending probe for " << probeInterest <<
" to=" << faceId);
233 [
this, name = interest.getName(), faceId] {
234 onTimeoutOrNack(name, faceId,
false);
237 <<
" in " << time::duration_cast<time::milliseconds>(timeout) <<
" ms");
242 AsfStrategy::sendProbe(
const Interest& interest,
const FaceEndpoint& ingress,
const Face& faceToUse,
243 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry)
249 if (faceToProbe ==
nullptr)
252 forwardInterest(interest, *faceToProbe, fibEntry, pitEntry,
true);
259 time::nanoseconds rtt;
260 time::nanoseconds srtt;
264 struct FaceStatsCompare
267 operator()(
const FaceStats& lhs,
const FaceStats& rhs)
const 269 time::nanoseconds lhsValue = getValueForSorting(lhs);
270 time::nanoseconds rhsValue = getValueForSorting(rhs);
273 return std::tie(lhsValue, lhs.cost) < std::tie(rhsValue, rhs.cost);
277 static time::nanoseconds
278 getValueForSorting(
const FaceStats& stats)
283 return time::nanoseconds::max();
286 return time::nanoseconds::max() / 2;
295 AsfStrategy::getBestFaceForForwarding(
const Interest& interest,
const Face& inFace,
296 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry,
299 std::set<FaceStats, FaceStatsCompare> rankedFaces;
301 auto now = time::steady_clock::now();
307 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, nh.getFace().getId());
308 if (info ==
nullptr) {
313 rankedFaces.insert({&nh.getFace(), info->
getLastRtt(), info->
getSrtt(), nh.getCost()});
317 auto it = rankedFaces.begin();
318 return it != rankedFaces.end() ? it->face :
nullptr;
322 AsfStrategy::onTimeoutOrNack(
const Name& interestName,
FaceId faceId,
bool isNack)
324 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
325 if (namespaceInfo ==
nullptr) {
326 NFD_LOG_TRACE(interestName <<
" FibEntry has been removed since timeout scheduling");
331 if (fiPtr ==
nullptr) {
332 NFD_LOG_TRACE(interestName <<
" FaceInfo id=" << faceId <<
" has been removed since timeout scheduling");
336 auto& faceInfo = *fiPtr;
338 faceInfo.setNSilentTimeouts(nTimeouts);
340 if (nTimeouts <= m_nMaxSilentTimeouts && !isNack) {
341 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts <<
" ignoring");
344 faceInfo.cancelTimeout(interestName);
347 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts);
348 faceInfo.recordTimeout(interestName);
353 AsfStrategy::sendNoRouteNack(
Face& face,
const shared_ptr<pit::Entry>& pitEntry)
355 lp::NackHeader nackHeader;
356 nackHeader.setReason(lp::NackReason::NO_ROUTE);
357 this->
sendNack(pitEntry, face, 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)
bool sendNack(const shared_ptr< pit::Entry > &pitEntry, Face &egress, const lp::NackHeader &header)
Send a Nack packet.
void extendFaceInfoLifetime(FaceInfo &info, FaceId faceId)
size_t getNSilentTimeouts() const
static const Name & getStrategyName()
NamespaceInfo * getNamespaceInfo(const Name &prefix)
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 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
void setExpiryTimer(const shared_ptr< pit::Entry > &pitEntry, time::milliseconds duration)
Schedule the PIT entry to be erased after duration.
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())
pit::OutRecord * sendInterest(const shared_ptr< pit::Entry > &pitEntry, Face &egress, const Interest &interest)
Send an Interest packet.
optional< uint64_t > version
whether strategyName contains a version component
FaceInfo * getFaceInfo(FaceId faceId)
time::nanoseconds getSrtt() const