blob: 6e7a32c5cbdeec751d1cf3fbc0e4d8237d4adf69 [file] [log] [blame]
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -07003 * Copyright (c) 2014 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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070024
25#include "ncc-strategy.hpp"
26
27namespace nfd {
28namespace fw {
29
Junxiao Shif3c07812014-03-11 21:48:49 -070030const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc");
31
32NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
33 : Strategy(forwarder, name)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070034{
35}
36
37NccStrategy::~NccStrategy()
38{
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
46NccStrategy::afterReceiveInterest(const Face& inFace,
47 const Interest& interest,
48 shared_ptr<fib::Entry> fibEntry,
49 shared_ptr<pit::Entry> pitEntry)
50{
51 const fib::NextHopList& nexthops = fibEntry->getNextHops();
52 if (nexthops.size() == 0) {
53 this->rejectPendingInterest(pitEntry);
54 return;
55 }
56
57 shared_ptr<PitEntryInfo> pitEntryInfo =
58 pitEntry->getOrCreateStrategyInfo<PitEntryInfo>();
Junxiao Shi1391d612014-03-27 22:27:20 -070059 bool isNewInterest = pitEntryInfo->isNewInterest;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070060 if (!isNewInterest) {
61 return;
62 }
Junxiao Shi1391d612014-03-27 22:27:20 -070063 pitEntryInfo->isNewInterest = false;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070064
65 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
66 this->getMeasurementsEntryInfo(pitEntry);
67
Junxiao Shi1391d612014-03-27 22:27:20 -070068 time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
69 time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070070 size_t nUpstreams = nexthops.size();
71
72 shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
73 if (static_cast<bool>(bestFace) && fibEntry->hasNextHop(bestFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -070074 pitEntry->canForwardTo(*bestFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070075 // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
Junxiao Shi1391d612014-03-27 22:27:20 -070076 deferFirst = measurementsEntryInfo->prediction;
77 deferRange = time::microseconds((deferFirst.count() + 1) / 2);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070078 --nUpstreams;
79 this->sendInterest(pitEntry, bestFace);
Junxiao Shi1391d612014-03-27 22:27:20 -070080 pitEntryInfo->bestFaceTimeout = scheduler::schedule(
81 measurementsEntryInfo->prediction,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070082 bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
83 }
84 else {
85 // use first nexthop
86 this->sendInterest(pitEntry, nexthops.begin()->getFace());
87 // TODO avoid sending to inFace
88 }
89
Junxiao Shi1391d612014-03-27 22:27:20 -070090 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070091 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -070092 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070093 --nUpstreams;
94 }
95
Junxiao Shi1391d612014-03-27 22:27:20 -070096 if (nUpstreams > 0) {
97 pitEntryInfo->maxInterval = std::max(time::microseconds(1),
98 time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
99 }
100 pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700101 bind(&NccStrategy::doPropagate, this,
102 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
103}
104
105void
106NccStrategy::doPropagate(weak_ptr<pit::Entry> pitEntryWeak, weak_ptr<fib::Entry> fibEntryWeak)
107{
108 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
109 if (!static_cast<bool>(pitEntry)) {
110 return;
111 }
112 shared_ptr<fib::Entry> fibEntry = fibEntryWeak.lock();
113 if (!static_cast<bool>(fibEntry)) {
114 return;
115 }
116
Junxiao Shi1391d612014-03-27 22:27:20 -0700117 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
118 // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
119 // from a timer set by NccStrategy.
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700120 BOOST_ASSERT(static_cast<bool>(pitEntryInfo));
121
122 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
123 this->getMeasurementsEntryInfo(pitEntry);
124
Junxiao Shi1391d612014-03-27 22:27:20 -0700125 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700126 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -0700127 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700128 this->sendInterest(pitEntry, previousFace);
129 }
130
131 const fib::NextHopList& nexthops = fibEntry->getNextHops();
132 bool isForwarded = false;
133 for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
134 shared_ptr<Face> face = it->getFace();
Junxiao Shi57f0f312014-03-16 11:52:20 -0700135 if (pitEntry->canForwardTo(*face)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700136 isForwarded = true;
137 this->sendInterest(pitEntry, face);
138 break;
139 }
140 }
141
142 if (isForwarded) {
143 static unsigned short seed[3];
Junxiao Shi1391d612014-03-27 22:27:20 -0700144 time::nanoseconds deferNext = time::nanoseconds(nrand48(seed) % pitEntryInfo->maxInterval.count());
145 pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700146 bind(&NccStrategy::doPropagate, this,
147 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
148 }
149}
150
151void
152NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
153{
154 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
155 if (!static_cast<bool>(pitEntry)) {
156 return;
157 }
158 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
159
160 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
161 if (!static_cast<bool>(measurementsEntry)) {
162 // going out of this strategy's namespace
163 return;
164 }
165 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
166
167 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
168 this->getMeasurementsEntryInfo(measurementsEntry);
169 measurementsEntryInfo->adjustPredictUp();
170
171 measurementsEntry = this->getMeasurements().getParent(measurementsEntry);
172 }
173}
174
175void
176NccStrategy::beforeSatisfyPendingInterest(shared_ptr<pit::Entry> pitEntry,
177 const Face& inFace, const Data& data)
178{
179 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
180
181 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
182 if (!static_cast<bool>(measurementsEntry)) {
183 // going out of this strategy's namespace
184 return;
185 }
186 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
187
188 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
189 this->getMeasurementsEntryInfo(measurementsEntry);
190 measurementsEntryInfo->updateBestFace(inFace);
191
192 measurementsEntry = this->getMeasurements().getParent(measurementsEntry);
193 }
194
Junxiao Shi1391d612014-03-27 22:27:20 -0700195 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
196 if (static_cast<bool>(pitEntryInfo)) {
197 scheduler::cancel(pitEntryInfo->propagateTimer);
198 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700199}
200
201shared_ptr<NccStrategy::MeasurementsEntryInfo>
202NccStrategy::getMeasurementsEntryInfo(shared_ptr<pit::Entry> entry)
203{
204 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*entry);
205 return this->getMeasurementsEntryInfo(measurementsEntry);
206}
207
208shared_ptr<NccStrategy::MeasurementsEntryInfo>
209NccStrategy::getMeasurementsEntryInfo(shared_ptr<measurements::Entry> entry)
210{
211 shared_ptr<MeasurementsEntryInfo> info = entry->getStrategyInfo<MeasurementsEntryInfo>();
212 if (static_cast<bool>(info)) {
213 return info;
214 }
215
216 info = make_shared<MeasurementsEntryInfo>();
217 entry->setStrategyInfo(info);
218
219 shared_ptr<measurements::Entry> parentEntry = this->getMeasurements().getParent(entry);
220 if (static_cast<bool>(parentEntry)) {
221 shared_ptr<MeasurementsEntryInfo> parentInfo = this->getMeasurementsEntryInfo(parentEntry);
222 BOOST_ASSERT(static_cast<bool>(parentInfo));
223 info->inheritFrom(*parentInfo);
224 }
225
226 return info;
227}
228
229
Junxiao Shi1391d612014-03-27 22:27:20 -0700230const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION =
231 time::microseconds(8192);
232const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION =
233 time::microseconds(127);
234const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION =
235 time::microseconds(160000);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700236
237NccStrategy::MeasurementsEntryInfo::MeasurementsEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700238 : prediction(INITIAL_PREDICTION)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700239{
240}
241
242void
243NccStrategy::MeasurementsEntryInfo::inheritFrom(const MeasurementsEntryInfo& other)
244{
245 this->operator=(other);
246}
247
248shared_ptr<Face>
249NccStrategy::MeasurementsEntryInfo::getBestFace(void) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700250 shared_ptr<Face> best = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700251 if (static_cast<bool>(best)) {
252 return best;
253 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700254 this->bestFace = best = this->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700255 return best;
256}
257
258void
259NccStrategy::MeasurementsEntryInfo::updateBestFace(const Face& face) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700260 if (this->bestFace.expired()) {
261 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700262 return;
263 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700264 shared_ptr<Face> bestFace = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700265 if (bestFace.get() == &face) {
266 this->adjustPredictDown();
267 }
268 else {
Junxiao Shi1391d612014-03-27 22:27:20 -0700269 this->previousFace = this->bestFace;
270 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700271 }
272}
273
274void
275NccStrategy::MeasurementsEntryInfo::adjustPredictDown() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700276 prediction = std::max(MIN_PREDICTION,
277 time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700278}
279
280void
281NccStrategy::MeasurementsEntryInfo::adjustPredictUp() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700282 prediction = std::min(MAX_PREDICTION,
283 time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700284}
285
286void
287NccStrategy::MeasurementsEntryInfo::ageBestFace() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700288 this->previousFace = this->bestFace;
289 this->bestFace.reset();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700290}
291
292NccStrategy::PitEntryInfo::PitEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700293 : isNewInterest(true)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700294{
295}
296
297NccStrategy::PitEntryInfo::~PitEntryInfo()
298{
Junxiao Shi1391d612014-03-27 22:27:20 -0700299 scheduler::cancel(this->bestFaceTimeout);
300 scheduler::cancel(this->propagateTimer);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700301}
302
303} // namespace fw
304} // namespace nfd