asf-strategy.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "asf-strategy.hpp"
27 #include "algorithm.hpp"
28 
29 #include "core/logger.hpp"
30 
31 namespace nfd {
32 namespace fw {
33 namespace asf {
34 
35 NFD_LOG_INIT("AsfStrategy");
36 NFD_REGISTER_STRATEGY(AsfStrategy);
37 
38 const time::milliseconds AsfStrategy::RETX_SUPPRESSION_INITIAL(10);
39 const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
40 
41 AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
42  : Strategy(forwarder)
43  , m_measurements(getMeasurements())
44  , m_probing(m_measurements)
45  , m_retxSuppression(RETX_SUPPRESSION_INITIAL,
46  RetxSuppressionExponential::DEFAULT_MULTIPLIER,
47  RETX_SUPPRESSION_MAX)
48 {
50  if (!parsed.parameters.empty()) {
51  BOOST_THROW_EXCEPTION(std::invalid_argument("AsfStrategy does not accept parameters"));
52  }
53  if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
54  BOOST_THROW_EXCEPTION(std::invalid_argument(
55  "AsfStrategy does not support version " + std::to_string(*parsed.version)));
56  }
58 }
59 
60 const Name&
62 {
63  static Name strategyName("/localhost/nfd/strategy/asf/%FD%01");
64  return strategyName;
65 }
66 
67 void
68 AsfStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
69  const shared_ptr<pit::Entry>& pitEntry)
70 {
71  // Should the Interest be suppressed?
72  RetxSuppression::Result suppressResult = m_retxSuppression.decide(inFace, interest, *pitEntry);
73 
74  switch (suppressResult) {
77  break;
79  NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " suppressed");
80  return;
81  }
82 
83  const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
84  const fib::NextHopList& nexthops = fibEntry.getNextHops();
85 
86  if (nexthops.size() == 0) {
87  sendNoRouteNack(inFace, interest, pitEntry);
88  this->rejectPendingInterest(pitEntry);
89  return;
90  }
91 
92  Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, inFace);
93 
94  if (faceToUse == nullptr) {
95  sendNoRouteNack(inFace, interest, pitEntry);
96  this->rejectPendingInterest(pitEntry);
97  return;
98  }
99 
100  forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
101 
102  // If necessary, send probe
103  if (m_probing.isProbingNeeded(fibEntry, interest)) {
104  Face* faceToProbe = m_probing.getFaceToProbe(inFace, interest, fibEntry, *faceToUse);
105 
106  if (faceToProbe != nullptr) {
107  bool wantNewNonce = true;
108  forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, wantNewNonce);
109  m_probing.afterForwardingProbe(fibEntry, interest);
110  }
111  }
112 }
113 
114 void
115 AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
116  const Face& inFace, const Data& data)
117 {
118  NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
119 
120  if (namespaceInfo == nullptr) {
121  NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
122  return;
123  }
124 
125  // Record the RTT between the Interest out to Data in
126  FaceInfo& faceInfo = namespaceInfo->get(inFace.getId());
127  faceInfo.recordRtt(pitEntry, inFace);
128 
129  // Extend lifetime for measurements associated with Face
130  namespaceInfo->extendFaceInfoLifetime(faceInfo, inFace);
131 
132  if (faceInfo.isTimeoutScheduled()) {
133  faceInfo.cancelTimeoutEvent(data.getName());
134  }
135 }
136 
137 void
138 AsfStrategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
139  const shared_ptr<pit::Entry>& pitEntry)
140 {
141  NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << inFace.getId() << ": " << nack.getReason());
142  onTimeout(pitEntry->getName(), inFace.getId());
143 }
144 
147 
148 void
149 AsfStrategy::forwardInterest(const Interest& interest,
150  const fib::Entry& fibEntry,
151  const shared_ptr<pit::Entry>& pitEntry,
152  Face& outFace,
153  bool wantNewNonce)
154 {
155  if (wantNewNonce) {
156  //Send probe: interest with new Nonce
157  Interest probeInterest(interest);
158  probeInterest.refreshNonce();
159  NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
160  << " to FaceId: " << outFace.getId());
161  this->sendInterest(pitEntry, outFace, probeInterest);
162  }
163  else {
164  this->sendInterest(pitEntry, outFace, interest);
165  }
166 
167  FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, outFace);
168 
169  // Refresh measurements since Face is being used for forwarding
170  NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
171  namespaceInfo.extendFaceInfoLifetime(faceInfo, outFace);
172 
173  if (!faceInfo.isTimeoutScheduled()) {
174  // Estimate and schedule timeout
175  RttEstimator::Duration timeout = faceInfo.computeRto();
176 
177  NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix()
178  << " FaceId: " << outFace.getId()
179  << " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
180 
181  scheduler::EventId id = scheduler::schedule(timeout,
182  bind(&AsfStrategy::onTimeout, this, interest.getName(), outFace.getId()));
183 
184  faceInfo.setTimeoutEvent(id, interest.getName());
185  }
186 }
187 
188 struct FaceStats
189 {
190  Face* face;
191  RttStats::Rtt rtt;
192  RttStats::Rtt srtt;
193  uint64_t cost;
194 };
195 
196 double
197 getValueForSorting(const FaceStats& stats)
198 {
199  // These values allow faces with no measurements to be ranked better than timeouts
200  // srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
201  static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
202  static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
203 
204  if (stats.rtt == RttStats::RTT_TIMEOUT) {
205  return SORTING_RTT_TIMEOUT.count();
206  }
207  else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
208  return SORTING_RTT_NO_MEASUREMENT.count();
209  }
210  else {
211  return stats.srtt.count();
212  }
213 }
214 
215 Face*
216 AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
217  const Face& inFace)
218 {
219  NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
220 
221  typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
222  typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
223 
224  FaceStatsSet rankedFaces(
225  [] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
226  // Sort by RTT and then by cost
227  double lhsValue = getValueForSorting(lhs);
228  double rhsValue = getValueForSorting(rhs);
229 
230  if (lhsValue < rhsValue) {
231  return true;
232  }
233  else if (lhsValue == rhsValue) {
234  return lhs.cost < rhs.cost;
235  }
236  else {
237  return false;
238  }
239  });
240 
241  for (const fib::NextHop& hop : fibEntry.getNextHops()) {
242  Face& hopFace = hop.getFace();
243 
244  if (hopFace.getId() == inFace.getId() || wouldViolateScope(inFace, interest, hopFace)) {
245  continue;
246  }
247 
248  FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
249 
250  if (info == nullptr) {
251  FaceStats stats = {&hopFace,
254  hop.getCost()};
255 
256  rankedFaces.insert(stats);
257  }
258  else {
259  FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
260  rankedFaces.insert(stats);
261  }
262  }
263 
264  FaceStatsSet::iterator it = rankedFaces.begin();
265 
266  if (it != rankedFaces.end()) {
267  return it->face;
268  }
269  else {
270  return nullptr;
271  }
272 }
273 
274 void
275 AsfStrategy::onTimeout(const Name& interestName, face::FaceId faceId)
276 {
277  NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
278 
279  NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
280 
281  if (namespaceInfo == nullptr) {
282  NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
283  return;
284  }
285 
286  FaceInfoTable::iterator it = namespaceInfo->find(faceId);
287 
288  if (it == namespaceInfo->end()) {
289  it = namespaceInfo->insert(faceId);
290  }
291 
292  FaceInfo& faceInfo = it->second;
293  faceInfo.recordTimeout(interestName);
294 }
295 
296 void
297 AsfStrategy::sendNoRouteNack(const Face& inFace, const Interest& interest,
298  const shared_ptr<pit::Entry>& pitEntry)
299 {
300  NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " noNextHop");
301 
302  lp::NackHeader nackHeader;
303  nackHeader.setReason(lp::NackReason::NO_ROUTE);
304  this->sendNack(pitEntry, inFace, nackHeader);
305 }
306 
307 } // namespace asf
308 } // namespace fw
309 } // namespace nfd
main class of NFD
Definition: forwarder.hpp:52
void setInstanceName(const Name &name)
set strategy instance name
Definition: strategy.hpp:290
void afterForwardingProbe(const fib::Entry &fibEntry, const Interest &interest)
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:161
FaceInfo & getOrCreateFaceInfo(const fib::Entry &fibEntry, const Interest &interest, const Face &face)
static const Name & getStrategyName()
time::microseconds Duration
NamespaceInfo * getNamespaceInfo(const Name &prefix)
represents a FIB entry
Definition: fib-entry.hpp:51
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace, const Data &data) override
trigger before PIT entry is satisfied
NFD_REGISTER_STRATEGY(AsfStrategy)
void extendFaceInfoLifetime(FaceInfo &info, const Face &face)
Interest is retransmission and should be suppressed.
void sendInterest(const shared_ptr< pit::Entry > &pitEntry, Face &outFace, const Interest &interest)
send Interest to outFace
Definition: strategy.hpp:191
void sendNack(const shared_ptr< pit::Entry > &pitEntry, const Face &outFace, const lp::NackHeader &header)
send Nack to outFace
Definition: strategy.hpp:217
static Name makeInstanceName(const Name &input, const Name &strategyName)
construct a strategy instance name
Definition: strategy.cpp:132
time::duration< double, boost::micro > Rtt
FaceInfo & get(nfd::face::FaceId faceId)
Table::const_iterator iterator
Definition: cs-internal.hpp:41
void cancelTimeoutEvent(const Name &prefix)
FaceInfo * getFaceInfo(const fib::Entry &fibEntry, const Interest &interest, const Face &face)
const Name & getPrefix() const
Definition: fib-entry.hpp:58
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
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...
a retransmission suppression decision algorithm that suppresses retransmissions using exponential bac...
NamespaceInfo & getOrCreateNamespaceInfo(const fib::Entry &fibEntry, const Interest &interest)
std::vector< fib::NextHop > NextHopList
Definition: fib-entry.hpp:47
bool isProbingNeeded(const fib::Entry &fibEntry, const Interest &interest)
PartialName parameters
parameter components
Definition: strategy.hpp:263
Interest is retransmission and should be forwarded.
ndn::optional< uint64_t > version
whether strategyName contains a version component
Definition: strategy.hpp:262
bool isTimeoutScheduled() const
void recordRtt(const shared_ptr< pit::Entry > &pitEntry, const Face &inFace)
stores stategy information about each face in this namespace
represents a forwarding strategy
Definition: strategy.hpp:37
virtual void afterReceiveNack(const Face &inFace, const lp::Nack &nack, const shared_ptr< pit::Entry > &pitEntry) override
trigger after Nack is received
Copyright (c) 2014-2016, Regents of the University of California, Arizona Board of Regents...
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
static const Rtt RTT_TIMEOUT
static ParsedInstanceName parseInstanceName(const Name &input)
parse a strategy instance name
Definition: strategy.cpp:121
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:160
virtual void afterReceiveInterest(const Face &inFace, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry) override
trigger after Interest is received
double getValueForSorting(const FaceStats &stats)
Face * getFaceToProbe(const Face &inFace, const Interest &interest, const fib::Entry &fibEntry, const Face &faceUsed)
uint64_t FaceId
identifies a face
Definition: face.hpp:39
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 NextHopList & getNextHops() const
Definition: fib-entry.hpp:64
void rejectPendingInterest(const shared_ptr< pit::Entry > &pitEntry)
decide that a pending Interest cannot be forwarded
Definition: strategy.hpp:204
const fib::Entry & lookupFib(const pit::Entry &pitEntry) const
performs a FIB lookup, considering Link object if present
Definition: strategy.cpp:196
Strategy information for each face in a namespace.
AsfStrategy(Forwarder &forwarder, const Name &name=getStrategyName())
static const Rtt RTT_NO_MEASUREMENT