rib: Generate FIB updates using route flags
refs: #1325
Change-Id: I5c567da1c06819caeba5cc5b024914666ba70ab6
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
index b89b619..8b7010a 100644
--- a/rib/rib-manager.cpp
+++ b/rib/rib-manager.cpp
@@ -64,6 +64,7 @@
, m_localhopValidator(m_face)
, m_faceMonitor(m_face)
, m_isLocalhopEnabled(false)
+ , m_lastTransactionId(0)
, m_verbDispatch(COMMAND_VERBS,
COMMAND_VERBS + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
{
@@ -225,18 +226,9 @@
NFD_LOG_TRACE("register prefix: " << faceEntry);
- /// \todo For right now, just pass the options to fib as is
- /// without processing flags. Later, options will first be added to
- /// Rib tree, nrd will generate fib updates based on flags, and
- /// will then add next hops one by one.
m_managedRib.insert(parameters.getName(), faceEntry);
- m_nfdController.start<ndn::nfd::FibAddNextHopCommand>(
- ControlParameters()
- .setName(parameters.getName())
- .setFaceId(faceEntry.faceId)
- .setCost(faceEntry.cost),
- bind(&RibManager::onRegSuccess, this, request, parameters, faceEntry),
- bind(&RibManager::onCommandError, this, _1, _2, request, faceEntry));
+
+ sendUpdatesToFib(request, parameters);
}
void
@@ -258,12 +250,9 @@
NFD_LOG_TRACE("unregister prefix: " << faceEntry);
- m_nfdController.start<ndn::nfd::FibRemoveNextHopCommand>(
- ControlParameters()
- .setName(parameters.getName())
- .setFaceId(faceEntry.faceId),
- bind(&RibManager::onUnRegSuccess, this, request, parameters, faceEntry),
- bind(&RibManager::onCommandError, this, _1, _2, request, faceEntry));
+ m_managedRib.erase(parameters.getName(), faceEntry);
+
+ sendUpdatesToFib(request, parameters);
}
void
@@ -334,7 +323,6 @@
}
sendResponse(request->getName(), response);
- m_managedRib.erase(request->getName(), faceEntry);
}
void
@@ -368,7 +356,53 @@
NFD_LOG_TRACE("onUnRegSuccess: unregistered " << faceEntry);
sendResponse(request->getName(), response);
- m_managedRib.erase(request->getName(), faceEntry);
+}
+
+void
+RibManager::sendSuccessResponse(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters)
+{
+ if (!static_cast<bool>(request))
+ {
+ return;
+ }
+
+ ControlResponse response;
+
+ response.setCode(200);
+ response.setText("Success");
+ response.setBody(parameters.wireEncode());
+
+ sendResponse(request->getName(), response);
+}
+
+void
+RibManager::sendErrorResponse(uint32_t code, const std::string& error,
+ const shared_ptr<const Interest>& request)
+{
+ NFD_LOG_ERROR("NFD returned an error: " << error << " (code: " << code << ")");
+
+ if (!static_cast<bool>(request))
+ {
+ return;
+ }
+
+ ControlResponse response;
+
+ if (code == 404)
+ {
+ response.setCode(code);
+ response.setText(error);
+ }
+ else
+ {
+ response.setCode(533);
+ std::ostringstream os;
+ os << "Failure to update NFD " << "(NFD Error: " << code << " " << error << ")";
+ response.setText(os.str());
+ }
+
+ sendResponse(request->getName(), response);
}
void
@@ -383,16 +417,87 @@
throw Error("Error in setting interest filter (" + name.toUri() + "): " + msg);
}
-void
-RibManager::onAddNextHopSuccess(const Name& prefix)
+bool
+RibManager::isTransactionComplete(const TransactionId transactionId)
{
- NFD_LOG_DEBUG("Successfully registered " + prefix.toUri() + " with NFD");
+ FibTransactionTable::iterator it = m_pendingFibTransactions.find(transactionId);
+
+ if (it != m_pendingFibTransactions.end())
+ {
+ int& updatesLeft = it->second;
+
+ updatesLeft--;
+
+ // All of the updates have been applied successfully
+ if (updatesLeft == 0)
+ {
+ m_pendingFibTransactions.erase(it);
+ return true;
+ }
+ }
+
+ return false;
}
void
-RibManager::onAddNextHopError(const Name& name, const std::string& msg)
+RibManager::invalidateTransaction(const TransactionId transactionId)
{
- throw Error("Error in setting interest filter (" + name.toUri() + "): " + msg);
+ FibTransactionTable::iterator it = m_pendingFibTransactions.find(transactionId);
+
+ if (it != m_pendingFibTransactions.end())
+ {
+ m_pendingFibTransactions.erase(it);
+ }
+}
+
+void
+RibManager::onAddNextHopSuccess(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters,
+ const TransactionId transactionId,
+ const bool shouldSendResponse)
+{
+ if (isTransactionComplete(transactionId) && shouldSendResponse)
+ {
+ sendSuccessResponse(request, parameters);
+ }
+}
+
+void
+RibManager::onAddNextHopError(uint32_t code, const std::string& error,
+ const shared_ptr<const Interest>& request,
+ const TransactionId transactionId, const bool shouldSendResponse)
+{
+ invalidateTransaction(transactionId);
+
+ if (shouldSendResponse)
+ {
+ sendErrorResponse(code, error, request);
+ }
+}
+
+void
+RibManager::onRemoveNextHopSuccess(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters,
+ const TransactionId transactionId,
+ const bool shouldSendResponse)
+{
+ if (isTransactionComplete(transactionId) && shouldSendResponse)
+ {
+ sendSuccessResponse(request, parameters);
+ }
+}
+
+void
+RibManager::onRemoveNextHopError(uint32_t code, const std::string& error,
+ const shared_ptr<const Interest>& request,
+ const TransactionId transactionId, const bool shouldSendResponse)
+{
+ invalidateTransaction(transactionId);
+
+ if (shouldSendResponse)
+ {
+ sendErrorResponse(code, error, request);
+ }
}
void
@@ -425,9 +530,98 @@
{
/// \todo A notification can be missed, in this case check Facelist
NFD_LOG_TRACE("onNotification: " << notification);
- if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) { //face destroyed
- m_managedRib.erase(notification.getFaceId());
- }
+ if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) //face destroyed
+ {
+ m_managedRib.erase(notification.getFaceId());
+
+ sendUpdatesToFibAfterFaceDestroyEvent();
+ }
+}
+
+void
+RibManager::sendUpdatesToFib(const shared_ptr<const Interest>& request,
+ const ControlParameters& parameters)
+{
+ const Rib::FibUpdateList& updates = m_managedRib.getFibUpdates();
+
+ // If no updates were generated, consider the operation a success
+ if (updates.empty())
+ {
+ sendSuccessResponse(request, parameters);
+ return;
+ }
+
+ bool shouldWaitToRespond = false;
+
+ // An application request should wait for all FIB updates to be applied
+ // successfully before sending a response
+ if (parameters.getOrigin() == ndn::nfd::ROUTE_ORIGIN_APP)
+ {
+ shouldWaitToRespond = true;
+ }
+ else // Respond immediately
+ {
+ sendSuccessResponse(request, parameters);
+ }
+
+ NFD_LOG_DEBUG("Applying " << updates.size() << " updates to FIB");
+
+ // Assign an ID to this FIB transaction
+ TransactionId currentTransactionId = ++m_lastTransactionId;
+
+ // Add this transaction to the transaction table
+ m_pendingFibTransactions[currentTransactionId] = updates.size();
+
+ for (Rib::FibUpdateList::const_iterator it = updates.begin(); it != updates.end(); ++it)
+ {
+ shared_ptr<const FibUpdate> update(*it);
+
+ if (update->action == FibUpdate::ADD_NEXTHOP)
+ {
+ FaceEntry faceEntry;
+ faceEntry.faceId = update->faceId;
+ faceEntry.cost = update->cost;
+
+ m_nfdController.start<ndn::nfd::FibAddNextHopCommand>(
+ ControlParameters()
+ .setName(update->name)
+ .setFaceId(faceEntry.faceId)
+ .setCost(faceEntry.cost),
+ bind(&RibManager::onAddNextHopSuccess, this, request,
+ parameters,
+ currentTransactionId,
+ shouldWaitToRespond),
+ bind(&RibManager::onAddNextHopError, this, _1, _2, request, currentTransactionId,
+ shouldWaitToRespond));
+ }
+ else if (update->action == FibUpdate::REMOVE_NEXTHOP)
+ {
+ FaceEntry faceEntry;
+ faceEntry.faceId = update->faceId;
+
+ m_nfdController.start<ndn::nfd::FibRemoveNextHopCommand>(
+ ControlParameters()
+ .setName(update->name)
+ .setFaceId(faceEntry.faceId),
+ bind(&RibManager::onRemoveNextHopSuccess, this, request,
+ parameters,
+ currentTransactionId,
+ shouldWaitToRespond),
+ bind(&RibManager::onRemoveNextHopError, this, _1, _2, request, currentTransactionId,
+ shouldWaitToRespond));
+ }
+ }
+
+ m_managedRib.clearFibUpdates();
+}
+
+void
+RibManager::sendUpdatesToFibAfterFaceDestroyEvent()
+{
+ ControlParameters parameters;
+ parameters.setOrigin(ndn::nfd::ROUTE_ORIGIN_STATIC);
+
+ sendUpdatesToFib(shared_ptr<const Interest>(), parameters);
}
} // namespace rib