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