blob: 9ed2c773acaae9a9d367f89da6cf86d4fbea0a18 [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"
27
28#include "core/logger.hpp"
29
30namespace nfd {
31namespace fw {
32namespace asf {
33
34NFD_LOG_INIT("AsfStrategy");
35
36const Name AsfStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/asf/%FD%01");
37const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
38const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
39
40NFD_REGISTER_STRATEGY(AsfStrategy);
41
42AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
43 : Strategy(forwarder, name)
44 , m_measurements(getMeasurements())
45 , m_probing(m_measurements)
46 , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
47 RetxSuppressionExponential::DEFAULT_MULTIPLIER,
48 RETX_SUPPRESSION_MAX)
49{
50}
51
Vince Lehman8a4c29e2016-07-11 08:49:35 +000052void
Junxiao Shi15e98b02016-08-12 11:21:44 +000053AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
54 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000055{
56 // Should the Interest be suppressed?
57 RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
58
59 switch (suppressResult) {
60 case RetxSuppression::NEW:
61 case RetxSuppression::FORWARD:
62 break;
63 case RetxSuppression::SUPPRESS:
64 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
65 return;
66 }
67
Junxiao Shi8d843142016-07-11 22:42:42 +000068 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
69 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000070
71 if (nexthops.size() == 0) {
72 sendNoRouteNack(inFace, interest, pitEntry);
73 this->rejectPendingInterest(pitEntry);
74 return;
75 }
76
Junxiao Shia6de4292016-07-12 02:08:10 +000077 Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000078
79 if (faceToUse == nullptr) {
80 sendNoRouteNack(inFace, interest, pitEntry);
81 this->rejectPendingInterest(pitEntry);
82 return;
83 }
84
Junxiao Shia6de4292016-07-12 02:08:10 +000085 forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000086
87 // If necessary, send probe
88 if (m_probing.isProbingNeeded(fibEntry, interest)) {
Junxiao Shia6de4292016-07-12 02:08:10 +000089 Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000090
91 if (faceToProbe != nullptr) {
Junxiao Shi8d843142016-07-11 22:42:42 +000092 NFD_LOG_TRACE("Sending probe for " << fibEntry.getPrefix()
Vince Lehman8a4c29e2016-07-11 08:49:35 +000093 << " to FaceId: " << faceToProbe->getId());
94
95 bool wantNewNonce = true;
Junxiao Shia6de4292016-07-12 02:08:10 +000096 forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000097 m_probing.afterForwardingProbe(fibEntry, interest);
98 }
99 }
100}
101
102void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000103AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
104 const Face& inFace, const Data& data)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000105{
106 shared_ptr<NamespaceInfo> namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
107
108 if (namespaceInfo == nullptr) {
109 NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
110 return;
111 }
112
113 // Record the RTT between the Interest out to Data in
114 FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
115 faceInfo.recordRtt(pitEntry, inFace);
116
117 // Extend lifetime for measurements associated with Face
118 namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
119
120 if (faceInfo.isTimeoutScheduled()) {
121 faceInfo.cancelTimeoutEvent(data.getName());
122 }
123}
124
125void
126AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000127 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000128{
129 NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
130 onTimeout(pitEntry->getName(), inFace.getId());
131}
132
133////////////////////////////////////////////////////////////////////////////////
134////////////////////////////////////////////////////////////////////////////////
135
136void
137AsfStrategy::forwardInterest(const Interest& interest,
138 const fib::Entry& fibEntry,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000139 const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shia6de4292016-07-12 02:08:10 +0000140 Face& outFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000141 bool wantNewNonce)
142{
143 this->sendInterest(pitEntry, outFace, wantNewNonce);
144
Junxiao Shia6de4292016-07-12 02:08:10 +0000145 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000146
147 // Refresh measurements since Face is being used for forwarding
148 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Junxiao Shia6de4292016-07-12 02:08:10 +0000149 namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000150
151 if (!faceInfo.isTimeoutScheduled()) {
152 // Estimate and schedule timeout
153 RttEstimator::Duration timeout = faceInfo.computeRto();
154
155 NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
Junxiao Shia6de4292016-07-12 02:08:10 +0000156 << " FaceId: " << outFace.getId()
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000157 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
158
159 scheduler::EventId id = scheduler::schedule(timeout,
Junxiao Shia6de4292016-07-12 02:08:10 +0000160 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000161
162 faceInfo.setTimeoutEvent(id, interest.getName());
163 }
164}
165
166struct FaceStats
167{
Junxiao Shia6de4292016-07-12 02:08:10 +0000168 Face* face;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000169 RttStats::Rtt rtt;
170 RttStats::Rtt srtt;
171 uint64_t cost;
172};
173
174double
175getValueForSorting(const FaceStats& stats)
176{
177 // These values allow faces with no measurements to be ranked better than timeouts
178 // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
179 static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
180 static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
181
182 if (stats.rtt == RttStats::RTT_TIMEOUT) {
183 return SORTING_RTT_TIMEOUT.count();
184 }
185 else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
186 return SORTING_RTT_NO_MEASUREMENT.count();
187 }
188 else {
189 return stats.srtt.count();
190 }
191}
192
Junxiao Shia6de4292016-07-12 02:08:10 +0000193Face*
Junxiao Shi15e98b02016-08-12 11:21:44 +0000194AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
195 const Face& inFace)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000196{
197 NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
198
199 typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
200 typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
201
202 FaceStatsSet rankedFaces(
203 [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
204 // Sort by RTT and then by cost
205 double lhsValue = getValueForSorting(lhs);
206 double rhsValue = getValueForSorting(rhs);
207
208 if (lhsValue < rhsValue) {
209 return true;
210 }
211 else if (lhsValue == rhsValue) {
212 return lhs.cost < rhs.cost;
213 }
214 else {
215 return false;
216 }
217 });
218
219 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000220 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000221
Junxiao Shia6de4292016-07-12 02:08:10 +0000222 if (hopFace.getId() == inFace.getId()) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000223 continue;
224 }
225
Junxiao Shia6de4292016-07-12 02:08:10 +0000226 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000227
228 if (info == nullptr) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000229 FaceStats stats = {&hopFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000230 RttStats::RTT_NO_MEASUREMENT,
231 RttStats::RTT_NO_MEASUREMENT,
232 hop.getCost()};
233
234 rankedFaces.insert(stats);
235 }
236 else {
Junxiao Shia6de4292016-07-12 02:08:10 +0000237 FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000238 rankedFaces.insert(stats);
239 }
240 }
241
242 FaceStatsSet::iterator it = rankedFaces.begin();
243
244 if (it != rankedFaces.end()) {
245 return it->face;
246 }
247 else {
248 return nullptr;
249 }
250}
251
252void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000253AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000254{
255 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
256
257 shared_ptr<NamespaceInfo> namespaceInfo = m_measurements.getNamespaceInfo(interestName);
258
259 if (namespaceInfo == nullptr) {
260 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
261 return;
262 }
263
264 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
265
266 if (it == namespaceInfo->end()) {
267 it = namespaceInfo->insert(faceId);
268 }
269
270 FaceInfo& faceInfo = it->second;
271 faceInfo.recordTimeout(interestName);
272}
273
274void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000275AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
276 const shared_ptr<pit::Entry>& pitEntry)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000277{
278 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
279
280 lp::NackHeader nackHeader;
281 nackHeader.setReason(lp::NackReason::NO_ROUTE);
282 this->sendNack(pitEntry, inFace, nackHeader);
283}
284
285} // namespace asf
286} // namespace fw
287} // namespace nfd