mgmt: refactor management modules to conform to NFD Management Protocol

Refactor management protocol specific option types to ControlParameters
Add control parameter field enforcement
Add missing control response "success" message bodies
Update fib management protocol response codes and behavior
Merge local control header manager into face manager
Refactor references of nfd::LocalControlHeaderFeature enum to ndn::nfd::LocalControlFeature
Remove "control-header" privilege from default configuration

refs: #1397, #1399, #1400

Change-Id: Id042daf00b3cee1f1c7fa38d2e4a4ff6d95c15c6
diff --git a/daemon/face/local-face.hpp b/daemon/face/local-face.hpp
index 7023efb..d16a64f 100644
--- a/daemon/face/local-face.hpp
+++ b/daemon/face/local-face.hpp
@@ -8,48 +8,50 @@
 #define NFD_FACE_LOCAL_FACE_HPP
 
 #include "face.hpp"
+#include <ndn-cpp-dev/management/nfd-control-parameters.hpp>
 
 namespace nfd {
 
-/* \brief indicates a feature in LocalControlHeader
- */
-enum LocalControlHeaderFeature
-{
-  /// any feature
-  LOCAL_CONTROL_HEADER_FEATURE_ANY,
-  /// in-faceid
-  LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID,
-  /// out-faceid
-  LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID,
-  /// upper bound of enum
-  LOCAL_CONTROL_HEADER_FEATURE_MAX
-};
-
+using ndn::nfd::LocalControlFeature;
+using ndn::nfd::LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID;
+using ndn::nfd::LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID;
 
 /** \brief represents a face
  */
 class LocalFace : public Face
 {
 public:
+
   explicit
   LocalFace(const FaceUri& uri);
 
-  /** \brief get whether a LocalControlHeader feature is enabled
+  /** \brief get whether any LocalControlHeader feature is enabled
    *
-   *  \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_MAX
-   *  LOCAL_CONTROL_HEADER_FEATURE_ANY returns true if any feature is enabled.
+   * \returns true if any feature is enabled.
    */
   bool
-  isLocalControlHeaderEnabled(LocalControlHeaderFeature feature =
-                              LOCAL_CONTROL_HEADER_FEATURE_ANY) const;
+  isLocalControlHeaderEnabled() const;
+
+  /** \brief get whether a specific LocalControlHeader feature is enabled
+   *
+   *  \param feature The feature.
+   *  \returns true if the specified feature is enabled.
+   */
+  bool
+  isLocalControlHeaderEnabled(LocalControlFeature feature) const;
 
   /** \brief enable or disable a LocalControlHeader feature
    *
-   *  \param feature The feature. Cannot be LOCAL_CONTROL_HEADER_FEATURE_ANY
-   *                                     or LOCAL_CONTROL_HEADER_FEATURE_MAX
+   *  \param feature The feature. Cannot be LOCAL_CONTROL_FEATURE_ANY
+   *                                     or LOCAL_CONTROL_FEATURE_MAX
    */
   void
-  setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled = true);
+  setLocalControlHeaderFeature(LocalControlFeature feature, bool enabled = true);
+
+public:
+
+  static const size_t LOCAL_CONTROL_FEATURE_MAX = 3; /// upper bound of LocalControlFeature enum
+  static const size_t LOCAL_CONTROL_FEATURE_ANY = 0; /// any feature
 
 protected:
   // statically overridden from Face
@@ -84,26 +86,31 @@
 inline
 LocalFace::LocalFace(const FaceUri& uri)
   : Face(uri, true)
-  , m_localControlHeaderFeatures(LOCAL_CONTROL_HEADER_FEATURE_MAX)
+  , m_localControlHeaderFeatures(LocalFace::LOCAL_CONTROL_FEATURE_MAX)
 {
 }
 
 inline bool
-LocalFace::isLocalControlHeaderEnabled(LocalControlHeaderFeature feature) const
+LocalFace::isLocalControlHeaderEnabled() const
 {
-  BOOST_ASSERT(feature < m_localControlHeaderFeatures.size());
+  return m_localControlHeaderFeatures[LOCAL_CONTROL_FEATURE_ANY];
+}
+
+inline bool
+LocalFace::isLocalControlHeaderEnabled(LocalControlFeature feature) const
+{
+  BOOST_ASSERT(0 < feature && feature < m_localControlHeaderFeatures.size());
   return m_localControlHeaderFeatures[feature];
 }
 
 inline void
-LocalFace::setLocalControlHeaderFeature(LocalControlHeaderFeature feature, bool enabled/* = true*/)
+LocalFace::setLocalControlHeaderFeature(LocalControlFeature feature, bool enabled/* = true*/)
 {
-  BOOST_ASSERT(feature > LOCAL_CONTROL_HEADER_FEATURE_ANY &&
-               feature < m_localControlHeaderFeatures.size());
+  BOOST_ASSERT(0 < feature && feature < m_localControlHeaderFeatures.size());
+
   m_localControlHeaderFeatures[feature] = enabled;
 
-  BOOST_STATIC_ASSERT(LOCAL_CONTROL_HEADER_FEATURE_ANY == 0);
-  m_localControlHeaderFeatures[LOCAL_CONTROL_HEADER_FEATURE_ANY] =
+  m_localControlHeaderFeatures[LOCAL_CONTROL_FEATURE_ANY] =
     std::find(m_localControlHeaderFeatures.begin() + 1,
               m_localControlHeaderFeatures.end(), true) <
               m_localControlHeaderFeatures.end();
@@ -127,7 +134,7 @@
         {
           i->getLocalControlHeader().wireDecode(element,
             false,
-            this->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID));
+            this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID));
         }
 
       this->onReceiveInterest(*i);
@@ -162,7 +169,7 @@
   if (!this->isLocalControlHeaderEnabled())
     return true;
 
-  return header.empty(this->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID),
+  return header.empty(this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
                       false);
 }
 
