38 , m_rttEstimatorOpts(make_shared<RttEstimator::Options>())
39 , m_removeFaceConn(beforeRemoveFace.connect([this] (const
Face& face) { m_fit.erase(face.getId()); }))
42 if (!parsed.parameters.empty()) {
43 NDN_THROW(std::invalid_argument(
"AccessStrategy does not accept parameters"));
45 if (parsed.version && *parsed.version !=
getStrategyName()[-1].toVersion()) {
46 NDN_THROW(std::invalid_argument(
"AccessStrategy does not support version " + to_string(*parsed.version)));
54 static const auto strategyName = Name(
"/localhost/nfd/strategy/access").appendVersion(1);
60 const shared_ptr<pit::Entry>& pitEntry)
64 return afterReceiveNewInterest(interest, ingress, pitEntry);
66 return afterReceiveRetxInterest(interest, ingress, pitEntry);
68 NFD_LOG_DEBUG(interest <<
" interestFrom " << ingress <<
" retx-suppress");
74 AccessStrategy::afterReceiveNewInterest(
const Interest& interest,
const FaceEndpoint& ingress,
75 const shared_ptr<pit::Entry>& pitEntry)
77 const auto& fibEntry = this->
lookupFib(*pitEntry);
78 auto [miName, mi] = this->findPrefixMeasurements(*pitEntry);
82 NFD_LOG_DEBUG(interest <<
" interestFrom " << ingress <<
" new-interest mi=" << miName);
85 bool isSentToLastNexthop = this->sendToLastNexthop(interest, ingress, pitEntry, *mi, fibEntry);
86 if (isSentToLastNexthop) {
91 NFD_LOG_DEBUG(interest <<
" interestFrom " << ingress <<
" new-interest no-mi");
97 size_t nMulticastSent = this->multicast(interest, ingress.
face, pitEntry, fibEntry);
99 if (nMulticastSent == 0) {
105 AccessStrategy::afterReceiveRetxInterest(
const Interest& interest,
const FaceEndpoint& ingress,
106 const shared_ptr<pit::Entry>& pitEntry)
108 const auto& fibEntry = this->
lookupFib(*pitEntry);
109 NFD_LOG_DEBUG(interest <<
" interestFrom " << ingress <<
" retx-forward");
110 this->multicast(interest, ingress.face, pitEntry, fibEntry);
114 AccessStrategy::sendToLastNexthop(
const Interest& interest,
const FaceEndpoint& ingress,
115 const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
116 const fib::Entry& fibEntry)
119 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" no-last-nexthop");
123 if (mi.lastNexthop == ingress.face.getId()) {
124 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" last-nexthop-is-downstream");
128 Face* outFace = this->
getFace(mi.lastNexthop);
129 if (outFace ==
nullptr || !fibEntry.hasNextHop(*outFace)) {
130 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" last-nexthop-gone");
135 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" last-nexthop-violates-scope");
139 auto rto = mi.rtt.getEstimatedRto();
140 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" interestTo " << mi.lastNexthop
141 <<
" last-nexthop rto=" << time::duration_cast<time::microseconds>(rto).count());
143 if (!this->
sendInterest(interest, *outFace, pitEntry)) {
148 PitInfo* pi = pitEntry->insertStrategyInfo<PitInfo>().first;
150 [
this, pitWeak = weak_ptr<pit::Entry>(pitEntry), face = ingress.face.getId(), nh = mi.lastNexthop] {
151 afterRtoTimeout(pitWeak, face, nh);
158 AccessStrategy::afterRtoTimeout(
const weak_ptr<pit::Entry>& pitWeak,
161 shared_ptr<pit::Entry> pitEntry = pitWeak.lock();
163 BOOST_ASSERT(pitEntry !=
nullptr);
165 Face* inFace = this->
getFace(inFaceId);
166 if (inFace ==
nullptr) {
167 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" timeoutFrom " << firstOutFaceId
168 <<
" inFace-gone " << inFaceId);
172 auto inRecord = pitEntry->getInRecord(*inFace);
176 BOOST_ASSERT(inRecord != pitEntry->in_end());
178 const Interest& interest = inRecord->getInterest();
179 const fib::Entry& fibEntry = this->
lookupFib(*pitEntry);
181 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" timeoutFrom " << firstOutFaceId
182 <<
" multicast-except " << firstOutFaceId);
183 this->multicast(interest, *inFace, pitEntry, fibEntry, firstOutFaceId);
187 AccessStrategy::multicast(
const Interest& interest,
const Face& inFace,
188 const shared_ptr<pit::Entry>& pitEntry,
const fib::Entry& fibEntry,
192 for (
const auto& nexthop : fibEntry.getNextHops()) {
193 Face& outFace = nexthop.getFace();
194 if (&outFace == &inFace || outFace.getId() == exceptFace ||
198 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" interestTo " << outFace.getId() <<
" multicast");
208 const shared_ptr<pit::Entry>& pitEntry)
210 PitInfo* pi = pitEntry->getStrategyInfo<PitInfo>();
212 pi->rtoTimer.cancel();
215 if (!pitEntry->hasInRecords()) {
216 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" dataFrom " << ingress <<
" not-fastest");
220 auto outRecord = pitEntry->getOutRecord(ingress.
face);
221 if (outRecord == pitEntry->out_end()) {
222 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" dataFrom " << ingress <<
" no-out-record");
226 auto rtt = time::steady_clock::now() - outRecord->getLastRenewed();
227 NFD_LOG_DEBUG(pitEntry->getInterest() <<
" dataFrom " << ingress
228 <<
" rtt=" << time::duration_cast<time::microseconds>(rtt).count());
229 this->updateMeasurements(ingress.
face, data, rtt);
233 AccessStrategy::updateMeasurements(
const Face& inFace,
const Data& data, time::nanoseconds rtt)
235 FaceInfo& fi = m_fit.try_emplace(inFace.
getId(), m_rttEstimatorOpts).first->second;
236 fi.rtt.addMeasurement(rtt);
238 MtInfo* mi = this->addPrefixMeasurements(data);
239 if (mi->lastNexthop != inFace.
getId()) {
240 mi->lastNexthop = inFace.
getId();
244 mi->rtt.addMeasurement(rtt);
248 std::tuple<Name, AccessStrategy::MtInfo*>
249 AccessStrategy::findPrefixMeasurements(
const pit::Entry& pitEntry)
253 return {Name{},
nullptr};
260 return {me->getName(), mi};
263 AccessStrategy::MtInfo*
264 AccessStrategy::addPrefixMeasurements(
const Data& data)
266 measurements::Entry* me =
nullptr;
267 if (!data.getName().empty()) {
273 BOOST_ASSERT(me !=
nullptr);
277 return me->insertStrategyInfo<MtInfo>(m_rttEstimatorOpts).first;
This file contains common algorithms used by forwarding strategies.
Represents a face-endpoint pair in the forwarder.
Main class of NFD's forwarding engine.
T * getStrategyInfo() const
Get a StrategyInfo item.
Generalization of a network interface.
FaceId getId() const noexcept
Returns the face ID.
A forwarding strategy for "access" routers.
void afterReceiveInterest(const Interest &interest, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger after an Interest is received.
static const Name & getStrategyName()
AccessStrategy(Forwarder &forwarder, const Name &name=getStrategyName())
void beforeSatisfyInterest(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger before a PIT entry is satisfied.
RetxSuppressionResult decidePerPitEntry(pit::Entry &pitEntry) const
Determines whether Interest is a retransmission, and if so, whether it shall be forwarded or suppress...
Base class of all forwarding strategies.
Face * getFace(FaceId id) const noexcept
void rejectPendingInterest(const shared_ptr< pit::Entry > &pitEntry)
Schedule the PIT entry for immediate deletion.
const fib::Entry & lookupFib(const pit::Entry &pitEntry) const
Performs a FIB lookup, considering Link object if present.
pit::OutRecord * sendInterest(const Interest &interest, Face &egress, const shared_ptr< pit::Entry > &pitEntry)
Send an Interest packet.
static ParsedInstanceName parseInstanceName(const Name &input)
Parse a strategy instance name.
MeasurementsAccessor & getMeasurements() noexcept
void setInstanceName(const Name &name) noexcept
Set strategy instance name.
static Name makeInstanceName(const Name &input, const Name &strategyName)
Construct a strategy instance name.
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.
Entry * get(const Name &name)
Find or insert a Measurements entry for name.
#define NFD_LOG_INIT(name)
constexpr FaceId INVALID_FACEID
Indicates an invalid FaceId.
uint64_t FaceId
Identifies a face.
@ SUPPRESS
Interest is retransmission and should be suppressed.
@ NEW
Interest is new (not a retransmission)
@ FORWARD
Interest is retransmission and should be forwarded.
NFD_REGISTER_STRATEGY(SelfLearningStrategy)
bool wouldViolateScope(const Face &inFace, const Interest &interest, const Face &outFace)
Determine whether forwarding the Interest in pitEntry to outFace would violate scope.
Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.