NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: 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; -*- */
26 #include "rib-manager.hpp"
30 
31 #include "core/logger.hpp"
32 #include "core/scheduler.hpp"
33 
34 #include <ndn-cxx/lp/tags.hpp>
35 #include <ndn-cxx/mgmt/nfd/control-command.hpp>
36 #include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
37 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
38 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
39 #include <ndn-cxx/mgmt/nfd/rib-entry.hpp>
40 
41 namespace nfd {
42 namespace rib {
43 
44 NFD_LOG_INIT("RibManager");
45 
46 const Name RibManager::LOCAL_HOST_TOP_PREFIX = "/localhost/nfd";
47 const Name RibManager::LOCAL_HOP_TOP_PREFIX = "/localhop/nfd";
48 const std::string RibManager::MGMT_MODULE_NAME = "rib";
49 const Name RibManager::FACES_LIST_DATASET_PREFIX = "/localhost/nfd/faces/list";
50 const time::seconds RibManager::ACTIVE_FACE_FETCH_INTERVAL = time::seconds(300);
51 const Name RibManager::READVERTISE_NLSR_PREFIX = "/localhost/nlsr";
52 
54  ndn::Face& face,
55  ndn::KeyChain& keyChain)
56  : ManagerBase(dispatcher, MGMT_MODULE_NAME)
57  , m_face(face)
58  , m_keyChain(keyChain)
59  , m_nfdController(m_face, m_keyChain)
60  , m_faceMonitor(m_face)
61  , m_localhostValidator(m_face)
62  , m_localhopValidator(m_face)
63  , m_isLocalhopEnabled(false)
64  , m_prefixPropagator(m_nfdController, m_keyChain, m_rib)
65  , m_fibUpdater(m_rib, m_nfdController)
66  , m_addTopPrefix([&dispatcher] (const Name& topPrefix) {
67  dispatcher.addTopPrefix(topPrefix, false);
68  })
69 {
70  registerCommandHandler<ndn::nfd::RibRegisterCommand>("register",
71  bind(&RibManager::registerEntry, this, _2, _3, _4, _5));
72  registerCommandHandler<ndn::nfd::RibUnregisterCommand>("unregister",
73  bind(&RibManager::unregisterEntry, this, _2, _3, _4, _5));
74 
75  registerStatusDatasetHandler("list", bind(&RibManager::listEntries, this, _1, _2, _3));
76 }
77 
78 RibManager::~RibManager() = default;
79 
80 void
82 {
83  registerTopPrefix(LOCAL_HOST_TOP_PREFIX);
84 
85  if (m_isLocalhopEnabled) {
86  registerTopPrefix(LOCAL_HOP_TOP_PREFIX);
87  }
88 
89  NFD_LOG_INFO("Start monitoring face create/destroy events");
90  m_faceMonitor.onNotification.connect(bind(&RibManager::onNotification, this, _1));
91  m_faceMonitor.start();
92 
93  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
94 }
95 
96 void
98 {
99  m_nfdController.start<ndn::nfd::FaceUpdateCommand>(
101  .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true),
102  bind(&RibManager::onEnableLocalFieldsSuccess, this),
103  bind(&RibManager::onEnableLocalFieldsError, this, _1));
104 }
105 
106 void
108 {
109  configFile.addSectionHandler("rib",
110  bind(&RibManager::onConfig, this, _1, _2, _3));
111 }
112 
113 void
115 {
116  NFD_LOG_DEBUG("RIB update succeeded for " << update);
117 }
118 
119 void
120 RibManager::onRibUpdateFailure(const RibUpdate& update, uint32_t code, const std::string& error)
121 {
122  NFD_LOG_DEBUG("RIB update failed for " << update << " (code: " << code
123  << ", error: " << error << ")");
124 
125  // Since the FIB rejected the update, clean up invalid routes
126  scheduleActiveFaceFetch(time::seconds(1));
127 }
128 
129 void
130 RibManager::onConfig(const ConfigSection& configSection,
131  bool isDryRun,
132  const std::string& filename)
133 {
134  bool isAutoPrefixPropagatorEnabled = false;
135  bool wantReadvertiseToNlsr = false;
136 
137  for (const auto& item : configSection) {
138  if (item.first == "localhost_security") {
139  m_localhostValidator.load(item.second, filename);
140  }
141  else if (item.first == "localhop_security") {
142  m_localhopValidator.load(item.second, filename);
143  m_isLocalhopEnabled = true;
144  }
145  else if (item.first == "auto_prefix_propagate") {
146  m_prefixPropagator.loadConfig(item.second);
147  isAutoPrefixPropagatorEnabled = true;
148 
149  // Avoid other actions when isDryRun == true
150  if (isDryRun) {
151  continue;
152  }
153 
154  m_prefixPropagator.enable();
155  }
156  else if (item.first == "readvertise_nlsr") {
157  wantReadvertiseToNlsr = ConfigFile::parseYesNo(item, "rib.readvertise_nlsr");
158  }
159  else {
160  BOOST_THROW_EXCEPTION(Error("Unrecognized rib property: " + item.first));
161  }
162  }
163 
164  if (!isAutoPrefixPropagatorEnabled) {
165  m_prefixPropagator.disable();
166  }
167 
168  if (wantReadvertiseToNlsr && m_readvertiseNlsr == nullptr) {
169  NFD_LOG_DEBUG("Enabling readvertise-to-nlsr.");
170  m_readvertiseNlsr.reset(new Readvertise(
171  m_rib,
172  make_unique<ClientToNlsrReadvertisePolicy>(),
173  make_unique<NfdRibReadvertiseDestination>(m_nfdController, READVERTISE_NLSR_PREFIX, m_rib)));
174  }
175  else if (!wantReadvertiseToNlsr && m_readvertiseNlsr != nullptr) {
176  NFD_LOG_DEBUG("Disabling readvertise-to-nlsr.");
177  m_readvertiseNlsr.reset();
178  }
179 }
180 
181 void
182 RibManager::registerTopPrefix(const Name& topPrefix)
183 {
184  // register entry to the FIB
185  m_nfdController.start<ndn::nfd::FibAddNextHopCommand>(
187  .setName(Name(topPrefix).append(MGMT_MODULE_NAME))
188  .setFaceId(0),
189  bind(&RibManager::onCommandPrefixAddNextHopSuccess, this, cref(topPrefix), _1),
190  bind(&RibManager::onCommandPrefixAddNextHopError, this, cref(topPrefix), _1));
191 
192  // add top prefix to the dispatcher
193  m_addTopPrefix(topPrefix);
194 }
195 
196 void
197 RibManager::registerEntry(const Name& topPrefix, const Interest& interest,
198  ControlParameters parameters,
199  const ndn::mgmt::CommandContinuation& done)
200 {
201  setFaceForSelfRegistration(interest, parameters);
202 
203  // Respond since command is valid and authorized
204  done(ControlResponse(200, "Success").setBody(parameters.wireEncode()));
205 
206  Route route;
207  route.faceId = parameters.getFaceId();
208  route.origin = parameters.getOrigin();
209  route.cost = parameters.getCost();
210  route.flags = parameters.getFlags();
211 
212  if (parameters.hasExpirationPeriod() &&
213  parameters.getExpirationPeriod() != time::milliseconds::max()) {
214  route.expires = time::steady_clock::now() + parameters.getExpirationPeriod();
215 
216  // Schedule a new event, the old one will be cancelled during rib insertion.
218  bind(&Rib::onRouteExpiration, &m_rib, parameters.getName(), route));
219 
220  NFD_LOG_TRACE("Scheduled unregistration at: " << *route.expires <<
221  " with EventId: " << eventId);
222 
223  // Set the NewEventId of this entry
224  route.setExpirationEvent(eventId);
225  }
226  else {
227  route.expires = ndn::nullopt;
228  }
229 
230  NFD_LOG_INFO("Adding route " << parameters.getName() << " nexthop=" << route.faceId
231  << " origin=" << route.origin
232  << " cost=" << route.cost);
233 
234  RibUpdate update;
236  .setName(parameters.getName())
237  .setRoute(route);
238 
239  m_rib.beginApplyUpdate(update,
240  bind(&RibManager::onRibUpdateSuccess, this, update),
241  bind(&RibManager::onRibUpdateFailure, this, update, _1, _2));
242 
243  m_registeredFaces.insert(route.faceId);
244 }
245 
246 void
247 RibManager::unregisterEntry(const Name& topPrefix, const Interest& interest,
248  ControlParameters parameters,
249  const ndn::mgmt::CommandContinuation& done)
250 {
251  setFaceForSelfRegistration(interest, parameters);
252 
253  // Respond since command is valid and authorized
254  done(ControlResponse(200, "Success").setBody(parameters.wireEncode()));
255 
256  Route route;
257  route.faceId = parameters.getFaceId();
258  route.origin = parameters.getOrigin();
259 
260  NFD_LOG_INFO("Removing route " << parameters.getName() << " nexthop=" << route.faceId
261  << " origin=" << route.origin);
262 
263  RibUpdate update;
265  .setName(parameters.getName())
266  .setRoute(route);
267 
268  m_rib.beginApplyUpdate(update,
269  bind(&RibManager::onRibUpdateSuccess, this, update),
270  bind(&RibManager::onRibUpdateFailure, this, update, _1, _2));
271 }
272 
273 void
274 RibManager::listEntries(const Name& topPrefix, const Interest& interest,
276 {
277  auto now = time::steady_clock::now();
278  for (const auto& kv : m_rib) {
279  const RibEntry& entry = *kv.second;
280  ndn::nfd::RibEntry item;
281  item.setName(entry.getName());
282  for (const Route& route : entry.getRoutes()) {
283  ndn::nfd::Route r;
284  r.setFaceId(route.faceId);
285  r.setOrigin(route.origin);
286  r.setCost(route.cost);
287  r.setFlags(route.flags);
288  if (route.expires) {
289  r.setExpirationPeriod(time::duration_cast<time::milliseconds>(*route.expires - now));
290  }
291  item.addRoute(r);
292  }
293  context.append(item.wireEncode());
294  }
295  context.end();
296 }
297 
298 void
299 RibManager::setFaceForSelfRegistration(const Interest& request, ControlParameters& parameters)
300 {
301  bool isSelfRegistration = (parameters.getFaceId() == 0);
302  if (isSelfRegistration) {
303  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
304  // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
305  // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
306  // and is initialized synchronously with IncomingFaceId field enabled.
307  BOOST_ASSERT(incomingFaceIdTag != nullptr);
308  parameters.setFaceId(*incomingFaceIdTag);
309  }
310 }
311 
313 RibManager::makeAuthorization(const std::string& verb)
314 {
315  return [this] (const Name& prefix, const Interest& interest,
316  const ndn::mgmt::ControlParameters* params,
318  const ndn::mgmt::RejectContinuation& reject) {
319  BOOST_ASSERT(params != nullptr);
320  BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters));
321  BOOST_ASSERT(prefix == LOCAL_HOST_TOP_PREFIX || prefix == LOCAL_HOP_TOP_PREFIX);
322 
323  ndn::ValidatorConfig& validator = prefix == LOCAL_HOST_TOP_PREFIX ?
324  m_localhostValidator : m_localhopValidator;
325  validator.validate(interest,
326  bind([&interest, this, accept] { extractRequester(interest, accept); }),
327  bind([reject] { reject(ndn::mgmt::RejectReply::STATUS403); }));
328  };
329 }
330 
331 void
332 RibManager::fetchActiveFaces()
333 {
334  NFD_LOG_DEBUG("Fetching active faces");
335 
336  m_nfdController.fetch<ndn::nfd::FaceDataset>(
337  bind(&RibManager::removeInvalidFaces, this, _1),
338  bind(&RibManager::onFetchActiveFacesFailure, this, _1, _2),
340 }
341 
342 void
343 RibManager::onFetchActiveFacesFailure(uint32_t code, const std::string& reason)
344 {
345  NFD_LOG_DEBUG("Face Status Dataset request failure " << code << " " << reason);
346  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
347 }
348 
349 void
350 RibManager::onFaceDestroyedEvent(uint64_t faceId)
351 {
352  m_rib.beginRemoveFace(faceId);
353  m_registeredFaces.erase(faceId);
354 }
355 
356 void
357 RibManager::scheduleActiveFaceFetch(const time::seconds& timeToWait)
358 {
359  m_activeFaceFetchEvent = scheduler::schedule(timeToWait, [this] { this->fetchActiveFaces(); });
360 }
361 
362 void
363 RibManager::removeInvalidFaces(const std::vector<ndn::nfd::FaceStatus>& activeFaces)
364 {
365  NFD_LOG_DEBUG("Checking for invalid face registrations");
366 
367  FaceIdSet activeFaceIds;
368  for (const auto& faceStatus : activeFaces) {
369  activeFaceIds.insert(faceStatus.getFaceId());
370  }
371 
372  // Look for face IDs that were registered but not active to find missed
373  // face destroyed events
374  for (auto faceId : m_registeredFaces) {
375  if (activeFaceIds.count(faceId) == 0) {
376  NFD_LOG_DEBUG("Removing invalid face ID: " << faceId);
377  scheduler::schedule(time::seconds(0), [this, faceId] { this->onFaceDestroyedEvent(faceId); });
378  }
379  }
380 
381  // Reschedule the check for future clean up
382  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
383 }
384 
385 void
386 RibManager::onNotification(const ndn::nfd::FaceEventNotification& notification)
387 {
388  NFD_LOG_TRACE("onNotification: " << notification);
389 
390  if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) {
391  NFD_LOG_DEBUG("Received notification for destroyed faceId: " << notification.getFaceId());
392 
393  scheduler::schedule(time::seconds(0),
394  bind(&RibManager::onFaceDestroyedEvent, this, notification.getFaceId()));
395  }
396 }
397 
398 void
399 RibManager::onCommandPrefixAddNextHopSuccess(const Name& prefix,
400  const ndn::nfd::ControlParameters& result)
401 {
402  NFD_LOG_DEBUG("Successfully registered " + prefix.toUri() + " with NFD");
403 
404  // Routes must be inserted into the RIB so route flags can be applied
405  Route route;
406  route.faceId = result.getFaceId();
407  route.origin = ndn::nfd::ROUTE_ORIGIN_APP;
408  route.expires = ndn::nullopt;
410 
411  m_rib.insert(prefix, route);
412 
413  m_registeredFaces.insert(route.faceId);
414 }
415 
416 void
417 RibManager::onCommandPrefixAddNextHopError(const Name& name,
418  const ndn::nfd::ControlResponse& response)
419 {
420  BOOST_THROW_EXCEPTION(Error("Error in setting interest filter (" + name.toUri() +
421  "): " + response.getText()));
422 }
423 
424 void
425 RibManager::onEnableLocalFieldsSuccess()
426 {
427  NFD_LOG_DEBUG("Local fields enabled");
428 }
429 
430 void
431 RibManager::onEnableLocalFieldsError(const ndn::nfd::ControlResponse& response)
432 {
433  BOOST_THROW_EXCEPTION(Error("Couldn't enable local fields (code: " +
434  to_string(response.getCode()) + ", info: " + response.getText() +
435  ")"));
436 }
437 
438 } // namespace rib
439 } // 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
ControlParameters & setFaceId(uint64_t faceId)
a collection of common functions shared by all NFD managers and RIB manager, such as communicating wi...
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
void setExpirationEvent(const scheduler::EventId eid)
Definition: route.hpp:45
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
Accept any value the remote endpoint offers.
Definition: enabled.hpp:194
represents a dispatcher on server side of NFD Management protocol
Definition: dispatcher.hpp:129
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
reply with a ControlResponse where StatusCode is 403
configuration file parsing utility
Definition: config-file.hpp:58
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
std::underlying_type< ndn::nfd::RouteFlags >::type flags
Definition: route.hpp:66
Route & setOrigin(RouteOrigin origin)
Definition: rib-entry.cpp:59
RibManager(Dispatcher &dispatcher, ndn::Face &face, ndn::KeyChain &keyChain)
Definition: rib-manager.cpp:53
represents a Face status change notification
uint64_t cost
Definition: route.hpp:65
uint64_t faceId
Definition: route.hpp:63
represents an Interest packet
Definition: interest.hpp:42
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:55
std::function< void(RejectReply act)> RejectContinuation
a function to be called if authorization is rejected
Definition: dispatcher.hpp:60
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
ndn::optional< time::steady_clock::TimePoint > expires
Definition: route.hpp:67
Route & setCost(uint64_t cost)
Definition: rib-entry.cpp:67
const std::string & getText() const
provides a tag type for simple types
Definition: tag.hpp:58
std::shared_ptr< ns3::EventId > EventId
Definition: scheduler.hpp:48
std::string toUri() const
Get URI representation of the name.
Definition: name.cpp:122
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54
size_t wireEncode(EncodingImpl< TAG > &encoder) const
ndn::nfd::RouteOrigin origin
Definition: route.hpp:64
~RibManager() override
void insert(const Name &prefix, const Route &route)
Definition: rib.cpp:91
mgmt::ControlResponse ControlResponse
contains options for ControlCommand execution
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
RibUpdate & setAction(Action action)
Definition: rib-update.hpp:81
represents a RIB entry, which contains one or more Routes with the same prefix
Definition: rib-entry.hpp:36
const RouteList & getRoutes() const
Definition: rib-entry.hpp:229
void loadConfig(const ConfigSection &configSection)
load the "auto_prefix_propagate" section from config file
represents a route for a name prefix
Definition: route.hpp:39
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:95
void addTopPrefix(const Name &prefix, bool wantRegister=true, const security::SigningInfo &signingInfo=security::SigningInfo())
add a top-level prefix
Definition: dispatcher.cpp:72
uint64_t getFaceId() const
Definition: face-traits.hpp:51
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
const Name & getName() const
Definition: rib-entry.hpp:205
void beginRemoveFace(uint64_t faceId)
starts the FIB update process when a face has been destroyed
Definition: rib.cpp:363
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
void enable()
enable automatic prefix propagation
const time::milliseconds & getExpirationPeriod() const
RibUpdate & setName(const Name &name)
Definition: rib-update.hpp:94
EventId schedule(time::nanoseconds after, const EventCallback &event)
schedule an event
Definition: scheduler.cpp:47
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
shared_ptr< T > getTag() const
get a tag item
Definition: tag-host.hpp:67
represents a faces/list dataset
std::string to_string(const V &v)
Definition: backports.hpp:84
ControlCommand response.
provides a context for generating response to a StatusDataset request
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
Route & setExpirationPeriod(time::milliseconds expirationPeriod)
Definition: rib-entry.cpp:83
controls 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 registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
void onRibUpdateFailure(const RibUpdate &update, uint32_t code, const std::string &error)
represents an item in NFD RIB dataset
Definition: rib-entry.hpp:157
ndn security v2 KeyChain
Definition: key-chain.cpp:76
void setConfigFile(ConfigFile &configFile)