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/asio/post.hpp>
38 #include <boost/range/adaptor/reversed.hpp>
52 NDN_THROW(std::invalid_argument(
"SelfLearningStrategy does not accept parameters"));
55 NDN_THROW(std::invalid_argument(
"SelfLearningStrategy does not support version " +
56 std::to_string(*parsed.
version)));
64 static const auto strategyName = Name(
"/localhost/nfd/strategy/self-learning").appendVersion(1);
70 const shared_ptr<pit::Entry>& pitEntry)
75 bool isNonDiscovery = interest.getTag<lp::NonDiscoveryTag>() !=
nullptr;
76 auto inRecordInfo = pitEntry->findInRecord(ingress.
face)->insertStrategyInfo<
InRecordInfo>().first;
79 if (nexthops.empty()) {
81 lp::NackHeader nackHeader;
82 nackHeader.setReason(lp::NackReason::NO_ROUTE);
87 multicastInterest(interest, ingress.
face, pitEntry, nexthops);
91 inRecordInfo->isNonDiscoveryInterest =
false;
92 if (nexthops.empty()) {
93 broadcastInterest(interest, ingress.
face, pitEntry);
96 interest.setTag(make_shared<lp::NonDiscoveryTag>(lp::EmptyValue{}));
97 multicastInterest(interest, ingress.
face, pitEntry, nexthops);
104 const shared_ptr<pit::Entry>& pitEntry)
106 auto outRecord = pitEntry->findOutRecord(ingress.
face);
107 if (outRecord == pitEntry->out_end()) {
114 if (!needPrefixAnn(pitEntry)) {
118 asyncProcessData(pitEntry, ingress.
face, data);
122 auto paTag = data.getTag<lp::PrefixAnnouncementTag>();
123 if (paTag !=
nullptr) {
124 addRoute(pitEntry, ingress.
face, data, *paTag->get().getPrefixAnn());
134 const shared_ptr<pit::Entry>& pitEntry)
138 if (nack.getReason() == lp::NackReason::NO_ROUTE) {
141 this->
sendNacks(nack.getHeader(), pitEntry);
142 renewRoute(nack.getInterest().getName(), ingress.
face.
getId(), 0_ms);
147 SelfLearningStrategy::broadcastInterest(
const Interest& interest,
const Face& inFace,
148 const shared_ptr<pit::Entry>& pitEntry)
150 for (
auto& outFace : this->
getFaceTable() | boost::adaptors::reversed) {
151 if ((outFace.getId() == inFace.
getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
153 outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
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();
177 auto outRecord = this->
sendInterest(interest, outFace, pitEntry);
178 if (outRecord !=
nullptr) {
179 outRecord->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest =
true;
185 SelfLearningStrategy::asyncProcessData(
const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace,
const Data& data)
193 [
this, pitEntryWeak = weak_ptr<pit::Entry>{pitEntry}, inFaceId = inFace.getId(), data] {
195 [
this, pitEntryWeak, inFaceId, data] (std::optional<ndn::PrefixAnnouncement> paOpt) {
197 boost::asio::post(getMainIoService(),
198 [this, pitEntryWeak, inFaceId, data, pa = std::move(*paOpt)] {
199 auto pitEntry = pitEntryWeak.lock();
200 auto inFace = this->getFace(inFaceId);
201 if (pitEntry && inFace) {
202 NFD_LOG_DEBUG(
"Found PrefixAnnouncement=" << pa.getAnnouncedName());
203 data.setTag(make_shared<lp::PrefixAnnouncementTag>(lp::PrefixAnnouncementHeader(pa)));
204 this->sendDataToAll(data, pitEntry, *inFace);
205 this->setExpiryTimer(pitEntry, 0_ms);
208 NFD_LOG_DEBUG(
"PIT entry or face no longer exists");
217 SelfLearningStrategy::needPrefixAnn(
const shared_ptr<pit::Entry>& pitEntry)
219 bool hasDiscoveryInterest =
false;
220 bool directToConsumer =
true;
222 auto now = time::steady_clock::now();
223 for (
const auto& inRecord : pitEntry->getInRecords()) {
224 if (inRecord.getExpiry() > now) {
225 InRecordInfo* inRecordInfo = inRecord.getStrategyInfo<InRecordInfo>();
226 if (inRecordInfo && !inRecordInfo->isNonDiscoveryInterest) {
227 hasDiscoveryInterest =
true;
229 if (inRecord.getFace().getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
230 directToConsumer =
false;
234 return hasDiscoveryInterest && !directToConsumer;
238 SelfLearningStrategy::addRoute(
const shared_ptr<pit::Entry>& pitEntry,
const Face& inFace,
239 const Data& data,
const ndn::PrefixAnnouncement& pa)
242 [pitEntryWeak = weak_ptr<pit::Entry>{pitEntry}, inFaceId = inFace.getId(), data, pa] {
245 NFD_LOG_DEBUG(
"Add route via PrefixAnnouncement with result=" << res);
251 SelfLearningStrategy::renewRoute(
const Name& name,
FaceId inFaceId, time::milliseconds maxLifetime)
255 [name, inFaceId, 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 noexcept
bool hasNextHops() const noexcept
Returns whether this Entry has any NextHop records.
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
A collection of nexthops in a FIB entry.
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.
boost::asio::io_context & getRibIoService()
#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.