blob: 0b8fc0e3dc0c2a50c2999fd9f9aa920034f4063f [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) {
71 switch (update.getAction()) {
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{
91 const Name& prefix = update.getName();
92 const Route& route = update.getRoute();
93
Davide Pesavento412c9822021-07-02 00:21:05 -040094 auto it = m_rib.find(prefix);
Vince Lehman76c751c2014-11-18 17:36:38 -060095
96 // Name prefix exists
97 if (it != m_rib.end()) {
98 shared_ptr<const RibEntry> entry(it->second);
99
Davide Pesavento412c9822021-07-02 00:21:05 -0400100 auto existingRoute = entry->findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600101
102 // Route will be new
103 if (existingRoute == entry->end()) {
104 // Will the new route change the namespace's capture flag?
Junxiao Shi3f21e582017-05-29 15:26:32 +0000105 bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isRibCapture());
Vince Lehman76c751c2014-11-18 17:36:38 -0600106
107 createFibUpdatesForNewRoute(*entry, route, willCaptureBeTurnedOn);
108 }
109 else {
110 // Route already exists
111 RibEntry entryCopy = *entry;
112
Davide Pesavento412c9822021-07-02 00:21:05 -0400113 Route& routeToUpdate = *entryCopy.findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600114 routeToUpdate.flags = route.flags;
115 routeToUpdate.cost = route.cost;
116 routeToUpdate.expires = route.expires;
117
118 createFibUpdatesForUpdatedRoute(entryCopy, route, *existingRoute);
119 }
120 }
121 else {
122 // New name in RIB
123 // Find prefix's parent
124 shared_ptr<RibEntry> parent = m_rib.findParent(prefix);
125
126 Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(prefix);
127 Rib::RibEntryList children;
128
129 for (const auto& descendant : descendants) {
130 // If the child has the same parent as the new entry,
131 // the new entry must be the child's new parent
132 if (descendant->getParent() == parent) {
133 children.push_back(descendant);
134 }
135 }
136
137 createFibUpdatesForNewRibEntry(prefix, route, children);
138 }
139}
140
141void
142FibUpdater::computeUpdatesForUnregistration(const RibUpdate& update)
143{
144 const Name& prefix = update.getName();
145 const Route& route = update.getRoute();
146
Davide Pesavento412c9822021-07-02 00:21:05 -0400147 auto ribIt = m_rib.find(prefix);
Vince Lehman76c751c2014-11-18 17:36:38 -0600148
149 // Name prefix exists
150 if (ribIt != m_rib.end()) {
151 shared_ptr<const RibEntry> entry(ribIt->second);
Vince Lehman76c751c2014-11-18 17:36:38 -0600152 const bool hadCapture = entry->hasCapture();
153
Davide Pesavento412c9822021-07-02 00:21:05 -0400154 auto existing = entry->findRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600155 if (existing != entry->end()) {
156 RibEntry temp = *entry;
157
158 // Erase route in temp entry
159 temp.eraseRoute(route);
160
161 const bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
162
163 createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
164
165 // The RibEntry still has the face ID; need to update FIB
166 // with lowest cost for the same face instead of removing the face from the FIB
167 const Route* next = entry->getRouteWithSecondLowestCostByFaceId(route.faceId);
168
169 if (next != nullptr) {
170 createFibUpdatesForNewRoute(temp, *next, false);
171 }
172
173 // The RibEntry will be empty after this removal
174 if (entry->getNRoutes() == 1) {
175 createFibUpdatesForErasedRibEntry(*entry);
176 }
177 }
178 }
179}
180
181void
182FibUpdater::sendUpdates(const FibUpdateList& updates,
183 const FibUpdateSuccessCallback& onSuccess,
184 const FibUpdateFailureCallback& onFailure)
185{
Davide Pesavento191a7a22023-05-17 22:40:43 -0400186 NFD_LOG_DEBUG("Applying " << updates.size() << " FIB update(s)");
Vince Lehman76c751c2014-11-18 17:36:38 -0600187
188 for (const FibUpdate& update : updates) {
Davide Pesavento191a7a22023-05-17 22:40:43 -0400189 NFD_LOG_DEBUG("Sending " << update);
Vince Lehman76c751c2014-11-18 17:36:38 -0600190
191 if (update.action == FibUpdate::ADD_NEXTHOP) {
192 sendAddNextHopUpdate(update, onSuccess, onFailure);
193 }
194 else if (update.action == FibUpdate::REMOVE_NEXTHOP) {
195 sendRemoveNextHopUpdate(update, onSuccess, onFailure);
196 }
197 }
198}
199
200void
201FibUpdater::sendUpdatesForBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
202 const FibUpdateFailureCallback& onFailure)
203{
204 if (m_updatesForBatchFaceId.size() > 0) {
205 sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
206 }
207 else {
208 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
209 }
210}
211
212void
213FibUpdater::sendUpdatesForNonBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
214 const FibUpdateFailureCallback& onFailure)
215{
216 if (m_updatesForNonBatchFaceId.size() > 0) {
217 sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
218 }
219 else {
220 onSuccess(m_inheritedRoutes);
221 }
222}
223
224void
225FibUpdater::sendAddNextHopUpdate(const FibUpdate& update,
226 const FibUpdateSuccessCallback& onSuccess,
227 const FibUpdateFailureCallback& onFailure,
228 uint32_t nTimeouts)
229{
230 m_controller.start<ndn::nfd::FibAddNextHopCommand>(
231 ControlParameters()
232 .setName(update.name)
233 .setFaceId(update.faceId)
234 .setCost(update.cost),
Davide Pesavento412c9822021-07-02 00:21:05 -0400235 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
236 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600237}
238
239void
240FibUpdater::sendRemoveNextHopUpdate(const FibUpdate& update,
241 const FibUpdateSuccessCallback& onSuccess,
242 const FibUpdateFailureCallback& onFailure,
243 uint32_t nTimeouts)
244{
245 m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
246 ControlParameters()
247 .setName(update.name)
248 .setFaceId(update.faceId),
Davide Pesavento412c9822021-07-02 00:21:05 -0400249 [=] (const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
250 [=] (const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
Vince Lehman76c751c2014-11-18 17:36:38 -0600251}
252
253void
Davide Pesavento412c9822021-07-02 00:21:05 -0400254FibUpdater::onUpdateSuccess(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600255 const FibUpdateSuccessCallback& onSuccess,
256 const FibUpdateFailureCallback& onFailure)
257{
258 if (update.faceId == m_batchFaceId) {
259 m_updatesForBatchFaceId.remove(update);
260
261 if (m_updatesForBatchFaceId.size() == 0) {
262 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
263 }
264 }
265 else {
266 m_updatesForNonBatchFaceId.remove(update);
267
268 if (m_updatesForNonBatchFaceId.size() == 0) {
269 onSuccess(m_inheritedRoutes);
270 }
271 }
272}
273
274void
Davide Pesavento412c9822021-07-02 00:21:05 -0400275FibUpdater::onUpdateError(const FibUpdate& update,
Vince Lehman76c751c2014-11-18 17:36:38 -0600276 const FibUpdateSuccessCallback& onSuccess,
277 const FibUpdateFailureCallback& onFailure,
Junxiao Shi29b41282016-08-22 03:47:02 +0000278 const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
Vince Lehman76c751c2014-11-18 17:36:38 -0600279{
Junxiao Shi29b41282016-08-22 03:47:02 +0000280 uint32_t code = response.getCode();
281 NFD_LOG_DEBUG("Failed to apply " << update <<
Davide Pesavento191a7a22023-05-17 22:40:43 -0400282 " [code: " << code << ", error: " << response.getText() << "]");
Vince Lehman76c751c2014-11-18 17:36:38 -0600283
284 if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts < MAX_NUM_TIMEOUTS) {
285 sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
286 }
287 else if (code == ERROR_FACE_NOT_FOUND) {
288 if (update.faceId == m_batchFaceId) {
Junxiao Shi29b41282016-08-22 03:47:02 +0000289 onFailure(code, response.getText());
Vince Lehman76c751c2014-11-18 17:36:38 -0600290 }
291 else {
292 m_updatesForNonBatchFaceId.remove(update);
293
294 if (m_updatesForNonBatchFaceId.size() == 0) {
295 onSuccess(m_inheritedRoutes);
296 }
297 }
298 }
299 else {
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500300 NDN_THROW(Error("Non-recoverable error " + std::to_string(code) + ": " + response.getText()));
Vince Lehman76c751c2014-11-18 17:36:38 -0600301 }
302}
303
304void
Davide Pesavento412c9822021-07-02 00:21:05 -0400305FibUpdater::addFibUpdate(const FibUpdate& update)
Vince Lehman76c751c2014-11-18 17:36:38 -0600306{
307 FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
308 m_updatesForNonBatchFaceId;
309
Davide Pesavento412c9822021-07-02 00:21:05 -0400310 // If an update with the same name and route already exists, replace it
311 auto it = std::find_if(updates.begin(), updates.end(),
Vince Lehman76c751c2014-11-18 17:36:38 -0600312 [&update] (const FibUpdate& other) {
313 return update.name == other.name && update.faceId == other.faceId;
314 });
315
316 if (it != updates.end()) {
317 FibUpdate& existingUpdate = *it;
318 existingUpdate.action = update.action;
319 existingUpdate.cost = update.cost;
320 }
321 else {
322 updates.push_back(update);
323 }
324}
325
326void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500327FibUpdater::addInheritedRoutes(const RibEntry& entry, const Rib::RouteSet& routesToAdd)
Vince Lehman76c751c2014-11-18 17:36:38 -0600328{
329 for (const Route& route : routesToAdd) {
330 // Don't add an ancestor faceId if the namespace has an entry for that faceId
331 if (!entry.hasFaceId(route.faceId)) {
332 // Create a record of the inherited route so it can be added to the RIB later
333 addInheritedRoute(entry.getName(), route);
334
335 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
336 }
337 }
338}
339
340void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500341FibUpdater::addInheritedRoutes(const Name& name, const Rib::RouteSet& routesToAdd,
Vince Lehman76c751c2014-11-18 17:36:38 -0600342 const Route& ignore)
343{
344 for (const Route& route : routesToAdd) {
345 if (route.faceId != ignore.faceId) {
346 // Create a record of the inherited route so it can be added to the RIB later
347 addInheritedRoute(name, route);
348
349 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
350 }
351 }
352}
353
354void
355FibUpdater::removeInheritedRoutes(const RibEntry& entry, const Rib::Rib::RouteSet& routesToRemove)
356{
357 for (const Route& route : routesToRemove) {
358 // Only remove if the route has been inherited
359 if (entry.hasInheritedRoute(route)) {
360 removeInheritedRoute(entry.getName(), route);
361 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
362 }
363 }
364}
365
366void
367FibUpdater::createFibUpdatesForNewRibEntry(const Name& name, const Route& route,
368 const Rib::RibEntryList& children)
369{
370 // Create FIB update for new entry
371 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
372
373 // No flags are set
Junxiao Shi3f21e582017-05-29 15:26:32 +0000374 if (!route.isChildInherit() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600375 // Add ancestor routes to self
376 addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
377 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000378 else if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600379 // Add route to children
380 Rib::RouteSet routesToAdd;
381 routesToAdd.insert(route);
382
383 // Remove routes blocked by capture and add self to children
384 modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
385 }
386 else if (route.isChildInherit()) {
387 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
388
389 // Add ancestor routes to self
390 addInheritedRoutes(name, ancestorRoutes, route);
391
392 // If there is an ancestor route which is the same as the new route, replace it
393 // with the new route
Davide Pesavento412c9822021-07-02 00:21:05 -0400394 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600395
396 // There is a route that needs to be overwritten, erase and then replace
397 if (it != ancestorRoutes.end()) {
398 ancestorRoutes.erase(it);
399 }
400
401 // Add new route to ancestor list so it can be added to children
402 ancestorRoutes.insert(route);
403
404 // Add ancestor routes to children
405 modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
406 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000407 else if (route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600408 // Remove routes blocked by capture
409 modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
410 }
411}
412
413void
414FibUpdater::createFibUpdatesForNewRoute(const RibEntry& entry, const Route& route,
415 bool captureWasTurnedOn)
416{
417 // Only update if the new route has a lower cost than a previously installed route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500418 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600419
420 Rib::RouteSet routesToAdd;
421 if (route.isChildInherit()) {
422 // Add to children if this new route doesn't override a previous lower cost, or
423 // add to children if this new route is lower cost than a previous route.
424 // Less than equal, since entry may find this route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500425 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600426 // Add self to children
427 routesToAdd.insert(route);
428 }
429 }
430
431 Rib::RouteSet routesToRemove;
432 if (captureWasTurnedOn) {
433 // Capture flag on
434 routesToRemove = m_rib.getAncestorRoutes(entry);
435
436 // Remove ancestor routes from self
437 removeInheritedRoutes(entry, routesToRemove);
438 }
439
440 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
441
442 // If another route with same faceId and lower cost exists, don't update.
443 // Must be done last so that add updates replace removal updates
444 // Create FIB update for new entry
Vince Lehman9dcfc402015-03-26 03:18:54 -0500445 const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600446
Vince Lehman9dcfc402015-03-26 03:18:54 -0500447 if (other == nullptr || route.cost <= other->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600448 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
449 }
450}
451
452void
453FibUpdater::createFibUpdatesForUpdatedRoute(const RibEntry& entry, const Route& route,
454 const Route& existingRoute)
455{
456 const bool costDidChange = (route.cost != existingRoute.cost);
457
458 // Look for an installed route with the lowest cost and child inherit set
Vince Lehman9dcfc402015-03-26 03:18:54 -0500459 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600460
461 // No flags changed and cost didn't change, no change in FIB
462 if (route.flags == existingRoute.flags && !costDidChange) {
463 return;
464 }
465
466 // Cost changed so create update for the entry itself
467 if (costDidChange) {
468 // Create update if this route's cost is lower than other routes
469 if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
470 // Create FIB update for the updated entry
471 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
472 }
473 else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
474 // Create update if this route used to be the lowest route but is no longer
475 // the lowest cost route.
476 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), prevRoute->faceId, prevRoute->cost));
477 }
478
479 // If another route with same faceId and lower cost and ChildInherit exists,
480 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500481 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600482 // If no flags changed but child inheritance is set, need to update children
483 // with new cost
484 if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
485 // Add self to children
486 Rib::RouteSet routesToAdd;
487 routesToAdd.insert(route);
488 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
489
490 return;
491 }
492 }
493 }
494
495 // Child inherit was turned on
496 if (!existingRoute.isChildInherit() && route.isChildInherit()) {
497 // If another route with same faceId and lower cost and ChildInherit exists,
498 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500499 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600500 // Add self to children
501 Rib::RouteSet routesToAdd;
502 routesToAdd.insert(route);
503 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
504 }
505 } // Child inherit was turned off
506 else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
507 // Remove self from children
508 Rib::RouteSet routesToRemove;
509 routesToRemove.insert(route);
510
511 Rib::RouteSet routesToAdd;
512 // If another route with same faceId and ChildInherit exists, update children with this route.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500513 if (prevRoute != nullptr) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600514 routesToAdd.insert(*prevRoute);
515 }
516 else {
517 // Look for an ancestor that was blocked previously
518 const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
Davide Pesavento412c9822021-07-02 00:21:05 -0400519 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600520
521 // If an ancestor is found, add it to children
522 if (it != ancestorRoutes.end()) {
523 routesToAdd.insert(*it);
524 }
525 }
526
527 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
528 }
529
530 // Capture was turned on
Junxiao Shi3f21e582017-05-29 15:26:32 +0000531 if (!existingRoute.isRibCapture() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600532 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
533
534 // Remove ancestor routes from self
535 removeInheritedRoutes(entry, ancestorRoutes);
536
537 // Remove ancestor routes from children
538 modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
539 } // Capture was turned off
Junxiao Shi3f21e582017-05-29 15:26:32 +0000540 else if (existingRoute.isRibCapture() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600541 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
542
543 // Add ancestor routes to self
544 addInheritedRoutes(entry, ancestorRoutes);
545
546 // Add ancestor routes to children
547 modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
548 }
549}
550
551void
552FibUpdater::createFibUpdatesForErasedRoute(const RibEntry& entry, const Route& route,
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400553 bool captureWasTurnedOff)
Vince Lehman76c751c2014-11-18 17:36:38 -0600554{
555 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
556
Junxiao Shi3f21e582017-05-29 15:26:32 +0000557 if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600558 // Remove self from children
559 Rib::RouteSet routesToRemove;
560 routesToRemove.insert(route);
561
Vince Lehman9aac8732016-01-11 15:49:23 -0600562 // If capture is turned off for the route and another route is installed in the RibEntry,
563 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600564 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600565 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600566 // Look for an ancestors that were blocked previously
567 routesToAdd = m_rib.getAncestorRoutes(entry);
568
569 // Add ancestor routes to self
570 addInheritedRoutes(entry, routesToAdd);
571 }
572
573 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
574 }
575 else if (route.isChildInherit()) {
576 // If not blocked by capture, add inherited routes to children
577 Rib::RouteSet routesToAdd;
578 if (!entry.hasCapture()) {
579 routesToAdd = m_rib.getAncestorRoutes(entry);
580 }
581
582 Rib::RouteSet routesToRemove;
583 routesToRemove.insert(route);
584
585 // Add ancestor routes to children
586 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
587 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000588 else if (route.isRibCapture()) {
Vince Lehman9aac8732016-01-11 15:49:23 -0600589 // If capture is turned off for the route and another route is installed in the RibEntry,
590 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600591 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600592 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600593 // Look for an ancestors that were blocked previously
594 routesToAdd = m_rib.getAncestorRoutes(entry);
595
596 // Add ancestor routes to self
597 addInheritedRoutes(entry, routesToAdd);
598 }
599
600 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
601 }
602
603 // Need to check if the removed route was blocking an inherited route
604 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
605
Vince Lehmanf91ab742015-04-23 15:26:55 -0500606 // If the current entry has capture set or is pending removal, don't add inherited route
607 if (!entry.hasCapture() && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600608 // If there is an ancestor route which is the same as the erased route, add that route
609 // to the current entry
Davide Pesavento412c9822021-07-02 00:21:05 -0400610 auto it = ancestorRoutes.find(route);
Vince Lehman76c751c2014-11-18 17:36:38 -0600611
612 if (it != ancestorRoutes.end()) {
613 addInheritedRoute(entry.getName(), *it);
614 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), it->faceId, it->cost));
615 }
616 }
617}
618
619void
620FibUpdater::createFibUpdatesForErasedRibEntry(const RibEntry& entry)
621{
622 for (const Route& route : entry.getInheritedRoutes()) {
623 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
624 }
625}
626
627void
628FibUpdater::modifyChildrensInheritedRoutes(const Rib::RibEntryList& children,
629 const Rib::RouteSet& routesToAdd,
630 const Rib::RouteSet& routesToRemove)
631{
632 for (const auto& child : children) {
633 traverseSubTree(*child, routesToAdd, routesToRemove);
634 }
635}
636
637void
638FibUpdater::traverseSubTree(const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
639 Rib::Rib::RouteSet routesToRemove)
640{
641 // If a route on the namespace has the capture flag set, ignore self and children
642 if (entry.hasCapture()) {
643 return;
644 }
645
646 // Remove inherited routes from current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400647 for (auto removeIt = routesToRemove.begin(); removeIt != routesToRemove.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600648 // If a route on the namespace has the same face ID and child inheritance set,
649 // ignore this route
650 if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400651 removeIt = routesToRemove.erase(removeIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600652 continue;
653 }
654
655 // Only remove route if it removes an existing inherited route
656 if (entry.hasInheritedRoute(*removeIt)) {
657 removeInheritedRoute(entry.getName(), *removeIt);
658 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), removeIt->faceId));
659 }
660
661 ++removeIt;
662 }
663
664 // Add inherited routes to current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400665 for (auto addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600666 // If a route on the namespace has the same face ID and child inherit set, ignore this face
667 if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400668 addIt = routesToAdd.erase(addIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600669 continue;
670 }
671
672 // Only add route if it does not override an existing route
673 if (!entry.hasFaceId(addIt->faceId)) {
674 addInheritedRoute(entry.getName(), *addIt);
675 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), addIt->faceId, addIt->cost));
676 }
677
678 ++addIt;
679 }
680
681 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
682}
683
684void
685FibUpdater::addInheritedRoute(const Name& name, const Route& route)
686{
687 RibUpdate update;
688 update.setAction(RibUpdate::REGISTER)
689 .setName(name)
690 .setRoute(route);
691
692 m_inheritedRoutes.push_back(update);
693}
694
695void
696FibUpdater::removeInheritedRoute(const Name& name, const Route& route)
697{
698 RibUpdate update;
699 update.setAction(RibUpdate::UNREGISTER)
700 .setName(name)
701 .setRoute(route);
702
703 m_inheritedRoutes.push_back(update);
704}
705
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400706} // namespace nfd::rib