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,
61 <<
" n-silent-timeouts=" << m_maxSilentTimeouts);
67 static Name strategyName(
"/localhost/nfd/strategy/asf/%FD%03");
75 if (!value.empty() && value[0] ==
'-')
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");
190 NFD_LOG_DEBUG(pitEntry->getName() <<
" data from=" << ingress
202 const shared_ptr<pit::Entry>& pitEntry)
205 onTimeout(pitEntry->getName(), ingress.
face.
getId());
210 const shared_ptr<pit::Entry>& pitEntry,
bool wantNewNonce)
216 probeInterest.refreshNonce();
217 NFD_LOG_TRACE(
"Sending probe for " << probeInterest <<
" to=" << egress);
224 FaceInfo& faceInfo = m_measurements.
getOrCreateFaceInfo(fibEntry, interest, egress.face.getId());
230 if (!faceInfo.isTimeoutScheduled()) {
231 auto timeout = faceInfo.scheduleTimeout(interest.
getName(),
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)
247 Face* faceToProbe = m_probing.
getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
248 if (faceToProbe ==
nullptr)
251 forwardInterest(interest, *faceToProbe, fibEntry, pitEntry,
true);
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;
301 for (
const auto& nh : fibEntry.getNextHops()) {
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");
329 FaceInfo* fiPtr = namespaceInfo->getFaceInfo(faceId);
330 if (fiPtr ==
nullptr) {
331 NFD_LOG_TRACE(interestName <<
" FaceInfo id=" << faceId <<
" has been removed since timeout scheduling");
335 auto& faceInfo = *fiPtr;
336 size_t nTimeouts = faceInfo.getNSilentTimeouts() + 1;
337 faceInfo.setNSilentTimeouts(nTimeouts);
339 if (nTimeouts <= m_maxSilentTimeouts) {
340 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts <<
" ignoring");
342 namespaceInfo->extendFaceInfoLifetime(faceInfo, faceId);
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)
355 nackHeader.
setReason(lp::NackReason::NO_ROUTE);
356 this->
sendNack(pitEntry, ingress, nackHeader);