@@ -171,7 +178,7 @@
 LocalFace::filterAndEncodeLocalControlHeader(const Packet& packet)
 {
   return packet.getLocalControlHeader().wireEncode(packet,
-           this->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID),
+           this->isLocalControlHeaderEnabled(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
            false);
 }
 
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 8abdba6..44880b2 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -10,7 +10,6 @@
 #include "mgmt/internal-face.hpp"
 #include "mgmt/fib-manager.hpp"
 #include "mgmt/face-manager.hpp"
-#include "mgmt/local-control-header-manager.hpp"
 #include "mgmt/strategy-choice-manager.hpp"
 #include "mgmt/status-server.hpp"
 #include "mgmt/config-file.hpp"
@@ -31,7 +30,6 @@
 static Forwarder* g_forwarder;
 static FibManager* g_fibManager;
 static FaceManager* g_faceManager;
-static LocalControlHeaderManager* g_localControlHeaderManager;
 static StrategyChoiceManager* g_strategyChoiceManager;
 static StatusServer* g_statusServer;
 static shared_ptr<InternalFace> g_internalFace;
@@ -100,10 +98,6 @@
   g_faceManager = new FaceManager(g_forwarder->getFaceTable(), g_internalFace);
   g_faceManager->setConfigFile(config);
 
-  g_localControlHeaderManager =
-    new LocalControlHeaderManager(bind(&Forwarder::getFace, g_forwarder, _1),
-                                  g_internalFace);
-
   g_strategyChoiceManager = new StrategyChoiceManager(g_forwarder->getStrategyChoice(),
                                                       g_internalFace);
 
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 4028ad5..ea92898 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -31,7 +31,7 @@
 const size_t FaceManager::COMMAND_UNSIGNED_NCOMPS =
   FaceManager::COMMAND_PREFIX.size() +
   1 + // verb
-  1;  // verb options
+  1;  // verb parameters
 
 const size_t FaceManager::COMMAND_SIGNED_NCOMPS =
   FaceManager::COMMAND_UNSIGNED_NCOMPS +
@@ -40,14 +40,24 @@
 const FaceManager::SignedVerbAndProcessor FaceManager::SIGNED_COMMAND_VERBS[] =
   {
     SignedVerbAndProcessor(
-                     Name::Component("create"),
-                     &FaceManager::createFace
-                     ),
+                           Name::Component("create"),
+                           &FaceManager::createFace
+                           ),
 
     SignedVerbAndProcessor(
-                     Name::Component("destroy"),
-                     &FaceManager::destroyFace
-                     ),
+                           Name::Component("destroy"),
+                           &FaceManager::destroyFace
+                           ),
+
+    SignedVerbAndProcessor(
+                           Name::Component("enable-local-control"),
+                           &FaceManager::enableLocalControl
+                           ),
+
+    SignedVerbAndProcessor(
+                           Name::Component("disable-local-control"),
+                           &FaceManager::disableLocalControl
+                           ),
   };
 
 const FaceManager::UnsignedVerbAndProcessor FaceManager::UNSIGNED_COMMAND_VERBS[] =
