33 #include <boost/asio/defer.hpp>
34 #include <boost/lexical_cast.hpp>
36 #include <ndn-cxx/lp/tags.hpp>
37 #include <ndn-cxx/mgmt/nfd/rib-entry.hpp>
38 #include <ndn-cxx/mgmt/nfd/status-dataset.hpp>
39 #include <ndn-cxx/security/certificate-fetcher-direct-fetch.hpp>
52 ndn::nfd::Controller& nfdController, Dispatcher& dispatcher)
55 , m_keyChain(keyChain)
56 , m_nfdController(nfdController)
57 , m_dispatcher(dispatcher)
59 , m_localhostValidator(face)
60 , m_localhopValidator(make_unique<
ndn::security::CertificateFetcherDirectFetch>(face))
61 , m_paValidator(make_unique<
ndn::security::CertificateFetcherDirectFetch>(face))
62 , m_isLocalhopEnabled(false)
64 registerCommandHandler<ndn::nfd::RibRegisterCommand>([
this] (
auto&&,
auto&&... args) {
65 registerEntry(std::forward<decltype(args)>(args)...);
67 registerCommandHandler<ndn::nfd::RibUnregisterCommand>([
this] (
auto&&,
auto&&... args) {
68 unregisterEntry(std::forward<decltype(args)>(args)...);
70 registerCommandHandler<ndn::nfd::RibAnnounceCommand>([
this] (
auto&&,
auto&&... args) {
71 announceEntry(std::forward<decltype(args)>(args)...);
74 listEntries(std::forward<decltype(args)>(args)...);
81 m_localhostValidator.load(section, filename);
87 m_localhopValidator.load(section, filename);
88 m_isLocalhopEnabled =
true;
94 m_isLocalhopEnabled =
false;
100 m_paValidator.load(section, filename);
108 if (m_isLocalhopEnabled) {
112 NFD_LOG_INFO(
"Start monitoring face create/destroy events");
113 m_faceMonitor.onNotification.connect([
this] (
const auto& notif) { onNotification(notif); });
114 m_faceMonitor.start();
122 m_nfdController.start<ndn::nfd::FaceUpdateCommand>(
123 ControlParameters().setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
true),
124 [] (
const ControlParameters&) {
127 [] (
const ControlResponse& res) {
128 NDN_THROW(
Error(
"Could not enable local fields (error " +
129 std::to_string(res.getCode()) +
": " + res.getText() +
")"));
134 RibManager::addRoute(
const Name& name,
Route route,
const time::steady_clock::time_point& now,
135 const std::function<
void(RibUpdateResult)>& done)
140 done(RibUpdateResult::EXPIRED);
146 " origin=" << route.
origin <<
" cost=" << route.
cost);
149 auto delay = *route.
expires - now;
153 NFD_LOG_TRACE(
"Route will expire in " << time::duration_cast<time::milliseconds>(delay));
160 RibManager::beginRibUpdate(
const rib::RibUpdate& update,
161 const std::function<
void(RibUpdateResult)>& done)
167 done(RibUpdateResult::OK);
170 [=] (uint32_t code,
const std::string& error) {
171 NFD_LOG_DEBUG(update <<
" -> error " << code <<
": " << error);
174 scheduleActiveFaceFetch(1_s);
177 done(RibUpdateResult::ERROR);
183 RibManager::registerTopPrefix(
const Name& topPrefix)
186 m_nfdController.start<ndn::nfd::FibAddNextHopCommand>(
187 ControlParameters().setName(Name(topPrefix).append(
MGMT_MODULE_NAME)).setFaceId(0),
188 [=] (
const ControlParameters& res) {
189 NFD_LOG_DEBUG(
"Successfully registered " << topPrefix <<
" with the forwarder");
193 route.
faceId = res.getFaceId();
194 route.origin = ndn::nfd::ROUTE_ORIGIN_APP;
195 route.flags = ndn::nfd::ROUTE_FLAG_CHILD_INHERIT;
197 m_rib.
insert(topPrefix, route);
199 [=] (
const ControlResponse& res) {
200 NDN_THROW(Error(
"Could not add FIB entry " + topPrefix.toUri() +
" (error " +
201 std::to_string(res.getCode()) +
": " + res.getText() +
")"));
205 m_dispatcher.addTopPrefix(topPrefix,
false);
211 auto incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
215 BOOST_ASSERT(incomingFaceIdTag !=
nullptr);
216 return incomingFaceIdTag->get();
220 RibManager::registerEntry(
const Interest& interest, ControlParameters parameters,
221 const CommandContinuation& done)
224 done(ControlResponse(414,
"Route prefix cannot exceed " + std::to_string(
Fib::getMaxDepth()) +
229 if (parameters.getFaceId() == 0) {
234 done(ControlResponse(200,
"OK").setBody(parameters.wireEncode()));
237 route.faceId = parameters.getFaceId();
238 route.origin = parameters.getOrigin();
239 route.cost = parameters.getCost();
240 route.flags = parameters.getFlags();
242 auto now = time::steady_clock::now();
243 if (parameters.hasExpirationPeriod() &&
244 parameters.getExpirationPeriod() != time::milliseconds::max()) {
245 route.expires = now + parameters.getExpirationPeriod();
248 addRoute(parameters.getName(), std::move(route), now);
252 RibManager::unregisterEntry(
const Interest& interest, ControlParameters parameters,
253 const CommandContinuation& done)
255 if (parameters.getFaceId() == 0) {
260 done(ControlResponse(200,
"OK").setBody(parameters.wireEncode()));
263 route.faceId = parameters.getFaceId();
264 route.origin = parameters.getOrigin();
266 NFD_LOG_INFO(
"Removing route " << parameters.getName() <<
267 " nexthop=" << route.faceId <<
" origin=" << route.origin);
273 RibManager::announceEntry(
const Interest& interest,
const ndn::nfd::RibAnnounceParameters& parameters,
274 const CommandContinuation& done)
276 const auto& announcement = parameters.getPrefixAnnouncement();
277 const auto& name = announcement.getAnnouncedName();
279 done(ControlResponse(414,
"Route prefix cannot exceed " + std::to_string(
Fib::getMaxDepth()) +
286 NDN_LOG_TRACE(
"Validating announcement " << announcement);
287 BOOST_ASSERT(announcement.getData());
288 m_paValidator.validate(*announcement.getData(),
290 auto now = time::steady_clock::now();
291 Route route(announcement, inFaceId);
294 ControlParameters responseParams;
296 .setName(announcement.getAnnouncedName())
297 .setFaceId(route.faceId)
298 .setOrigin(route.origin)
300 .setFlags(route.flags)
301 .setExpirationPeriod(time::duration_cast<time::milliseconds>(route.annExpires - now));
304 done(ControlResponse(200,
"OK").setBody(responseParams.wireEncode()));
305 addRoute(announcement.getAnnouncedName(), std::move(route), now);
307 [=] (
const Data&,
const ndn::security::ValidationError& err) {
308 NDN_LOG_DEBUG(
"announce " << name <<
" -> " << err);
309 done(ControlResponse(403,
"Prefix announcement rejected: " +
310 boost::lexical_cast<std::string>(err.getCode())));
315 RibManager::listEntries(ndn::mgmt::StatusDatasetContext& context)
const
317 auto now = time::steady_clock::now();
318 for (
const auto& kv : m_rib) {
319 const rib::RibEntry& entry = *kv.second;
320 ndn::nfd::RibEntry item;
321 item.setName(entry.getName());
322 for (
const Route& route : entry.getRoutes()) {
324 r.setFaceId(route.faceId);
325 r.setOrigin(route.origin);
326 r.setCost(route.cost);
327 r.setFlags(route.flags);
329 r.setExpirationPeriod(time::duration_cast<time::milliseconds>(*route.expires - now));
333 context.append(item.wireEncode());
338 ndn::mgmt::Authorization
339 RibManager::makeAuthorization(
const std::string&)
341 return [
this] (
const Name& prefix,
const Interest& interest,
342 const ndn::mgmt::ControlParametersBase* params,
343 const ndn::mgmt::AcceptContinuation& accept,
344 const ndn::mgmt::RejectContinuation& reject) {
345 BOOST_ASSERT(params !=
nullptr);
346 BOOST_ASSERT(
typeid(*params) ==
typeid(ndn::nfd::ControlParameters) ||
347 typeid(*params) ==
typeid(ndn::nfd::RibAnnounceParameters));
351 validator.validate(interest,
352 [&interest, accept] (
auto&&...) { accept(
extractSigner(interest)); },
353 [reject] (
auto&&...) { reject(ndn::mgmt::RejectReply::STATUS403); });
364 return os <<
"ERROR";
366 return os <<
"VALIDATION_FAILURE";
368 return os <<
"EXPIRED";
370 return os <<
"NOT_FOUND";
372 NDN_THROW(std::invalid_argument(
"Unknown SlAnnounceResult"));
376 RibManager::getSlAnnounceResultFromRibUpdateResult(RibUpdateResult r)
379 case RibUpdateResult::OK:
381 case RibUpdateResult::ERROR:
383 case RibUpdateResult::EXPIRED:
393 BOOST_ASSERT(pa.getData());
395 m_paValidator.validate(*pa.getData(),
397 auto now = time::steady_clock::now();
398 Route route(pa, faceId);
399 route.expires = std::min(route.annExpires, now + maxLifetime);
400 addRoute(pa.getAnnouncedName(), std::move(route), now, [=] (RibUpdateResult ribRes) {
401 auto res = getSlAnnounceResultFromRibUpdateResult(ribRes);
402 NFD_LOG_INFO(
"slAnnounce " << pa.getAnnouncedName() <<
" " << faceId <<
" -> " << res);
406 [=] (
const Data&,
const ndn::security::ValidationError& err) {
407 NFD_LOG_INFO(
"slAnnounce " << pa.getAnnouncedName() <<
" " << faceId <<
408 " -> validation error: " << err);
409 cb(SlAnnounceResult::VALIDATION_FAILURE);
414 RibManager::slRenew(
const Name& name, uint64_t faceId, time::milliseconds maxLifetime,
418 routeQuery.
faceId = faceId;
419 routeQuery.
origin = ndn::nfd::ROUTE_ORIGIN_PREFIXANN;
420 Route* oldRoute = m_rib.findLongestPrefix(name, routeQuery);
423 NFD_LOG_DEBUG(
"slRenew " << name <<
" " << faceId <<
" -> not found");
424 return cb(SlAnnounceResult::NOT_FOUND);
427 auto now = time::steady_clock::now();
428 Name routeName = oldRoute->
announcement->getAnnouncedName();
429 Route route = *oldRoute;
432 addRoute(routeName, std::move(route), now, [=] (RibUpdateResult ribRes) {
433 auto res = getSlAnnounceResultFromRibUpdateResult(ribRes);
434 NFD_LOG_INFO(
"slRenew " << name <<
" " << faceId <<
" -> " << res <<
" " << routeName);
442 shared_ptr<rib::RibEntry> entry;
443 auto exactMatch = m_rib.find(name);
444 if (exactMatch != m_rib.end()) {
445 entry = exactMatch->second;
448 entry = m_rib.findParent(name);
450 if (entry ==
nullptr) {
451 return cb(std::nullopt);
454 auto pa = entry->getPrefixAnnouncement();
455 pa.toData(m_keyChain);
460 RibManager::fetchActiveFaces()
464 m_nfdController.fetch<ndn::nfd::FaceDataset>(
465 [
this] (
auto&&... args) { removeInvalidFaces(std::forward<decltype(args)>(args)...); },
466 [
this] (uint32_t code,
const std::string& reason) {
467 NFD_LOG_WARN(
"Failed to fetch face dataset (error " << code <<
": " << reason <<
")");
473 RibManager::scheduleActiveFaceFetch(time::seconds timeToWait)
475 m_activeFaceFetchEvent =
getScheduler().schedule(timeToWait, [
this] { fetchActiveFaces(); });
479 RibManager::removeInvalidFaces(
const std::vector<ndn::nfd::FaceStatus>& activeFaces)
483 std::set<uint64_t> activeIds;
484 for (
const auto& faceStatus : activeFaces) {
485 activeIds.insert(faceStatus.getFaceId());
488 [
this, active = std::move(activeIds)] { m_rib.beginRemoveFailedFaces(active); });
495 RibManager::onNotification(
const ndn::nfd::FaceEventNotification& notification)
499 if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) {
501 [
this,
id = notification.getFaceId()] { m_rib.beginRemoveFace(id); });
A collection of common functions shared by all NFD managers, such as communicating with the dispatche...
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
static std::string extractSigner(const Interest &interest)
Extracts the name from the KeyLocator of a ControlCommand request.
std::function< void(SlAnnounceResult res)> SlAnnounceCallback
void registerWithNfd()
Start accepting commands and dataset requests.
void disableLocalhop()
Disallow accepting commands on /localhop/nfd/rib prefix.
RibManager(rib::Rib &rib, ndn::Face &face, ndn::KeyChain &keyChain, ndn::nfd::Controller &nfdController, Dispatcher &dispatcher)
static const Name LOCALHOP_TOP_PREFIX
void applyLocalhostConfig(const ConfigSection §ion, const std::string &filename)
Apply localhost_security configuration.
void enableLocalhop(const ConfigSection §ion, const std::string &filename)
Apply localhop_security configuration and allow accepting commands on /localhop/nfd/rib prefix.
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.
std::function< void(std::optional< ndn::PrefixAnnouncement >)> SlFindAnnCallback
@ VALIDATION_FAILURE
the announcement cannot be verified against the trust schema
@ EXPIRED
the announcement has expired
@ NOT_FOUND
route does not exist (slRenew only)
@ OK
RIB and FIB have been updated.
void enableLocalFields()
Enable NDNLP IncomingFaceId field in order to support self-registration commands.
void applyPaConfig(const ConfigSection §ion, const std::string &filename)
Apply prefix_announcement_validation configuration.
static constexpr size_t getMaxDepth()
Maximum number of components in a FIB entry prefix.
Represents the Routing Information Base.
void insert(const Name &prefix, const Route &route)
void onRouteExpiration(const Name &prefix, const Route &route)
void beginApplyUpdate(const RibUpdate &update, const UpdateSuccessCallback &onSuccess, const UpdateFailureCallback &onFailure)
Passes the provided RibUpdateBatch to FibUpdater to calculate and send FibUpdates.
Represents a route for a name prefix.
ndn::nfd::RouteOrigin origin
time::steady_clock::time_point annExpires
Expiration time of the prefix announcement.
std::optional< time::steady_clock::time_point > expires
void setExpirationEvent(ndn::scheduler::EventId &&eid)
std::optional< ndn::PrefixAnnouncement > announcement
The prefix announcement that caused the creation of this route.
#define NFD_LOG_INIT(name)
ndn::Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
boost::property_tree::ptree ConfigSection
A configuration file section.
static uint64_t getIncomingFaceId(const Interest &request)
const std::string MGMT_MODULE_NAME
constexpr time::seconds ACTIVE_FACE_FETCH_INTERVAL
std::ostream & operator<<(std::ostream &os, const Network &network)
const Name LOCALHOST_TOP_PREFIX
boost::asio::io_context & getGlobalIoService()
Returns the global io_context instance for the calling thread.