rib.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.hpp"
27 #include "fib-updater.hpp"
28 #include "core/logger.hpp"
29 
30 namespace nfd {
31 namespace rib {
32 
33 NFD_LOG_INIT(Rib);
34 
35 bool
36 operator<(const RibRouteRef& lhs, const RibRouteRef& rhs)
37 {
38  return std::tie(lhs.entry->getName(), lhs.route->faceId, lhs.route->origin) <
39  std::tie(rhs.entry->getName(), rhs.route->faceId, rhs.route->origin);
40 }
41 
42 static inline bool
43 sortRoutes(const Route& lhs, const Route& rhs)
44 {
45  return lhs.faceId < rhs.faceId;
46 }
47 
49  : m_nItems(0)
50  , m_isUpdateInProgress(false)
51 {
52 }
53 
54 Rib::~Rib() = default;
55 
56 void
58 {
59  m_fibUpdater = updater;
60 }
61 
63 Rib::find(const Name& prefix) const
64 {
65  return m_rib.find(prefix);
66 }
67 
68 Route*
69 Rib::find(const Name& prefix, const Route& route) const
70 {
71  auto ribIt = m_rib.find(prefix);
72 
73  // Name prefix exists
74  if (ribIt != m_rib.end()) {
75  shared_ptr<RibEntry> entry = ribIt->second;
76  auto routeIt = entry->findRoute(route);
77  if (routeIt != entry->end()) {
78  return &*routeIt;
79  }
80  }
81 
82  return nullptr;
83 }
84 
85 void
86 Rib::insert(const Name& prefix, const Route& route)
87 {
88  auto ribIt = m_rib.find(prefix);
89 
90  // Name prefix exists
91  if (ribIt != m_rib.end()) {
92  shared_ptr<RibEntry> entry(ribIt->second);
93 
94  RibEntry::iterator entryIt;
95  bool didInsert = false;
96  std::tie(entryIt, didInsert) = entry->insertRoute(route);
97 
98  if (didInsert) {
99  // The route was new and we successfully inserted it.
100  m_nItems++;
101 
102  afterAddRoute(RibRouteRef{entry, entryIt});
103 
104  // Register with face lookup table
105  m_faceMap[route.faceId].push_back(entry);
106  }
107  else {
108  // Route exists, update fields
109  // First cancel old scheduled event, if any, then set the EventId to new one
110  if (static_cast<bool>(entryIt->getExpirationEvent())) {
111  NFD_LOG_TRACE("Cancelling expiration event for " << entry->getName() << " "
112  << (*entryIt));
113  scheduler::cancel(entryIt->getExpirationEvent());
114  }
115 
116  *entryIt = route;
117 
118  // No checks are required here as the iterator needs to be updated in all cases.
119  entryIt->setExpirationEvent(route.getExpirationEvent());
120  }
121  }
122  else {
123  // New name prefix
124  auto entry = make_shared<RibEntry>();
125 
126  m_rib[prefix] = entry;
127  m_nItems++;
128 
129  entry->setName(prefix);
130  auto routeIt = entry->insertRoute(route).first;
131 
132  // Find prefix's parent
133  shared_ptr<RibEntry> parent = findParent(prefix);
134 
135  // Add self to parent's children
136  if (parent != nullptr) {
137  parent->addChild(entry);
138  }
139 
140  RibEntryList children = findDescendants(prefix);
141 
142  for (const auto& child : children) {
143  if (child->getParent() == parent) {
144  // Remove child from parent and inherit parent's child
145  if (parent != nullptr) {
146  parent->removeChild(child);
147  }
148 
149  entry->addChild(child);
150  }
151  }
152 
153  // Register with face lookup table
154  m_faceMap[route.faceId].push_back(entry);
155 
156  // do something after inserting an entry
157  afterInsertEntry(prefix);
158  afterAddRoute(RibRouteRef{entry, routeIt});
159  }
160 }
161 
162 void
163 Rib::erase(const Name& prefix, const Route& route)
164 {
165  auto ribIt = m_rib.find(prefix);
166 
167  // Name prefix exists
168  if (ribIt != m_rib.end()) {
169  shared_ptr<RibEntry> entry = ribIt->second;
170  auto routeIt = entry->findRoute(route);
171 
172  if (routeIt != entry->end()) {
173  beforeRemoveRoute(RibRouteRef{entry, routeIt});
174 
175  auto faceId = route.faceId;
176  entry->eraseRoute(routeIt);
177  m_nItems--;
178 
179  // If this RibEntry no longer has this faceId, unregister from face lookup table
180  if (!entry->hasFaceId(faceId)) {
181  m_faceMap[faceId].remove(entry);
182  }
183 
184  // If a RibEntry's route list is empty, remove it from the tree
185  if (entry->getRoutes().empty()) {
186  eraseEntry(ribIt);
187  }
188  }
189  }
190 }
191 
192 void
193 Rib::onRouteExpiration(const Name& prefix, const Route& route)
194 {
195  NFD_LOG_DEBUG(route << " for " << prefix << " has expired");
196 
197  RibUpdate update;
199  .setName(prefix)
200  .setRoute(route);
201 
202  beginApplyUpdate(update, nullptr, nullptr);
203 }
204 
205 shared_ptr<RibEntry>
206 Rib::findParent(const Name& prefix) const
207 {
208  for (int i = prefix.size() - 1; i >= 0; i--) {
209  auto it = m_rib.find(prefix.getPrefix(i));
210  if (it != m_rib.end()) {
211  return it->second;
212  }
213  }
214 
215  return nullptr;
216 }
217 
218 std::list<shared_ptr<RibEntry>>
219 Rib::findDescendants(const Name& prefix) const
220 {
221  std::list<shared_ptr<RibEntry>> children;
222 
223  RibTable::const_iterator it = m_rib.find(prefix);
224  if (it != m_rib.end()) {
225  ++it;
226  for (; it != m_rib.end(); ++it) {
227  if (prefix.isPrefixOf(it->first)) {
228  children.push_back((it->second));
229  }
230  else {
231  break;
232  }
233  }
234  }
235 
236  return children;
237 }
238 
239 std::list<shared_ptr<RibEntry>>
240 Rib::findDescendantsForNonInsertedName(const Name& prefix) const
241 {
242  std::list<shared_ptr<RibEntry>> children;
243 
244  for (const auto& pair : m_rib) {
245  if (prefix.isPrefixOf(pair.first)) {
246  children.push_back(pair.second);
247  }
248  }
249 
250  return children;
251 }
252 
254 Rib::eraseEntry(RibTable::iterator it)
255 {
256  // Entry does not exist
257  if (it == m_rib.end()) {
258  return m_rib.end();
259  }
260 
261  shared_ptr<RibEntry> entry(it->second);
262 
263  shared_ptr<RibEntry> parent = entry->getParent();
264 
265  // Remove self from parent's children
266  if (parent != nullptr) {
267  parent->removeChild(entry);
268  }
269 
270  for (auto childIt = entry->getChildren().begin(); childIt != entry->getChildren().end(); ) {
271  shared_ptr<RibEntry> child = *childIt;
272 
273  // Advance iterator so it is not invalidated by removal
274  ++childIt;
275 
276  // Remove children from self
277  entry->removeChild(child);
278 
279  // Update parent's children
280  if (parent != nullptr) {
281  parent->addChild(child);
282  }
283  }
284 
285  auto nextIt = m_rib.erase(it);
286 
287  // do something after erasing an entry.
288  afterEraseEntry(entry->getName());
289 
290  return nextIt;
291 }
292 
294 Rib::getAncestorRoutes(const RibEntry& entry) const
295 {
296  RouteSet ancestorRoutes(&sortRoutes);
297 
298  shared_ptr<RibEntry> parent = entry.getParent();
299 
300  while (parent != nullptr) {
301  for (const Route& route : parent->getRoutes()) {
302  if (route.isChildInherit()) {
303  ancestorRoutes.insert(route);
304  }
305  }
306 
307  if (parent->hasCapture()) {
308  break;
309  }
310 
311  parent = parent->getParent();
312  }
313 
314  return ancestorRoutes;
315 }
316 
318 Rib::getAncestorRoutes(const Name& name) const
319 {
320  RouteSet ancestorRoutes(&sortRoutes);
321 
322  shared_ptr<RibEntry> parent = findParent(name);
323 
324  while (parent != nullptr) {
325  for (const Route& route : parent->getRoutes()) {
326  if (route.isChildInherit()) {
327  ancestorRoutes.insert(route);
328  }
329  }
330 
331  if (parent->hasCapture()) {
332  break;
333  }
334 
335  parent = parent->getParent();
336  }
337 
338  return ancestorRoutes;
339 }
340 
341 void
343  const Rib::UpdateSuccessCallback& onSuccess,
344  const Rib::UpdateFailureCallback& onFailure)
345 {
346  BOOST_ASSERT(m_fibUpdater != nullptr);
347 
348  addUpdateToQueue(update, onSuccess, onFailure);
349 
350  sendBatchFromQueue();
351 }
352 
353 void
354 Rib::beginRemoveFace(uint64_t faceId)
355 {
356  for (const auto& nameAndRoute : findRoutesWithFaceId(faceId)) {
357  RibUpdate update;
359  .setName(nameAndRoute.first)
360  .setRoute(nameAndRoute.second);
361 
362  addUpdateToQueue(update, nullptr, nullptr);
363  }
364 
365  sendBatchFromQueue();
366 }
367 
368 void
369 Rib::addUpdateToQueue(const RibUpdate& update,
370  const Rib::UpdateSuccessCallback& onSuccess,
371  const Rib::UpdateFailureCallback& onFailure)
372 {
373  RibUpdateBatch batch(update.getRoute().faceId);
374  batch.add(update);
375 
376  UpdateQueueItem item{batch, onSuccess, onFailure};
377  m_updateBatches.push_back(std::move(item));
378 }
379 
380 void
381 Rib::sendBatchFromQueue()
382 {
383  if (m_updateBatches.empty() || m_isUpdateInProgress) {
384  return;
385  }
386 
387  m_isUpdateInProgress = true;
388 
389  UpdateQueueItem item = std::move(m_updateBatches.front());
390  m_updateBatches.pop_front();
391 
392  RibUpdateBatch& batch = item.batch;
393 
394  // Until task #1698, each RibUpdateBatch contains exactly one RIB update
395  BOOST_ASSERT(batch.size() == 1);
396 
397  auto fibSuccessCb = bind(&Rib::onFibUpdateSuccess, this, batch, _1, item.managerSuccessCallback);
398  auto fibFailureCb = bind(&Rib::onFibUpdateFailure, this, item.managerFailureCallback, _1, _2);
399 
400 #ifdef WITH_TESTS
401  if (mockFibResponse != nullptr) {
402  m_fibUpdater->computeAndSendFibUpdates(batch, bind([]{}), bind([]{}));
403  bool shouldFibSucceed = mockFibResponse(batch);
404  if (wantMockFibResponseOnce) {
405  mockFibResponse = nullptr;
406  }
407  if (shouldFibSucceed) {
408  fibSuccessCb(m_fibUpdater->m_inheritedRoutes);
409  }
410  else {
411  fibFailureCb(504, "mocked failure");
412  }
413  return;
414  }
415 #endif
416 
417  m_fibUpdater->computeAndSendFibUpdates(batch, fibSuccessCb, fibFailureCb);
418 }
419 
420 void
422  const RibUpdateList& inheritedRoutes,
423  const Rib::UpdateSuccessCallback& onSuccess)
424 {
425  for (const RibUpdate& update : batch) {
426  switch (update.getAction()) {
427  case RibUpdate::REGISTER:
428  insert(update.getName(), update.getRoute());
429  break;
432  erase(update.getName(), update.getRoute());
433  break;
434  }
435  }
436 
437  // Add and remove precalculated inherited routes to RibEntries
438  modifyInheritedRoutes(inheritedRoutes);
439 
440  m_isUpdateInProgress = false;
441 
442  if (onSuccess != nullptr) {
443  onSuccess();
444  }
445 
446  // Try to advance the batch queue
447  sendBatchFromQueue();
448 }
449 
450 void
452  uint32_t code, const std::string& error)
453 {
454  m_isUpdateInProgress = false;
455 
456  if (onFailure != nullptr) {
457  onFailure(code, error);
458  }
459 
460  // Try to advance the batch queue
461  sendBatchFromQueue();
462 }
463 
464 void
465 Rib::modifyInheritedRoutes(const RibUpdateList& inheritedRoutes)
466 {
467  for (const RibUpdate& update : inheritedRoutes) {
468  auto ribIt = m_rib.find(update.getName());
469  BOOST_ASSERT(ribIt != m_rib.end());
470  shared_ptr<RibEntry> entry(ribIt->second);
471 
472  switch (update.getAction()) {
473  case RibUpdate::REGISTER:
474  entry->addInheritedRoute(update.getRoute());
475  break;
477  entry->removeInheritedRoute(update.getRoute());
478  break;
480  break;
481  }
482  }
483 }
484 
485 std::list<Rib::NameAndRoute>
486 Rib::findRoutesWithFaceId(uint64_t faceId)
487 {
488  std::list<NameAndRoute> routes;
489 
490  auto lookupIt = m_faceMap.find(faceId);
491  if (lookupIt == m_faceMap.end()) {
492  // No RIB entries have this face
493  return routes;
494  }
495 
496  // For each RIB entry that has faceId
497  for (const auto& entry : lookupIt->second) {
498  // Find the routes in the entry
499  for (const Route& route : *entry) {
500  if (route.faceId == faceId) {
501  routes.emplace_back(entry->getName(), route);
502  }
503  }
504  }
505 
506  return routes;
507 }
508 
509 std::ostream&
510 operator<<(std::ostream& os, const Rib& rib)
511 {
512  for (const auto& item : rib) {
513  os << *item.second << "\n";
514  }
515 
516  return os;
517 }
518 
519 } // namespace rib
520 } // namespace nfd
references a route
Definition: rib.hpp:43
uint64_t faceId
Definition: route.hpp:74
RibUpdate & setRoute(const Route &route)
Definition: rib-update.hpp:107
represents the Routing Information Base
Definition: rib.hpp:59
std::set< Route, RouteComparePredicate > RouteSet
Definition: rib.hpp:67
void onFibUpdateFailure(const Rib::UpdateFailureCallback &onFailure, uint32_t code, const std::string &error)
Definition: rib.cpp:451
computes FibUpdates based on updates to the RIB and sends them to NFD
Definition: fib-updater.hpp:41
void cancel(const EventId &eventId)
Cancel a scheduled event.
Definition: scheduler.cpp:53
static bool sortRoutes(const Route &lhs, const Route &rhs)
Definition: rib.cpp:43
std::ostream & operator<<(std::ostream &os, const FibUpdate &update)
Definition: fib-update.hpp:74
RibUpdate & setAction(Action action)
Definition: rib-update.hpp:81
#define NFD_LOG_TRACE
Definition: logger.hpp:37
An update triggered by a face destruction notification.
Definition: rib-update.hpp:51
const_iterator find(const Name &prefix) const
Definition: rib.cpp:63
std::function< void(uint32_t code, const std::string &error)> UpdateFailureCallback
Definition: rib.hpp:116
const Name & getName() const
Definition: rib-update.hpp:101
std::list< shared_ptr< RibEntry > > findDescendantsForNonInsertedName(const Name &prefix) const
finds namespaces under the passed prefix
Definition: rib.cpp:240
Represents a collection of RibUpdates to be applied to a single FaceId.
void setFibUpdater(FibUpdater *updater)
Definition: rib.cpp:57
void add(const RibUpdate &update)
ndn::util::signal::Signal< Rib, Name > afterEraseEntry
signals after a RIB entry is erased
Definition: rib.hpp:241
void computeAndSendFibUpdates(const RibUpdateBatch &batch, const FibUpdateSuccessCallback &onSuccess, const FibUpdateFailureCallback &onFailure)
computes FibUpdates using the provided RibUpdateBatch and then sends the updates to NFD&#39;s FIB ...
Definition: fib-updater.cpp:49
ndn::util::signal::Signal< Rib, RibRouteRef > afterAddRoute
signals after a Route is added
Definition: rib.hpp:245
Table::const_iterator iterator
Definition: cs-internal.hpp:41
RibUpdate & setName(const Name &name)
Definition: rib-update.hpp:94
std::list< RibUpdate > RibUpdateList
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
std::list< shared_ptr< RibEntry > > RibEntryList
Definition: rib.hpp:62
Action getAction() const
Definition: rib-update.hpp:88
void insert(const Name &prefix, const Route &route)
Definition: rib.cpp:86
void setExpirationEvent(const scheduler::EventId eid)
Definition: route.hpp:56
RouteList::iterator iterator
Definition: rib-entry.hpp:42
std::list< shared_ptr< RibEntry > > findDescendants(const Name &prefix) const
finds namespaces under the passed prefix
Definition: rib.cpp:219
represents a route for a name prefix
Definition: route.hpp:42
RibEntry::const_iterator route
Definition: rib.hpp:46
shared_ptr< RibEntry > entry
Definition: rib.hpp:45
ndn::util::signal::Signal< Rib, RibRouteRef > beforeRemoveRoute
signals before a route is removed
Definition: rib.hpp:249
const scheduler::EventId & getExpirationEvent() const
Definition: route.hpp:62
shared_ptr< RibEntry > getParent() const
Definition: rib-entry.hpp:235
#define NFD_LOG_DEBUG
Definition: logger.hpp:38
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31
const Route & getRoute() const
Definition: rib-update.hpp:114
void onFibUpdateSuccess(const RibUpdateBatch &batch, const RibUpdateList &inheritedRoutes, const Rib::UpdateSuccessCallback &onSuccess)
Definition: rib.cpp:421
RibTable::const_iterator const_iterator
Definition: rib.hpp:64
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
bool operator<(const ReadvertisedRoute &lhs, const ReadvertisedRoute &rhs)
std::function< void()> UpdateSuccessCallback
Definition: rib.hpp:115
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
ndn::util::signal::Signal< Rib, Name > afterInsertEntry
signals after a RIB entry is inserted
Definition: rib.hpp:233
shared_ptr< RibEntry > findParent(const Name &prefix) const
Definition: rib.cpp:206