41 NDN_THROW(std::invalid_argument(
"AsfStrategy does not support version " +
42 std::to_string(*parsed.
version)));
47 auto probingInterval = params.
getOrDefault<time::milliseconds::rep>(
"probing-interval",
50 m_nMaxTimeouts = params.
getOrDefault<
size_t>(
"max-timeouts", m_nMaxTimeouts);
54 NDN_LOG_DEBUG(*m_retxSuppression);
56 <<
" max-timeouts=" << m_nMaxTimeouts);
62 static const auto strategyName = Name(
"/localhost/nfd/strategy/asf").appendVersion(5);
68 const shared_ptr<pit::Entry>& pitEntry)
70 const auto& fibEntry = this->
lookupFib(*pitEntry);
74 auto faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry);
75 if (faceToUse ==
nullptr) {
77 sendNoRouteNack(ingress.
face, pitEntry);
81 forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
82 sendProbe(interest, ingress, *faceToUse, fibEntry, pitEntry);
87 auto faceToUse = getBestFaceForForwarding(interest, ingress.
face, fibEntry, pitEntry,
false);
88 if (faceToUse !=
nullptr) {
89 auto suppressResult = m_retxSuppression->decidePerUpstream(*pitEntry, *faceToUse);
98 auto* outRecord = forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
100 m_retxSuppression->incrementIntervalForOutRecord(*outRecord);
108 const auto& nexthops = fibEntry.getNextHops();
110 if (it == nexthops.end()) {
114 auto& outFace = it->getFace();
115 auto suppressResult = m_retxSuppression->decidePerUpstream(*pitEntry, outFace);
123 auto* outRecord =
sendInterest(interest, outFace, pitEntry);
125 m_retxSuppression->incrementIntervalForOutRecord(*outRecord);
132 const shared_ptr<pit::Entry>& pitEntry)
135 if (namespaceInfo ==
nullptr) {
142 if (faceInfo ==
nullptr) {
147 auto outRecord = pitEntry->findOutRecord(ingress.
face);
148 if (outRecord == pitEntry->out_end()) {
152 faceInfo->
recordRtt(time::steady_clock::now() - outRecord->getLastRenewed());
166 const shared_ptr<pit::Entry>& pitEntry)
169 onTimeoutOrNack(pitEntry->getName(), ingress.
face.
getId(),
true);
174 AsfStrategy::forwardInterest(
const Interest& interest,
Face& outFace,
const fib::Entry& fibEntry,
175 const shared_ptr<pit::Entry>& pitEntry)
177 const auto& interestName = interest.getName();
178 auto faceId = outFace.
getId();
180 auto* outRecord =
sendInterest(interest, outFace, pitEntry);
190 [
this, name = interestName, faceId] {
191 onTimeoutOrNack(name, faceId,
false);
194 <<
" in " << time::duration_cast<time::milliseconds>(timeout));
201 AsfStrategy::sendProbe(
const Interest& interest,
const FaceEndpoint& ingress,
const Face& faceToUse,
202 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry)
207 Face* faceToProbe = m_probing.
getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
208 if (faceToProbe ==
nullptr)
211 Interest probeInterest(interest);
212 probeInterest.refreshNonce();
213 NFD_LOG_DEBUG(
"Sending probe " << probeInterest.getName() <<
" nonce=" << probeInterest.getNonce()
214 <<
" to=" << faceToProbe->getId() <<
" trigger-nonce=" << interest.getNonce());
215 forwardInterest(probeInterest, *faceToProbe, fibEntry, pitEntry);
246 auto srtt = priority == 1 ? fs.srtt : time::nanoseconds::max();
251 return std::tuple(priority, srtt, fs.cost, fs.face->getId());
255 AsfStrategy::FaceStatsForwardingCompare::operator()(
const FaceStats& lhs,
const FaceStats& rhs)
const noexcept
261 AsfStrategy::getBestFaceForForwarding(
const Interest& interest,
const Face& inFace,
262 const fib::Entry& fibEntry,
const shared_ptr<pit::Entry>& pitEntry,
265 FaceStatsForwardingSet rankedFaces;
267 auto now = time::steady_clock::now();
273 const FaceInfo* info = m_measurements.
getFaceInfo(fibEntry, interest.getName(), nh.getFace().getId());
274 if (info ==
nullptr) {
279 rankedFaces.insert({&nh.getFace(), info->getLastRtt(), info->getSrtt(), nh.getCost()});
283 auto it = rankedFaces.begin();
284 return it != rankedFaces.end() ? it->face :
nullptr;
288 AsfStrategy::onTimeoutOrNack(
const Name& interestName,
FaceId faceId,
bool isNack)
290 NamespaceInfo* namespaceInfo = m_measurements.
getNamespaceInfo(interestName);
291 if (namespaceInfo ==
nullptr) {
292 NFD_LOG_TRACE(interestName <<
" FibEntry has been removed since timeout scheduling");
296 FaceInfo* fiPtr = namespaceInfo->getFaceInfo(faceId);
297 if (fiPtr ==
nullptr) {
298 NFD_LOG_TRACE(interestName <<
" FaceInfo id=" << faceId <<
" has been removed since timeout scheduling");
302 auto& faceInfo = *fiPtr;
306 if (nTimeouts < m_nMaxTimeouts && !isNack) {
307 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts <<
" ignoring");
309 namespaceInfo->extendFaceInfoLifetime(faceInfo, faceId);
313 NFD_LOG_TRACE(interestName <<
" face=" << faceId <<
" timeout-count=" << nTimeouts);
320 AsfStrategy::sendNoRouteNack(Face& face,
const shared_ptr<pit::Entry>& pitEntry)
322 lp::NackHeader nackHeader;
323 nackHeader.setReason(lp::NackReason::NO_ROUTE);
324 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)
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.