@@ -75,11 +85,11 @@
   , m_statusPublisher(m_faceTable, m_face, LIST_COMMAND_PREFIX)
   , m_notificationStream(m_face, EVENTS_COMMAND_PREFIX)
   , m_signedVerbDispatch(SIGNED_COMMAND_VERBS,
-                   SIGNED_COMMAND_VERBS +
-                   (sizeof(SIGNED_COMMAND_VERBS) / sizeof(SignedVerbAndProcessor)))
+                         SIGNED_COMMAND_VERBS +
+                         (sizeof(SIGNED_COMMAND_VERBS) / sizeof(SignedVerbAndProcessor)))
   , m_unsignedVerbDispatch(UNSIGNED_COMMAND_VERBS,
-                   UNSIGNED_COMMAND_VERBS +
-                   (sizeof(UNSIGNED_COMMAND_VERBS) / sizeof(UnsignedVerbAndProcessor)))
+                           UNSIGNED_COMMAND_VERBS +
+                           (sizeof(UNSIGNED_COMMAND_VERBS) / sizeof(UnsignedVerbAndProcessor)))
 
 {
   face->setInterestFilter("/localhost/nfd/faces",
@@ -528,7 +538,7 @@
       (unsignedVerbProcessor->second)(this, boost::cref(request));
     }
   else if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
-      commandNComps < COMMAND_SIGNED_NCOMPS)
+           commandNComps < COMMAND_SIGNED_NCOMPS)
     {
       NFD_LOG_INFO("command result: unsigned verb: " << command);
       sendResponse(command, 401, "Signature required");
@@ -551,20 +561,21 @@
 FaceManager::onValidatedFaceRequest(const shared_ptr<const Interest>& request)
 {
   const Name& command = request->getName();
-  const Name::Component& verb = command.get(COMMAND_PREFIX.size());
+  const Name::Component& verb = command[COMMAND_PREFIX.size()];
+  const Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
 
   SignedVerbDispatchTable::const_iterator signedVerbProcessor = m_signedVerbDispatch.find(verb);
   if (signedVerbProcessor != m_signedVerbDispatch.end())
     {
-      ndn::nfd::FaceManagementOptions options;
-      if (!extractOptions(*request, options))
+      ControlParameters parameters;
+      if (!extractParameters(parameterComponent, parameters))
         {
           sendResponse(command, 400, "Malformed command");
           return;
         }
 
       NFD_LOG_INFO("command result: processing verb: " << verb);
-      (signedVerbProcessor->second)(this, command, options);
+      (signedVerbProcessor->second)(this, *request, parameters);
     }
   else
     {
@@ -574,28 +585,6 @@
 
 }
 
-bool
-FaceManager::extractOptions(const Interest& request,
-                            ndn::nfd::FaceManagementOptions& extractedOptions)
-{
-  const Name& command = request.getName();
-  const size_t optionCompIndex =
-    COMMAND_PREFIX.size() + 1;
-
-  try
-    {
-      Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
-      extractedOptions.wireDecode(rawOptions);
-    }
-  catch (const ndn::Tlv::Error& e)
-    {
-      NFD_LOG_INFO("Bad command option parse: " << command);
-      return false;
-    }
-  NFD_LOG_DEBUG("Options parsed OK");
-  return true;
-}
-
 void
 FaceManager::addCreatedFaceToForwarder(const shared_ptr<Face>& newFace)
 {
@@ -606,16 +595,13 @@
 
 void
 FaceManager::onCreated(const Name& requestName,
-                       ndn::nfd::FaceManagementOptions& options,
+                       ControlParameters& parameters,
                        const shared_ptr<Face>& newFace)
 {
   addCreatedFaceToForwarder(newFace);
+  parameters.setFaceId(newFace->getId());
 
-  options.setFaceId(newFace->getId());
-
-  ndn::nfd::ControlResponse response;
-  setResponse(response, 200, "Success", options.wireEncode());
-  sendResponse(requestName, response);
+  sendResponse(requestName, 200, "Success", parameters.wireEncode());
 }
 
 void
@@ -626,11 +612,12 @@
 }
 
 void
-FaceManager::createFace(const Name& requestName,
-                        ndn::nfd::FaceManagementOptions& options)
+FaceManager::createFace(const Interest& request,
+                        ControlParameters& parameters)
 {
+  const Name& requestName = request.getName();
   FaceUri uri;
-  if (!uri.parse(options.getUri()))
+  if (!parameters.hasUri() || !uri.parse(parameters.getUri()))
     {
       sendResponse(requestName, 400, "Malformed command");
       return;
@@ -644,24 +631,29 @@
     }
 
   factory->second->createFace(uri,
-                              bind(&FaceManager::onCreated, this, requestName, options, _1),
+                              bind(&FaceManager::onCreated, this, requestName, parameters, _1),
                               bind(&FaceManager::onConnectFailed, this, requestName, _1));
 }
 
 
 void
-FaceManager::destroyFace(const Name& requestName,
-                         ndn::nfd::FaceManagementOptions& options)
+FaceManager::destroyFace(const Interest& request,
+                         ControlParameters& parameters)
 {
-  shared_ptr<Face> target = m_faceTable.get(options.getFaceId());
+  const Name& requestName = request.getName();
+  if (!parameters.hasFaceId())
+    {
+      sendResponse(requestName, 400, "Malformed command");
+      return;
+    }
+
+  shared_ptr<Face> target = m_faceTable.get(parameters.getFaceId());
   if (static_cast<bool>(target))
     {
       target->close();
     }
 
-  ndn::nfd::ControlResponse response;
-  setResponse(response, 200, "Success", options.wireEncode());
-  sendResponse(requestName, response);
+  sendResponse(requestName, 200, "Success", parameters.wireEncode());
 }
 
 void
@@ -689,6 +681,70 @@
 }
 
 
+bool
+FaceManager::validateLocalControlParameters(const Interest& request,
+                                            ControlParameters& parameters,
+                                            shared_ptr<LocalFace>& outFace,
+                                            LocalControlFeature& outFeature)
+{
+  if (!parameters.hasLocalControlFeature() ||
+      (parameters.getLocalControlFeature() != LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID &&
+       parameters.getLocalControlFeature() != LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID))
+    {
+      NFD_LOG_INFO("command result: malformed");
+      sendResponse(request.getName(), 400, "Malformed command");
+      return false;
+    }
+
+  shared_ptr<Face> face = m_faceTable.get(request.getIncomingFaceId());
+
+  if (!static_cast<bool>(face))
+    {
+      NFD_LOG_INFO("command result: faceid " << parameters.getFaceId() << " not found");
+      sendResponse(request.getName(), 410, "Requested face not found");
+      return false;
+    }
+  else if (!face->isLocal())
+    {
+      NFD_LOG_INFO("command result: cannot enable local control on non-local faceid " << parameters.getFaceId());
+      sendResponse(request.getName(), 412, "Requested face is non-local");
+      return false;
+    }
+
+  outFace = dynamic_pointer_cast<LocalFace>(face);
+  outFeature = static_cast<LocalControlFeature>(parameters.getLocalControlFeature());
+
+  return true;
+}
+
+void
+FaceManager::enableLocalControl(const Interest& request,
+                                ControlParameters& parameters)
+{
+  shared_ptr<LocalFace> face;
+  LocalControlFeature feature;
+
+  if (validateLocalControlParameters(request, parameters, face, feature))
+    {
+      face->setLocalControlHeaderFeature(feature, true);
+      sendResponse(request.getName(), 200, "Success", parameters.wireEncode());
+    }
+}
+
+void
+FaceManager::disableLocalControl(const Interest& request,
+                                 ControlParameters& parameters)
+{
+  shared_ptr<LocalFace> face;
+  LocalControlFeature feature;
+
+  if (validateLocalControlParameters(request, parameters, face, feature))
+    {
+      face->setLocalControlHeaderFeature(feature, false);
+      sendResponse(request.getName(), 200, "Success", parameters.wireEncode());
+    }
+}
+
 void
 FaceManager::listFaces(const Interest& request)
 {
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index d489dff..7312bba 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -9,6 +9,7 @@
 
 #include "common.hpp"
 #include "face/face.hpp"
+#include "face/local-face.hpp"
 #include "mgmt/app-face.hpp"
 #include "mgmt/manager-base.hpp"
 #include "mgmt/config-file.hpp"
@@ -16,7 +17,7 @@
 #include "mgmt/notification-stream.hpp"
 #include "fw/face-table.hpp"
 
-#include <ndn-cpp-dev/management/nfd-face-management-options.hpp>
+#include <ndn-cpp-dev/management/nfd-control-parameters.hpp>
 #include <ndn-cpp-dev/management/nfd-control-response.hpp>
 
 namespace nfd {
@@ -25,6 +26,7 @@
 
 class ProtocolFactory;
 class NetworkInterfaceInfo;
+class LocalFace;
 
 class FaceManager : public ManagerBase
 {
@@ -63,26 +65,36 @@
   onValidatedFaceRequest(const shared_ptr<const Interest>& request);
 
   VIRTUAL_WITH_TESTS void
-  createFace(const Name& requestName,
-             ndn::nfd::FaceManagementOptions& options);
+  createFace(const Interest& request,
+             ControlParameters& parameters);
 
   VIRTUAL_WITH_TESTS void
-  destroyFace(const Name& requestName,
-              ndn::nfd::FaceManagementOptions& options);
+  destroyFace(const Interest& request,
+              ControlParameters& parameters);
+
+  VIRTUAL_WITH_TESTS bool
+  validateLocalControlParameters(const Interest& request,
+                                 ControlParameters& parameters,
+                                 shared_ptr<LocalFace>& outFace,
+                                 LocalControlFeature& outFeature);
+
+  VIRTUAL_WITH_TESTS void
+  enableLocalControl(const Interest& request,
+                     ControlParameters& parambeters);
+
+  VIRTUAL_WITH_TESTS void
+  disableLocalControl(const Interest& request,
+                      ControlParameters& parameters);
 
   void
   ignoreUnsignedVerb(const Interest& request);
 
-  bool
-  extractOptions(const Interest& request,
-                 ndn::nfd::FaceManagementOptions& extractedOptions);
-
   void
   addCreatedFaceToForwarder(const shared_ptr<Face>& newFace);
 
   void
   onCreated(const Name& requestName,
-            ndn::nfd::FaceManagementOptions& options,
+            ControlParameters& parameters,
             const shared_ptr<Face>& newFace);
 
   void
@@ -131,8 +143,8 @@
   NotificationStream m_notificationStream;
 
   typedef function<void(FaceManager*,
-                        const Name&,
-                        ndn::nfd::FaceManagementOptions&)> SignedVerbProcessor;
+                        const Interest&,
+                        ControlParameters&)> SignedVerbProcessor;
 
   typedef std::map<Name::Component, SignedVerbProcessor> SignedVerbDispatchTable;
   typedef std::pair<Name::Component, SignedVerbProcessor> SignedVerbAndProcessor;
@@ -149,7 +161,7 @@
   static const Name COMMAND_PREFIX; // /localhost/nfd/faces
 
   // number of components in an invalid signed command (i.e. should be signed, but isn't)
-  // (/localhost/nfd/faces + verb + options) = 5
+  // (/localhost/nfd/faces + verb + parameters) = 5
   static const size_t COMMAND_UNSIGNED_NCOMPS;
 
   // number of components in a valid signed command.
diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp
index 9ce7a6f..b1b869b 100644
--- a/daemon/mgmt/fib-manager.cpp
+++ b/daemon/mgmt/fib-manager.cpp
@@ -22,7 +22,7 @@
 const size_t FibManager::COMMAND_UNSIGNED_NCOMPS =
   FibManager::COMMAND_PREFIX.size() +
   1 + // verb
-  1;  // verb options
+  1;  // verb parameters
 
 const size_t FibManager::COMMAND_SIGNED_NCOMPS =
   FibManager::COMMAND_UNSIGNED_NCOMPS +
@@ -92,13 +92,13 @@
       (unsignedVerbProcessor->second)(this, boost::cref(request));
     }
   else if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
-      commandNComps < COMMAND_SIGNED_NCOMPS)
+           commandNComps < COMMAND_SIGNED_NCOMPS)
     {
       NFD_LOG_INFO("command result: unsigned verb: " << command);
       sendResponse(command, 401, "Signature required");
     }
   else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
