33 #include <ndn-cxx/lp/empty-value.hpp>
34 #include <ndn-cxx/lp/prefix-announcement-header.hpp>
35 #include <ndn-cxx/lp/tags.hpp>
37 #include <boost/range/adaptor/reversed.hpp>
51 NDN_THROW(std::invalid_argument(
"SelfLearningStrategy does not accept parameters"));
54 NDN_THROW(std::invalid_argument(
55 "SelfLearningStrategy does not support version " + to_string(*parsed.
version)));
63 static const auto strategyName = Name(
"/localhost/nfd/strategy/self-learning").appendVersion(1);
69 const shared_ptr<pit::Entry>& pitEntry)
74 bool isNonDiscovery = interest.getTag<lp::NonDiscoveryTag>() !=
nullptr;
75 auto inRecordInfo = pitEntry->getInRecord(ingress.
face)->insertStrategyInfo<
InRecordInfo>().first;
78 if (nexthops.empty()) {
79 NFD_LOG_DEBUG(
"NACK non-discovery Interest=" << interest <<
" from=" << ingress <<
" noNextHop");
80 lp::NackHeader nackHeader;
81 nackHeader.setReason(lp::NackReason::NO_ROUTE);
86 multicastInterest(interest, ingress.
face, pitEntry, nexthops);
90 inRecordInfo->isNonDiscoveryInterest =
false;
91 if (nexthops.empty()) {
92 broadcastInterest(interest, ingress.
face, pitEntry);
95 interest.setTag(make_shared<lp::NonDiscoveryTag>(lp::EmptyValue{}));
96 multicastInterest(interest, ingress.
face, pitEntry, nexthops);
103 const shared_ptr<pit::Entry>& pitEntry)
105 auto outRecord = pitEntry->getOutRecord(ingress.
face);
106 if (outRecord == pitEntry->out_end()) {
107 NFD_LOG_DEBUG(
"Data " << data.getName() <<
" from=" << ingress <<
" no out-record");
113 if (!needPrefixAnn(pitEntry)) {
117 asyncProcessData(pitEntry, ingress.
face, data);
121 auto paTag = data.getTag<lp::PrefixAnnouncementTag>();
122 if (paTag !=
nullptr) {
123 addRoute(pitEntry, ingress.
face, data, *paTag->get().getPrefixAnn());
133 const shared_ptr<pit::Entry>& pitEntry)
135 NFD_LOG_DEBUG(
"Nack for " << nack.getInterest() <<
" from=" << ingress
136 <<
" reason=" << nack.getReason());
137 if (nack.getReason() == lp::NackReason::NO_ROUTE) {
140 this->
sendNacks(nack.getHeader(), pitEntry);
141 renewRoute(nack.getInterest().getName(), ingress.
face.
getId(), 0_ms);
146 SelfLearningStrategy::broadcastInterest(
const Interest& interest,
const Face& inFace,
147 const shared_ptr<pit::Entry>& pitEntry)
149 for (
auto& outFace : this->
getFaceTable() | boost::adaptors::reversed) {
150 if ((outFace.getId() == inFace.
getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
152 outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
157 " to=" << outFace.getId());
158 auto outRecord = this->
sendInterest(interest, outFace, pitEntry);
159 if (outRecord !=
nullptr) {
160 outRecord->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest =
false;
166 SelfLearningStrategy::multicastInterest(
const Interest& interest,
const Face& inFace,
167 const shared_ptr<pit::Entry>& pitEntry,
170 for (
const auto& nexthop : nexthops) {
175 Face& outFace = nexthop.getFace();
176 NFD_LOG_DEBUG(
"send non-discovery Interest=" << interest <<
" from=" << inFace.getId() <<
177 " to=" << outFace.getId());
178 auto outRecord = this->
sendInterest(interest, outFace, pitEntry);
179 if (outRecord !=
nullptr) {
180 outRecord->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest =
true;
186 SelfLearningStrategy::asyncProcessData(
const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace,
const Data& data)
193 runOnRibIoService([
this, pitEntryWeak = weak_ptr<pit::Entry>{pitEntry}, inFaceId = inFace.getId(), data] {
195 [
this, pitEntryWeak, inFaceId, data] (std::optional<ndn::PrefixAnnouncement> paOpt) {
197 runOnMainIoService([this, pitEntryWeak, inFaceId, data, pa = std::move(*paOpt)] {
198 auto pitEntry = pitEntryWeak.lock();
199 auto inFace = this->getFace(inFaceId);
200 if (pitEntry && inFace) {
201 NFD_LOG_DEBUG(
"found PrefixAnnouncement=" << pa.getAnnouncedName());
202 data.setTag(make_shared<lp::PrefixAnnouncementTag>(lp::PrefixAnnouncementHeader(pa)));
203 this->sendDataToAll(data, pitEntry, *inFace);
204 this->setExpiryTimer(pitEntry, 0_ms);
207 NFD_LOG_DEBUG(
"PIT entry or Face no longer exists");
216 SelfLearningStrategy::needPrefixAnn(
const shared_ptr<pit::Entry>& pitEntry)
218 bool hasDiscoveryInterest =
false;
219 bool directToConsumer =
true;
221 auto now = time::steady_clock::now();
222 for (
const auto& inRecord : pitEntry->getInRecords()) {
223 if (inRecord.getExpiry() > now) {
224 InRecordInfo* inRecordInfo = inRecord.getStrategyInfo<InRecordInfo>();
225 if (inRecordInfo && !inRecordInfo->isNonDiscoveryInterest) {
226 hasDiscoveryInterest =
true;
228 if (inRecord.getFace().getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
229 directToConsumer =
false;
233 return hasDiscoveryInterest && !directToConsumer;
237 SelfLearningStrategy::addRoute(
const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace,
238 const Data& data,
const ndn::PrefixAnnouncement& pa)
240 runOnRibIoService([pitEntryWeak = weak_ptr<pit::Entry>{pitEntry}, inFaceId = inFace.getId(), data, pa] {
243 NFD_LOG_DEBUG(
"Add route via PrefixAnnouncement with result=" << res);
249 SelfLearningStrategy::renewRoute(
const Name& name,
FaceId inFaceId, time::milliseconds maxLifetime)
This file contains common algorithms used by forwarding strategies.
Represents a face-endpoint pair in the forwarder.
Main class of NFD's forwarding engine.
void slRenew(const Name &name, uint64_t faceId, time::milliseconds maxLifetime, const SlAnnounceCallback &cb)
Renew a route created by prefix announcement from self-learning strategy.
void slAnnounce(const ndn::PrefixAnnouncement &pa, uint64_t faceId, time::milliseconds maxLifetime, const SlAnnounceCallback &cb)
Insert a route by prefix announcement from self-learning strategy.
void slFindAnn(const Name &name, const SlFindAnnCallback &cb) const
Retrieve an outgoing prefix announcement for self-learning strategy.
Generalization of a network interface.
FaceId getId() const noexcept
Returns the face ID.
Represents an entry in the FIB.
const NextHopList & getNextHops() const
StrategyInfo on pit::InRecord.
bool isNonDiscoveryInterest
StrategyInfo on pit::OutRecord.
bool isNonDiscoveryInterest
Self-learning forwarding strategy.
void afterReceiveNack(const lp::Nack &nack, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger after a Nack is received.
void afterReceiveData(const Data &data, const FaceEndpoint &ingress, const shared_ptr< pit::Entry > &pitEntry) override
Trigger after Data is received.
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()
SelfLearningStrategy(Forwarder &forwarder, const Name &name=getStrategyName())
Base class of all forwarding strategies.
void rejectPendingInterest(const shared_ptr< pit::Entry > &pitEntry)
Schedule the PIT entry for immediate deletion.
const FaceTable & getFaceTable() const noexcept
void sendNacks(const lp::NackHeader &header, const shared_ptr< pit::Entry > &pitEntry, std::initializer_list< const Face * > exceptFaces={})
Send Nack to every face that has an in-record, except those in exceptFaces.
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.
void sendDataToAll(const Data &data, const shared_ptr< pit::Entry > &pitEntry, const Face &inFace)
Send a Data packet to all matched and qualified faces.
static Name makeInstanceName(const Name &input, const Name &strategyName)
Construct a strategy instance name.
static Service & get()
Get a reference to the only instance of this class.
RibManager & getRibManager() noexcept
#define NFD_LOG_INIT(name)
uint64_t FaceId
Identifies a face.
std::vector< NextHop > NextHopList
constexpr time::milliseconds ROUTE_RENEW_LIFETIME
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.
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.
void runOnRibIoService(const std::function< void()> &f)
Run a function on the RIB io_service instance.
std::optional< uint64_t > version
The strategy version number, if present.
PartialName parameters
Parameter components, may be empty.