NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ncc-strategy.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "ncc-strategy.hpp"
27 #include "core/random.hpp"
28 #include <boost/random/uniform_int_distribution.hpp>
29 
30 namespace nfd {
31 namespace fw {
32 
33 const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc/%FD%01");
34 
35 NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
36  : Strategy(forwarder, name)
37 {
38 }
39 
41 {
42 }
43 
44 const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = time::microseconds(4000);
45 const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = time::microseconds(75000);
46 const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
47 
48 void
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>();
62  bool isNewPitEntry = !pitEntry->hasUnexpiredOutRecords();
63  if (!isNewPitEntry) {
64  return;
65  }
66 
67  shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
68  this->getMeasurementsEntryInfo(pitEntry);
69 
70  time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
71  time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
72  size_t nUpstreams = nexthops.size();
73 
74  shared_ptr<Face> bestFace = measurementsEntryInfo->getBestFace();
75  if (static_cast<bool>(bestFace) && fibEntry->hasNextHop(bestFace) &&
76  pitEntry->canForwardTo(*bestFace)) {
77  // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
78  deferFirst = measurementsEntryInfo->prediction;
79  deferRange = time::microseconds((deferFirst.count() + 1) / 2);
80  --nUpstreams;
81  this->sendInterest(pitEntry, bestFace);
82  pitEntryInfo->bestFaceTimeout = scheduler::schedule(
83  measurementsEntryInfo->prediction,
84  bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
85  }
86  else {
87  // use first nexthop
88  this->sendInterest(pitEntry, nexthops.begin()->getFace());
89  // TODO avoid sending to inFace
90  }
91 
92  shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
93  if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
94  pitEntry->canForwardTo(*previousFace)) {
95  --nUpstreams;
96  }
97 
98  if (nUpstreams > 0) {
99  pitEntryInfo->maxInterval = std::max(time::microseconds(1),
100  time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
101  }
102  else {
103  // Normally, maxInterval is unused if there aren't any face beyond best and previousBest.
104  // However, in case FIB entry gains a new nexthop before doPropagate executes (bug 1853),
105  // this maxInterval would be used to determine when the next doPropagate would happen.
106  pitEntryInfo->maxInterval = deferFirst;
107  }
108  pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
109  bind(&NccStrategy::doPropagate, this,
110  weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
111 }
112 
113 void
114 NccStrategy::doPropagate(weak_ptr<pit::Entry> pitEntryWeak, weak_ptr<fib::Entry> fibEntryWeak)
115 {
116  shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
117  if (!static_cast<bool>(pitEntry)) {
118  return;
119  }
120  shared_ptr<fib::Entry> fibEntry = fibEntryWeak.lock();
121  if (!static_cast<bool>(fibEntry)) {
122  return;
123  }
124 
125  shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
126  // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
127  // from a timer set by NccStrategy.
128  BOOST_ASSERT(static_cast<bool>(pitEntryInfo));
129 
130  shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
131  this->getMeasurementsEntryInfo(pitEntry);
132 
133  shared_ptr<Face> previousFace = measurementsEntryInfo->previousFace.lock();
134  if (static_cast<bool>(previousFace) && fibEntry->hasNextHop(previousFace) &&
135  pitEntry->canForwardTo(*previousFace)) {
136  this->sendInterest(pitEntry, previousFace);
137  }
138 
139  const fib::NextHopList& nexthops = fibEntry->getNextHops();
140  bool isForwarded = false;
141  for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
142  shared_ptr<Face> face = it->getFace();
143  if (pitEntry->canForwardTo(*face)) {
144  isForwarded = true;
145  this->sendInterest(pitEntry, face);
146  break;
147  }
148  }
149 
150  if (isForwarded) {
151  boost::random::uniform_int_distribution<time::nanoseconds::rep> dist(0,
152  pitEntryInfo->maxInterval.count() - 1);
153  time::nanoseconds deferNext = time::nanoseconds(dist(getGlobalRng()));
154  pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
155  bind(&NccStrategy::doPropagate, this,
156  weak_ptr<pit::Entry>(pitEntry), weak_ptr<fib::Entry>(fibEntry)));
157  }
158 }
159 
160 void
161 NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
162 {
163  shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
164  if (!static_cast<bool>(pitEntry)) {
165  return;
166  }
167  shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
168 
169  for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
170  if (!static_cast<bool>(measurementsEntry)) {
171  // going out of this strategy's namespace
172  return;
173  }
174  this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
175 
176  shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
177  this->getMeasurementsEntryInfo(measurementsEntry);
178  measurementsEntryInfo->adjustPredictUp();
179 
180  measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
181  }
182 }
183 
184 void
185 NccStrategy::beforeSatisfyInterest(shared_ptr<pit::Entry> pitEntry,
186  const Face& inFace, const Data& data)
187 {
188  if (pitEntry->getInRecords().empty()) {
189  // PIT entry has already been satisfied (and is now waiting for straggler timer to expire)
190  // NCC does not collect measurements for non-best face
191  return;
192  }
193 
194  shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*pitEntry);
195 
196  for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
197  if (!static_cast<bool>(measurementsEntry)) {
198  // going out of this strategy's namespace
199  return;
200  }
201  this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
202 
203  shared_ptr<MeasurementsEntryInfo> measurementsEntryInfo =
204  this->getMeasurementsEntryInfo(measurementsEntry);
205  measurementsEntryInfo->updateBestFace(inFace);
206 
207  measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
208  }
209 
210  shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
211  if (static_cast<bool>(pitEntryInfo)) {
212  scheduler::cancel(pitEntryInfo->propagateTimer);
213  }
214 }
215 
216 shared_ptr<NccStrategy::MeasurementsEntryInfo>
217 NccStrategy::getMeasurementsEntryInfo(shared_ptr<pit::Entry> entry)
218 {
219  shared_ptr<measurements::Entry> measurementsEntry = this->getMeasurements().get(*entry);
220  return this->getMeasurementsEntryInfo(measurementsEntry);
221 }
222 
223 shared_ptr<NccStrategy::MeasurementsEntryInfo>
224 NccStrategy::getMeasurementsEntryInfo(shared_ptr<measurements::Entry> entry)
225 {
226  shared_ptr<MeasurementsEntryInfo> info = entry->getStrategyInfo<MeasurementsEntryInfo>();
227  if (static_cast<bool>(info)) {
228  return info;
229  }
230 
231  info = make_shared<MeasurementsEntryInfo>();
232  entry->setStrategyInfo(info);
233 
234  shared_ptr<measurements::Entry> parentEntry = this->getMeasurements().getParent(*entry);
235  if (static_cast<bool>(parentEntry)) {
236  shared_ptr<MeasurementsEntryInfo> parentInfo = this->getMeasurementsEntryInfo(parentEntry);
237  BOOST_ASSERT(static_cast<bool>(parentInfo));
238  info->inheritFrom(*parentInfo);
239  }
240 
241  return info;
242 }
243 
244 
246  time::microseconds(8192);
248  time::microseconds(127);
250  time::microseconds(160000);
251 
253  : prediction(INITIAL_PREDICTION)
254 {
255 }
256 
257 void
259 {
260  this->operator=(other);
261 }
262 
263 shared_ptr<Face>
265  shared_ptr<Face> best = this->bestFace.lock();
266  if (static_cast<bool>(best)) {
267  return best;
268  }
269  this->bestFace = best = this->previousFace.lock();
270  return best;
271 }
272 
273 void
275  if (this->bestFace.expired()) {
276  this->bestFace = const_cast<Face&>(face).shared_from_this();
277  return;
278  }
279  shared_ptr<Face> bestFace = this->bestFace.lock();
280  if (bestFace.get() == &face) {
281  this->adjustPredictDown();
282  }
283  else {
284  this->previousFace = this->bestFace;
285  this->bestFace = const_cast<Face&>(face).shared_from_this();
286  }
287 }
288 
289 void
290 NccStrategy::MeasurementsEntryInfo::adjustPredictDown() {
291  prediction = std::max(MIN_PREDICTION,
292  time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
293 }
294 
295 void
297  prediction = std::min(MAX_PREDICTION,
298  time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
299 }
300 
301 void
302 NccStrategy::MeasurementsEntryInfo::ageBestFace() {
303  this->previousFace = this->bestFace;
304  this->bestFace.reset();
305 }
306 
308 {
309  scheduler::cancel(this->bestFaceTimeout);
310  scheduler::cancel(this->propagateTimer);
311 }
312 
313 } // namespace fw
314 } // namespace nfd
static const time::microseconds DEFER_FIRST_WITHOUT_BEST_FACE
static const Name STRATEGY_NAME
virtual void afterReceiveInterest(const Face &inFace, const Interest &interest, shared_ptr< fib::Entry > fibEntry, shared_ptr< pit::Entry > pitEntry) 1
trigger after Interest is received
StrategyInfo on measurements::Entry.
static const int UPDATE_MEASUREMENTS_N_LEVELS
void cancel(const EventId &eventId)
cancel a scheduled event
Definition: scheduler.cpp:58
static const time::microseconds DEFER_RANGE_WITHOUT_BEST_FACE
main class of NFD
Definition: forwarder.hpp:54
NccStrategy(Forwarder &forwarder, const Name &name=STRATEGY_NAME)
shared_ptr< measurements::Entry > get(const Name &name)
find or insert a Measurements entry for name
shared_ptr< MeasurementsEntryInfo > getMeasurementsEntryInfo(shared_ptr< measurements::Entry > entry)
static const time::microseconds MIN_PREDICTION
virtual void beforeSatisfyInterest(shared_ptr< pit::Entry > pitEntry, const Face &inFace, const Data &data) 1
trigger before PIT entry is satisfied
represents a face
Definition: face.hpp:59
MeasurementsAccessor & getMeasurements()
Definition: strategy.hpp:174
void inheritFrom(const MeasurementsEntryInfo &other)
void doPropagate(weak_ptr< pit::Entry > pitEntryWeak, weak_ptr< fib::Entry > fibEntryWeak)
propagate to another upstream
std::vector< fib::NextHop > NextHopList
Definition: fib-entry.hpp:48
void timeoutOnBestFace(weak_ptr< pit::Entry > pitEntryWeak)
best face did not reply within prediction
static const time::nanoseconds MEASUREMENTS_LIFETIME
EventId schedule(const time::nanoseconds &after, const std::function< void()> &event)
schedule an event
Definition: scheduler.cpp:50
boost::random::mt19937 & getGlobalRng()
Definition: random.cpp:33
void rejectPendingInterest(shared_ptr< pit::Entry > pitEntry)
decide that a pending Interest cannot be forwarded
Definition: strategy.hpp:168
StrategyInfo on pit::Entry.
represents a forwarding strategy
Definition: strategy.hpp:37
void extendLifetime(measurements::Entry &entry, const time::nanoseconds &lifetime)
extend lifetime of an entry
static const time::microseconds INITIAL_PREDICTION
void sendInterest(shared_ptr< pit::Entry > pitEntry, shared_ptr< Face > outFace, bool wantNewNonce=false)
send Interest to outFace
Definition: strategy.hpp:160
static const time::microseconds MAX_PREDICTION
shared_ptr< measurements::Entry > getParent(const measurements::Entry &child)
find or insert a Measurements entry for child's parent