blob: 6e856cc47453ed79137a65990c52c9f4609c00a2 [file] [log] [blame]
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#include "ncc-strategy.hpp"
8
9namespace nfd {
10namespace fw {
11
Junxiao Shif3c07812014-03-11 21:48:49 -070012const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc");
13
14NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
15 : Strategy(forwarder, name)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070016{
17}
18
19NccStrategy::~NccStrategy()
20{
21}
22
Junxiao Shi1391d612014-03-27 22:27:20 -070023const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = time::microseconds(4000);
24const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = time::microseconds(75000);
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070025const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070026
27void
28NccStrategy::afterReceiveInterest(const Face& inFace,
29 const Interest& interest,
30 shared_ptr<fib::Entry> fibEntry,
31 shared_ptr<pit::Entry> pitEntry)
32{
33 const fib::NextHopList& nexthops = fibEntry->getNextHops();
34 if (nexthops.size() == 0) {
35 this->rejectPendingInterest(pitEntry);
36 return;
37 }
38
39 shared_ptr<PitEntryInfo> pitEntryInfo =
40 pitEntry->getOrCreateStrategyInfo<PitEntryInfo>();
Junxiao Shi1391d612014-03-27 22:27:20 -070041 bool isNewInterest = pitEntryInfo->isNewInterest;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070042 if (!isNewInterest) {
43 return;
44 }
Junxiao Shi1391d612014-03-27 22:27:20 -070045 pitEntryInfo->isNewInterest = false;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070046
47 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
48 this->getMeasurementsEntryInfo(pitEntry);
49
Junxiao Shi1391d612014-03-27 22:27:20 -070050 time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
51 time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070052 size_t nUpstreams = nexthops.size();
53
54 shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
55 if (static_cast<bool>(bestFace) && fibEntry->hasNextHop(bestFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -070056 pitEntry->canForwardTo(*bestFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070057 // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
Junxiao Shi1391d612014-03-27 22:27:20 -070058 deferFirst = measurementsEntryInfo->prediction;
59 deferRange = time::microseconds((deferFirst.count() + 1) / 2);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070060 --nUpstreams;
61 this->sendInterest(pitEntry, bestFace);
Junxiao Shi1391d612014-03-27 22:27:20 -070062 pitEntryInfo->bestFaceTimeout = scheduler::schedule(
63 measurementsEntryInfo->prediction,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070064 bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
65 }
66 else {
67 // use first nexthop
68 this->sendInterest(pitEntry, nexthops.begin()->getFace());
69 // TODO avoid sending to inFace
70 }
71
Junxiao Shi1391d612014-03-27 22:27:20 -070072 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070073 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -070074 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070075 --nUpstreams;
76 }
77
Junxiao Shi1391d612014-03-27 22:27:20 -070078 if (nUpstreams > 0) {
79 pitEntryInfo->maxInterval = std::max(time::microseconds(1),
80 time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
81 }
82 pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070083 bind(&NccStrategy::doPropagate, this,
84 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
85}
86
87void
88NccStrategy::doPropagate(weak_ptr<pit::Entry> pitEntryWeak, weak_ptr<fib::Entry> fibEntryWeak)
89{
90 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
91 if (!static_cast<bool>(pitEntry)) {
92 return;
93 }
94 shared_ptr<fib::Entry> fibEntry = fibEntryWeak.lock();
95 if (!static_cast<bool>(fibEntry)) {
96 return;
97 }
98
Junxiao Shi1391d612014-03-27 22:27:20 -070099 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
100 // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
101 // from a timer set by NccStrategy.
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700102 BOOST_ASSERT(static_cast<bool>(pitEntryInfo));
103
104 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
105 this->getMeasurementsEntryInfo(pitEntry);
106
Junxiao Shi1391d612014-03-27 22:27:20 -0700107 shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700108 if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
Junxiao Shi57f0f312014-03-16 11:52:20 -0700109 pitEntry->canForwardTo(*previousFace)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700110 this->sendInterest(pitEntry, previousFace);
111 }
112
113 const fib::NextHopList& nexthops = fibEntry->getNextHops();
114 bool isForwarded = false;
115 for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
116 shared_ptr<Face> face = it->getFace();
Junxiao Shi57f0f312014-03-16 11:52:20 -0700117 if (pitEntry->canForwardTo(*face)) {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700118 isForwarded = true;
119 this->sendInterest(pitEntry, face);
120 break;
121 }
122 }
123
124 if (isForwarded) {
125 static unsigned short seed[3];
Junxiao Shi1391d612014-03-27 22:27:20 -0700126 time::nanoseconds deferNext = time::nanoseconds(nrand48(seed) % pitEntryInfo->maxInterval.count());
127 pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700128 bind(&NccStrategy::doPropagate, this,
129 weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
130 }
131}
132
133void
134NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
135{
136 shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
137 if (!static_cast<bool>(pitEntry)) {
138 return;
139 }
140 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
141
142 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
143 if (!static_cast<bool>(measurementsEntry)) {
144 // going out of this strategy's namespace
145 return;
146 }
147 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
148
149 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
150 this->getMeasurementsEntryInfo(measurementsEntry);
151 measurementsEntryInfo->adjustPredictUp();
152
153 measurementsEntry = this->getMeasurements().getParent(measurementsEntry);
154 }
155}
156
157void
158NccStrategy::beforeSatisfyPendingInterest(shared_ptr<pit::Entry> pitEntry,
159 const Face& inFace, const Data& data)
160{
161 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
162
163 for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
164 if (!static_cast<bool>(measurementsEntry)) {
165 // going out of this strategy's namespace
166 return;
167 }
168 this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
169
170 shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
171 this->getMeasurementsEntryInfo(measurementsEntry);
172 measurementsEntryInfo->updateBestFace(inFace);
173
174 measurementsEntry = this->getMeasurements().getParent(measurementsEntry);
175 }
176
Junxiao Shi1391d612014-03-27 22:27:20 -0700177 shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
178 if (static_cast<bool>(pitEntryInfo)) {
179 scheduler::cancel(pitEntryInfo->propagateTimer);
180 }
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700181}
182
183shared_ptr<NccStrategy::MeasurementsEntryInfo>
184NccStrategy::getMeasurementsEntryInfo(shared_ptr<pit::Entry> entry)
185{
186 shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*entry);
187 return this->getMeasurementsEntryInfo(measurementsEntry);
188}
189
190shared_ptr<NccStrategy::MeasurementsEntryInfo>
191NccStrategy::getMeasurementsEntryInfo(shared_ptr<measurements::Entry> entry)
192{
193 shared_ptr<MeasurementsEntryInfo> info = entry->getStrategyInfo<MeasurementsEntryInfo>();
194 if (static_cast<bool>(info)) {
195 return info;
196 }
197
198 info = make_shared<MeasurementsEntryInfo>();
199 entry->setStrategyInfo(info);
200
201 shared_ptr<measurements::Entry> parentEntry = this->getMeasurements().getParent(entry);
202 if (static_cast<bool>(parentEntry)) {
203 shared_ptr<MeasurementsEntryInfo> parentInfo = this->getMeasurementsEntryInfo(parentEntry);
204 BOOST_ASSERT(static_cast<bool>(parentInfo));
205 info->inheritFrom(*parentInfo);
206 }
207
208 return info;
209}
210
211
Junxiao Shi1391d612014-03-27 22:27:20 -0700212const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION =
213 time::microseconds(8192);
214const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION =
215 time::microseconds(127);
216const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION =
217 time::microseconds(160000);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700218
219NccStrategy::MeasurementsEntryInfo::MeasurementsEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700220 : prediction(INITIAL_PREDICTION)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700221{
222}
223
224void
225NccStrategy::MeasurementsEntryInfo::inheritFrom(const MeasurementsEntryInfo& other)
226{
227 this->operator=(other);
228}
229
230shared_ptr<Face>
231NccStrategy::MeasurementsEntryInfo::getBestFace(void) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700232 shared_ptr<Face> best = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700233 if (static_cast<bool>(best)) {
234 return best;
235 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700236 this->bestFace = best = this->previousFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700237 return best;
238}
239
240void
241NccStrategy::MeasurementsEntryInfo::updateBestFace(const Face& face) {
Junxiao Shi1391d612014-03-27 22:27:20 -0700242 if (this->bestFace.expired()) {
243 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700244 return;
245 }
Junxiao Shi1391d612014-03-27 22:27:20 -0700246 shared_ptr<Face> bestFace = this->bestFace.lock();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700247 if (bestFace.get() == &face) {
248 this->adjustPredictDown();
249 }
250 else {
Junxiao Shi1391d612014-03-27 22:27:20 -0700251 this->previousFace = this->bestFace;
252 this->bestFace = const_cast<Face&>(face).shared_from_this();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700253 }
254}
255
256void
257NccStrategy::MeasurementsEntryInfo::adjustPredictDown() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700258 prediction = std::max(MIN_PREDICTION,
259 time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700260}
261
262void
263NccStrategy::MeasurementsEntryInfo::adjustPredictUp() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700264 prediction = std::min(MAX_PREDICTION,
265 time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700266}
267
268void
269NccStrategy::MeasurementsEntryInfo::ageBestFace() {
Junxiao Shi1391d612014-03-27 22:27:20 -0700270 this->previousFace = this->bestFace;
271 this->bestFace.reset();
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700272}
273
274NccStrategy::PitEntryInfo::PitEntryInfo()
Junxiao Shi1391d612014-03-27 22:27:20 -0700275 : isNewInterest(true)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700276{
277}
278
279NccStrategy::PitEntryInfo::~PitEntryInfo()
280{
Junxiao Shi1391d612014-03-27 22:27:20 -0700281 scheduler::cancel(this->bestFaceTimeout);
282 scheduler::cancel(this->propagateTimer);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700283}
284
285} // namespace fw
286} // namespace nfd