blob: 45b0d7259047eb98e3196514f09bca094d1bf8a4 [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 }
Junxiao Shi91f6ee02016-12-29 21:44:44 +000053 if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
54 BOOST_THROW_EXCEPTION(std::invalid_argument(
55 "AsfStrategy does not support version " + std::to_string(*parsed.version)));
56 }
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{
63 static Name strategyName("/localhost/nfd/strategy/asf/%FD%01");
64 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?
72 RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
73
74 switch (suppressResult) {
75 case RetxSuppression::NEW:
76 case RetxSuppression::FORWARD:
77 break;
78 case RetxSuppression::SUPPRESS:
79 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
Junxiao Shia6de4292016-07-12 02:08:10 +0000100 forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000101
102 // If necessary, send probe
103 if (m_probing.isProbingNeeded(fibEntry, interest)) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000104 Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000105
106 if (faceToProbe != nullptr) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000107 bool wantNewNonce = true;
Junxiao Shia6de4292016-07-12 02:08:10 +0000108 forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000109 m_probing.afterForwardingProbe(fibEntry, interest);
110 }
111 }
112}
113
114void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000115AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
116 const Face& inFace, const Data& data)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000117{
Junxiao Shifc021862016-08-25 21:51:18 +0000118 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000119
120 if (namespaceInfo == nullptr) {
121 NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
122 return;
123 }
124
125 // Record the RTT between the Interest out to Data in
126 FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
127 faceInfo.recordRtt(pitEntry, inFace);
128
129 // Extend lifetime for measurements associated with Face
130 namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
131
132 if (faceInfo.isTimeoutScheduled()) {
133 faceInfo.cancelTimeoutEvent(data.getName());
134 }
135}
136
137void
138AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000139 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000140{
141 NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
142 onTimeout(pitEntry->getName(), inFace.getId());
143}
144
145////////////////////////////////////////////////////////////////////////////////
146////////////////////////////////////////////////////////////////////////////////
147
148void
149AsfStrategy::forwardInterest(const Interest& interest,
150 const fib::Entry& fibEntry,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000151 const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shia6de4292016-07-12 02:08:10 +0000152 Face& outFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000153 bool wantNewNonce)
154{
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000155 if (wantNewNonce) {
156 //Send probe: interest with new Nonce
157 Interest probeInterest(interest);
158 probeInterest.refreshNonce();
159 NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
160 << " to FaceId: " << outFace.getId());
161 this->sendInterest(pitEntry, outFace, probeInterest);
162 }
163 else {
164 this->sendInterest(pitEntry, outFace, interest);
165 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000166
Junxiao Shia6de4292016-07-12 02:08:10 +0000167 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000168
169 // Refresh measurements since Face is being used for forwarding
170 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Junxiao Shia6de4292016-07-12 02:08:10 +0000171 namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000172
173 if (!faceInfo.isTimeoutScheduled()) {
174 // Estimate and schedule timeout
175 RttEstimator::Duration timeout = faceInfo.computeRto();
176
177 NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
Junxiao Shia6de4292016-07-12 02:08:10 +0000178 << " FaceId: " << outFace.getId()
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000179 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
180
181 scheduler::EventId id = scheduler::schedule(timeout,
Junxiao Shia6de4292016-07-12 02:08:10 +0000182 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000183
184 faceInfo.setTimeoutEvent(id, interest.getName());
185 }
186}
187
188struct FaceStats
189{
Junxiao Shia6de4292016-07-12 02:08:10 +0000190 Face* face;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000191 RttStats::Rtt rtt;
192 RttStats::Rtt srtt;
193 uint64_t cost;
194};
195
196double
197getValueForSorting(const FaceStats& stats)
198{
199 // These values allow faces with no measurements to be ranked better than timeouts
200 // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
201 static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
202 static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
203
204 if (stats.rtt == RttStats::RTT_TIMEOUT) {
205 return SORTING_RTT_TIMEOUT.count();
206 }
207 else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
208 return SORTING_RTT_NO_MEASUREMENT.count();
209 }
210 else {
211 return stats.srtt.count();
212 }
213}
214
Junxiao Shia6de4292016-07-12 02:08:10 +0000215Face*
Junxiao Shi15e98b02016-08-12 11:21:44 +0000216AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
217 const Face& inFace)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000218{
219 NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
220
221 typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
222 typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
223
224 FaceStatsSet rankedFaces(
225 [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
226 // Sort by RTT and then by cost
227 double lhsValue = getValueForSorting(lhs);
228 double rhsValue = getValueForSorting(rhs);
229
230 if (lhsValue < rhsValue) {
231 return true;
232 }
233 else if (lhsValue == rhsValue) {
234 return lhs.cost < rhs.cost;
235 }
236 else {
237 return false;
238 }
239 });
240
241 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000242 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000243
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000244 if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000245 continue;
246 }
247
Junxiao Shia6de4292016-07-12 02:08:10 +0000248 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000249
250 if (info == nullptr) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000251 FaceStats stats = {&hopFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000252 RttStats::RTT_NO_MEASUREMENT,
253 RttStats::RTT_NO_MEASUREMENT,
254 hop.getCost()};
255
256 rankedFaces.insert(stats);
257 }
258 else {
Junxiao Shia6de4292016-07-12 02:08:10 +0000259 FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000260 rankedFaces.insert(stats);
261 }
262 }
263
264 FaceStatsSet::iterator it = rankedFaces.begin();
265
266 if (it != rankedFaces.end()) {
267 return it->face;
268 }
269 else {
270 return nullptr;
271 }
272}
273
274void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000275AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000276{
277 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
278
Junxiao Shifc021862016-08-25 21:51:18 +0000279 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000280
281 if (namespaceInfo == nullptr) {
282 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
283 return;
284 }
285
286 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
287
288 if (it == namespaceInfo->end()) {
289 it = namespaceInfo->insert(faceId);
290 }
291
292 FaceInfo& faceInfo = it->second;
293 faceInfo.recordTimeout(interestName);
294}
295
296void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000297AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
298 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000299{
300 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
301
302 lp::NackHeader nackHeader;
303 nackHeader.setReason(lp::NackReason::NO_ROUTE);
304 this->sendNack(pitEntry, inFace, nackHeader);
305}
306
307} // namespace asf
308} // namespace fw
309} // namespace nfd