-      !COMMAND_PREFIX.isPrefixOf(command))
+           !COMMAND_PREFIX.isPrefixOf(command))
     {
       NFD_LOG_INFO("command result: malformed");
       sendResponse(command, 400, "Malformed command");
@@ -115,22 +115,30 @@
 FibManager::onValidatedFibRequest(const shared_ptr<const Interest>& request)
 {
   const Name& command = request->getName();
-  const Name::Component& verb = command.get(COMMAND_PREFIX.size());
+  const Name::Component& verb = command[COMMAND_PREFIX.size()];
+  const Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
 
   SignedVerbDispatchTable::const_iterator signedVerbProcessor = m_signedVerbDispatch.find (verb);
   if (signedVerbProcessor != m_signedVerbDispatch.end())
     {
-      FibManagementOptions options;
-      if (!extractOptions(*request, options))
+      ControlParameters parameters;
+      if (!extractParameters(parameterComponent, parameters) ||
+          !parameters.hasName() ||
+          !parameters.hasFaceId())
         {
           NFD_LOG_INFO("command result: malformed verb: " << verb);
           sendResponse(command, 400, "Malformed command");
           return;
         }
 
+      if (parameters.getFaceId() == 0)
+        {
+          parameters.setFaceId(request->getIncomingFaceId());
+        }
+
       NFD_LOG_INFO("command result: processing verb: " << verb);
       ControlResponse response;
-      (signedVerbProcessor->second)(this, options, response);
+      (signedVerbProcessor->second)(this, parameters, response);
       sendResponse(command, response);
     }
   else
@@ -140,98 +148,70 @@
     }
 }
 
-bool
-FibManager::extractOptions(const Interest& request,
-                           FibManagementOptions& extractedOptions)
-{
-  const Name& command = request.getName();
-  const size_t optionCompIndex = COMMAND_PREFIX.size() + 1;
 
-  try
-    {
-      Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
-      extractedOptions.wireDecode(rawOptions);
-    }
-  catch (const ndn::Tlv::Error& e)
-    {
-      NFD_LOG_INFO("Bad command option parse: " << command);
-      return false;
-    }
-
-  if (extractedOptions.getFaceId() == 0)
-    {
-      extractedOptions.setFaceId(request.getIncomingFaceId());
-    }
-
-  NFD_LOG_DEBUG("Options parsed OK");
-  return true;
-}
 
 void
