tools: refactor nfd-status

refs #3658

Change-Id: Ia347074bea802eba5f539208e276e849a60db8a4
diff --git a/tools/nfd-status/channel-module.cpp b/tools/nfd-status/channel-module.cpp
new file mode 100644
index 0000000..4cd5484
--- /dev/null
+++ b/tools/nfd-status/channel-module.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "channel-module.hpp"
+#include "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+void
+ChannelModule::fetchStatus(Controller& controller,
+                           const function<void()>& onSuccess,
+                           const Controller::CommandFailCallback& onFailure,
+                           const CommandOptions& options)
+{
+  controller.fetch<ndn::nfd::ChannelDataset>(
+    [this, onSuccess] (const std::vector<ChannelStatus>& result) {
+      m_status = result;
+      onSuccess();
+    },
+    onFailure, options);
+}
+
+void
+ChannelModule::formatStatusXml(std::ostream& os) const
+{
+  os << "<channels>";
+  for (const ChannelStatus& item : m_status) {
+    this->formatItemXml(os, item);
+  }
+  os << "</channels>";
+}
+
+void
+ChannelModule::formatItemXml(std::ostream& os, const ChannelStatus& item) const
+{
+  os << "<channel>";
+  os << "<localUri>" << xml::Text{item.getLocalUri()} << "</localUri>";
+  os << "</channel>";
+}
+
+void
+ChannelModule::formatStatusText(std::ostream& os) const
+{
+  os << "Channels:\n";
+  for (const ChannelStatus& item : m_status) {
+    this->formatItemText(os, item);
+  }
+}
+
+void
+ChannelModule::formatItemText(std::ostream& os, const ChannelStatus& item) const
+{
+  os << "  " << item.getLocalUri();
+  os << "\n";
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/channel-module.hpp b/tools/nfd-status/channel-module.hpp
new file mode 100644
index 0000000..1230554
--- /dev/null
+++ b/tools/nfd-status/channel-module.hpp
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_CHANNEL_MODULE_HPP
+#define NFD_TOOLS_NFD_STATUS_CHANNEL_MODULE_HPP
+
+#include "module.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::nfd::ChannelStatus;
+
+/** \brief provides access to NFD channel dataset
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Channel-Dataset
+ */
+class ChannelModule : public Module, noncopyable
+{
+public:
+  virtual void
+  fetchStatus(Controller& controller,
+              const function<void()>& onSuccess,
+              const Controller::CommandFailCallback& onFailure,
+              const CommandOptions& options) override;
+
+  virtual void
+  formatStatusXml(std::ostream& os) const override;
+
+  /** \brief format a single status item as XML
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemXml(std::ostream& os, const ChannelStatus& item) const;
+
+  virtual void
+  formatStatusText(std::ostream& os) const override;
+
+  /** \brief format a single status item as text
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemText(std::ostream& os, const ChannelStatus& item) const;
+
+private:
+  std::vector<ChannelStatus> m_status;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_CHANNEL_MODULE_HPP
diff --git a/tools/nfd-status/face-module.cpp b/tools/nfd-status/face-module.cpp
new file mode 100644
index 0000000..3ec0467
--- /dev/null
+++ b/tools/nfd-status/face-module.cpp
@@ -0,0 +1,154 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+/** \todo
+ *  #2542 plans to merge nfd-status with nfdc.
+ *  FaceModule class should be changed as follows:
+ *  (1) move into ndn::nfd::nfdc namespace
+ *  (2) assuming command syntax is similar to Windows NT \p netsh ,
+ *      this class can handle command argument parsing as soon as
+ *      'face' sub-command is detected
+ *  (3) introduce methods to create and destroy faces, and update face attributes
+ *
+ *  \todo
+ *  #3444 aims at improving output texts of nfdc.
+ *  Assuming it's worked with or after #2542:
+ *  (1) introduce an \p style parameter on formatItemText method to specify desired text style,
+ *      such as human friendly style vs. porcelain style for script consumption
+ *  (2) upon successful command execute, convert the command result into FaceStatus type,
+ *      and use formatItemText to render the result, so that output from status retrieval
+ *      and command execution have consistent styles
+ *  }
+ */
+
+#include "face-module.hpp"
+#include "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+void
+FaceModule::fetchStatus(Controller& controller,
+                        const function<void()>& onSuccess,
+                        const Controller::CommandFailCallback& onFailure,
+                        const CommandOptions& options)
+{
+  controller.fetch<ndn::nfd::FaceDataset>(
+    [this, onSuccess] (const std::vector<FaceStatus>& result) {
+      m_status = result;
+      onSuccess();
+    },
+    onFailure, options);
+}
+
+void
+FaceModule::formatStatusXml(std::ostream& os) const
+{
+  os << "<faces>";
+  for (const FaceStatus& item : m_status) {
+    this->formatItemXml(os, item);
+  }
+  os << "</faces>";
+}
+
+void
+FaceModule::formatItemXml(std::ostream& os, const FaceStatus& item) const
+{
+  os << "<face>";
+
+  os << "<faceId>" << item.getFaceId() << "</faceId>";
+  os << "<remoteUri>" << xml::Text{item.getRemoteUri()} << "</remoteUri>";
+  os << "<localUri>" << xml::Text{item.getLocalUri()} << "</localUri>";
+
+  if (item.hasExpirationPeriod()) {
+    os << "<expirationPeriod>" << xml::formatDuration(item.getExpirationPeriod())
+       << "</expirationPeriod>";
+  }
+  os << "<faceScope>" << item.getFaceScope() << "</faceScope>";
+  os << "<facePersistency>" << item.getFacePersistency() << "</facePersistency>";
+  os << "<linkType>" << item.getLinkType() << "</linkType>";
+
+  os << "<packetCounters>";
+  os << "<incomingPackets>"
+     << "<nInterests>" << item.getNInInterests() << "</nInterests>"
+     << "<nDatas>" << item.getNInDatas() << "</nDatas>"
+     << "<nNacks>" << item.getNInNacks() << "</nNacks>"
+     << "</incomingPackets>";
+  os << "<outgoingPackets>"
+     << "<nInterests>" << item.getNOutInterests() << "</nInterests>"
+     << "<nDatas>" << item.getNOutDatas() << "</nDatas>"
+     << "<nNacks>" << item.getNOutNacks() << "</nNacks>"
+     << "</outgoingPackets>";
+  os << "</packetCounters>";
+
+  os << "<byteCounters>";
+  os << "<incomingBytes>" << item.getNInBytes() << "</incomingBytes>";
+  os << "<outgoingBytes>" << item.getNOutBytes() << "</outgoingBytes>";
+  os << "</byteCounters>";
+
+  os << "</face>";
+}
+
+void
+FaceModule::formatStatusText(std::ostream& os) const
+{
+  os << "Faces:\n";
+  for (const FaceStatus& item : m_status) {
+    this->formatItemText(os, item);
+  }
+}
+
+void
+FaceModule::formatItemText(std::ostream& os, const FaceStatus& item) const
+{
+  os << "  faceid=" << item.getFaceId();
+  os << " remote=" << item.getRemoteUri();
+  os << " local=" << item.getLocalUri();
+
+  if (item.hasExpirationPeriod()) {
+    os << " expires=" << text::formatDuration(item.getExpirationPeriod());
+  }
+
+  os << " counters={in={"
+     << item.getNInInterests() << "i "
+     << item.getNInDatas() << "d "
+     << item.getNInNacks() << "n "
+     << item.getNInBytes() << "B} ";
+  os << "out={"
+     << item.getNOutInterests() << "i "
+     << item.getNOutDatas() << "d "
+     << item.getNOutNacks() << "n "
+     << item.getNOutBytes() << "B}}";
+
+  os << " " << item.getFaceScope();
+  os << " " << item.getFacePersistency();
+  os << " " << item.getLinkType();
+  os << "\n";
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/face-module.hpp b/tools/nfd-status/face-module.hpp
new file mode 100644
index 0000000..58bb5ee
--- /dev/null
+++ b/tools/nfd-status/face-module.hpp
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_FACE_MODULE_HPP
+#define NFD_TOOLS_NFD_STATUS_FACE_MODULE_HPP
+
+#include "module.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::nfd::FaceStatus;
+
+/** \brief provides access to NFD face management
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/FaceMgmt
+ */
+class FaceModule : public Module, noncopyable
+{
+public:
+  virtual void
+  fetchStatus(Controller& controller,
+              const function<void()>& onSuccess,
+              const Controller::CommandFailCallback& onFailure,
+              const CommandOptions& options) override;
+
+  virtual void
+  formatStatusXml(std::ostream& os) const override;
+
+  /** \brief format a single status item as XML
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemXml(std::ostream& os, const FaceStatus& item) const;
+
+  virtual void
+  formatStatusText(std::ostream& os) const override;
+
+  /** \brief format a single status item as text
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemText(std::ostream& os, const FaceStatus& item) const;
+
+private:
+  std::vector<FaceStatus> m_status;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_FACE_MODULE_HPP
diff --git a/tools/nfd-status/fib-module.cpp b/tools/nfd-status/fib-module.cpp
new file mode 100644
index 0000000..a1c7f94
--- /dev/null
+++ b/tools/nfd-status/fib-module.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "fib-module.hpp"
+#include "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+void
+FibModule::fetchStatus(Controller& controller,
+                       const function<void()>& onSuccess,
+                       const Controller::CommandFailCallback& onFailure,
+                       const CommandOptions& options)
+{
+  controller.fetch<ndn::nfd::FibDataset>(
+    [this, onSuccess] (const std::vector<FibEntry>& result) {
+      m_status = result;
+      onSuccess();
+    },
+    onFailure, options);
+}
+
+void
+FibModule::formatStatusXml(std::ostream& os) const
+{
+  os << "<fib>";
+  for (const FibEntry& item : m_status) {
+    this->formatItemXml(os, item);
+  }
+  os << "</fib>";
+}
+
+void
+FibModule::formatItemXml(std::ostream& os, const FibEntry& item) const
+{
+  os << "<fibEntry>";
+
+  os << "<prefix>" << xml::Text{item.getPrefix().toUri()} << "</prefix>";
+
+  os << "<nextHops>";
+  for (const NextHopRecord& nh : item.getNextHopRecords()) {
+    os << "<nextHop>"
+       << "<faceId>" << nh.getFaceId() << "</faceId>"
+       << "<cost>" << nh.getCost() << "</cost>"
+       << "</nextHop>";
+  }
+  os << "</nextHops>";
+
+  os << "</fibEntry>";
+}
+
+void
+FibModule::formatStatusText(std::ostream& os) const
+{
+  os << "FIB:\n";
+  for (const FibEntry& item : m_status) {
+    this->formatItemText(os, item);
+  }
+}
+
+void
+FibModule::formatItemText(std::ostream& os, const FibEntry& item) const
+{
+  os << "  " << item.getPrefix() << " nexthops={";
+
+  text::Separator sep(", ");
+  for (const NextHopRecord& nh : item.getNextHopRecords()) {
+    os << sep
+       << "faceid=" << nh.getFaceId()
+       << " (cost=" << nh.getCost() << ")";
+  }
+
+  os << "}";
+  os << "\n";
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/fib-module.hpp b/tools/nfd-status/fib-module.hpp
new file mode 100644
index 0000000..353e594
--- /dev/null
+++ b/tools/nfd-status/fib-module.hpp
@@ -0,0 +1,78 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_FIB_MODULE_HPP
+#define NFD_TOOLS_NFD_STATUS_FIB_MODULE_HPP
+
+#include "module.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::nfd::FibEntry;
+using ndn::nfd::NextHopRecord;
+
+/** \brief provides access to NFD FIB management
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/FibMgmt
+ */
+class FibModule : public Module, noncopyable
+{
+public:
+  virtual void
+  fetchStatus(Controller& controller,
+              const function<void()>& onSuccess,
+              const Controller::CommandFailCallback& onFailure,
+              const CommandOptions& options) override;
+
+  virtual void
+  formatStatusXml(std::ostream& os) const override;
+
+  /** \brief format a single status item as XML
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemXml(std::ostream& os, const FibEntry& item) const;
+
+  virtual void
+  formatStatusText(std::ostream& os) const override;
+
+  /** \brief format a single status item as text
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemText(std::ostream& os, const FibEntry& item) const;
+
+private:
+  std::vector<FibEntry> m_status;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_FIB_MODULE_HPP
diff --git a/tools/nfd-status/format-helpers.cpp b/tools/nfd-status/format-helpers.cpp
new file mode 100644
index 0000000..c7e595b
--- /dev/null
+++ b/tools/nfd-status/format-helpers.cpp
@@ -0,0 +1,128 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+namespace xml {
+
+void
+printHeader(std::ostream& os)
+{
+  os << "<?xml version=\"1.0\"?>"
+     << "<nfdStatus xmlns=\"ndn:/localhost/nfd/status/1\">";
+}
+
+void
+printFooter(std::ostream& os)
+{
+  os << "</nfdStatus>";
+}
+
+std::ostream&
+operator<<(std::ostream& os, const Text& text)
+{
+  for (char ch : text.s) {
+    switch (ch) {
+      case '"':
+        os << "&quot;";
+        break;
+      case '&':
+        os << "&amp;";
+        break;
+      case '\'':
+        os << "&apos;";
+        break;
+      case '<':
+        os << "&lt;";
+        break;
+      case '>':
+        os << "&gt;";
+        break;
+      default:
+        os << ch;
+        break;
+    }
+  }
+  return os;
+}
+
+std::string
+formatSeconds(time::seconds d)
+{
+  return "PT" + to_string(d.count()) + "S";
+}
+
+std::string
+formatTimestamp(time::system_clock::TimePoint t)
+{
+  return time::toString(t, "%Y-%m-%dT%H:%M:%S%F");
+}
+
+} // namespace xml
+
+namespace text {
+
+Separator::Separator(const std::string& first, const std::string& subsequent)
+  : m_first(first)
+  , m_subsequent(subsequent)
+  , m_count(0)
+{
+}
+
+Separator::Separator(const std::string& subsequent)
+  : Separator("", subsequent)
+{
+}
+
+std::ostream&
+operator<<(std::ostream& os, Separator& sep)
+{
+  if (++sep.m_count == 1) {
+    return os << sep.m_first;
+  }
+  return os << sep.m_subsequent;
+}
+
+std::string
+formatSeconds(time::seconds d, bool isLong)
+{
+  return to_string(d.count()) + (isLong ? " seconds" : "s");
+}
+
+std::string
+formatTimestamp(time::system_clock::TimePoint t)
+{
+  return time::toIsoString(t);
+}
+
+} // namespace text
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/format-helpers.hpp b/tools/nfd-status/format-helpers.hpp
new file mode 100644
index 0000000..11d3d5a
--- /dev/null
+++ b/tools/nfd-status/format-helpers.hpp
@@ -0,0 +1,118 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_FORMAT_HELPERS_HPP
+#define NFD_TOOLS_NFD_STATUS_FORMAT_HELPERS_HPP
+
+#include "common.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+namespace xml {
+
+void
+printHeader(std::ostream& os);
+
+void
+printFooter(std::ostream& os);
+
+struct Text
+{
+  const std::string& s;
+};
+
+/** \brief print XML text with special character represented as predefined entities
+ */
+std::ostream&
+operator<<(std::ostream& os, const Text& text);
+
+std::string
+formatSeconds(time::seconds d);
+
+template<typename DURATION>
+std::string
+formatDuration(DURATION d)
+{
+  return formatSeconds(time::duration_cast<time::seconds>(d));
+}
+
+std::string
+formatTimestamp(time::system_clock::TimePoint t);
+
+} // namespace xml
+
+namespace text {
+
+/** \brief print different string on first and subsequent usage
+ *
+ *  \code
+ *  Separator sep(",");
+ *  for (int i = 1; i <= 3; ++i) {
+ *    os << sep << i;
+ *  }
+ *  // prints: 1,2,3
+ *  \endcode
+ */
+class Separator
+{
+public:
+  Separator(const std::string& first, const std::string& subsequent);
+
+  explicit
+  Separator(const std::string& subsequent);
+
+private:
+  std::string m_first;
+  std::string m_subsequent;
+  int m_count;
+
+  friend std::ostream& operator<<(std::ostream& os, Separator& sep);
+};
+
+std::ostream&
+operator<<(std::ostream& os, Separator& sep);
+
+std::string
+formatSeconds(time::seconds d, bool isLong = false);
+
+template<typename DURATION>
+std::string
+formatDuration(DURATION d, bool isLong = false)
+{
+  return formatSeconds(time::duration_cast<time::seconds>(d), isLong);
+}
+
+std::string
+formatTimestamp(time::system_clock::TimePoint t);
+
+} // namespace text
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_FORMAT_HELPERS_HPP
diff --git a/tools/nfd-status/forwarder-general-module.cpp b/tools/nfd-status/forwarder-general-module.cpp
new file mode 100644
index 0000000..41b715a
--- /dev/null
+++ b/tools/nfd-status/forwarder-general-module.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "forwarder-general-module.hpp"
+#include "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+ForwarderGeneralModule::ForwarderGeneralModule()
+  : m_nfdIdCollector(nullptr)
+{
+}
+
+void
+ForwarderGeneralModule::fetchStatus(Controller& controller,
+                                    const function<void()>& onSuccess,
+                                    const Controller::CommandFailCallback& onFailure,
+                                    const CommandOptions& options)
+{
+  controller.fetch<ndn::nfd::ForwarderGeneralStatusDataset>(
+    [this, onSuccess] (const ForwarderStatus& result) {
+      m_status = result;
+      onSuccess();
+    },
+    onFailure, options);
+}
+
+static time::system_clock::Duration
+calculateUptime(const ForwarderStatus& status)
+{
+  return status.getCurrentTimestamp() - status.getStartTimestamp();
+}
+
+const Name&
+ForwarderGeneralModule::getNfdId() const
+{
+  if (m_nfdIdCollector != nullptr && m_nfdIdCollector->hasNfdId()) {
+    return m_nfdIdCollector->getNfdId();
+  }
+
+  static Name unavailable("/nfdId-unavailable");
+  return unavailable;
+}
+
+void
+ForwarderGeneralModule::formatStatusXml(std::ostream& os) const
+{
+  this->formatItemXml(os, m_status, this->getNfdId());
+}
+
+void
+ForwarderGeneralModule::formatItemXml(std::ostream& os, const ForwarderStatus& item,
+                                      const Name& nfdId) const
+{
+  os << "<generalStatus>";
+
+  os << "<nfdId>" << nfdId << "</nfdId>";
+  os << "<version>" << xml::Text{item.getNfdVersion()} << "</version>";
+  os << "<startTime>" << xml::formatTimestamp(item.getStartTimestamp()) << "</startTime>";
+  os << "<currentTime>" << xml::formatTimestamp(item.getCurrentTimestamp()) << "</currentTime>";
+  os << "<uptime>" << xml::formatDuration(calculateUptime(item)) << "</uptime>";
+
+  os << "<nNameTreeEntries>" << item.getNNameTreeEntries() << "</nNameTreeEntries>";
+  os << "<nFibEntries>" << item.getNFibEntries() << "</nFibEntries>";
+  os << "<nPitEntries>" << item.getNPitEntries() << "</nPitEntries>";
+  os << "<nMeasurementsEntries>" << item.getNMeasurementsEntries() << "</nMeasurementsEntries>";
+  os << "<nCsEntries>" << item.getNCsEntries() << "</nCsEntries>";
+
+  os << "<packetCounters>";
+  os << "<incomingPackets>"
+     << "<nInterests>" << item.getNInInterests() << "</nInterests>"
+     << "<nDatas>" << item.getNInDatas() << "</nDatas>"
+     << "<nNacks>" << item.getNInNacks() << "</nNacks>"
+     << "</incomingPackets>";
+  os << "<outgoingPackets>"
+     << "<nInterests>" << item.getNOutInterests() << "</nInterests>"
+     << "<nDatas>" << item.getNOutDatas() << "</nDatas>"
+     << "<nNacks>" << item.getNOutNacks() << "</nNacks>"
+     << "</outgoingPackets>";
+  os << "</packetCounters>";
+
+  os << "</generalStatus>";
+}
+
+void
+ForwarderGeneralModule::formatStatusText(std::ostream& os) const
+{
+  os << "General NFD status:\n";
+  this->formatItemText(os, m_status, this->getNfdId());
+}
+
+void
+ForwarderGeneralModule::formatItemText(std::ostream& os, const ForwarderStatus& item,
+                                       const Name& nfdId) const
+{
+  os << "                 nfdId=" << nfdId << "\n";
+  os << "               version=" << item.getNfdVersion() << "\n";
+  os << "             startTime=" << text::formatTimestamp(item.getStartTimestamp()) << "\n";
+  os << "           currentTime=" << text::formatTimestamp(item.getCurrentTimestamp()) << "\n";
+  os << "                uptime=" << text::formatDuration(calculateUptime(item), true) << "\n";
+
+  os << "      nNameTreeEntries=" << item.getNNameTreeEntries() << "\n";
+  os << "           nFibEntries=" << item.getNFibEntries() << "\n";
+  os << "           nPitEntries=" << item.getNPitEntries() << "\n";
+  os << "  nMeasurementsEntries=" << item.getNMeasurementsEntries() << "\n";
+  os << "            nCsEntries=" << item.getNCsEntries() << "\n";
+
+  os << "          nInInterests=" << item.getNInInterests() << "\n";
+  os << "         nOutInterests=" << item.getNOutInterests() << "\n";
+  os << "              nInDatas=" << item.getNInDatas() << "\n";
+  os << "             nOutDatas=" << item.getNOutDatas() << "\n";
+  os << "              nInNacks=" << item.getNInNacks() << "\n";
+  os << "             nOutNacks=" << item.getNOutNacks() << "\n";
+}
+
+NfdIdCollector::NfdIdCollector(unique_ptr<ndn::Validator> inner)
+  : m_inner(std::move(inner))
+  , m_hasNfdId(false)
+{
+  BOOST_ASSERT(m_inner != nullptr);
+}
+
+const Name&
+NfdIdCollector::getNfdId() const
+{
+  if (!m_hasNfdId) {
+    BOOST_THROW_EXCEPTION(std::runtime_error("NfdId is unavailable"));
+  }
+
+  return m_nfdId;
+}
+
+void
+NfdIdCollector::checkPolicy(const Data& data, int nSteps,
+                            const ndn::OnDataValidated& accept,
+                            const ndn::OnDataValidationFailed& reject,
+                            std::vector<shared_ptr<ndn::ValidationRequest>>& nextSteps)
+{
+  ndn::OnDataValidated accepted = [this, accept] (const shared_ptr<const Data>& data) {
+    accept(data); // pass the Data to Validator user's validated callback
+
+    if (m_hasNfdId) {
+      return;
+    }
+
+    const ndn::Signature& sig = data->getSignature();
+    if (!sig.hasKeyLocator()) {
+      return;
+    }
+
+    const ndn::KeyLocator& kl = sig.getKeyLocator();
+    if (kl.getType() != ndn::KeyLocator::KeyLocator_Name) {
+      return;
+    }
+
+    m_nfdId = kl.getName();
+    m_hasNfdId = true;
+  };
+
+  BOOST_ASSERT(nSteps == 0);
+  m_inner->validate(data, accepted, reject);
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/forwarder-general-module.hpp b/tools/nfd-status/forwarder-general-module.hpp
new file mode 100644
index 0000000..a55bc21
--- /dev/null
+++ b/tools/nfd-status/forwarder-general-module.hpp
@@ -0,0 +1,140 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_FORWARDER_GENERAL_MODULE_HPP
+#define NFD_TOOLS_NFD_STATUS_FORWARDER_GENERAL_MODULE_HPP
+
+#include "module.hpp"
+#include <ndn-cxx/security/validator.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::nfd::ForwarderStatus;
+
+class NfdIdCollector;
+
+/** \brief provides access to NFD forwarder general status
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus
+ */
+class ForwarderGeneralModule : public Module, noncopyable
+{
+public:
+  ForwarderGeneralModule();
+
+  virtual void
+  fetchStatus(Controller& controller,
+              const function<void()>& onSuccess,
+              const Controller::CommandFailCallback& onFailure,
+              const CommandOptions& options) override;
+
+  void
+  setNfdIdCollector(const NfdIdCollector& nfdIdCollector)
+  {
+    m_nfdIdCollector = &nfdIdCollector;
+  }
+
+  virtual void
+  formatStatusXml(std::ostream& os) const override;
+
+  /** \brief format a single status item as XML
+   *  \param os output stream
+   *  \param item status item
+   *  \param nfdId NFD's signing certificate name
+   */
+  void
+  formatItemXml(std::ostream& os, const ForwarderStatus& item, const Name& nfdId) const;
+
+  virtual void
+  formatStatusText(std::ostream& os) const override;
+
+  /** \brief format a single status item as text
+   *  \param os output stream
+   *  \param item status item
+   *  \param nfdId NFD's signing certificate name
+   */
+  void
+  formatItemText(std::ostream& os, const ForwarderStatus& item, const Name& nfdId) const;
+
+private:
+  const Name&
+  getNfdId() const;
+
+private:
+  const NfdIdCollector* m_nfdIdCollector;
+  ForwarderStatus m_status;
+};
+
+
+/** \brief a validator that can collect NFD's signing certificate name
+ *
+ *  This validator redirects all validation requests to an inner validator.
+ *  For the first Data packet accepted by the inner validator that has a Name in KeyLocator,
+ *  this Name is collected as NFD's signing certificate name.
+ */
+class NfdIdCollector : public ndn::Validator
+{
+public:
+  explicit
+  NfdIdCollector(unique_ptr<ndn::Validator> inner);
+
+  bool
+  hasNfdId() const
+  {
+    return m_hasNfdId;
+  }
+
+  const Name&
+  getNfdId() const;
+
+protected:
+  virtual void
+  checkPolicy(const Interest& interest, int nSteps,
+              const ndn::OnInterestValidated& accept,
+              const ndn::OnInterestValidationFailed& reject,
+              std::vector<shared_ptr<ndn::ValidationRequest>>& nextSteps) override
+  {
+    BOOST_ASSERT(nSteps == 0);
+    m_inner->validate(interest, accept, reject);
+  }
+
+  virtual void
+  checkPolicy(const Data& data, int nSteps,
+              const ndn::OnDataValidated& accept,
+              const ndn::OnDataValidationFailed& reject,
+              std::vector<shared_ptr<ndn::ValidationRequest>>& nextSteps) override;
+
+private:
+  unique_ptr<ndn::Validator> m_inner;
+  bool m_hasNfdId;
+  Name m_nfdId;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_FORWARDER_GENERAL_MODULE_HPP
diff --git a/tools/nfd-status/main.cpp b/tools/nfd-status/main.cpp
new file mode 100644
index 0000000..a3033a6
--- /dev/null
+++ b/tools/nfd-status/main.cpp
@@ -0,0 +1,199 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "version.hpp"
+#include <ndn-cxx/security/validator-null.hpp>
+
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/program_options/parsers.hpp>
+
+#include "status-report.hpp"
+#include "forwarder-general-module.hpp"
+#include "channel-module.hpp"
+#include "face-module.hpp"
+#include "fib-module.hpp"
+#include "rib-module.hpp"
+#include "strategy-choice-module.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+enum class OutputFormat
+{
+  XML = 1,
+  TEXT = 2
+};
+
+struct Options
+{
+  OutputFormat output = OutputFormat::TEXT;
+  bool wantForwarderGeneral = false;
+  bool wantChannels = false;
+  bool wantFaces = false;
+  bool wantFib = false;
+  bool wantRib = false;
+  bool wantStrategyChoice = false;
+};
+
+static void
+showUsage(std::ostream& os, const boost::program_options::options_description& cmdOptions)
+{
+  os << "Usage: nfd-status [options]\n\n"
+     << "Show NFD version and status information.\n\n"
+     << cmdOptions;
+}
+
+/** \brief parse command line, and show usage if necessary
+ *  \return if first item is -1, caller should retrieve and display StatusReport;
+ *          otherwise, caller should immediately exit with the specified exit code
+ */
+static std::tuple<int, Options>
+parseCommandLine(int argc, const char* const* argv)
+{
+  Options options;
+
+  namespace po = boost::program_options;
+  po::options_description cmdOptions("Options");
+  cmdOptions.add_options()
+    ("help,h", "print this help message")
+    ("version,V", "show program version")
+    ("general,v", po::bool_switch(&options.wantForwarderGeneral), "show general status")
+    ("channels,c", po::bool_switch(&options.wantChannels), "show channels")
+    ("faces,f", po::bool_switch(&options.wantFaces), "show faces")
+    ("fib,b", po::bool_switch(&options.wantFib), "show FIB entries")
+    ("rib,r", po::bool_switch(&options.wantRib), "show RIB routes")
+    ("sc,s", po::bool_switch(&options.wantStrategyChoice), "show strategy choice entries")
+    ("xml,x", "output as XML instead of text (implies -vcfbrs)");
+  po::variables_map vm;
+  try {
+    po::store(po::parse_command_line(argc, argv, cmdOptions), vm);
+  }
+  catch (const po::error& e) {
+    std::cerr << e.what() << "\n";
+    showUsage(std::cerr, cmdOptions);
+    return std::make_tuple(2, options);
+  }
+  po::notify(vm);
+
+  if (vm.count("help") > 0) {
+    showUsage(std::cout, cmdOptions);
+    return std::make_tuple(0, options);
+  }
+  if (vm.count("version") > 0) {
+    std::cout << "nfd-status " << NFD_VERSION_BUILD_STRING << "\n";
+    return std::make_tuple(0, options);
+  }
+
+  if (vm.count("xml") > 0) {
+    options.output = OutputFormat::XML;
+  }
+  if (options.output == OutputFormat::XML ||
+      (!options.wantForwarderGeneral && !options.wantChannels && !options.wantFaces &&
+       !options.wantFib && !options.wantRib && !options.wantStrategyChoice)) {
+    options.wantForwarderGeneral = options.wantChannels = options.wantFaces =
+      options.wantFib = options.wantRib = options.wantStrategyChoice = true;
+  }
+
+  return std::make_tuple(-1, options);
+}
+
+static int
+main(int argc, char** argv)
+{
+  int exitCode = -1;
+  Options options;
+  std::tie(exitCode, options) = parseCommandLine(argc, argv);
+  if (exitCode >= 0) {
+    return exitCode;
+  }
+
+  Face face;
+  KeyChain keyChain;
+  unique_ptr<Validator> validator = make_unique<ndn::ValidatorNull>();
+  CommandOptions ctrlOptions;
+
+  StatusReport report;
+
+  if (options.wantForwarderGeneral) {
+    auto nfdIdCollector = make_unique<NfdIdCollector>(std::move(validator));
+    auto forwarderGeneralModule = make_unique<ForwarderGeneralModule>();
+    forwarderGeneralModule->setNfdIdCollector(*nfdIdCollector);
+    report.sections.push_back(std::move(forwarderGeneralModule));
+    validator = std::move(nfdIdCollector);
+  }
+
+  if (options.wantChannels) {
+    report.sections.push_back(make_unique<ChannelModule>());
+  }
+
+  if (options.wantFaces) {
+    report.sections.push_back(make_unique<FaceModule>());
+  }
+
+  if (options.wantFib) {
+    report.sections.push_back(make_unique<FibModule>());
+  }
+
+  if (options.wantRib) {
+    report.sections.push_back(make_unique<RibModule>());
+  }
+
+  if (options.wantStrategyChoice) {
+    report.sections.push_back(make_unique<StrategyChoiceModule>());
+  }
+
+  uint32_t code = report.collect(face, keyChain, *validator, ctrlOptions);
+  if (code != 0) {
+    // Give a simple error code for end user.
+    // Technical support personnel:
+    // 1. get the exact command from end user
+    // 2. code div 1000000 is zero-based section index
+    // 3. code mod 1000000 is a Controller.fetch error code
+    std::cerr << "Error while collecting status report (" << code << ").\n";
+    return 1;
+  }
+
+  switch (options.output) {
+    case OutputFormat::XML:
+      report.formatXml(std::cout);
+      break;
+    case OutputFormat::TEXT:
+      report.formatText(std::cout);
+      break;
+  }
+  return 0;
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+int
+main(int argc, char** argv)
+{
+  return nfd::tools::nfd_status::main(argc, argv);
+}
diff --git a/tools/nfd-status/module.hpp b/tools/nfd-status/module.hpp
new file mode 100644
index 0000000..07d5647
--- /dev/null
+++ b/tools/nfd-status/module.hpp
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_MODULE_HPP
+#define NFD_TOOLS_NFD_STATUS_MODULE_HPP
+
+#include "common.hpp"
+#include <ndn-cxx/management/nfd-controller.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::nfd::Controller;
+using ndn::nfd::CommandOptions;
+
+/** \brief provides access to an NFD management module
+ *  \note This type is an interface. It should not have member fields.
+ */
+class Module
+{
+public:
+  virtual
+  ~Module() = default;
+
+  /** \brief collect status from NFD
+   *  \pre no other fetchStatus is in progress
+   *  \param controller a controller through which StatusDataset can be requested
+   *  \param onSuccess invoked when status has been collected into this instance
+   *  \param onFailure passed to controller.fetch
+   *  \param options passed to controller.fetch
+   */
+  virtual void
+  fetchStatus(Controller& controller,
+              const function<void()>& onSuccess,
+              const Controller::CommandFailCallback& onFailure,
+              const CommandOptions& options) = 0;
+
+  /** \brief format collected status as XML
+   *  \pre fetchStatus has been successful
+   *  \param os output stream
+   */
+  virtual void
+  formatStatusXml(std::ostream& os) const = 0;
+
+  /** \brief format collected status as text
+   *  \pre fetchStatus has been successful
+   *  \param os output stream
+   */
+  virtual void
+  formatStatusText(std::ostream& os) const = 0;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_MODULE_HPP
diff --git a/tools/nfd-status/rib-module.cpp b/tools/nfd-status/rib-module.cpp
new file mode 100644
index 0000000..fe254cc
--- /dev/null
+++ b/tools/nfd-status/rib-module.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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-module.hpp"
+#include "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+void
+RibModule::fetchStatus(Controller& controller,
+                       const function<void()>& onSuccess,
+                       const Controller::CommandFailCallback& onFailure,
+                       const CommandOptions& options)
+{
+  controller.fetch<ndn::nfd::RibDataset>(
+    [this, onSuccess] (const std::vector<RibEntry>& result) {
+      m_status = result;
+      onSuccess();
+    },
+    onFailure, options);
+}
+
+void
+RibModule::formatStatusXml(std::ostream& os) const
+{
+  os << "<rib>";
+  for (const RibEntry& item : m_status) {
+    this->formatItemXml(os, item);
+  }
+  os << "</rib>";
+}
+
+void
+RibModule::formatItemXml(std::ostream& os, const RibEntry& item) const
+{
+  os << "<ribEntry>";
+
+  os << "<prefix>" << xml::Text{item.getName().toUri()} << "</prefix>";
+
+  os << "<routes>";
+  for (const Route& route : item.getRoutes()) {
+    os << "<route>"
+       << "<faceId>" << route.getFaceId() << "</faceId>"
+       << "<origin>" << route.getOrigin() << "</origin>"
+       << "<cost>" << route.getCost() << "</cost>";
+    if (route.getFlags() == ndn::nfd::ROUTE_FLAGS_NONE) {
+       os << "<flags/>";
+    }
+    else {
+       os << "<flags>";
+      if (route.isChildInherit()) {
+        os << "<childInherit/>";
+      }
+      if (route.isRibCapture()) {
+        os << "<ribCapture/>";
+      }
+      os << "</flags>";
+    }
+    if (!route.hasInfiniteExpirationPeriod()) {
+      os << "<expirationPeriod>"
+         << xml::formatDuration(route.getExpirationPeriod())
+         << "</expirationPeriod>";
+    }
+    os << "</route>";
+  }
+  os << "</routes>";
+
+  os << "</ribEntry>";
+}
+
+void
+RibModule::formatStatusText(std::ostream& os) const
+{
+  os << "RIB:\n";
+  for (const RibEntry& item : m_status) {
+    this->formatItemText(os, item);
+  }
+}
+
+void
+RibModule::formatItemText(std::ostream& os, const RibEntry& item) const
+{
+  os << "  " << item.getName() << " route={";
+
+  text::Separator sep(", ");
+  for (const Route& route : item.getRoutes()) {
+    os << sep
+       << "faceid=" << route.getFaceId()
+       << " (origin=" << route.getOrigin()
+       << " cost=" << route.getCost();
+    if (!route.hasInfiniteExpirationPeriod()) {
+      os << " expires=" << text::formatDuration(route.getExpirationPeriod());
+    }
+    if (route.isChildInherit()) {
+      os << " ChildInherit";
+    }
+    if (route.isRibCapture()) {
+      os << " RibCapture";
+    }
+    os << ")";
+  }
+
+  os << "}";
+  os << "\n";
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/rib-module.hpp b/tools/nfd-status/rib-module.hpp
new file mode 100644
index 0000000..6a4ddd1
--- /dev/null
+++ b/tools/nfd-status/rib-module.hpp
@@ -0,0 +1,78 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_RIB_MODULE_HPP
+#define NFD_TOOLS_NFD_STATUS_RIB_MODULE_HPP
+
+#include "module.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::nfd::RibEntry;
+using ndn::nfd::Route;
+
+/** \brief provides access to NFD RIB management
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/RibMgmt
+ */
+class RibModule : public Module, noncopyable
+{
+public:
+  virtual void
+  fetchStatus(Controller& controller,
+              const function<void()>& onSuccess,
+              const Controller::CommandFailCallback& onFailure,
+              const CommandOptions& options) override;
+
+  virtual void
+  formatStatusXml(std::ostream& os) const override;
+
+  /** \brief format a single status item as XML
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemXml(std::ostream& os, const RibEntry& item) const;
+
+  virtual void
+  formatStatusText(std::ostream& os) const override;
+
+  /** \brief format a single status item as text
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemText(std::ostream& os, const RibEntry& item) const;
+
+private:
+  std::vector<RibEntry> m_status;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_RIB_MODULE_HPP
diff --git a/tools/nfd-status/status-report.cpp b/tools/nfd-status/status-report.cpp
new file mode 100644
index 0000000..ff04e1f
--- /dev/null
+++ b/tools/nfd-status/status-report.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "status-report.hpp"
+#include "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+uint32_t
+StatusReport::collect(Face& face, KeyChain& keyChain, Validator& validator, const CommandOptions& options)
+{
+  Controller controller(face, keyChain, validator);
+  uint32_t errorCode = 0;
+
+  for (size_t i = 0; i < sections.size(); ++i) {
+    Module& module = *sections[i];
+    module.fetchStatus(
+      controller,
+      [] {},
+      [i, &errorCode] (uint32_t code, const std::string& reason) {
+        errorCode = i * 1000000 + code;
+      },
+      options);
+  }
+
+  this->processEvents(face);
+  return errorCode;
+}
+
+void
+StatusReport::processEvents(Face& face)
+{
+  face.processEvents();
+}
+
+void
+StatusReport::formatXml(std::ostream& os) const
+{
+  xml::printHeader(os);
+  for (const unique_ptr<Module>& module : sections) {
+    module->formatStatusXml(os);
+  }
+  xml::printFooter(os);
+}
+
+void
+StatusReport::formatText(std::ostream& os) const
+{
+  for (const unique_ptr<Module>& module : sections) {
+    module->formatStatusText(os);
+  }
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/status-report.hpp b/tools/nfd-status/status-report.hpp
new file mode 100644
index 0000000..80aaee7
--- /dev/null
+++ b/tools/nfd-status/status-report.hpp
@@ -0,0 +1,85 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_STATUS_REPORT_HPP
+#define NFD_TOOLS_NFD_STATUS_STATUS_REPORT_HPP
+
+#include "module.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::Face;
+using ndn::security::KeyChain;
+using ndn::Validator;
+
+/** \brief collects and prints NFD status report
+ */
+class StatusReport : noncopyable
+{
+public:
+#ifdef WITH_TESTS
+  virtual
+  ~StatusReport() = default;
+#endif
+
+  /** \brief collect status via chosen \p sections
+   *
+   *  This function is blocking. It has exclusive use of \p face.
+   *
+   *  \return if status has been fetched successfully, 0;
+   *          otherwise, error code from any failed section, plus 1000000 * section index
+   */
+  uint32_t
+  collect(Face& face, KeyChain& keyChain, Validator& validator, const CommandOptions& options);
+
+  /** \brief print an XML report
+   *  \param os output stream
+   */
+  void
+  formatXml(std::ostream& os) const;
+
+  /** \brief print a text report
+   *  \param os output stream
+   */
+  void
+  formatText(std::ostream& os) const;
+
+private:
+  VIRTUAL_WITH_TESTS void
+  processEvents(Face& face);
+
+public:
+  /** \brief modules through which status is collected
+   */
+  std::vector<unique_ptr<Module>> sections;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_STATUS_REPORT_HPP
diff --git a/tools/nfd-status/strategy-choice-module.cpp b/tools/nfd-status/strategy-choice-module.cpp
new file mode 100644
index 0000000..efdff50
--- /dev/null
+++ b/tools/nfd-status/strategy-choice-module.cpp
@@ -0,0 +1,85 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "strategy-choice-module.hpp"
+#include "format-helpers.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+void
+StrategyChoiceModule::fetchStatus(Controller& controller,
+                                  const function<void()>& onSuccess,
+                                  const Controller::CommandFailCallback& onFailure,
+                                  const CommandOptions& options)
+{
+  controller.fetch<ndn::nfd::StrategyChoiceDataset>(
+    [this, onSuccess] (const std::vector<StrategyChoice>& result) {
+      m_status = result;
+      onSuccess();
+    },
+    onFailure, options);
+}
+
+void
+StrategyChoiceModule::formatStatusXml(std::ostream& os) const
+{
+  os << "<strategyChoices>";
+  for (const StrategyChoice& item : m_status) {
+    this->formatItemXml(os, item);
+  }
+  os << "</strategyChoices>";
+}
+
+void
+StrategyChoiceModule::formatItemXml(std::ostream& os, const StrategyChoice& item) const
+{
+  os << "<strategyChoice>";
+  os << "<namespace>" << xml::Text{item.getName().toUri()} << "</namespace>";
+  os << "<strategy><name>" << xml::Text{item.getStrategy().toUri()} << "</name></strategy>";
+  os << "</strategyChoice>";
+}
+
+void
+StrategyChoiceModule::formatStatusText(std::ostream& os) const
+{
+  os << "Strategy choices:\n";
+  for (const StrategyChoice& item : m_status) {
+    this->formatItemText(os, item);
+  }
+}
+
+void
+StrategyChoiceModule::formatItemText(std::ostream& os, const StrategyChoice& item) const
+{
+  os << "  " << item.getName()
+     << " strategy=" << item.getStrategy()
+     << "\n";
+}
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tools/nfd-status/strategy-choice-module.hpp b/tools/nfd-status/strategy-choice-module.hpp
new file mode 100644
index 0000000..be84374
--- /dev/null
+++ b/tools/nfd-status/strategy-choice-module.hpp
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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/>.
+ */
+
+#ifndef NFD_TOOLS_NFD_STATUS_STARTEGY_CHOICE_MODULE_HPP
+#define NFD_TOOLS_NFD_STATUS_STARTEGY_CHOICE_MODULE_HPP
+
+#include "module.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+
+using ndn::nfd::StrategyChoice;
+
+/** \brief provides access to NFD Strategy Choice management
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
+ */
+class StrategyChoiceModule : public Module, noncopyable
+{
+public:
+  virtual void
+  fetchStatus(Controller& controller,
+              const function<void()>& onSuccess,
+              const Controller::CommandFailCallback& onFailure,
+              const CommandOptions& options) override;
+
+  virtual void
+  formatStatusXml(std::ostream& os) const override;
+
+  /** \brief format a single status item as XML
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemXml(std::ostream& os, const StrategyChoice& item) const;
+
+  virtual void
+  formatStatusText(std::ostream& os) const override;
+
+  /** \brief format a single status item as text
+   *  \param os output stream
+   *  \param item status item
+   */
+  void
+  formatItemText(std::ostream& os, const StrategyChoice& item) const;
+
+private:
+  std::vector<StrategyChoice> m_status;
+};
+
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFD_STATUS_STARTEGY_CHOICE_MODULE_HPP