blob: 6e600e4da44a5d3ec245e24e0d14ee95fefe8c34 [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 Pesavento19779d82019-02-14 13:40:04 -05003 * Copyright (c) 2014-2019, 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
31namespace nfd {
32namespace rib {
33
Davide Pesaventoa3148082018-04-12 18:21:54 -040034NFD_LOG_INIT(FibUpdater);
Vince Lehman76c751c2014-11-18 17:36:38 -060035
Davide Pesaventoa3148082018-04-12 18:21:54 -040036using ndn::nfd::ControlParameters;
Vince Lehman76c751c2014-11-18 17:36:38 -060037
Junxiao Shidf1dc652019-08-30 19:03:19 +000038constexpr int MAX_NUM_TIMEOUTS = 10;
39constexpr uint32_t ERROR_FACE_NOT_FOUND = 410;
Vince Lehman76c751c2014-11-18 17:36:38 -060040
41FibUpdater::FibUpdater(Rib& rib, ndn::nfd::Controller& controller)
42 : m_rib(rib)
43 , m_controller(controller)
44{
45 rib.setFibUpdater(this);
46}
47
48void
49FibUpdater::computeAndSendFibUpdates(const RibUpdateBatch& batch,
50 const FibUpdateSuccessCallback& onSuccess,
51 const FibUpdateFailureCallback& onFailure)
52{
53 m_batchFaceId = batch.getFaceId();
54
55 // Erase previously calculated inherited routes
56 m_inheritedRoutes.clear();
57
58 // Erase previously calculated FIB updates
59 m_updatesForBatchFaceId.clear();
60 m_updatesForNonBatchFaceId.clear();
61
62 computeUpdates(batch);
63
64 sendUpdatesForBatchFaceId(onSuccess, onFailure);
65}
66
67void
68FibUpdater::computeUpdates(const RibUpdateBatch& batch)
69{
70 NFD_LOG_DEBUG("Computing updates for batch with faceID: " << batch.getFaceId());
71
72 // Compute updates and add to m_fibUpdates
Junxiao Shi3f21e582017-05-29 15:26:32 +000073 for (const RibUpdate& update : batch) {
74 switch (update.getAction()) {
Vince Lehman76c751c2014-11-18 17:36:38 -060075 case RibUpdate::REGISTER:
76 computeUpdatesForRegistration(update);
77 break;
78 case RibUpdate::UNREGISTER:
79 computeUpdatesForUnregistration(update);
80 break;
81 case RibUpdate::REMOVE_FACE:
82 computeUpdatesForUnregistration(update);
83
84 // Do not apply updates with the same face ID as the destroyed face
85 // since they will be rejected by the FIB
86 m_updatesForBatchFaceId.clear();
87 break;
Vince Lehman76c751c2014-11-18 17:36:38 -060088 }
Junxiao Shi3f21e582017-05-29 15:26:32 +000089 }
Vince Lehman76c751c2014-11-18 17:36:38 -060090}
91
92void
93FibUpdater::computeUpdatesForRegistration(const RibUpdate& update)
94{
95 const Name& prefix = update.getName();
96 const Route& route = update.getRoute();
97
98 Rib::const_iterator it = m_rib.find(prefix);
99
100 // Name prefix exists
101 if (it != m_rib.end()) {
102 shared_ptr<const RibEntry> entry(it->second);
103
104 RibEntry::const_iterator existingRoute = entry->findRoute(route);
105
106 // Route will be new
107 if (existingRoute == entry->end()) {
108 // Will the new route change the namespace's capture flag?
Junxiao Shi3f21e582017-05-29 15:26:32 +0000109 bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isRibCapture());
Vince Lehman76c751c2014-11-18 17:36:38 -0600110
111 createFibUpdatesForNewRoute(*entry, route, willCaptureBeTurnedOn);
112 }
113 else {
114 // Route already exists
115 RibEntry entryCopy = *entry;
116
117 Route& routeToUpdate = *(entryCopy.findRoute(route));
118
119 routeToUpdate.flags = route.flags;
120 routeToUpdate.cost = route.cost;
121 routeToUpdate.expires = route.expires;
122
123 createFibUpdatesForUpdatedRoute(entryCopy, route, *existingRoute);
124 }
125 }
126 else {
127 // New name in RIB
128 // Find prefix's parent
129 shared_ptr<RibEntry> parent = m_rib.findParent(prefix);
130
131 Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(prefix);
132 Rib::RibEntryList children;
133
134 for (const auto& descendant : descendants) {
135 // If the child has the same parent as the new entry,
136 // the new entry must be the child's new parent
137 if (descendant->getParent() == parent) {
138 children.push_back(descendant);
139 }
140 }
141
142 createFibUpdatesForNewRibEntry(prefix, route, children);
143 }
144}
145
146void
147FibUpdater::computeUpdatesForUnregistration(const RibUpdate& update)
148{
149 const Name& prefix = update.getName();
150 const Route& route = update.getRoute();
151
152 Rib::const_iterator ribIt = m_rib.find(prefix);
153
154 // Name prefix exists
155 if (ribIt != m_rib.end()) {
156 shared_ptr<const RibEntry> entry(ribIt->second);
157
158 const bool hadCapture = entry->hasCapture();
159
160 RibEntry::const_iterator existing = entry->findRoute(route);
161
162 if (existing != entry->end()) {
163 RibEntry temp = *entry;
164
165 // Erase route in temp entry
166 temp.eraseRoute(route);
167
168 const bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
169
170 createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
171
172 // The RibEntry still has the face ID; need to update FIB
173 // with lowest cost for the same face instead of removing the face from the FIB
174 const Route* next = entry->getRouteWithSecondLowestCostByFaceId(route.faceId);
175
176 if (next != nullptr) {
177 createFibUpdatesForNewRoute(temp, *next, false);
178 }
179
180 // The RibEntry will be empty after this removal
181 if (entry->getNRoutes() == 1) {
182 createFibUpdatesForErasedRibEntry(*entry);
183 }
184 }
185 }
186}
187
188void
189FibUpdater::sendUpdates(const FibUpdateList& updates,
190 const FibUpdateSuccessCallback& onSuccess,
191 const FibUpdateFailureCallback& onFailure)
192{
193 std::string updateString = (updates.size() == 1) ? " update" : " updates";
194 NFD_LOG_DEBUG("Applying " << updates.size() << updateString << " to FIB");
195
196 for (const FibUpdate& update : updates) {
197 NFD_LOG_DEBUG("Sending FIB update: " << update);
198
199 if (update.action == FibUpdate::ADD_NEXTHOP) {
200 sendAddNextHopUpdate(update, onSuccess, onFailure);
201 }
202 else if (update.action == FibUpdate::REMOVE_NEXTHOP) {
203 sendRemoveNextHopUpdate(update, onSuccess, onFailure);
204 }
205 }
206}
207
208void
209FibUpdater::sendUpdatesForBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
210 const FibUpdateFailureCallback& onFailure)
211{
212 if (m_updatesForBatchFaceId.size() > 0) {
213 sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
214 }
215 else {
216 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
217 }
218}
219
220void
221FibUpdater::sendUpdatesForNonBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
222 const FibUpdateFailureCallback& onFailure)
223{
224 if (m_updatesForNonBatchFaceId.size() > 0) {
225 sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
226 }
227 else {
228 onSuccess(m_inheritedRoutes);
229 }
230}
231
232void
233FibUpdater::sendAddNextHopUpdate(const FibUpdate& update,
234 const FibUpdateSuccessCallback& onSuccess,
235 const FibUpdateFailureCallback& onFailure,
236 uint32_t nTimeouts)
237{
238 m_controller.start<ndn::nfd::FibAddNextHopCommand>(
239 ControlParameters()
240 .setName(update.name)
241 .setFaceId(update.faceId)
242 .setCost(update.cost),
243 bind(&FibUpdater::onUpdateSuccess, this, update, onSuccess, onFailure),
Junxiao Shi29b41282016-08-22 03:47:02 +0000244 bind(&FibUpdater::onUpdateError, this, update, onSuccess, onFailure, _1, nTimeouts));
Vince Lehman76c751c2014-11-18 17:36:38 -0600245}
246
247void
248FibUpdater::sendRemoveNextHopUpdate(const FibUpdate& update,
249 const FibUpdateSuccessCallback& onSuccess,
250 const FibUpdateFailureCallback& onFailure,
251 uint32_t nTimeouts)
252{
253 m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
254 ControlParameters()
255 .setName(update.name)
256 .setFaceId(update.faceId),
257 bind(&FibUpdater::onUpdateSuccess, this, update, onSuccess, onFailure),
Junxiao Shi29b41282016-08-22 03:47:02 +0000258 bind(&FibUpdater::onUpdateError, this, update, onSuccess, onFailure, _1, nTimeouts));
Vince Lehman76c751c2014-11-18 17:36:38 -0600259}
260
261void
262FibUpdater::onUpdateSuccess(const FibUpdate update,
263 const FibUpdateSuccessCallback& onSuccess,
264 const FibUpdateFailureCallback& onFailure)
265{
266 if (update.faceId == m_batchFaceId) {
267 m_updatesForBatchFaceId.remove(update);
268
269 if (m_updatesForBatchFaceId.size() == 0) {
270 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
271 }
272 }
273 else {
274 m_updatesForNonBatchFaceId.remove(update);
275
276 if (m_updatesForNonBatchFaceId.size() == 0) {
277 onSuccess(m_inheritedRoutes);
278 }
279 }
280}
281
282void
283FibUpdater::onUpdateError(const FibUpdate update,
284 const FibUpdateSuccessCallback& onSuccess,
285 const FibUpdateFailureCallback& onFailure,
Junxiao Shi29b41282016-08-22 03:47:02 +0000286 const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
Vince Lehman76c751c2014-11-18 17:36:38 -0600287{
Junxiao Shi29b41282016-08-22 03:47:02 +0000288 uint32_t code = response.getCode();
289 NFD_LOG_DEBUG("Failed to apply " << update <<
290 " (code: " << code << ", error: " << response.getText() << ")");
Vince Lehman76c751c2014-11-18 17:36:38 -0600291
292 if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts < MAX_NUM_TIMEOUTS) {
293 sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
294 }
295 else if (code == ERROR_FACE_NOT_FOUND) {
296 if (update.faceId == m_batchFaceId) {
Junxiao Shi29b41282016-08-22 03:47:02 +0000297 onFailure(code, response.getText());
Vince Lehman76c751c2014-11-18 17:36:38 -0600298 }
299 else {
300 m_updatesForNonBatchFaceId.remove(update);
301
302 if (m_updatesForNonBatchFaceId.size() == 0) {
303 onSuccess(m_inheritedRoutes);
304 }
305 }
306 }
307 else {
Davide Pesavento19779d82019-02-14 13:40:04 -0500308 NDN_THROW(Error("Non-recoverable error: " + response.getText() + " code: " + to_string(code)));
Vince Lehman76c751c2014-11-18 17:36:38 -0600309 }
310}
311
312void
313FibUpdater::addFibUpdate(FibUpdate update)
314{
315 FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
316 m_updatesForNonBatchFaceId;
317
318 // If an update with the same name and route already exists,
319 // replace it
320 FibUpdateList::iterator it = std::find_if(updates.begin(), updates.end(),
321 [&update] (const FibUpdate& other) {
322 return update.name == other.name && update.faceId == other.faceId;
323 });
324
325 if (it != updates.end()) {
326 FibUpdate& existingUpdate = *it;
327 existingUpdate.action = update.action;
328 existingUpdate.cost = update.cost;
329 }
330 else {
331 updates.push_back(update);
332 }
333}
334
335void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500336FibUpdater::addInheritedRoutes(const RibEntry& entry, const Rib::RouteSet& routesToAdd)
Vince Lehman76c751c2014-11-18 17:36:38 -0600337{
338 for (const Route& route : routesToAdd) {
339 // Don't add an ancestor faceId if the namespace has an entry for that faceId
340 if (!entry.hasFaceId(route.faceId)) {
341 // Create a record of the inherited route so it can be added to the RIB later
342 addInheritedRoute(entry.getName(), route);
343
344 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
345 }
346 }
347}
348
349void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500350FibUpdater::addInheritedRoutes(const Name& name, const Rib::RouteSet& routesToAdd,
Vince Lehman76c751c2014-11-18 17:36:38 -0600351 const Route& ignore)
352{
353 for (const Route& route : routesToAdd) {
354 if (route.faceId != ignore.faceId) {
355 // Create a record of the inherited route so it can be added to the RIB later
356 addInheritedRoute(name, route);
357
358 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
359 }
360 }
361}
362
363void
364FibUpdater::removeInheritedRoutes(const RibEntry& entry, const Rib::Rib::RouteSet& routesToRemove)
365{
366 for (const Route& route : routesToRemove) {
367 // Only remove if the route has been inherited
368 if (entry.hasInheritedRoute(route)) {
369 removeInheritedRoute(entry.getName(), route);
370 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
371 }
372 }
373}
374
375void
376FibUpdater::createFibUpdatesForNewRibEntry(const Name& name, const Route& route,
377 const Rib::RibEntryList& children)
378{
379 // Create FIB update for new entry
380 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
381
382 // No flags are set
Junxiao Shi3f21e582017-05-29 15:26:32 +0000383 if (!route.isChildInherit() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600384 // Add ancestor routes to self
385 addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
386 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000387 else if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600388 // Add route to children
389 Rib::RouteSet routesToAdd;
390 routesToAdd.insert(route);
391
392 // Remove routes blocked by capture and add self to children
393 modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
394 }
395 else if (route.isChildInherit()) {
396 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
397
398 // Add ancestor routes to self
399 addInheritedRoutes(name, ancestorRoutes, route);
400
401 // If there is an ancestor route which is the same as the new route, replace it
402 // with the new route
403 Rib::RouteSet::iterator it = ancestorRoutes.find(route);
404
405 // There is a route that needs to be overwritten, erase and then replace
406 if (it != ancestorRoutes.end()) {
407 ancestorRoutes.erase(it);
408 }
409
410 // Add new route to ancestor list so it can be added to children
411 ancestorRoutes.insert(route);
412
413 // Add ancestor routes to children
414 modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
415 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000416 else if (route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600417 // Remove routes blocked by capture
418 modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
419 }
420}
421
422void
423FibUpdater::createFibUpdatesForNewRoute(const RibEntry& entry, const Route& route,
424 bool captureWasTurnedOn)
425{
426 // Only update if the new route has a lower cost than a previously installed route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500427 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600428
429 Rib::RouteSet routesToAdd;
430 if (route.isChildInherit()) {
431 // Add to children if this new route doesn't override a previous lower cost, or
432 // add to children if this new route is lower cost than a previous route.
433 // Less than equal, since entry may find this route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500434 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600435 // Add self to children
436 routesToAdd.insert(route);
437 }
438 }
439
440 Rib::RouteSet routesToRemove;
441 if (captureWasTurnedOn) {
442 // Capture flag on
443 routesToRemove = m_rib.getAncestorRoutes(entry);
444
445 // Remove ancestor routes from self
446 removeInheritedRoutes(entry, routesToRemove);
447 }
448
449 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
450
451 // If another route with same faceId and lower cost exists, don't update.
452 // Must be done last so that add updates replace removal updates
453 // Create FIB update for new entry
Vince Lehman9dcfc402015-03-26 03:18:54 -0500454 const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600455
Vince Lehman9dcfc402015-03-26 03:18:54 -0500456 if (other == nullptr || route.cost <= other->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600457 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
458 }
459}
460
461void
462FibUpdater::createFibUpdatesForUpdatedRoute(const RibEntry& entry, const Route& route,
463 const Route& existingRoute)
464{
465 const bool costDidChange = (route.cost != existingRoute.cost);
466
467 // Look for an installed route with the lowest cost and child inherit set
Vince Lehman9dcfc402015-03-26 03:18:54 -0500468 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600469
470 // No flags changed and cost didn't change, no change in FIB
471 if (route.flags == existingRoute.flags && !costDidChange) {
472 return;
473 }
474
475 // Cost changed so create update for the entry itself
476 if (costDidChange) {
477 // Create update if this route's cost is lower than other routes
478 if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
479 // Create FIB update for the updated entry
480 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
481 }
482 else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
483 // Create update if this route used to be the lowest route but is no longer
484 // the lowest cost route.
485 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), prevRoute->faceId, prevRoute->cost));
486 }
487
488 // If another route with same faceId and lower cost and ChildInherit exists,
489 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500490 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600491 // If no flags changed but child inheritance is set, need to update children
492 // with new cost
493 if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
494 // Add self to children
495 Rib::RouteSet routesToAdd;
496 routesToAdd.insert(route);
497 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
498
499 return;
500 }
501 }
502 }
503
504 // Child inherit was turned on
505 if (!existingRoute.isChildInherit() && route.isChildInherit()) {
506 // If another route with same faceId and lower cost and ChildInherit exists,
507 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500508 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600509 // Add self to children
510 Rib::RouteSet routesToAdd;
511 routesToAdd.insert(route);
512 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
513 }
514 } // Child inherit was turned off
515 else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
516 // Remove self from children
517 Rib::RouteSet routesToRemove;
518 routesToRemove.insert(route);
519
520 Rib::RouteSet routesToAdd;
521 // If another route with same faceId and ChildInherit exists, update children with this route.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500522 if (prevRoute != nullptr) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600523 routesToAdd.insert(*prevRoute);
524 }
525 else {
526 // Look for an ancestor that was blocked previously
527 const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
528 Rib::RouteSet::iterator it = ancestorRoutes.find(route);
529
530 // If an ancestor is found, add it to children
531 if (it != ancestorRoutes.end()) {
532 routesToAdd.insert(*it);
533 }
534 }
535
536 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
537 }
538
539 // Capture was turned on
Junxiao Shi3f21e582017-05-29 15:26:32 +0000540 if (!existingRoute.isRibCapture() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600541 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
542
543 // Remove ancestor routes from self
544 removeInheritedRoutes(entry, ancestorRoutes);
545
546 // Remove ancestor routes from children
547 modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
548 } // Capture was turned off
Junxiao Shi3f21e582017-05-29 15:26:32 +0000549 else if (existingRoute.isRibCapture() && !route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600550 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
551
552 // Add ancestor routes to self
553 addInheritedRoutes(entry, ancestorRoutes);
554
555 // Add ancestor routes to children
556 modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
557 }
558}
559
560void
561FibUpdater::createFibUpdatesForErasedRoute(const RibEntry& entry, const Route& route,
562 const bool captureWasTurnedOff)
563{
564 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
565
Junxiao Shi3f21e582017-05-29 15:26:32 +0000566 if (route.isChildInherit() && route.isRibCapture()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600567 // Remove self from children
568 Rib::RouteSet routesToRemove;
569 routesToRemove.insert(route);
570
Vince Lehman9aac8732016-01-11 15:49:23 -0600571 // If capture is turned off for the route and another route is installed in the RibEntry,
572 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600573 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600574 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600575 // Look for an ancestors that were blocked previously
576 routesToAdd = m_rib.getAncestorRoutes(entry);
577
578 // Add ancestor routes to self
579 addInheritedRoutes(entry, routesToAdd);
580 }
581
582 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
583 }
584 else if (route.isChildInherit()) {
585 // If not blocked by capture, add inherited routes to children
586 Rib::RouteSet routesToAdd;
587 if (!entry.hasCapture()) {
588 routesToAdd = m_rib.getAncestorRoutes(entry);
589 }
590
591 Rib::RouteSet routesToRemove;
592 routesToRemove.insert(route);
593
594 // Add ancestor routes to children
595 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
596 }
Junxiao Shi3f21e582017-05-29 15:26:32 +0000597 else if (route.isRibCapture()) {
Vince Lehman9aac8732016-01-11 15:49:23 -0600598 // If capture is turned off for the route and another route is installed in the RibEntry,
599 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600600 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600601 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600602 // Look for an ancestors that were blocked previously
603 routesToAdd = m_rib.getAncestorRoutes(entry);
604
605 // Add ancestor routes to self
606 addInheritedRoutes(entry, routesToAdd);
607 }
608
609 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
610 }
611
612 // Need to check if the removed route was blocking an inherited route
613 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
614
Vince Lehmanf91ab742015-04-23 15:26:55 -0500615 // If the current entry has capture set or is pending removal, don't add inherited route
616 if (!entry.hasCapture() && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600617 // If there is an ancestor route which is the same as the erased route, add that route
618 // to the current entry
619 Rib::RouteSet::iterator it = ancestorRoutes.find(route);
620
621 if (it != ancestorRoutes.end()) {
622 addInheritedRoute(entry.getName(), *it);
623 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), it->faceId, it->cost));
624 }
625 }
626}
627
628void
629FibUpdater::createFibUpdatesForErasedRibEntry(const RibEntry& entry)
630{
631 for (const Route& route : entry.getInheritedRoutes()) {
632 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
633 }
634}
635
636void
637FibUpdater::modifyChildrensInheritedRoutes(const Rib::RibEntryList& children,
638 const Rib::RouteSet& routesToAdd,
639 const Rib::RouteSet& routesToRemove)
640{
641 for (const auto& child : children) {
642 traverseSubTree(*child, routesToAdd, routesToRemove);
643 }
644}
645
646void
647FibUpdater::traverseSubTree(const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
648 Rib::Rib::RouteSet routesToRemove)
649{
650 // If a route on the namespace has the capture flag set, ignore self and children
651 if (entry.hasCapture()) {
652 return;
653 }
654
655 // Remove inherited routes from current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400656 for (auto removeIt = routesToRemove.begin(); removeIt != routesToRemove.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600657 // If a route on the namespace has the same face ID and child inheritance set,
658 // ignore this route
659 if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400660 removeIt = routesToRemove.erase(removeIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600661 continue;
662 }
663
664 // Only remove route if it removes an existing inherited route
665 if (entry.hasInheritedRoute(*removeIt)) {
666 removeInheritedRoute(entry.getName(), *removeIt);
667 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), removeIt->faceId));
668 }
669
670 ++removeIt;
671 }
672
673 // Add inherited routes to current namespace
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400674 for (auto addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600675 // If a route on the namespace has the same face ID and child inherit set, ignore this face
676 if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400677 addIt = routesToAdd.erase(addIt);
Vince Lehman76c751c2014-11-18 17:36:38 -0600678 continue;
679 }
680
681 // Only add route if it does not override an existing route
682 if (!entry.hasFaceId(addIt->faceId)) {
683 addInheritedRoute(entry.getName(), *addIt);
684 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), addIt->faceId, addIt->cost));
685 }
686
687 ++addIt;
688 }
689
690 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
691}
692
693void
694FibUpdater::addInheritedRoute(const Name& name, const Route& route)
695{
696 RibUpdate update;
697 update.setAction(RibUpdate::REGISTER)
698 .setName(name)
699 .setRoute(route);
700
701 m_inheritedRoutes.push_back(update);
702}
703
704void
705FibUpdater::removeInheritedRoute(const Name& name, const Route& route)
706{
707 RibUpdate update;
708 update.setAction(RibUpdate::UNREGISTER)
709 .setName(name)
710 .setRoute(route);
711
712 m_inheritedRoutes.push_back(update);
713}
714
715} // namespace rib
716} // namespace nfd