rib: Integrating NRD code into NFD codebase
Change-Id: I3e548f974255f62a4680cfc6c12be3bb7a3db4d2
Refs: #1486
diff --git a/rib/rib-manager.cpp b/rib/rib-manager.cpp
new file mode 100644
index 0000000..1a3e41f
--- /dev/null
+++ b/rib/rib-manager.cpp
@@ -0,0 +1,341 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 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 "rib-manager.hpp"
+
+namespace nfd {
+namespace rib {
+
+const Name RibManager::COMMAND_PREFIX = "/localhost/nrd";
+const Name RibManager::REMOTE_COMMAND_PREFIX = "/localhop/nrd";
+
+const size_t RibManager::COMMAND_UNSIGNED_NCOMPS =
+ RibManager::COMMAND_PREFIX.size() +
+ 1 + // verb
+ 1; // verb options
+
+const size_t RibManager::COMMAND_SIGNED_NCOMPS =
+ RibManager::COMMAND_UNSIGNED_NCOMPS +
+ 4; // (timestamp, nonce, signed info tlv, signature tlv)
+
+const RibManager::VerbAndProcessor RibManager::COMMAND_VERBS[] =
+ {
+ VerbAndProcessor(
+ Name::Component("register"),
+ &RibManager::insertEntry
+ ),
+
+ VerbAndProcessor(
+ Name::Component("unregister"),
+ &RibManager::deleteEntry
+ ),
+ };
+
+RibManager::RibManager()
+ : m_face(new ndn::Face())
+ , m_nfdController(new ndn::nfd::Controller(*m_face))
+ , m_validator(m_face)
+ , m_faceMonitor(*m_face)
+ , m_verbDispatch(COMMAND_VERBS,
+ COMMAND_VERBS + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
+{
+}
+
+void
+RibManager::registerWithNfd()
+{
+ //check whether the components of localhop and localhost prefixes are same
+ BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size());
+
+ std::cerr << "Setting interest filter on: " << COMMAND_PREFIX.toUri() << std::endl;
+ m_face->setController(m_nfdController);
+ m_face->setInterestFilter(COMMAND_PREFIX.toUri(),
+ bind(&RibManager::onRibRequest, this, _2),
+ bind(&RibManager::setInterestFilterFailed, this, _1, _2));
+
+ std::cerr << "Setting interest filter on: " << REMOTE_COMMAND_PREFIX.toUri() << std::endl;
+ m_face->setInterestFilter(REMOTE_COMMAND_PREFIX.toUri(),
+ bind(&RibManager::onRibRequest, this, _2),
+ bind(&RibManager::setInterestFilterFailed, this, _1, _2));
+
+ std::cerr << "Monitoring faces" << std::endl;
+ m_faceMonitor.addSubscriber(boost::bind(&RibManager::onNotification, this, _1));
+ m_faceMonitor.startNotifications();
+}
+
+void
+RibManager::setConfigFile(ConfigFile& configFile)
+{
+ configFile.addSectionHandler("security",
+ bind(&RibManager::onConfig, this, _1, _2, _3));
+}
+
+void
+RibManager::onConfig(const ConfigSection& configSection,
+ bool isDryRun,
+ const std::string& filename)
+{
+ /// \todo remove check after validator-conf replaces settings on each load
+ if (!isDryRun)
+ m_validator.load(configSection, filename);
+}
+
+void
+RibManager::setInterestFilterFailed(const Name& name, const std::string& msg)
+{
+ std::cerr << "Error in setting interest filter (" << name << "): " << msg << std::endl;
+ m_face->shutdown();
+}
+
+void
+RibManager::sendResponse(const Name& name,
+ const ControlResponse& response)
+{
+ const Block& encodedControl = response.wireEncode();
+
+ Data responseData(name);
+ responseData.setContent(encodedControl);
+
+ m_keyChain.sign(responseData);
+ m_face->put(responseData);
+}
+
+void
+RibManager::sendResponse(const Name& name,
+ uint32_t code,
+ const std::string& text)
+{
+ ControlResponse response(code, text);
+ sendResponse(name, response);
+}
+
+void
+RibManager::onRibRequest(const Interest& request)
+{
+ m_validator.validate(request,
+ bind(&RibManager::onRibRequestValidated, this, _1),
+ bind(&RibManager::onRibRequestValidationFailed, this, _1, _2));
+}
+
+void
+RibManager::onRibRequestValidated(const shared_ptr<const Interest>& request)
+{
+ const Name& command = request->getName();
+
+ //REMOTE_COMMAND_PREFIX number of componenets are same as
+ // NRD_COMMAND_PREFIX's so no extra checks are required.
+ const Name::Component& verb = command.get(COMMAND_PREFIX.size());
+ VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find(verb);
+
+ if (verbProcessor != m_verbDispatch.end())
+ {
+ PrefixRegOptions options;
+ if (!extractOptions(*request, options))
+ {
+ sendResponse(command, 400, "Malformed command");
+ return;
+ }
+
+ /// \todo authorize command
+ if (false)
+ {
+ sendResponse(request->getName(), 403, "Unauthorized command");
+ return;
+ }
+
+ // \todo add proper log support
+ std::cout << "Received options (name, faceid, cost): " << options.getName() <<
+ ", " << options.getFaceId() << ", " << options.getCost() << std::endl;
+
+ ControlResponse response;
+ (verbProcessor->second)(this, *request, options);
+ }
+ else
+ {
+ sendResponse(request->getName(), 501, "Unsupported command");
+ }
+}
+
+void
+RibManager::onRibRequestValidationFailed(const shared_ptr<const Interest>& request,
+ const std::string& failureInfo)
+{
+ sendResponse(request->getName(), 403, failureInfo);
+}
+
+bool
+RibManager::extractOptions(const Interest& request,
+ PrefixRegOptions& extractedOptions)
+{
+ // const Name& command = request.getName();
+ //REMOTE_COMMAND_PREFIX is same in size of NRD_COMMAND_PREFIX
+ //so no extra processing is required.
+ const size_t optionCompIndex = COMMAND_PREFIX.size() + 1;
+
+ try
+ {
+ Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
+ extractedOptions.wireDecode(rawOptions);
+ }
+ catch (const ndn::Tlv::Error& e)
+ {
+ return false;
+ }
+
+ if (extractedOptions.getFaceId() == 0)
+ {
+ std::cout <<"IncomingFaceId: " << request.getIncomingFaceId() << std::endl;
+ extractedOptions.setFaceId(request.getIncomingFaceId());
+ }
+ return true;
+}
+
+void
+RibManager::onCommandError(uint32_t code, const std::string& error,
+ const Interest& request,
+ const PrefixRegOptions& options)
+{
+ std::cout << "NFD Error: " << error << " (code: " << code << ")" << std::endl;
+
+ 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);
+ m_managedRib.erase(options);
+}
+
+void
+RibManager::onUnRegSuccess(const Interest& request, const PrefixRegOptions& options)
+{
+ ControlResponse response;
+
+ response.setCode(200);
+ response.setText("Success");
+ response.setBody(options.wireEncode());
+
+ std::cout << "Success: Name unregistered (" <<
+ options.getName() << ", " <<
+ options.getFaceId() << ")" << std::endl;
+ sendResponse(request.getName(), response);
+ m_managedRib.erase(options);
+}
+
+void
+RibManager::onRegSuccess(const Interest& request, const PrefixRegOptions& options)
+{
+ ControlResponse response;
+
+ response.setCode(200);
+ response.setText("Success");
+ response.setBody(options.wireEncode());
+
+ std::cout << "Success: Name registered (" << options.getName() << ", " <<
+ options.getFaceId() << ")" << std::endl;
+ sendResponse(request.getName(), response);
+}
+
+void
+RibManager::insertEntry(const Interest& request, const PrefixRegOptions& options)
+{
+ // For right now, just pass the options to fib as it is,
+ // without processing flags. Later options will be first added to
+ // Rib tree, then nrd will generate fib updates based on flags and then
+ // will add next hops one by one..
+ m_managedRib.insert(options);
+ m_nfdController->start<ndn::nfd::FibAddNextHopCommand>(
+ ControlParameters()
+ .setName(options.getName())
+ .setFaceId(options.getFaceId())
+ .setCost(options.getCost()),
+ bind(&RibManager::onRegSuccess, this, request, options),
+ bind(&RibManager::onCommandError, this, _1, _2, request, options));
+}
+
+void
+RibManager::deleteEntry(const Interest& request, const PrefixRegOptions& options)
+{
+ m_nfdController->start<ndn::nfd::FibRemoveNextHopCommand>(
+ ControlParameters()
+ .setName(options.getName())
+ .setFaceId(options.getFaceId()),
+ bind(&RibManager::onUnRegSuccess, this, request, options),
+ bind(&RibManager::onCommandError, this, _1, _2, request, options));
+}
+
+boost::asio::io_service&
+RibManager::getIoService()
+{
+ /// \todo Switch face to use global io service (needs library update)
+ return *m_face->ioService();
+}
+
+void
+RibManager::onControlHeaderSuccess()
+{
+ std::cout << "Local control header enabled" << std::endl;
+}
+
+void
+RibManager::onControlHeaderError(uint32_t code, const std::string& reason)
+{
+ std::cout << "Error: couldn't enable local control header "
+ << "(code: " << code << ", info: " << reason << ")" << std::endl;
+ m_face->shutdown();
+}
+
+void
+RibManager::enableLocalControlHeader()
+{
+ m_nfdController->start<ndn::nfd::FaceEnableLocalControlCommand>(
+ ControlParameters()
+ .setLocalControlFeature(ndn::nfd::LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
+ bind(&RibManager::onControlHeaderSuccess, this),
+ bind(&RibManager::onControlHeaderError, this, _1, _2));
+}
+
+void
+RibManager::onNotification(const FaceEventNotification& notification)
+{
+ /// \todo A notification can be missed, in this case check Facelist
+ std::cerr << "Notification Rcvd: " << notification << std::endl;
+ if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) { //face destroyed
+ m_managedRib.erase(notification.getFaceId());
+ }
+}
+
+} // namespace rib
+} // namespace nfd