blob: acab918a0ea9fe22d9657d593412b5110dc3f1f2 [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");
36
37const Name AsfStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/asf/%FD%01");
38const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
39const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
40
41NFD_REGISTER_STRATEGY(AsfStrategy);
42
43AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
44 : Strategy(forwarder, name)
45 , m_measurements(getMeasurements())
46 , m_probing(m_measurements)
47 , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
48 RetxSuppressionExponential::DEFAULT_MULTIPLIER,
49 RETX_SUPPRESSION_MAX)
50{
51}
52
Vince Lehman8a4c29e2016-07-11 08:49:35 +000053void
Junxiao Shi15e98b02016-08-12 11:21:44 +000054AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
55 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000056{
57 // Should the Interest be suppressed?
58 RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
59
60 switch (suppressResult) {
61 case RetxSuppression::NEW:
62 case RetxSuppression::FORWARD:
63 break;
64 case RetxSuppression::SUPPRESS:
65 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
66 return;
67 }
68
Junxiao Shi8d843142016-07-11 22:42:42 +000069 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
70 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000071
72 if (nexthops.size() == 0) {
73 sendNoRouteNack(inFace, interest, pitEntry);
74 this->rejectPendingInterest(pitEntry);
75 return;
76 }
77
Junxiao Shia6de4292016-07-12 02:08:10 +000078 Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000079
80 if (faceToUse == nullptr) {
81 sendNoRouteNack(inFace, interest, pitEntry);
82 this->rejectPendingInterest(pitEntry);
83 return;
84 }
85
Junxiao Shia6de4292016-07-12 02:08:10 +000086 forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000087
88 // If necessary, send probe
89 if (m_probing.isProbingNeeded(fibEntry, interest)) {
Junxiao Shia6de4292016-07-12 02:08:10 +000090 Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000091
92 if (faceToProbe != nullptr) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +000093 bool wantNewNonce = true;
Junxiao Shia6de4292016-07-12 02:08:10 +000094 forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000095 m_probing.afterForwardingProbe(fibEntry, interest);
96 }
97 }
98}
99
100void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000101AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
102 const Face& inFace, const Data& data)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000103{
Junxiao Shifc021862016-08-25 21:51:18 +0000104 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000105
106 if (namespaceInfo == nullptr) {
107 NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
108 return;
109 }
110
111 // Record the RTT between the Interest out to Data in
112 FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
113 faceInfo.recordRtt(pitEntry, inFace);
114
115 // Extend lifetime for measurements associated with Face
116 namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
117
118 if (faceInfo.isTimeoutScheduled()) {
119 faceInfo.cancelTimeoutEvent(data.getName());
120 }
121}
122
123void
124AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000125 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000126{
127 NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
128 onTimeout(pitEntry->getName(), inFace.getId());
129}
130
131////////////////////////////////////////////////////////////////////////////////
132////////////////////////////////////////////////////////////////////////////////
133
134void
135AsfStrategy::forwardInterest(const Interest& interest,
136 const fib::Entry& fibEntry,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000137 const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shia6de4292016-07-12 02:08:10 +0000138 Face& outFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000139 bool wantNewNonce)
140{
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000141 if (wantNewNonce) {
142 //Send probe: interest with new Nonce
143 Interest probeInterest(interest);
144 probeInterest.refreshNonce();
145 NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
146 << " to FaceId: " << outFace.getId());
147 this->sendInterest(pitEntry, outFace, probeInterest);
148 }
149 else {
150 this->sendInterest(pitEntry, outFace, interest);
151 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000152
Junxiao Shia6de4292016-07-12 02:08:10 +0000153 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000154
155 // Refresh measurements since Face is being used for forwarding
156 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Junxiao Shia6de4292016-07-12 02:08:10 +0000157 namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000158
159 if (!faceInfo.isTimeoutScheduled()) {
160 // Estimate and schedule timeout
161 RttEstimator::Duration timeout = faceInfo.computeRto();
162
163 NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
Junxiao Shia6de4292016-07-12 02:08:10 +0000164 << " FaceId: " << outFace.getId()
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000165 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
166
167 scheduler::EventId id = scheduler::schedule(timeout,
Junxiao Shia6de4292016-07-12 02:08:10 +0000168 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000169
170 faceInfo.setTimeoutEvent(id, interest.getName());
171 }
172}
173
174struct FaceStats
175{
Junxiao Shia6de4292016-07-12 02:08:10 +0000176 Face* face;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000177 RttStats::Rtt rtt;
178 RttStats::Rtt srtt;
179 uint64_t cost;
180};
181
182double
183getValueForSorting(const FaceStats& stats)
184{
185 // These values allow faces with no measurements to be ranked better than timeouts
186 // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
187 static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
188 static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
189
190 if (stats.rtt == RttStats::RTT_TIMEOUT) {
191 return SORTING_RTT_TIMEOUT.count();
192 }
193 else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
194 return SORTING_RTT_NO_MEASUREMENT.count();
195 }
196 else {
197 return stats.srtt.count();
198 }
199}
200
Junxiao Shia6de4292016-07-12 02:08:10 +0000201Face*
Junxiao Shi15e98b02016-08-12 11:21:44 +0000202AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
203 const Face& inFace)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000204{
205 NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
206
207 typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
208 typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
209
210 FaceStatsSet rankedFaces(
211 [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
212 // Sort by RTT and then by cost
213 double lhsValue = getValueForSorting(lhs);
214 double rhsValue = getValueForSorting(rhs);
215
216 if (lhsValue < rhsValue) {
217 return true;
218 }
219 else if (lhsValue == rhsValue) {
220 return lhs.cost < rhs.cost;
221 }
222 else {
223 return false;
224 }
225 });
226
227 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000228 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000229
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000230 if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000231 continue;
232 }
233
Junxiao Shia6de4292016-07-12 02:08:10 +0000234 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000235
236 if (info == nullptr) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000237 FaceStats stats = {&hopFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000238 RttStats::RTT_NO_MEASUREMENT,
239 RttStats::RTT_NO_MEASUREMENT,
240 hop.getCost()};
241
242 rankedFaces.insert(stats);
243 }
244 else {
Junxiao Shia6de4292016-07-12 02:08:10 +0000245 FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000246 rankedFaces.insert(stats);
247 }
248 }
249
250 FaceStatsSet::iterator it = rankedFaces.begin();
251
252 if (it != rankedFaces.end()) {
253 return it->face;
254 }
255 else {
256 return nullptr;
257 }
258}
259
260void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000261AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000262{
263 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
264
Junxiao Shifc021862016-08-25 21:51:18 +0000265 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000266
267 if (namespaceInfo == nullptr) {
268 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
269 return;
270 }
271
272 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
273
274 if (it == namespaceInfo->end()) {
275 it = namespaceInfo->insert(faceId);
276 }
277
278 FaceInfo& faceInfo = it->second;
279 faceInfo.recordTimeout(interestName);
280}
281
282void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000283AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
284 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000285{
286 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
287
288 lp::NackHeader nackHeader;
289 nackHeader.setReason(lp::NackReason::NO_ROUTE);
290 this->sendNack(pitEntry, inFace, nackHeader);
291}
292
293} // namespace asf
294} // namespace fw
295} // namespace nfd