29#include <ndn-cxx/mgmt/nfd/control-command.hpp>
40 , m_controller(controller)
53 m_inheritedRoutes.clear();
56 m_updatesForBatchFaceId.clear();
57 m_updatesForNonBatchFaceId.clear();
59 computeUpdates(batch);
61 sendUpdatesForBatchFaceId(onSuccess, onFailure);
71 switch (update.action) {
73 computeUpdatesForRegistration(update);
76 computeUpdatesForUnregistration(update);
79 computeUpdatesForUnregistration(update);
82 m_updatesForBatchFaceId.clear();
89FibUpdater::computeUpdatesForRegistration(
const RibUpdate& update)
91 auto it = m_rib.
find(update.name);
94 if (it != m_rib.
end()) {
95 shared_ptr<const RibEntry> entry(it->second);
96 auto existingRoute = entry->findRoute(update.route);
99 if (existingRoute == entry->end()) {
101 bool willCaptureBeTurnedOn = (!entry->hasCapture() && update.route.isRibCapture());
103 createFibUpdatesForNewRoute(*entry, update.route, willCaptureBeTurnedOn);
107 RibEntry entryCopy = *entry;
109 Route& routeToUpdate = *entryCopy.findRoute(update.route);
110 routeToUpdate.flags = update.route.flags;
111 routeToUpdate.cost = update.route.cost;
112 routeToUpdate.expires = update.route.expires;
114 createFibUpdatesForUpdatedRoute(entryCopy, update.route, *existingRoute);
120 shared_ptr<RibEntry> parent = m_rib.
findParent(update.name);
122 Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(update.name);
125 for (
const auto& descendant : descendants) {
128 if (descendant->getParent() == parent) {
129 children.push_back(descendant);
133 createFibUpdatesForNewRibEntry(update.name, update.route, children);
138FibUpdater::computeUpdatesForUnregistration(
const RibUpdate& update)
140 auto ribIt = m_rib.
find(update.name);
143 if (ribIt != m_rib.
end()) {
144 shared_ptr<const RibEntry> entry(ribIt->second);
145 const bool hadCapture = entry->hasCapture();
147 auto existing = entry->findRoute(update.route);
148 if (existing != entry->end()) {
149 RibEntry temp = *entry;
152 temp.eraseRoute(update.route);
154 bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
155 createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
159 const Route* next = entry->getRouteWithSecondLowestCostByFaceId(update.route.faceId);
161 if (next !=
nullptr) {
162 createFibUpdatesForNewRoute(temp, *next,
false);
166 if (entry->getRoutes().size() == 1) {
167 createFibUpdatesForErasedRibEntry(*entry);
174FibUpdater::sendUpdates(
const FibUpdateList& updates,
175 const FibUpdateSuccessCallback& onSuccess,
176 const FibUpdateFailureCallback& onFailure)
178 NFD_LOG_DEBUG(
"Applying " << updates.size() <<
" FIB update(s)");
180 for (
const FibUpdate& update : updates) {
184 sendAddNextHopUpdate(update, onSuccess, onFailure);
187 sendRemoveNextHopUpdate(update, onSuccess, onFailure);
193FibUpdater::sendUpdatesForBatchFaceId(
const FibUpdateSuccessCallback& onSuccess,
194 const FibUpdateFailureCallback& onFailure)
196 if (m_updatesForBatchFaceId.size() > 0) {
197 sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
200 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
205FibUpdater::sendUpdatesForNonBatchFaceId(
const FibUpdateSuccessCallback& onSuccess,
206 const FibUpdateFailureCallback& onFailure)
208 if (m_updatesForNonBatchFaceId.size() > 0) {
209 sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
212 onSuccess(m_inheritedRoutes);
217FibUpdater::sendAddNextHopUpdate(
const FibUpdate& update,
218 const FibUpdateSuccessCallback& onSuccess,
219 const FibUpdateFailureCallback& onFailure,
222 m_controller.start<ndn::nfd::FibAddNextHopCommand>(
224 .setName(update.name)
225 .setFaceId(update.faceId)
226 .setCost(update.cost),
227 [=] (
const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
228 [=] (
const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
232FibUpdater::sendRemoveNextHopUpdate(
const FibUpdate& update,
233 const FibUpdateSuccessCallback& onSuccess,
234 const FibUpdateFailureCallback& onFailure,
237 m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
239 .setName(update.name)
240 .setFaceId(update.faceId),
241 [=] (
const auto&) { onUpdateSuccess(update, onSuccess, onFailure); },
242 [=] (
const auto& resp) { onUpdateError(update, onSuccess, onFailure, resp, nTimeouts); });
246FibUpdater::onUpdateSuccess(
const FibUpdate& update,
247 const FibUpdateSuccessCallback& onSuccess,
248 const FibUpdateFailureCallback& onFailure)
250 if (update.faceId == m_batchFaceId) {
251 m_updatesForBatchFaceId.remove(update);
253 if (m_updatesForBatchFaceId.size() == 0) {
254 sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
258 m_updatesForNonBatchFaceId.remove(update);
260 if (m_updatesForNonBatchFaceId.size() == 0) {
261 onSuccess(m_inheritedRoutes);
267FibUpdater::onUpdateError(
const FibUpdate& update,
268 const FibUpdateSuccessCallback& onSuccess,
269 const FibUpdateFailureCallback& onFailure,
270 const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
272 uint32_t code = response.getCode();
274 " [code: " << code <<
", error: " << response.getText() <<
"]");
276 if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts <
MAX_NUM_TIMEOUTS) {
277 sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
280 if (update.faceId == m_batchFaceId) {
281 onFailure(code, response.getText());
284 m_updatesForNonBatchFaceId.remove(update);
286 if (m_updatesForNonBatchFaceId.size() == 0) {
287 onSuccess(m_inheritedRoutes);
292 NDN_THROW(Error(
"Non-recoverable error " + std::to_string(code) +
": " + response.getText()));
297FibUpdater::addFibUpdate(
const FibUpdate& update)
299 FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
300 m_updatesForNonBatchFaceId;
303 auto it = std::find_if(updates.begin(), updates.end(),
304 [&update] (
const FibUpdate& other) {
305 return update.name == other.name && update.faceId == other.faceId;
308 if (it != updates.end()) {
309 FibUpdate& existingUpdate = *it;
310 existingUpdate.action = update.action;
311 existingUpdate.cost = update.cost;
314 updates.push_back(update);
319FibUpdater::addInheritedRoutes(
const RibEntry& entry,
const Rib::RouteSet& routesToAdd)
321 for (
const Route& route : routesToAdd) {
323 if (!entry.hasFaceId(route.faceId)) {
325 addInheritedRoute(entry.getName(), route);
333FibUpdater::addInheritedRoutes(
const Name& name,
const Rib::RouteSet& routesToAdd,
336 for (
const Route& route : routesToAdd) {
337 if (route.faceId != ignore.faceId) {
339 addInheritedRoute(name, route);
347FibUpdater::removeInheritedRoutes(
const RibEntry& entry,
const Rib::Rib::RouteSet& routesToRemove)
349 for (
const Route& route : routesToRemove) {
351 if (entry.hasInheritedRoute(route)) {
352 removeInheritedRoute(entry.getName(), route);
359FibUpdater::createFibUpdatesForNewRibEntry(
const Name& name,
const Route& route,
366 if (!route.isChildInherit() && !route.isRibCapture()) {
368 addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
370 else if (route.isChildInherit() && route.isRibCapture()) {
372 Rib::RouteSet routesToAdd;
373 routesToAdd.insert(route);
376 modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
378 else if (route.isChildInherit()) {
379 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
382 addInheritedRoutes(name, ancestorRoutes, route);
386 auto it = ancestorRoutes.find(route);
389 if (it != ancestorRoutes.end()) {
390 ancestorRoutes.erase(it);
394 ancestorRoutes.insert(route);
397 modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
399 else if (route.isRibCapture()) {
401 modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
406FibUpdater::createFibUpdatesForNewRoute(
const RibEntry& entry,
const Route& route,
407 bool captureWasTurnedOn)
410 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
412 Rib::RouteSet routesToAdd;
413 if (route.isChildInherit()) {
417 if (prevRoute ==
nullptr || route.cost <= prevRoute->cost) {
419 routesToAdd.insert(route);
423 Rib::RouteSet routesToRemove;
424 if (captureWasTurnedOn) {
426 routesToRemove = m_rib.getAncestorRoutes(entry);
429 removeInheritedRoutes(entry, routesToRemove);
432 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
437 const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
439 if (other ==
nullptr || route.cost <= other->cost) {
445FibUpdater::createFibUpdatesForUpdatedRoute(
const RibEntry& entry,
const Route& route,
446 const Route& existingRoute)
448 const bool costDidChange = (route.cost != existingRoute.cost);
451 const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
454 if (route.flags == existingRoute.flags && !costDidChange) {
461 if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
465 else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
473 if (prevRoute ==
nullptr || route.cost <= prevRoute->cost) {
476 if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
478 Rib::RouteSet routesToAdd;
479 routesToAdd.insert(route);
480 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
488 if (!existingRoute.isChildInherit() && route.isChildInherit()) {
491 if (prevRoute ==
nullptr || route.cost <= prevRoute->cost) {
493 Rib::RouteSet routesToAdd;
494 routesToAdd.insert(route);
495 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
498 else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
500 Rib::RouteSet routesToRemove;
501 routesToRemove.insert(route);
503 Rib::RouteSet routesToAdd;
505 if (prevRoute !=
nullptr) {
506 routesToAdd.insert(*prevRoute);
510 const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
511 auto it = ancestorRoutes.find(route);
514 if (it != ancestorRoutes.end()) {
515 routesToAdd.insert(*it);
519 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
523 if (!existingRoute.isRibCapture() && route.isRibCapture()) {
524 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
527 removeInheritedRoutes(entry, ancestorRoutes);
530 modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
532 else if (existingRoute.isRibCapture() && !route.isRibCapture()) {
533 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
536 addInheritedRoutes(entry, ancestorRoutes);
539 modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
544FibUpdater::createFibUpdatesForErasedRoute(
const RibEntry& entry,
const Route& route,
545 bool captureWasTurnedOff)
549 if (route.isChildInherit() && route.isRibCapture()) {
551 Rib::RouteSet routesToRemove;
552 routesToRemove.insert(route);
556 Rib::RouteSet routesToAdd;
557 if (captureWasTurnedOff && !entry.empty()) {
559 routesToAdd = m_rib.getAncestorRoutes(entry);
562 addInheritedRoutes(entry, routesToAdd);
565 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
567 else if (route.isChildInherit()) {
569 Rib::RouteSet routesToAdd;
570 if (!entry.hasCapture()) {
571 routesToAdd = m_rib.getAncestorRoutes(entry);
574 Rib::RouteSet routesToRemove;
575 routesToRemove.insert(route);
578 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
580 else if (route.isRibCapture()) {
583 Rib::RouteSet routesToAdd;
584 if (captureWasTurnedOff && !entry.empty()) {
586 routesToAdd = m_rib.getAncestorRoutes(entry);
589 addInheritedRoutes(entry, routesToAdd);
592 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
596 Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
599 if (!entry.hasCapture() && !entry.empty()) {
602 auto it = ancestorRoutes.find(route);
603 if (it != ancestorRoutes.end()) {
604 addInheritedRoute(entry.getName(), *it);
611FibUpdater::createFibUpdatesForErasedRibEntry(
const RibEntry& entry)
613 for (
const Route& route : entry.getInheritedRoutes()) {
620 const Rib::RouteSet& routesToAdd,
621 const Rib::RouteSet& routesToRemove)
623 for (
const auto& child : children) {
624 traverseSubTree(*child, routesToAdd, routesToRemove);
629FibUpdater::traverseSubTree(
const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
630 Rib::Rib::RouteSet routesToRemove)
633 if (entry.hasCapture()) {
638 for (
auto removeIt = routesToRemove.begin(); removeIt != routesToRemove.end(); ) {
641 if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
642 removeIt = routesToRemove.erase(removeIt);
647 if (entry.hasInheritedRoute(*removeIt)) {
648 removeInheritedRoute(entry.getName(), *removeIt);
656 for (
auto addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
658 if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
659 addIt = routesToAdd.erase(addIt);
664 if (!entry.hasFaceId(addIt->faceId)) {
665 addInheritedRoute(entry.getName(), *addIt);
672 modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
676FibUpdater::addInheritedRoute(
const Name& name,
const Route& route)
682FibUpdater::removeInheritedRoute(
const Name& name,
const Route& route)
static FibUpdate createRemoveUpdate(const Name &name, uint64_t faceId)
static FibUpdate createAddUpdate(const Name &name, uint64_t faceId, uint64_t cost)
std::function< void(RibUpdateList inheritedRoutes)> FibUpdateSuccessCallback
std::list< FibUpdate > FibUpdateList
FibUpdater(Rib &rib, ndn::nfd::Controller &controller)
std::function< void(uint32_t code, const std::string &error)> FibUpdateFailureCallback
void computeAndSendFibUpdates(const RibUpdateBatch &batch, const FibUpdateSuccessCallback &onSuccess, const FibUpdateFailureCallback &onFailure)
Computes FibUpdates using the provided RibUpdateBatch and then sends the updates to NFD's FIB.
Represents the Routing Information Base.
void setFibUpdater(FibUpdater *updater)
const_iterator end() const
std::list< shared_ptr< RibEntry > > RibEntryList
const_iterator find(const Name &prefix) const
shared_ptr< RibEntry > findParent(const Name &prefix) const
Represents a collection of RibUpdates to be applied to a single FaceId.
uint64_t getFaceId() const noexcept
#define NFD_LOG_INIT(name)
constexpr uint32_t ERROR_FACE_NOT_FOUND
constexpr int MAX_NUM_TIMEOUTS
Represents a route that will be added to or removed from a namespace.
@ REMOVE_FACE
An update triggered by a face destruction notification.