blob: 8d3b81854f082eb1ec91464c8e00702fbc626d9a [file] [log] [blame]
Vince Lehman76c751c2014-11-18 17:36:38 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa3148082018-04-12 18:21:54 -04002/*
Davide Pesavento45c1f6a2025-01-01 19:30:30 -05003 * Copyright (c) 2014-2025, Regents of the University of California,
Vince Lehman76c751c2014-11-18 17:36:38 -06004 * 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 "fib-updater.hpp"
Davide Pesavento2cae8ca2019-04-18 20:48:05 -040027#include "common/logger.hpp"
Vince Lehman76c751c2014-11-18 17:36:38 -060028
Davide Pesavento45c1f6a2025-01-01 19:30:30 -050029#include <ndn-cxx/mgmt/nfd/control-command.hpp>
Vince Lehman76c751c2014-11-18 17:36:38 -060030
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040031namespace nfd::rib {
Vince Lehman76c751c2014-11-18 17:36:38 -060032
Davide Pesaventoa3148082018-04-12 18:21:54 -040033NFD_LOG_INIT(FibUpdater);
Vince Lehman76c751c2014-11-18 17:36:38 -060034
Junxiao Shidf1dc652019-08-30 19:03:19 +000035constexpr int MAX_NUM_TIMEOUTS = 10;
36constexpr uint32_t ERROR_FACE_NOT_FOUND = 410;
Vince Lehman76c751c2014-11-18 17:36:38 -060037
38FibUpdater::FibUpdater(Rib& rib, ndn::nfd::Controller& controller)
39 : m_rib(rib)
40 , m_controller(controller)
41{
42 rib.setFibUpdater(this);
43}
44
45void
46FibUpdater::computeAndSendFibUpdates(const RibUpdateBatch& batch,
47 const FibUpdateSuccessCallback& onSuccess,
48 const FibUpdateFailureCallback& onFailure)
49{
50 m_batchFaceId = batch.getFaceId();
51
52 // Erase previously calculated inherited routes
53 m_inheritedRoutes.clear();
54
55 // Erase previously calculated FIB updates
56 m_updatesForBatchFaceId.clear();
57 m_updatesForNonBatchFaceId.clear();
58
59 computeUpdates(batch);
60
61 sendUpdatesForBatchFaceId(onSuccess, onFailure);
62}
63
64void
65FibUpdater::computeUpdates(const RibUpdateBatch& batch)
66{
Davide Pesavento21e24f92025-01-10 22:22:43 -050067 NFD_LOG_TRACE("Computing updates for batch with faceid=" << batch.getFaceId());
Vince Lehman76c751c2014-11-18 17:36:38 -060068
69 // Compute updates and add to m_fibUpdates
Junxiao Shi3f21e582017-05-29 15:26:32 +000070 for (const RibUpdate& update : batch) {
Davide Pesaventoc2442be2025-01-11 17:25:40 -050071 switch (update.action) {
Davide Pesavento21e24f92025-01-10 22:22:43 -050072 case RibUpdate::REGISTER:
73 computeUpdatesForRegistration(update);
74 break;
75 case RibUpdate::UNREGISTER:
76 computeUpdatesForUnregistration(update);
77 break;
78 case RibUpdate::REMOVE_FACE:
79 computeUpdatesForUnregistration(update);
80 // Do not apply updates with the same face ID as the destroyed face
81 // since they will be rejected by the FIB
82 m_updatesForBatchFaceId.clear();
83 break;
Vince Lehman76c751c2014-11-18 17:36:38 -060084 }
Junxiao Shi3f21e582017-05-29 15:26:32 +000085 }
Vince Lehman76c751c2014-11-18 17:36:38 -060086}
87
88void
89FibUpdater::computeUpdatesForRegistration(const RibUpdate& update)
90{
Davide Pesaventoc2442be2025-01-11 17:25:40 -050091 auto it = m_rib.find(update.name);
Vince Lehman76c751c2014-11-18 17:36:38 -060092
93 // Name prefix exists
94 if (it != m_rib.end()) {
95 shared_ptr<const RibEntry> entry(it->second);
Davide Pesaventoc2442be2025-01-11 17:25:40 -050096 auto existingRoute = entry->findRoute(update.route);
Vince Lehman76c751c2014-11-18 17:36:38 -060097
98 // Route will be new
99 if (existingRoute == entry->end()) {
100 // Will the new route change the namespace's capture flag?
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500101 bool willCaptureBeTurnedOn = (!entry->hasCapture() && update.route.isRibCapture());
Vince Lehman76c751c2014-11-18 17:36:38 -0600102
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500103 createFibUpdatesForNewRoute(*entry, update.route, willCaptureBeTurnedOn);
Vince Lehman76c751c2014-11-18 17:36:38 -0600104 }
105 else {
106 // Route already exists
107 RibEntry entryCopy = *entry;
108
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500109 Route& routeToUpdate = *entryCopy.findRoute(update.route);
110 routeToUpdate.flags = update.route.flags;
111 routeToUpdate.cost = update.route.cost;
112 routeToUpdate.expires = update.route.expires;
Vince Lehman76c751c2014-11-18 17:36:38 -0600113
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500114 createFibUpdatesForUpdatedRoute(entryCopy, update.route, *existingRoute);
Vince Lehman76c751c2014-11-18 17:36:38 -0600115 }
116 }
117 else {
118 // New name in RIB
119 // Find prefix's parent
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500120 shared_ptr<RibEntry> parent = m_rib.findParent(update.name);
Vince Lehman76c751c2014-11-18 17:36:38 -0600121
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500122 Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(update.name);
Vince Lehman76c751c2014-11-18 17:36:38 -0600123 Rib::RibEntryList children;
124
125 for (const auto& descendant : descendants) {
126 // If the child has the same parent as the new entry,
127 // the new entry must be the child's new parent
128 if (descendant->getParent() == parent) {
129 children.push_back(descendant);
130 }
131 }
132
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500133 createFibUpdatesForNewRibEntry(update.name, update.route, children);
Vince Lehman76c751c2014-11-18 17:36:38 -0600134 }
135}
136
137void
138FibUpdater::computeUpdatesForUnregistration(const RibUpdate& update)
139{
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500140 auto ribIt = m_rib.find(update.name);
Vince Lehman76c751c2014-11-18 17:36:38 -0600141
142 // Name prefix exists
143 if (ribIt != m_rib.end()) {
144 shared_ptr<const RibEntry> entry(ribIt->second);
Vince Lehman76c751c2014-11-18 17:36:38 -0600145 const bool hadCapture = entry->hasCapture();
146
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500147 auto existing = entry->findRoute(update.route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600148 if (existing != entry->end()) {
149 RibEntry temp = *entry;
150
151 // Erase route in temp entry
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500152 temp.eraseRoute(update.route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600153
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500154 bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
Vince Lehman76c751c2014-11-18 17:36:38 -0600155 createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
156
157 // The RibEntry still has the face ID; need to update FIB
158 // with lowest cost for the same face instead of removing the face from the FIB
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500159 const Route* next = entry->getRouteWithSecondLowestCostByFaceId(update.route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600160
161 if (next != nullptr) {
162 createFibUpdatesForNewRoute(temp, *next, false);
163 }
164
165 // The RibEntry will be empty after this removal
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500166 if (entry->getRoutes().size() == 1) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600167 createFibUpdatesForErasedRibEntry(*entry);
168 }
169 }
170 }
171}
172
173void
174FibUpdater::sendUpdates(const FibUpdateList& updates,
175 const FibUpdateSuccessCallback& onSuccess,
176 const FibUpdateFailureCallback& onFailure)
177{
Davide Pesavento191a7a22023-05-17 22:40:43 -0400178 NFD_LOG_DEBUG("Applying " << updates.size() << " FIB update(s)");
Vince Lehman76c751c2014-11-18 17:36:38 -0600179
180 for (const FibUpdate& update : updates) {
Davide Pesavento191a7a22023-05-17 22:40:43 -0400181 NFD_LOG_DEBUG("Sending " << update);
Vince Lehman76c751c2014-11-18 17:36:38 -0600182
183 if (update.action == FibUpdate::ADD_NEXTHOP) {
184 sendAddNextHopUpdate(update, onSuccess, onFailure);
185 }
186 else if (update.action == FibUpdate::REMOVE_NEXTHOP) {
187 sendRemoveNextHopUpdate(update, onSuccess, onFailure);
188 }
189 }
190}
191
192void
193FibUpdater::sendUpdatesForBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
194 const FibUpdateFailureCallback& onFailure)
195{
196 if (m_updatesForBatchFaceId.size() > 0) {
197 sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
198 }
199 else {
200 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
201 }
202}
203
204void
205FibUpdater::sendUpdatesForNonBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
206 const FibUpdateFailureCallback& onFailure)
207{
208 if (m_updatesForNonBatchFaceId.size() > 0) {
209 sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
210 }
211 else {
212 onSuccess(m_inheritedRoutes);
213 }
214}
215
216void
217FibUpdater::sendAddNextHopUpdate(const FibUpdate& update,
218 const FibUpdateSuccessCallback& onSuccess,
219 const FibUpdateFailureCallback& onFailure,
220 uint32_t nTimeouts)
221{
222 m_controller.start<ndn::nfd::FibAddNextHopCommand>(
223 ControlParameters()
224 .setName(update.name)
225 .setFaceId(update.faceId)
226 .setCost(update.cost),
Davide Pesavento412c9822021-07-02 00:21:05 -0400227 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
228 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600229}
230
231void
232FibUpdater::sendRemoveNextHopUpdate(const FibUpdate& update,
233 const FibUpdateSuccessCallback& onSuccess,
234 const FibUpdateFailureCallback& onFailure,
235 uint32_t nTimeouts)
236{
237 m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
238 ControlParameters()
239 .setName(update.name)
240 .setFaceId(update.faceId),
Davide Pesavento412c9822021-07-02 00:21:05 -0400241 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
242 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600243}
244
245void
Davide Pesavento412c9822021-07-02 00:21:05 -0400246FibUpdater::onUpdateSuccess(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600247 const FibUpdateSuccessCallback& onSuccess,
248 const FibUpdateFailureCallback& onFailure)
249{
250 if (update.faceId == m_batchFaceId) {
251 m_updatesForBatchFaceId.remove(update);
252
253 if (m_updatesForBatchFaceId.size() == 0) {
254 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
255 }
256 }
257 else {
258 m_updatesForNonBatchFaceId.remove(update);
259
260 if (m_updatesForNonBatchFaceId.size() == 0) {
261 onSuccess(m_inheritedRoutes);
262 }
263 }
264}
265
266void
Davide Pesavento412c9822021-07-02 00:21:05 -0400267FibUpdater::onUpdateError(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600268 const FibUpdateSuccessCallback& onSuccess,
269 const FibUpdateFailureCallback& onFailure,
Junxiao Shi29b41282016-08-22 03:47:02 +0000270 const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
Vince Lehman76c751c2014-11-18 17:36:38 -0600271{
Junxiao Shi29b41282016-08-22 03:47:02 +0000272 uint32_t code = response.getCode();
273 NFD_LOG_DEBUG("Failed to apply " << update <<
Davide Pesavento191a7a22023-05-17 22:40:43 -0400274 " [code: " << code << ", error: " << response.getText() << "]");
Vince Lehman76c751c2014-11-18 17:36:38 -0600275
276 if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts < MAX_NUM_TIMEOUTS) {
277 sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
278 }
279 else if (code == ERROR_FACE_NOT_FOUND) {
280 if (update.faceId == m_batchFaceId) {
Junxiao Shi29b41282016-08-22 03:47:02 +0000281 onFailure(code, response.getText());
Vince Lehman76c751c2014-11-18 17:36:38 -0600282 }
283 else {
284 m_updatesForNonBatchFaceId.remove(update);
285
286 if (m_updatesForNonBatchFaceId.size() == 0) {
287 onSuccess(m_inheritedRoutes);
288 }
289 }
290 }
291 else {
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500292 NDN_THROW(Error("Non-recoverable error " + std::to_string(code) + ": " + response.getText()));
Vince Lehman76c751c2014-11-18 17:36:38 -0600293 }
294}
295
296void
Davide Pesavento412c9822021-07-02 00:21:05 -0400297FibUpdater::addFibUpdate(const FibUpdate& update)
Vince Lehman76c751c2014-11-18 17:36:38 -0600298{
299 FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
300 m_updatesForNonBatchFaceId;
301
Davide Pesavento412c9822021-07-02 00:21:05 -0400302 // If an update with the same name and route already exists, replace it
303 auto it = std::find_if(updates.begin(), updates.end(),
Vince Lehman76c751c2014-11-18 17:36:38 -0600304 [&update] (const FibUpdate& other) {
305 return update.name == other.name && update.faceId == other.faceId;
306 });
307
308 if (it != updates.end()) {
309 FibUpdate& existingUpdate = *it;
310 existingUpdate.action = update.action;
311 existingUpdate.cost = update.cost;
312 }
313 else {
314 updates.push_back(update);
315 }
316}
317
318void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500319FibUpdater::addInheritedRoutes(const RibEntry& entry, const Rib::RouteSet& routesToAdd)
Vince Lehman76c751c2014-11-18 17:36:38 -0600320{
321 for (const Route& route : routesToAdd) {
322 // Don't add an ancestor faceId if the namespace has an entry for that faceId
323 if (!entry.hasFaceId(route.faceId)) {
324 // Create a record of the inherited route so it can be added to the RIB later
325 addInheritedRoute(entry.getName(), route);
326
327 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
328 }
329 }
330}
331
332void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500333FibUpdater::addInheritedRoutes(const Name& name, const Rib::RouteSet& routesToAdd,
Vince Lehman76c751c2014-11-18 17:36:38 -0600334 const Route& ignore)
335{
336 for (const Route& route : routesToAdd) {
337 if (route.faceId != ignore.faceId) {
338 // Create a record of the inherited route so it can be added to the RIB later
339 addInheritedRoute(name, route);
340
341 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
342 }
343 }
344}
345
346void
347FibUpdater::removeInheritedRoutes(const RibEntry& entry, const Rib::Rib::RouteSet& routesToRemove)
348{
349 for (const Route& route : routesToRemove) {
350 // Only remove if the route has been inherited
351 if (entry.hasInheritedRoute(route)) {
352 removeInheritedRoute(entry.getName(), route);
353 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
354 }
355 }
356}
357
358void
359FibUpdater::createFibUpdatesForNewRibEntry(const Name& name, const Route& route,
360 const Rib::RibEntryList& children)
361{
362 // Create FIB update for new entry
363 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
364
365 // No flags are set
Junxiao Shi3f21e582017-05-29 15:26:32 +0000366 if (!route.isChildInherit() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600367 // Add ancestor routes to self
368 addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
369 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000370 else if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600371 // Add route to children
372 Rib::RouteSet routesToAdd;
373 routesToAdd.insert(route);
374
375 // Remove routes blocked by capture and add self to children
376 modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
377 }
378 else if (route.isChildInherit()) {
379 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
380
381 // Add ancestor routes to self
382 addInheritedRoutes(name, ancestorRoutes, route);
383
384 // If there is an ancestor route which is the same as the new route, replace it
385 // with the new route
Davide Pesavento412c9822021-07-02 00:21:05 -0400386 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600387
388 // There is a route that needs to be overwritten, erase and then replace
389 if (it != ancestorRoutes.end()) {
390 ancestorRoutes.erase(it);
391 }
392
393 // Add new route to ancestor list so it can be added to children
394 ancestorRoutes.insert(route);
395
396 // Add ancestor routes to children
397 modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
398 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000399 else if (route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600400 // Remove routes blocked by capture
401 modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
402 }
403}
404
405void
406FibUpdater::createFibUpdatesForNewRoute(const RibEntry& entry, const Route& route,
407 bool captureWasTurnedOn)
408{
409 // Only update if the new route has a lower cost than a previously installed route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500410 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600411
412 Rib::RouteSet routesToAdd;
413 if (route.isChildInherit()) {
414 // Add to children if this new route doesn't override a previous lower cost, or
415 // add to children if this new route is lower cost than a previous route.
416 // Less than equal, since entry may find this route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500417 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600418 // Add self to children
419 routesToAdd.insert(route);
420 }
421 }
422
423 Rib::RouteSet routesToRemove;
424 if (captureWasTurnedOn) {
425 // Capture flag on
426 routesToRemove = m_rib.getAncestorRoutes(entry);
427
428 // Remove ancestor routes from self
429 removeInheritedRoutes(entry, routesToRemove);
430 }
431
432 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
433
434 // If another route with same faceId and lower cost exists, don't update.
435 // Must be done last so that add updates replace removal updates
436 // Create FIB update for new entry
Vince Lehman9dcfc402015-03-26 03:18:54 -0500437 const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600438
Vince Lehman9dcfc402015-03-26 03:18:54 -0500439 if (other == nullptr || route.cost <= other->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600440 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
441 }
442}
443
444void
445FibUpdater::createFibUpdatesForUpdatedRoute(const RibEntry& entry, const Route& route,
446 const Route& existingRoute)
447{
448 const bool costDidChange = (route.cost != existingRoute.cost);
449
450 // Look for an installed route with the lowest cost and child inherit set
Vince Lehman9dcfc402015-03-26 03:18:54 -0500451 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600452
453 // No flags changed and cost didn't change, no change in FIB
454 if (route.flags == existingRoute.flags && !costDidChange) {
455 return;
456 }
457
458 // Cost changed so create update for the entry itself
459 if (costDidChange) {
460 // Create update if this route's cost is lower than other routes
461 if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
462 // Create FIB update for the updated entry
463 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
464 }
465 else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
466 // Create update if this route used to be the lowest route but is no longer
467 // the lowest cost route.
468 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), prevRoute->faceId, prevRoute->cost));
469 }
470
471 // If another route with same faceId and lower cost and ChildInherit exists,
472 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500473 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600474 // If no flags changed but child inheritance is set, need to update children
475 // with new cost
476 if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
477 // Add self to children
478 Rib::RouteSet routesToAdd;
479 routesToAdd.insert(route);
480 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
481
482 return;
483 }
484 }
485 }
486
487 // Child inherit was turned on
488 if (!existingRoute.isChildInherit() && route.isChildInherit()) {
489 // If another route with same faceId and lower cost and ChildInherit exists,
490 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500491 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600492 // Add self to children
493 Rib::RouteSet routesToAdd;
494 routesToAdd.insert(route);
495 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
496 }
497 } // Child inherit was turned off
498 else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
499 // Remove self from children
500 Rib::RouteSet routesToRemove;
501 routesToRemove.insert(route);
502
503 Rib::RouteSet routesToAdd;
504 // If another route with same faceId and ChildInherit exists, update children with this route.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500505 if (prevRoute != nullptr) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600506 routesToAdd.insert(*prevRoute);
507 }
508 else {
509 // Look for an ancestor that was blocked previously
510 const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
Davide Pesavento412c9822021-07-02 00:21:05 -0400511 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600512
513 // If an ancestor is found, add it to children
514 if (it != ancestorRoutes.end()) {
515 routesToAdd.insert(*it);
516 }
517 }
518
519 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
520 }
521
522 // Capture was turned on
Junxiao Shi3f21e582017-05-29 15:26:32 +0000523 if (!existingRoute.isRibCapture() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600524 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
525
526 // Remove ancestor routes from self
527 removeInheritedRoutes(entry, ancestorRoutes);
528
529 // Remove ancestor routes from children
530 modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
531 } // Capture was turned off
Junxiao Shi3f21e582017-05-29 15:26:32 +0000532 else if (existingRoute.isRibCapture() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600533 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
534
535 // Add ancestor routes to self
536 addInheritedRoutes(entry, ancestorRoutes);
537
538 // Add ancestor routes to children
539 modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
540 }
541}
542
543void
544FibUpdater::createFibUpdatesForErasedRoute(const RibEntry& entry, const Route& route,
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400545 bool captureWasTurnedOff)
Vince Lehman76c751c2014-11-18 17:36:38 -0600546{
547 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
548
Junxiao Shi3f21e582017-05-29 15:26:32 +0000549 if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600550 // Remove self from children
551 Rib::RouteSet routesToRemove;
552 routesToRemove.insert(route);
553
Vince Lehman9aac8732016-01-11 15:49:23 -0600554 // If capture is turned off for the route and another route is installed in the RibEntry,
555 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600556 Rib::RouteSet routesToAdd;
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500557 if (captureWasTurnedOff && !entry.empty()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600558 // Look for an ancestors that were blocked previously
559 routesToAdd = m_rib.getAncestorRoutes(entry);
560
561 // Add ancestor routes to self
562 addInheritedRoutes(entry, routesToAdd);
563 }
564
565 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
566 }
567 else if (route.isChildInherit()) {
568 // If not blocked by capture, add inherited routes to children
569 Rib::RouteSet routesToAdd;
570 if (!entry.hasCapture()) {
571 routesToAdd = m_rib.getAncestorRoutes(entry);
572 }
573
574 Rib::RouteSet routesToRemove;
575 routesToRemove.insert(route);
576
577 // Add ancestor routes to children
578 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
579 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000580 else if (route.isRibCapture()) {
Vince Lehman9aac8732016-01-11 15:49:23 -0600581 // If capture is turned off for the route and another route is installed in the RibEntry,
582 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600583 Rib::RouteSet routesToAdd;
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500584 if (captureWasTurnedOff && !entry.empty()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600585 // Look for an ancestors that were blocked previously
586 routesToAdd = m_rib.getAncestorRoutes(entry);
587
588 // Add ancestor routes to self
589 addInheritedRoutes(entry, routesToAdd);
590 }
591
592 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
593 }
594
595 // Need to check if the removed route was blocking an inherited route
596 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
597
Vince Lehmanf91ab742015-04-23 15:26:55 -0500598 // If the current entry has capture set or is pending removal, don't add inherited route
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500599 if (!entry.hasCapture() && !entry.empty()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600600 // If there is an ancestor route which is the same as the erased route, add that route
601 // to the current entry
Davide Pesavento412c9822021-07-02 00:21:05 -0400602 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600603 if (it != ancestorRoutes.end()) {
604 addInheritedRoute(entry.getName(), *it);
605 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), it->faceId, it->cost));
606 }
607 }
608}
609
610void
611FibUpdater::createFibUpdatesForErasedRibEntry(const RibEntry& entry)
612{
613 for (const Route& route : entry.getInheritedRoutes()) {
614 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
615 }
616}
617
618void
619FibUpdater::modifyChildrensInheritedRoutes(const Rib::RibEntryList& children,
620 const Rib::RouteSet& routesToAdd,
621 const Rib::RouteSet& routesToRemove)
622{
623 for (const auto& child : children) {
624 traverseSubTree(*child, routesToAdd, routesToRemove);
625 }
626}
627
628void
629FibUpdater::traverseSubTree(const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
630 Rib::Rib::RouteSet routesToRemove)
631{
632 // If a route on the namespace has the capture flag set, ignore self and children
633 if (entry.hasCapture()) {
634 return;
635 }
636
637 // Remove inherited routes from current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400638 for (auto removeIt = routesToRemove.begin(); removeIt != routesToRemove.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600639 // If a route on the namespace has the same face ID and child inheritance set,
640 // ignore this route
641 if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400642 removeIt = routesToRemove.erase(removeIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600643 continue;
644 }
645
646 // Only remove route if it removes an existing inherited route
647 if (entry.hasInheritedRoute(*removeIt)) {
648 removeInheritedRoute(entry.getName(), *removeIt);
649 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), removeIt->faceId));
650 }
651
652 ++removeIt;
653 }
654
655 // Add inherited routes to current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400656 for (auto addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600657 // If a route on the namespace has the same face ID and child inherit set, ignore this face
658 if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400659 addIt = routesToAdd.erase(addIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600660 continue;
661 }
662
663 // Only add route if it does not override an existing route
664 if (!entry.hasFaceId(addIt->faceId)) {
665 addInheritedRoute(entry.getName(), *addIt);
666 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), addIt->faceId, addIt->cost));
667 }
668
669 ++addIt;
670 }
671
672 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
673}
674
675void
676FibUpdater::addInheritedRoute(const Name& name, const Route& route)
677{
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500678 m_inheritedRoutes.push_back({RibUpdate::REGISTER, name, route});
Vince Lehman76c751c2014-11-18 17:36:38 -0600679}
680
681void
682FibUpdater::removeInheritedRoute(const Name& name, const Route& route)
683{
Davide Pesaventoc2442be2025-01-11 17:25:40 -0500684 m_inheritedRoutes.push_back({RibUpdate::UNREGISTER, name, route});
Vince Lehman76c751c2014-11-18 17:36:38 -0600685}
686
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400687} // namespace nfd::rib