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