mgmt: fib manager implicit fib entry insertion and deletion

refs: #1340

Change-Id: If552bbff71b54c4616ff4478a470c9cdc2a5c4e4
diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp
index dee765b..4e1dbe7 100644
--- a/daemon/mgmt/fib-manager.cpp
+++ b/daemon/mgmt/fib-manager.cpp
@@ -30,15 +30,6 @@
 
 const FibManager::VerbAndProcessor FibManager::COMMAND_VERBS[] =
   {
-    VerbAndProcessor(
-                     Name::Component("insert"),
-                     &FibManager::insertEntry
-                     ),
-
-    VerbAndProcessor(
-                     Name::Component("delete"),
-                     &FibManager::deleteEntry
-                     ),
 
     VerbAndProcessor(
                      Name::Component("add-nexthop"),
@@ -66,6 +57,11 @@
                           bind(&FibManager::onFibRequest, this, _2));
 }
 
+FibManager::~FibManager()
+{
+
+}
+
 void
 FibManager::onFibRequest(const Interest& request)
 {
@@ -152,35 +148,6 @@
 }
 
 void
-FibManager::insertEntry(const FibManagementOptions& options,
-                        ControlResponse& response)
-{
-  NFD_LOG_DEBUG("insert prefix: " << options.getName());
-  NFD_LOG_INFO("insert result: OK"
-               << " prefix: " << options.getName());
-  std::pair<shared_ptr<fib::Entry>, bool> insertResult = m_managedFib.insert(options.getName());
-  setResponse(response, 200, "Success", options.wireEncode());
-}
-
-void
-FibManager::deleteEntry(const FibManagementOptions& options,
-                        ControlResponse& response)
-{
-  NFD_LOG_DEBUG("delete prefix: " << options.getName());
-  NFD_LOG_INFO("delete result: OK"
-               << " prefix: " << options.getName());
-
-  m_managedFib.erase(options.getName());
-  setResponse(response, 200, "Success", options.wireEncode());
-}
-
-static inline bool
-nextHopEqPredicate(const fib::NextHop& target, const fib::NextHop& hop)
-{
-  return target.getFace()->getId() == hop.getFace()->getId();
-}
-
-void
 FibManager::addNextHop(const FibManagementOptions& options,
                        ControlResponse& response)
 {
@@ -191,22 +158,15 @@
   shared_ptr<Face> nextHopFace = m_getFace(options.getFaceId());
   if (static_cast<bool>(nextHopFace))
     {
-      shared_ptr<fib::Entry> entry = m_managedFib.findExactMatch(options.getName());
-      if (static_cast<bool>(entry))
-        {
-          entry->addNextHop(nextHopFace, options.getCost());
+      shared_ptr<fib::Entry> entry = m_managedFib.insert(options.getName()).first;
 
-          NFD_LOG_INFO("add-nexthop result: OK"
-                       << " prefix:" << options.getName()
-                       << " faceid: " << options.getFaceId()
-                       << " cost: " << options.getCost());
-          setResponse(response, 200, "Success", options.wireEncode());
-        }
-      else
-        {
-          NFD_LOG_INFO("add-nexthop result: FAIL reason: unknown-prefix: " << options.getName());
-          setResponse(response, 404, "Prefix not found");
-        }
+      entry->addNextHop(nextHopFace, options.getCost());
+
+      NFD_LOG_INFO("add-nexthop result: OK"
+                   << " prefix:" << options.getName()
+                   << " faceid: " << options.getFaceId()
+                   << " cost: " << options.getCost());
+      setResponse(response, 200, "Success", options.wireEncode());
     }
   else
     {
@@ -232,6 +192,11 @@
           NFD_LOG_INFO("remove-nexthop result: OK prefix: " << options.getName()
                        << " faceid: " << options.getFaceId());
 
+          if (!entry->hasNextHops())
+            {
+              m_managedFib.erase(*entry);
+            }
+
           setResponse(response, 200, "Success", options.wireEncode());
         }
       else
diff --git a/daemon/mgmt/fib-manager.hpp b/daemon/mgmt/fib-manager.hpp
index 43b410e..1cbc49c 100644
--- a/daemon/mgmt/fib-manager.hpp
+++ b/daemon/mgmt/fib-manager.hpp
@@ -32,6 +32,9 @@
              function<shared_ptr<Face>(FaceId)> getFace,
              shared_ptr<InternalFace> face);
 
