blob: 897b6fba1c51c52e4e4841c476f5a7b16e539c23 [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{
67 NFD_LOG_DEBUG("Computing updates for batch with faceID: " << batch.getFaceId());
68
69 // Compute updates and add to m_fibUpdates
Junxiao Shi3f21e582017-05-29 15:26:32 +000070 for (const RibUpdate& update : batch) {
71 switch (update.getAction()) {
Vince Lehman76c751c2014-11-18 17:36:38 -060072 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
81 // Do not apply updates with the same face ID as the destroyed face
82 // since they will be rejected by the FIB
83 m_updatesForBatchFaceId.clear();
84 break;
Vince Lehman76c751c2014-11-18 17:36:38 -060085 }
Junxiao Shi3f21e582017-05-29 15:26:32 +000086 }
Vince Lehman76c751c2014-11-18 17:36:38 -060087}
88
89void
90FibUpdater::computeUpdatesForRegistration(const RibUpdate& update)
91{
92 const Name& prefix = update.getName();
93 const Route& route = update.getRoute();
94
Davide Pesavento412c9822021-07-02 00:21:05 -040095 auto it = m_rib.find(prefix);
Vince Lehman76c751c2014-11-18 17:36:38 -060096
97 // Name prefix exists
98 if (it != m_rib.end()) {
99 shared_ptr<const RibEntry> entry(it->second);
100
Davide Pesavento412c9822021-07-02 00:21:05 -0400101 auto existingRoute = entry->findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600102
103 // Route will be new
104 if (existingRoute == entry->end()) {
105 // Will the new route change the namespace's capture flag?
Junxiao Shi3f21e582017-05-29 15:26:32 +0000106 bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isRibCapture());
Vince Lehman76c751c2014-11-18 17:36:38 -0600107
108 createFibUpdatesForNewRoute(*entry, route, willCaptureBeTurnedOn);
109 }
110 else {
111 // Route already exists
112 RibEntry entryCopy = *entry;
113
Davide Pesavento412c9822021-07-02 00:21:05 -0400114 Route& routeToUpdate = *entryCopy.findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600115 routeToUpdate.flags = route.flags;
116 routeToUpdate.cost = route.cost;
117 routeToUpdate.expires = route.expires;
118
119 createFibUpdatesForUpdatedRoute(entryCopy, route, *existingRoute);
120 }
121 }
122 else {
123 // New name in RIB
124 // Find prefix's parent
125 shared_ptr<RibEntry> parent = m_rib.findParent(prefix);
126
127 Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(prefix);
128 Rib::RibEntryList children;
129
130 for (const auto& descendant : descendants) {
131 // If the child has the same parent as the new entry,
132 // the new entry must be the child's new parent
133 if (descendant->getParent() == parent) {
134 children.push_back(descendant);
135 }
136 }
137
138 createFibUpdatesForNewRibEntry(prefix, route, children);
139 }
140}
141
142void
143FibUpdater::computeUpdatesForUnregistration(const RibUpdate& update)
144{
145 const Name& prefix = update.getName();
146 const Route& route = update.getRoute();
147
Davide Pesavento412c9822021-07-02 00:21:05 -0400148 auto ribIt = m_rib.find(prefix);
Vince Lehman76c751c2014-11-18 17:36:38 -0600149
150 // Name prefix exists
151 if (ribIt != m_rib.end()) {
152 shared_ptr<const RibEntry> entry(ribIt->second);
Vince Lehman76c751c2014-11-18 17:36:38 -0600153 const bool hadCapture = entry->hasCapture();
154
Davide Pesavento412c9822021-07-02 00:21:05 -0400155 auto existing = entry->findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600156 if (existing != entry->end()) {
157 RibEntry temp = *entry;
158
159 // Erase route in temp entry
160 temp.eraseRoute(route);
161
162 const bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
163
164 createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
165
166 // The RibEntry still has the face ID; need to update FIB
167 // with lowest cost for the same face instead of removing the face from the FIB
168 const Route* next = entry->getRouteWithSecondLowestCostByFaceId(route.faceId);
169
170 if (next != nullptr) {
171 createFibUpdatesForNewRoute(temp, *next, false);
172 }
173
174 // The RibEntry will be empty after this removal
175 if (entry->getNRoutes() == 1) {
176 createFibUpdatesForErasedRibEntry(*entry);
177 }
178 }
179 }
180}
181
182void
183FibUpdater::sendUpdates(const FibUpdateList& updates,
184 const FibUpdateSuccessCallback& onSuccess,
185 const FibUpdateFailureCallback& onFailure)
186{
Davide Pesavento191a7a22023-05-17 22:40:43 -0400187 NFD_LOG_DEBUG("Applying " << updates.size() << " FIB update(s)");
Vince Lehman76c751c2014-11-18 17:36:38 -0600188
189 for (const FibUpdate& update : updates) {
Davide Pesavento191a7a22023-05-17 22:40:43 -0400190 NFD_LOG_DEBUG("Sending " << update);
Vince Lehman76c751c2014-11-18 17:36:38 -0600191
192 if (update.action == FibUpdate::ADD_NEXTHOP) {
193 sendAddNextHopUpdate(update, onSuccess, onFailure);
194 }
195 else if (update.action == FibUpdate::REMOVE_NEXTHOP) {
196 sendRemoveNextHopUpdate(update, onSuccess, onFailure);
197 }
198 }
199}
200
201void
202FibUpdater::sendUpdatesForBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
203 const FibUpdateFailureCallback& onFailure)
204{
205 if (m_updatesForBatchFaceId.size() > 0) {
206 sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
207 }
208 else {
209 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
210 }
211}
212
213void
214FibUpdater::sendUpdatesForNonBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
215 const FibUpdateFailureCallback& onFailure)
216{
217 if (m_updatesForNonBatchFaceId.size() > 0) {
218 sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
219 }
220 else {
221 onSuccess(m_inheritedRoutes);
222 }
223}
224
225void
226FibUpdater::sendAddNextHopUpdate(const FibUpdate& update,
227 const FibUpdateSuccessCallback& onSuccess,
228 const FibUpdateFailureCallback& onFailure,
229 uint32_t nTimeouts)
230{
231 m_controller.start<ndn::nfd::FibAddNextHopCommand>(
232 ControlParameters()
233 .setName(update.name)
234 .setFaceId(update.faceId)
235 .setCost(update.cost),
Davide Pesavento412c9822021-07-02 00:21:05 -0400236 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
237 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600238}
239
240void
241FibUpdater::sendRemoveNextHopUpdate(const FibUpdate& update,
242 const FibUpdateSuccessCallback& onSuccess,
243 const FibUpdateFailureCallback& onFailure,
244 uint32_t nTimeouts)
245{
246 m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
247 ControlParameters()
248 .setName(update.name)
249 .setFaceId(update.faceId),
Davide Pesavento412c9822021-07-02 00:21:05 -0400250 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
251 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600252}
253
254void
Davide Pesavento412c9822021-07-02 00:21:05 -0400255FibUpdater::onUpdateSuccess(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600256 const FibUpdateSuccessCallback& onSuccess,
257 const FibUpdateFailureCallback& onFailure)
258{
259 if (update.faceId == m_batchFaceId) {
260 m_updatesForBatchFaceId.remove(update);
261
262 if (m_updatesForBatchFaceId.size() == 0) {
263 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
264 }
265 }
266 else {
267 m_updatesForNonBatchFaceId.remove(update);
268
269 if (m_updatesForNonBatchFaceId.size() == 0) {
270 onSuccess(m_inheritedRoutes);
271 }
272 }
273}
274
275void
Davide Pesavento412c9822021-07-02 00:21:05 -0400276FibUpdater::onUpdateError(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600277 const FibUpdateSuccessCallback& onSuccess,
278 const FibUpdateFailureCallback& onFailure,
Junxiao Shi29b41282016-08-22 03:47:02 +0000279 const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
Vince Lehman76c751c2014-11-18 17:36:38 -0600280{
Junxiao Shi29b41282016-08-22 03:47:02 +0000281 uint32_t code = response.getCode();
282 NFD_LOG_DEBUG("Failed to apply " << update <<
Davide Pesavento191a7a22023-05-17 22:40:43 -0400283 " [code: " << code << ", error: " << response.getText() << "]");
Vince Lehman76c751c2014-11-18 17:36:38 -0600284
285 if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts < MAX_NUM_TIMEOUTS) {
286 sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
287 }
288 else if (code == ERROR_FACE_NOT_FOUND) {
289 if (update.faceId == m_batchFaceId) {
Junxiao Shi29b41282016-08-22 03:47:02 +0000290 onFailure(code, response.getText());
Vince Lehman76c751c2014-11-18 17:36:38 -0600291 }
292 else {
293 m_updatesForNonBatchFaceId.remove(update);
294
295 if (m_updatesForNonBatchFaceId.size() == 0) {
296 onSuccess(m_inheritedRoutes);
297 }
298 }
299 }
300 else {
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500301 NDN_THROW(Error("Non-recoverable error " + std::to_string(code) + ": " + response.getText()));
Vince Lehman76c751c2014-11-18 17:36:38 -0600302 }
303}
304
305void
Davide Pesavento412c9822021-07-02 00:21:05 -0400306FibUpdater::addFibUpdate(const FibUpdate& update)
Vince Lehman76c751c2014-11-18 17:36:38 -0600307{
308 FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
309 m_updatesForNonBatchFaceId;
310
Davide Pesavento412c9822021-07-02 00:21:05 -0400311 // If an update with the same name and route already exists, replace it
312 auto it = std::find_if(updates.begin(), updates.end(),
Vince Lehman76c751c2014-11-18 17:36:38 -0600313 [&update] (const FibUpdate& other) {
314 return update.name == other.name && update.faceId == other.faceId;
315 });
316
317 if (it != updates.end()) {
318 FibUpdate& existingUpdate = *it;
319 existingUpdate.action = update.action;
320 existingUpdate.cost = update.cost;
321 }
322 else {
323 updates.push_back(update);
324 }
325}
326
327void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500328FibUpdater::addInheritedRoutes(const RibEntry& entry, const Rib::RouteSet& routesToAdd)
Vince Lehman76c751c2014-11-18 17:36:38 -0600329{
330 for (const Route& route : routesToAdd) {
331 // Don't add an ancestor faceId if the namespace has an entry for that faceId
332 if (!entry.hasFaceId(route.faceId)) {
333 // Create a record of the inherited route so it can be added to the RIB later
334 addInheritedRoute(entry.getName(), route);
335
336 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
337 }
338 }
339}
340
341void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500342FibUpdater::addInheritedRoutes(const Name& name, const Rib::RouteSet& routesToAdd,
Vince Lehman76c751c2014-11-18 17:36:38 -0600343 const Route& ignore)
344{
345 for (const Route& route : routesToAdd) {
346 if (route.faceId != ignore.faceId) {
347 // Create a record of the inherited route so it can be added to the RIB later
348 addInheritedRoute(name, route);
349
350 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
351 }
352 }
353}
354
355void
356FibUpdater::removeInheritedRoutes(const RibEntry& entry, const Rib::Rib::RouteSet& routesToRemove)
357{
358 for (const Route& route : routesToRemove) {
359 // Only remove if the route has been inherited
360 if (entry.hasInheritedRoute(route)) {
361 removeInheritedRoute(entry.getName(), route);
362 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
363 }
364 }
365}
366
367void
368FibUpdater::createFibUpdatesForNewRibEntry(const Name& name, const Route& route,
369 const Rib::RibEntryList& children)
370{
371 // Create FIB update for new entry
372 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
373
374 // No flags are set
Junxiao Shi3f21e582017-05-29 15:26:32 +0000375 if (!route.isChildInherit() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600376 // Add ancestor routes to self
377 addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
378 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000379 else if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600380 // Add route to children
381 Rib::RouteSet routesToAdd;
382 routesToAdd.insert(route);
383
384 // Remove routes blocked by capture and add self to children
385 modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
386 }
387 else if (route.isChildInherit()) {
388 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
389
390 // Add ancestor routes to self
391 addInheritedRoutes(name, ancestorRoutes, route);
392
393 // If there is an ancestor route which is the same as the new route, replace it
394 // with the new route
Davide Pesavento412c9822021-07-02 00:21:05 -0400395 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600396
397 // There is a route that needs to be overwritten, erase and then replace
398 if (it != ancestorRoutes.end()) {
399 ancestorRoutes.erase(it);
400 }
401
402 // Add new route to ancestor list so it can be added to children
403 ancestorRoutes.insert(route);
404
405 // Add ancestor routes to children
406 modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
407 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000408 else if (route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600409 // Remove routes blocked by capture
410 modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
411 }
412}
413
414void
415FibUpdater::createFibUpdatesForNewRoute(const RibEntry& entry, const Route& route,
416 bool captureWasTurnedOn)
417{
418 // Only update if the new route has a lower cost than a previously installed route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500419 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600420
421 Rib::RouteSet routesToAdd;
422 if (route.isChildInherit()) {
423 // Add to children if this new route doesn't override a previous lower cost, or
424 // add to children if this new route is lower cost than a previous route.
425 // Less than equal, since entry may find this route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500426 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600427 // Add self to children
428 routesToAdd.insert(route);
429 }
430 }
431
432 Rib::RouteSet routesToRemove;
433 if (captureWasTurnedOn) {
434 // Capture flag on
435 routesToRemove = m_rib.getAncestorRoutes(entry);
436
437 // Remove ancestor routes from self
438 removeInheritedRoutes(entry, routesToRemove);
439 }
440
441 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
442
443 // If another route with same faceId and lower cost exists, don't update.
444 // Must be done last so that add updates replace removal updates
445 // Create FIB update for new entry
Vince Lehman9dcfc402015-03-26 03:18:54 -0500446 const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600447
Vince Lehman9dcfc402015-03-26 03:18:54 -0500448 if (other == nullptr || route.cost <= other->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600449 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
450 }
451}
452
453void
454FibUpdater::createFibUpdatesForUpdatedRoute(const RibEntry& entry, const Route& route,
455 const Route& existingRoute)
456{
457 const bool costDidChange = (route.cost != existingRoute.cost);
458
459 // Look for an installed route with the lowest cost and child inherit set
Vince Lehman9dcfc402015-03-26 03:18:54 -0500460 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600461
462 // No flags changed and cost didn't change, no change in FIB
463 if (route.flags == existingRoute.flags && !costDidChange) {
464 return;
465 }
466
467 // Cost changed so create update for the entry itself
468 if (costDidChange) {
469 // Create update if this route's cost is lower than other routes
470 if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
471 // Create FIB update for the updated entry
472 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
473 }
474 else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
475 // Create update if this route used to be the lowest route but is no longer
476 // the lowest cost route.
477 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), prevRoute->faceId, prevRoute->cost));
478 }
479
480 // If another route with same faceId and lower cost and ChildInherit exists,
481 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500482 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600483 // If no flags changed but child inheritance is set, need to update children
484 // with new cost
485 if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
486 // Add self to children
487 Rib::RouteSet routesToAdd;
488 routesToAdd.insert(route);
489 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
490
491 return;
492 }
493 }
494 }
495
496 // Child inherit was turned on
497 if (!existingRoute.isChildInherit() && route.isChildInherit()) {
498 // If another route with same faceId and lower cost and ChildInherit exists,
499 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500500 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600501 // Add self to children
502 Rib::RouteSet routesToAdd;
503 routesToAdd.insert(route);
504 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
505 }
506 } // Child inherit was turned off
507 else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
508 // Remove self from children
509 Rib::RouteSet routesToRemove;
510 routesToRemove.insert(route);
511
512 Rib::RouteSet routesToAdd;
513 // If another route with same faceId and ChildInherit exists, update children with this route.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500514 if (prevRoute != nullptr) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600515 routesToAdd.insert(*prevRoute);
516 }
517 else {
518 // Look for an ancestor that was blocked previously
519 const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
Davide Pesavento412c9822021-07-02 00:21:05 -0400520 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600521
522 // If an ancestor is found, add it to children
523 if (it != ancestorRoutes.end()) {
524 routesToAdd.insert(*it);
525 }
526 }
527
528 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
529 }
530
531 // Capture was turned on
Junxiao Shi3f21e582017-05-29 15:26:32 +0000532 if (!existingRoute.isRibCapture() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600533 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
534
535 // Remove ancestor routes from self
536 removeInheritedRoutes(entry, ancestorRoutes);
537
538 // Remove ancestor routes from children
539 modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
540 } // Capture was turned off
Junxiao Shi3f21e582017-05-29 15:26:32 +0000541 else if (existingRoute.isRibCapture() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600542 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
543
544 // Add ancestor routes to self
545 addInheritedRoutes(entry, ancestorRoutes);
546
547 // Add ancestor routes to children
548 modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
549 }
550}
551
552void
553FibUpdater::createFibUpdatesForErasedRoute(const RibEntry& entry, const Route& route,
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400554 bool captureWasTurnedOff)
Vince Lehman76c751c2014-11-18 17:36:38 -0600555{
556 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
557
Junxiao Shi3f21e582017-05-29 15:26:32 +0000558 if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600559 // Remove self from children
560 Rib::RouteSet routesToRemove;
561 routesToRemove.insert(route);
562
Vince Lehman9aac8732016-01-11 15:49:23 -0600563 // If capture is turned off for the route and another route is installed in the RibEntry,
564 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600565 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600566 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600567 // Look for an ancestors that were blocked previously
568 routesToAdd = m_rib.getAncestorRoutes(entry);
569
570 // Add ancestor routes to self
571 addInheritedRoutes(entry, routesToAdd);
572 }
573
574 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
575 }
576 else if (route.isChildInherit()) {
577 // If not blocked by capture, add inherited routes to children
578 Rib::RouteSet routesToAdd;
579 if (!entry.hasCapture()) {
580 routesToAdd = m_rib.getAncestorRoutes(entry);
581 }
582
583 Rib::RouteSet routesToRemove;
584 routesToRemove.insert(route);
585
586 // Add ancestor routes to children
587 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
588 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000589 else if (route.isRibCapture()) {
Vince Lehman9aac8732016-01-11 15:49:23 -0600590 // If capture is turned off for the route and another route is installed in the RibEntry,
591 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600592 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600593 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600594 // Look for an ancestors that were blocked previously
595 routesToAdd = m_rib.getAncestorRoutes(entry);
596
597 // Add ancestor routes to self
598 addInheritedRoutes(entry, routesToAdd);
599 }
600
601 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
602 }
603
604 // Need to check if the removed route was blocking an inherited route
605 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
606
Vince Lehmanf91ab742015-04-23 15:26:55 -0500607 // If the current entry has capture set or is pending removal, don't add inherited route
608 if (!entry.hasCapture() && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600609 // If there is an ancestor route which is the same as the erased route, add that route
610 // to the current entry
Davide Pesavento412c9822021-07-02 00:21:05 -0400611 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600612
613 if (it != ancestorRoutes.end()) {
614 addInheritedRoute(entry.getName(), *it);
615 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), it->faceId, it->cost));
616 }
617 }
618}
619
620void
621FibUpdater::createFibUpdatesForErasedRibEntry(const RibEntry& entry)
622{
623 for (const Route& route : entry.getInheritedRoutes()) {
624 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
625 }
626}
627
628void
629FibUpdater::modifyChildrensInheritedRoutes(const Rib::RibEntryList& children,
630 const Rib::RouteSet& routesToAdd,
631 const Rib::RouteSet& routesToRemove)
632{
633 for (const auto& child : children) {
634 traverseSubTree(*child, routesToAdd, routesToRemove);
635 }
636}
637
638void
639FibUpdater::traverseSubTree(const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
640 Rib::Rib::RouteSet routesToRemove)
641{
642 // If a route on the namespace has the capture flag set, ignore self and children
643 if (entry.hasCapture()) {
644 return;
645 }
646
647 // Remove inherited routes from current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400648 for (auto removeIt = routesToRemove.begin(); removeIt != routesToRemove.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600649 // If a route on the namespace has the same face ID and child inheritance set,
650 // ignore this route
651 if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400652 removeIt = routesToRemove.erase(removeIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600653 continue;
654 }
655
656 // Only remove route if it removes an existing inherited route
657 if (entry.hasInheritedRoute(*removeIt)) {
658 removeInheritedRoute(entry.getName(), *removeIt);
659 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), removeIt->faceId));
660 }
661
662 ++removeIt;
663 }
664
665 // Add inherited routes to current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400666 for (auto addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600667 // If a route on the namespace has the same face ID and child inherit set, ignore this face
668 if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400669 addIt = routesToAdd.erase(addIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600670 continue;
671 }
672
673 // Only add route if it does not override an existing route
674 if (!entry.hasFaceId(addIt->faceId)) {
675 addInheritedRoute(entry.getName(), *addIt);
676 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), addIt->faceId, addIt->cost));
677 }
678
679 ++addIt;
680 }
681
682 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
683}
684
685void
686FibUpdater::addInheritedRoute(const Name& name, const Route& route)
687{
688 RibUpdate update;
689 update.setAction(RibUpdate::REGISTER)
690 .setName(name)
691 .setRoute(route);
692
693 m_inheritedRoutes.push_back(update);
694}
695
696void
697FibUpdater::removeInheritedRoute(const Name& name, const Route& route)
698{
699 RibUpdate update;
700 update.setAction(RibUpdate::UNREGISTER)
701 .setName(name)
702 .setRoute(route);
703
704 m_inheritedRoutes.push_back(update);
705}
706
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400707} // namespace nfd::rib