blob: 9ecb2cd0456bc486a0a0fb5d9aa71b8c528bd63d [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 Shifaf3eb02015-02-16 10:50:36 -070034NFD_REGISTER_STRATEGY(NccStrategy);
Junxiao Shif3c07812014-03-11 21:48:49 -070035
36NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
37 : Strategy(forwarder, name)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070038{
39}
40
41NccStrategy::~NccStrategy()
42{
43}
44
Junxiao Shi1391d612014-03-27 22:27:20 -070045const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = time::microseconds(4000);
46const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = time::microseconds(75000);
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070047const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070048
49void
50NccStrategy::afterReceiveInterest(const Face& inFace,
51 const Interest& interest,
52 shared_ptr<fib::Entry> fibEntry,
53 shared_ptr<pit::Entry> pitEntry)
54{
55 const fib::NextHopList& nexthops = fibEntry->getNextHops();
56 if (nexthops.size() == 0) {
57 this->rejectPendingInterest(pitEntry);
58 return;
59 }
60
61 shared_ptr<PitEntryInfo> pitEntryInfo =
62 pitEntry->getOrCreateStrategyInfo<PitEntryInfo>();
Junxiao Shi8bfd56d2014-10-08 10:06:00 -070063 bool isNewPitEntry = !pitEntry->hasUnexpiredOutRecords();
64 if (!isNewPitEntry) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070065 return;
66 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070067
68 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
69 this->getMeasurementsEntryInfo(pitEntry);
70
Junxiao Shi1391d612014-03-27 22:27:20 -070071 time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
72 time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070073 size_t nUpstreams = nexthops.size();
74
75 shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
76 if (static_cast<bool>(bestFace) && fibEntry->hasNextHop(bestFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -070077 pitEntry->canForwardTo(*bestFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070078 // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
Junxiao Shi1391d612014-03-27 22:27:20 -070079 deferFirst = measurementsEntryInfo->prediction;
80 deferRange = time::microseconds((deferFirst.count() + 1) / 2);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070081 --nUpstreams;
82 this->sendInterest(pitEntry, bestFace);
Junxiao Shi1391d612014-03-27 22:27:20 -070083 pitEntryInfo->bestFaceTimeout = scheduler::schedule(
84 measurementsEntryInfo->prediction,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070085 bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
86 }
87 else {
Junxiao Shi63162202015-01-14 22:27:33 -070088 // use first eligible nexthop
89 auto firstEligibleNexthop = std::find_if(nexthops.begin(), nexthops.end(),
90 [&pitEntry] (const fib::NextHop& nexthop) {
91 return pitEntry->canForwardTo(*nexthop.getFace());
92 });
93 if (firstEligibleNexthop != nexthops.end()) {
94 this->sendInterest(pitEntry, firstEligibleNexthop->getFace());
95 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070096 }
97
Junxiao Shi1391d612014-03-27 22:27:20 -070098 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070099 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -0700100 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700101 --nUpstreams;
102 }
103
Junxiao Shi1391d612014-03-27 22:27:20 -0700104 if (nUpstreams > 0) {
105 pitEntryInfo->maxInterval = std::max(time::microseconds(1),
106 time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
107 }
Junxiao Shicbb490a2014-08-13 12:24:24 -0700108 else {
109 // Normally, maxInterval is unused if there aren't any face beyond best and previousBest.
110 // However, in case FIB entry gains a new nexthop before doPropagate executes (bug 1853),
111 // this maxInterval would be used to determine when the next doPropagate would happen.
112 pitEntryInfo->maxInterval = deferFirst;
113 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700114 pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700115 bind(&NccStrategy::doPropagate, this,
116 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
117}
118
119void
120NccStrategy::doPropagate(weak_ptr<pit::Entry> pitEntryWeak, weak_ptr<fib::Entry> fibEntryWeak)
121{
122 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
123 if (!static_cast<bool>(pitEntry)) {
124 return;
125 }
126 shared_ptr<fib::Entry> fibEntry = fibEntryWeak.lock();
127 if (!static_cast<bool>(fibEntry)) {
128 return;
129 }
130
Junxiao Shi1391d612014-03-27 22:27:20 -0700131 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
132 // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
133 // from a timer set by NccStrategy.
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700134 BOOST_ASSERT(static_cast<bool>(pitEntryInfo));
135
136 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
137 this->getMeasurementsEntryInfo(pitEntry);
138
Junxiao Shi1391d612014-03-27 22:27:20 -0700139 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700140 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -0700141 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700142 this->sendInterest(pitEntry, previousFace);
143 }
144
145 const fib::NextHopList& nexthops = fibEntry->getNextHops();
146 bool isForwarded = false;
147 for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
148 shared_ptr<Face> face = it->getFace();
Junxiao Shi57f0f312014-03-16 11:52:20 -0700149 if (pitEntry->canForwardTo(*face)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700150 isForwarded = true;
151 this->sendInterest(pitEntry, face);
152 break;
153 }
154 }
155
156 if (isForwarded) {
Junxiao Shicbb490a2014-08-13 12:24:24 -0700157 boost::random::uniform_int_distribution<time::nanoseconds::rep> dist(0,
158 pitEntryInfo->maxInterval.count() - 1);
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700159 time::nanoseconds deferNext = time::nanoseconds(dist(getGlobalRng()));
Junxiao Shi1391d612014-03-27 22:27:20 -0700160 pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700161 bind(&NccStrategy::doPropagate, this,
162 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
163 }
164}
165
166void
167NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
168{
169 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
170 if (!static_cast<bool>(pitEntry)) {
171 return;
172 }
173 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
174
175 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
176 if (!static_cast<bool>(measurementsEntry)) {
177 // going out of this strategy's namespace
178 return;
179 }
Junxiao Shie368d992014-12-02 23:44:31 -0700180 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700181
182 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
183 this->getMeasurementsEntryInfo(measurementsEntry);
184 measurementsEntryInfo->adjustPredictUp();
185
Junxiao Shie368d992014-12-02 23:44:31 -0700186 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700187 }
188}
189
190void
Junxiao Shi82e7f582014-09-07 15:15:40 -0700191NccStrategy::beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
192 const Face& inFace, const Data& data)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700193{
Junxiao Shi82e7f582014-09-07 15:15:40 -0700194 if (pitEntry->getInRecords().empty()) {
195 // PIT entry has already been satisfied (and is now waiting for straggler timer to expire)
196 // NCC does not collect measurements for non-best face
197 return;
198 }
199
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700200 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
201
202 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
203 if (!static_cast<bool>(measurementsEntry)) {
204 // going out of this strategy's namespace
205 return;
206 }
Junxiao Shie368d992014-12-02 23:44:31 -0700207 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700208
209 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
210 this->getMeasurementsEntryInfo(measurementsEntry);
211 measurementsEntryInfo->updateBestFace(inFace);
212
Junxiao Shie368d992014-12-02 23:44:31 -0700213 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700214 }
215
Junxiao Shi1391d612014-03-27 22:27:20 -0700216 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
217 if (static_cast<bool>(pitEntryInfo)) {
218 scheduler::cancel(pitEntryInfo->propagateTimer);
219 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700220}
221
222shared_ptr<NccStrategy::MeasurementsEntryInfo>
223NccStrategy::getMeasurementsEntryInfo(shared_ptr<pit::Entry> entry)
224{
225 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*entry);
226 return this->getMeasurementsEntryInfo(measurementsEntry);
227}
228
229shared_ptr<NccStrategy::MeasurementsEntryInfo>
230NccStrategy::getMeasurementsEntryInfo(shared_ptr<measurements::Entry> entry)
231{
232 shared_ptr<MeasurementsEntryInfo> info = entry->getStrategyInfo<MeasurementsEntryInfo>();
233 if (static_cast<bool>(info)) {
234 return info;
235 }
236
237 info = make_shared<MeasurementsEntryInfo>();
238 entry->setStrategyInfo(info);
239
Junxiao Shie368d992014-12-02 23:44:31 -0700240 shared_ptr<measurements::Entry> parentEntry = this->getMeasurements().getParent(*entry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700241 if (static_cast<bool>(parentEntry)) {
242 shared_ptr<MeasurementsEntryInfo> parentInfo = this->getMeasurementsEntryInfo(parentEntry);
243 BOOST_ASSERT(static_cast<bool>(parentInfo));
244 info->inheritFrom(*parentInfo);
245 }
246
247 return info;
248}
249
250
Junxiao Shi1391d612014-03-27 22:27:20 -0700251const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION =
252 time::microseconds(8192);
253const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION =
254 time::microseconds(127);
255const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION =
256 time::microseconds(160000);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700257
258NccStrategy::MeasurementsEntryInfo::MeasurementsEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700259 : prediction(INITIAL_PREDICTION)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700260{
261}
262
263void
264NccStrategy::MeasurementsEntryInfo::inheritFrom(const MeasurementsEntryInfo& other)
265{
266 this->operator=(other);
267}
268
269shared_ptr<Face>
270NccStrategy::MeasurementsEntryInfo::getBestFace(void) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700271 shared_ptr<Face> best = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700272 if (static_cast<bool>(best)) {
273 return best;
274 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700275 this->bestFace = best = this->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700276 return best;
277}
278
279void
280NccStrategy::MeasurementsEntryInfo::updateBestFace(const Face& face) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700281 if (this->bestFace.expired()) {
282 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700283 return;
284 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700285 shared_ptr<Face> bestFace = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700286 if (bestFace.get() == &face) {
287 this->adjustPredictDown();
288 }
289 else {
Junxiao Shi1391d612014-03-27 22:27:20 -0700290 this->previousFace = this->bestFace;
291 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700292 }
293}
294
295void
296NccStrategy::MeasurementsEntryInfo::adjustPredictDown() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700297 prediction = std::max(MIN_PREDICTION,
298 time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700299}
300
301void
302NccStrategy::MeasurementsEntryInfo::adjustPredictUp() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700303 prediction = std::min(MAX_PREDICTION,
304 time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700305}
306
307void
308NccStrategy::MeasurementsEntryInfo::ageBestFace() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700309 this->previousFace = this->bestFace;
310 this->bestFace.reset();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700311}
312
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700313NccStrategy::PitEntryInfo::~PitEntryInfo()
314{
Junxiao Shi1391d612014-03-27 22:27:20 -0700315 scheduler::cancel(this->bestFaceTimeout);
316 scheduler::cancel(this->propagateTimer);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700317}
318
319} // namespace fw
320} // namespace nfd