NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
access-strategy.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "access-strategy.hpp"
27 #include "algorithm.hpp"
28 #include "core/logger.hpp"
29 
30 namespace nfd {
31 namespace fw {
32 
33 NFD_LOG_INIT("AccessStrategy");
34 
35 const Name AccessStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/access/%FD%01");
37 
39  : Strategy(forwarder, name)
40  , m_removeFaceInfoConn(this->beforeRemoveFace.connect(
41  bind(&AccessStrategy::removeFaceInfo, this, _1)))
42 {
43 }
44 
45 void
46 AccessStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
47  const shared_ptr<pit::Entry>& pitEntry)
48 {
49  RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
50  switch (suppressResult) {
52  this->afterReceiveNewInterest(inFace, interest, pitEntry);
53  break;
55  this->afterReceiveRetxInterest(inFace, interest, pitEntry);
56  break;
58  NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-suppress");
59  break;
60  default:
61  BOOST_ASSERT(false);
62  break;
63  }
64 }
65 
66 void
67 AccessStrategy::afterReceiveNewInterest(const Face& inFace, const Interest& interest,
68  const shared_ptr<pit::Entry>& pitEntry)
69 {
70  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
71  Name miName;
72  MtInfo* mi = nullptr;
73  std::tie(miName, mi) = this->findPrefixMeasurements(*pitEntry);
74 
75  // has measurements for Interest Name?
76  if (mi != nullptr) {
77  NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() <<
78  " new-interest mi=" << miName);
79 
80  // send to last working nexthop
81  bool isSentToLastNexthop = this->sendToLastNexthop(inFace, interest, pitEntry, *mi, fibEntry);
82 
83  if (isSentToLastNexthop) {
84  return;
85  }
86  }
87  else {
88  NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() <<
89  " new-interest no-mi");
90  }
91 
92  // no measurements, or last working nexthop unavailable
93 
94  // multicast to all nexthops except incoming face
95  int nMulticastSent = this->multicast(inFace, interest, pitEntry, fibEntry);
96 
97  if (nMulticastSent < 1) {
98  this->rejectPendingInterest(pitEntry);
99  }
100 }
101 
102 void
103 AccessStrategy::afterReceiveRetxInterest(const Face& inFace, const Interest& interest,
104  const shared_ptr<pit::Entry>& pitEntry)
105 {
106  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
107  NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-forward");
108  this->multicast(inFace, interest, pitEntry, fibEntry);
109 }
110 
111 bool
112 AccessStrategy::sendToLastNexthop(const Face& inFace, const Interest& interest,
113  const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
114  const fib::Entry& fibEntry)
115 {
116  if (mi.lastNexthop == face::INVALID_FACEID) {
117  NFD_LOG_DEBUG(pitEntry->getInterest() << " no-last-nexthop");
118  return false;
119  }
120 
121  if (mi.lastNexthop == inFace.getId()) {
122  NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-is-downstream");
123  return false;
124  }
125 
126  Face* outFace = this->getFace(mi.lastNexthop);
127  if (outFace == nullptr || !fibEntry.hasNextHop(*outFace)) {
128  NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-gone");
129  return false;
130  }
131 
132  if (wouldViolateScope(inFace, interest, *outFace)) {
133  NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-violates-scope");
134  return false;
135  }
136 
137  RttEstimator::Duration rto = mi.rtt.computeRto();
138  NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << mi.lastNexthop <<
139  " last-nexthop rto=" << time::duration_cast<time::microseconds>(rto).count());
140 
141  this->sendInterest(pitEntry, *outFace, interest);
142 
143  // schedule RTO timeout
144  PitInfo* pi = pitEntry->insertStrategyInfo<PitInfo>().first;
145  pi->rtoTimer = scheduler::schedule(rto,
146  bind(&AccessStrategy::afterRtoTimeout, this, weak_ptr<pit::Entry>(pitEntry),
147  inFace.getId(), mi.lastNexthop));
148 
149  return true;
150 }
151 
152 void
153 AccessStrategy::afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, FaceId inFaceId, FaceId firstOutFaceId)
154 {
155  shared_ptr<pit::Entry> pitEntry = pitWeak.lock();
156  BOOST_ASSERT(pitEntry != nullptr);
157  // if pitEntry is gone, RTO timer should have been cancelled
158 
159  Face* inFace = this->getFace(inFaceId);
160  if (inFace == nullptr) {
161  NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFaceId <<
162  " inFace-gone " << inFaceId);
163  return;
164  }
165 
166  pit::InRecordCollection::iterator inRecord = pitEntry->getInRecord(*inFace);
167  BOOST_ASSERT(inRecord != pitEntry->in_end());
168  // in-record is erased only if Interest is satisfied, and RTO timer should have been cancelled
169  // note: if this strategy is extended to send Nacks, that would also erase in-record,
170  // and RTO timer should be cancelled in that case as well
171 
172  const Interest& interest = inRecord->getInterest();
173 
174  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
175 
176  NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFaceId <<
177  " multicast-except " << firstOutFaceId);
178  this->multicast(*inFace, interest, pitEntry, fibEntry, firstOutFaceId);
179 }
180 
181 int
182 AccessStrategy::multicast(const Face& inFace, const Interest& interest,
183  const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
184  FaceId exceptFace)
185 {
186  int nSent = 0;
187  for (const fib::NextHop& nexthop : fibEntry.getNextHops()) {
188  Face& outFace = nexthop.getFace();
189  if (&outFace == &inFace || outFace.getId() == exceptFace ||
190  wouldViolateScope(inFace, interest, outFace)) {
191  continue;
192  }
193  NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << outFace.getId() <<
194  " multicast");
195  this->sendInterest(pitEntry, outFace, interest);
196  ++nSent;
197  }
198  return nSent;
199 }
200 
201 void
202 AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
203  const Face& inFace, const Data& data)
204 {
205  PitInfo* pi = pitEntry->getStrategyInfo<PitInfo>();
206  if (pi != nullptr) {
207  pi->rtoTimer.cancel();
208  }
209 
210  if (!pitEntry->hasInRecords()) { // already satisfied by another upstream
211  NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
212  " not-fastest");
213  return;
214  }
215 
216  pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(inFace);
217  if (outRecord == pitEntry->out_end()) { // no out-record
218  NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
219  " no-out-record");
220  return;
221  }
222 
223  time::steady_clock::Duration rtt = time::steady_clock::now() - outRecord->getLastRenewed();
224  NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
225  " rtt=" << time::duration_cast<time::microseconds>(rtt).count());
226  this->updateMeasurements(inFace, data, time::duration_cast<RttEstimator::Duration>(rtt));
227 }
228 
229 void
230 AccessStrategy::updateMeasurements(const Face& inFace, const Data& data,
231  const RttEstimator::Duration& rtt)
232 {
233  FaceInfo& fi = m_fit[inFace.getId()];
234  fi.rtt.addMeasurement(rtt);
235 
236  MtInfo* mi = this->addPrefixMeasurements(data);
237  if (mi->lastNexthop != inFace.getId()) {
238  mi->lastNexthop = inFace.getId();
239  mi->rtt = fi.rtt;
240  }
241  else {
242  mi->rtt.addMeasurement(rtt);
243  }
244 }
245 
246 AccessStrategy::MtInfo::MtInfo()
247  : lastNexthop(face::INVALID_FACEID)
248  , rtt(1, time::milliseconds(1), 0.1)
249 {
250 }
251 
252 std::tuple<Name, AccessStrategy::MtInfo*>
253 AccessStrategy::findPrefixMeasurements(const pit::Entry& pitEntry)
254 {
256  if (me == nullptr) {
257  return std::make_tuple(Name(), nullptr);
258  }
259 
260  MtInfo* mi = me->getStrategyInfo<MtInfo>();
261  BOOST_ASSERT(mi != nullptr);
262  // XXX after runtime strategy change, it's possible that me exists but mi doesn't exist;
263  // this case needs another longest prefix match until mi is found
264  return std::make_tuple(me->getName(), mi);
265 }
266 
267 AccessStrategy::MtInfo*
268 AccessStrategy::addPrefixMeasurements(const Data& data)
269 {
270  measurements::Entry* me = nullptr;
271  if (!data.getName().empty()) {
272  me = this->getMeasurements().get(data.getName().getPrefix(-1));
273  }
274  if (me == nullptr) { // parent of Data Name is not in this strategy, or Data Name is empty
275  me = this->getMeasurements().get(data.getName());
276  // Data Name must be in this strategy
277  BOOST_ASSERT(me != nullptr);
278  }
279 
280  static const time::nanoseconds ME_LIFETIME = time::seconds(8);
281  this->getMeasurements().extendLifetime(*me, ME_LIFETIME);
282 
283  return me->insertStrategyInfo<MtInfo>().first;
284 }
285 
286 AccessStrategy::FaceInfo::FaceInfo()
287  : rtt(1, time::milliseconds(1), 0.1)
288 {
289 }
290 
291 void
292 AccessStrategy::removeFaceInfo(const Face& face)
293 {
294  m_fit.erase(face.getId());
295 }
296 
297 } // namespace fw
298 } // namespace nfd
const Name & getName() const
time::microseconds Duration
PartialName getPrefix(ssize_t nComponents) const
Extract a prefix (PartialName) of the name, containing first nComponents components.
Definition: name.hpp:241
generalization of a network interface
Definition: face.hpp:67
represents a FIB entry
Definition: fib-entry.hpp:51
AccessStrategy(Forwarder &forwarder, const Name &name=STRATEGY_NAME)
static time_point now() noexcept
Definition: time.cpp:79
const Name & getName() const
Get name of the Data packet.
Definition: data.hpp:318
virtual Result decide(const Face &inFace, const Interest &interest, pit::Entry &pitEntry) const override
determines whether Interest is a retransmission, and if so, whether it shall be forwarded or suppress...
Face * getFace(FaceId id) const
Definition: strategy.hpp:205
Interest is retransmission and should be suppressed.
main class of NFD
Definition: forwarder.hpp:54
represents an Interest packet
Definition: interest.hpp:42
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:55
static const 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
Entry * findLongestPrefixMatch(const Name &name, const EntryPredicate &pred=AnyEntry()) const
perform a longest prefix match for name
Interest is new (not a retransmission)
represents a Measurements entry
Table::const_iterator iterator
Definition: cs-internal.hpp:41
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
MeasurementsAccessor & getMeasurements()
Definition: strategy.hpp:199
an Interest table entry
Definition: pit-entry.hpp:57
FaceId getId() const
Definition: face.hpp:229
NFD_REGISTER_STRATEGY(AccessStrategy)
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
std::pair< T *, bool > insertStrategyInfo(A &&... args)
insert a StrategyInfo item
represents a forwarding strategy
Definition: strategy.hpp:38
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace, const Data &data) override
trigger before PIT entry is satisfied
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
Interest is retransmission and should be forwarded.
Entry * get(const Name &name)
find or insert a Measurements entry for name
bool empty() const
Check if name is emtpy.
Definition: name.hpp:390
const NextHopList & getNextHops() const
Definition: fib-entry.hpp:64
Access Router Strategy version 1.
uint64_t FaceId
identifies a face
Definition: face.hpp:39
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
represents a Data packet
Definition: data.hpp:37
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
const FaceId INVALID_FACEID
indicates an invalid FaceId
Definition: face.hpp:42
represents a nexthop record in FIB entry
Definition: fib-nexthop.hpp:38
bool hasNextHop(const Face &face) const
Definition: fib-entry.cpp:47
T * getStrategyInfo() const
get a StrategyInfo item