-FibManager::addNextHop(const FibManagementOptions& options,
+FibManager::addNextHop(ControlParameters& parameters,
                        ControlResponse& response)
 {
-  NFD_LOG_DEBUG("add-nexthop prefix: " << options.getName()
-                << " faceid: " << options.getFaceId()
-                << " cost: " << options.getCost());
+  if (!parameters.hasCost())
+    {
+      parameters.setCost(0);
+    }
 
-  shared_ptr<Face> nextHopFace = m_getFace(options.getFaceId());
+  const Name& prefix = parameters.getName();
+  FaceId faceId = parameters.getFaceId();
+  uint64_t cost = parameters.getCost();
+
+  NFD_LOG_DEBUG("add-nexthop prefix: " << prefix
+                << " faceid: " << faceId
+                << " cost: " << cost);
+
+  shared_ptr<Face> nextHopFace = m_getFace(faceId);
   if (static_cast<bool>(nextHopFace))
     {
-      shared_ptr<fib::Entry> entry = m_managedFib.insert(options.getName()).first;
+      shared_ptr<fib::Entry> entry = m_managedFib.insert(prefix).first;
 
-      entry->addNextHop(nextHopFace, options.getCost());
+      entry->addNextHop(nextHopFace, cost);
 
       NFD_LOG_INFO("add-nexthop result: OK"
-                   << " prefix:" << options.getName()
-                   << " faceid: " << options.getFaceId()
-                   << " cost: " << options.getCost());
-      setResponse(response, 200, "Success", options.wireEncode());
+                   << " prefix:" << prefix
+                   << " faceid: " << faceId
+                   << " cost: " << cost);
+
+      setResponse(response, 200, "Success", parameters.wireEncode());
     }
   else
     {
-      NFD_LOG_INFO("add-nexthop result: FAIL reason: unknown-faceid: " << options.getFaceId());
-      setResponse(response, 404, "Face not found");
+      NFD_LOG_INFO("add-nexthop result: FAIL reason: unknown-faceid: " << faceId);
+      setResponse(response, 410, "Face not found");
     }
 }
 
 void
