NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
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 "algorithm.hpp"
28 #include "core/random.hpp"
29 
30 namespace nfd {
31 namespace fw {
32 
33 const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc/%FD%01");
34 NFD_REGISTER_STRATEGY(NccStrategy);
35 
37  : Strategy(forwarder, name)
38 {
39 }
40 
41 const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = time::microseconds(4000);
42 const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = time::microseconds(75000);
43 const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
44 
45 void
46 NccStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
47  const shared_ptr<pit::Entry>& pitEntry)
48 {
49  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
50  const fib::NextHopList& nexthops = fibEntry.getNextHops();
51  if (nexthops.size() == 0) {
52  this->rejectPendingInterest(pitEntry);
53  return;
54  }
55 
56  PitEntryInfo* pitEntryInfo = pitEntry->insertStrategyInfo<PitEntryInfo>().first;
57  bool isNewPitEntry = !hasPendingOutRecords(*pitEntry);
58  if (!isNewPitEntry) {
59  return;
60  }
61 
62  MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
63 
64  time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
65  time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
66  size_t nUpstreams = nexthops.size();
67 
68  shared_ptr<Face> bestFace = meInfo.getBestFace();
69  if (bestFace != nullptr && fibEntry.hasNextHop(*bestFace) &&
70  !wouldViolateScope(inFace, interest, *bestFace) &&
71  canForwardToLegacy(*pitEntry, *bestFace)) {
72  // TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
73  deferFirst = meInfo.prediction;
74  deferRange = time::microseconds((deferFirst.count() + 1) / 2);
75  --nUpstreams;
76  this->sendInterest(pitEntry, *bestFace, interest);
77  pitEntryInfo->bestFaceTimeout = scheduler::schedule(
78  meInfo.prediction,
79  bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
80  }
81  else {
82  // use first eligible nexthop
83  auto firstEligibleNexthop = std::find_if(nexthops.begin(), nexthops.end(),
84  [&] (const fib::NextHop& nexthop) {
85  Face& outFace = nexthop.getFace();
86  return !wouldViolateScope(inFace, interest, outFace) &&
87  canForwardToLegacy(*pitEntry, outFace);
88  });
89  if (firstEligibleNexthop != nexthops.end()) {
90  this->sendInterest(pitEntry, firstEligibleNexthop->getFace(), interest);
91  }
92  else {
93  this->rejectPendingInterest(pitEntry);
94  return;
95  }
96  }
97 
98  shared_ptr<Face> previousFace = meInfo.previousFace.lock();
99  if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
100  !wouldViolateScope(inFace, interest, *previousFace) &&
101  canForwardToLegacy(*pitEntry, *previousFace)) {
102  --nUpstreams;
103  }
104 
105  if (nUpstreams > 0) {
106  pitEntryInfo->maxInterval = std::max(time::microseconds(1),
107  time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
108  }
109  else {
110  // Normally, maxInterval is unused if there aren't any face beyond best and previousBest.
111  // However, in case FIB entry gains a new nexthop before doPropagate executes (bug 1853),
112  // this maxInterval would be used to determine when the next doPropagate would happen.
113  pitEntryInfo->maxInterval = deferFirst;
114  }
115  pitEntryInfo->propagateTimer = scheduler::schedule(deferFirst,
116  bind(&NccStrategy::doPropagate, this, inFace.getId(), weak_ptr<pit::Entry>(pitEntry)));
117 }
118 
119 void
120 NccStrategy::doPropagate(FaceId inFaceId, weak_ptr<pit::Entry> pitEntryWeak)
121 {
122  Face* inFace = this->getFace(inFaceId);
123  if (inFace == nullptr) {
124  return;
125  }
126  shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
127  if (pitEntry == nullptr) {
128  return;
129  }
130  pit::InRecordCollection::const_iterator inRecord = pitEntry->getInRecord(*inFace);
131  if (inRecord == pitEntry->in_end()) {
132  return;
133  }
134  const Interest& interest = inRecord->getInterest();
135  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
136 
137  PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
138  // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
139  // from a timer set by NccStrategy.
140  BOOST_ASSERT(pitEntryInfo != nullptr);
141 
142  MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
143 
144  shared_ptr<Face> previousFace = meInfo.previousFace.lock();
145  if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
146  !wouldViolateScope(*inFace, interest, *previousFace) &&
147  canForwardToLegacy(*pitEntry, *previousFace)) {
148  this->sendInterest(pitEntry, *previousFace, interest);
149  }
150 
151  const fib::NextHopList& nexthops = fibEntry.getNextHops();
152  bool isForwarded = false;
153  for (fib::NextHopList::const_iterator it = nexthops.begin(); it != nexthops.end(); ++it) {
154  Face& face = it->getFace();
155  if (!wouldViolateScope(*inFace, interest, face) &&
156  canForwardToLegacy(*pitEntry, face)) {
157  isForwarded = true;
158  this->sendInterest(pitEntry, face, interest);
159  break;
160  }
161  }
162 
163  if (isForwarded) {
164  std::uniform_int_distribution<time::nanoseconds::rep> dist(0, pitEntryInfo->maxInterval.count() - 1);
165  time::nanoseconds deferNext = time::nanoseconds(dist(getGlobalRng()));
166  pitEntryInfo->propagateTimer = scheduler::schedule(deferNext,
167  bind(&NccStrategy::doPropagate, this, inFaceId, weak_ptr<pit::Entry>(pitEntry)));
168  }
169 }
170 
171 void
172 NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
173 {
174  shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
175  if (pitEntry == nullptr) {
176  return;
177  }
178  measurements::Entry* measurementsEntry = this->getMeasurements().get(*pitEntry);
179 
180  for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
181  if (measurementsEntry == nullptr) {
182  // going out of this strategy's namespace
183  break;
184  }
185  this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
186 
187  MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(measurementsEntry);
188  meInfo.adjustPredictUp();
189 
190  measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
191  }
192 }
193 
194 void
195 NccStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
196  const Face& inFace, const Data& data)
197 {
198  if (!pitEntry->hasInRecords()) {
199  // PIT entry has already been satisfied (and is now waiting for straggler timer to expire)
200  // NCC does not collect measurements for non-best face
201  return;
202  }
203 
204  measurements::Entry* measurementsEntry = this->getMeasurements().get(*pitEntry);
205 
206  for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
207  if (measurementsEntry == nullptr) {
208  // going out of this strategy's namespace
209  return;
210  }
211  this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
212 
213  MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(measurementsEntry);
214  meInfo.updateBestFace(inFace);
215 
216  measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
217  }
218 
219  PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
220  if (pitEntryInfo != nullptr) {
221  scheduler::cancel(pitEntryInfo->propagateTimer);
222 
223  // Verify that the best face satisfied the interest before canceling the timeout call
224  MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
225  shared_ptr<Face> bestFace = meInfo.getBestFace();
226 
227  if (bestFace.get() == &inFace)
228  scheduler::cancel(pitEntryInfo->bestFaceTimeout);
229  }
230 }
231 
233 NccStrategy::getMeasurementsEntryInfo(const shared_ptr<pit::Entry>& entry)
234 {
235  measurements::Entry* measurementsEntry = this->getMeasurements().get(*entry);
236  return this->getMeasurementsEntryInfo(measurementsEntry);
237 }
238 
241 {
242  BOOST_ASSERT(entry != nullptr);
243  MeasurementsEntryInfo* info = nullptr;
244  bool isNew = false;
245  std::tie(info, isNew) = entry->insertStrategyInfo<MeasurementsEntryInfo>();
246  if (!isNew) {
247  return *info;
248  }
249 
250  measurements::Entry* parentEntry = this->getMeasurements().getParent(*entry);
251  if (parentEntry != nullptr) {
252  MeasurementsEntryInfo& parentInfo = this->getMeasurementsEntryInfo(parentEntry);
253  info->inheritFrom(parentInfo);
254  }
255 
256  return *info;
257 }
258 
259 const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION = time::microseconds(8192);
260 const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION = time::microseconds(127);
261 const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION = time::milliseconds(160);
262 
264  : prediction(INITIAL_PREDICTION)
265 {
266 }
267 
268 void
270 {
271  this->operator=(other);
272 }
273 
274 shared_ptr<Face>
276 {
277  shared_ptr<Face> best = this->bestFace.lock();
278  if (best != nullptr) {
279  return best;
280  }
281  this->bestFace = best = this->previousFace.lock();
282  return best;
283 }
284 
285 void
287 {
288  if (this->bestFace.expired()) {
289  this->bestFace = const_cast<Face&>(face).shared_from_this();
290  return;
291  }
292  shared_ptr<Face> bestFace = this->bestFace.lock();
293  if (bestFace.get() == &face) {
294  this->adjustPredictDown();
295  }
296  else {
297  this->previousFace = this->bestFace;
298  this->bestFace = const_cast<Face&>(face).shared_from_this();
299  }
300 }
301 
302 void
303 NccStrategy::MeasurementsEntryInfo::adjustPredictDown()
304 {
305  prediction = std::max(MIN_PREDICTION,
306  time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
307 }
308 
309 void
311 {
312  prediction = std::min(MAX_PREDICTION,
313  time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
314 }
315 
316 void
317 NccStrategy::MeasurementsEntryInfo::ageBestFace()
318 {
319  this->previousFace = this->bestFace;
320  this->bestFace.reset();
321 }
322 
324 {
325  scheduler::cancel(this->bestFaceTimeout);
326  scheduler::cancel(this->propagateTimer);
327 }
328 
329 } // namespace fw
330 } // namespace nfd
static const time::microseconds DEFER_FIRST_WITHOUT_BEST_FACE
bool canForwardToLegacy(const pit::Entry &pitEntry, const Face &face)
decide whether Interest can be forwarded to face
Definition: algorithm.cpp:82
static const Name STRATEGY_NAME
StrategyInfo on measurements::Entry.
void doPropagate(FaceId inFaceId, weak_ptr< pit::Entry > pitEntryWeak)
propagate to another upstream
static const int UPDATE_MEASUREMENTS_N_LEVELS
generalization of a network interface
Definition: face.hpp:67
void cancel(const EventId &eventId)
cancel a scheduled event
Definition: scheduler.cpp:53
represents a FIB entry
Definition: fib-entry.hpp:51
static const time::microseconds DEFER_RANGE_WITHOUT_BEST_FACE
Face * getFace(FaceId id) const
Definition: strategy.hpp:205
time::microseconds maxInterval
maximum interval between forwarding to two nexthops except best and previous
main class of NFD
Definition: forwarder.hpp:54
represents an Interest packet
Definition: interest.hpp:42
NccStrategy(Forwarder &forwarder, const Name &name=STRATEGY_NAME)
virtual void afterReceiveInterest(const Face &inFace, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry) override
trigger after Interest is received
void extendLifetime(Entry &entry, const time::nanoseconds &lifetime)
extend lifetime of an entry
static const time::microseconds MIN_PREDICTION
represents a Measurements entry
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
MeasurementsAccessor & getMeasurements()
Definition: strategy.hpp:199
void inheritFrom(const MeasurementsEntryInfo &other)
FaceId getId() const
Definition: face.hpp:229
NFD_REGISTER_STRATEGY(AccessStrategy)
std::vector< fib::NextHop > NextHopList
Definition: fib-entry.hpp:47
void timeoutOnBestFace(weak_ptr< pit::Entry > pitEntryWeak)
best face did not reply within prediction
static const time::nanoseconds MEASUREMENTS_LIFETIME
void rejectPendingInterest(const shared_ptr< pit::Entry > &pitEntry)
decide that a pending Interest cannot be forwarded
Definition: strategy.hpp:162
Name abstraction to represent an absolute name.
Definition: name.hpp:46
scheduler::EventId propagateTimer
timer for propagating to another face
bool hasPendingOutRecords(const pit::Entry &pitEntry)
determine whether pitEntry has any pending out-records
Definition: algorithm.cpp:136
std::pair< T *, bool > insertStrategyInfo(A &&... args)
insert a StrategyInfo item
scheduler::EventId bestFaceTimeout
timer that expires when best face does not respond within predicted time
StrategyInfo on pit::Entry.
represents a forwarding strategy
Definition: strategy.hpp:38
MeasurementsEntryInfo & getMeasurementsEntryInfo(measurements::Entry *entry)
std::mt19937 & getGlobalRng()
Definition: random.cpp:32
Copyright (c) 2014-2016, Regents of the University of California, Arizona Board of Regents...
const fib::Entry & lookupFib(const pit::Entry &pitEntry) const
performs a FIB lookup, considering Link object if present
Definition: strategy.cpp:129
EventId schedule(const time::nanoseconds &after, const Scheduler::Event &event)
schedule an event
Definition: scheduler.cpp:47
static const time::microseconds INITIAL_PREDICTION
Entry * get(const Name &name)
find or insert a Measurements entry for name
const NextHopList & getNextHops() const
Definition: fib-entry.hpp:64
uint64_t FaceId
identifies a face
Definition: face.hpp:39
represents a Data packet
Definition: data.hpp:37
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace, const Data &data) override
trigger before PIT entry is satisfied
void sendInterest(const shared_ptr< pit::Entry > &pitEntry, Face &outFace, const Interest &interest)
send Interest to outFace
Definition: strategy.hpp:137
bool wouldViolateScope(const Face &inFace, const Interest &interest, const Face &outFace)
determine whether forwarding the Interest in pitEntry to outFace would violate scope ...
Definition: algorithm.cpp:37
static const time::microseconds MAX_PREDICTION
Entry * getParent(const Entry &child)
find or insert a Measurements entry for child&#39;s parent
represents a nexthop record in FIB entry
Definition: fib-nexthop.hpp:38
bool hasNextHop(const Face &face) const
Definition: fib-entry.cpp:47