blob: 2ae2fd05a4e08a14533eeaf23d5f051614c93e22 [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 Shi00dc9142016-11-21 14:23:12 +000027#include "algorithm.hpp"
Junxiao Shiaf6569a2014-06-14 00:01:34 -070028#include "core/random.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
Junxiao Shi1391d612014-03-27 22:27:20 -070041const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = time::microseconds(4000);
42const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = time::microseconds(75000);
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070043const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070044
45void
Junxiao Shi15e98b02016-08-12 11:21:44 +000046NccStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
47 const shared_ptr<pit::Entry>& pitEntry)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070048{
Junxiao Shi8d843142016-07-11 22:42:42 +000049 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
50 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070051 if (nexthops.size() == 0) {
52 this->rejectPendingInterest(pitEntry);
53 return;
54 }
55
Junxiao Shifc021862016-08-25 21:51:18 +000056 PitEntryInfo* pitEntryInfo = pitEntry->insertStrategyInfo<PitEntryInfo>().first;
Junxiao Shifef73e42016-03-29 14:15:05 -070057 bool isNewPitEntry = !hasPendingOutRecords(*pitEntry);
Junxiao Shi8bfd56d2014-10-08 10:06:00 -070058 if (!isNewPitEntry) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070059 return;
60 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070061
Junxiao Shi80f9fcd2016-07-23 02:48:36 +000062 MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070063
Junxiao Shi1391d612014-03-27 22:27:20 -070064 time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
65 time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070066 size_t nUpstreams = nexthops.size();
67
Junxiao Shi80f9fcd2016-07-23 02:48:36 +000068 shared_ptr<Face> bestFace = meInfo.getBestFace();
Junxiao Shia6de4292016-07-12 02:08:10 +000069 if (bestFace != nullptr && fibEntry.hasNextHop(*bestFace) &&
Junxiao Shifef73e42016-03-29 14:15:05 -070070 canForwardToLegacy(*pitEntry, *bestFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070071 // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
Junxiao Shi80f9fcd2016-07-23 02:48:36 +000072 deferFirst = meInfo.prediction;
Junxiao Shi1391d612014-03-27 22:27:20 -070073 deferRange = time::microseconds((deferFirst.count() + 1) / 2);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070074 --nUpstreams;
Junxiao Shia6de4292016-07-12 02:08:10 +000075 this->sendInterest(pitEntry, *bestFace);
Junxiao Shi1391d612014-03-27 22:27:20 -070076 pitEntryInfo->bestFaceTimeout = scheduler::schedule(
Junxiao Shi80f9fcd2016-07-23 02:48:36 +000077 meInfo.prediction,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070078 bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
79 }
80 else {
Junxiao Shi63162202015-01-14 22:27:33 -070081 // use first eligible nexthop
82 auto firstEligibleNexthop = std::find_if(nexthops.begin(), nexthops.end(),
83 [&pitEntry] (const fib::NextHop& nexthop) {
Junxiao Shia6de4292016-07-12 02:08:10 +000084 return canForwardToLegacy(*pitEntry, nexthop.getFace());
Junxiao Shi63162202015-01-14 22:27:33 -070085 });
86 if (firstEligibleNexthop != nexthops.end()) {
87 this->sendInterest(pitEntry, firstEligibleNexthop->getFace());
88 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070089 }
90
Junxiao Shi80f9fcd2016-07-23 02:48:36 +000091 shared_ptr<Face> previousFace = meInfo.previousFace.lock();
Junxiao Shia6de4292016-07-12 02:08:10 +000092 if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
Junxiao Shifef73e42016-03-29 14:15:05 -070093 canForwardToLegacy(*pitEntry, *previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070094 --nUpstreams;
95 }
96
Junxiao Shi1391d612014-03-27 22:27:20 -070097 if (nUpstreams > 0) {
98 pitEntryInfo->maxInterval = std::max(time::microseconds(1),
99 time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
100 }
Junxiao Shicbb490a2014-08-13 12:24:24 -0700101 else {
102 // Normally, maxInterval is unused if there aren't any face beyond best and previousBest.
103 // However, in case FIB entry gains a new nexthop before doPropagate executes (bug 1853),
104 // this maxInterval would be used to determine when the next doPropagate would happen.
105 pitEntryInfo->maxInterval = deferFirst;
106 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700107 pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000108 bind(&NccStrategy::doPropagate, this, weak_ptr<pit::Entry>(pitEntry)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700109}
110
111void
Junxiao Shi8d843142016-07-11 22:42:42 +0000112NccStrategy::doPropagate(weak_ptr<pit::Entry> pitEntryWeak)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700113{
114 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
Junxiao Shi8d843142016-07-11 22:42:42 +0000115 if (pitEntry == nullptr) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700116 return;
117 }
Junxiao Shi8d843142016-07-11 22:42:42 +0000118 const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700119
Junxiao Shifc021862016-08-25 21:51:18 +0000120 PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
Junxiao Shi1391d612014-03-27 22:27:20 -0700121 // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
122 // from a timer set by NccStrategy.
Junxiao Shi8d843142016-07-11 22:42:42 +0000123 BOOST_ASSERT(pitEntryInfo != nullptr);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700124
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000125 MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700126
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000127 shared_ptr<Face> previousFace = meInfo.previousFace.lock();
Junxiao Shia6de4292016-07-12 02:08:10 +0000128 if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
Junxiao Shifef73e42016-03-29 14:15:05 -0700129 canForwardToLegacy(*pitEntry, *previousFace)) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000130 this->sendInterest(pitEntry, *previousFace);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700131 }
132
Junxiao Shi8d843142016-07-11 22:42:42 +0000133 const fib::NextHopList& nexthops = fibEntry.getNextHops();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700134 bool isForwarded = false;
135 for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
Junxiao Shia6de4292016-07-12 02:08:10 +0000136 Face& face = it->getFace();
137 if (canForwardToLegacy(*pitEntry, face)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700138 isForwarded = true;
139 this->sendInterest(pitEntry, face);
140 break;
141 }
142 }
143
144 if (isForwarded) {
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200145 std::uniform_int_distribution<time::nanoseconds::rep> dist(0, pitEntryInfo->maxInterval.count() - 1);
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700146 time::nanoseconds deferNext = time::nanoseconds(dist(getGlobalRng()));
Junxiao Shi1391d612014-03-27 22:27:20 -0700147 pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000148 bind(&NccStrategy::doPropagate, this, weak_ptr<pit::Entry>(pitEntry)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700149 }
150}
151
152void
153NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
154{
155 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000156 if (pitEntry == nullptr) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700157 return;
158 }
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000159 measurements::Entry* measurementsEntry = this->getMeasurements().get(*pitEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700160
161 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000162 if (measurementsEntry == nullptr) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700163 // going out of this strategy's namespace
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000164 break;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700165 }
Junxiao Shie368d992014-12-02 23:44:31 -0700166 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700167
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000168 MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(measurementsEntry);
169 meInfo.adjustPredictUp();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700170
Junxiao Shie368d992014-12-02 23:44:31 -0700171 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700172 }
173}
174
175void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000176NccStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shi82e7f582014-09-07 15:15:40 -0700177 const Face& inFace, const Data& data)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700178{
Junxiao Shi4846f372016-04-05 13:39:30 -0700179 if (!pitEntry->hasInRecords()) {
Junxiao Shi82e7f582014-09-07 15:15:40 -0700180 // PIT entry has already been satisfied (and is now waiting for straggler timer to expire)
181 // NCC does not collect measurements for non-best face
182 return;
183 }
184
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000185 measurements::Entry* measurementsEntry = this->getMeasurements().get(*pitEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700186
187 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000188 if (measurementsEntry == nullptr) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700189 // going out of this strategy's namespace
190 return;
191 }
Junxiao Shie368d992014-12-02 23:44:31 -0700192 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700193
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000194 MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(measurementsEntry);
195 meInfo.updateBestFace(inFace);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700196
Junxiao Shie368d992014-12-02 23:44:31 -0700197 measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700198 }
199
Junxiao Shifc021862016-08-25 21:51:18 +0000200 PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
Hila Ben Abraham39a79be2016-03-30 22:00:55 -0700201 if (pitEntryInfo != nullptr) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700202 scheduler::cancel(pitEntryInfo->propagateTimer);
Hila Ben Abraham39a79be2016-03-30 22:00:55 -0700203
204 // Verify that the best face satisfied the interest before canceling the timeout call
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000205 MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
206 shared_ptr<Face> bestFace = meInfo.getBestFace();
Hila Ben Abraham39a79be2016-03-30 22:00:55 -0700207
208 if (bestFace.get() == &inFace)
209 scheduler::cancel(pitEntryInfo->bestFaceTimeout);
Junxiao Shi1391d612014-03-27 22:27:20 -0700210 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700211}
212
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000213NccStrategy::MeasurementsEntryInfo&
Junxiao Shi15e98b02016-08-12 11:21:44 +0000214NccStrategy::getMeasurementsEntryInfo(const shared_ptr<pit::Entry>& entry)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700215{
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000216 measurements::Entry* measurementsEntry = this->getMeasurements().get(*entry);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700217 return this->getMeasurementsEntryInfo(measurementsEntry);
218}
219
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000220NccStrategy::MeasurementsEntryInfo&
221NccStrategy::getMeasurementsEntryInfo(measurements::Entry* entry)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700222{
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000223 BOOST_ASSERT(entry != nullptr);
Junxiao Shifc021862016-08-25 21:51:18 +0000224 MeasurementsEntryInfo* info = nullptr;
225 bool isNew = false;
226 std::tie(info, isNew) = entry->insertStrategyInfo<MeasurementsEntryInfo>();
227 if (!isNew) {
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000228 return *info;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700229 }
230
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000231 measurements::Entry* parentEntry = this->getMeasurements().getParent(*entry);
232 if (parentEntry != nullptr) {
233 MeasurementsEntryInfo& parentInfo = this->getMeasurementsEntryInfo(parentEntry);
234 info->inheritFrom(parentInfo);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700235 }
236
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000237 return *info;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700238}
239
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200240const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION = time::microseconds(8192);
241const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION = time::microseconds(127);
242const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION = time::milliseconds(160);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700243
244NccStrategy::MeasurementsEntryInfo::MeasurementsEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700245 : prediction(INITIAL_PREDICTION)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700246{
247}
248
249void
250NccStrategy::MeasurementsEntryInfo::inheritFrom(const MeasurementsEntryInfo& other)
251{
252 this->operator=(other);
253}
254
255shared_ptr<Face>
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200256NccStrategy::MeasurementsEntryInfo::getBestFace()
257{
Junxiao Shi1391d612014-03-27 22:27:20 -0700258 shared_ptr<Face> best = this->bestFace.lock();
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000259 if (best != nullptr) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700260 return best;
261 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700262 this->bestFace = best = this->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700263 return best;
264}
265
266void
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200267NccStrategy::MeasurementsEntryInfo::updateBestFace(const Face& face)
268{
Junxiao Shi1391d612014-03-27 22:27:20 -0700269 if (this->bestFace.expired()) {
270 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700271 return;
272 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700273 shared_ptr<Face> bestFace = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700274 if (bestFace.get() == &face) {
275 this->adjustPredictDown();
276 }
277 else {
Junxiao Shi1391d612014-03-27 22:27:20 -0700278 this->previousFace = this->bestFace;
279 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700280 }
281}
282
283void
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200284NccStrategy::MeasurementsEntryInfo::adjustPredictDown()
285{
Junxiao Shi1391d612014-03-27 22:27:20 -0700286 prediction = std::max(MIN_PREDICTION,
287 time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700288}
289
290void
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200291NccStrategy::MeasurementsEntryInfo::adjustPredictUp()
292{
Junxiao Shi1391d612014-03-27 22:27:20 -0700293 prediction = std::min(MAX_PREDICTION,
294 time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700295}
296
297void
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200298NccStrategy::MeasurementsEntryInfo::ageBestFace()
299{
Junxiao Shi1391d612014-03-27 22:27:20 -0700300 this->previousFace = this->bestFace;
301 this->bestFace.reset();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700302}
303
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700304NccStrategy::PitEntryInfo::~PitEntryInfo()
305{
Junxiao Shi1391d612014-03-27 22:27:20 -0700306 scheduler::cancel(this->bestFaceTimeout);
307 scheduler::cancel(this->propagateTimer);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700308}
309
310} // namespace fw
311} // namespace nfd