blob: b9a0ce43cd576f7a8450611deb5f79d0eb52d4c5 [file] [log] [blame]
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi63162202015-01-14 22:27:33 -07003 * Copyright (c) 2014-2015, 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.
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 Shiaf6569a2014-06-14 00:01:34 -070027#include "core/random.hpp"
28#include <boost/random/uniform_int_distribution.hpp>
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070029
30namespace nfd {
31namespace fw {
32
Junxiao Shie93d6a32014-09-07 16:13:22 -070033const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc/%FD%01");
Junxiao Shif3c07812014-03-11 21:48:49 -070034
35NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
36 : Strategy(forwarder, name)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070037{
38}
39
40NccStrategy::~NccStrategy()
41{
42}
43
Junxiao Shi1391d612014-03-27 22:27:20 -070044const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = time::microseconds(4000);
45const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = time::microseconds(75000);
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070046const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070047
48void
49NccStrategy::afterReceiveInterest(const Face& inFace,
50 const Interest& interest,
51 shared_ptr<fib::Entry> fibEntry,
52 shared_ptr<pit::Entry> pitEntry)
53{
54 const fib::NextHopList& nexthops = fibEntry->getNextHops();
55 if (nexthops.size() == 0) {
56 this->rejectPendingInterest(pitEntry);
57 return;
58 }
59
60 shared_ptr<PitEntryInfo> pitEntryInfo =
61 pitEntry->getOrCreateStrategyInfo<PitEntryInfo>();
Junxiao Shi8bfd56d2014-10-08 10:06:00 -070062 bool isNewPitEntry = !pitEntry->hasUnexpiredOutRecords();
63 if (!isNewPitEntry) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070064 return;
65 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070066
67 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
68 this->getMeasurementsEntryInfo(pitEntry);
69
Junxiao Shi1391d612014-03-27 22:27:20 -070070 time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
71 time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070072 size_t nUpstreams = nexthops.size();
73
74 shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
75 if (static_cast<bool>(bestFace) && fibEntry->hasNextHop(bestFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -070076 pitEntry->canForwardTo(*bestFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070077 // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
Junxiao Shi1391d612014-03-27 22:27:20 -070078 deferFirst = measurementsEntryInfo->prediction;
79 deferRange = time::microseconds((deferFirst.count() + 1) / 2);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070080 --nUpstreams;
81 this->sendInterest(pitEntry, bestFace);
Junxiao Shi1391d612014-03-27 22:27:20 -070082 pitEntryInfo->bestFaceTimeout = scheduler::schedule(
83 measurementsEntryInfo->prediction,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070084 bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
85 }
86 else {
Junxiao Shi63162202015-01-14 22:27:33 -070087 // use first eligible nexthop
88 auto firstEligibleNexthop = std::find_if(nexthops.begin(), nexthops.end(),
89 [&pitEntry] (const fib::NextHop& nexthop) {
90 return pitEntry->canForwardTo(*nexthop.getFace());
91 });
92 if (firstEligibleNexthop != nexthops.end()) {
93 this->sendInterest(pitEntry, firstEligibleNexthop->getFace());
94 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070095 }
96
Junxiao Shi1391d612014-03-27 22:27:20 -070097 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070098 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -070099 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700100 --nUpstreams;
101 }
102
Junxiao Shi1391d612014-03-27 22:27:20 -0700103 if (nUpstreams > 0) {
104 pitEntryInfo->maxInterval = std::max(time::microseconds(1),
105 time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
106 }
Junxiao Shicbb490a2014-08-13 12:24:24 -0700107 else {
108 // Normally, maxInterval is unused if there aren't any face beyond best and previousBest.
109 // However, in case FIB entry gains a new nexthop before doPropagate executes (bug 1853),
110 // this maxInterval would be used to determine when the next doPropagate would happen.
111 pitEntryInfo->maxInterval = deferFirst;
112 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700113 pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700114 bind(&NccStrategy::doPropagate, this,
115 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
116}
117
118void
119NccStrategy::doPropagate(weak_ptr<pit::Entry> pitEntryWeak, weak_ptr<fib::Entry> fibEntryWeak)
120{
121 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
122 if (!static_cast<bool>(pitEntry)) {
123 return;
124 }
125 shared_ptr<fib::Entry> fibEntry = fibEntryWeak.lock();
126 if (!static_cast<bool>(fibEntry)) {
127 return;
128 }
129
Junxiao Shi1391d612014-03-27 22:27:20 -0700130 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
131 // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
132 // from a timer set by NccStrategy.
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700133 BOOST_ASSERT(static_cast<bool>(pitEntryInfo));
134
135 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
136 this->getMeasurementsEntryInfo(pitEntry);
137
Junxiao Shi1391d612014-03-27 22:27:20 -0700138 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700139 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -0700140 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700141 this->sendInterest(pitEntry, previousFace);
142 }
143
144 const fib::NextHopList& nexthops = fibEntry->getNextHops();
145 bool isForwarded = false;
146 for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
147 shared_ptr<Face> face = it->getFace();
Junxiao Shi57f0f312014-03-16 11:52:20 -0700148 if (pitEntry->canForwardTo(*face)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700149 isForwarded = true;
150 this->sendInterest(pitEntry, face);
151 break;
152 }
153 }
154
155 if (isForwarded) {
Junxiao Shicbb490a2014-08-13 12:24:24 -0700156 boost::random::uniform_int_distribution<time::nanoseconds::rep> dist(0,
157 pitEntryInfo->maxInterval.count() - 1);
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700158 time::nanoseconds deferNext = time::nanoseconds(dist(getGlobalRng()));
Junxiao Shi1391d612014-03-27 22:27:20 -0700159 pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700160 bind(&NccStrategy::doPropagate, this,
161 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
162 }
163}
164
165void
166NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
167{
168 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
169 if (!static_cast<bool>(pitEntry)) {
170 return;
171 }
172 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
173
174 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
175 if (!static_cast<bool>(measurementsEntry)) {
176 // going out of this strategy's namespace
177 return;
178 }
Junxiao Shie368d992014-12-02 23:44:31 -0700179 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700180
181 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
182 this->getMeasurementsEntryInfo(measurementsEntry);
183 measurementsEntryInfo->adjustPredictUp();
184
Junxiao Shie368d992014-12-02 23:44:31 -0700185 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700186 }
187}
188
189void
Junxiao Shi82e7f582014-09-07 15:15:40 -0700190NccStrategy::beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
191 const Face& inFace, const Data& data)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700192{
Junxiao Shi82e7f582014-09-07 15:15:40 -0700193 if (pitEntry->getInRecords().empty()) {
194 // PIT entry has already been satisfied (and is now waiting for straggler timer to expire)
195 // NCC does not collect measurements for non-best face
196 return;
197 }
198
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700199 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
200
201 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
202 if (!static_cast<bool>(measurementsEntry)) {
203 // going out of this strategy's namespace
204 return;
205 }
Junxiao Shie368d992014-12-02 23:44:31 -0700206 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700207
208 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
209 this->getMeasurementsEntryInfo(measurementsEntry);
210 measurementsEntryInfo->updateBestFace(inFace);
211
Junxiao Shie368d992014-12-02 23:44:31 -0700212 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700213 }
214
Junxiao Shi1391d612014-03-27 22:27:20 -0700215 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
216 if (static_cast<bool>(pitEntryInfo)) {
217 scheduler::cancel(pitEntryInfo->propagateTimer);
218 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700219}
220
221shared_ptr<NccStrategy::MeasurementsEntryInfo>
222NccStrategy::getMeasurementsEntryInfo(shared_ptr<pit::Entry> entry)
223{
224 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*entry);
225 return this->getMeasurementsEntryInfo(measurementsEntry);
226}
227
228shared_ptr<NccStrategy::MeasurementsEntryInfo>
229NccStrategy::getMeasurementsEntryInfo(shared_ptr<measurements::Entry> entry)
230{
231 shared_ptr<MeasurementsEntryInfo> info = entry->getStrategyInfo<MeasurementsEntryInfo>();
232 if (static_cast<bool>(info)) {
233 return info;
234 }
235
236 info = make_shared<MeasurementsEntryInfo>();
237 entry->setStrategyInfo(info);
238
Junxiao Shie368d992014-12-02 23:44:31 -0700239 shared_ptr<measurements::Entry> parentEntry = this->getMeasurements().getParent(*entry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700240 if (static_cast<bool>(parentEntry)) {
241 shared_ptr<MeasurementsEntryInfo> parentInfo = this->getMeasurementsEntryInfo(parentEntry);
242 BOOST_ASSERT(static_cast<bool>(parentInfo));
243 info->inheritFrom(*parentInfo);
244 }
245
246 return info;
247}
248
249
Junxiao Shi1391d612014-03-27 22:27:20 -0700250const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION =
251 time::microseconds(8192);
252const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION =
253 time::microseconds(127);
254const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION =
255 time::microseconds(160000);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700256
257NccStrategy::MeasurementsEntryInfo::MeasurementsEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700258 : prediction(INITIAL_PREDICTION)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700259{
260}
261
262void
263NccStrategy::MeasurementsEntryInfo::inheritFrom(const MeasurementsEntryInfo& other)
264{
265 this->operator=(other);
266}
267
268shared_ptr<Face>
269NccStrategy::MeasurementsEntryInfo::getBestFace(void) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700270 shared_ptr<Face> best = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700271 if (static_cast<bool>(best)) {
272 return best;
273 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700274 this->bestFace = best = this->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700275 return best;
276}
277
278void
279NccStrategy::MeasurementsEntryInfo::updateBestFace(const Face& face) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700280 if (this->bestFace.expired()) {
281 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700282 return;
283 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700284 shared_ptr<Face> bestFace = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700285 if (bestFace.get() == &face) {
286 this->adjustPredictDown();
287 }
288 else {
Junxiao Shi1391d612014-03-27 22:27:20 -0700289 this->previousFace = this->bestFace;
290 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700291 }
292}
293
294void
295NccStrategy::MeasurementsEntryInfo::adjustPredictDown() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700296 prediction = std::max(MIN_PREDICTION,
297 time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700298}
299
300void
301NccStrategy::MeasurementsEntryInfo::adjustPredictUp() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700302 prediction = std::min(MAX_PREDICTION,
303 time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700304}
305
306void
307NccStrategy::MeasurementsEntryInfo::ageBestFace() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700308 this->previousFace = this->bestFace;
309 this->bestFace.reset();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700310}
311
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700312NccStrategy::PitEntryInfo::~PitEntryInfo()
313{
Junxiao Shi1391d612014-03-27 22:27:20 -0700314 scheduler::cancel(this->bestFaceTimeout);
315 scheduler::cancel(this->propagateTimer);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700316}
317
318} // namespace fw
319} // namespace nfd