blob: 076a3bb2d1db86673f53974433e1673e377cc2e5 [file] [log] [blame]
Vince Lehman8a4c29e2016-07-11 08:49:35 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2016, Regents of the University of California,
4 * 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 }
53 this->setInstanceName(makeInstanceName(name, getStrategyName()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +000054}
55
Junxiao Shi037f4ab2016-12-13 04:27:06 +000056const Name&
57AsfStrategy::getStrategyName()
58{
59 static Name strategyName("/localhost/nfd/strategy/asf/%FD%01");
60 return strategyName;
61}
62
Vince Lehman8a4c29e2016-07-11 08:49:35 +000063void
Junxiao Shi15e98b02016-08-12 11:21:44 +000064AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
65 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000066{
67 // Should the Interest be suppressed?
68 RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
69
70 switch (suppressResult) {
71 case RetxSuppression::NEW:
72 case RetxSuppression::FORWARD:
73 break;
74 case RetxSuppression::SUPPRESS:
75 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
76 return;
77 }
78
Junxiao Shi8d843142016-07-11 22:42:42 +000079 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
80 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000081
82 if (nexthops.size() == 0) {
83 sendNoRouteNack(inFace, interest, pitEntry);
84 this->rejectPendingInterest(pitEntry);
85 return;
86 }
87
Junxiao Shia6de4292016-07-12 02:08:10 +000088 Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000089
90 if (faceToUse == nullptr) {
91 sendNoRouteNack(inFace, interest, pitEntry);
92 this->rejectPendingInterest(pitEntry);
93 return;
94 }
95
Junxiao Shia6de4292016-07-12 02:08:10 +000096 forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000097
98 // If necessary, send probe
99 if (m_probing.isProbingNeeded(fibEntry, interest)) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000100 Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000101
102 if (faceToProbe != nullptr) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000103 bool wantNewNonce = true;
Junxiao Shia6de4292016-07-12 02:08:10 +0000104 forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000105 m_probing.afterForwardingProbe(fibEntry, interest);
106 }
107 }
108}
109
110void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000111AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
112 const Face& inFace, const Data& data)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000113{
Junxiao Shifc021862016-08-25 21:51:18 +0000114 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000115
116 if (namespaceInfo == nullptr) {
117 NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
118 return;
119 }
120
121 // Record the RTT between the Interest out to Data in
122 FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
123 faceInfo.recordRtt(pitEntry, inFace);
124
125 // Extend lifetime for measurements associated with Face
126 namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
127
128 if (faceInfo.isTimeoutScheduled()) {
129 faceInfo.cancelTimeoutEvent(data.getName());
130 }
131}
132
133void
134AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000135 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000136{
137 NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
138 onTimeout(pitEntry->getName(), inFace.getId());
139}
140
141////////////////////////////////////////////////////////////////////////////////
142////////////////////////////////////////////////////////////////////////////////
143
144void
145AsfStrategy::forwardInterest(const Interest& interest,
146 const fib::Entry& fibEntry,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000147 const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shia6de4292016-07-12 02:08:10 +0000148 Face& outFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000149 bool wantNewNonce)
150{
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000151 if (wantNewNonce) {
152 //Send probe: interest with new Nonce
153 Interest probeInterest(interest);
154 probeInterest.refreshNonce();
155 NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
156 << " to FaceId: " << outFace.getId());
157 this->sendInterest(pitEntry, outFace, probeInterest);
158 }
159 else {
160 this->sendInterest(pitEntry, outFace, interest);
161 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000162
Junxiao Shia6de4292016-07-12 02:08:10 +0000163 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000164
165 // Refresh measurements since Face is being used for forwarding
166 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Junxiao Shia6de4292016-07-12 02:08:10 +0000167 namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000168
169 if (!faceInfo.isTimeoutScheduled()) {
170 // Estimate and schedule timeout
171 RttEstimator::Duration timeout = faceInfo.computeRto();
172
173 NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
Junxiao Shia6de4292016-07-12 02:08:10 +0000174 << " FaceId: " << outFace.getId()
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000175 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
176
177 scheduler::EventId id = scheduler::schedule(timeout,
Junxiao Shia6de4292016-07-12 02:08:10 +0000178 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000179
180 faceInfo.setTimeoutEvent(id, interest.getName());
181 }
182}
183
184struct FaceStats
185{
Junxiao Shia6de4292016-07-12 02:08:10 +0000186 Face* face;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000187 RttStats::Rtt rtt;
188 RttStats::Rtt srtt;
189 uint64_t cost;
190};
191
192double
193getValueForSorting(const FaceStats& stats)
194{
195 // These values allow faces with no measurements to be ranked better than timeouts
196 // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
197 static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
198 static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
199
200 if (stats.rtt == RttStats::RTT_TIMEOUT) {
201 return SORTING_RTT_TIMEOUT.count();
202 }
203 else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
204 return SORTING_RTT_NO_MEASUREMENT.count();
205 }
206 else {
207 return stats.srtt.count();
208 }
209}
210
Junxiao Shia6de4292016-07-12 02:08:10 +0000211Face*
Junxiao Shi15e98b02016-08-12 11:21:44 +0000212AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
213 const Face& inFace)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000214{
215 NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
216
217 typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
218 typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
219
220 FaceStatsSet rankedFaces(
221 [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
222 // Sort by RTT and then by cost
223 double lhsValue = getValueForSorting(lhs);
224 double rhsValue = getValueForSorting(rhs);
225
226 if (lhsValue < rhsValue) {
227 return true;
228 }
229 else if (lhsValue == rhsValue) {
230 return lhs.cost < rhs.cost;
231 }
232 else {
233 return false;
234 }
235 });
236
237 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000238 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000239
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000240 if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000241 continue;
242 }
243
Junxiao Shia6de4292016-07-12 02:08:10 +0000244 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000245
246 if (info == nullptr) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000247 FaceStats stats = {&hopFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000248 RttStats::RTT_NO_MEASUREMENT,
249 RttStats::RTT_NO_MEASUREMENT,
250 hop.getCost()};
251
252 rankedFaces.insert(stats);
253 }
254 else {
Junxiao Shia6de4292016-07-12 02:08:10 +0000255 FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000256 rankedFaces.insert(stats);
257 }
258 }
259
260 FaceStatsSet::iterator it = rankedFaces.begin();
261
262 if (it != rankedFaces.end()) {
263 return it->face;
264 }
265 else {
266 return nullptr;
267 }
268}
269
270void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000271AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000272{
273 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
274
Junxiao Shifc021862016-08-25 21:51:18 +0000275 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000276
277 if (namespaceInfo == nullptr) {
278 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
279 return;
280 }
281
282 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
283
284 if (it == namespaceInfo->end()) {
285 it = namespaceInfo->insert(faceId);
286 }
287
288 FaceInfo& faceInfo = it->second;
289 faceInfo.recordTimeout(interestName);
290}
291
292void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000293AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
294 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000295{
296 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
297
298 lp::NackHeader nackHeader;
299 nackHeader.setReason(lp::NackReason::NO_ROUTE);
300 this->sendNack(pitEntry, inFace, nackHeader);
301}
302
303} // namespace asf
304} // namespace fw
305} // namespace nfd