tools: nfdc route remove command

refs #3866

Change-Id: Iffbcf3face8758a52d35a854408f9910f4ba6c0b
diff --git a/tools/nfdc/find-face.cpp b/tools/nfdc/find-face.cpp
index d877e81..5645e26 100644
--- a/tools/nfdc/find-face.cpp
+++ b/tools/nfdc/find-face.cpp
@@ -43,7 +43,7 @@
 {
   FaceQueryFilter filter;
   filter.setRemoteUri(faceUri.toString());
-  return this->execute(filter);
+  return this->execute(filter, allowMulti);
 }
 
 FindFace::Code
@@ -55,14 +55,14 @@
 }
 
 FindFace::Code
-FindFace::execute(const boost::any& faceIdOrUri)
+FindFace::execute(const boost::any& faceIdOrUri, bool allowMulti)
 {
   const uint64_t* faceId = boost::any_cast<uint64_t>(&faceIdOrUri);
   if (faceId != nullptr) {
     return this->execute(*faceId);
   }
   else {
-    return this->execute(boost::any_cast<FaceUri>(faceIdOrUri));
+    return this->execute(boost::any_cast<FaceUri>(faceIdOrUri), allowMulti);
   }
 }
 
diff --git a/tools/nfdc/find-face.hpp b/tools/nfdc/find-face.hpp
index 45c3f1e..2661aa6 100644
--- a/tools/nfdc/find-face.hpp
+++ b/tools/nfdc/find-face.hpp
@@ -72,11 +72,11 @@
 
   /** \brief find face by FaceId or FaceUri
    *  \param faceIdOrUri a boost::any that contains uint64_t or FaceUri
-   *  \note allowMulti will be set to false
+   *  \param allowMulti effective only if \p faceIdOrUri contains a FaceUri
    *  \throw boost::bad_any_cast faceIdOrUri is neither uint64_t nor FaceUri
    */
   Code
-  execute(const boost::any& faceIdOrUri);
+  execute(const boost::any& faceIdOrUri, bool allowMulti = false);
 
   /** \brief find face by FaceQueryFilter
    *  \pre execute has not been invoked
diff --git a/tools/nfdc/rib-module.cpp b/tools/nfdc/rib-module.cpp
index b85410c..295ad3f 100644
--- a/tools/nfdc/rib-module.cpp
+++ b/tools/nfdc/rib-module.cpp
@@ -45,6 +45,14 @@
     .addArg("capture", ArgValueType::NONE, Required::NO, Positional::NO)
     .addArg("expires", ArgValueType::UNSIGNED, Required::NO, Positional::NO);
   parser.addCommand(defRouteAdd, &RibModule::add);
+
+  CommandDefinition defRouteRemove("route", "remove");
+  defRouteRemove
+    .setTitle("remove a route")
+    .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES)
+    .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::YES, Positional::YES)
+    .addArg("origin", ArgValueType::UNSIGNED, Required::NO, Positional::NO);
+  parser.addCommand(defRouteRemove, &RibModule::remove);
 }
 
 void
@@ -116,6 +124,54 @@
 }
 
 void
+RibModule::remove(ExecuteContext& ctx)
+{
+  auto prefix = ctx.args.get<Name>("prefix");
+  const boost::any& nexthop = ctx.args.at("nexthop");
+  auto origin = ctx.args.get<uint64_t>("origin", ndn::nfd::ROUTE_ORIGIN_STATIC);
+
+  FindFace findFace(ctx);
+  FindFace::Code res = findFace.execute(nexthop, true);
+
+  ctx.exitCode = static_cast<int>(res);
+  switch (res) {
+    case FindFace::Code::OK:
+      break;
+    case FindFace::Code::ERROR:
+    case FindFace::Code::CANONIZE_ERROR:
+    case FindFace::Code::NOT_FOUND:
+      ctx.err << findFace.getErrorReason() << '\n';
+      return;
+    default:
+      BOOST_ASSERT_MSG(false, "unexpected FindFace result");
+      return;
+  }
+
+  for (const FaceStatus& faceStatus : findFace.getResults()) {
+    ControlParameters unregisterParams;
+    unregisterParams
+      .setName(prefix)
+      .setFaceId(faceStatus.getFaceId())
+      .setOrigin(origin);
+
+    ctx.controller.start<ndn::nfd::RibUnregisterCommand>(
+      unregisterParams,
+      [&] (const ControlParameters& resp) {
+        ctx.out << "route-removed ";
+        text::ItemAttributes ia;
+        ctx.out << ia("prefix") << resp.getName()
+                << ia("nexthop") << resp.getFaceId()
+                << ia("origin") << resp.getOrigin()
+                << '\n';
+      },
+      ctx.makeCommandFailureHandler("removing route"),
+      ctx.makeCommandOptions());
+  }
+
+  ctx.face.processEvents();
+}
+
+void
 RibModule::fetchStatus(Controller& controller,
                        const function<void()>& onSuccess,
                        const Controller::DatasetFailCallback& onFailure,
diff --git a/tools/nfdc/rib-module.hpp b/tools/nfdc/rib-module.hpp
index cca1ef4..aee2c8b 100644
--- a/tools/nfdc/rib-module.hpp
+++ b/tools/nfdc/rib-module.hpp
@@ -52,6 +52,11 @@
   static void
   add(ExecuteContext& ctx);
 
+  /** \brief the 'route remove' command
+   */
+  static void
+  remove(ExecuteContext& ctx);
+
   void
   fetchStatus(Controller& controller,
               const function<void()>& onSuccess,