-FibManager::removeNextHop(const FibManagementOptions& options,
+FibManager::removeNextHop(ControlParameters& parameters,
                           ControlResponse& response)
 {
-  NFD_LOG_DEBUG("remove-nexthop prefix: " << options.getName()
-                << " faceid: " << options.getFaceId());
+  NFD_LOG_DEBUG("remove-nexthop prefix: " << parameters.getName()
+                << " faceid: " << parameters.getFaceId());
 
-  shared_ptr<Face> faceToRemove = m_getFace(options.getFaceId());
+  shared_ptr<Face> faceToRemove = m_getFace(parameters.getFaceId());
   if (static_cast<bool>(faceToRemove))
     {
-      shared_ptr<fib::Entry> entry = m_managedFib.findExactMatch(options.getName());
+      shared_ptr<fib::Entry> entry = m_managedFib.findExactMatch(parameters.getName());
       if (static_cast<bool>(entry))
         {
           entry->removeNextHop(faceToRemove);
-          NFD_LOG_INFO("remove-nexthop result: OK prefix: " << options.getName()
-                       << " faceid: " << options.getFaceId());
+          NFD_LOG_INFO("remove-nexthop result: OK prefix: " << parameters.getName()
+                       << " faceid: " << parameters.getFaceId());
 
           if (!entry->hasNextHops())
             {
               m_managedFib.erase(*entry);
             }
-
-          setResponse(response, 200, "Success", options.wireEncode());
-        }
-      else
-        {
-          NFD_LOG_INFO("remove-nexthop result: FAIL reason: unknown-prefix: "
-                       << options.getName());
-          setResponse(response, 404, "Prefix not found");
         }
     }
-  else
-    {
-      NFD_LOG_INFO("remove-nexthop result: FAIL reason: unknown-faceid: "
-                   << options.getFaceId());
-      setResponse(response, 404, "Face not found");
-    }
+  setResponse(response, 200, "Success", parameters.wireEncode());
 }
 
 void
diff --git a/daemon/mgmt/fib-manager.hpp b/daemon/mgmt/fib-manager.hpp
index 10b4fb2..5ce6e86 100644
--- a/daemon/mgmt/fib-manager.hpp
+++ b/daemon/mgmt/fib-manager.hpp
@@ -14,12 +14,8 @@
 #include "mgmt/manager-base.hpp"
 #include "mgmt/fib-enumeration-publisher.hpp"
 
-#include <ndn-cpp-dev/management/nfd-fib-management-options.hpp>
-
 namespace nfd {
 
-using ndn::nfd::FibManagementOptions;
-
 class Forwarder;
 class Fib;
 
@@ -45,29 +41,16 @@
   onValidatedFibRequest(const shared_ptr<const Interest>& request);
 
   void
-  insertEntry(const FibManagementOptions& options,
-              ControlResponse& response);
-
-
-  void
-  deleteEntry(const FibManagementOptions& options,
-              ControlResponse& response);
-
-  void
-  addNextHop(const FibManagementOptions& options,
+  addNextHop(ControlParameters& parameters,
              ControlResponse& response);
 
   void
-  removeNextHop(const FibManagementOptions& options,
+  removeNextHop(ControlParameters& parameters,
                 ControlResponse& response);
 
   void
   listEntries(const Interest& request);
 
-  bool
-  extractOptions(const Interest& request,
-                 FibManagementOptions& extractedOptions);
-
 private:
 
   Fib& m_managedFib;
@@ -75,7 +58,7 @@
   FibEnumerationPublisher m_fibEnumerationPublisher;
 
   typedef function<void(FibManager*,
-                        const FibManagementOptions&,
+                        ControlParameters&,
                         ControlResponse&)> SignedVerbProcessor;
 
   typedef std::map<Name::Component, SignedVerbProcessor> SignedVerbDispatchTable;
@@ -94,7 +77,7 @@
   static const Name COMMAND_PREFIX; // /localhost/nfd/fib
 
   // number of components in an invalid, but not malformed, unsigned command.
-  // (/localhost/nfd/fib + verb + options) = 5
+  // (/localhost/nfd/fib + verb + parameters) = 5
   static const size_t COMMAND_UNSIGNED_NCOMPS;
 
   // number of components in a valid signed Interest.
diff --git a/daemon/mgmt/local-control-header-manager.cpp b/daemon/mgmt/local-control-header-manager.cpp
deleted file mode 100644
index aae1d0c..0000000
--- a/daemon/mgmt/local-control-header-manager.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (C) 2014 Named Data Networking Project
- * See COPYING for copyright and distribution information.
- */
-
-#include "local-control-header-manager.hpp"
-#include "face/local-face.hpp"
-#include "mgmt/internal-face.hpp"
-
-namespace nfd {
-
-NFD_LOG_INIT("LocalControlHeaderManager");
-
-const Name LocalControlHeaderManager::COMMAND_PREFIX = "/localhost/nfd/control-header";
-
-const size_t LocalControlHeaderManager::COMMAND_UNSIGNED_NCOMPS =
-  LocalControlHeaderManager::COMMAND_PREFIX.size() +
-  1 + // control-module
-  1; // verb
-
-const size_t LocalControlHeaderManager::COMMAND_SIGNED_NCOMPS =
-  LocalControlHeaderManager::COMMAND_UNSIGNED_NCOMPS +
-  4; // (timestamp, nonce, signed info tlv, signature tlv)
-
-
-LocalControlHeaderManager::LocalControlHeaderManager(function<shared_ptr<Face>(FaceId)> getFace,
-                                                     shared_ptr<InternalFace> face)
-  : ManagerBase(face, CONTROL_HEADER_PRIVILEGE),
-    m_getFace(getFace)
-{
-  face->setInterestFilter("/localhost/nfd/control-header",
-                          bind(&LocalControlHeaderManager::onLocalControlHeaderRequest, this, _2));
-}
-
-
-
-void
-LocalControlHeaderManager::onLocalControlHeaderRequest(const Interest& request)
-{
-  const Name& command = request.getName();
-  const size_t commandNComps = command.size();
-
-  if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
-      commandNComps < COMMAND_SIGNED_NCOMPS)
-    {
-      NFD_LOG_INFO("command result: unsigned verb: " << command);
-      sendResponse(command, 401, "Signature required");
-
-      return;
-    }
-  else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
-      !COMMAND_PREFIX.isPrefixOf(command))
-    {
-      NFD_LOG_INFO("command result: malformed");
-      sendResponse(command, 400, "Malformed command");
-      return;
-    }
-
-  validate(request,
-             bind(&LocalControlHeaderManager::onCommandValidated,
-                    this, _1),
-             bind(&ManagerBase::onCommandValidationFailed,
-                    this, _1, _2));
-
-
-}
-
-void
-LocalControlHeaderManager::onCommandValidated(const shared_ptr<const Interest>& command)
-{
-  static const Name::Component MODULE_IN_FACEID("in-faceid");
-  static const Name::Component MODULE_NEXTHOP_FACEID("nexthop-faceid");
-  static const Name::Component VERB_ENABLE("enable");
-  static const Name::Component VERB_DISABLE("disable");
-
-  shared_ptr<LocalFace> face =
-    dynamic_pointer_cast<LocalFace>(m_getFace(command->getIncomingFaceId()));
-
-  if (!static_cast<bool>(face))
-    {
-      NFD_LOG_INFO("command result: command to enable control header on non-local face");
-      sendResponse(command->getName(), 400, "Command not supported on the requested face");
-      return;
-    }
-
-  const Name& commandName = command->getName();
-  const Name::Component& module = commandName[COMMAND_PREFIX.size()];
-  const Name::Component& verb = commandName[COMMAND_PREFIX.size() + 1];
-
-  if (module == MODULE_IN_FACEID)
-    {
-      if (verb == VERB_ENABLE)
-        {
-          face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID, true);
-          sendResponse(commandName, 200, "Success");
-        }
-      else if (verb == VERB_DISABLE)
-        {
-          face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID, false);
-          sendResponse(commandName, 200, "Success");
-        }
-      else
-        {
-          NFD_LOG_INFO("command result: unsupported verb: " << verb);
-          sendResponse(commandName, 501, "Unsupported");
-        }
-    }
-  else if (module == MODULE_NEXTHOP_FACEID)
-    {
-      if (verb == VERB_ENABLE)
-        {
-          face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID, true);
-          sendResponse(commandName, 200, "Success");
-        }
-      else if (verb == VERB_DISABLE)
-        {
-          face->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID, false);
-          sendResponse(commandName, 200, "Success");
-        }
-      else
-        {
-          NFD_LOG_INFO("command result: unsupported verb: " << verb);
-          sendResponse(commandName, 501, "Unsupported");
-        }
-    }
-  else
-    {
-      NFD_LOG_INFO("command result: unsupported module: " << module);
-      sendResponse(commandName, 501, "Unsupported");
-    }
-}
-
-} // namespace nfd
-
diff --git a/daemon/mgmt/local-control-header-manager.hpp b/daemon/mgmt/local-control-header-manager.hpp
deleted file mode 100644
index 0aa5d63..0000000
--- a/daemon/mgmt/local-control-header-manager.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (C) 2014 Named Data Networking Project
- * See COPYING for copyright and distribution information.
- */
-
-#ifndef NFD_MGMT_LOCAL_CONTROL_HEADER_MANAGER_HPP
-#define NFD_MGMT_LOCAL_CONTROL_HEADER_MANAGER_HPP
-
-#include "common.hpp"
-#include "face/face.hpp"
-#include "mgmt/app-face.hpp"
-#include "mgmt/manager-base.hpp"
-
-namespace nfd {
-
-const std::string CONTROL_HEADER_PRIVILEGE = "control-header"; // config file privilege name
-
-class LocalControlHeaderManager : public ManagerBase
-{
-public:
-  LocalControlHeaderManager(function<shared_ptr<Face>(FaceId)> getFace,
-                            shared_ptr<InternalFace> face);
-
-  void
-  onLocalControlHeaderRequest(const Interest& request);
-
-  void
-  onCommandValidated(const shared_ptr<const Interest>& command);
-
-private:
-  function<shared_ptr<Face>(FaceId)> m_getFace;
-
-  static const Name COMMAND_PREFIX; // /localhost/nfd/control-header
-
-  // number of components in an invalid, but not malformed, unsigned command.
-  // (/localhost/nfd/control-header + control-module + verb) = 5
-  static const size_t COMMAND_UNSIGNED_NCOMPS;
-
-  // number of components in a valid signed Interest.
-  // UNSIGNED_NCOMPS + 4 command Interest components = 9
-  static const size_t COMMAND_SIGNED_NCOMPS;
-};
-
-} // namespace nfd
-
-#endif // NFD_MGMT_LOCAL_CONTROL_HEADER_MANAGER_HPP
-
-
-
diff --git a/daemon/mgmt/manager-base.cpp b/daemon/mgmt/manager-base.cpp
index ad26e53..af5fc37 100644
--- a/daemon/mgmt/manager-base.cpp
+++ b/daemon/mgmt/manager-base.cpp
@@ -21,6 +21,24 @@
 
 }
 
