blob: a2657a1e8361a2eabe261f006cfc1f479ffc1378 [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 Pesavento2c9d2ca2024-01-27 16:36:51 -05003 * Copyright (c) 2014-2024, 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
Junxiao Shi25c6ce42016-09-09 13:49:59 +000029#include <ndn-cxx/mgmt/nfd/control-parameters.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
Davide Pesaventoa3148082018-04-12 18:21:54 -040035using ndn::nfd::ControlParameters;
Vince Lehman76c751c2014-11-18 17:36:38 -060036
Junxiao Shidf1dc652019-08-30 19:03:19 +000037constexpr int MAX_NUM_TIMEOUTS = 10;
38constexpr uint32_t ERROR_FACE_NOT_FOUND = 410;
Vince Lehman76c751c2014-11-18 17:36:38 -060039
40FibUpdater::FibUpdater(Rib& rib, ndn::nfd::Controller& controller)
41 : m_rib(rib)
42 , m_controller(controller)
43{
44 rib.setFibUpdater(this);
45}
46
47void
48FibUpdater::computeAndSendFibUpdates(const RibUpdateBatch& batch,
49 const FibUpdateSuccessCallback& onSuccess,
50 const FibUpdateFailureCallback& onFailure)
51{
52 m_batchFaceId = batch.getFaceId();
53
54 // Erase previously calculated inherited routes
55 m_inheritedRoutes.clear();
56
57 // Erase previously calculated FIB updates
58 m_updatesForBatchFaceId.clear();
59 m_updatesForNonBatchFaceId.clear();
60
61 computeUpdates(batch);
62
63 sendUpdatesForBatchFaceId(onSuccess, onFailure);
64}
65
66void
67FibUpdater::computeUpdates(const RibUpdateBatch& batch)
68{
69 NFD_LOG_DEBUG("Computing updates for batch with faceID: " << batch.getFaceId());
70
71 // Compute updates and add to m_fibUpdates
Junxiao Shi3f21e582017-05-29 15:26:32 +000072 for (const RibUpdate& update : batch) {
73 switch (update.getAction()) {
Vince Lehman76c751c2014-11-18 17:36:38 -060074 case RibUpdate::REGISTER:
75 computeUpdatesForRegistration(update);
76 break;
77 case RibUpdate::UNREGISTER:
78 computeUpdatesForUnregistration(update);
79 break;
80 case RibUpdate::REMOVE_FACE:
81 computeUpdatesForUnregistration(update);
82
83 // Do not apply updates with the same face ID as the destroyed face
84 // since they will be rejected by the FIB
85 m_updatesForBatchFaceId.clear();
86 break;
Vince Lehman76c751c2014-11-18 17:36:38 -060087 }
Junxiao Shi3f21e582017-05-29 15:26:32 +000088 }
Vince Lehman76c751c2014-11-18 17:36:38 -060089}
90
91void
92FibUpdater::computeUpdatesForRegistration(const RibUpdate& update)
93{
94 const Name& prefix = update.getName();
95 const Route& route = update.getRoute();
96
Davide Pesavento412c9822021-07-02 00:21:05 -040097 auto it = m_rib.find(prefix);
Vince Lehman76c751c2014-11-18 17:36:38 -060098
99 // Name prefix exists
100 if (it != m_rib.end()) {
101 shared_ptr<const RibEntry> entry(it->second);
102
Davide Pesavento412c9822021-07-02 00:21:05 -0400103 auto existingRoute = entry->findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600104
105 // Route will be new
106 if (existingRoute == entry->end()) {
107 // Will the new route change the namespace's capture flag?
Junxiao Shi3f21e582017-05-29 15:26:32 +0000108 bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isRibCapture());
Vince Lehman76c751c2014-11-18 17:36:38 -0600109
110 createFibUpdatesForNewRoute(*entry, route, willCaptureBeTurnedOn);
111 }
112 else {
113 // Route already exists
114 RibEntry entryCopy = *entry;
115
Davide Pesavento412c9822021-07-02 00:21:05 -0400116 Route& routeToUpdate = *entryCopy.findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600117 routeToUpdate.flags = route.flags;
118 routeToUpdate.cost = route.cost;
119 routeToUpdate.expires = route.expires;
120
121 createFibUpdatesForUpdatedRoute(entryCopy, route, *existingRoute);
122 }
123 }
124 else {
125 // New name in RIB
126 // Find prefix's parent
127 shared_ptr<RibEntry> parent = m_rib.findParent(prefix);
128
129 Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(prefix);
130 Rib::RibEntryList children;
131
132 for (const auto& descendant : descendants) {
133 // If the child has the same parent as the new entry,
134 // the new entry must be the child's new parent
135 if (descendant->getParent() == parent) {
136 children.push_back(descendant);
137 }
138 }
139
140 createFibUpdatesForNewRibEntry(prefix, route, children);
141 }
142}
143
144void
145FibUpdater::computeUpdatesForUnregistration(const RibUpdate& update)
146{
147 const Name& prefix = update.getName();
148 const Route& route = update.getRoute();
149
Davide Pesavento412c9822021-07-02 00:21:05 -0400150 auto ribIt = m_rib.find(prefix);
Vince Lehman76c751c2014-11-18 17:36:38 -0600151
152 // Name prefix exists
153 if (ribIt != m_rib.end()) {
154 shared_ptr<const RibEntry> entry(ribIt->second);
Vince Lehman76c751c2014-11-18 17:36:38 -0600155 const bool hadCapture = entry->hasCapture();
156
Davide Pesavento412c9822021-07-02 00:21:05 -0400157 auto existing = entry->findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600158 if (existing != entry->end()) {
159 RibEntry temp = *entry;
160
161 // Erase route in temp entry
162 temp.eraseRoute(route);
163
164 const bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
165
166 createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
167
168 // The RibEntry still has the face ID; need to update FIB
169 // with lowest cost for the same face instead of removing the face from the FIB
170 const Route* next = entry->getRouteWithSecondLowestCostByFaceId(route.faceId);
171
172 if (next != nullptr) {
173 createFibUpdatesForNewRoute(temp, *next, false);
174 }
175
176 // The RibEntry will be empty after this removal
177 if (entry->getNRoutes() == 1) {
178 createFibUpdatesForErasedRibEntry(*entry);
179 }
180 }
181 }
182}
183
184void
185FibUpdater::sendUpdates(const FibUpdateList& updates,
186 const FibUpdateSuccessCallback& onSuccess,
187 const FibUpdateFailureCallback& onFailure)
188{
Davide Pesavento191a7a22023-05-17 22:40:43 -0400189 NFD_LOG_DEBUG("Applying " << updates.size() << " FIB update(s)");
Vince Lehman76c751c2014-11-18 17:36:38 -0600190
191 for (const FibUpdate& update : updates) {
Davide Pesavento191a7a22023-05-17 22:40:43 -0400192 NFD_LOG_DEBUG("Sending " << update);
Vince Lehman76c751c2014-11-18 17:36:38 -0600193
194 if (update.action == FibUpdate::ADD_NEXTHOP) {
195 sendAddNextHopUpdate(update, onSuccess, onFailure);
196 }
197 else if (update.action == FibUpdate::REMOVE_NEXTHOP) {
198 sendRemoveNextHopUpdate(update, onSuccess, onFailure);
199 }
200 }
201}
202
203void
204FibUpdater::sendUpdatesForBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
205 const FibUpdateFailureCallback& onFailure)
206{
207 if (m_updatesForBatchFaceId.size() > 0) {
208 sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
209 }
210 else {
211 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
212 }
213}
214
215void
216FibUpdater::sendUpdatesForNonBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
217 const FibUpdateFailureCallback& onFailure)
218{
219 if (m_updatesForNonBatchFaceId.size() > 0) {
220 sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
221 }
222 else {
223 onSuccess(m_inheritedRoutes);
224 }
225}
226
227void
228FibUpdater::sendAddNextHopUpdate(const FibUpdate& update,
229 const FibUpdateSuccessCallback& onSuccess,
230 const FibUpdateFailureCallback& onFailure,
231 uint32_t nTimeouts)
232{
233 m_controller.start<ndn::nfd::FibAddNextHopCommand>(
234 ControlParameters()
235 .setName(update.name)
236 .setFaceId(update.faceId)
237 .setCost(update.cost),
Davide Pesavento412c9822021-07-02 00:21:05 -0400238 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
239 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600240}
241
242void
243FibUpdater::sendRemoveNextHopUpdate(const FibUpdate& update,
244 const FibUpdateSuccessCallback& onSuccess,
245 const FibUpdateFailureCallback& onFailure,
246 uint32_t nTimeouts)
247{
248 m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
249 ControlParameters()
250 .setName(update.name)
251 .setFaceId(update.faceId),
Davide Pesavento412c9822021-07-02 00:21:05 -0400252 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
253 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600254}
255
256void
Davide Pesavento412c9822021-07-02 00:21:05 -0400257FibUpdater::onUpdateSuccess(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600258 const FibUpdateSuccessCallback& onSuccess,
259 const FibUpdateFailureCallback& onFailure)
260{
261 if (update.faceId == m_batchFaceId) {
262 m_updatesForBatchFaceId.remove(update);
263
264 if (m_updatesForBatchFaceId.size() == 0) {
265 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
266 }
267 }
268 else {
269 m_updatesForNonBatchFaceId.remove(update);
270
271 if (m_updatesForNonBatchFaceId.size() == 0) {
272 onSuccess(m_inheritedRoutes);
273 }
274 }
275}
276
277void
Davide Pesavento412c9822021-07-02 00:21:05 -0400278FibUpdater::onUpdateError(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600279 const FibUpdateSuccessCallback& onSuccess,
280 const FibUpdateFailureCallback& onFailure,
Junxiao Shi29b41282016-08-22 03:47:02 +0000281 const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
Vince Lehman76c751c2014-11-18 17:36:38 -0600282{
Junxiao Shi29b41282016-08-22 03:47:02 +0000283 uint32_t code = response.getCode();
284 NFD_LOG_DEBUG("Failed to apply " << update <<
Davide Pesavento191a7a22023-05-17 22:40:43 -0400285 " [code: " << code << ", error: " << response.getText() << "]");
Vince Lehman76c751c2014-11-18 17:36:38 -0600286
287 if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts < MAX_NUM_TIMEOUTS) {
288 sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
289 }
290 else if (code == ERROR_FACE_NOT_FOUND) {
291 if (update.faceId == m_batchFaceId) {
Junxiao Shi29b41282016-08-22 03:47:02 +0000292 onFailure(code, response.getText());
Vince Lehman76c751c2014-11-18 17:36:38 -0600293 }
294 else {
295 m_updatesForNonBatchFaceId.remove(update);
296
297 if (m_updatesForNonBatchFaceId.size() == 0) {
298 onSuccess(m_inheritedRoutes);
299 }
300 }
301 }
302 else {
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500303 NDN_THROW(Error("Non-recoverable error " + std::to_string(code) + ": " + response.getText()));
Vince Lehman76c751c2014-11-18 17:36:38 -0600304 }
305}
306
307void
Davide Pesavento412c9822021-07-02 00:21:05 -0400308FibUpdater::addFibUpdate(const FibUpdate& update)
Vince Lehman76c751c2014-11-18 17:36:38 -0600309{
310 FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
311 m_updatesForNonBatchFaceId;
312
Davide Pesavento412c9822021-07-02 00:21:05 -0400313 // If an update with the same name and route already exists, replace it
314 auto it = std::find_if(updates.begin(), updates.end(),
Vince Lehman76c751c2014-11-18 17:36:38 -0600315 [&update] (const FibUpdate& other) {
316 return update.name == other.name && update.faceId == other.faceId;
317 });
318
319 if (it != updates.end()) {
320 FibUpdate& existingUpdate = *it;
321 existingUpdate.action = update.action;
322 existingUpdate.cost = update.cost;
323 }
324 else {
325 updates.push_back(update);
326 }
327}
328
329void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500330FibUpdater::addInheritedRoutes(const RibEntry& entry, const Rib::RouteSet& routesToAdd)
Vince Lehman76c751c2014-11-18 17:36:38 -0600331{
332 for (const Route& route : routesToAdd) {
333 // Don't add an ancestor faceId if the namespace has an entry for that faceId
334 if (!entry.hasFaceId(route.faceId)) {
335 // Create a record of the inherited route so it can be added to the RIB later
336 addInheritedRoute(entry.getName(), route);
337
338 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
339 }
340 }
341}
342
343void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500344FibUpdater::addInheritedRoutes(const Name& name, const Rib::RouteSet& routesToAdd,
Vince Lehman76c751c2014-11-18 17:36:38 -0600345 const Route& ignore)
346{
347 for (const Route& route : routesToAdd) {
348 if (route.faceId != ignore.faceId) {
349 // Create a record of the inherited route so it can be added to the RIB later
350 addInheritedRoute(name, route);
351
352 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
353 }
354 }
355}
356
357void
358FibUpdater::removeInheritedRoutes(const RibEntry& entry, const Rib::Rib::RouteSet& routesToRemove)
359{
360 for (const Route& route : routesToRemove) {
361 // Only remove if the route has been inherited
362 if (entry.hasInheritedRoute(route)) {
363 removeInheritedRoute(entry.getName(), route);
364 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
365 }
366 }
367}
368
369void
370FibUpdater::createFibUpdatesForNewRibEntry(const Name& name, const Route& route,
371 const Rib::RibEntryList& children)
372{
373 // Create FIB update for new entry
374 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
375
376 // No flags are set
Junxiao Shi3f21e582017-05-29 15:26:32 +0000377 if (!route.isChildInherit() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600378 // Add ancestor routes to self
379 addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
380 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000381 else if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600382 // Add route to children
383 Rib::RouteSet routesToAdd;
384 routesToAdd.insert(route);
385
386 // Remove routes blocked by capture and add self to children
387 modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
388 }
389 else if (route.isChildInherit()) {
390 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
391
392 // Add ancestor routes to self
393 addInheritedRoutes(name, ancestorRoutes, route);
394
395 // If there is an ancestor route which is the same as the new route, replace it
396 // with the new route
Davide Pesavento412c9822021-07-02 00:21:05 -0400397 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600398
399 // There is a route that needs to be overwritten, erase and then replace
400 if (it != ancestorRoutes.end()) {
401 ancestorRoutes.erase(it);
402 }
403
404 // Add new route to ancestor list so it can be added to children
405 ancestorRoutes.insert(route);
406
407 // Add ancestor routes to children
408 modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
409 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000410 else if (route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600411 // Remove routes blocked by capture
412 modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
413 }
414}
415
416void
417FibUpdater::createFibUpdatesForNewRoute(const RibEntry& entry, const Route& route,
418 bool captureWasTurnedOn)
419{
420 // Only update if the new route has a lower cost than a previously installed route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500421 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600422
423 Rib::RouteSet routesToAdd;
424 if (route.isChildInherit()) {
425 // Add to children if this new route doesn't override a previous lower cost, or
426 // add to children if this new route is lower cost than a previous route.
427 // Less than equal, since entry may find this route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500428 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600429 // Add self to children
430 routesToAdd.insert(route);
431 }
432 }
433
434 Rib::RouteSet routesToRemove;
435 if (captureWasTurnedOn) {
436 // Capture flag on
437 routesToRemove = m_rib.getAncestorRoutes(entry);
438
439 // Remove ancestor routes from self
440 removeInheritedRoutes(entry, routesToRemove);
441 }
442
443 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
444
445 // If another route with same faceId and lower cost exists, don't update.
446 // Must be done last so that add updates replace removal updates
447 // Create FIB update for new entry
Vince Lehman9dcfc402015-03-26 03:18:54 -0500448 const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600449
Vince Lehman9dcfc402015-03-26 03:18:54 -0500450 if (other == nullptr || route.cost <= other->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600451 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
452 }
453}
454
455void
456FibUpdater::createFibUpdatesForUpdatedRoute(const RibEntry& entry, const Route& route,
457 const Route& existingRoute)
458{
459 const bool costDidChange = (route.cost != existingRoute.cost);
460
461 // Look for an installed route with the lowest cost and child inherit set
Vince Lehman9dcfc402015-03-26 03:18:54 -0500462 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600463
464 // No flags changed and cost didn't change, no change in FIB
465 if (route.flags == existingRoute.flags && !costDidChange) {
466 return;
467 }
468
469 // Cost changed so create update for the entry itself
470 if (costDidChange) {
471 // Create update if this route's cost is lower than other routes
472 if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
473 // Create FIB update for the updated entry
474 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
475 }
476 else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
477 // Create update if this route used to be the lowest route but is no longer
478 // the lowest cost route.
479 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), prevRoute->faceId, prevRoute->cost));
480 }
481
482 // If another route with same faceId and lower cost and ChildInherit exists,
483 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500484 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600485 // If no flags changed but child inheritance is set, need to update children
486 // with new cost
487 if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
488 // Add self to children
489 Rib::RouteSet routesToAdd;
490 routesToAdd.insert(route);
491 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
492
493 return;
494 }
495 }
496 }
497
498 // Child inherit was turned on
499 if (!existingRoute.isChildInherit() && route.isChildInherit()) {
500 // If another route with same faceId and lower cost and ChildInherit exists,
501 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500502 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600503 // Add self to children
504 Rib::RouteSet routesToAdd;
505 routesToAdd.insert(route);
506 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
507 }
508 } // Child inherit was turned off
509 else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
510 // Remove self from children
511 Rib::RouteSet routesToRemove;
512 routesToRemove.insert(route);
513
514 Rib::RouteSet routesToAdd;
515 // If another route with same faceId and ChildInherit exists, update children with this route.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500516 if (prevRoute != nullptr) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600517 routesToAdd.insert(*prevRoute);
518 }
519 else {
520 // Look for an ancestor that was blocked previously
521 const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
Davide Pesavento412c9822021-07-02 00:21:05 -0400522 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600523
524 // If an ancestor is found, add it to children
525 if (it != ancestorRoutes.end()) {
526 routesToAdd.insert(*it);
527 }
528 }
529
530 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
531 }
532
533 // Capture was turned on
Junxiao Shi3f21e582017-05-29 15:26:32 +0000534 if (!existingRoute.isRibCapture() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600535 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
536
537 // Remove ancestor routes from self
538 removeInheritedRoutes(entry, ancestorRoutes);
539
540 // Remove ancestor routes from children
541 modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
542 } // Capture was turned off
Junxiao Shi3f21e582017-05-29 15:26:32 +0000543 else if (existingRoute.isRibCapture() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600544 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
545
546 // Add ancestor routes to self
547 addInheritedRoutes(entry, ancestorRoutes);
548
549 // Add ancestor routes to children
550 modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
551 }
552}
553
554void
555FibUpdater::createFibUpdatesForErasedRoute(const RibEntry& entry, const Route& route,
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400556 bool captureWasTurnedOff)
Vince Lehman76c751c2014-11-18 17:36:38 -0600557{
558 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
559
Junxiao Shi3f21e582017-05-29 15:26:32 +0000560 if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600561 // Remove self from children
562 Rib::RouteSet routesToRemove;
563 routesToRemove.insert(route);
564
Vince Lehman9aac8732016-01-11 15:49:23 -0600565 // If capture is turned off for the route and another route is installed in the RibEntry,
566 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600567 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600568 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600569 // Look for an ancestors that were blocked previously
570 routesToAdd = m_rib.getAncestorRoutes(entry);
571
572 // Add ancestor routes to self
573 addInheritedRoutes(entry, routesToAdd);
574 }
575
576 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
577 }
578 else if (route.isChildInherit()) {
579 // If not blocked by capture, add inherited routes to children
580 Rib::RouteSet routesToAdd;
581 if (!entry.hasCapture()) {
582 routesToAdd = m_rib.getAncestorRoutes(entry);
583 }
584
585 Rib::RouteSet routesToRemove;
586 routesToRemove.insert(route);
587
588 // Add ancestor routes to children
589 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
590 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000591 else if (route.isRibCapture()) {
Vince Lehman9aac8732016-01-11 15:49:23 -0600592 // If capture is turned off for the route and another route is installed in the RibEntry,
593 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600594 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600595 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600596 // Look for an ancestors that were blocked previously
597 routesToAdd = m_rib.getAncestorRoutes(entry);
598
599 // Add ancestor routes to self
600 addInheritedRoutes(entry, routesToAdd);
601 }
602
603 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
604 }
605
606 // Need to check if the removed route was blocking an inherited route
607 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
608
Vince Lehmanf91ab742015-04-23 15:26:55 -0500609 // If the current entry has capture set or is pending removal, don't add inherited route
610 if (!entry.hasCapture() && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600611 // If there is an ancestor route which is the same as the erased route, add that route
612 // to the current entry
Davide Pesavento412c9822021-07-02 00:21:05 -0400613 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600614
615 if (it != ancestorRoutes.end()) {
616 addInheritedRoute(entry.getName(), *it);
617 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), it->faceId, it->cost));
618 }
619 }
620}
621
622void
623FibUpdater::createFibUpdatesForErasedRibEntry(const RibEntry& entry)
624{
625 for (const Route& route : entry.getInheritedRoutes()) {
626 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
627 }
628}
629
630void
631FibUpdater::modifyChildrensInheritedRoutes(const Rib::RibEntryList& children,
632 const Rib::RouteSet& routesToAdd,
633 const Rib::RouteSet& routesToRemove)
634{
635 for (const auto& child : children) {
636 traverseSubTree(*child, routesToAdd, routesToRemove);
637 }
638}
639
640void
641FibUpdater::traverseSubTree(const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
642 Rib::Rib::RouteSet routesToRemove)
643{
644 // If a route on the namespace has the capture flag set, ignore self and children
645 if (entry.hasCapture()) {
646 return;
647 }
648
649 // Remove inherited routes from current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400650 for (auto removeIt = routesToRemove.begin(); removeIt != routesToRemove.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600651 // If a route on the namespace has the same face ID and child inheritance set,
652 // ignore this route
653 if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400654 removeIt = routesToRemove.erase(removeIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600655 continue;
656 }
657
658 // Only remove route if it removes an existing inherited route
659 if (entry.hasInheritedRoute(*removeIt)) {
660 removeInheritedRoute(entry.getName(), *removeIt);
661 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), removeIt->faceId));
662 }
663
664 ++removeIt;
665 }
666
667 // Add inherited routes to current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400668 for (auto addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600669 // If a route on the namespace has the same face ID and child inherit set, ignore this face
670 if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400671 addIt = routesToAdd.erase(addIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600672 continue;
673 }
674
675 // Only add route if it does not override an existing route
676 if (!entry.hasFaceId(addIt->faceId)) {
677 addInheritedRoute(entry.getName(), *addIt);
678 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), addIt->faceId, addIt->cost));
679 }
680
681 ++addIt;
682 }
683
684 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
685}
686
687void
688FibUpdater::addInheritedRoute(const Name& name, const Route& route)
689{
690 RibUpdate update;
691 update.setAction(RibUpdate::REGISTER)
692 .setName(name)
693 .setRoute(route);
694
695 m_inheritedRoutes.push_back(update);
696}
697
698void
699FibUpdater::removeInheritedRoute(const Name& name, const Route& route)
700{
701 RibUpdate update;
702 update.setAction(RibUpdate::UNREGISTER)
703 .setName(name)
704 .setRoute(route);
705
706 m_inheritedRoutes.push_back(update);
707}
708
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400709} // namespace nfd::rib