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 "pit-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 
38 AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
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, 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  this->multicast(pitEntry, fibEntry, {inFace.getId()});
96 }
97 
98 void
99 AccessStrategy::afterReceiveRetxInterest(const Face& inFace, const Interest& interest,
100  const shared_ptr<pit::Entry>& pitEntry)
101 {
102  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
103  NFD_LOG_DEBUG(interest << " interestFrom " << inFace.getId() << " retx-forward");
104  this->multicast(pitEntry, fibEntry, {inFace.getId()});
105 }
106 
107 bool
108 AccessStrategy::sendToLastNexthop(const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
109  MtInfo& mi, const fib::Entry& fibEntry)
110 {
111  if (mi.lastNexthop == face::INVALID_FACEID) {
112  NFD_LOG_DEBUG(pitEntry->getInterest() << " no-last-nexthop");
113  return false;
114  }
115 
116  if (mi.lastNexthop == inFace.getId()) {
117  NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-is-downstream");
118  return false;
119  }
120 
121  Face* face = this->getFace(mi.lastNexthop);
122  if (face == nullptr || !fibEntry.hasNextHop(*face)) {
123  NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-gone");
124  return false;
125  }
126 
127  if (violatesScope(*pitEntry, *face)) {
128  NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-violates-scope");
129  return false;
130  }
131 
132  RttEstimator::Duration rto = mi.rtt.computeRto();
133  NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << mi.lastNexthop <<
134  " last-nexthop rto=" << time::duration_cast<time::microseconds>(rto).count());
135 
136  this->sendInterest(pitEntry, *face);
137 
138  // schedule RTO timeout
139  PitInfo* pi = pitEntry->insertStrategyInfo<PitInfo>().first;
140  pi->rtoTimer = scheduler::schedule(rto,
141  bind(&AccessStrategy::afterRtoTimeout, this, weak_ptr<pit::Entry>(pitEntry),
142  inFace.getId(), mi.lastNexthop));
143 
144  return true;
145 }
146 
147 void
148 AccessStrategy::afterRtoTimeout(weak_ptr<pit::Entry> pitWeak, FaceId inFace, FaceId firstOutFace)
149 {
150  shared_ptr<pit::Entry> pitEntry = pitWeak.lock();
151  BOOST_ASSERT(pitEntry != nullptr);
152  // pitEntry can't become nullptr, because RTO timer should be cancelled upon pitEntry destruction
153 
154  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
155 
156  NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFace <<
157  " multicast-except " << inFace << ',' << firstOutFace);
158  this->multicast(pitEntry, fibEntry, {inFace, firstOutFace});
159 }
160 
161 void
162 AccessStrategy::multicast(const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
163  std::unordered_set<FaceId> exceptFaces)
164 {
165  for (const fib::NextHop& nexthop : fibEntry.getNextHops()) {
166  Face& face = nexthop.getFace();
167  if (exceptFaces.count(face.getId()) > 0) {
168  continue;
169  }
170  NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << face.getId() <<
171  " multicast");
172  this->sendInterest(pitEntry, face);
173  }
174 }
175 
176 void
177 AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
178  const Face& inFace, const Data& data)
179 {
180  PitInfo* pi = pitEntry->getStrategyInfo<PitInfo>();
181  if (pi != nullptr) {
182  pi->rtoTimer.cancel();
183  }
184 
185  if (!pitEntry->hasInRecords()) { // already satisfied by another upstream
186  NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
187  " not-fastest");
188  return;
189  }
190 
191  pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(inFace);
192  if (outRecord == pitEntry->out_end()) { // no out-record
193  NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
194  " no-out-record");
195  return;
196  }
197 
198  time::steady_clock::Duration rtt = time::steady_clock::now() - outRecord->getLastRenewed();
199  NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << inFace.getId() <<
200  " rtt=" << time::duration_cast<time::microseconds>(rtt).count());
201  this->updateMeasurements(inFace, data, time::duration_cast<RttEstimator::Duration>(rtt));
202 }
203 
204 void
205 AccessStrategy::updateMeasurements(const Face& inFace, const Data& data,
206  const RttEstimator::Duration& rtt)
207 {
208  FaceInfo& fi = m_fit[inFace.getId()];
209  fi.rtt.addMeasurement(rtt);
210 
211  MtInfo* mi = this->addPrefixMeasurements(data);
212  if (mi->lastNexthop != inFace.getId()) {
213  mi->lastNexthop = inFace.getId();
214  mi->rtt = fi.rtt;
215  }
216  else {
217  mi->rtt.addMeasurement(rtt);
218  }
219 }
220 
221 AccessStrategy::MtInfo::MtInfo()
222  : lastNexthop(face::INVALID_FACEID)
223  , rtt(1, time::milliseconds(1), 0.1)
224 {
225 }
226 
227 std::tuple<Name, AccessStrategy::MtInfo*>
228 AccessStrategy::findPrefixMeasurements(const pit::Entry& pitEntry)
229 {
230  measurements::Entry* me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
231  if (me == nullptr) {
232  return std::make_tuple(Name(), nullptr);
233  }
234 
235  MtInfo* mi = me->getStrategyInfo<MtInfo>();
236  BOOST_ASSERT(mi != nullptr);
237  // XXX after runtime strategy change, it's possible that me exists but mi doesn't exist;
238  // this case needs another longest prefix match until mi is found
239  return std::make_tuple(me->getName(), mi);
240 }
241 
242 AccessStrategy::MtInfo*
243 AccessStrategy::addPrefixMeasurements(const Data& data)
244 {
245  measurements::Entry* me = nullptr;
246  if (!data.getName().empty()) {
247  me = this->getMeasurements().get(data.getName().getPrefix(-1));
248  }
249  if (me == nullptr) { // parent of Data Name is not in this strategy, or Data Name is empty
250  me = this->getMeasurements().get(data.getName());
251  // Data Name must be in this strategy
252  BOOST_ASSERT(me != nullptr);
253  }
254 
255  static const time::nanoseconds ME_LIFETIME = time::seconds(8);
256  this->getMeasurements().extendLifetime(*me, ME_LIFETIME);
257 
258  return me->insertStrategyInfo<MtInfo>().first;
259 }
260 
261 AccessStrategy::FaceInfo::FaceInfo()
262  : rtt(1, time::milliseconds(1), 0.1)
263 {
264 }
265 
266 void
267 AccessStrategy::removeFaceInfo(const Face& face)
268 {
269  m_fit.erase(face.getId());
270 }
271 
272 } // namespace fw
273 } // namespace nfd
#define NFD_REGISTER_STRATEGY(StrategyType)
registers a built-in strategy
main class of NFD
Definition: forwarder.hpp:52
Copyright (c) 2014-2016, Regents of the University of California, Arizona Board of Regents...
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:161
time::microseconds Duration
represents a FIB entry
Definition: fib-entry.hpp:51
Interest is retransmission and should be suppressed.
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace, const Data &data) override
trigger before PIT entry is satisfied
MeasurementsAccessor & getMeasurements()
Definition: strategy.hpp:188
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...
Table::const_iterator iterator
Definition: cs-internal.hpp:41
AccessStrategy(Forwarder &forwarder, const Name &name=STRATEGY_NAME)
Access Router Strategy version 1.
bool violatesScope(const pit::Entry &pitEntry, const Face &outFace)
determine whether forwarding the Interest in pitEntry to outFace would violate scope ...
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
virtual void afterReceiveInterest(const Face &inFace, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry) override
trigger after Interest is received
Interest is retransmission and should be forwarded.
represents a forwarding strategy
Definition: strategy.hpp:38
Interest is new (not a retransmission)
#define NFD_LOG_INIT(name)
Definition: logger.hpp:122
EventId schedule(const time::nanoseconds &after, const Scheduler::Event &event)
schedule an event
Definition: scheduler.cpp:47
uint64_t FaceId
identifies a face
Definition: face.hpp:39
static const Name STRATEGY_NAME
void sendInterest(const shared_ptr< pit::Entry > &pitEntry, Face &outFace, bool wantNewNonce=false)
send Interest to outFace
Definition: strategy.hpp:138
const FaceId INVALID_FACEID
indicates an invalid FaceId
Definition: face.hpp:42
Face * getFace(FaceId id) const
Definition: strategy.hpp:194
const fib::Entry & lookupFib(const pit::Entry &pitEntry) const
performs a FIB lookup, considering Link object if present
Definition: strategy.cpp:91