+bool
+ManagerBase::extractParameters(const Name::Component& parameterComponent,
+                               ControlParameters& extractedParameters)
+{
+  try
+    {
+      Block rawParameters = parameterComponent.blockFromValue();
+      extractedParameters.wireDecode(rawParameters);
+    }
+  catch (const ndn::Tlv::Error& e)
+    {
+      return false;
+    }
+
+  NFD_LOG_DEBUG("Parameters parsed OK");
+  return true;
+}
+
 void
 ManagerBase::sendResponse(const Name& name,
                           uint32_t code,
@@ -32,6 +50,17 @@
 
 void
 ManagerBase::sendResponse(const Name& name,
+                          uint32_t code,
+                          const std::string& text,
+                          const Block& body)
+{
+  ControlResponse response(code, text);
+  response.setBody(body);
+  sendResponse(name, response);
+}
+
+void
+ManagerBase::sendResponse(const Name& name,
                           const ControlResponse& response)
 {
   NFD_LOG_DEBUG("responding"
diff --git a/daemon/mgmt/manager-base.hpp b/daemon/mgmt/manager-base.hpp
index 9522812..46e34b6 100644
--- a/daemon/mgmt/manager-base.hpp
+++ b/daemon/mgmt/manager-base.hpp
@@ -8,15 +8,17 @@
 #define NFD_MGMT_MANAGER_BASE_HPP
 
 #include "common.hpp"
-#include <ndn-cpp-dev/management/nfd-control-response.hpp>
 
 #include "mgmt/command-validator.hpp"
 #include "mgmt/internal-face.hpp"
 
+#include <ndn-cpp-dev/management/nfd-control-response.hpp>
+#include <ndn-cpp-dev/management/nfd-control-parameters.hpp>
 
 namespace nfd {
 
 using ndn::nfd::ControlResponse;
+using ndn::nfd::ControlParameters;
 
 class InternalFace;
 
@@ -40,6 +42,10 @@
 
 protected:
 
+  static bool
+  extractParameters(const Name::Component& parameterComponent,
+                    ControlParameters& extractedParameters);
+
   void
   setResponse(ControlResponse& response,
               uint32_t code,
@@ -59,6 +65,12 @@
                uint32_t code,
                const std::string& text);
 
+  void
+  sendResponse(const Name& name,
+               uint32_t code,
+               const std::string& text,
+               const Block& body);
+
 PUBLIC_WITH_TESTS_ELSE_PROTECTED:
   void
   addInterestRule(const std::string& regex,
diff --git a/daemon/mgmt/strategy-choice-manager.cpp b/daemon/mgmt/strategy-choice-manager.cpp
index cd4dc5b..bbedd34 100644
--- a/daemon/mgmt/strategy-choice-manager.cpp
+++ b/daemon/mgmt/strategy-choice-manager.cpp
@@ -17,7 +17,7 @@
 const size_t StrategyChoiceManager::COMMAND_UNSIGNED_NCOMPS =
   StrategyChoiceManager::COMMAND_PREFIX.size() +
   1 + // verb
-  1;  // verb options
+  1;  // verb parameters
 
 const size_t StrategyChoiceManager::COMMAND_SIGNED_NCOMPS =
   StrategyChoiceManager::COMMAND_UNSIGNED_NCOMPS +
@@ -71,23 +71,24 @@
   static const Name::Component VERB_UNSET("unset");
 
   const Name& command = request->getName();
+  const Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
 
-  ndn::nfd::StrategyChoiceOptions options;
-  if (!extractOptions(*request, options))
+  ControlParameters parameters;
+  if (!extractParameters(parameterComponent, parameters) || !parameters.hasName())
     {
       sendResponse(command, 400, "Malformed command");
       return;
     }
 
-  const Name::Component& verb = command.get(COMMAND_PREFIX.size());
+  const Name::Component& verb = command[COMMAND_PREFIX.size()];
   ControlResponse response;
   if (verb == VERB_SET)
     {
-      setStrategy(options, response);
+      setStrategy(parameters, response);
     }
   else if (verb == VERB_UNSET)
     {
-      unsetStrategy(options, response);
+      unsetStrategy(parameters, response);
     }
   else
     {
@@ -97,47 +98,30 @@
   sendResponse(command, response);
 }
 
-bool
-StrategyChoiceManager::extractOptions(const Interest& request,
-                                      ndn::nfd::StrategyChoiceOptions& extractedOptions)
-{
-  const Name& command = request.getName();
-  const size_t optionCompIndex =
-    COMMAND_PREFIX.size() + 1;
-
-  try
-    {
-      Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
-      extractedOptions.wireDecode(rawOptions);
-    }
-  catch (const ndn::Tlv::Error& e)
-    {
-      NFD_LOG_INFO("Bad command option parse: " << command);
-      return false;
-    }
-
-  NFD_LOG_DEBUG("Options parsed OK");
-  return true;
-}
-
 void
-StrategyChoiceManager::setStrategy(const ndn::nfd::StrategyChoiceOptions& options,
+StrategyChoiceManager::setStrategy(const ControlParameters& parameters,
                                    ControlResponse& response)
 {
-  const Name& prefix = options.getName();
-  const Name& selectedStrategy = options.getStrategy();
+  if (!parameters.hasStrategy())
+    {
+      setResponse(response, 400, "Malformed command");
+      return;
+    }
+
+  const Name& prefix = parameters.getName();
+  const Name& selectedStrategy = parameters.getStrategy();
 
   if (!m_strategyChoice.hasStrategy(selectedStrategy))
     {
       NFD_LOG_INFO("strategy-choice result: FAIL reason: unknown-strategy: "
-                   << options.getStrategy());
+                   << parameters.getStrategy());
       setResponse(response, 504, "Unsupported strategy");
       return;
     }
 
   if (m_strategyChoice.insert(prefix, selectedStrategy))
     {
-      setResponse(response, 200, "Success", options.wireEncode());
+      setResponse(response, 200, "Success", parameters.wireEncode());
     }
   else
     {
@@ -146,22 +130,22 @@
 }
 
 void
-StrategyChoiceManager::unsetStrategy(const ndn::nfd::StrategyChoiceOptions& options,
+StrategyChoiceManager::unsetStrategy(const ControlParameters& parameters,
                                      ControlResponse& response)
 {
   static const Name ROOT_PREFIX;
 
-  const Name& prefix = options.getName();
+  const Name& prefix = parameters.getName();
   if (prefix == ROOT_PREFIX)
     {
       NFD_LOG_INFO("strategy-choice result: FAIL reason: unknown-prefix: "
-                   << options.getName());
+                   << parameters.getName());
       setResponse(response, 403, "Cannot unset root prefix strategy");
       return;
     }
 
   m_strategyChoice.erase(prefix);
-  setResponse(response, 200, "Success", options.wireEncode());
+  setResponse(response, 200, "Success", parameters.wireEncode());
 }
 
 
diff --git a/daemon/mgmt/strategy-choice-manager.hpp b/daemon/mgmt/strategy-choice-manager.hpp
index 2232588..d884786 100644
--- a/daemon/mgmt/strategy-choice-manager.hpp
+++ b/daemon/mgmt/strategy-choice-manager.hpp
@@ -9,7 +9,7 @@
 
 #include "mgmt/manager-base.hpp"
 
-#include <ndn-cpp-dev/management/nfd-strategy-choice-options.hpp>
+#include <ndn-cpp-dev/management/nfd-control-parameters.hpp>
 
 namespace nfd {
 
@@ -33,18 +33,12 @@
   void
   onValidatedStrategyChoiceRequest(const shared_ptr<const Interest>& request);
 
-  bool
-  extractOptions(const Interest& request,
-                   ndn::nfd::StrategyChoiceOptions& extractedOptions);
-
-
-
   void
-  setStrategy(const ndn::nfd::StrategyChoiceOptions& options,
+  setStrategy(const ControlParameters& parameters,
               ControlResponse& response);
 
   void
-  unsetStrategy(const ndn::nfd::StrategyChoiceOptions& options,
+  unsetStrategy(const ControlParameters& parameters,
                 ControlResponse& response);
 private:
 
@@ -53,7 +47,7 @@
   static const Name COMMAND_PREFIX; // /localhost/nfd/strategy-choice
 
   // number of components in an invalid, but not malformed, unsigned command.
-  // (/localhost/nfd/strategy-choice + verb + options) = 5
+  // (/localhost/nfd/strategy-choice + verb + parameters) = 5
   static const size_t COMMAND_UNSIGNED_NCOMPS;
 
   // number of components in a valid signed Interest.
diff --git a/daemon/table/fib-nexthop.cpp b/daemon/table/fib-nexthop.cpp
index 6fec93f..8e068e6 100644
--- a/daemon/table/fib-nexthop.cpp
+++ b/daemon/table/fib-nexthop.cpp
@@ -26,12 +26,12 @@
 }
 
 void
-NextHop::setCost(uint32_t cost)
+NextHop::setCost(uint64_t cost)
 {
   m_cost = cost;
 }
 
-uint32_t
+uint64_t
 NextHop::getCost() const
 {
   return m_cost;
diff --git a/daemon/table/fib-nexthop.hpp b/daemon/table/fib-nexthop.hpp
index 72fa687..de29c0f 100644
--- a/daemon/table/fib-nexthop.hpp
+++ b/daemon/table/fib-nexthop.hpp
@@ -28,14 +28,14 @@
   getFace() const;
 
   void
-  setCost(uint32_t cost);
+  setCost(uint64_t cost);
 
-  uint32_t
+  uint64_t
   getCost() const;
 
 private:
   shared_ptr<Face> m_face;
-  uint32_t m_cost;
+  uint64_t m_cost;
 };
 
 } // namespace fib