+  virtual
+  ~FibManager();
+
   void
   onFibRequest(const Interest& request);
 
diff --git a/daemon/table/fib.hpp b/daemon/table/fib.hpp
index 0fbacea..e1e5c5a 100644
--- a/daemon/table/fib.hpp
+++ b/daemon/table/fib.hpp
@@ -55,6 +55,9 @@
   void
   erase(const Name& prefix);
 
+  void
+  erase(const fib::Entry& entry);
+
   /** \brief removes the NextHop record for face in all entrites
    *  This is usually invoked when face goes away.
    *  Removing all NextHops in a FIB entry will not remove the FIB entry.
@@ -66,9 +69,6 @@
   size() const;
 
 private:
-  void
-  erase(const fib::Entry& entry);
-
   shared_ptr<fib::Entry>
   findLongestPrefixMatch(shared_ptr<name_tree::Entry> nameTreeEntry) const;
 
diff --git a/tests/mgmt/fib-manager.cpp b/tests/mgmt/fib-manager.cpp
index e6748be..66ed32b 100644
--- a/tests/mgmt/fib-manager.cpp
+++ b/tests/mgmt/fib-manager.cpp
@@ -424,8 +424,6 @@
     bind(&FibManagerFixture::validateControlResponse, this, _1,
          command->getName(), 200, "Success", encodedExpectedOptions);
 
-  getFib().insert("/hello");
-
   getFibManager().onFibRequest(*command);
 
   BOOST_REQUIRE(didCallbackFire());
@@ -456,8 +454,6 @@
     bind(&FibManagerFixture::validateControlResponse, this, _1,
          command->getName(), 200, "Success", encodedOptions);
 
-  getFib().insert("/hello");
-
   getFibManager().onFibRequest(*command);
 
   BOOST_REQUIRE(didCallbackFire());
@@ -469,8 +465,6 @@
   addFace(make_shared<DummyFace>());
   shared_ptr<InternalFace> face = getInternalFace();
 
-  getFib().insert("/hello");
-
   for (int i = 1; i <= 2; i++)
     {
 
@@ -520,8 +514,6 @@
   addFace(make_shared<DummyFace>());
   shared_ptr<InternalFace> face = getInternalFace();
 
-  getFib().insert("/hello");
-
   FibManagementOptions options;
   options.setName("/hello");
   options.setFaceId(1);
@@ -590,145 +582,151 @@
     }
 }
 
-BOOST_AUTO_TEST_CASE(Insert)
-{
-  shared_ptr<InternalFace> face = getInternalFace();
+// BOOST_AUTO_TEST_CASE(Insert)
+// {
+//   addFace(make_shared<DummyFace>());
+//   addFace(make_shared<DummyFace>());
+//   shared_ptr<InternalFace> face = getInternalFace();
 
-  {
-    FibManagementOptions options;
-    options.setName("/hello");
+//   {
+//     FibManagementOptions options;
+//     options.setName("/hello");
+//     options.setFaceId(1);
+//     options.setCost(101);
 
-    Block encodedOptions(options.wireEncode());
+//     Block encodedOptions(options.wireEncode());
 
-    Name commandName("/localhost/nfd/fib");
-    commandName.append("insert");
-    commandName.append(encodedOptions);
+//     Name commandName("/localhost/nfd/fib");
+//     commandName.append("add-nexthop");
+//     commandName.append(encodedOptions);
 
-    shared_ptr<Interest> command(make_shared<Interest>(commandName));
-    generateCommand(*command);
+//     shared_ptr<Interest> command(make_shared<Interest>(commandName));
+//     generateCommand(*command);
 
-    face->onReceiveData +=
-      bind(&FibManagerFixture::validateControlResponse, this, _1,
-           command->getName(), 200, "Success", encodedOptions);
+//     face->onReceiveData +=
+//       bind(&FibManagerFixture::validateControlResponse, this, _1,
+//            command->getName(), 200, "Success", encodedOptions);
 
-    getFibManager().onFibRequest(*command);
-  }
+//     getFibManager().onFibRequest(*command);
+//   }
 
-  BOOST_REQUIRE(didCallbackFire());
+//   BOOST_REQUIRE(didCallbackFire());
 
-  shared_ptr<fib::Entry> entry = getFib().findExactMatch("/hello");
-  if (static_cast<bool>(entry))
-    {
-      const fib::NextHopList& hops = entry->getNextHops();
-      BOOST_CHECK_EQUAL(hops.size(), 0);
-    }
+//   shared_ptr<fib::Entry> entry = getFib().findExactMatch("/hello");
+//   if (static_cast<bool>(entry))
+//     {
+//       const fib::NextHopList& hops = entry->getNextHops();
+//       BOOST_CHECK_EQUAL(hops.size(), 1);
+//     }
 
-  resetCallbackFired();
-  face->onReceiveData.clear();
+//   resetCallbackFired();
+//   face->onReceiveData.clear();
 
-  {
-    FibManagementOptions options;
-    options.setName("/hello");
+//   {
+//     FibManagementOptions options;
+//     options.setName("/hello");
+//     options.setFaceId(2);
+//     options.setCost(102);
 
-    Block encodedOptions(options.wireEncode());
+//     Block encodedOptions(options.wireEncode());
 
-    Name commandName("/localhost/nfd/fib");
-    commandName.append("insert");
-    commandName.append(encodedOptions);
+//     Name commandName("/localhost/nfd/fib");
+//     commandName.append("add-nexthop");
+//     commandName.append(encodedOptions);
 
-    shared_ptr<Interest> command(make_shared<Interest>(commandName));
-    generateCommand(*command);
+//     shared_ptr<Interest> command(make_shared<Interest>(commandName));
+//     generateCommand(*command);
 
-    face->onReceiveData +=
-      bind(&FibManagerFixture::validateControlResponse, this, _1,
-           command->getName(), 200, "Success", encodedOptions);
+//     face->onReceiveData +=
+//       bind(&FibManagerFixture::validateControlResponse, this, _1,
+//            command->getName(), 200, "Success", encodedOptions);
 
-    getFibManager().onFibRequest(*command);
-  }
+//     getFibManager().onFibRequest(*command);
+//   }
 
-  BOOST_REQUIRE(didCallbackFire());
+//   BOOST_REQUIRE(didCallbackFire());
 
-  entry = getFib().findExactMatch("/hello");
-  if (static_cast<bool>(entry))
-    {
-      const fib::NextHopList& hops = entry->getNextHops();
-      BOOST_CHECK_EQUAL(hops.size(), 0);
-    }
+//   entry = getFib().findExactMatch("/hello");
+//   if (static_cast<bool>(entry))
+//     {
+//       const fib::NextHopList& hops = entry->getNextHops();
+//       BOOST_CHECK_EQUAL(hops.size(), 2);
+//     }
 
-}
+// }
 
-void
-testRemove(CommandFixture<FibManagerFixture>* fixture,
-           FibManager& manager,
-           Fib& fib,
-           shared_ptr<Face> face,
-           const Name& target)
-{
-  FibManagementOptions options;
-  options.setName(target);
+// void
+// testRemove(CommandFixture<FibManagerFixture>* fixture,
+//            FibManager& manager,
+//            Fib& fib,
+//            shared_ptr<Face> face,
+//            const Name& target)
+// {
+//   FibManagementOptions options;
+//   options.setName(target);
 
-  Block encodedOptions(options.wireEncode());
+//   Block encodedOptions(options.wireEncode());
 
-  Name commandName("/localhost/nfd/fib");
-  commandName.append("delete");
-  commandName.append(encodedOptions);
+//   Name commandName("/localhost/nfd/fib");
+//   commandName.append("delete");
+//   commandName.append(encodedOptions);
 
-  shared_ptr<Interest> command(make_shared<Interest>(commandName));
-  fixture->generateCommand(*command);
+//   shared_ptr<Interest> command(make_shared<Interest>(commandName));
+//   fixture->generateCommand(*command);
 
-  face->onReceiveData +=
-    bind(&FibManagerFixture::validateControlResponse, fixture, _1,
-         command->getName(), 200, "Success", encodedOptions);
+//   face->onReceiveData +=
+//     bind(&FibManagerFixture::validateControlResponse, fixture, _1,
+//          command->getName(), 200, "Success", encodedOptions);
 
-  manager.onFibRequest(*command);
+//   manager.onFibRequest(*command);
 
-  BOOST_REQUIRE(fixture->didCallbackFire());
+//   BOOST_REQUIRE(fixture->didCallbackFire());
 
-  if (static_cast<bool>(fib.findExactMatch(target)))
-    {
-      BOOST_FAIL("Found \"removed\" prefix");
-    }
-  face->onReceiveData.clear();
-}
+//   if (static_cast<bool>(fib.findExactMatch(target)))
+//     {
+//       BOOST_FAIL("Found \"removed\" prefix");
+//     }
+//   face->onReceiveData.clear();
+// }
 
-BOOST_AUTO_TEST_CASE(Delete)
-{
-  shared_ptr<InternalFace> face = getInternalFace();
-  FibManager& manager = getFibManager();
-  Fib& fib = getFib();
+// BOOST_AUTO_TEST_CASE(Delete)
+// {
+//   shared_ptr<InternalFace> face = getInternalFace();
+//   FibManager& manager = getFibManager();
+//   Fib& fib = getFib();
 
-  fib.insert("/a");
-  fib.insert("/a/b");
-  fib.insert("/a/b/c");
+//   fib.insert("/a");
+//   fib.insert("/a/b");
+//   fib.insert("/a/b/c");
 
-  testRemove(this, manager, fib, face, "/");
+//   testRemove(this, manager, fib, face, "/");
 
-  if (!static_cast<bool>(fib.findExactMatch("/a")) ||
-      !static_cast<bool>(fib.findExactMatch("/a/b")) ||
-      !static_cast<bool>(fib.findExactMatch("/a/b/c")))
-    {
-      BOOST_FAIL("Removed incorrect entry");
-    }
+//   if (!static_cast<bool>(fib.findExactMatch("/a")) ||
+//       !static_cast<bool>(fib.findExactMatch("/a/b")) ||
+//       !static_cast<bool>(fib.findExactMatch("/a/b/c")))
+//     {
+//       BOOST_FAIL("Removed incorrect entry");
+//     }
 
-  testRemove(this, manager, fib, face, "/a/b");
+//   testRemove(this, manager, fib, face, "/a/b");
 
-  if (!static_cast<bool>(fib.findExactMatch("/a")) ||
-      !static_cast<bool>(fib.findExactMatch("/a/b/c")))
-    {
-      BOOST_FAIL("Removed incorrect entry");
-    }
+//   if (!static_cast<bool>(fib.findExactMatch("/a")) ||
+//       !static_cast<bool>(fib.findExactMatch("/a/b/c")))
+//     {
+//       BOOST_FAIL("Removed incorrect entry");
+//     }
 
-  testRemove(this, manager, fib, face, "/a/b/c");
+//   testRemove(this, manager, fib, face, "/a/b/c");
 
-  if (!static_cast<bool>(fib.findExactMatch("/a")))
-    {
-      BOOST_FAIL("Removed incorrect entry");
-    }
+//   if (!static_cast<bool>(fib.findExactMatch("/a")))
+//     {
+//       BOOST_FAIL("Removed incorrect entry");
+//     }
 
-  testRemove(this, manager, fib, face, "/a");
+//   testRemove(this, manager, fib, face, "/a");
 
-  testRemove(this, manager, fib, face, "/does/not/exist");
-}
+//   testRemove(this, manager, fib, face, "/does/not/exist");
+// }
 
 bool
 removedNextHopWithCost(const Fib& fib, const Name& prefix, size_t oldSize, uint32_t cost)
@@ -804,13 +802,9 @@
   BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 2, 303));
 
   testRemoveNextHop(this, manager, fib, face, "/hello", 1);
-  BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 1, 101));
+  // BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 1, 101));
 
-  if (!static_cast<bool>(getFib().findExactMatch("/hello")))
-    {
-      BOOST_FAIL("removed entry after removing all next hops");
-    }
-
+  BOOST_CHECK(!static_cast<bool>(getFib().findExactMatch("/hello")));
 }
 
 BOOST_AUTO_TEST_CASE(RemoveNoFace)