blob: cb2bca338d72f8fc1f6bd67d33bec20f71d4bb47 [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)
42 : Strategy(forwarder, name)
43 , m_measurements(getMeasurements())
44 , m_probing(m_measurements)
45 , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
46 RetxSuppressionExponential::DEFAULT_MULTIPLIER,
47 RETX_SUPPRESSION_MAX)
48{
49}
50
Junxiao Shi037f4ab2016-12-13 04:27:06 +000051const Name&
52AsfStrategy::getStrategyName()
53{
54 static Name strategyName("/localhost/nfd/strategy/asf/%FD%01");
55 return strategyName;
56}
57
Vince Lehman8a4c29e2016-07-11 08:49:35 +000058void
Junxiao Shi15e98b02016-08-12 11:21:44 +000059AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
60 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000061{
62 // Should the Interest be suppressed?
63 RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
64
65 switch (suppressResult) {
66 case RetxSuppression::NEW:
67 case RetxSuppression::FORWARD:
68 break;
69 case RetxSuppression::SUPPRESS:
70 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
71 return;
72 }
73
Junxiao Shi8d843142016-07-11 22:42:42 +000074 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
75 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000076
77 if (nexthops.size() == 0) {
78 sendNoRouteNack(inFace, interest, pitEntry);
79 this->rejectPendingInterest(pitEntry);
80 return;
81 }
82
Junxiao Shia6de4292016-07-12 02:08:10 +000083 Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000084
85 if (faceToUse == nullptr) {
86 sendNoRouteNack(inFace, interest, pitEntry);
87 this->rejectPendingInterest(pitEntry);
88 return;
89 }
90
Junxiao Shia6de4292016-07-12 02:08:10 +000091 forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000092
93 // If necessary, send probe
94 if (m_probing.isProbingNeeded(fibEntry, interest)) {
Junxiao Shia6de4292016-07-12 02:08:10 +000095 Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000096
97 if (faceToProbe != nullptr) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +000098 bool wantNewNonce = true;
Junxiao Shia6de4292016-07-12 02:08:10 +000099 forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000100 m_probing.afterForwardingProbe(fibEntry, interest);
101 }
102 }
103}
104
105void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000106AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
107 const Face& inFace, const Data& data)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000108{
Junxiao Shifc021862016-08-25 21:51:18 +0000109 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000110
111 if (namespaceInfo == nullptr) {
112 NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
113 return;
114 }
115
116 // Record the RTT between the Interest out to Data in
117 FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
118 faceInfo.recordRtt(pitEntry, inFace);
119
120 // Extend lifetime for measurements associated with Face
121 namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
122
123 if (faceInfo.isTimeoutScheduled()) {
124 faceInfo.cancelTimeoutEvent(data.getName());
125 }
126}
127
128void
129AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000130 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000131{
132 NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
133 onTimeout(pitEntry->getName(), inFace.getId());
134}
135
136////////////////////////////////////////////////////////////////////////////////
137////////////////////////////////////////////////////////////////////////////////
138
139void
140AsfStrategy::forwardInterest(const Interest& interest,
141 const fib::Entry& fibEntry,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000142 const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shia6de4292016-07-12 02:08:10 +0000143 Face& outFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000144 bool wantNewNonce)
145{
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000146 if (wantNewNonce) {
147 //Send probe: interest with new Nonce
148 Interest probeInterest(interest);
149 probeInterest.refreshNonce();
150 NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
151 << " to FaceId: " << outFace.getId());
152 this->sendInterest(pitEntry, outFace, probeInterest);
153 }
154 else {
155 this->sendInterest(pitEntry, outFace, interest);
156 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000157
Junxiao Shia6de4292016-07-12 02:08:10 +0000158 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000159
160 // Refresh measurements since Face is being used for forwarding
161 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Junxiao Shia6de4292016-07-12 02:08:10 +0000162 namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000163
164 if (!faceInfo.isTimeoutScheduled()) {
165 // Estimate and schedule timeout
166 RttEstimator::Duration timeout = faceInfo.computeRto();
167
168 NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
Junxiao Shia6de4292016-07-12 02:08:10 +0000169 << " FaceId: " << outFace.getId()
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000170 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
171
172 scheduler::EventId id = scheduler::schedule(timeout,
Junxiao Shia6de4292016-07-12 02:08:10 +0000173 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000174
175 faceInfo.setTimeoutEvent(id, interest.getName());
176 }
177}
178
179struct FaceStats
180{
Junxiao Shia6de4292016-07-12 02:08:10 +0000181 Face* face;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000182 RttStats::Rtt rtt;
183 RttStats::Rtt srtt;
184 uint64_t cost;
185};
186
187double
188getValueForSorting(const FaceStats& stats)
189{
190 // These values allow faces with no measurements to be ranked better than timeouts
191 // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
192 static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
193 static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
194
195 if (stats.rtt == RttStats::RTT_TIMEOUT) {
196 return SORTING_RTT_TIMEOUT.count();
197 }
198 else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
199 return SORTING_RTT_NO_MEASUREMENT.count();
200 }
201 else {
202 return stats.srtt.count();
203 }
204}
205
Junxiao Shia6de4292016-07-12 02:08:10 +0000206Face*
Junxiao Shi15e98b02016-08-12 11:21:44 +0000207AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
208 const Face& inFace)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000209{
210 NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
211
212 typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
213 typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
214
215 FaceStatsSet rankedFaces(
216 [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
217 // Sort by RTT and then by cost
218 double lhsValue = getValueForSorting(lhs);
219 double rhsValue = getValueForSorting(rhs);
220
221 if (lhsValue < rhsValue) {
222 return true;
223 }
224 else if (lhsValue == rhsValue) {
225 return lhs.cost < rhs.cost;
226 }
227 else {
228 return false;
229 }
230 });
231
232 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000233 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000234
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000235 if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000236 continue;
237 }
238
Junxiao Shia6de4292016-07-12 02:08:10 +0000239 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000240
241 if (info == nullptr) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000242 FaceStats stats = {&hopFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000243 RttStats::RTT_NO_MEASUREMENT,
244 RttStats::RTT_NO_MEASUREMENT,
245 hop.getCost()};
246
247 rankedFaces.insert(stats);
248 }
249 else {
Junxiao Shia6de4292016-07-12 02:08:10 +0000250 FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000251 rankedFaces.insert(stats);
252 }
253 }
254
255 FaceStatsSet::iterator it = rankedFaces.begin();
256
257 if (it != rankedFaces.end()) {
258 return it->face;
259 }
260 else {
261 return nullptr;
262 }
263}
264
265void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000266AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000267{
268 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
269
Junxiao Shifc021862016-08-25 21:51:18 +0000270 NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000271
272 if (namespaceInfo == nullptr) {
273 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
274 return;
275 }
276
277 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
278
279 if (it == namespaceInfo->end()) {
280 it = namespaceInfo->insert(faceId);
281 }
282
283 FaceInfo& faceInfo = it->second;
284 faceInfo.recordTimeout(interestName);
285}
286
287void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000288AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
289 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000290{
291 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
292
293 lp::NackHeader nackHeader;
294 nackHeader.setReason(lp::NackReason::NO_ROUTE);
295 this->sendNack(pitEntry, inFace, nackHeader);
296}
297
298} // namespace asf
299} // namespace fw
300} // namespace nfd