blob: cf616e84f234b3b3f4007c6a60c80fa032beb776 [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 Shi8d843142016-07-11 22:42:42 +000082 const shared_ptr<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 Shi8d843142016-07-11 22:42:42 +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)) {
94 shared_ptr<Face> faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
95
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 Shi8d843142016-07-11 22:42:42 +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,
146 shared_ptr<Face> outFace,
147 bool wantNewNonce)
148{
149 this->sendInterest(pitEntry, outFace, wantNewNonce);
150
151 FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, *outFace);
152
153 // Refresh measurements since Face is being used for forwarding
154 NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
155 namespaceInfo.extendFaceInfoLifetime(faceInfo, *outFace);
156
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()
162 << " FaceId: " << outFace->getId()
163 << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
164
165 scheduler::EventId id = scheduler::schedule(timeout,
166 bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace->getId()));
167
168 faceInfo.setTimeoutEvent(id, interest.getName());
169 }
170}
171
172struct FaceStats
173{
174 shared_ptr<Face> face;
175 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
199const shared_ptr<Face>
200AsfStrategy::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()) {
225
226 const shared_ptr<Face>& hopFace = hop.getFace();
227
228 if (hopFace->getId() == inFace.getId()) {
229 continue;
230 }
231
232 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, *hopFace);
233
234 if (info == nullptr) {
235 FaceStats stats = {hopFace,
236 RttStats::RTT_NO_MEASUREMENT,
237 RttStats::RTT_NO_MEASUREMENT,
238 hop.getCost()};
239
240 rankedFaces.insert(stats);
241 }
242 else {
243 FaceStats stats = {hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
244 rankedFaces.insert(stats);
245 }
246 }
247
248 FaceStatsSet::iterator it = rankedFaces.begin();
249
250 if (it != rankedFaces.end()) {
251 return it->face;
252 }
253 else {
254 return nullptr;
255 }
256}
257
258void
259AsfStrategy::onTimeout(const ndn::Name& interestName, nfd::face::FaceId faceId)
260{
261 NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
262
263 shared_ptr<NamespaceInfo> namespaceInfo = m_measurements.getNamespaceInfo(interestName);
264
265 if (namespaceInfo == nullptr) {
266 NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
267 return;
268 }
269
270 FaceInfoTable::iterator it = namespaceInfo->find(faceId);
271
272 if (it == namespaceInfo->end()) {
273 it = namespaceInfo->insert(faceId);
274 }
275
276 FaceInfo& faceInfo = it->second;
277 faceInfo.recordTimeout(interestName);
278}
279
280void
281AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest, shared_ptr<pit::Entry> pitEntry)
282{
283 NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
284
285 lp::NackHeader nackHeader;
286 nackHeader.setReason(lp::NackReason::NO_ROUTE);
287 this->sendNack(pitEntry, inFace, nackHeader);
288}
289
290} // namespace asf
291} // namespace fw
292} // namespace nfd