blob: c6b4f09a4b1198d55fd6828c22611731d3cc7bae [file] [log] [blame]
Vince Lehman76c751c2014-11-18 17:36:38 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi41006462016-01-19 07:31:59 -07003 * Copyright (c) 2014-2016, 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"
27
28#include "core/logger.hpp"
29
30#include <ndn-cxx/management/nfd-control-parameters.hpp>
31
32namespace nfd {
33namespace rib {
34
35using ndn::nfd::ControlParameters;
36
37NFD_LOG_INIT("FibUpdater");
38
39const unsigned int FibUpdater::MAX_NUM_TIMEOUTS = 10;
40const uint32_t FibUpdater::ERROR_FACE_NOT_FOUND = 410;
41
42FibUpdater::FibUpdater(Rib& rib, ndn::nfd::Controller& controller)
43 : m_rib(rib)
44 , m_controller(controller)
45{
46 rib.setFibUpdater(this);
47}
48
49void
50FibUpdater::computeAndSendFibUpdates(const RibUpdateBatch& batch,
51 const FibUpdateSuccessCallback& onSuccess,
52 const FibUpdateFailureCallback& onFailure)
53{
54 m_batchFaceId = batch.getFaceId();
55
56 // Erase previously calculated inherited routes
57 m_inheritedRoutes.clear();
58
59 // Erase previously calculated FIB updates
60 m_updatesForBatchFaceId.clear();
61 m_updatesForNonBatchFaceId.clear();
62
63 computeUpdates(batch);
64
65 sendUpdatesForBatchFaceId(onSuccess, onFailure);
66}
67
68void
69FibUpdater::computeUpdates(const RibUpdateBatch& batch)
70{
71 NFD_LOG_DEBUG("Computing updates for batch with faceID: " << batch.getFaceId());
72
73 // Compute updates and add to m_fibUpdates
74 for (const RibUpdate& update : batch)
75 {
76 switch(update.getAction()) {
77 case RibUpdate::REGISTER:
78 computeUpdatesForRegistration(update);
79 break;
80 case RibUpdate::UNREGISTER:
81 computeUpdatesForUnregistration(update);
82 break;
83 case RibUpdate::REMOVE_FACE:
84 computeUpdatesForUnregistration(update);
85
86 // Do not apply updates with the same face ID as the destroyed face
87 // since they will be rejected by the FIB
88 m_updatesForBatchFaceId.clear();
89 break;
90 }
91 }
92}
93
94void
95FibUpdater::computeUpdatesForRegistration(const RibUpdate& update)
96{
97 const Name& prefix = update.getName();
98 const Route& route = update.getRoute();
99
100 Rib::const_iterator it = m_rib.find(prefix);
101
102 // Name prefix exists
103 if (it != m_rib.end()) {
104 shared_ptr<const RibEntry> entry(it->second);
105
106 RibEntry::const_iterator existingRoute = entry->findRoute(route);
107
108 // Route will be new
109 if (existingRoute == entry->end()) {
110 // Will the new route change the namespace's capture flag?
111 bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isCapture());
112
113 createFibUpdatesForNewRoute(*entry, route, willCaptureBeTurnedOn);
114 }
115 else {
116 // Route already exists
117 RibEntry entryCopy = *entry;
118
119 Route& routeToUpdate = *(entryCopy.findRoute(route));
120
121 routeToUpdate.flags = route.flags;
122 routeToUpdate.cost = route.cost;
123 routeToUpdate.expires = route.expires;
124
125 createFibUpdatesForUpdatedRoute(entryCopy, route, *existingRoute);
126 }
127 }
128 else {
129 // New name in RIB
130 // Find prefix's parent
131 shared_ptr<RibEntry> parent = m_rib.findParent(prefix);
132
133 Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(prefix);
134 Rib::RibEntryList children;
135
136 for (const auto& descendant : descendants) {
137 // If the child has the same parent as the new entry,
138 // the new entry must be the child's new parent
139 if (descendant->getParent() == parent) {
140 children.push_back(descendant);
141 }
142 }
143
144 createFibUpdatesForNewRibEntry(prefix, route, children);
145 }
146}
147
148void
149FibUpdater::computeUpdatesForUnregistration(const RibUpdate& update)
150{
151 const Name& prefix = update.getName();
152 const Route& route = update.getRoute();
153
154 Rib::const_iterator ribIt = m_rib.find(prefix);
155
156 // Name prefix exists
157 if (ribIt != m_rib.end()) {
158 shared_ptr<const RibEntry> entry(ribIt->second);
159
160 const bool hadCapture = entry->hasCapture();
161
162 RibEntry::const_iterator existing = entry->findRoute(route);
163
164 if (existing != entry->end()) {
165 RibEntry temp = *entry;
166
167 // Erase route in temp entry
168 temp.eraseRoute(route);
169
170 const bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
171
172 createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
173
174 // The RibEntry still has the face ID; need to update FIB
175 // with lowest cost for the same face instead of removing the face from the FIB
176 const Route* next = entry->getRouteWithSecondLowestCostByFaceId(route.faceId);
177
178 if (next != nullptr) {
179 createFibUpdatesForNewRoute(temp, *next, false);
180 }
181
182 // The RibEntry will be empty after this removal
183 if (entry->getNRoutes() == 1) {
184 createFibUpdatesForErasedRibEntry(*entry);
185 }
186 }
187 }
188}
189
190void
191FibUpdater::sendUpdates(const FibUpdateList& updates,
192 const FibUpdateSuccessCallback& onSuccess,
193 const FibUpdateFailureCallback& onFailure)
194{
195 std::string updateString = (updates.size() == 1) ? " update" : " updates";
196 NFD_LOG_DEBUG("Applying " << updates.size() << updateString << " to FIB");
197
198 for (const FibUpdate& update : updates) {
199 NFD_LOG_DEBUG("Sending FIB update: " << update);
200
201 if (update.action == FibUpdate::ADD_NEXTHOP) {
202 sendAddNextHopUpdate(update, onSuccess, onFailure);
203 }
204 else if (update.action == FibUpdate::REMOVE_NEXTHOP) {
205 sendRemoveNextHopUpdate(update, onSuccess, onFailure);
206 }
207 }
208}
209
210void
211FibUpdater::sendUpdatesForBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
212 const FibUpdateFailureCallback& onFailure)
213{
214 if (m_updatesForBatchFaceId.size() > 0) {
215 sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
216 }
217 else {
218 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
219 }
220}
221
222void
223FibUpdater::sendUpdatesForNonBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
224 const FibUpdateFailureCallback& onFailure)
225{
226 if (m_updatesForNonBatchFaceId.size() > 0) {
227 sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
228 }
229 else {
230 onSuccess(m_inheritedRoutes);
231 }
232}
233
234void
235FibUpdater::sendAddNextHopUpdate(const FibUpdate& update,
236 const FibUpdateSuccessCallback& onSuccess,
237 const FibUpdateFailureCallback& onFailure,
238 uint32_t nTimeouts)
239{
240 m_controller.start<ndn::nfd::FibAddNextHopCommand>(
241 ControlParameters()
242 .setName(update.name)
243 .setFaceId(update.faceId)
244 .setCost(update.cost),
245 bind(&FibUpdater::onUpdateSuccess, this, update, onSuccess, onFailure),
Junxiao Shi29b41282016-08-22 03:47:02 +0000246 bind(&FibUpdater::onUpdateError, this, update, onSuccess, onFailure, _1, nTimeouts));
Vince Lehman76c751c2014-11-18 17:36:38 -0600247}
248
249void
250FibUpdater::sendRemoveNextHopUpdate(const FibUpdate& update,
251 const FibUpdateSuccessCallback& onSuccess,
252 const FibUpdateFailureCallback& onFailure,
253 uint32_t nTimeouts)
254{
255 m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
256 ControlParameters()
257 .setName(update.name)
258 .setFaceId(update.faceId),
259 bind(&FibUpdater::onUpdateSuccess, this, update, onSuccess, onFailure),
Junxiao Shi29b41282016-08-22 03:47:02 +0000260 bind(&FibUpdater::onUpdateError, this, update, onSuccess, onFailure, _1, nTimeouts));
Vince Lehman76c751c2014-11-18 17:36:38 -0600261}
262
263void
264FibUpdater::onUpdateSuccess(const FibUpdate update,
265 const FibUpdateSuccessCallback& onSuccess,
266 const FibUpdateFailureCallback& onFailure)
267{
268 if (update.faceId == m_batchFaceId) {
269 m_updatesForBatchFaceId.remove(update);
270
271 if (m_updatesForBatchFaceId.size() == 0) {
272 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
273 }
274 }
275 else {
276 m_updatesForNonBatchFaceId.remove(update);
277
278 if (m_updatesForNonBatchFaceId.size() == 0) {
279 onSuccess(m_inheritedRoutes);
280 }
281 }
282}
283
284void
285FibUpdater::onUpdateError(const FibUpdate update,
286 const FibUpdateSuccessCallback& onSuccess,
287 const FibUpdateFailureCallback& onFailure,
Junxiao Shi29b41282016-08-22 03:47:02 +0000288 const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
Vince Lehman76c751c2014-11-18 17:36:38 -0600289{
Junxiao Shi29b41282016-08-22 03:47:02 +0000290 uint32_t code = response.getCode();
291 NFD_LOG_DEBUG("Failed to apply " << update <<
292 " (code: " << code << ", error: " << response.getText() << ")");
Vince Lehman76c751c2014-11-18 17:36:38 -0600293
294 if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts < MAX_NUM_TIMEOUTS) {
295 sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
296 }
297 else if (code == ERROR_FACE_NOT_FOUND) {
298 if (update.faceId == m_batchFaceId) {
Junxiao Shi29b41282016-08-22 03:47:02 +0000299 onFailure(code, response.getText());
Vince Lehman76c751c2014-11-18 17:36:38 -0600300 }
301 else {
302 m_updatesForNonBatchFaceId.remove(update);
303
304 if (m_updatesForNonBatchFaceId.size() == 0) {
305 onSuccess(m_inheritedRoutes);
306 }
307 }
308 }
309 else {
Junxiao Shi29b41282016-08-22 03:47:02 +0000310 BOOST_THROW_EXCEPTION(Error("Non-recoverable error: " + response.getText() +
311 " code: " + to_string(code)));
Vince Lehman76c751c2014-11-18 17:36:38 -0600312 }
313}
314
315void
316FibUpdater::addFibUpdate(FibUpdate update)
317{
318 FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
319 m_updatesForNonBatchFaceId;
320
321 // If an update with the same name and route already exists,
322 // replace it
323 FibUpdateList::iterator it = std::find_if(updates.begin(), updates.end(),
324 [&update] (const FibUpdate& other) {
325 return update.name == other.name && update.faceId == other.faceId;
326 });
327
328 if (it != updates.end()) {
329 FibUpdate& existingUpdate = *it;
330 existingUpdate.action = update.action;
331 existingUpdate.cost = update.cost;
332 }
333 else {
334 updates.push_back(update);
335 }
336}
337
338void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500339FibUpdater::addInheritedRoutes(const RibEntry& entry, const Rib::RouteSet& routesToAdd)
Vince Lehman76c751c2014-11-18 17:36:38 -0600340{
341 for (const Route& route : routesToAdd) {
342 // Don't add an ancestor faceId if the namespace has an entry for that faceId
343 if (!entry.hasFaceId(route.faceId)) {
344 // Create a record of the inherited route so it can be added to the RIB later
345 addInheritedRoute(entry.getName(), route);
346
347 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
348 }
349 }
350}
351
352void
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500353FibUpdater::addInheritedRoutes(const Name& name, const Rib::RouteSet& routesToAdd,
Vince Lehman76c751c2014-11-18 17:36:38 -0600354 const Route& ignore)
355{
356 for (const Route& route : routesToAdd) {
357 if (route.faceId != ignore.faceId) {
358 // Create a record of the inherited route so it can be added to the RIB later
359 addInheritedRoute(name, route);
360
361 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
362 }
363 }
364}
365
366void
367FibUpdater::removeInheritedRoutes(const RibEntry& entry, const Rib::Rib::RouteSet& routesToRemove)
368{
369 for (const Route& route : routesToRemove) {
370 // Only remove if the route has been inherited
371 if (entry.hasInheritedRoute(route)) {
372 removeInheritedRoute(entry.getName(), route);
373 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
374 }
375 }
376}
377
378void
379FibUpdater::createFibUpdatesForNewRibEntry(const Name& name, const Route& route,
380 const Rib::RibEntryList& children)
381{
382 // Create FIB update for new entry
383 addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
384
385 // No flags are set
386 if (!route.isChildInherit() && !route.isCapture()) {
387 // Add ancestor routes to self
388 addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
389 }
390 else if (route.isChildInherit() && route.isCapture()) {
391 // Add route to children
392 Rib::RouteSet routesToAdd;
393 routesToAdd.insert(route);
394
395 // Remove routes blocked by capture and add self to children
396 modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
397 }
398 else if (route.isChildInherit()) {
399 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
400
401 // Add ancestor routes to self
402 addInheritedRoutes(name, ancestorRoutes, route);
403
404 // If there is an ancestor route which is the same as the new route, replace it
405 // with the new route
406 Rib::RouteSet::iterator it = ancestorRoutes.find(route);
407
408 // There is a route that needs to be overwritten, erase and then replace
409 if (it != ancestorRoutes.end()) {
410 ancestorRoutes.erase(it);
411 }
412
413 // Add new route to ancestor list so it can be added to children
414 ancestorRoutes.insert(route);
415
416 // Add ancestor routes to children
417 modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
418 }
419 else if (route.isCapture()) {
420 // Remove routes blocked by capture
421 modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
422 }
423}
424
425void
426FibUpdater::createFibUpdatesForNewRoute(const RibEntry& entry, const Route& route,
427 bool captureWasTurnedOn)
428{
429 // Only update if the new route has a lower cost than a previously installed route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500430 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600431
432 Rib::RouteSet routesToAdd;
433 if (route.isChildInherit()) {
434 // Add to children if this new route doesn't override a previous lower cost, or
435 // add to children if this new route is lower cost than a previous route.
436 // Less than equal, since entry may find this route
Vince Lehman9dcfc402015-03-26 03:18:54 -0500437 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600438 // Add self to children
439 routesToAdd.insert(route);
440 }
441 }
442
443 Rib::RouteSet routesToRemove;
444 if (captureWasTurnedOn) {
445 // Capture flag on
446 routesToRemove = m_rib.getAncestorRoutes(entry);
447
448 // Remove ancestor routes from self
449 removeInheritedRoutes(entry, routesToRemove);
450 }
451
452 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
453
454 // If another route with same faceId and lower cost exists, don't update.
455 // Must be done last so that add updates replace removal updates
456 // Create FIB update for new entry
Vince Lehman9dcfc402015-03-26 03:18:54 -0500457 const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600458
Vince Lehman9dcfc402015-03-26 03:18:54 -0500459 if (other == nullptr || route.cost <= other->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600460 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
461 }
462}
463
464void
465FibUpdater::createFibUpdatesForUpdatedRoute(const RibEntry& entry, const Route& route,
466 const Route& existingRoute)
467{
468 const bool costDidChange = (route.cost != existingRoute.cost);
469
470 // Look for an installed route with the lowest cost and child inherit set
Vince Lehman9dcfc402015-03-26 03:18:54 -0500471 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
Vince Lehman76c751c2014-11-18 17:36:38 -0600472
473 // No flags changed and cost didn't change, no change in FIB
474 if (route.flags == existingRoute.flags && !costDidChange) {
475 return;
476 }
477
478 // Cost changed so create update for the entry itself
479 if (costDidChange) {
480 // Create update if this route's cost is lower than other routes
481 if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
482 // Create FIB update for the updated entry
483 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
484 }
485 else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
486 // Create update if this route used to be the lowest route but is no longer
487 // the lowest cost route.
488 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), prevRoute->faceId, prevRoute->cost));
489 }
490
491 // If another route with same faceId and lower cost and ChildInherit exists,
492 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500493 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600494 // If no flags changed but child inheritance is set, need to update children
495 // with new cost
496 if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
497 // Add self to children
498 Rib::RouteSet routesToAdd;
499 routesToAdd.insert(route);
500 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
501
502 return;
503 }
504 }
505 }
506
507 // Child inherit was turned on
508 if (!existingRoute.isChildInherit() && route.isChildInherit()) {
509 // If another route with same faceId and lower cost and ChildInherit exists,
510 // don't update children.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500511 if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600512 // Add self to children
513 Rib::RouteSet routesToAdd;
514 routesToAdd.insert(route);
515 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
516 }
517 } // Child inherit was turned off
518 else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
519 // Remove self from children
520 Rib::RouteSet routesToRemove;
521 routesToRemove.insert(route);
522
523 Rib::RouteSet routesToAdd;
524 // If another route with same faceId and ChildInherit exists, update children with this route.
Vince Lehman9dcfc402015-03-26 03:18:54 -0500525 if (prevRoute != nullptr) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600526 routesToAdd.insert(*prevRoute);
527 }
528 else {
529 // Look for an ancestor that was blocked previously
530 const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
531 Rib::RouteSet::iterator it = ancestorRoutes.find(route);
532
533 // If an ancestor is found, add it to children
534 if (it != ancestorRoutes.end()) {
535 routesToAdd.insert(*it);
536 }
537 }
538
539 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
540 }
541
542 // Capture was turned on
543 if (!existingRoute.isCapture() && route.isCapture()) {
544 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
545
546 // Remove ancestor routes from self
547 removeInheritedRoutes(entry, ancestorRoutes);
548
549 // Remove ancestor routes from children
550 modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
551 } // Capture was turned off
552 else if (existingRoute.isCapture() && !route.isCapture()) {
553 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
554
555 // Add ancestor routes to self
556 addInheritedRoutes(entry, ancestorRoutes);
557
558 // Add ancestor routes to children
559 modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
560 }
561}
562
563void
564FibUpdater::createFibUpdatesForErasedRoute(const RibEntry& entry, const Route& route,
565 const bool captureWasTurnedOff)
566{
567 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
568
569 if (route.isChildInherit() && route.isCapture()) {
570 // Remove self from children
571 Rib::RouteSet routesToRemove;
572 routesToRemove.insert(route);
573
Vince Lehman9aac8732016-01-11 15:49:23 -0600574 // If capture is turned off for the route and another route is installed in the RibEntry,
575 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600576 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600577 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600578 // Look for an ancestors that were blocked previously
579 routesToAdd = m_rib.getAncestorRoutes(entry);
580
581 // Add ancestor routes to self
582 addInheritedRoutes(entry, routesToAdd);
583 }
584
585 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
586 }
587 else if (route.isChildInherit()) {
588 // If not blocked by capture, add inherited routes to children
589 Rib::RouteSet routesToAdd;
590 if (!entry.hasCapture()) {
591 routesToAdd = m_rib.getAncestorRoutes(entry);
592 }
593
594 Rib::RouteSet routesToRemove;
595 routesToRemove.insert(route);
596
597 // Add ancestor routes to children
598 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
599 }
600 else if (route.isCapture()) {
Vince Lehman9aac8732016-01-11 15:49:23 -0600601 // If capture is turned off for the route and another route is installed in the RibEntry,
602 // add ancestors to self
Vince Lehman76c751c2014-11-18 17:36:38 -0600603 Rib::RouteSet routesToAdd;
Vince Lehman9aac8732016-01-11 15:49:23 -0600604 if (captureWasTurnedOff && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600605 // Look for an ancestors that were blocked previously
606 routesToAdd = m_rib.getAncestorRoutes(entry);
607
608 // Add ancestor routes to self
609 addInheritedRoutes(entry, routesToAdd);
610 }
611
612 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
613 }
614
615 // Need to check if the removed route was blocking an inherited route
616 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
617
Vince Lehmanf91ab742015-04-23 15:26:55 -0500618 // If the current entry has capture set or is pending removal, don't add inherited route
619 if (!entry.hasCapture() && entry.getNRoutes() != 0) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600620 // If there is an ancestor route which is the same as the erased route, add that route
621 // to the current entry
622 Rib::RouteSet::iterator it = ancestorRoutes.find(route);
623
624 if (it != ancestorRoutes.end()) {
625 addInheritedRoute(entry.getName(), *it);
626 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), it->faceId, it->cost));
627 }
628 }
629}
630
631void
632FibUpdater::createFibUpdatesForErasedRibEntry(const RibEntry& entry)
633{
634 for (const Route& route : entry.getInheritedRoutes()) {
635 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
636 }
637}
638
639void
640FibUpdater::modifyChildrensInheritedRoutes(const Rib::RibEntryList& children,
641 const Rib::RouteSet& routesToAdd,
642 const Rib::RouteSet& routesToRemove)
643{
644 for (const auto& child : children) {
645 traverseSubTree(*child, routesToAdd, routesToRemove);
646 }
647}
648
649void
650FibUpdater::traverseSubTree(const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
651 Rib::Rib::RouteSet routesToRemove)
652{
653 // If a route on the namespace has the capture flag set, ignore self and children
654 if (entry.hasCapture()) {
655 return;
656 }
657
658 // Remove inherited routes from current namespace
659 for (Rib::RouteSet::const_iterator removeIt = routesToRemove.begin();
660 removeIt != routesToRemove.end(); )
661 {
662 // If a route on the namespace has the same face ID and child inheritance set,
663 // ignore this route
664 if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
665 routesToRemove.erase(removeIt++);
666 continue;
667 }
668
669 // Only remove route if it removes an existing inherited route
670 if (entry.hasInheritedRoute(*removeIt)) {
671 removeInheritedRoute(entry.getName(), *removeIt);
672 addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), removeIt->faceId));
673 }
674
675 ++removeIt;
676 }
677
678 // Add inherited routes to current namespace
679 for (Rib::RouteSet::const_iterator addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
680
681 // If a route on the namespace has the same face ID and child inherit set, ignore this face
682 if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
683 routesToAdd.erase(addIt++);
684 continue;
685 }
686
687 // Only add route if it does not override an existing route
688 if (!entry.hasFaceId(addIt->faceId)) {
689 addInheritedRoute(entry.getName(), *addIt);
690 addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), addIt->faceId, addIt->cost));
691 }
692
693 ++addIt;
694 }
695
696 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
697}
698
699void
700FibUpdater::addInheritedRoute(const Name& name, const Route& route)
701{
702 RibUpdate update;
703 update.setAction(RibUpdate::REGISTER)
704 .setName(name)
705 .setRoute(route);
706
707 m_inheritedRoutes.push_back(update);
708}
709
710void
711FibUpdater::removeInheritedRoute(const Name& name, const Route& route)
712{
713 RibUpdate update;
714 update.setAction(RibUpdate::UNREGISTER)
715 .setName(name)
716 .setRoute(route);
717
718 m_inheritedRoutes.push_back(update);
719}
720
721} // namespace rib
722} // namespace nfd