29 #include <boost/lexical_cast.hpp>
42 NDN_THROW(std::invalid_argument(
"AsfStrategy does not support version " +
43 std::to_string(*parsed.
version)));
48 auto probingInterval = params.
getOrDefault<time::milliseconds::rep>(
"probing-interval",
51 m_nMaxTimeouts = params.
getOrDefault<
size_t>(
"max-timeouts", m_nMaxTimeouts);
52 auto measurementsLifetime = time::milliseconds(params.
getOrDefault<time::milliseconds::rep>(
"measurements-lifetime",
55 NDN_THROW(std::invalid_argument(
"Measurements lifetime (" + boost::lexical_cast<std::string>(measurementsLifetime) +
56 ") should be greater than the probing interval of " +
63 NDN_LOG_DEBUG(*m_retxSuppression);
65 <<
" max-timeouts=" << m_nMaxTimeouts
72 static const auto strategyName = Name(
"/localhost/nfd/strategy/asf").appendVersion(5);
78 const shared_ptr<pit::Entry>& pitEntry)
80 const auto& fibEntry = this->
lookupFib(*pitEntry);
84 auto faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry);
85 if (faceToUse ==
nullptr) {
87 sendNoRouteNack(ingress.
face, pitEntry);
91 forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
92 sendProbe(interest, ingress, *faceToUse, fibEntry, pitEntry);
97 auto faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry,
false);
98 if (faceToUse !=
nullptr) {
99 auto suppressResult = m_retxSuppression->decidePerUpstream(*pitEntry, *faceToUse);
108 auto* outRecord = forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
110 m_retxSuppression->incrementIntervalForOutRecord(*outRecord);
118 const auto& nexthops = fibEntry.getNextHops();
120 if (it == nexthops.end()) {
124 auto& outFace = it->getFace();
125 auto suppressResult = m_retxSuppression->decidePerUpstream(*pitEntry, outFace);
133 auto* outRecord =
sendInterest(interest, outFace, pitEntry);
135 m_retxSuppression->incrementIntervalForOutRecord(*outRecord);
142 const shared_ptr<pit::Entry>& pitEntry)
145 if (namespaceInfo ==
nullptr) {
152 if (faceInfo ==
nullptr) {
157 auto outRecord = pitEntry->findOutRecord(ingress.
face);
158 if (outRecord == pitEntry->out_end()) {
162 faceInfo->
recordRtt(time::steady_clock::now() - outRecord->getLastRenewed());
176 const shared_ptr<pit::Entry>& pitEntry)
179 onTimeoutOrNack(pitEntry->getName(), ingress.
face.
getId(),
true);
184 AsfStrategy::forwardInterest(
const Interest& interest,
Face& outFace,
const fib::Entry& fibEntry,
185 const shared_ptr<pit::Entry>& pitEntry)
187 const auto& interestName = interest.getName();
188 auto faceId = outFace.
getId();
190 auto* outRecord =
sendInterest(interest, outFace, pitEntry);
200 [
this, name = interestName, faceId] {
201 onTimeoutOrNack(name, faceId,
false);
204 <<
" in " << time::duration_cast<time::milliseconds>(timeout));
211 AsfStrategy::sendProbe(
const Interest& interest,
const FaceEndpoint& ingress,
const Face& faceToUse,
212 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry)
217 Face* faceToProbe = m_probing.
getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
218 if (faceToProbe ==
nullptr)
221 Interest probeInterest(interest);
222 probeInterest.refreshNonce();
223 NFD_LOG_DEBUG(
"Sending probe " << probeInterest.getName() <<
" nonce=" << probeInterest.getNonce()
224 <<
" to=" << faceToProbe->getId() <<
" trigger-nonce=" << interest.getNonce());
225 forwardInterest(probeInterest, *faceToProbe, fibEntry, pitEntry);
256 auto srtt = priority == 1 ? fs.srtt : time::nanoseconds::max();
261 return std::tuple(priority, srtt, fs.cost, fs.face->getId());
265 AsfStrategy::FaceStatsForwardingCompare::operator()(
const FaceStats& lhs,
const FaceStats& rhs)
const noexcept
271 AsfStrategy::getBestFaceForForwarding(
const Interest& interest,
const Face& inFace,
272 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry,
275 FaceStatsForwardingSet rankedFaces;
277 auto now = time::steady_clock::now();
283 const FaceInfo* info = m_measurements.
getFaceInfo(fibEntry, interest.getName(), nh.getFace().getId());
284 if (info ==
nullptr) {
289 rankedFaces.insert({&nh.getFace(), info->getLastRtt(), info->getSrtt(), nh.getCost()});
293 auto it = rankedFaces.begin();
294 return it != rankedFaces.end() ? it->face :
nullptr;
298 AsfStrategy::onTimeoutOrNack(
const Name& interestName,
FaceId faceId,
bool isNack)
300 NamespaceInfo* namespaceInfo = m_measurements.
getNamespaceInfo(interestName);
301 if (namespaceInfo ==
nullptr) {
302 NFD_LOG_TRACE(interestName <<
" FibEntry has been removed since timeout scheduling");
306 FaceInfo* fiPtr = namespaceInfo->getFaceInfo(faceId);
307 if (fiPtr ==
nullptr) {
308 NFD_LOG_TRACE(interestName <<
" FaceInfo id=" << faceId <<
" has been removed since timeout scheduling");
312 auto& faceInfo = *fiPtr;
316 if (nTimeouts < m_nMaxTimeouts && !isNack) {
317 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts <<
" ignoring");
319 namespaceInfo->extendFaceInfoLifetime(faceInfo, faceId);
323 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts);
330 AsfStrategy::sendNoRouteNack(Face& face,
const shared_ptr<pit::Entry>& pitEntry)
332 lp::NackHeader nackHeader;
333 nackHeader.setReason(lp::NackReason::NO_ROUTE);
334 this->
sendNack(nackHeader, face, pitEntry);
This file contains common algorithms used by forwarding strategies.
Represents a face-endpoint pair in the forwarder.
Main class of NFD's forwarding engine.
Generalization of a network interface.
FaceId getId() const noexcept
Returns the face ID.
Represents an entry in the FIB.
const NextHopList & getNextHops() const noexcept
const Name & getPrefix() const noexcept
void processNack(const lp::Nack &nack, const Face &inFace, const shared_ptr< pit::Entry > &pitEntry)
static std::unique_ptr< RetxSuppressionExponential > construct(const StrategyParameters ¶ms)
Base class of all forwarding strategies.
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.
bool sendNack(const lp::NackHeader &header, Face &egress, const shared_ptr< pit::Entry > &pitEntry)
Send a Nack packet.
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.
void setExpiryTimer(const shared_ptr< pit::Entry > &pitEntry, time::milliseconds duration)
Schedule the PIT entry to be erased after duration.
void setInstanceName(const Name &name) noexcept
Set strategy instance name.
static StrategyParameters parseParameters(const PartialName ¶ms)
Parse strategy parameters encoded in a strategy instance name.
static Name makeInstanceName(const Name &input, const Name &strategyName)
Construct a strategy instance name.
std::enable_if_t< std::is_signed_v< T >, T > getOrDefault(const key_type &key, const T &defaultVal) const
NamespaceInfo & getOrCreateNamespaceInfo(const fib::Entry &fibEntry, const Name &prefix)
static constexpr time::milliseconds DEFAULT_MEASUREMENTS_LIFETIME
void setMeasurementsLifetime(time::milliseconds measurementsLifetime)
time::milliseconds getMeasurementsLifetime() const
FaceInfo & getOrCreateFaceInfo(const fib::Entry &fibEntry, const Name &interestName, FaceId faceId)
FaceInfo * getFaceInfo(const fib::Entry &fibEntry, const Name &interestName, FaceId faceId)
NamespaceInfo * getNamespaceInfo(const Name &prefix)
Adaptive SRTT-based forwarding strategy.
static const Name & getStrategyName()
void afterReceiveNack(const lp::Nack &nack, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger after a Nack is received.
AsfStrategy(Forwarder &forwarder, const Name &name=getStrategyName())
void afterReceiveInterest(const Interest &interest, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger after an Interest is received.
void beforeSatisfyInterest(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger before a PIT entry is satisfied.
Strategy information for each face in a namespace.
static constexpr time::nanoseconds RTT_TIMEOUT
void cancelTimeout(const Name &prefix)
bool isTimeoutScheduled() const
size_t getNTimeouts() const
time::nanoseconds scheduleTimeout(const Name &interestName, ndn::scheduler::EventCallback cb)
static constexpr time::nanoseconds RTT_NO_MEASUREMENT
time::nanoseconds getSrtt() const
void setNTimeouts(size_t nTimeouts)
time::nanoseconds getLastRtt() const
void recordTimeout(const Name &interestName)
void recordRtt(time::nanoseconds rtt)
Stores strategy information about each face in this namespace.
FaceInfo * getFaceInfo(FaceId faceId)
void extendFaceInfoLifetime(FaceInfo &info, FaceId faceId)
Face * getFaceToProbe(const Face &inFace, const Interest &interest, const fib::Entry &fibEntry, const Face &faceUsed)
bool isProbingNeeded(const fib::Entry &fibEntry, const Name &interestName)
time::milliseconds getProbingInterval() const
void afterForwardingProbe(const fib::Entry &fibEntry, const Name &interestName)
void setProbingInterval(time::milliseconds probingInterval)
Contains information about an Interest toward an outgoing face.
#define NFD_LOG_INIT(name)
uint64_t FaceId
Identifies a face.
static auto getFaceRankForForwarding(const FaceStats &fs) noexcept
@ SUPPRESS
Interest is a retransmission and should be suppressed.
@ FORWARD
Interest is a retransmission and should be forwarded.
bool isNextHopEligible(const Face &inFace, const Interest &interest, const fib::NextHop &nexthop, const shared_ptr< pit::Entry > &pitEntry, bool wantUnused, time::steady_clock::time_point now)
Determines whether a NextHop is eligible, i.e., not the same inFace.
fib::NextHopList::const_iterator findEligibleNextHopWithEarliestOutRecord(const Face &inFace, const Interest &interest, const fib::NextHopList &nexthops, const shared_ptr< pit::Entry > &pitEntry)
Pick an eligible NextHop with earliest out-record.
NFD_REGISTER_STRATEGY(SelfLearningStrategy)
bool hasPendingOutRecords(const pit::Entry &pitEntry)
Determine whether pitEntry has any pending out-records.
#define NFD_LOG_INTEREST_FROM(interest, ingress, msg)
Logs the reception of interest on ingress, followed by msg, at DEBUG level.
#define NFD_LOG_DATA_FROM(data, ingress, msg)
Logs the reception of data on ingress, followed by msg, at DEBUG level.
#define NFD_LOG_NACK_FROM(nack, ingress, msg)
Logs the reception of nack on ingress, followed by msg, at DEBUG level.
std::optional< uint64_t > version
The strategy version number, if present.
PartialName parameters
Parameter components, may be empty.
Container for ranking-related values.