blob: 3f8abf778635b4049d0fb7679c9e8c6f8c84b2b8 [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
52AsfStrategy::~AsfStrategy()
53{
54}
55
56void
57AsfStrategy::afterReceiveInterest(const Face& inFace,
58 const Interest& interest,
Vince Lehman8a4c29e2016-07-11 08:49:35 +000059 shared_ptr<pit::Entry> pitEntry)
60{
61 // Should the Interest be suppressed?
62 RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
63
64 switch (suppressResult) {
65 case RetxSuppression::NEW:
66 case RetxSuppression::FORWARD:
67 break;
68 case RetxSuppression::SUPPRESS:
69 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
70 return;
71 }
72
Junxiao Shi8d843142016-07-11 22:42:42 +000073 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
74 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000075
76 if (nexthops.size() == 0) {
77 sendNoRouteNack(inFace, interest, pitEntry);
78 this->rejectPendingInterest(pitEntry);
79 return;
80 }
81
Junxiao Shia6de4292016-07-12 02:08:10 +000082 Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000083
84 if (faceToUse == nullptr) {
85 sendNoRouteNack(inFace, interest, pitEntry);
86 this->rejectPendingInterest(pitEntry);
87 return;
88 }
89
Junxiao Shia6de4292016-07-12 02:08:10 +000090 forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000091
92 // If necessary, send probe
93 if (m_probing.isProbingNeeded(fibEntry, interest)) {
Junxiao Shia6de4292016-07-12 02:08:10 +000094 Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000095
96 if (faceToProbe != nullptr) {
Junxiao Shi8d843142016-07-11 22:42:42 +000097 NFD_LOG_TRACE("Sending probe for " << fibEntry.getPrefix()
Vince Lehman8a4c29e2016-07-11 08:49:35 +000098 << " to FaceId: " << faceToProbe->getId());
99
100 bool wantNewNonce = true;
Junxiao Shia6de4292016-07-12 02:08:10 +0000101 forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000102 m_probing.afterForwardingProbe(fibEntry, interest);
103 }
104 }
105}
106
107void
108AsfStrategy::beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
109 const Face& inFace,
110 const Data& data)
111{
112 shared_ptr<NamespaceInfo> namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
113
114 if (namespaceInfo == nullptr) {
115 NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
116 return;
117 }
118
119 // Record the RTT between the Interest out to Data in
120 FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
121 faceInfo.recordRtt(pitEntry, inFace);
122
123 // Extend lifetime for measurements associated with Face
124 namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
125
126 if (faceInfo.isTimeoutScheduled()) {
127 faceInfo.cancelTimeoutEvent(data.getName());
128 }
129}
130
131void
132AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000133 shared_ptr<pit::Entry> pitEntry)
134{
135 NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
136 onTimeout(pitEntry->getName(), inFace.getId());
137}
138
139////////////////////////////////////////////////////////////////////////////////
140////////////////////////////////////////////////////////////////////////////////
141
142void
143AsfStrategy::forwardInterest(const Interest& interest,
144 const fib::Entry& fibEntry,
145 shared_ptr<pit::Entry> pitEntry,
Junxiao Shia6de4292016-07-12 02:08:10 +0000146 Face& outFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000147 bool wantNewNonce)
148{
149 this->sendInterest(pitEntry, outFace, wantNewNonce);
150
Junxiao Shia6de4292016-07-12 02:08:10 +0000151 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000152
153 // Refresh measurements since Face is being used for forwarding
154 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Junxiao Shia6de4292016-07-12 02:08:10 +0000155 namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000156
157 if (!faceInfo.isTimeoutScheduled()) {
158 // Estimate and schedule timeout
159 RttEstimator::Duration timeout = faceInfo.computeRto();
160
161 NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
Junxiao Shia6de4292016-07-12 02:08:10 +0000162 << " FaceId: " << outFace.getId()
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000163 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
164
165 scheduler::EventId id = scheduler::schedule(timeout,
Junxiao Shia6de4292016-07-12 02:08:10 +0000166 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000167
168 faceInfo.setTimeoutEvent(id, interest.getName());
169 }
170}
171
172struct FaceStats
173{
Junxiao Shia6de4292016-07-12 02:08:10 +0000174 Face* face;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000175 RttStats::Rtt rtt;
176 RttStats::Rtt srtt;
177 uint64_t cost;
178};
179
180double
181getValueForSorting(const FaceStats& stats)
182{
183 // These values allow faces with no measurements to be ranked better than timeouts
184 // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
185 static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
186 static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
187
188 if (stats.rtt == RttStats::RTT_TIMEOUT) {
189 return SORTING_RTT_TIMEOUT.count();
190 }
191 else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
192 return SORTING_RTT_NO_MEASUREMENT.count();
193 }
194 else {
195 return stats.srtt.count();
196 }
197}
198
Junxiao Shia6de4292016-07-12 02:08:10 +0000199Face*
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000200AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& inFace)
201{
202 NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
203
204 typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
205 typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
206
207 FaceStatsSet rankedFaces(
208 [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
209 // Sort by RTT and then by cost
210 double lhsValue = getValueForSorting(lhs);
211 double rhsValue = getValueForSorting(rhs);
212
213 if (lhsValue < rhsValue) {
214 return true;
215 }
216 else if (lhsValue == rhsValue) {
217 return lhs.cost < rhs.cost;
218 }
219 else {
220 return false;
221 }
222 });
223
224 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000225 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000226
Junxiao Shia6de4292016-07-12 02:08:10 +0000227 if (hopFace.getId() == inFace.getId()) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000228 continue;
229 }
230
Junxiao Shia6de4292016-07-12 02:08:10 +0000231 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000232
233 if (info == nullptr) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000234 FaceStats stats = {&hopFace,
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000235 RttStats::RTT_NO_MEASUREMENT,
236 RttStats::RTT_NO_MEASUREMENT,
237 hop.getCost()};
238
239 rankedFaces.insert(stats);
240 }
241 else {
Junxiao Shia6de4292016-07-12 02:08:10 +0000242 FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000243 rankedFaces.insert(stats);
244 }
245 }
246
247 FaceStatsSet::iterator it = rankedFaces.begin();
248
249 if (it != rankedFaces.end()) {
250 return it->face;
251 }
252 else {
253 return nullptr;
254 }
255}
256
257void
258AsfStrategy::onTimeout(const ndn::Name& interestName, nfd::face::FaceId faceId)
259{
260 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
261
262 shared_ptr<NamespaceInfo> namespaceInfo = m_measurements.getNamespaceInfo(interestName);
263
264 if (namespaceInfo == nullptr) {
265 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
266 return;
267 }
268
269 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
270
271 if (it == namespaceInfo->end()) {
272 it = namespaceInfo->insert(faceId);
273 }
274
275 FaceInfo& faceInfo = it->second;
276 faceInfo.recordTimeout(interestName);
277}
278
279void
280AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest, shared_ptr<pit::Entry> pitEntry)
281{
282 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
283
284 lp::NackHeader nackHeader;
285 nackHeader.setReason(lp::NackReason::NO_ROUTE);
286 this->sendNack(pitEntry, inFace, nackHeader);
287}
288
289} // namespace asf
290} // namespace fw
291} // namespace nfd