25c6ce41d5
refs #3760 Change-Id: I9a2e3012af2f72495ce3259fa4f51ebaa8ea7096
723 lines
24 KiB
C++
723 lines
24 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/**
|
|
* Copyright (c) 2014-2016, Regents of the University of California,
|
|
* Arizona Board of Regents,
|
|
* Colorado State University,
|
|
* University Pierre & Marie Curie, Sorbonne University,
|
|
* Washington University in St. Louis,
|
|
* Beijing Institute of Technology,
|
|
* The University of Memphis.
|
|
*
|
|
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
|
* See AUTHORS.md for complete list of NFD authors and contributors.
|
|
*
|
|
* NFD is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU General Public License as published by the Free Software Foundation,
|
|
* either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "fib-updater.hpp"
|
|
|
|
#include "core/logger.hpp"
|
|
|
|
#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
|
|
|
|
namespace nfd {
|
|
namespace rib {
|
|
|
|
using ndn::nfd::ControlParameters;
|
|
|
|
NFD_LOG_INIT("FibUpdater");
|
|
|
|
const unsigned int FibUpdater::MAX_NUM_TIMEOUTS = 10;
|
|
const uint32_t FibUpdater::ERROR_FACE_NOT_FOUND = 410;
|
|
|
|
FibUpdater::FibUpdater(Rib& rib, ndn::nfd::Controller& controller)
|
|
: m_rib(rib)
|
|
, m_controller(controller)
|
|
{
|
|
rib.setFibUpdater(this);
|
|
}
|
|
|
|
void
|
|
FibUpdater::computeAndSendFibUpdates(const RibUpdateBatch& batch,
|
|
const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure)
|
|
{
|
|
m_batchFaceId = batch.getFaceId();
|
|
|
|
// Erase previously calculated inherited routes
|
|
m_inheritedRoutes.clear();
|
|
|
|
// Erase previously calculated FIB updates
|
|
m_updatesForBatchFaceId.clear();
|
|
m_updatesForNonBatchFaceId.clear();
|
|
|
|
computeUpdates(batch);
|
|
|
|
sendUpdatesForBatchFaceId(onSuccess, onFailure);
|
|
}
|
|
|
|
void
|
|
FibUpdater::computeUpdates(const RibUpdateBatch& batch)
|
|
{
|
|
NFD_LOG_DEBUG("Computing updates for batch with faceID: " << batch.getFaceId());
|
|
|
|
// Compute updates and add to m_fibUpdates
|
|
for (const RibUpdate& update : batch)
|
|
{
|
|
switch(update.getAction()) {
|
|
case RibUpdate::REGISTER:
|
|
computeUpdatesForRegistration(update);
|
|
break;
|
|
case RibUpdate::UNREGISTER:
|
|
computeUpdatesForUnregistration(update);
|
|
break;
|
|
case RibUpdate::REMOVE_FACE:
|
|
computeUpdatesForUnregistration(update);
|
|
|
|
// Do not apply updates with the same face ID as the destroyed face
|
|
// since they will be rejected by the FIB
|
|
m_updatesForBatchFaceId.clear();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::computeUpdatesForRegistration(const RibUpdate& update)
|
|
{
|
|
const Name& prefix = update.getName();
|
|
const Route& route = update.getRoute();
|
|
|
|
Rib::const_iterator it = m_rib.find(prefix);
|
|
|
|
// Name prefix exists
|
|
if (it != m_rib.end()) {
|
|
shared_ptr<const RibEntry> entry(it->second);
|
|
|
|
RibEntry::const_iterator existingRoute = entry->findRoute(route);
|
|
|
|
// Route will be new
|
|
if (existingRoute == entry->end()) {
|
|
// Will the new route change the namespace's capture flag?
|
|
bool willCaptureBeTurnedOn = (entry->hasCapture() == false && route.isCapture());
|
|
|
|
createFibUpdatesForNewRoute(*entry, route, willCaptureBeTurnedOn);
|
|
}
|
|
else {
|
|
// Route already exists
|
|
RibEntry entryCopy = *entry;
|
|
|
|
Route& routeToUpdate = *(entryCopy.findRoute(route));
|
|
|
|
routeToUpdate.flags = route.flags;
|
|
routeToUpdate.cost = route.cost;
|
|
routeToUpdate.expires = route.expires;
|
|
|
|
createFibUpdatesForUpdatedRoute(entryCopy, route, *existingRoute);
|
|
}
|
|
}
|
|
else {
|
|
// New name in RIB
|
|
// Find prefix's parent
|
|
shared_ptr<RibEntry> parent = m_rib.findParent(prefix);
|
|
|
|
Rib::RibEntryList descendants = m_rib.findDescendantsForNonInsertedName(prefix);
|
|
Rib::RibEntryList children;
|
|
|
|
for (const auto& descendant : descendants) {
|
|
// If the child has the same parent as the new entry,
|
|
// the new entry must be the child's new parent
|
|
if (descendant->getParent() == parent) {
|
|
children.push_back(descendant);
|
|
}
|
|
}
|
|
|
|
createFibUpdatesForNewRibEntry(prefix, route, children);
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::computeUpdatesForUnregistration(const RibUpdate& update)
|
|
{
|
|
const Name& prefix = update.getName();
|
|
const Route& route = update.getRoute();
|
|
|
|
Rib::const_iterator ribIt = m_rib.find(prefix);
|
|
|
|
// Name prefix exists
|
|
if (ribIt != m_rib.end()) {
|
|
shared_ptr<const RibEntry> entry(ribIt->second);
|
|
|
|
const bool hadCapture = entry->hasCapture();
|
|
|
|
RibEntry::const_iterator existing = entry->findRoute(route);
|
|
|
|
if (existing != entry->end()) {
|
|
RibEntry temp = *entry;
|
|
|
|
// Erase route in temp entry
|
|
temp.eraseRoute(route);
|
|
|
|
const bool captureWasTurnedOff = (hadCapture && !temp.hasCapture());
|
|
|
|
createFibUpdatesForErasedRoute(temp, *existing, captureWasTurnedOff);
|
|
|
|
// The RibEntry still has the face ID; need to update FIB
|
|
// with lowest cost for the same face instead of removing the face from the FIB
|
|
const Route* next = entry->getRouteWithSecondLowestCostByFaceId(route.faceId);
|
|
|
|
if (next != nullptr) {
|
|
createFibUpdatesForNewRoute(temp, *next, false);
|
|
}
|
|
|
|
// The RibEntry will be empty after this removal
|
|
if (entry->getNRoutes() == 1) {
|
|
createFibUpdatesForErasedRibEntry(*entry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::sendUpdates(const FibUpdateList& updates,
|
|
const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure)
|
|
{
|
|
std::string updateString = (updates.size() == 1) ? " update" : " updates";
|
|
NFD_LOG_DEBUG("Applying " << updates.size() << updateString << " to FIB");
|
|
|
|
for (const FibUpdate& update : updates) {
|
|
NFD_LOG_DEBUG("Sending FIB update: " << update);
|
|
|
|
if (update.action == FibUpdate::ADD_NEXTHOP) {
|
|
sendAddNextHopUpdate(update, onSuccess, onFailure);
|
|
}
|
|
else if (update.action == FibUpdate::REMOVE_NEXTHOP) {
|
|
sendRemoveNextHopUpdate(update, onSuccess, onFailure);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::sendUpdatesForBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure)
|
|
{
|
|
if (m_updatesForBatchFaceId.size() > 0) {
|
|
sendUpdates(m_updatesForBatchFaceId, onSuccess, onFailure);
|
|
}
|
|
else {
|
|
sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::sendUpdatesForNonBatchFaceId(const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure)
|
|
{
|
|
if (m_updatesForNonBatchFaceId.size() > 0) {
|
|
sendUpdates(m_updatesForNonBatchFaceId, onSuccess, onFailure);
|
|
}
|
|
else {
|
|
onSuccess(m_inheritedRoutes);
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::sendAddNextHopUpdate(const FibUpdate& update,
|
|
const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure,
|
|
uint32_t nTimeouts)
|
|
{
|
|
m_controller.start<ndn::nfd::FibAddNextHopCommand>(
|
|
ControlParameters()
|
|
.setName(update.name)
|
|
.setFaceId(update.faceId)
|
|
.setCost(update.cost),
|
|
bind(&FibUpdater::onUpdateSuccess, this, update, onSuccess, onFailure),
|
|
bind(&FibUpdater::onUpdateError, this, update, onSuccess, onFailure, _1, nTimeouts));
|
|
}
|
|
|
|
void
|
|
FibUpdater::sendRemoveNextHopUpdate(const FibUpdate& update,
|
|
const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure,
|
|
uint32_t nTimeouts)
|
|
{
|
|
m_controller.start<ndn::nfd::FibRemoveNextHopCommand>(
|
|
ControlParameters()
|
|
.setName(update.name)
|
|
.setFaceId(update.faceId),
|
|
bind(&FibUpdater::onUpdateSuccess, this, update, onSuccess, onFailure),
|
|
bind(&FibUpdater::onUpdateError, this, update, onSuccess, onFailure, _1, nTimeouts));
|
|
}
|
|
|
|
void
|
|
FibUpdater::onUpdateSuccess(const FibUpdate update,
|
|
const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure)
|
|
{
|
|
if (update.faceId == m_batchFaceId) {
|
|
m_updatesForBatchFaceId.remove(update);
|
|
|
|
if (m_updatesForBatchFaceId.size() == 0) {
|
|
sendUpdatesForNonBatchFaceId(onSuccess, onFailure);
|
|
}
|
|
}
|
|
else {
|
|
m_updatesForNonBatchFaceId.remove(update);
|
|
|
|
if (m_updatesForNonBatchFaceId.size() == 0) {
|
|
onSuccess(m_inheritedRoutes);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::onUpdateError(const FibUpdate update,
|
|
const FibUpdateSuccessCallback& onSuccess,
|
|
const FibUpdateFailureCallback& onFailure,
|
|
const ndn::nfd::ControlResponse& response, uint32_t nTimeouts)
|
|
{
|
|
uint32_t code = response.getCode();
|
|
NFD_LOG_DEBUG("Failed to apply " << update <<
|
|
" (code: " << code << ", error: " << response.getText() << ")");
|
|
|
|
if (code == ndn::nfd::Controller::ERROR_TIMEOUT && nTimeouts < MAX_NUM_TIMEOUTS) {
|
|
sendAddNextHopUpdate(update, onSuccess, onFailure, ++nTimeouts);
|
|
}
|
|
else if (code == ERROR_FACE_NOT_FOUND) {
|
|
if (update.faceId == m_batchFaceId) {
|
|
onFailure(code, response.getText());
|
|
}
|
|
else {
|
|
m_updatesForNonBatchFaceId.remove(update);
|
|
|
|
if (m_updatesForNonBatchFaceId.size() == 0) {
|
|
onSuccess(m_inheritedRoutes);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
BOOST_THROW_EXCEPTION(Error("Non-recoverable error: " + response.getText() +
|
|
" code: " + to_string(code)));
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::addFibUpdate(FibUpdate update)
|
|
{
|
|
FibUpdateList& updates = (update.faceId == m_batchFaceId) ? m_updatesForBatchFaceId :
|
|
m_updatesForNonBatchFaceId;
|
|
|
|
// If an update with the same name and route already exists,
|
|
// replace it
|
|
FibUpdateList::iterator it = std::find_if(updates.begin(), updates.end(),
|
|
[&update] (const FibUpdate& other) {
|
|
return update.name == other.name && update.faceId == other.faceId;
|
|
});
|
|
|
|
if (it != updates.end()) {
|
|
FibUpdate& existingUpdate = *it;
|
|
existingUpdate.action = update.action;
|
|
existingUpdate.cost = update.cost;
|
|
}
|
|
else {
|
|
updates.push_back(update);
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::addInheritedRoutes(const RibEntry& entry, const Rib::RouteSet& routesToAdd)
|
|
{
|
|
for (const Route& route : routesToAdd) {
|
|
// Don't add an ancestor faceId if the namespace has an entry for that faceId
|
|
if (!entry.hasFaceId(route.faceId)) {
|
|
// Create a record of the inherited route so it can be added to the RIB later
|
|
addInheritedRoute(entry.getName(), route);
|
|
|
|
addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::addInheritedRoutes(const Name& name, const Rib::RouteSet& routesToAdd,
|
|
const Route& ignore)
|
|
{
|
|
for (const Route& route : routesToAdd) {
|
|
if (route.faceId != ignore.faceId) {
|
|
// Create a record of the inherited route so it can be added to the RIB later
|
|
addInheritedRoute(name, route);
|
|
|
|
addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::removeInheritedRoutes(const RibEntry& entry, const Rib::Rib::RouteSet& routesToRemove)
|
|
{
|
|
for (const Route& route : routesToRemove) {
|
|
// Only remove if the route has been inherited
|
|
if (entry.hasInheritedRoute(route)) {
|
|
removeInheritedRoute(entry.getName(), route);
|
|
addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::createFibUpdatesForNewRibEntry(const Name& name, const Route& route,
|
|
const Rib::RibEntryList& children)
|
|
{
|
|
// Create FIB update for new entry
|
|
addFibUpdate(FibUpdate::createAddUpdate(name, route.faceId, route.cost));
|
|
|
|
// No flags are set
|
|
if (!route.isChildInherit() && !route.isCapture()) {
|
|
// Add ancestor routes to self
|
|
addInheritedRoutes(name, m_rib.getAncestorRoutes(name), route);
|
|
}
|
|
else if (route.isChildInherit() && route.isCapture()) {
|
|
// Add route to children
|
|
Rib::RouteSet routesToAdd;
|
|
routesToAdd.insert(route);
|
|
|
|
// Remove routes blocked by capture and add self to children
|
|
modifyChildrensInheritedRoutes(children, routesToAdd, m_rib.getAncestorRoutes(name));
|
|
}
|
|
else if (route.isChildInherit()) {
|
|
Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(name);
|
|
|
|
// Add ancestor routes to self
|
|
addInheritedRoutes(name, ancestorRoutes, route);
|
|
|
|
// If there is an ancestor route which is the same as the new route, replace it
|
|
// with the new route
|
|
Rib::RouteSet::iterator it = ancestorRoutes.find(route);
|
|
|
|
// There is a route that needs to be overwritten, erase and then replace
|
|
if (it != ancestorRoutes.end()) {
|
|
ancestorRoutes.erase(it);
|
|
}
|
|
|
|
// Add new route to ancestor list so it can be added to children
|
|
ancestorRoutes.insert(route);
|
|
|
|
// Add ancestor routes to children
|
|
modifyChildrensInheritedRoutes(children, ancestorRoutes, Rib::RouteSet());
|
|
}
|
|
else if (route.isCapture()) {
|
|
// Remove routes blocked by capture
|
|
modifyChildrensInheritedRoutes(children, Rib::RouteSet(), m_rib.getAncestorRoutes(name));
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::createFibUpdatesForNewRoute(const RibEntry& entry, const Route& route,
|
|
bool captureWasTurnedOn)
|
|
{
|
|
// Only update if the new route has a lower cost than a previously installed route
|
|
const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
|
|
|
|
Rib::RouteSet routesToAdd;
|
|
if (route.isChildInherit()) {
|
|
// Add to children if this new route doesn't override a previous lower cost, or
|
|
// add to children if this new route is lower cost than a previous route.
|
|
// Less than equal, since entry may find this route
|
|
if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
|
|
// Add self to children
|
|
routesToAdd.insert(route);
|
|
}
|
|
}
|
|
|
|
Rib::RouteSet routesToRemove;
|
|
if (captureWasTurnedOn) {
|
|
// Capture flag on
|
|
routesToRemove = m_rib.getAncestorRoutes(entry);
|
|
|
|
// Remove ancestor routes from self
|
|
removeInheritedRoutes(entry, routesToRemove);
|
|
}
|
|
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
|
|
|
|
// If another route with same faceId and lower cost exists, don't update.
|
|
// Must be done last so that add updates replace removal updates
|
|
// Create FIB update for new entry
|
|
const Route* other = entry.getRouteWithLowestCostByFaceId(route.faceId);
|
|
|
|
if (other == nullptr || route.cost <= other->cost) {
|
|
addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::createFibUpdatesForUpdatedRoute(const RibEntry& entry, const Route& route,
|
|
const Route& existingRoute)
|
|
{
|
|
const bool costDidChange = (route.cost != existingRoute.cost);
|
|
|
|
// Look for an installed route with the lowest cost and child inherit set
|
|
const Route* prevRoute = entry.getRouteWithLowestCostAndChildInheritByFaceId(route.faceId);
|
|
|
|
// No flags changed and cost didn't change, no change in FIB
|
|
if (route.flags == existingRoute.flags && !costDidChange) {
|
|
return;
|
|
}
|
|
|
|
// Cost changed so create update for the entry itself
|
|
if (costDidChange) {
|
|
// Create update if this route's cost is lower than other routes
|
|
if (route.cost <= entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
|
|
// Create FIB update for the updated entry
|
|
addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), route.faceId, route.cost));
|
|
}
|
|
else if (existingRoute.cost < entry.getRouteWithLowestCostByFaceId(route.faceId)->cost) {
|
|
// Create update if this route used to be the lowest route but is no longer
|
|
// the lowest cost route.
|
|
addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), prevRoute->faceId, prevRoute->cost));
|
|
}
|
|
|
|
// If another route with same faceId and lower cost and ChildInherit exists,
|
|
// don't update children.
|
|
if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
|
|
// If no flags changed but child inheritance is set, need to update children
|
|
// with new cost
|
|
if ((route.flags == existingRoute.flags) && route.isChildInherit()) {
|
|
// Add self to children
|
|
Rib::RouteSet routesToAdd;
|
|
routesToAdd.insert(route);
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Child inherit was turned on
|
|
if (!existingRoute.isChildInherit() && route.isChildInherit()) {
|
|
// If another route with same faceId and lower cost and ChildInherit exists,
|
|
// don't update children.
|
|
if (prevRoute == nullptr || route.cost <= prevRoute->cost) {
|
|
// Add self to children
|
|
Rib::RouteSet routesToAdd;
|
|
routesToAdd.insert(route);
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
|
|
}
|
|
} // Child inherit was turned off
|
|
else if (existingRoute.isChildInherit() && !route.isChildInherit()) {
|
|
// Remove self from children
|
|
Rib::RouteSet routesToRemove;
|
|
routesToRemove.insert(route);
|
|
|
|
Rib::RouteSet routesToAdd;
|
|
// If another route with same faceId and ChildInherit exists, update children with this route.
|
|
if (prevRoute != nullptr) {
|
|
routesToAdd.insert(*prevRoute);
|
|
}
|
|
else {
|
|
// Look for an ancestor that was blocked previously
|
|
const Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
|
|
Rib::RouteSet::iterator it = ancestorRoutes.find(route);
|
|
|
|
// If an ancestor is found, add it to children
|
|
if (it != ancestorRoutes.end()) {
|
|
routesToAdd.insert(*it);
|
|
}
|
|
}
|
|
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
|
|
}
|
|
|
|
// Capture was turned on
|
|
if (!existingRoute.isCapture() && route.isCapture()) {
|
|
Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
|
|
|
|
// Remove ancestor routes from self
|
|
removeInheritedRoutes(entry, ancestorRoutes);
|
|
|
|
// Remove ancestor routes from children
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), Rib::RouteSet(), ancestorRoutes);
|
|
} // Capture was turned off
|
|
else if (existingRoute.isCapture() && !route.isCapture()) {
|
|
Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
|
|
|
|
// Add ancestor routes to self
|
|
addInheritedRoutes(entry, ancestorRoutes);
|
|
|
|
// Add ancestor routes to children
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), ancestorRoutes, Rib::RouteSet());
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::createFibUpdatesForErasedRoute(const RibEntry& entry, const Route& route,
|
|
const bool captureWasTurnedOff)
|
|
{
|
|
addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
|
|
|
|
if (route.isChildInherit() && route.isCapture()) {
|
|
// Remove self from children
|
|
Rib::RouteSet routesToRemove;
|
|
routesToRemove.insert(route);
|
|
|
|
// If capture is turned off for the route and another route is installed in the RibEntry,
|
|
// add ancestors to self
|
|
Rib::RouteSet routesToAdd;
|
|
if (captureWasTurnedOff && entry.getNRoutes() != 0) {
|
|
// Look for an ancestors that were blocked previously
|
|
routesToAdd = m_rib.getAncestorRoutes(entry);
|
|
|
|
// Add ancestor routes to self
|
|
addInheritedRoutes(entry, routesToAdd);
|
|
}
|
|
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
|
|
}
|
|
else if (route.isChildInherit()) {
|
|
// If not blocked by capture, add inherited routes to children
|
|
Rib::RouteSet routesToAdd;
|
|
if (!entry.hasCapture()) {
|
|
routesToAdd = m_rib.getAncestorRoutes(entry);
|
|
}
|
|
|
|
Rib::RouteSet routesToRemove;
|
|
routesToRemove.insert(route);
|
|
|
|
// Add ancestor routes to children
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
|
|
}
|
|
else if (route.isCapture()) {
|
|
// If capture is turned off for the route and another route is installed in the RibEntry,
|
|
// add ancestors to self
|
|
Rib::RouteSet routesToAdd;
|
|
if (captureWasTurnedOff && entry.getNRoutes() != 0) {
|
|
// Look for an ancestors that were blocked previously
|
|
routesToAdd = m_rib.getAncestorRoutes(entry);
|
|
|
|
// Add ancestor routes to self
|
|
addInheritedRoutes(entry, routesToAdd);
|
|
}
|
|
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, Rib::RouteSet());
|
|
}
|
|
|
|
// Need to check if the removed route was blocking an inherited route
|
|
Rib::RouteSet ancestorRoutes = m_rib.getAncestorRoutes(entry);
|
|
|
|
// If the current entry has capture set or is pending removal, don't add inherited route
|
|
if (!entry.hasCapture() && entry.getNRoutes() != 0) {
|
|
// If there is an ancestor route which is the same as the erased route, add that route
|
|
// to the current entry
|
|
Rib::RouteSet::iterator it = ancestorRoutes.find(route);
|
|
|
|
if (it != ancestorRoutes.end()) {
|
|
addInheritedRoute(entry.getName(), *it);
|
|
addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), it->faceId, it->cost));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::createFibUpdatesForErasedRibEntry(const RibEntry& entry)
|
|
{
|
|
for (const Route& route : entry.getInheritedRoutes()) {
|
|
addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), route.faceId));
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::modifyChildrensInheritedRoutes(const Rib::RibEntryList& children,
|
|
const Rib::RouteSet& routesToAdd,
|
|
const Rib::RouteSet& routesToRemove)
|
|
{
|
|
for (const auto& child : children) {
|
|
traverseSubTree(*child, routesToAdd, routesToRemove);
|
|
}
|
|
}
|
|
|
|
void
|
|
FibUpdater::traverseSubTree(const RibEntry& entry, Rib::Rib::RouteSet routesToAdd,
|
|
Rib::Rib::RouteSet routesToRemove)
|
|
{
|
|
// If a route on the namespace has the capture flag set, ignore self and children
|
|
if (entry.hasCapture()) {
|
|
return;
|
|
}
|
|
|
|
// Remove inherited routes from current namespace
|
|
for (Rib::RouteSet::const_iterator removeIt = routesToRemove.begin();
|
|
removeIt != routesToRemove.end(); )
|
|
{
|
|
// If a route on the namespace has the same face ID and child inheritance set,
|
|
// ignore this route
|
|
if (entry.hasChildInheritOnFaceId(removeIt->faceId)) {
|
|
routesToRemove.erase(removeIt++);
|
|
continue;
|
|
}
|
|
|
|
// Only remove route if it removes an existing inherited route
|
|
if (entry.hasInheritedRoute(*removeIt)) {
|
|
removeInheritedRoute(entry.getName(), *removeIt);
|
|
addFibUpdate(FibUpdate::createRemoveUpdate(entry.getName(), removeIt->faceId));
|
|
}
|
|
|
|
++removeIt;
|
|
}
|
|
|
|
// Add inherited routes to current namespace
|
|
for (Rib::RouteSet::const_iterator addIt = routesToAdd.begin(); addIt != routesToAdd.end(); ) {
|
|
|
|
// If a route on the namespace has the same face ID and child inherit set, ignore this face
|
|
if (entry.hasChildInheritOnFaceId(addIt->faceId)) {
|
|
routesToAdd.erase(addIt++);
|
|
continue;
|
|
}
|
|
|
|
// Only add route if it does not override an existing route
|
|
if (!entry.hasFaceId(addIt->faceId)) {
|
|
addInheritedRoute(entry.getName(), *addIt);
|
|
addFibUpdate(FibUpdate::createAddUpdate(entry.getName(), addIt->faceId, addIt->cost));
|
|
}
|
|
|
|
++addIt;
|
|
}
|
|
|
|
modifyChildrensInheritedRoutes(entry.getChildren(), routesToAdd, routesToRemove);
|
|
}
|
|
|
|
void
|
|
FibUpdater::addInheritedRoute(const Name& name, const Route& route)
|
|
{
|
|
RibUpdate update;
|
|
update.setAction(RibUpdate::REGISTER)
|
|
.setName(name)
|
|
.setRoute(route);
|
|
|
|
m_inheritedRoutes.push_back(update);
|
|
}
|
|
|
|
void
|
|
FibUpdater::removeInheritedRoute(const Name& name, const Route& route)
|
|
{
|
|
RibUpdate update;
|
|
update.setAction(RibUpdate::UNREGISTER)
|
|
.setName(name)
|
|
.setRoute(route);
|
|
|
|
m_inheritedRoutes.push_back(update);
|
|
}
|
|
|
|
} // namespace rib
|
|
} // namespace nfd
|