NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
rib-manager.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2018, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "rib-manager.hpp"
30 
31 #include "core/fib-max-depth.hpp"
32 #include "core/logger.hpp"
33 #include "core/scheduler.hpp"
34 
35 #include <ndn-cxx/lp/tags.hpp>
36 #include <ndn-cxx/mgmt/nfd/control-command.hpp>
37 #include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
38 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
39 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
40 #include <ndn-cxx/mgmt/nfd/rib-entry.hpp>
41 
42 namespace nfd {
43 namespace rib {
44 
45 NFD_LOG_INIT("RibManager");
46 
47 const Name RibManager::LOCAL_HOST_TOP_PREFIX = "/localhost/nfd";
48 const Name RibManager::LOCAL_HOP_TOP_PREFIX = "/localhop/nfd";
49 const std::string RibManager::MGMT_MODULE_NAME = "rib";
50 const Name RibManager::FACES_LIST_DATASET_PREFIX = "/localhost/nfd/faces/list";
51 const time::seconds RibManager::ACTIVE_FACE_FETCH_INTERVAL = time::seconds(300);
52 const Name RibManager::READVERTISE_NLSR_PREFIX = "/localhost/nlsr";
53 
55  ndn::Face& face,
56  ndn::KeyChain& keyChain)
57  : ManagerBase(dispatcher, MGMT_MODULE_NAME)
58  , m_face(face)
59  , m_keyChain(keyChain)
60  , m_nfdController(m_face, m_keyChain)
61  , m_faceMonitor(m_face)
62  , m_localhostValidator(m_face)
63  , m_localhopValidator(m_face)
64  , m_isLocalhopEnabled(false)
65  , m_prefixPropagator(m_nfdController, m_keyChain, m_rib)
66  , m_fibUpdater(m_rib, m_nfdController)
67  , m_addTopPrefix([&dispatcher] (const Name& topPrefix) {
68  dispatcher.addTopPrefix(topPrefix, false);
69  })
70 {
71  registerCommandHandler<ndn::nfd::RibRegisterCommand>("register",
72  bind(&RibManager::registerEntry, this, _2, _3, _4, _5));
73  registerCommandHandler<ndn::nfd::RibUnregisterCommand>("unregister",
74  bind(&RibManager::unregisterEntry, this, _2, _3, _4, _5));
75 
76  registerStatusDatasetHandler("list", bind(&RibManager::listEntries, this, _1, _2, _3));
77 }
78 
79 RibManager::~RibManager() = default;
80 
81 void
83 {
84  registerTopPrefix(LOCAL_HOST_TOP_PREFIX);
85 
86  if (m_isLocalhopEnabled) {
87  registerTopPrefix(LOCAL_HOP_TOP_PREFIX);
88  }
89 
90  NFD_LOG_INFO("Start monitoring face create/destroy events");
91  m_faceMonitor.onNotification.connect(bind(&RibManager::onNotification, this, _1));
92  m_faceMonitor.start();
93 
94  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
95 }
96 
97 void
99 {
100  m_nfdController.start<ndn::nfd::FaceUpdateCommand>(
102  .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true),
103  bind(&RibManager::onEnableLocalFieldsSuccess, this),
104  bind(&RibManager::onEnableLocalFieldsError, this, _1));
105 }
106 
107 void
109 {
110  configFile.addSectionHandler("rib",
111  bind(&RibManager::onConfig, this, _1, _2, _3));
112 }
113 
114 void
116 {
117  NFD_LOG_DEBUG("RIB update succeeded for " << update);
118 }
119 
120 void
121 RibManager::onRibUpdateFailure(const RibUpdate& update, uint32_t code, const std::string& error)
122 {
123  NFD_LOG_DEBUG("RIB update failed for " << update << " (code: " << code
124  << ", error: " << error << ")");
125 
126  // Since the FIB rejected the update, clean up invalid routes
127  scheduleActiveFaceFetch(time::seconds(1));
128 }
129 
130 void
131 RibManager::onConfig(const ConfigSection& configSection,
132  bool isDryRun,
133  const std::string& filename)
134 {
135  bool isAutoPrefixPropagatorEnabled = false;
136  bool wantReadvertiseToNlsr = false;
137 
138  for (const auto& item : configSection) {
139  if (item.first == "localhost_security") {
140  m_localhostValidator.load(item.second, filename);
141  }
142  else if (item.first == "localhop_security") {
143  m_localhopValidator.load(item.second, filename);
144  m_isLocalhopEnabled = true;
145  }
146  else if (item.first == "auto_prefix_propagate") {
147  m_prefixPropagator.loadConfig(item.second);
148  isAutoPrefixPropagatorEnabled = true;
149 
150  // Avoid other actions when isDryRun == true
151  if (isDryRun) {
152  continue;
153  }
154 
155  m_prefixPropagator.enable();
156  }
157  else if (item.first == "readvertise_nlsr") {
158  wantReadvertiseToNlsr = ConfigFile::parseYesNo(item, "rib.readvertise_nlsr");
159  }
160  else {
161  BOOST_THROW_EXCEPTION(Error("Unrecognized rib property: " + item.first));
162  }
163  }
164 
165  if (!isAutoPrefixPropagatorEnabled) {
166  m_prefixPropagator.disable();
167  }
168 
169  if (wantReadvertiseToNlsr && m_readvertiseNlsr == nullptr) {
170  NFD_LOG_DEBUG("Enabling readvertise-to-nlsr.");
171  m_readvertiseNlsr.reset(new Readvertise(
172  m_rib,
173  make_unique<ClientToNlsrReadvertisePolicy>(),
174  make_unique<NfdRibReadvertiseDestination>(m_nfdController, READVERTISE_NLSR_PREFIX, m_rib)));
175  }
176  else if (!wantReadvertiseToNlsr && m_readvertiseNlsr != nullptr) {
177  NFD_LOG_DEBUG("Disabling readvertise-to-nlsr.");
178  m_readvertiseNlsr.reset();
179  }
180 }
181 
182 void
183 RibManager::registerTopPrefix(const Name& topPrefix)
184 {
185  // register entry to the FIB
186  m_nfdController.start<ndn::nfd::FibAddNextHopCommand>(
188  .setName(Name(topPrefix).append(MGMT_MODULE_NAME))
189  .setFaceId(0),
190  bind(&RibManager::onCommandPrefixAddNextHopSuccess, this, cref(topPrefix), _1),
191  bind(&RibManager::onCommandPrefixAddNextHopError, this, cref(topPrefix), _1));
192 
193  // add top prefix to the dispatcher
194  m_addTopPrefix(topPrefix);
195 }
196 
197 void
198 RibManager::registerEntry(const Name& topPrefix, const Interest& interest,
199  ControlParameters parameters,
200  const ndn::mgmt::CommandContinuation& done)
201 {
202  if (parameters.getName().size() > FIB_MAX_DEPTH) {
203  done(ControlResponse(414, "Route prefix cannot exceed " + ndn::to_string(FIB_MAX_DEPTH) +
204  " components"));
205  return;
206  }
207 
208  setFaceForSelfRegistration(interest, parameters);
209 
210  // Respond since command is valid and authorized
211  done(ControlResponse(200, "Success").setBody(parameters.wireEncode()));
212 
213  Route route;
214  route.faceId = parameters.getFaceId();
215  route.origin = parameters.getOrigin();
216  route.cost = parameters.getCost();
217  route.flags = parameters.getFlags();
218 
219  if (parameters.hasExpirationPeriod() &&
220  parameters.getExpirationPeriod() != time::milliseconds::max()) {
221  route.expires = time::steady_clock::now() + parameters.getExpirationPeriod();
222 
223  // Schedule a new event, the old one will be cancelled during rib insertion.
224  scheduler::EventId eventId = scheduler::schedule(parameters.getExpirationPeriod(),
225  bind(&Rib::onRouteExpiration, &m_rib, parameters.getName(), route));
226 
227  NFD_LOG_TRACE("Scheduled unregistration at: " << *route.expires <<
228  " with EventId: " << eventId);
229 
230  // Set the NewEventId of this entry
231  route.setExpirationEvent(eventId);
232  }
233  else {
234  route.expires = nullopt;
235  }
236 
237  NFD_LOG_INFO("Adding route " << parameters.getName() << " nexthop=" << route.faceId
238  << " origin=" << route.origin
239  << " cost=" << route.cost);
240 
241  RibUpdate update;
242  update.setAction(RibUpdate::REGISTER)
243  .setName(parameters.getName())
244  .setRoute(route);
245 
246  m_rib.beginApplyUpdate(update,
247  bind(&RibManager::onRibUpdateSuccess, this, update),
248  bind(&RibManager::onRibUpdateFailure, this, update, _1, _2));
249 
250  m_registeredFaces.insert(route.faceId);
251 }
252 
253 void
254 RibManager::unregisterEntry(const Name& topPrefix, const Interest& interest,
255  ControlParameters parameters,
256  const ndn::mgmt::CommandContinuation& done)
257 {
258  setFaceForSelfRegistration(interest, parameters);
259 
260  // Respond since command is valid and authorized
261  done(ControlResponse(200, "Success").setBody(parameters.wireEncode()));
262 
263  Route route;
264  route.faceId = parameters.getFaceId();
265  route.origin = parameters.getOrigin();
266 
267  NFD_LOG_INFO("Removing route " << parameters.getName() << " nexthop=" << route.faceId
268  << " origin=" << route.origin);
269 
270  RibUpdate update;
271  update.setAction(RibUpdate::UNREGISTER)
272  .setName(parameters.getName())
273  .setRoute(route);
274 
275  m_rib.beginApplyUpdate(update,
276  bind(&RibManager::onRibUpdateSuccess, this, update),
277  bind(&RibManager::onRibUpdateFailure, this, update, _1, _2));
278 }
279 
280 void
281 RibManager::listEntries(const Name& topPrefix, const Interest& interest,
283 {
284  auto now = time::steady_clock::now();
285  for (const auto& kv : m_rib) {
286  const RibEntry& entry = *kv.second;
287  ndn::nfd::RibEntry item;
288  item.setName(entry.getName());
289  for (const Route& route : entry.getRoutes()) {
290  ndn::nfd::Route r;
291  r.setFaceId(route.faceId);
292  r.setOrigin(route.origin);
293  r.setCost(route.cost);
294  r.setFlags(route.flags);
295  if (route.expires) {
296  r.setExpirationPeriod(time::duration_cast<time::milliseconds>(*route.expires - now));
297  }
298  item.addRoute(r);
299  }
300  context.append(item.wireEncode());
301  }
302  context.end();
303 }
304 
305 void
306 RibManager::setFaceForSelfRegistration(const Interest& request, ControlParameters& parameters)
307 {
308  bool isSelfRegistration = (parameters.getFaceId() == 0);
309  if (isSelfRegistration) {
310  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
311  // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
312  // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
313  // and is initialized synchronously with IncomingFaceId field enabled.
314  BOOST_ASSERT(incomingFaceIdTag != nullptr);
315  parameters.setFaceId(*incomingFaceIdTag);
316  }
317 }
318 
320 RibManager::makeAuthorization(const std::string& verb)
321 {
322  return [this] (const Name& prefix, const Interest& interest,
323  const ndn::mgmt::ControlParameters* params,
324  const ndn::mgmt::AcceptContinuation& accept,
325  const ndn::mgmt::RejectContinuation& reject) {
326  BOOST_ASSERT(params != nullptr);
327  BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters));
328  BOOST_ASSERT(prefix == LOCAL_HOST_TOP_PREFIX || prefix == LOCAL_HOP_TOP_PREFIX);
329 
330  ndn::ValidatorConfig& validator = prefix == LOCAL_HOST_TOP_PREFIX ?
331  m_localhostValidator : m_localhopValidator;
332  validator.validate(interest,
333  bind([&interest, this, accept] { extractRequester(interest, accept); }),
334  bind([reject] { reject(ndn::mgmt::RejectReply::STATUS403); }));
335  };
336 }
337 
338 void
339 RibManager::fetchActiveFaces()
340 {
341  NFD_LOG_DEBUG("Fetching active faces");
342 
343  m_nfdController.fetch<ndn::nfd::FaceDataset>(
344  bind(&RibManager::removeInvalidFaces, this, _1),
345  bind(&RibManager::onFetchActiveFacesFailure, this, _1, _2),
347 }
348 
349 void
350 RibManager::onFetchActiveFacesFailure(uint32_t code, const std::string& reason)
351 {
352  NFD_LOG_DEBUG("Face Status Dataset request failure " << code << " " << reason);
353  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
354 }
355 
356 void
357 RibManager::onFaceDestroyedEvent(uint64_t faceId)
358 {
359  m_rib.beginRemoveFace(faceId);
360  m_registeredFaces.erase(faceId);
361 }
362 
363 void
364 RibManager::scheduleActiveFaceFetch(const time::seconds& timeToWait)
365 {
366  m_activeFaceFetchEvent = scheduler::schedule(timeToWait, [this] { this->fetchActiveFaces(); });
367 }
368 
369 void
370 RibManager::removeInvalidFaces(const std::vector<ndn::nfd::FaceStatus>& activeFaces)
371 {
372  NFD_LOG_DEBUG("Checking for invalid face registrations");
373 
374  FaceIdSet activeFaceIds;
375  for (const auto& faceStatus : activeFaces) {
376  activeFaceIds.insert(faceStatus.getFaceId());
377  }
378 
379  // Look for face IDs that were registered but not active to find missed
380  // face destroyed events
381  for (auto faceId : m_registeredFaces) {
382  if (activeFaceIds.count(faceId) == 0) {
383  NFD_LOG_DEBUG("Removing invalid face ID: " << faceId);
384  scheduler::schedule(time::seconds(0), [this, faceId] { this->onFaceDestroyedEvent(faceId); });
385  }
386  }
387 
388  // Reschedule the check for future clean up
389  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
390 }
391 
392 void
393 RibManager::onNotification(const ndn::nfd::FaceEventNotification& notification)
394 {
395  NFD_LOG_TRACE("onNotification: " << notification);
396 
397  if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) {
398  NFD_LOG_DEBUG("Received notification for destroyed faceId: " << notification.getFaceId());
399 
400  scheduler::schedule(time::seconds(0),
401  bind(&RibManager::onFaceDestroyedEvent, this, notification.getFaceId()));
402  }
403 }
404 
405 void
406 RibManager::onCommandPrefixAddNextHopSuccess(const Name& prefix,
407  const ndn::nfd::ControlParameters& result)
408 {
409  NFD_LOG_DEBUG("Successfully registered " + prefix.toUri() + " with NFD");
410 
411  // Routes must be inserted into the RIB so route flags can be applied
412  Route route;
413  route.faceId = result.getFaceId();
414  route.origin = ndn::nfd::ROUTE_ORIGIN_APP;
415  route.expires = nullopt;
417 
418  m_rib.insert(prefix, route);
419 
420  m_registeredFaces.insert(route.faceId);
421 }
422 
423 void
424 RibManager::onCommandPrefixAddNextHopError(const Name& name,
425  const ndn::nfd::ControlResponse& response)
426 {
427  BOOST_THROW_EXCEPTION(Error("Error in setting interest filter (" + name.toUri() +
428  "): " + response.getText()));
429 }
430 
431 void
432 RibManager::onEnableLocalFieldsSuccess()
433 {
434  NFD_LOG_DEBUG("Local fields enabled");
435 }
436 
437 void
438 RibManager::onEnableLocalFieldsError(const ndn::nfd::ControlResponse& response)
439 {
440  BOOST_THROW_EXCEPTION(Error("Couldn't enable local fields (code: " +
441  to_string(response.getCode()) + ", info: " + response.getText() +
442  ")"));
443 }
444 
445 } // namespace rib
446 } // namespace nfd
void start()
start or resume receiving notifications
constexpr nullopt_t nullopt
void start(const ControlParameters &parameters, const CommandSucceedCallback &onSuccess, const CommandFailCallback &onFailure, const CommandOptions &options=CommandOptions())
start command execution
Definition: controller.hpp:74
a collection of common functions shared by all NFD managers and RIB manager, such as communicating wi...
RibEntry
Copyright (c) 2014-2017, Regents of the University of California, Arizona Board of Regents...
Definition: rib-entry.cpp:32
void load(const std::string &filename)
static bool parseYesNo(const ConfigSection &node, const std::string &key, const std::string &sectionName)
parse a config option that can be either "yes" or "no"
Definition: config-file.cpp:59
represents a fib/add-nexthop command
The interface of signing key management.
Definition: key-chain.hpp:46
void beginApplyUpdate(const RibUpdate &update, const UpdateSuccessCallback &onSuccess, const UpdateFailureCallback &onFailure)
passes the provided RibUpdateBatch to FibUpdater to calculate and send FibUpdates.
Definition: rib.cpp:351
represents parameters in a ControlCommand request or response
represents a dispatcher on server side of NFD Management protocol
Definition: dispatcher.hpp:130
static time_point now() noexcept
Definition: time.cpp:80
void extractRequester(const Interest &interest, ndn::mgmt::AcceptContinuation accept)
extract a requester from a ControlCommand request
Helper for validator that uses CommandInterest + Config policy and NetworkFetcher.
reply with a ControlResponse where StatusCode is 403
configuration file parsing utility
Definition: config-file.hpp:57
Route & setFlags(uint64_t flags)
Definition: rib-entry.cpp:75
std::enable_if< std::is_default_constructible< Dataset >::value >::type fetch(const std::function< void(typename Dataset::ResultType)> &onSuccess, const DatasetFailCallback &onFailure, const CommandOptions &options=CommandOptions())
start dataset fetching
Definition: controller.hpp:87
Route & setOrigin(RouteOrigin origin)
Definition: rib-entry.cpp:59
RibManager(Dispatcher &dispatcher, ndn::Face &face, ndn::KeyChain &keyChain)
Definition: rib-manager.cpp:54
represents a Face status change notification
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:55
std::function< void(const std::string &requester)> AcceptContinuation
a function to be called if authorization is successful
Definition: dispatcher.hpp:45
represents a route in a RibEntry
Definition: rib-entry.hpp:42
void disable()
disable automatic prefix propagation
void onRibUpdateSuccess(const RibUpdate &update)
signal::Signal< NotificationSubscriber, Notification > onNotification
fires when a Notification is received
#define NFD_LOG_INFO(expression)
Definition: logger.hpp:56
Route & setCost(uint64_t cost)
Definition: rib-entry.cpp:67
provides a tag type for simple types
Definition: tag.hpp:58
std::shared_ptr< ns3::EventId > EventId
Definition: scheduler.hpp:51
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54
~RibManager() override
mgmt::ControlResponse ControlResponse
contains options for ControlCommand execution
std::function< void(RejectReply reply)> RejectContinuation
a function to be called if authorization is rejected
Definition: dispatcher.hpp:60
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
void addSectionHandler(const std::string &sectionName, ConfigSectionHandler subscriber)
setup notification of configuration file sections
Definition: config-file.cpp:76
size_t wireEncode(EncodingImpl< TAG > &block) const
Definition: rib-entry.cpp:254
void end()
end the response successfully after appending zero or more blocks
void loadConfig(const ConfigSection &configSection)
load the "auto_prefix_propagate" section from config file
void validate(const Data &data, const DataValidationSuccessCallback &successCb, const DataValidationFailureCallback &failureCb)
Asynchronously validate data.
Definition: validator.cpp:75
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:90
void addTopPrefix(const Name &prefix, bool wantRegister=true, const security::SigningInfo &signingInfo=security::SigningInfo())
add a top-level prefix
Definition: dispatcher.cpp:70
RibEntry & addRoute(const Route &route)
Definition: rib-entry.cpp:237
boost::property_tree::ptree ConfigSection
a config file section
Represents an absolute name.
Definition: name.hpp:42
std::function< void(const ControlResponse &resp)> CommandContinuation
a function to be called after ControlCommandHandler completes
Definition: dispatcher.hpp:95
base class for a struct that contains ControlCommand parameters
represents a faces/update command
static const int FIB_MAX_DEPTH
Maximum number of components in a FIB entry prefix.
void enable()
enable automatic prefix propagation
EventId schedule(time::nanoseconds after, const EventCallback &event)
Schedule an event.
Definition: scheduler.cpp:48
void onRouteExpiration(const Name &prefix, const Route &route)
Definition: rib.cpp:200
Route & setFaceId(uint64_t faceId)
Definition: rib-entry.cpp:51
void append(const Block &block)
append a Block to the response
const std::string & getText() const
represents a faces/list dataset
std::string to_string(const V &v)
Definition: backports.hpp:107
ControlCommand response.
provides a context for generating response to a StatusDataset request
uint64_t getFaceId() const
Definition: face-traits.hpp:51
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
Route & setExpirationPeriod(time::milliseconds expirationPeriod)
Definition: rib-entry.cpp:83
whether local fields are enabled on a face
RibEntry & setName(const Name &prefix)
Definition: rib-entry.cpp:229
std::function< void(const Name &prefix, const Interest &interest, const ControlParameters *params, const AcceptContinuation &accept, const RejectContinuation &reject)> Authorization
a function that performs authorization
Definition: dispatcher.hpp:77
void onRibUpdateFailure(const RibUpdate &update, uint32_t code, const std::string &error)
represents an item in NFD RIB dataset
Definition: rib-entry.hpp:157
void setConfigFile(ConfigFile &configFile)