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"
27 
28 #include "core/fib-max-depth.hpp"
29 #include "core/logger.hpp"
30 #include "core/scheduler.hpp"
31 
32 #include <ndn-cxx/lp/tags.hpp>
33 #include <ndn-cxx/mgmt/nfd/control-command.hpp>
34 #include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
35 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
36 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
37 #include <ndn-cxx/mgmt/nfd/rib-entry.hpp>
38 
39 namespace nfd {
40 namespace rib {
41 
42 NFD_LOG_INIT(RibManager);
43 
44 static const std::string MGMT_MODULE_NAME = "rib";
45 static const Name LOCALHOST_TOP_PREFIX = "/localhost/nfd";
46 static const Name LOCALHOP_TOP_PREFIX = "/localhop/nfd";
47 static const time::seconds ACTIVE_FACE_FETCH_INTERVAL = time::seconds(300);
48 
49 RibManager::RibManager(Rib& rib, ndn::Face& face, ndn::nfd::Controller& nfdController, Dispatcher& dispatcher)
50  : ManagerBase(dispatcher, MGMT_MODULE_NAME)
51  , m_rib(rib)
52  , m_nfdController(nfdController)
53  , m_dispatcher(dispatcher)
54  , m_faceMonitor(face)
55  , m_localhostValidator(face)
56  , m_localhopValidator(face)
57  , m_isLocalhopEnabled(false)
58 {
59  registerCommandHandler<ndn::nfd::RibRegisterCommand>("register",
60  bind(&RibManager::registerEntry, this, _2, _3, _4, _5));
61  registerCommandHandler<ndn::nfd::RibUnregisterCommand>("unregister",
62  bind(&RibManager::unregisterEntry, this, _2, _3, _4, _5));
63 
64  registerStatusDatasetHandler("list", bind(&RibManager::listEntries, this, _1, _2, _3));
65 }
66 
67 void
68 RibManager::applyLocalhostConfig(const ConfigSection& section, const std::string& filename)
69 {
70  m_localhostValidator.load(section, filename);
71 }
72 
73 void
74 RibManager::enableLocalhop(const ConfigSection& section, const std::string& filename)
75 {
76  m_localhopValidator.load(section, filename);
77  m_isLocalhopEnabled = true;
78 }
79 
80 void
82 {
83  m_isLocalhopEnabled = false;
84 }
85 
86 void
88 {
89  registerTopPrefix(LOCALHOST_TOP_PREFIX);
90 
91  if (m_isLocalhopEnabled) {
92  registerTopPrefix(LOCALHOP_TOP_PREFIX);
93  }
94 
95  NFD_LOG_INFO("Start monitoring face create/destroy events");
96  m_faceMonitor.onNotification.connect(bind(&RibManager::onNotification, this, _1));
97  m_faceMonitor.start();
98 
99  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
100 }
101 
102 void
104 {
105  m_nfdController.start<ndn::nfd::FaceUpdateCommand>(
106  ControlParameters().setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true),
107  [] (const ControlParameters& res) {
108  NFD_LOG_DEBUG("Local fields enabled");
109  },
110  [] (const ControlResponse& res) {
111  BOOST_THROW_EXCEPTION(Error("Couldn't enable local fields (" + to_string(res.getCode()) +
112  " " + res.getText() + ")"));
113  });
114 }
115 
116 void
117 RibManager::beginAddRoute(const Name& name, Route route, optional<time::nanoseconds> expires,
118  const std::function<void(RibUpdateResult)>& done)
119 {
120  if (expires) {
121  if (*expires <= 0_ns) {
122  done(RibUpdateResult::EXPIRED);
123  return;
124  }
125  route.expires = time::steady_clock::now() + *expires;
126  }
127  else if (route.expires) {
128  expires = *route.expires - time::steady_clock::now();
129  if (*expires <= 0_ns) {
130  done(RibUpdateResult::EXPIRED);
131  return;
132  }
133  }
134 
135  NFD_LOG_INFO("Adding route " << name << " nexthop=" << route.faceId <<
136  " origin=" << route.origin << " cost=" << route.cost);
137 
138  if (expires) {
140  *expires, [=] { m_rib.onRouteExpiration(name, route); }));
141  NFD_LOG_TRACE("Scheduled unregistration at: " << *route.expires);
142  }
143 
144  m_registeredFaces.insert(route.faceId);
145 
146  RibUpdate update;
148  .setName(name)
149  .setRoute(route);
150  beginRibUpdate(update, done);
151 }
152 
153 void
154 RibManager::beginRemoveRoute(const Name& name, const Route& route,
155  const std::function<void(RibUpdateResult)>& done)
156 {
157  NFD_LOG_INFO("Removing route " << name << " nexthop=" << route.faceId <<
158  " origin=" << route.origin);
159 
160  RibUpdate update;
162  .setName(name)
163  .setRoute(route);
164  beginRibUpdate(update, done);
165 }
166 
167 void
168 RibManager::beginRibUpdate(const RibUpdate& update,
169  const std::function<void(RibUpdateResult)>& done)
170 {
171  m_rib.beginApplyUpdate(update,
172  [=] {
173  NFD_LOG_DEBUG("RIB update succeeded for " << update);
174  done(RibUpdateResult::OK);
175  },
176  [=] (uint32_t code, const std::string& error) {
177  NFD_LOG_DEBUG("RIB update failed for " << update << " (" << code << " " << error << ")");
178 
179  // Since the FIB rejected the update, clean up invalid routes
180  scheduleActiveFaceFetch(1_s);
181 
182  done(RibUpdateResult::ERROR);
183  });
184 }
185 
186 void
187 RibManager::registerTopPrefix(const Name& topPrefix)
188 {
189  // add FIB nexthop
190  m_nfdController.start<ndn::nfd::FibAddNextHopCommand>(
191  ControlParameters().setName(Name(topPrefix).append(MGMT_MODULE_NAME))
192  .setFaceId(0),
193  [=] (const ControlParameters& res) {
194  NFD_LOG_DEBUG("Successfully registered " << topPrefix << " with NFD");
195 
196  // Routes must be inserted into the RIB so route flags can be applied
197  Route route;
198  route.faceId = res.getFaceId();
199  route.origin = ndn::nfd::ROUTE_ORIGIN_APP;
200  route.flags = ndn::nfd::ROUTE_FLAG_CHILD_INHERIT;
201 
202  m_rib.insert(topPrefix, route);
203 
204  m_registeredFaces.insert(route.faceId);
205  },
206  [=] (const ControlResponse& res) {
207  BOOST_THROW_EXCEPTION(Error("Cannot add FIB entry " + topPrefix.toUri() + " (" +
208  to_string(res.getCode()) + " " + res.getText() + ")"));
209  });
210 
211  // add top prefix to the dispatcher without prefix registration
212  m_dispatcher.addTopPrefix(topPrefix, false);
213 }
214 
215 void
216 RibManager::registerEntry(const Name& topPrefix, const Interest& interest,
217  ControlParameters parameters,
218  const ndn::mgmt::CommandContinuation& done)
219 {
220  if (parameters.getName().size() > FIB_MAX_DEPTH) {
221  done(ControlResponse(414, "Route prefix cannot exceed " + ndn::to_string(FIB_MAX_DEPTH) +
222  " components"));
223  return;
224  }
225 
226  setFaceForSelfRegistration(interest, parameters);
227 
228  // Respond since command is valid and authorized
229  done(ControlResponse(200, "Success").setBody(parameters.wireEncode()));
230 
231  Route route;
232  route.faceId = parameters.getFaceId();
233  route.origin = parameters.getOrigin();
234  route.cost = parameters.getCost();
235  route.flags = parameters.getFlags();
236 
237  optional<time::nanoseconds> expires;
238  if (parameters.hasExpirationPeriod() &&
239  parameters.getExpirationPeriod() != time::milliseconds::max()) {
240  expires = time::duration_cast<time::nanoseconds>(parameters.getExpirationPeriod());
241  }
242 
243  beginAddRoute(parameters.getName(), std::move(route), expires, [] (RibUpdateResult) {});
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  beginRemoveRoute(parameters.getName(), route, [] (RibUpdateResult) {});
261 }
262 
263 void
264 RibManager::listEntries(const Name& topPrefix, const Interest& interest,
265  ndn::mgmt::StatusDatasetContext& context)
266 {
267  auto now = time::steady_clock::now();
268  for (const auto& kv : m_rib) {
269  const RibEntry& entry = *kv.second;
270  ndn::nfd::RibEntry item;
271  item.setName(entry.getName());
272  for (const Route& route : entry.getRoutes()) {
273  ndn::nfd::Route r;
274  r.setFaceId(route.faceId);
275  r.setOrigin(route.origin);
276  r.setCost(route.cost);
277  r.setFlags(route.flags);
278  if (route.expires) {
279  r.setExpirationPeriod(time::duration_cast<time::milliseconds>(*route.expires - now));
280  }
281  item.addRoute(r);
282  }
283  context.append(item.wireEncode());
284  }
285  context.end();
286 }
287 
288 void
289 RibManager::setFaceForSelfRegistration(const Interest& request, ControlParameters& parameters)
290 {
291  bool isSelfRegistration = (parameters.getFaceId() == 0);
292  if (isSelfRegistration) {
293  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
294  // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
295  // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
296  // and is initialized synchronously with IncomingFaceId field enabled.
297  BOOST_ASSERT(incomingFaceIdTag != nullptr);
298  parameters.setFaceId(*incomingFaceIdTag);
299  }
300 }
301 
302 ndn::mgmt::Authorization
303 RibManager::makeAuthorization(const std::string& verb)
304 {
305  return [this] (const Name& prefix, const Interest& interest,
306  const ndn::mgmt::ControlParameters* params,
307  const ndn::mgmt::AcceptContinuation& accept,
308  const ndn::mgmt::RejectContinuation& reject) {
309  BOOST_ASSERT(params != nullptr);
310  BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters));
311  BOOST_ASSERT(prefix == LOCALHOST_TOP_PREFIX || prefix == LOCALHOP_TOP_PREFIX);
312 
313  ndn::ValidatorConfig& validator = prefix == LOCALHOST_TOP_PREFIX ?
314  m_localhostValidator : m_localhopValidator;
315  validator.validate(interest,
316  bind([&interest, this, accept] { extractRequester(interest, accept); }),
317  bind([reject] { reject(ndn::mgmt::RejectReply::STATUS403); }));
318  };
319 }
320 
321 void
322 RibManager::fetchActiveFaces()
323 {
324  NFD_LOG_DEBUG("Fetching active faces");
325 
326  m_nfdController.fetch<ndn::nfd::FaceDataset>(
327  bind(&RibManager::removeInvalidFaces, this, _1),
328  bind(&RibManager::onFetchActiveFacesFailure, this, _1, _2),
329  ndn::nfd::CommandOptions());
330 }
331 
332 void
333 RibManager::onFetchActiveFacesFailure(uint32_t code, const std::string& reason)
334 {
335  NFD_LOG_DEBUG("Face Status Dataset request failure " << code << " " << reason);
336  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
337 }
338 
339 void
340 RibManager::onFaceDestroyedEvent(uint64_t faceId)
341 {
342  m_rib.beginRemoveFace(faceId);
343  m_registeredFaces.erase(faceId);
344 }
345 
346 void
347 RibManager::scheduleActiveFaceFetch(const time::seconds& timeToWait)
348 {
349  m_activeFaceFetchEvent = scheduler::schedule(timeToWait, [this] { this->fetchActiveFaces(); });
350 }
351 
352 void
353 RibManager::removeInvalidFaces(const std::vector<ndn::nfd::FaceStatus>& activeFaces)
354 {
355  NFD_LOG_DEBUG("Checking for invalid face registrations");
356 
357  FaceIdSet activeFaceIds;
358  for (const auto& faceStatus : activeFaces) {
359  activeFaceIds.insert(faceStatus.getFaceId());
360  }
361 
362  // Look for face IDs that were registered but not active to find missed
363  // face destroyed events
364  for (auto faceId : m_registeredFaces) {
365  if (activeFaceIds.count(faceId) == 0) {
366  NFD_LOG_DEBUG("Removing invalid face ID: " << faceId);
367  scheduler::schedule(time::seconds(0), [this, faceId] { this->onFaceDestroyedEvent(faceId); });
368  }
369  }
370 
371  // Reschedule the check for future clean up
372  scheduleActiveFaceFetch(ACTIVE_FACE_FETCH_INTERVAL);
373 }
374 
375 void
376 RibManager::onNotification(const ndn::nfd::FaceEventNotification& notification)
377 {
378  NFD_LOG_TRACE("onNotification: " << notification);
379 
380  if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) {
381  NFD_LOG_DEBUG("Received notification for destroyed faceId: " << notification.getFaceId());
382 
383  scheduler::schedule(time::seconds(0),
384  bind(&RibManager::onFaceDestroyedEvent, this, notification.getFaceId()));
385  }
386 }
387 
388 } // namespace rib
389 } // namespace nfd
void registerStatusDatasetHandler(const std::string &verb, const ndn::mgmt::StatusDatasetHandler &handler)
uint64_t faceId
Definition: route.hpp:74
RibUpdate & setRoute(const Route &route)
Definition: rib-update.hpp:107
uint64_t cost
Definition: route.hpp:76
represents the Routing Information Base
Definition: rib.hpp:59
static const Name LOCALHOP_TOP_PREFIX
Definition: rib-manager.cpp:46
RibUpdate & setAction(Action action)
Definition: rib-update.hpp:81
static const time::seconds ACTIVE_FACE_FETCH_INTERVAL
Definition: rib-manager.cpp:47
#define NFD_LOG_TRACE
Definition: logger.hpp:37
void setName(const Name &prefix)
Definition: rib-entry.hpp:217
RibManager(Rib &rib, ndn::Face &face, ndn::nfd::Controller &nfdController, Dispatcher &dispatcher)
Definition: rib-manager.cpp:49
void enableLocalhop(const ConfigSection &section, const std::string &filename)
Apply localhop_security configuration and allow accepting commands on /localhop/nfd/rib prefix...
Definition: rib-manager.cpp:74
void registerWithNfd()
Start accepting commands and dataset requests.
Definition: rib-manager.cpp:87
void applyLocalhostConfig(const ConfigSection &section, const std::string &filename)
Apply localhost_security configuration.
Definition: rib-manager.cpp:68
void enableLocalFields()
Enable NDNLP IncomingFaceId field in order to support self-registration commands. ...
RibUpdate & setName(const Name &name)
Definition: rib-update.hpp:94
a collection of common functions shared by all NFD managers and RIB manager, such as communicating wi...
boost::property_tree::ptree ConfigSection
a config file section
Definition: config-file.hpp:37
optional< time::steady_clock::TimePoint > expires
Definition: route.hpp:78
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
const Name & getName() const
Definition: rib-entry.hpp:223
const RouteList & getRoutes() const
Definition: rib-entry.hpp:247
ndn::nfd::RouteOrigin origin
Definition: route.hpp:75
void insert(const Name &prefix, const Route &route)
Definition: rib.cpp:86
void setExpirationEvent(const scheduler::EventId eid)
Definition: route.hpp:56
represents a route for a name prefix
Definition: route.hpp:42
static const std::string MGMT_MODULE_NAME
Definition: rib-manager.cpp:44
void extractRequester(const Interest &interest, ndn::mgmt::AcceptContinuation accept)
extract a requester from a ControlCommand request
static const int FIB_MAX_DEPTH
Maximum number of components in a FIB entry prefix.
#define NFD_LOG_INFO
Definition: logger.hpp:39
void disableLocalhop()
Disallow accepting commands on /localhop/nfd/rib prefix.
Definition: rib-manager.cpp:81
#define NFD_LOG_DEBUG
Definition: logger.hpp:38
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31
EventId schedule(time::nanoseconds after, const EventCallback &event)
Schedule an event.
Definition: scheduler.cpp:47
static const Name LOCALHOST_TOP_PREFIX
Definition: rib-manager.cpp:45
Represents a RIB entry, which contains one or more Routes with the same prefix.
Definition: rib-entry.hpp:38
void beginRemoveFace(uint64_t faceId)
starts the FIB update process when a face has been destroyed
Definition: rib.cpp:354
void onRouteExpiration(const Name &prefix, const Route &route)
Definition: rib.cpp:193
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:342
std::underlying_type< ndn::nfd::RouteFlags >::type flags
Definition: route.hpp:77