blob: 5e14e37681b5b3672e47230bd3d5f56799247e12 [file] [log] [blame]
Vince Lehman8a4c29e2016-07-11 08:49:35 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande90015992017-07-11 17:25:48 -05002/*
Ashlesh Gawandecad76b62017-04-04 15:28:30 -05003 * Copyright (c) 2014-2017, Regents of the University of California,
Vince Lehman8a4c29e2016-07-11 08:49:35 +00004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "asf-strategy.hpp"
Ashlesh Gawande2a73f352016-12-01 15:37:03 +000027#include "algorithm.hpp"
Vince Lehman8a4c29e2016-07-11 08:49:35 +000028
29#include "core/logger.hpp"
30
31namespace nfd {
32namespace fw {
33namespace asf {
34
35NFD_LOG_INIT("AsfStrategy");
Junxiao Shi037f4ab2016-12-13 04:27:06 +000036NFD_REGISTER_STRATEGY(AsfStrategy);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000037
Vince Lehman8a4c29e2016-07-11 08:49:35 +000038const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
39const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
40
Vince Lehman8a4c29e2016-07-11 08:49:35 +000041AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
Junxiao Shi18739c42016-12-22 08:03:00 +000042 : Strategy(forwarder)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000043 , m_measurements(getMeasurements())
44 , m_probing(m_measurements)
45 , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
46 RetxSuppressionExponential::DEFAULT_MULTIPLIER,
47 RETX_SUPPRESSION_MAX)
48{
Junxiao Shi18739c42016-12-22 08:03:00 +000049 ParsedInstanceName parsed = parseInstanceName(name);
50 if (!parsed.parameters.empty()) {
51 BOOST_THROW_EXCEPTION(std::invalid_argument("AsfStrategy does not accept parameters"));
52 }
Junxiao Shi91f6ee02016-12-29 21:44:44 +000053 if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
54 BOOST_THROW_EXCEPTION(std::invalid_argument(
Alexander Afanasyev0c63c632017-12-05 11:17:09 -050055 "AsfStrategy does not support version " + to_string(*parsed.version)));
Junxiao Shi91f6ee02016-12-29 21:44:44 +000056 }
Junxiao Shi18739c42016-12-22 08:03:00 +000057 this->setInstanceName(makeInstanceName(name, getStrategyName()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +000058}
59
Junxiao Shi037f4ab2016-12-13 04:27:06 +000060const Name&
61AsfStrategy::getStrategyName()
62{
Teng Liangf995f382017-04-04 22:09:39 +000063 static Name strategyName("/localhost/nfd/strategy/asf/%FD%02");
Junxiao Shi037f4ab2016-12-13 04:27:06 +000064 return strategyName;
65}
66
Vince Lehman8a4c29e2016-07-11 08:49:35 +000067void
Junxiao Shi15e98b02016-08-12 11:21:44 +000068AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
69 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000070{
71 // Should the Interest be suppressed?
Ashlesh Gawande90015992017-07-11 17:25:48 -050072 RetxSuppressionResult suppressResult = m_retxSuppression.decidePerPitEntry(*pitEntry);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000073
74 switch (suppressResult) {
Ashlesh Gawande90015992017-07-11 17:25:48 -050075 case RetxSuppressionResult::NEW:
76 case RetxSuppressionResult::FORWARD:
Vince Lehman8a4c29e2016-07-11 08:49:35 +000077 break;
Ashlesh Gawande90015992017-07-11 17:25:48 -050078 case RetxSuppressionResult::SUPPRESS:
Vince Lehman8a4c29e2016-07-11 08:49:35 +000079 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
80 return;
81 }
82
Junxiao Shi8d843142016-07-11 22:42:42 +000083 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
84 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000085
86 if (nexthops.size() == 0) {
87 sendNoRouteNack(inFace, interest, pitEntry);
88 this->rejectPendingInterest(pitEntry);
89 return;
90 }
91
Junxiao Shia6de4292016-07-12 02:08:10 +000092 Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000093
94 if (faceToUse == nullptr) {
95 sendNoRouteNack(inFace, interest, pitEntry);
96 this->rejectPendingInterest(pitEntry);
97 return;
98 }
99
Ashlesh Gawandecad76b62017-04-04 15:28:30 -0500100 NFD_LOG_TRACE("Forwarding interest to face: " << faceToUse->getId());
101
Junxiao Shia6de4292016-07-12 02:08:10 +0000102 forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000103
104 // If necessary, send probe
105 if (m_probing.isProbingNeeded(fibEntry, interest)) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000106 Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000107
108 if (faceToProbe != nullptr) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000109 bool wantNewNonce = true;
Junxiao Shia6de4292016-07-12 02:08:10 +0000110 forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000111 m_probing.afterForwardingProbe(fibEntry, interest);
112 }
113 }
114}
115
116void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000117AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
118 const Face& inFace, const Data& data)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000119{
Junxiao Shifc021862016-08-25 21:51:18 +0000120 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000121
122 if (namespaceInfo == nullptr) {
123 NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
124 return;
125 }
126
127 // Record the RTT between the Interest out to Data in
Ashlesh Gawandecad76b62017-04-04 15:28:30 -0500128 FaceInfo* faceInfo = namespaceInfo->get(inFace.getId());
129 if (faceInfo == nullptr) {
130 return;
131 }
132 faceInfo->recordRtt(pitEntry, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000133
134 // Extend lifetime for measurements associated with Face
Ashlesh Gawandecad76b62017-04-04 15:28:30 -0500135 namespaceInfo->extendFaceInfoLifetime(*faceInfo, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000136
Ashlesh Gawandecad76b62017-04-04 15:28:30 -0500137 if (faceInfo->isTimeoutScheduled()) {
138 faceInfo->cancelTimeoutEvent(data.getName());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000139 }
140}
141
142void
143AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000144 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000145{
146 NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
147 onTimeout(pitEntry->getName(), inFace.getId());
148}
149
150////////////////////////////////////////////////////////////////////////////////
151////////////////////////////////////////////////////////////////////////////////
152
153void
154AsfStrategy::forwardInterest(const Interest& interest,
155 const fib::Entry& fibEntry,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000156 const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shia6de4292016-07-12 02:08:10 +0000157 Face& outFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000158 bool wantNewNonce)
159{
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000160 if (wantNewNonce) {
161 //Send probe: interest with new Nonce
162 Interest probeInterest(interest);
163 probeInterest.refreshNonce();
164 NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
165 << " to FaceId: " << outFace.getId());
166 this->sendInterest(pitEntry, outFace, probeInterest);
167 }
168 else {
169 this->sendInterest(pitEntry, outFace, interest);
170 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000171
Junxiao Shia6de4292016-07-12 02:08:10 +0000172 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000173
174 // Refresh measurements since Face is being used for forwarding
175 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Junxiao Shia6de4292016-07-12 02:08:10 +0000176 namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000177
178 if (!faceInfo.isTimeoutScheduled()) {
179 // Estimate and schedule timeout
180 RttEstimator::Duration timeout = faceInfo.computeRto();
181
182 NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
Junxiao Shia6de4292016-07-12 02:08:10 +0000183 << " FaceId: " << outFace.getId()
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000184 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
185
186 scheduler::EventId id = scheduler::schedule(timeout,
Junxiao Shia6de4292016-07-12 02:08:10 +0000187 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000188
189 faceInfo.setTimeoutEvent(id, interest.getName());
190 }
191}
192
193struct FaceStats
194{
Junxiao Shia6de4292016-07-12 02:08:10 +0000195 Face* face;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000196 RttStats::Rtt rtt;
197 RttStats::Rtt srtt;
198 uint64_t cost;
199};
200
201double
202getValueForSorting(const FaceStats& stats)
203{
204 // These values allow faces with no measurements to be ranked better than timeouts
205 // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
206 static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
207 static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
208
209 if (stats.rtt == RttStats::RTT_TIMEOUT) {
210 return SORTING_RTT_TIMEOUT.count();
211 }
212 else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
213 return SORTING_RTT_NO_MEASUREMENT.count();
214 }
215 else {
216 return stats.srtt.count();
217 }
218}
219
Junxiao Shia6de4292016-07-12 02:08:10 +0000220Face*
Junxiao Shi15e98b02016-08-12 11:21:44 +0000221AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
222 const Face& inFace)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000223{
224 NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
225
226 typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
227 typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
228
229 FaceStatsSet rankedFaces(
230 [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
231 // Sort by RTT and then by cost
232 double lhsValue = getValueForSorting(lhs);
233 double rhsValue = getValueForSorting(rhs);
234
235 if (lhsValue < rhsValue) {
236 return true;
237 }
238 else if (lhsValue == rhsValue) {
239 return lhs.cost < rhs.cost;
240 }
241 else {
242 return false;
243 }
244 });
245
246 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000247 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000248
Teng Liangf995f382017-04-04 22:09:39 +0000249 if ((hopFace.getId() == inFace.getId() && hopFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
250 wouldViolateScope(inFace, interest, hopFace)) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000251 continue;
252 }
253
Junxiao Shia6de4292016-07-12 02:08:10 +0000254 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000255
256 if (info == nullptr) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000257 FaceStats stats = {&hopFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000258 RttStats::RTT_NO_MEASUREMENT,
259 RttStats::RTT_NO_MEASUREMENT,
260 hop.getCost()};
261
262 rankedFaces.insert(stats);
263 }
264 else {
Junxiao Shia6de4292016-07-12 02:08:10 +0000265 FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000266 rankedFaces.insert(stats);
267 }
268 }
269
270 FaceStatsSet::iterator it = rankedFaces.begin();
271
272 if (it != rankedFaces.end()) {
273 return it->face;
274 }
275 else {
276 return nullptr;
277 }
278}
279
280void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000281AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000282{
283 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
284
Junxiao Shifc021862016-08-25 21:51:18 +0000285 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000286
287 if (namespaceInfo == nullptr) {
288 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
289 return;
290 }
291
292 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
293
294 if (it == namespaceInfo->end()) {
295 it = namespaceInfo->insert(faceId);
296 }
297
298 FaceInfo& faceInfo = it->second;
299 faceInfo.recordTimeout(interestName);
300}
301
302void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000303AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
304 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000305{
306 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
307
308 lp::NackHeader nackHeader;
309 nackHeader.setReason(lp::NackReason::NO_ROUTE);
310 this->sendNack(pitEntry, inFace, nackHeader);
311}
312
313} // namespace asf
314} // namespace fw
315} // namespace nfd