blob: c096fe1898db9c966f110dceb8df6734271c48b5 [file] [log] [blame]
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shifef73e42016-03-29 14:15:05 -07003 * Copyright (c) 2014-2016, Regents of the University of California,
Junxiao Shi63162202015-01-14 22:27:33 -07004 * 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.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
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/>.
Junxiao Shiaf6569a2014-06-14 00:01:34 -070024 */
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070025
26#include "ncc-strategy.hpp"
Junxiao Shifef73e42016-03-29 14:15:05 -070027#include "pit-algorithm.hpp"
Junxiao Shiaf6569a2014-06-14 00:01:34 -070028#include "core/random.hpp"
29#include <boost/random/uniform_int_distribution.hpp>
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070030
31namespace nfd {
32namespace fw {
33
Junxiao Shie93d6a32014-09-07 16:13:22 -070034const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc/%FD%01");
Junxiao Shifaf3eb02015-02-16 10:50:36 -070035NFD_REGISTER_STRATEGY(NccStrategy);
Junxiao Shif3c07812014-03-11 21:48:49 -070036
37NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
38 : Strategy(forwarder, name)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070039{
40}
41
42NccStrategy::~NccStrategy()
43{
44}
45
Junxiao Shi1391d612014-03-27 22:27:20 -070046const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = time::microseconds(4000);
47const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = time::microseconds(75000);
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070048const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070049
50void
51NccStrategy::afterReceiveInterest(const Face& inFace,
52 const Interest& interest,
53 shared_ptr<fib::Entry> fibEntry,
54 shared_ptr<pit::Entry> pitEntry)
55{
56 const fib::NextHopList& nexthops = fibEntry->getNextHops();
57 if (nexthops.size() == 0) {
58 this->rejectPendingInterest(pitEntry);
59 return;
60 }
61
62 shared_ptr<PitEntryInfo> pitEntryInfo =
63 pitEntry->getOrCreateStrategyInfo<PitEntryInfo>();
Junxiao Shifef73e42016-03-29 14:15:05 -070064 bool isNewPitEntry = !hasPendingOutRecords(*pitEntry);
Junxiao Shi8bfd56d2014-10-08 10:06:00 -070065 if (!isNewPitEntry) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070066 return;
67 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070068
69 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
70 this->getMeasurementsEntryInfo(pitEntry);
71
Junxiao Shi1391d612014-03-27 22:27:20 -070072 time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
73 time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070074 size_t nUpstreams = nexthops.size();
75
76 shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
77 if (static_cast<bool>(bestFace) && fibEntry->hasNextHop(bestFace) &&
Junxiao Shifef73e42016-03-29 14:15:05 -070078 canForwardToLegacy(*pitEntry, *bestFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070079 // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
Junxiao Shi1391d612014-03-27 22:27:20 -070080 deferFirst = measurementsEntryInfo->prediction;
81 deferRange = time::microseconds((deferFirst.count() + 1) / 2);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070082 --nUpstreams;
83 this->sendInterest(pitEntry, bestFace);
Junxiao Shi1391d612014-03-27 22:27:20 -070084 pitEntryInfo->bestFaceTimeout = scheduler::schedule(
85 measurementsEntryInfo->prediction,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070086 bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
87 }
88 else {
Junxiao Shi63162202015-01-14 22:27:33 -070089 // use first eligible nexthop
90 auto firstEligibleNexthop = std::find_if(nexthops.begin(), nexthops.end(),
91 [&pitEntry] (const fib::NextHop& nexthop) {
Junxiao Shifef73e42016-03-29 14:15:05 -070092 return canForwardToLegacy(*pitEntry, *nexthop.getFace());
Junxiao Shi63162202015-01-14 22:27:33 -070093 });
94 if (firstEligibleNexthop != nexthops.end()) {
95 this->sendInterest(pitEntry, firstEligibleNexthop->getFace());
96 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070097 }
98
Junxiao Shi1391d612014-03-27 22:27:20 -070099 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700100 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shifef73e42016-03-29 14:15:05 -0700101 canForwardToLegacy(*pitEntry, *previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700102 --nUpstreams;
103 }
104
Junxiao Shi1391d612014-03-27 22:27:20 -0700105 if (nUpstreams > 0) {
106 pitEntryInfo->maxInterval = std::max(time::microseconds(1),
107 time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
108 }
Junxiao Shicbb490a2014-08-13 12:24:24 -0700109 else {
110 // Normally, maxInterval is unused if there aren't any face beyond best and previousBest.
111 // However, in case FIB entry gains a new nexthop before doPropagate executes (bug 1853),
112 // this maxInterval would be used to determine when the next doPropagate would happen.
113 pitEntryInfo->maxInterval = deferFirst;
114 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700115 pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700116 bind(&NccStrategy::doPropagate, this,
117 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
118}
119
120void
121NccStrategy::doPropagate(weak_ptr<pit::Entry> pitEntryWeak, weak_ptr<fib::Entry> fibEntryWeak)
122{
123 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
124 if (!static_cast<bool>(pitEntry)) {
125 return;
126 }
127 shared_ptr<fib::Entry> fibEntry = fibEntryWeak.lock();
128 if (!static_cast<bool>(fibEntry)) {
129 return;
130 }
131
Junxiao Shi1391d612014-03-27 22:27:20 -0700132 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
133 // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
134 // from a timer set by NccStrategy.
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700135 BOOST_ASSERT(static_cast<bool>(pitEntryInfo));
136
137 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
138 this->getMeasurementsEntryInfo(pitEntry);
139
Junxiao Shi1391d612014-03-27 22:27:20 -0700140 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700141 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shifef73e42016-03-29 14:15:05 -0700142 canForwardToLegacy(*pitEntry, *previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700143 this->sendInterest(pitEntry, previousFace);
144 }
145
146 const fib::NextHopList& nexthops = fibEntry->getNextHops();
147 bool isForwarded = false;
148 for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
149 shared_ptr<Face> face = it->getFace();
Junxiao Shifef73e42016-03-29 14:15:05 -0700150 if (canForwardToLegacy(*pitEntry, *face)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700151 isForwarded = true;
152 this->sendInterest(pitEntry, face);
153 break;
154 }
155 }
156
157 if (isForwarded) {
Junxiao Shicbb490a2014-08-13 12:24:24 -0700158 boost::random::uniform_int_distribution<time::nanoseconds::rep> dist(0,
159 pitEntryInfo->maxInterval.count() - 1);
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700160 time::nanoseconds deferNext = time::nanoseconds(dist(getGlobalRng()));
Junxiao Shi1391d612014-03-27 22:27:20 -0700161 pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700162 bind(&NccStrategy::doPropagate, this,
163 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
164 }
165}
166
167void
168NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
169{
170 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
171 if (!static_cast<bool>(pitEntry)) {
172 return;
173 }
174 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
175
176 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
177 if (!static_cast<bool>(measurementsEntry)) {
178 // going out of this strategy's namespace
179 return;
180 }
Junxiao Shie368d992014-12-02 23:44:31 -0700181 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700182
183 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
184 this->getMeasurementsEntryInfo(measurementsEntry);
185 measurementsEntryInfo->adjustPredictUp();
186
Junxiao Shie368d992014-12-02 23:44:31 -0700187 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700188 }
189}
190
191void
Junxiao Shi82e7f582014-09-07 15:15:40 -0700192NccStrategy::beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
193 const Face& inFace, const Data& data)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700194{
Junxiao Shi4846f372016-04-05 13:39:30 -0700195 if (!pitEntry->hasInRecords()) {
Junxiao Shi82e7f582014-09-07 15:15:40 -0700196 // PIT entry has already been satisfied (and is now waiting for straggler timer to expire)
197 // NCC does not collect measurements for non-best face
198 return;
199 }
200
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700201 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
202
203 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
204 if (!static_cast<bool>(measurementsEntry)) {
205 // going out of this strategy's namespace
206 return;
207 }
Junxiao Shie368d992014-12-02 23:44:31 -0700208 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700209
210 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
211 this->getMeasurementsEntryInfo(measurementsEntry);
212 measurementsEntryInfo->updateBestFace(inFace);
213
Junxiao Shie368d992014-12-02 23:44:31 -0700214 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700215 }
216
Junxiao Shi1391d612014-03-27 22:27:20 -0700217 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
Hila Ben Abraham39a79be2016-03-30 22:00:55 -0700218 if (pitEntryInfo != nullptr) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700219 scheduler::cancel(pitEntryInfo->propagateTimer);
Hila Ben Abraham39a79be2016-03-30 22:00:55 -0700220
221 // Verify that the best face satisfied the interest before canceling the timeout call
222 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
223 this->getMeasurementsEntryInfo(pitEntry);
224 shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
225
226 if (bestFace.get() == &inFace)
227 scheduler::cancel(pitEntryInfo->bestFaceTimeout);
Junxiao Shi1391d612014-03-27 22:27:20 -0700228 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700229}
230
231shared_ptr<NccStrategy::MeasurementsEntryInfo>
232NccStrategy::getMeasurementsEntryInfo(shared_ptr<pit::Entry> entry)
233{
234 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*entry);
235 return this->getMeasurementsEntryInfo(measurementsEntry);
236}
237
238shared_ptr<NccStrategy::MeasurementsEntryInfo>
239NccStrategy::getMeasurementsEntryInfo(shared_ptr<measurements::Entry> entry)
240{
241 shared_ptr<MeasurementsEntryInfo> info = entry->getStrategyInfo<MeasurementsEntryInfo>();
242 if (static_cast<bool>(info)) {
243 return info;
244 }
245
246 info = make_shared<MeasurementsEntryInfo>();
247 entry->setStrategyInfo(info);
248
Junxiao Shie368d992014-12-02 23:44:31 -0700249 shared_ptr<measurements::Entry> parentEntry = this->getMeasurements().getParent(*entry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700250 if (static_cast<bool>(parentEntry)) {
251 shared_ptr<MeasurementsEntryInfo> parentInfo = this->getMeasurementsEntryInfo(parentEntry);
252 BOOST_ASSERT(static_cast<bool>(parentInfo));
253 info->inheritFrom(*parentInfo);
254 }
255
256 return info;
257}
258
259
Junxiao Shi1391d612014-03-27 22:27:20 -0700260const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION =
261 time::microseconds(8192);
262const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION =
263 time::microseconds(127);
264const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION =
265 time::microseconds(160000);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700266
267NccStrategy::MeasurementsEntryInfo::MeasurementsEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700268 : prediction(INITIAL_PREDICTION)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700269{
270}
271
272void
273NccStrategy::MeasurementsEntryInfo::inheritFrom(const MeasurementsEntryInfo& other)
274{
275 this->operator=(other);
276}
277
278shared_ptr<Face>
279NccStrategy::MeasurementsEntryInfo::getBestFace(void) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700280 shared_ptr<Face> best = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700281 if (static_cast<bool>(best)) {
282 return best;
283 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700284 this->bestFace = best = this->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700285 return best;
286}
287
288void
289NccStrategy::MeasurementsEntryInfo::updateBestFace(const Face& face) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700290 if (this->bestFace.expired()) {
291 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700292 return;
293 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700294 shared_ptr<Face> bestFace = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700295 if (bestFace.get() == &face) {
296 this->adjustPredictDown();
297 }
298 else {
Junxiao Shi1391d612014-03-27 22:27:20 -0700299 this->previousFace = this->bestFace;
300 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700301 }
302}
303
304void
305NccStrategy::MeasurementsEntryInfo::adjustPredictDown() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700306 prediction = std::max(MIN_PREDICTION,
307 time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700308}
309
310void
311NccStrategy::MeasurementsEntryInfo::adjustPredictUp() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700312 prediction = std::min(MAX_PREDICTION,
313 time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700314}
315
316void
317NccStrategy::MeasurementsEntryInfo::ageBestFace() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700318 this->previousFace = this->bestFace;
319 this->bestFace.reset();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700320}
321
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700322NccStrategy::PitEntryInfo::~PitEntryInfo()
323{
Junxiao Shi1391d612014-03-27 22:27:20 -0700324 scheduler::cancel(this->bestFaceTimeout);
325 scheduler::cancel(this->propagateTimer);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700326}
327
328} // namespace fw
329} // namespace nfd