NFD: Named Data Networking Forwarding Daemon 24.07-28-gdcc0e6e0
Loading...
Searching...
No Matches
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-2025, 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
30namespace nfd::rib {
31
32NFD_LOG_INIT(Rib);
33
34static inline bool
35sortRoutes(const Route& lhs, const Route& rhs)
36{
37 return lhs.faceId < rhs.faceId;
38}
39
40void
42{
43 m_fibUpdater = updater;
44}
45
47Rib::find(const Name& prefix) const
48{
49 return m_rib.find(prefix);
50}
51
52Route*
53Rib::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
69Route*
70Rib::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
83void
84Rib::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
151void
152Rib::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->empty()) {
183 eraseEntry(ribIt);
184 }
185 }
186}
187
188void
189Rib::onRouteExpiration(const Name& prefix, const Route& route)
190{
191 NFD_LOG_DEBUG(route << " for " << prefix << " has expired");
192 beginApplyUpdate({RibUpdate::UNREGISTER, prefix, route}, nullptr, nullptr);
193}
194
195shared_ptr<RibEntry>
196Rib::findParent(const Name& prefix) const
197{
198 for (int i = prefix.size() - 1; i >= 0; i--) {
199 auto it = m_rib.find(prefix.getPrefix(i));
200 if (it != m_rib.end()) {
201 return it->second;
202 }
203 }
204
205 return nullptr;
206}
207
208std::list<shared_ptr<RibEntry>>
209Rib::findDescendants(const Name& prefix) const
210{
211 std::list<shared_ptr<RibEntry>> children;
212
213 auto it = m_rib.find(prefix);
214 if (it != m_rib.end()) {
215 ++it;
216 for (; it != m_rib.end(); ++it) {
217 if (prefix.isPrefixOf(it->first)) {
218 children.push_back(it->second);
219 }
220 else {
221 break;
222 }
223 }
224 }
225
226 return children;
227}
228
229std::list<shared_ptr<RibEntry>>
230Rib::findDescendantsForNonInsertedName(const Name& prefix) const
231{
232 std::list<shared_ptr<RibEntry>> children;
233
234 for (const auto& [name, ribEntry] : m_rib) {
235 if (prefix.isPrefixOf(name)) {
236 children.push_back(ribEntry);
237 }
238 }
239
240 return children;
241}
242
243Rib::RibTable::iterator
244Rib::eraseEntry(RibTable::iterator it)
245{
246 // Entry does not exist
247 if (it == m_rib.end()) {
248 return m_rib.end();
249 }
250
251 shared_ptr<RibEntry> entry(it->second);
252 shared_ptr<RibEntry> parent = entry->getParent();
253
254 // Remove self from parent's children
255 if (parent != nullptr) {
256 parent->removeChild(entry);
257 }
258
259 for (auto childIt = entry->getChildren().begin(); childIt != entry->getChildren().end(); ) {
260 shared_ptr<RibEntry> child = *childIt;
261
262 // Advance iterator so it is not invalidated by removal
263 ++childIt;
264
265 // Remove children from self
266 entry->removeChild(child);
267
268 // Update parent's children
269 if (parent != nullptr) {
270 parent->addChild(child);
271 }
272 }
273
274 auto nextIt = m_rib.erase(it);
275
276 // do something after erasing an entry
277 afterEraseEntry(entry->getName());
278
279 return nextIt;
280}
281
282Rib::RouteSet
283Rib::getAncestorRoutes(const RibEntry& entry) const
284{
285 RouteSet ancestorRoutes(&sortRoutes);
286
287 auto parent = entry.getParent();
288 while (parent != nullptr) {
289 for (const auto& route : parent->getRoutes()) {
290 if (route.isChildInherit()) {
291 ancestorRoutes.insert(route);
292 }
293 }
294
295 if (parent->hasCapture()) {
296 break;
297 }
298
299 parent = parent->getParent();
300 }
301
302 return ancestorRoutes;
303}
304
305Rib::RouteSet
306Rib::getAncestorRoutes(const Name& name) const
307{
308 RouteSet ancestorRoutes(&sortRoutes);
309
310 auto parent = findParent(name);
311 while (parent != nullptr) {
312 for (const auto& route : parent->getRoutes()) {
313 if (route.isChildInherit()) {
314 ancestorRoutes.insert(route);
315 }
316 }
317
318 if (parent->hasCapture()) {
319 break;
320 }
321
322 parent = parent->getParent();
323 }
324
325 return ancestorRoutes;
326}
327
328void
330 const Rib::UpdateSuccessCallback& onSuccess,
331 const Rib::UpdateFailureCallback& onFailure)
332{
333 BOOST_ASSERT(m_fibUpdater != nullptr);
334 addUpdateToQueue(update, onSuccess, onFailure);
335 sendBatchFromQueue();
336}
337
338void
339Rib::beginRemoveFace(uint64_t faceId)
340{
341 auto range = m_faceEntries.equal_range(faceId);
342 for (auto it = range.first; it != range.second; ++it) {
343 enqueueRemoveFace(*it->second, faceId);
344 }
345 sendBatchFromQueue();
346}
347
348void
349Rib::beginRemoveFailedFaces(const std::set<uint64_t>& activeFaceIds)
350{
351 for (const auto& [faceId, ribEntry] : m_faceEntries) {
352 if (activeFaceIds.count(faceId) > 0) {
353 continue;
354 }
355 enqueueRemoveFace(*ribEntry, faceId);
356 }
357 sendBatchFromQueue();
358}
359
360void
361Rib::enqueueRemoveFace(const RibEntry& entry, uint64_t faceId)
362{
363 for (const Route& route : entry) {
364 if (route.faceId != faceId) {
365 continue;
366 }
367 addUpdateToQueue({RibUpdate::REMOVE_FACE, entry.getName(), route}, nullptr, nullptr);
368 }
369}
370
371void
372Rib::addUpdateToQueue(const RibUpdate& update,
373 const Rib::UpdateSuccessCallback& onSuccess,
374 const Rib::UpdateFailureCallback& onFailure)
375{
376 RibUpdateBatch batch(update.route.faceId);
377 batch.add(update);
378
379 UpdateQueueItem item{batch, onSuccess, onFailure};
380 m_updateBatches.push_back(std::move(item));
381}
382
383void
384Rib::sendBatchFromQueue()
385{
386 if (m_updateBatches.empty() || m_isUpdateInProgress) {
387 return;
388 }
389
390 m_isUpdateInProgress = true;
391
392 UpdateQueueItem item = std::move(m_updateBatches.front());
393 m_updateBatches.pop_front();
394
395 // Until task #1698, each RibUpdateBatch contains exactly one RIB update
396 BOOST_ASSERT(item.batch.size() == 1);
397
398 m_fibUpdater->computeAndSendFibUpdates(item.batch,
399 [this, batch = item.batch, successCb = item.managerSuccessCallback] (const auto& routes) {
400 onFibUpdateSuccess(batch, routes, successCb);
401 },
402 [this, failureCb = item.managerFailureCallback] (const auto& code, const auto& error) {
403 onFibUpdateFailure(failureCb, code, error);
404 });
405}
406
407void
408Rib::onFibUpdateSuccess(const RibUpdateBatch& batch,
409 const RibUpdateList& inheritedRoutes,
410 const Rib::UpdateSuccessCallback& onSuccess)
411{
412 for (const RibUpdate& update : batch) {
413 switch (update.action) {
415 insert(update.name, update.route);
416 break;
419 erase(update.name, update.route);
420 break;
421 }
422 }
423
424 // Add and remove precalculated inherited routes to RibEntries
425 modifyInheritedRoutes(inheritedRoutes);
426
427 m_isUpdateInProgress = false;
428
429 if (onSuccess != nullptr) {
430 onSuccess();
431 }
432
433 // Try to advance the batch queue
434 sendBatchFromQueue();
435}
436
437void
438Rib::onFibUpdateFailure(const Rib::UpdateFailureCallback& onFailure,
439 uint32_t code, const std::string& error)
440{
441 m_isUpdateInProgress = false;
442
443 if (onFailure != nullptr) {
444 onFailure(code, error);
445 }
446
447 // Try to advance the batch queue
448 sendBatchFromQueue();
449}
450
451void
452Rib::modifyInheritedRoutes(const RibUpdateList& inheritedRoutes)
453{
454 for (const RibUpdate& update : inheritedRoutes) {
455 auto ribIt = m_rib.find(update.name);
456 BOOST_ASSERT(ribIt != m_rib.end());
457 shared_ptr<RibEntry> entry(ribIt->second);
458
459 switch (update.action) {
461 entry->addInheritedRoute(update.route);
462 break;
464 entry->removeInheritedRoute(update.route);
465 break;
467 break;
468 }
469 }
470}
471
472std::ostream&
473operator<<(std::ostream& os, const Rib& rib)
474{
475 for (const auto& item : rib) {
476 os << *item.second << "\n";
477 }
478 return os;
479}
480
481} // namespace nfd::rib
Computes FibUpdates based on updates to the RIB and sends them to NFD.
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.
Represents a RIB entry, which contains one or more Routes with the same prefix.
Definition rib-entry.hpp:39
void addInheritedRoute(const Route &route)
void removeInheritedRoute(const Route &route)
const Name & getName() const noexcept
Definition rib-entry.hpp:46
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:349
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:339
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:329
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:196
Represents a route for a name prefix.
Definition route.hpp:44
uint64_t faceId
Definition route.hpp:96
#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)
std::list< RibUpdate > RibUpdateList
static bool sortRoutes(const Route &lhs, const Route &rhs)
Definition rib.cpp:35
References a route.
Definition rib.hpp:47
Represents a route that will be added to or removed from a namespace.
@ REMOVE_FACE
An update triggered by a face destruction notification.