rib: provide self-learning helpers
refs #4683
Change-Id: Ib1e586a505d07a5e1f7a4b6d78306ea08b4dcda8
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index a1707ef..009b9ad 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -46,9 +46,11 @@
static const Name LOCALHOP_TOP_PREFIX = "/localhop/nfd";
static const time::seconds ACTIVE_FACE_FETCH_INTERVAL = time::seconds(300);
-RibManager::RibManager(Rib& rib, ndn::Face& face, ndn::nfd::Controller& nfdController, Dispatcher& dispatcher)
+RibManager::RibManager(Rib& rib, ndn::Face& face, ndn::KeyChain& keyChain,
+ ndn::nfd::Controller& nfdController, Dispatcher& dispatcher)
: ManagerBase(dispatcher, MGMT_MODULE_NAME)
, m_rib(rib)
+ , m_keyChain(keyChain)
, m_nfdController(nfdController)
, m_dispatcher(dispatcher)
, m_faceMonitor(face)
@@ -118,18 +120,15 @@
const std::function<void(RibUpdateResult)>& done)
{
if (expires) {
- if (*expires <= 0_ns) {
- done(RibUpdateResult::EXPIRED);
- return;
- }
route.expires = time::steady_clock::now() + *expires;
}
else if (route.expires) {
expires = *route.expires - time::steady_clock::now();
- if (*expires <= 0_ns) {
- done(RibUpdateResult::EXPIRED);
- return;
- }
+ }
+
+ if (expires && *expires <= 0_s) {
+ m_rib.onRouteExpiration(name, route);
+ return done(RibUpdateResult::EXPIRED);
}
NFD_LOG_INFO("Adding route " << name << " nexthop=" << route.faceId <<
@@ -318,6 +317,116 @@
};
}
+std::ostream&
+operator<<(std::ostream& os, RibManager::SlAnnounceResult res)
+{
+ switch (res) {
+ case RibManager::SlAnnounceResult::OK:
+ return os << "OK";
+ case RibManager::SlAnnounceResult::ERROR:
+ return os << "ERROR";
+ case RibManager::SlAnnounceResult::VALIDATION_FAILURE:
+ return os << "VALIDATION_FAILURE";
+ case RibManager::SlAnnounceResult::EXPIRED:
+ return os << "EXPIRED";
+ case RibManager::SlAnnounceResult::NOT_FOUND:
+ return os << "NOT_FOUND";
+ }
+ BOOST_ASSERT_MSG(false, "bad SlAnnounceResult");
+ return os;
+}
+
+RibManager::SlAnnounceResult
+RibManager::getSlAnnounceResultFromRibUpdateResult(RibUpdateResult r)
+{
+ switch (r) {
+ case RibUpdateResult::OK:
+ return SlAnnounceResult::OK;
+ case RibUpdateResult::ERROR:
+ return SlAnnounceResult::ERROR;
+ case RibUpdateResult::EXPIRED:
+ return SlAnnounceResult::EXPIRED;
+ default:
+ BOOST_ASSERT(false);
+ return SlAnnounceResult::ERROR;
+ }
+}
+
+void
+RibManager::slAnnounce(const ndn::PrefixAnnouncement& pa, uint64_t faceId,
+ time::milliseconds maxLifetime, const SlAnnounceCallback& cb)
+{
+ BOOST_ASSERT(pa.getData());
+
+ if (!m_isLocalhopEnabled) {
+ NFD_LOG_INFO("slAnnounce " << pa.getAnnouncedName() << ' ' << faceId <<
+ ": localhop_security unconfigured");
+ cb(SlAnnounceResult::VALIDATION_FAILURE);
+ return;
+ }
+
+ m_localhopValidator.validate(*pa.getData(),
+ [=] (const Data&) {
+ Route route(pa, faceId);
+ route.expires = std::min(route.annExpires, time::steady_clock::now() + maxLifetime);
+ beginAddRoute(pa.getAnnouncedName(), route, nullopt,
+ [=] (RibUpdateResult ribRes) {
+ auto res = getSlAnnounceResultFromRibUpdateResult(ribRes);
+ NFD_LOG_INFO("slAnnounce " << pa.getAnnouncedName() << ' ' << faceId << ": " << res);
+ cb(res);
+ });
+ },
+ [=] (const Data&, ndn::security::v2::ValidationError err) {
+ NFD_LOG_INFO("slAnnounce " << pa.getAnnouncedName() << ' ' << faceId <<
+ " validation error: " << err);
+ cb(SlAnnounceResult::VALIDATION_FAILURE);
+ }
+ );
+}
+
+void
+RibManager::slRenew(const Name& name, uint64_t faceId, time::milliseconds maxLifetime,
+ const SlAnnounceCallback& cb)
+{
+ Route routeQuery;
+ routeQuery.faceId = faceId;
+ routeQuery.origin = ndn::nfd::ROUTE_ORIGIN_PREFIXANN;
+ Route* oldRoute = m_rib.find(name, routeQuery);
+ if (oldRoute == nullptr || !oldRoute->announcement) {
+ NFD_LOG_DEBUG("slRenew " << name << ' ' << faceId << ": not found");
+ return cb(SlAnnounceResult::NOT_FOUND);
+ }
+
+ Route route = *oldRoute;
+ route.expires = std::min(route.annExpires, time::steady_clock::now() + maxLifetime);
+ beginAddRoute(name, route, nullopt,
+ [=] (RibUpdateResult ribRes) {
+ auto res = getSlAnnounceResultFromRibUpdateResult(ribRes);
+ NFD_LOG_INFO("slRenew " << name << ' ' << faceId << ": " << res);
+ cb(res);
+ });
+}
+
+void
+RibManager::slFindAnn(const Name& name, const SlFindAnnCallback& cb) const
+{
+ shared_ptr<RibEntry> entry;
+ auto exactMatch = m_rib.find(name);
+ if (exactMatch != m_rib.end()) {
+ entry = exactMatch->second;
+ }
+ else {
+ entry = m_rib.findParent(name);
+ }
+ if (entry == nullptr) {
+ return cb(nullopt);
+ }
+
+ auto pa = entry->getPrefixAnnouncement();
+ pa.toData(m_keyChain);
+ cb(pa);
+}
+
void
RibManager::fetchActiveFaces()
{
diff --git a/rib/rib-manager.hpp b/rib/rib-manager.hpp
index 169c9ec..0ae96a4 100644
--- a/rib/rib-manager.hpp
+++ b/rib/rib-manager.hpp
@@ -54,7 +54,8 @@
using std::runtime_error::runtime_error;
};
- RibManager(Rib& rib, ndn::Face& face, ndn::nfd::Controller& nfdController, Dispatcher& dispatcher);
+ RibManager(Rib& rib, ndn::Face& face, ndn::KeyChain& keyChain,
+ ndn::nfd::Controller& nfdController, Dispatcher& dispatcher);
/**
* @brief Apply localhost_security configuration.
@@ -87,6 +88,75 @@
void
enableLocalFields();
+public: // self-learning support
+ enum class SlAnnounceResult {
+ OK, ///< RIB and FIB have been updated
+ ERROR, ///< unspecified error
+ VALIDATION_FAILURE, ///< the announcement cannot be verified against the trust schema
+ EXPIRED, ///< the announcement has expired
+ NOT_FOUND, ///< route does not exist (slRenew only)
+ };
+
+ using SlAnnounceCallback = std::function<void(SlAnnounceResult res)>;
+ using SlFindAnnCallback = std::function<void(optional<ndn::PrefixAnnouncement>)>;
+
+ /** \brief Insert a route by prefix announcement from self-learning strategy.
+ * \param pa A prefix announcement. It must contain the Data.
+ * \param faceId Face on which the announcement arrives.
+ * \param maxLifetime Maximum route lifetime as imposed by self-learning strategy.
+ * \param cb Callback to receive the operation result.
+ *
+ * If \p pa passes validation and is unexpired, inserts or replaces a route for the announced
+ * name and faceId whose lifetime is set to the earlier of now+maxLifetime or prefix
+ * announcement expiration time, updates FIB, and invokes \p cb with SlAnnounceResult::OK.
+ * In case \p pa expires when validation completes, invokes \p cb with SlAnnounceResult::EXPIRED.
+ * If \p pa cannot be verified by the trust schema given in rib.localhop_security config key,
+ * or the relevant config has not been loaded via \c enableLocalHop, invokes \p cb with
+ * SlAnnounceResult::VALIDATION_FAILURE.
+ *
+ * Self-learning strategy invokes this method after receiving a Data carrying a prefix
+ * announcement.
+ */
+ void
+ slAnnounce(const ndn::PrefixAnnouncement& pa, uint64_t faceId, time::milliseconds maxLifetime,
+ const SlAnnounceCallback& cb);
+
+ /** \brief Renew a route created by prefix announcement from self-learning strategy.
+ * \param name Data name, for finding RIB entry by longest-prefix-match.
+ * \param faceId Nexthop face.
+ * \param maxLifetime Maximum route lifetime as imposed by self-learning strategy.
+ * \param cb Callback to receive the operation result.
+ *
+ * If the specified route exists, prolongs its lifetime to the earlier of now+maxLifetime or
+ * prefix announcement expiration time, and invokes \p cb with SlAnnounceResult::OK.
+ * If the prefix announcement has expired, invokes \p cb with SlAnnounceResult::EXPIRED.
+ * If the route is not found, invokes \p cb with SlAnnounceResult::NOT_FOUND.
+ *
+ * Self-learning strategy invokes this method after an Interest forwarded via a learned route
+ * is satisfied.
+ *
+ * \bug In current implementation, if an slAnnounce operation is in progress to create a Route
+ * or replace a prefix announcement, slRenew could fail because Route does not exist in
+ * existing RIB, or overwrite the new prefix announcement with an old one.
+ */
+ void
+ slRenew(const Name& name, uint64_t faceId, time::milliseconds maxLifetime,
+ const SlAnnounceCallback& cb);
+
+ /** \brief Retrieve an outgoing prefix announcement for self-learning strategy.
+ * \param name Data name.
+ * \param cb Callback to receive a prefix announcement that announces a prefix of \p name, or
+ * nullopt if no RIB entry is found by longest-prefix-match of \p name.
+ *
+ * Self-learning strategy invokes this method before sending a Data in reply to a discovery
+ * Interest, so as to attach a prefix announcement onto that Data.
+ *
+ * \bug In current implementation, if an slAnnounce operation is in progress, slFindAnn does not
+ * wait for that operation to complete and its result reflects the prior RIB state.
+ */
+ void
+ slFindAnn(const Name& name, const SlFindAnnCallback& cb) const;
+
private: // RIB and FibUpdater actions
enum class RibUpdateResult
{
@@ -95,6 +165,9 @@
EXPIRED,
};
+ static SlAnnounceResult
+ getSlAnnounceResultFromRibUpdateResult(RibUpdateResult r);
+
/** \brief Start adding a route to RIB and FIB.
* \param name route name
* \param route route parameters; may contain absolute expiration time
@@ -179,6 +252,7 @@
private:
Rib& m_rib;
+ ndn::KeyChain& m_keyChain;
ndn::nfd::Controller& m_nfdController;
Dispatcher& m_dispatcher;
@@ -187,6 +261,8 @@
ndn::ValidatorConfig m_localhopValidator;
bool m_isLocalhopEnabled;
+ static const std::map<RibManager::RibUpdateResult, RibManager::SlAnnounceResult> RIB_RESULT_TO_SL_ANNOUNCE_RESULT;
+
private:
scheduler::ScopedEventId m_activeFaceFetchEvent;
@@ -196,6 +272,9 @@
FaceIdSet m_registeredFaces;
};
+std::ostream&
+operator<<(std::ostream& os, RibManager::SlAnnounceResult res);
+
} // namespace rib
} // namespace nfd
diff --git a/rib/service.cpp b/rib/service.cpp
index 067806f..c25e977 100644
--- a/rib/service.cpp
+++ b/rib/service.cpp
@@ -108,7 +108,7 @@
, m_nfdController(m_face, m_keyChain)
, m_fibUpdater(m_rib, m_nfdController)
, m_dispatcher(m_face, m_keyChain)
- , m_ribManager(m_rib, m_face, m_nfdController, m_dispatcher)
+ , m_ribManager(m_rib, m_face, m_keyChain, m_nfdController, m_dispatcher)
{
if (s_instance != nullptr) {
BOOST_THROW_EXCEPTION(std::logic_error("RIB service cannot be instantiated more than once"));
diff --git a/rib/service.hpp b/rib/service.hpp
index a349787..135df58 100644
--- a/rib/service.hpp
+++ b/rib/service.hpp
@@ -85,6 +85,12 @@
static Service&
get();
+ RibManager&
+ getRibManager()
+ {
+ return m_ribManager;
+ }
+
private:
template<typename ConfigParseFunc>
Service(ndn::KeyChain& keyChain, shared_ptr<ndn::Transport> localNfdTransport,