face: face refactoring completion

* delete old Face
* rename LpFace as Face
* eliminate LpFaceWrapper and use new Face

refs #3172

Change-Id: I08c3a5dfb4cc1b9834b30cccd9ab634535d0608c
diff --git a/daemon/face/channel.cpp b/daemon/face/channel.cpp
index d161504..65e0a25 100644
--- a/daemon/face/channel.cpp
+++ b/daemon/face/channel.cpp
@@ -1,11 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014  Regents of the University of California,
- *                     Arizona Board of Regents,
- *                     Colorado State University,
- *                     University Pierre & Marie Curie, Sorbonne University,
- *                     Washington University in St. Louis,
- *                     Beijing Institute of Technology
+ * Copyright (c) 2014-2015,  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.
@@ -20,7 +21,7 @@
  *
  * 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.hpp"
 
@@ -36,4 +37,17 @@
   m_uri = uri;
 }
 
+void
+connectFaceClosedSignal(Face& face, const std::function<void()>& f)
+{
+  using face::FaceState;
+
+  face.afterStateChange.connect(
+    [f] (FaceState oldState, FaceState newState) {
+      if (newState == FaceState::CLOSED) {
+        f();
+      }
+    });
+}
+
 } // namespace nfd
diff --git a/daemon/face/channel.hpp b/daemon/face/channel.hpp
index cb5ed27..640395a 100644
--- a/daemon/face/channel.hpp
+++ b/daemon/face/channel.hpp
@@ -26,12 +26,10 @@
 #ifndef NFD_DAEMON_FACE_CHANNEL_HPP
 #define NFD_DAEMON_FACE_CHANNEL_HPP
 
-#include "common.hpp"
+#include "face.hpp"
 
 namespace nfd {
 
-class Face;
-
 /**
  * \brief Prototype for the callback that is invoked when the face
  *        is created (as a response to incoming connection or after
@@ -69,6 +67,16 @@
   return m_uri;
 }
 
+/** \brief invokes a callback when the face is closed
+ *  \param face the face
+ *  \param f the callback to be invoked when the face enters CLOSED state
+ *
+ *  This function connects a callback to the afterStateChange signal on the \p face,
+ *  and invokes \p f when the state becomes CLOSED.
+ */
+void
+connectFaceClosedSignal(Face& face, const std::function<void()>& f);
+
 } // namespace nfd
 
 #endif // NFD_DAEMON_FACE_CHANNEL_HPP
diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp
index 3592530..dd9d034 100644
--- a/daemon/face/ethernet-factory.cpp
+++ b/daemon/face/ethernet-factory.cpp
@@ -26,12 +26,10 @@
 #include "ethernet-factory.hpp"
 #include "ethernet-transport.hpp"
 #include "generic-link-service.hpp"
-#include "lp-face-wrapper.hpp"
-#include "core/global-io.hpp"
 
 namespace nfd {
 
-shared_ptr<face::LpFaceWrapper>
+shared_ptr<Face>
 EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
                                      const ethernet::Address& address)
 {
@@ -48,14 +46,11 @@
 
   auto linkService = make_unique<face::GenericLinkService>(opts);
   auto transport = make_unique<face::EthernetTransport>(interface, address);
-  auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
-  face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
+  face = make_shared<Face>(std::move(linkService), std::move(transport));
 
   auto key = std::make_pair(interface.name, address);
-  face->onFail.connectSingleShot([this, key] (const std::string& reason) {
-    m_multicastFaces.erase(key);
-  });
   m_multicastFaces[key] = face;
+  connectFaceClosedSignal(*face, [this, key] { m_multicastFaces.erase(key); });
 
   return face;
 }
@@ -75,7 +70,7 @@
   return {};
 }
 
-shared_ptr<face::LpFaceWrapper>
+shared_ptr<Face>
 EthernetFactory::findMulticastFace(const std::string& interfaceName,
                                    const ethernet::Address& address) const
 {
diff --git a/daemon/face/ethernet-factory.hpp b/daemon/face/ethernet-factory.hpp
index c0a951d..add176e 100644
--- a/daemon/face/ethernet-factory.hpp
+++ b/daemon/face/ethernet-factory.hpp
@@ -31,10 +31,6 @@
 
 namespace nfd {
 
-namespace face {
-class LpFaceWrapper;
-} // namespace face
-
 class EthernetFactory : public ProtocolFactory
 {
 public:
@@ -52,7 +48,7 @@
   };
 
   typedef std::map<std::pair<std::string, ethernet::Address>,
-                   shared_ptr<face::LpFaceWrapper>> MulticastFaceMap;
+                   shared_ptr<Face>> MulticastFaceMap;
 
   /**
    * \brief Create an EthernetFace to communicate with the given multicast group
@@ -69,7 +65,7 @@
    *
    * \throws EthernetFactory::Error or EthernetTransport::Error
    */
-  shared_ptr<face::LpFaceWrapper>
+  shared_ptr<Face>
   createMulticastFace(const NetworkInterfaceInfo& interface,
                       const ethernet::Address& address);
 
@@ -96,7 +92,7 @@
    * \returns shared pointer to the existing EthernetFace object
    *          or nullptr when such face does not exist
    */
-  shared_ptr<face::LpFaceWrapper>
+  shared_ptr<Face>
   findMulticastFace(const std::string& interfaceName,
                     const ethernet::Address& address) const;
 
diff --git a/daemon/face/face-counters.cpp b/daemon/face/face-counters.cpp
index 611b151..7c4dee4 100644
--- a/daemon/face/face-counters.cpp
+++ b/daemon/face/face-counters.cpp
@@ -24,7 +24,6 @@
  */
 
 #include "face-counters.hpp"
-#include "old-face-counters.hpp"
 
 namespace nfd {
 namespace face {
@@ -46,24 +45,5 @@
 {
 }
 
-static const LinkService::Counters g_dummyLinkServiceCounters{};
-static const Transport::Counters g_dummyTransportCounters{};
-
-FaceCounters::FaceCounters(const OldFaceCounters& oldCounters)
-  : nInInterests(oldCounters.getNInInterests())
-  , nOutInterests(oldCounters.getNOutInterests())
-  , nInData(oldCounters.getNInDatas())
-  , nOutData(oldCounters.getNOutDatas())
-  , nInNacks(g_dummyLinkServiceCounters.nInNacks)
-  , nOutNacks(g_dummyLinkServiceCounters.nOutNacks)
-  , nInPackets(g_dummyTransportCounters.nInPackets)
-  , nOutPackets(g_dummyTransportCounters.nOutPackets)
-  , nInBytes(oldCounters.getNInBytes())
-  , nOutBytes(oldCounters.getNOutBytes())
-  , m_linkServiceCounters(g_dummyLinkServiceCounters)
-  , m_transportCounters(g_dummyTransportCounters)
-{
-}
-
 } // namespace face
 } // namespace nfd
diff --git a/daemon/face/face-counters.hpp b/daemon/face/face-counters.hpp
index 93aebf4..08facf8 100644
--- a/daemon/face/face-counters.hpp
+++ b/daemon/face/face-counters.hpp
@@ -30,9 +30,6 @@
 #include "transport.hpp"
 
 namespace nfd {
-
-class OldFaceCounters;
-
 namespace face {
 
 /** \brief gives access to counters provided by Face
@@ -48,14 +45,6 @@
   FaceCounters(const LinkService::Counters& linkServiceCounters,
                const Transport::Counters& transportCounters);
 
-  /** \brief wraps old counters
-   *
-   *  FaceCounters instance created from this constructor only provides Interest/Data counters
-   *  and Nack counters. Other counters are always zero. get<T>() should not be used.
-   */
-  explicit
-  FaceCounters(const OldFaceCounters& oldCounters);
-
   /** \return counters provided by LinkService
    *  \tparam T LinkService counters type
    *  \throw std::bad_cast counters type mismatch
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index 5367d39..69d32c1 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -25,73 +25,31 @@
 
 #include "face.hpp"
 
-#include <ndn-cxx/management/nfd-face-event-notification.hpp>
-
 namespace nfd {
+namespace face {
 
-Face::Face(const FaceUri& remoteUri, const FaceUri& localUri, bool isLocal, bool isMultiAccess)
-  : m_id(INVALID_FACEID)
-  , m_countersWrapper(m_counters)
-  , m_remoteUri(remoteUri)
-  , m_localUri(localUri)
-  , m_isLocal(isLocal)
-  , m_persistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
-  , m_isMultiAccess(isMultiAccess)
-  , m_isFailed(false)
+Face::Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
+  : afterReceiveInterest(service->afterReceiveInterest)
+  , afterReceiveData(service->afterReceiveData)
+  , afterReceiveNack(service->afterReceiveNack)
+  , afterStateChange(transport->afterStateChange)
+  , m_id(INVALID_FACEID)
+  , m_service(std::move(service))
+  , m_transport(std::move(transport))
+  , m_counters(m_service->getCounters(), m_transport->getCounters())
 {
-  onReceiveInterest.connect([this] (const ndn::Interest&) { ++m_counters.getNInInterests(); });
-  onReceiveData    .connect([this] (const ndn::Data&)     { ++m_counters.getNInDatas(); });
-  onSendInterest   .connect([this] (const ndn::Interest&) { ++m_counters.getNOutInterests(); });
-  onSendData       .connect([this] (const ndn::Data&)     { ++m_counters.getNOutDatas(); });
+  m_service->setFaceAndTransport(*this, *m_transport);
+  m_transport->setFaceAndLinkService(*this, *m_service);
 }
 
-Face::~Face()
+std::ostream&
+operator<<(std::ostream& os, const FaceLogHelper<Face>& flh)
 {
+  const Face& face = flh.obj;
+  os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
+        ",remote=" << face.getRemoteUri() << "] ";
+  return os;
 }
 
-bool
-Face::isUp() const
-{
-  return true;
-}
-
-bool
-Face::decodeAndDispatchInput(const Block& element)
-{
-  try {
-    /// \todo Ensure lazy field decoding process
-
-    if (element.type() == tlv::Interest)
-      {
-        shared_ptr<Interest> i = make_shared<Interest>();
-        i->wireDecode(element);
-        this->onReceiveInterest(*i);
-      }
-    else if (element.type() == tlv::Data)
-      {
-        shared_ptr<Data> d = make_shared<Data>();
-        d->wireDecode(element);
-        this->onReceiveData(*d);
-      }
-    else
-      return false;
-
-    return true;
-  }
-  catch (const tlv::Error&) {
-    return false;
-  }
-}
-
-void
-Face::fail(const std::string& reason)
-{
-  if (m_isFailed) {
-    return;
-  }
-
-  m_isFailed = true;
-  this->onFail(reason);
-}
-
+} // namespace face
 } // namespace nfd
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index d964ef1..d783dd0 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -23,27 +23,23 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef NFD_DAEMON_FACE_FACE_HPP
-#define NFD_DAEMON_FACE_FACE_HPP
+#ifndef NFD_DAEMON_FACE_HPP
+#define NFD_DAEMON_FACE_HPP
 
-#include "common.hpp"
-#include "core/logger.hpp"
+#include "transport.hpp"
+#include "link-service.hpp"
 #include "face-counters.hpp"
-#include "old-face-counters.hpp"
 #include "face-log.hpp"
 
-#include <ndn-cxx/management/nfd-face-status.hpp>
-
 namespace nfd {
+namespace face {
 
-/** \class FaceId
- *  \brief identifies a face
+/** \brief identifies a face
  */
-typedef int FaceId;
+typedef uint64_t FaceId;
 
 /// indicates an invalid FaceId
-const FaceId INVALID_FACEID = -1;
-
+const FaceId INVALID_FACEID = 0;
 /// identifies the InternalFace used in management
 const FaceId FACEID_INTERNAL_FACE = 1;
 /// identifies a packet comes from the ContentStore
@@ -53,169 +49,169 @@
 /// upper bound of reserved FaceIds
 const FaceId FACEID_RESERVED_MAX = 255;
 
-
-/** \brief represents a face
+/** \brief indicates the state of a face
  */
-class Face : noncopyable, public enable_shared_from_this<Face>
+typedef TransportState FaceState;
+
+/** \brief generalization of a network interface
+ *
+ *  A face generalizes a network interface.
+ *  It provides best-effort network-layer packet delivery services
+ *  on a physical interface, an overlay tunnel, or a link to a local application.
+ *
+ *  A face combines two parts: LinkService and Transport.
+ *  Transport is the lower part, which provides best-effort TLV block deliveries.
+ *  LinkService is the upper part, which translates between network-layer packets
+ *  and TLV blocks, and may provide additional services such as fragmentation and reassembly.
+ */
+class Face
+#ifndef WITH_TESTS
+DECL_CLASS_FINAL
+#endif
+  : public enable_shared_from_this<Face>, noncopyable
 {
 public:
-  /**
-   * \brief Face-related error
+  Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
+
+  LinkService*
+  getLinkService();
+
+  Transport*
+  getTransport();
+
+public: // upper interface connected to forwarding
+  /** \brief sends Interest on Face
    */
-  class Error : public std::runtime_error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
-  };
+  void
+  sendInterest(const Interest& interest);
 
-  Face(const FaceUri& remoteUri, const FaceUri& localUri,
-       bool isLocal = false, bool isMultiAccess = false);
-
-  virtual
-  ~Face();
-
-  /// fires when an Interest is received
-  signal::Signal<Face, Interest> onReceiveInterest;
-
-  /// fires when a Data is received
-  signal::Signal<Face, Data> onReceiveData;
-
-  /// fires when a Nack is received
-  signal::Signal<Face, lp::Nack> onReceiveNack;
-
-  /// fires when an Interest is sent out
-  signal::Signal<Face, Interest> onSendInterest;
-
-  /// fires when a Data is sent out
-  signal::Signal<Face, Data> onSendData;
-
-  /// fires when a Nack is sent out
-  signal::Signal<Face, lp::Nack> onSendNack;
-
-  /// fires when face disconnects or fails to perform properly
-  signal::Signal<Face, std::string/*reason*/> onFail;
-
-  /// send an Interest
-  virtual void
-  sendInterest(const Interest& interest) = 0;
-
-  /// send a Data
-  virtual void
-  sendData(const Data& data) = 0;
-
-  /// send a Nack
-  virtual void
-  sendNack(const ndn::lp::Nack& nack)
-  {
-  }
-
-  /** \brief Close the face
-   *
-   *  This terminates all communication on the face and cause
-   *  onFail() method event to be invoked
+  /** \brief sends Data on Face
    */
-  virtual void
-  close() = 0;
+  void
+  sendData(const Data& data);
 
-public: // attributes
+  /** \brief sends Nack on Face
+   */
+  void
+  sendNack(const lp::Nack& nack);
+
+  /** \brief signals on Interest received
+   */
+  signal::Signal<LinkService, Interest>& afterReceiveInterest;
+
+  /** \brief signals on Data received
+   */
+  signal::Signal<LinkService, Data>& afterReceiveData;
+
+  /** \brief signals on Nack received
+   */
+  signal::Signal<LinkService, lp::Nack>& afterReceiveNack;
+
+public: // static properties
+  /** \return face ID
+   */
   FaceId
   getId() const;
 
-  /** \brief Get the description
-   */
-  const std::string&
-  getDescription() const;
-
-  /** \brief Set the face description
-   *
-   *  This is typically invoked by management on set description command
+  /** \brief sets face ID
+   *  \note Normally, this should only be invoked by FaceTable.
    */
   void
-  setDescription(const std::string& description);
+  setId(FaceId id);
 
-  /** \brief Get whether face is connected to a local app
+  /** \return a FaceUri representing local endpoint
    */
-  bool
-  isLocal() const;
+  FaceUri
+  getLocalUri() const;
 
-  /** \brief Get the persistency setting
+  /** \return a FaceUri representing remote endpoint
+   */
+  FaceUri
+  getRemoteUri() const;
+
+  /** \return whether face is local or non-local for scope control purpose
+   */
+  ndn::nfd::FaceScope
+  getScope() const;
+
+  /** \return face persistency setting
    */
   ndn::nfd::FacePersistency
   getPersistency() const;
 
-  // 'virtual' to allow override in LpFaceWrapper
-  virtual void
-  setPersistency(ndn::nfd::FacePersistency persistency);
-
-  /** \brief Get whether packets sent by this face may reach multiple peers
-   */
-  bool
-  isMultiAccess() const;
-
-  /** \brief Get whether underlying communication is up
-   *
-   *  In this base class this property is always true.
-   */
-  virtual bool
-  isUp() const;
-
-  virtual const face::FaceCounters&
-  getCounters() const;
-
-  /** \return a FaceUri that represents the remote endpoint
-   */
-  const FaceUri&
-  getRemoteUri() const;
-
-  /** \return a FaceUri that represents the local endpoint (NFD side)
-   */
-  const FaceUri&
-  getLocalUri() const;
-
-protected:
-  bool
-  decodeAndDispatchInput(const Block& element);
-
-  /** \brief fail the face and raise onFail event if it's UP; otherwise do nothing
+  /** \brief changes face persistency setting
    */
   void
-  fail(const std::string& reason);
+  setPersistency(ndn::nfd::FacePersistency persistency);
 
-  OldFaceCounters&
-  getMutableCounters();
+  /** \return whether face is point-to-point or multi-access
+   */
+  ndn::nfd::LinkType
+  getLinkType() const;
 
-  DECLARE_SIGNAL_EMIT(onReceiveInterest)
-  DECLARE_SIGNAL_EMIT(onReceiveData)
-  DECLARE_SIGNAL_EMIT(onReceiveNack)
-  DECLARE_SIGNAL_EMIT(onSendInterest)
-  DECLARE_SIGNAL_EMIT(onSendData)
-  DECLARE_SIGNAL_EMIT(onSendNack)
+public: // dynamic properties
+  /** \return face state
+   */
+  FaceState
+  getState() const;
 
-  // this method should be used only by the FaceTable
-  // 'virtual' to allow override in LpFaceWrapper
-  virtual void
-  setId(FaceId faceId);
+  /** \brief signals after face state changed
+   */
+  signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
+
+  /** \brief request the face to be closed
+   *
+   *  This operation is effective only if face is in UP or DOWN state,
+   *  otherwise it has no effect.
+   *  The face changes state to CLOSING, and performs cleanup procedure.
+   *  The state will be changed to CLOSED when cleanup is complete, which may
+   *  happen synchronously or asynchronously.
+   *
+   *  \warning the face must not be deallocated until its state changes to CLOSED
+   */
+  void
+  close();
+
+  const FaceCounters&
+  getCounters() const;
 
 private:
   FaceId m_id;
-  std::string m_description;
-  OldFaceCounters m_counters;
-  face::FaceCounters m_countersWrapper;
-  const FaceUri m_remoteUri;
-  const FaceUri m_localUri;
-  const bool m_isLocal;
-  ndn::nfd::FacePersistency m_persistency;
-  const bool m_isMultiAccess;
-  bool m_isFailed;
-
-  // allow setting FaceId
-  friend class FaceTable;
+  unique_ptr<LinkService> m_service;
+  unique_ptr<Transport> m_transport;
+  FaceCounters m_counters;
 };
 
+inline LinkService*
+Face::getLinkService()
+{
+  return m_service.get();
+}
+
+inline Transport*
+Face::getTransport()
+{
+  return m_transport.get();
+}
+
+inline void
+Face::sendInterest(const Interest& interest)
+{
+  m_service->sendInterest(interest);
+}
+
+inline void
+Face::sendData(const Data& data)
+{
+  m_service->sendData(data);
+}
+
+inline void
+Face::sendNack(const lp::Nack& nack)
+{
+  m_service->sendNack(nack);
+}
+
 inline FaceId
 Face::getId() const
 {
@@ -223,81 +219,80 @@
 }
 
 inline void
-Face::setId(FaceId faceId)
+Face::setId(FaceId id)
 {
-  m_id = faceId;
+  m_id = id;
 }
 
-inline const std::string&
-Face::getDescription() const
+inline FaceUri
+Face::getLocalUri() const
 {
-  return m_description;
+  return m_transport->getLocalUri();
 }
 
-inline void
-Face::setDescription(const std::string& description)
+inline FaceUri
+Face::getRemoteUri() const
 {
-  m_description = description;
+  return m_transport->getRemoteUri();
 }
 
-inline bool
-Face::isLocal() const
+inline ndn::nfd::FaceScope
+Face::getScope() const
 {
-  return m_isLocal;
+  return m_transport->getScope();
 }
 
 inline ndn::nfd::FacePersistency
 Face::getPersistency() const
 {
-  return m_persistency;
+  return m_transport->getPersistency();
 }
 
 inline void
 Face::setPersistency(ndn::nfd::FacePersistency persistency)
 {
-  m_persistency = persistency;
+  return m_transport->setPersistency(persistency);
 }
 
-inline bool
-Face::isMultiAccess() const
+inline ndn::nfd::LinkType
+Face::getLinkType() const
 {
-  return m_isMultiAccess;
+  return m_transport->getLinkType();
 }
 
-inline const face::FaceCounters&
+inline FaceState
+Face::getState() const
+{
+  return m_transport->getState();
+}
+
+inline void
+Face::close()
+{
+  m_transport->close();
+}
+
+inline const FaceCounters&
 Face::getCounters() const
 {
-  return m_countersWrapper;
-}
-
-inline OldFaceCounters&
-Face::getMutableCounters()
-{
   return m_counters;
 }
 
-inline const FaceUri&
-Face::getRemoteUri() const
-{
-  return m_remoteUri;
-}
-
-inline const FaceUri&
-Face::getLocalUri() const
-{
-  return m_localUri;
-}
+std::ostream&
+operator<<(std::ostream& os, const FaceLogHelper<Face>& flh);
 
 template<typename T>
 typename std::enable_if<std::is_base_of<Face, T>::value, std::ostream&>::type
-operator<<(std::ostream& os, const face::FaceLogHelper<T>& flh)
+operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
 {
-  const Face& face = flh.obj;
-  os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
-        ",remote=" << face.getRemoteUri() << "] ";
-  return os;
+  return os << FaceLogHelper<Face>(flh.obj);
 }
 
+} // namespace face
+
+using face::FaceId;
+using face::Face;
+
 } // namespace nfd
 
-#endif // NFD_DAEMON_FACE_FACE_HPP
+#endif // NFD_DAEMON_FACE_HPP
diff --git a/daemon/face/internal-face.cpp b/daemon/face/internal-face.cpp
index c89f87f..8bea03d 100644
--- a/daemon/face/internal-face.cpp
+++ b/daemon/face/internal-face.cpp
@@ -26,7 +26,6 @@
 #include "internal-face.hpp"
 #include "generic-link-service.hpp"
 #include "internal-transport.hpp"
-#include "lp-face-wrapper.hpp"
 #include "core/global-io.hpp"
 
 namespace nfd {
@@ -38,19 +37,16 @@
   GenericLinkService::Options serviceOpts;
   serviceOpts.allowLocalFields = true;
 
-  auto face = make_unique<LpFace>(make_unique<GenericLinkService>(serviceOpts),
-                                  make_unique<InternalForwarderTransport>());
-  auto faceW = make_shared<LpFaceWrapper>(std::move(face));
-  // TODO#3172 eliminate wrapper
+  auto face = make_shared<Face>(make_unique<GenericLinkService>(serviceOpts),
+                                make_unique<InternalForwarderTransport>());
 
-  InternalForwarderTransport* forwarderTransport =
-    static_cast<InternalForwarderTransport*>(faceW->getLpFace()->getTransport());
+  auto forwarderTransport = static_cast<InternalForwarderTransport*>(face->getTransport());
   auto clientTransport = make_shared<InternalClientTransport>();
   clientTransport->connectToForwarder(forwarderTransport);
 
   auto clientFace = make_shared<ndn::Face>(clientTransport, getGlobalIoService(), clientKeyChain);
 
-  return std::make_tuple(faceW, clientFace);
+  return std::make_tuple(face, clientFace);
 }
 
 } // namespace face
diff --git a/daemon/face/link-service.cpp b/daemon/face/link-service.cpp
index 93507e0..00dd6f0 100644
--- a/daemon/face/link-service.cpp
+++ b/daemon/face/link-service.cpp
@@ -24,8 +24,7 @@
  */
 
 #include "link-service.hpp"
-#include "lp-face.hpp"
-#include "transport.hpp"
+#include "face.hpp"
 
 namespace nfd {
 namespace face {
@@ -43,7 +42,7 @@
 }
 
 void
-LinkService::setFaceAndTransport(LpFace& face, Transport& transport)
+LinkService::setFaceAndTransport(Face& face, Transport& transport)
 {
   BOOST_ASSERT(m_face == nullptr);
   BOOST_ASSERT(m_transport == nullptr);
@@ -118,7 +117,7 @@
 std::ostream&
 operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh)
 {
-  const LpFace* face = flh.obj.getFace();
+  const Face* face = flh.obj.getFace();
   if (face == nullptr) {
     os << "[id=0,local=unknown,remote=unknown] ";
   }
diff --git a/daemon/face/link-service.hpp b/daemon/face/link-service.hpp
index 031735a..618e863 100644
--- a/daemon/face/link-service.hpp
+++ b/daemon/face/link-service.hpp
@@ -33,7 +33,7 @@
 namespace nfd {
 namespace face {
 
-class LpFace;
+class Face;
 
 /** \brief counters provided by LinkService
  *  \note The type name 'LinkServiceCounters' is implementation detail.
@@ -67,8 +67,8 @@
   PacketCounter nOutNacks;
 };
 
-/** \brief the upper part of an LpFace
- *  \sa LpFace
+/** \brief the upper part of a Face
+ *  \sa Face
  */
 class LinkService : protected virtual LinkServiceCounters, noncopyable
 {
@@ -87,11 +87,11 @@
    *  \pre setFaceAndTransport has not been called
    */
   void
-  setFaceAndTransport(LpFace& face, Transport& transport);
+  setFaceAndTransport(Face& face, Transport& transport);
 
   /** \return Face to which this LinkService is attached
    */
-  const LpFace*
+  const Face*
   getFace() const;
 
   /** \return Transport to which this LinkService is attached
@@ -187,11 +187,11 @@
   doReceivePacket(Transport::Packet&& packet) = 0;
 
 private:
-  LpFace* m_face;
+  Face* m_face;
   Transport* m_transport;
 };
 
-inline const LpFace*
+inline const Face*
 LinkService::getFace() const
 {
   return m_face;
diff --git a/daemon/face/lp-face-wrapper.cpp b/daemon/face/lp-face-wrapper.cpp
deleted file mode 100644
index 920997a..0000000
--- a/daemon/face/lp-face-wrapper.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  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 "lp-face-wrapper.hpp"
-
-namespace nfd {
-namespace face {
-
-LpFaceWrapper::LpFaceWrapper(unique_ptr<LpFace> face)
-  : Face(face->getRemoteUri(), face->getLocalUri(),
-         face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL,
-         face->getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS)
-  , m_face(std::move(face))
-{
-  this->Face::setPersistency(m_face->getPersistency());
-  m_face->afterReceiveInterest.connect(bind(&LpFaceWrapper::dispatchInterest, this, _1));
-  m_face->afterReceiveData.connect(bind(&LpFaceWrapper::dispatchData, this, _1));
-  m_face->afterReceiveNack.connect(bind(&LpFaceWrapper::dispatchNack, this, _1));
-  m_face->afterStateChange.connect(bind(&LpFaceWrapper::handleStateChange, this, _1, _2));
-}
-
-void
-LpFaceWrapper::setPersistency(ndn::nfd::FacePersistency persistency)
-{
-  this->Face::setPersistency(persistency);
-  m_face->setPersistency(persistency);
-}
-
-void
-LpFaceWrapper::setId(nfd::FaceId faceId)
-{
-  this->Face::setId(faceId);
-
-  FaceId lpId = static_cast<FaceId>(faceId);
-  if (faceId == nfd::INVALID_FACEID) {
-    lpId = INVALID_FACEID;
-  }
-  m_face->setId(lpId);
-}
-
-void
-LpFaceWrapper::dispatchInterest(const Interest& interest)
-{
-  this->emitSignal(onReceiveInterest, interest);
-}
-
-void
-LpFaceWrapper::dispatchData(const Data& data)
-{
-  this->emitSignal(onReceiveData, data);
-}
-
-void
-LpFaceWrapper::dispatchNack(const ndn::lp::Nack& nack)
-{
-  this->emitSignal(onReceiveNack, nack);
-}
-
-void
-LpFaceWrapper::handleStateChange(FaceState oldState, FaceState newState)
-{
-  if (newState != FaceState::CLOSED) {
-    return;
-  }
-
-  switch (oldState) {
-  case FaceState::CLOSING:
-    this->fail("LpFace closed");
-    break;
-  case FaceState::FAILED:
-    this->fail("LpFace failed");
-    break;
-  default:
-    BOOST_ASSERT(false);
-    break;
-  }
-}
-
-} // namespace face
-} // namespace nfd
diff --git a/daemon/face/lp-face-wrapper.hpp b/daemon/face/lp-face-wrapper.hpp
deleted file mode 100644
index 4cfb0f3..0000000
--- a/daemon/face/lp-face-wrapper.hpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  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_DAEMON_FACE_LP_FACE_WRAPPER_HPP
-#define NFD_DAEMON_FACE_LP_FACE_WRAPPER_HPP
-
-#include "common.hpp"
-#include "face.hpp"
-#include "lp-face.hpp"
-
-namespace nfd {
-namespace face {
-
-/** \brief an adaptor to provide old Face APIs from an LpFace
- *  \sa LpFace
- */
-class LpFaceWrapper : public Face
-{
-public:
-  explicit
-  LpFaceWrapper(unique_ptr<LpFace> face);
-
-  LpFace*
-  getLpFace();
-
-  virtual void
-  sendInterest(const Interest& interest) DECL_OVERRIDE;
-
-  virtual void
-  sendData(const Data& data) DECL_OVERRIDE;
-
-  virtual void
-  sendNack(const lp::Nack& nack) DECL_OVERRIDE;
-
-  virtual void
-  close() DECL_OVERRIDE;
-
-  virtual bool
-  isUp() const DECL_OVERRIDE;
-
-  virtual void
-  setPersistency(ndn::nfd::FacePersistency persistency) DECL_OVERRIDE;
-
-  virtual const FaceCounters&
-  getCounters() const DECL_OVERRIDE;
-
-protected:
-  virtual void
-  setId(nfd::FaceId faceId) DECL_OVERRIDE;
-
-private:
-  void
-  dispatchInterest(const Interest& interest);
-
-  void
-  dispatchData(const Data& data);
-
-  void
-  dispatchNack(const lp::Nack& nack);
-
-  void
-  handleStateChange(FaceState oldState, FaceState newState);
-
-private:
-  unique_ptr<LpFace> m_face;
-};
-
-inline LpFace*
-LpFaceWrapper::getLpFace()
-{
-  return m_face.get();
-}
-
-inline void
-LpFaceWrapper::sendInterest(const Interest& interest)
-{
-  this->emitSignal(onSendInterest, interest);
-  m_face->sendInterest(interest);
-}
-
-inline void
-LpFaceWrapper::sendData(const Data& data)
-{
-  this->emitSignal(onSendData, data);
-  m_face->sendData(data);
-}
-
-inline void
-LpFaceWrapper::sendNack(const lp::Nack& nack)
-{
-  this->emitSignal(onSendNack, nack);
-  m_face->sendNack(nack);
-}
-
-inline void
-LpFaceWrapper::close()
-{
-  m_face->close();
-}
-
-inline bool
-LpFaceWrapper::isUp() const
-{
-  return m_face->getState() == FaceState::UP;
-}
-
-inline const FaceCounters&
-LpFaceWrapper::getCounters() const
-{
-  return m_face->getCounters();
-}
-
-} // namespace face
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_LP_FACE_WRAPPER_HPP
diff --git a/daemon/face/lp-face.cpp b/daemon/face/lp-face.cpp
deleted file mode 100644
index 55cc4d0..0000000
--- a/daemon/face/lp-face.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  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 "lp-face.hpp"
-
-namespace nfd {
-namespace face {
-
-LpFace::LpFace(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
-  : afterReceiveInterest(service->afterReceiveInterest)
-  , afterReceiveData(service->afterReceiveData)
-  , afterReceiveNack(service->afterReceiveNack)
-  , afterStateChange(transport->afterStateChange)
-  , m_id(INVALID_FACEID)
-  , m_service(std::move(service))
-  , m_transport(std::move(transport))
-  , m_counters(m_service->getCounters(), m_transport->getCounters())
-{
-  m_service->setFaceAndTransport(*this, *m_transport);
-  m_transport->setFaceAndLinkService(*this, *m_service);
-}
-
-} // namespace face
-} // namespace nfd
diff --git a/daemon/face/lp-face.hpp b/daemon/face/lp-face.hpp
deleted file mode 100644
index 130fe00..0000000
--- a/daemon/face/lp-face.hpp
+++ /dev/null
@@ -1,303 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  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_DAEMON_LP_FACE_HPP
-#define NFD_DAEMON_LP_FACE_HPP
-
-#include "transport.hpp"
-#include "link-service.hpp"
-#include "face-counters.hpp"
-#include "face-log.hpp"
-
-namespace nfd {
-namespace face {
-
-/** \brief identifies a face
- */
-typedef uint64_t FaceId;
-
-/// indicates an invalid FaceId
-const FaceId INVALID_FACEID = 0;
-/// identifies the InternalFace used in management
-const FaceId FACEID_INTERNAL_FACE = 1;
-/// identifies a packet comes from the ContentStore
-const FaceId FACEID_CONTENT_STORE = 254;
-/// identifies the NullFace that drops every packet
-const FaceId FACEID_NULL = 255;
-/// upper bound of reserved FaceIds
-const FaceId FACEID_RESERVED_MAX = 255;
-
-/** \brief indicates the state of a face
- */
-typedef TransportState FaceState;
-
-/** \brief generalization of a network interface
- *
- *  A face generalizes a network interface.
- *  It provides network-layer packet delivery services on a physical interface,
- *  an overlay tunnel, or a link to a local application, with best-effort.
- *
- *  A face combines two parts: LinkService and Transport.
- *  Transport is the lower part, which provides TLV block delivery services with best-effort.
- *  LinkService is the upper part, which translates between network-layer packets
- *  and TLV blocks, and may provide additional services such as fragmentation and reassembly.
- *
- *  We are in the process of refactoring face system to use this LinkService+Transport
- *  architecture. During this process, the "face" is named LpFace, and we implement a
- *  LpFaceWrapper class as an adaptor to the old Face APIs. After the completion of refactoring,
- *  LpFace will be renamed to Face.
- */
-class LpFace
-#ifndef WITH_TESTS
-DECL_CLASS_FINAL
-#endif
-  : noncopyable
-{
-public:
-  LpFace(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
-
-  LinkService*
-  getLinkService();
-
-  Transport*
-  getTransport();
-
-public: // upper interface connected to forwarding
-  /** \brief sends Interest on Face
-   */
-  void
-  sendInterest(const Interest& interest);
-
-  /** \brief sends Data on Face
-   */
-  void
-  sendData(const Data& data);
-
-  /** \brief sends Nack on Face
-   */
-  void
-  sendNack(const lp::Nack& nack);
-
-  /** \brief signals on Interest received
-   */
-  signal::Signal<LinkService, Interest>& afterReceiveInterest;
-
-  /** \brief signals on Data received
-   */
-  signal::Signal<LinkService, Data>& afterReceiveData;
-
-  /** \brief signals on Nack received
-   */
-  signal::Signal<LinkService, lp::Nack>& afterReceiveNack;
-
-public: // static properties
-  /** \return face ID
-   */
-  FaceId
-  getId() const;
-
-  /** \brief sets face ID
-   *  \note Normally, this should only be invoked by FaceTable.
-   */
-  void
-  setId(FaceId id);
-
-  /** \return a FaceUri representing local endpoint
-   */
-  FaceUri
-  getLocalUri() const;
-
-  /** \return a FaceUri representing remote endpoint
-   */
-  FaceUri
-  getRemoteUri() const;
-
-  /** \return whether face is local or non-local for scope control purpose
-   */
-  ndn::nfd::FaceScope
-  getScope() const;
-
-  /** \return face persistency setting
-   */
-  ndn::nfd::FacePersistency
-  getPersistency() const;
-
-  /** \brief changes face persistency setting
-   */
-  void
-  setPersistency(ndn::nfd::FacePersistency persistency);
-
-  /** \return whether face is point-to-point or multi-access
-   */
-  ndn::nfd::LinkType
-  getLinkType() const;
-
-public: // dynamic properties
-  /** \return face state
-   */
-  FaceState
-  getState() const;
-
-  /** \brief signals after face state changed
-   */
-  signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
-
-  /** \brief request the face to be closed
-   *
-   *  This operation is effective only if face is in UP or DOWN state,
-   *  otherwise it has no effect.
-   *  The face changes state to CLOSING, and performs cleanup procedure.
-   *  The state will be changed to CLOSED when cleanup is complete, which may
-   *  happen synchronously or asynchronously.
-   *
-   *  \warning the face must not be deallocated until its state changes to CLOSED
-   */
-  void
-  close();
-
-  const FaceCounters&
-  getCounters() const;
-
-private:
-  FaceId m_id;
-  unique_ptr<LinkService> m_service;
-  unique_ptr<Transport> m_transport;
-  FaceCounters m_counters;
-};
-
-inline LinkService*
-LpFace::getLinkService()
-{
-  return m_service.get();
-}
-
-inline Transport*
-LpFace::getTransport()
-{
-  return m_transport.get();
-}
-
-inline void
-LpFace::sendInterest(const Interest& interest)
-{
-  m_service->sendInterest(interest);
-}
-
-inline void
-LpFace::sendData(const Data& data)
-{
-  m_service->sendData(data);
-}
-
-inline void
-LpFace::sendNack(const lp::Nack& nack)
-{
-  m_service->sendNack(nack);
-}
-
-inline FaceId
-LpFace::getId() const
-{
-  return m_id;
-}
-
-inline void
-LpFace::setId(FaceId id)
-{
-  m_id = id;
-}
-
-inline FaceUri
-LpFace::getLocalUri() const
-{
-  return m_transport->getLocalUri();
-}
-
-inline FaceUri
-LpFace::getRemoteUri() const
-{
-  return m_transport->getRemoteUri();
-}
-
-inline ndn::nfd::FaceScope
-LpFace::getScope() const
-{
-  return m_transport->getScope();
-}
-
-inline ndn::nfd::FacePersistency
-LpFace::getPersistency() const
-{
-  return m_transport->getPersistency();
-}
-
-inline void
-LpFace::setPersistency(ndn::nfd::FacePersistency persistency)
-{
-  return m_transport->setPersistency(persistency);
-}
-
-inline ndn::nfd::LinkType
-LpFace::getLinkType() const
-{
-  return m_transport->getLinkType();
-}
-
-inline FaceState
-LpFace::getState() const
-{
-  return m_transport->getState();
-}
-
-inline void
-LpFace::close()
-{
-  m_transport->close();
-}
-
-inline const FaceCounters&
-LpFace::getCounters() const
-{
-  return m_counters;
-}
-
-template<typename T>
-typename std::enable_if<std::is_base_of<LpFace, T>::value, std::ostream&>::type
-operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
-{
-  const LpFace& face = flh.obj;
-  os << "[id=" << face.getId() << ",local=" << face.getLocalUri() <<
-        ",remote=" << face.getRemoteUri() << "] ";
-  return os;
-}
-
-} // namespace face
-
-// using face::FaceId; // TODO uncomment in #3172
-using face::LpFace;
-
-} // namespace nfd
-
-#endif // NFD_DAEMON_LP_FACE_HPP
diff --git a/daemon/face/null-face.cpp b/daemon/face/null-face.cpp
index 2c409a7..a793e3e 100644
--- a/daemon/face/null-face.cpp
+++ b/daemon/face/null-face.cpp
@@ -24,7 +24,6 @@
  */
 
 #include "null-face.hpp"
-#include "lp-face-wrapper.hpp"
 #include "generic-link-service.hpp"
 #include "internal-transport.hpp"
 
@@ -37,12 +36,8 @@
 shared_ptr<Face>
 makeNullFace(const FaceUri& uri)
 {
-  auto face = make_unique<LpFace>(make_unique<GenericLinkService>(),
-                                  make_unique<InternalForwarderTransport>(uri, uri, ndn::nfd::FACE_SCOPE_LOCAL));
-  auto faceW = make_shared<LpFaceWrapper>(std::move(face));
-  // TODO#3172 eliminate wrapper
-
-  return faceW;
+  return make_shared<Face>(make_unique<GenericLinkService>(),
+                           make_unique<InternalForwarderTransport>(uri, uri, ndn::nfd::FACE_SCOPE_LOCAL));
 }
 
 } // namespace face
diff --git a/daemon/face/old-face-counters.hpp b/daemon/face/old-face-counters.hpp
deleted file mode 100644
index 1c1dd2e..0000000
--- a/daemon/face/old-face-counters.hpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  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_DAEMON_FACE_OLD_FACE_COUNTERS_HPP
-#define NFD_DAEMON_FACE_OLD_FACE_COUNTERS_HPP
-
-#include "core/counter.hpp"
-
-namespace nfd {
-
-/** \brief contains network layer packet counters
- */
-class NetworkLayerCounters : noncopyable
-{
-public:
-  /// incoming Interest
-  const PacketCounter&
-  getNInInterests() const
-  {
-    return m_nInInterests;
-  }
-
-  PacketCounter&
-  getNInInterests()
-  {
-    return m_nInInterests;
-  }
-
-  /// incoming Data
-  const PacketCounter&
-  getNInDatas() const
-  {
-    return m_nInDatas;
-  }
-
-  PacketCounter&
-  getNInDatas()
-  {
-    return m_nInDatas;
-  }
-
-  /// outgoing Interest
-  const PacketCounter&
-  getNOutInterests() const
-  {
-    return m_nOutInterests;
-  }
-
-  PacketCounter&
-  getNOutInterests()
-  {
-    return m_nOutInterests;
-  }
-
-  /// outgoing Data
-  const PacketCounter&
-  getNOutDatas() const
-  {
-    return m_nOutDatas;
-  }
-
-  PacketCounter&
-  getNOutDatas()
-  {
-    return m_nOutDatas;
-  }
-
-protected:
-  /** \brief copy current obseverations to a struct
-   *  \param recipient an object with set methods for counters
-   */
-  template<typename R>
-  void
-  copyTo(R& recipient) const
-  {
-    recipient.setNInInterests(this->getNInInterests());
-    recipient.setNInDatas(this->getNInDatas());
-    recipient.setNOutInterests(this->getNOutInterests());
-    recipient.setNOutDatas(this->getNOutDatas());
-  }
-
-private:
-  PacketCounter m_nInInterests;
-  PacketCounter m_nInDatas;
-  PacketCounter m_nOutInterests;
-  PacketCounter m_nOutDatas;
-};
-
-/** \brief contains link layer byte counters
- */
-class LinkLayerCounters : noncopyable
-{
-public:
-  /// received bytes
-  const ByteCounter&
-  getNInBytes() const
-  {
-    return m_nInBytes;
-  }
-
-  ByteCounter&
-  getNInBytes()
-  {
-    return m_nInBytes;
-  }
-
-  /// sent bytes
-  const ByteCounter&
-  getNOutBytes() const
-  {
-    return m_nOutBytes;
-  }
-
-  ByteCounter&
-  getNOutBytes()
-  {
-    return m_nOutBytes;
-  }
-
-protected:
-  /** \brief copy current obseverations to a struct
-   *  \param recipient an object with set methods for counters
-   */
-  template<typename R>
-  void
-  copyTo(R& recipient) const
-  {
-    recipient.setNInBytes(this->getNInBytes());
-    recipient.setNOutBytes(this->getNOutBytes());
-  }
-
-private:
-  ByteCounter m_nInBytes;
-  ByteCounter m_nOutBytes;
-};
-
-/** \brief contains counters on face (2014 face architecture)
- */
-class OldFaceCounters : public NetworkLayerCounters, public LinkLayerCounters
-{
-public:
-  /** \brief copy current obseverations to a struct
-   *  \param recipient an object with set methods for counters
-   */
-  template<typename R>
-  void
-  copyTo(R& recipient) const
-  {
-    this->NetworkLayerCounters::copyTo(recipient);
-    this->LinkLayerCounters::copyTo(recipient);
-  }
-};
-
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_OLD_FACE_COUNTERS_HPP
diff --git a/daemon/face/tcp-channel.cpp b/daemon/face/tcp-channel.cpp
index f9873c2..21943c8 100644
--- a/daemon/face/tcp-channel.cpp
+++ b/daemon/face/tcp-channel.cpp
@@ -99,7 +99,7 @@
                        const FaceCreatedCallback& onFaceCreated,
                        bool isOnDemand)
 {
-  shared_ptr<face::LpFaceWrapper> face;
+  shared_ptr<Face> face;
   tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
 
   auto it = m_channelFaces.find(remoteEndpoint);
@@ -108,14 +108,14 @@
                                   : ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
     auto linkService = make_unique<face::GenericLinkService>();
     auto transport = make_unique<face::TcpTransport>(std::move(socket), persistency);
-    auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
-    face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
+    face = make_shared<Face>(std::move(linkService), std::move(transport));
 
-    face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
-      NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
-      m_channelFaces.erase(remoteEndpoint);
-    });
     m_channelFaces[remoteEndpoint] = face;
+    connectFaceClosedSignal(*face,
+      [this, remoteEndpoint] {
+        NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
+        m_channelFaces.erase(remoteEndpoint);
+      });
   }
   else {
     // we already have a face for this endpoint, just reuse it
diff --git a/daemon/face/tcp-channel.hpp b/daemon/face/tcp-channel.hpp
index 799fbf1..c819014 100644
--- a/daemon/face/tcp-channel.hpp
+++ b/daemon/face/tcp-channel.hpp
@@ -27,7 +27,6 @@
 #define NFD_DAEMON_FACE_TCP_CHANNEL_HPP
 
 #include "channel.hpp"
-#include "lp-face-wrapper.hpp"
 #include "core/scheduler.hpp"
 
 namespace nfd {
@@ -114,7 +113,7 @@
                        const FaceCreationFailedCallback& onConnectFailed);
 
 private:
-  std::map<tcp::Endpoint, shared_ptr<face::LpFaceWrapper>> m_channelFaces;
+  std::map<tcp::Endpoint, shared_ptr<Face>> m_channelFaces;
 
   tcp::Endpoint m_localEndpoint;
   boost::asio::ip::tcp::acceptor m_acceptor;
diff --git a/daemon/face/transport.cpp b/daemon/face/transport.cpp
index e3e1e07..2d2c3dd 100644
--- a/daemon/face/transport.cpp
+++ b/daemon/face/transport.cpp
@@ -24,8 +24,7 @@
  */
 
 #include "transport.hpp"
-#include "lp-face.hpp"
-#include "link-service.hpp"
+#include "face.hpp"
 
 namespace nfd {
 namespace face {
@@ -73,7 +72,7 @@
 }
 
 void
-Transport::setFaceAndLinkService(LpFace& face, LinkService& service)
+Transport::setFaceAndLinkService(Face& face, LinkService& service)
 {
   BOOST_ASSERT(m_face == nullptr);
   BOOST_ASSERT(m_service == nullptr);
@@ -190,7 +189,7 @@
 operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh)
 {
   const Transport& transport = flh.obj;
-  const LpFace* face = transport.getFace();
+  const Face* face = transport.getFace();
   FaceId faceId = face == nullptr ? INVALID_FACEID : face->getId();
 
   os << "[id=" << faceId << ",local=" << transport.getLocalUri()
diff --git a/daemon/face/transport.hpp b/daemon/face/transport.hpp
index 626809c..56ff730 100644
--- a/daemon/face/transport.hpp
+++ b/daemon/face/transport.hpp
@@ -33,7 +33,7 @@
 namespace nfd {
 namespace face {
 
-class LpFace;
+class Face;
 class LinkService;
 
 /** \brief indicates the state of a transport
@@ -98,8 +98,8 @@
  */
 const ssize_t MTU_INVALID = -2;
 
-/** \brief the lower part of an LpFace
- *  \sa LpFace
+/** \brief the lower part of a Face
+ *  \sa Face
  */
 class Transport : protected virtual TransportCounters, noncopyable
 {
@@ -154,11 +154,11 @@
    *  \pre setFaceAndLinkService has not been called
    */
   void
-  setFaceAndLinkService(LpFace& face, LinkService& service);
+  setFaceAndLinkService(Face& face, LinkService& service);
 
   /** \return Face to which this Transport is attached
    */
-  const LpFace*
+  const Face*
   getFace() const;
 
   /** \return LinkService to which this Transport is attached
@@ -307,7 +307,7 @@
   doSend(Packet&& packet) = 0;
 
 private:
-  LpFace* m_face;
+  Face* m_face;
   LinkService* m_service;
   FaceUri m_localUri;
   FaceUri m_remoteUri;
@@ -318,7 +318,7 @@
   TransportState m_state;
 };
 
-inline const LpFace*
+inline const Face*
 Transport::getFace() const
 {
   return m_face;
diff --git a/daemon/face/udp-channel.cpp b/daemon/face/udp-channel.cpp
index bb6529f..e6d65df 100644
--- a/daemon/face/udp-channel.cpp
+++ b/daemon/face/udp-channel.cpp
@@ -120,7 +120,7 @@
   NFD_LOG_DEBUG("[" << m_localEndpoint << "] New peer " << m_remoteEndpoint);
 
   bool isCreated = false;
-  shared_ptr<face::LpFaceWrapper> face;
+  shared_ptr<Face> face;
   try {
     std::tie(isCreated, face) = createFace(m_remoteEndpoint, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
   }
@@ -136,12 +136,12 @@
     onFaceCreated(face);
 
   // dispatch the datagram to the face for processing
-  static_cast<face::UnicastUdpTransport*>(face->getLpFace()->getTransport())->receiveDatagram(m_inputBuffer, nBytesReceived, error);
+  static_cast<face::UnicastUdpTransport*>(face->getTransport())->receiveDatagram(m_inputBuffer, nBytesReceived, error);
 
   this->waitForNewPeer(onFaceCreated, onReceiveFailed);
 }
 
-std::pair<bool, shared_ptr<face::LpFaceWrapper>>
+std::pair<bool, shared_ptr<Face>>
 UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersistency persistency)
 {
   auto it = m_channelFaces.find(remoteEndpoint);
@@ -166,13 +166,13 @@
 
   auto linkService = make_unique<face::GenericLinkService>();
   auto transport = make_unique<face::UnicastUdpTransport>(std::move(socket), persistency, m_idleFaceTimeout);
-  auto face = make_shared<face::LpFaceWrapper>(make_unique<face::LpFace>(
-                                               std::move(linkService), std::move(transport)));
+  auto face = make_shared<Face>(std::move(linkService), std::move(transport));
 
   face->setPersistency(persistency);
 
   m_channelFaces[remoteEndpoint] = face;
-  face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
+  connectFaceClosedSignal(*face,
+    [this, remoteEndpoint] {
       NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
       m_channelFaces.erase(remoteEndpoint);
     });
diff --git a/daemon/face/udp-channel.hpp b/daemon/face/udp-channel.hpp
index a24d1ec..a2506d4 100644
--- a/daemon/face/udp-channel.hpp
+++ b/daemon/face/udp-channel.hpp
@@ -27,7 +27,6 @@
 #define NFD_DAEMON_FACE_UDP_CHANNEL_HPP
 
 #include "channel.hpp"
-#include "lp-face-wrapper.hpp"
 
 namespace nfd {
 
@@ -105,11 +104,11 @@
                 const FaceCreatedCallback& onFaceCreated,
                 const FaceCreationFailedCallback& onReceiveFailed);
 
-  std::pair<bool, shared_ptr<face::LpFaceWrapper>>
+  std::pair<bool, shared_ptr<Face>>
   createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersistency persistency);
 
 private:
-  std::map<udp::Endpoint, shared_ptr<face::LpFaceWrapper>> m_channelFaces;
+  std::map<udp::Endpoint, shared_ptr<Face>> m_channelFaces;
 
   udp::Endpoint m_localEndpoint;
 
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index 2a39e36..cc60a63 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -25,7 +25,6 @@
 
 #include "udp-factory.hpp"
 #include "generic-link-service.hpp"
-#include "lp-face-wrapper.hpp"
 #include "multicast-udp-transport.hpp"
 #include "core/global-io.hpp"
 #include "core/network-interface.hpp"
@@ -127,7 +126,7 @@
   return createChannel(endpoint, timeout);
 }
 
-shared_ptr<face::LpFaceWrapper>
+shared_ptr<Face>
 UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
                                 const udp::Endpoint& multicastEndpoint,
                                 const std::string& networkInterfaceName/* = ""*/)
@@ -210,18 +209,15 @@
   auto transport = make_unique<face::MulticastUdpTransport>(localEndpoint, multicastEndpoint,
                                                             std::move(receiveSocket),
                                                             std::move(sendSocket));
-  auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
-  face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
+  face = make_shared<Face>(std::move(linkService), std::move(transport));
 
-  face->onFail.connectSingleShot([this, localEndpoint] (const std::string& reason) {
-    m_multicastFaces.erase(localEndpoint);
-  });
   m_multicastFaces[localEndpoint] = face;
+  connectFaceClosedSignal(*face, [this, localEndpoint] { m_multicastFaces.erase(localEndpoint); });
 
   return face;
 }
 
-shared_ptr<face::LpFaceWrapper>
+shared_ptr<Face>
 UdpFactory::createMulticastFace(const std::string& localIp,
                                 const std::string& multicastIp,
                                 const std::string& multicastPort,
@@ -294,7 +290,7 @@
     return nullptr;
 }
 
-shared_ptr<face::LpFaceWrapper>
+shared_ptr<Face>
 UdpFactory::findMulticastFace(const udp::Endpoint& localEndpoint) const
 {
   auto i = m_multicastFaces.find(localEndpoint);
diff --git a/daemon/face/udp-factory.hpp b/daemon/face/udp-factory.hpp
index 134c5ee..9c851bd 100644
--- a/daemon/face/udp-factory.hpp
+++ b/daemon/face/udp-factory.hpp
@@ -49,7 +49,7 @@
     }
   };
 
-  typedef std::map<udp::Endpoint, shared_ptr<face::LpFaceWrapper>> MulticastFaceMap;
+  typedef std::map<udp::Endpoint, shared_ptr<Face>> MulticastFaceMap;
 
   /**
    * \brief Create UDP-based channel using udp::Endpoint
@@ -128,12 +128,12 @@
    * \see http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/ip__udp/endpoint.html
    *      for details on ways to create udp::Endpoint
    */
-  shared_ptr<face::LpFaceWrapper>
+  shared_ptr<Face>
   createMulticastFace(const udp::Endpoint& localEndpoint,
                       const udp::Endpoint& multicastEndpoint,
                       const std::string& networkInterfaceName = "");
 
-  shared_ptr<face::LpFaceWrapper>
+  shared_ptr<Face>
   createMulticastFace(const std::string& localIp,
                       const std::string& multicastIp,
                       const std::string& multicastPort,
@@ -181,7 +181,7 @@
    * \returns shared pointer to the existing multicast UdpFace object
    *          or nullptr when such face does not exist
    */
-  shared_ptr<face::LpFaceWrapper>
+  shared_ptr<Face>
   findMulticastFace(const udp::Endpoint& localEndpoint) const;
 
 private:
diff --git a/daemon/face/unix-stream-channel.cpp b/daemon/face/unix-stream-channel.cpp
index c34ad7b..5b56c6a 100644
--- a/daemon/face/unix-stream-channel.cpp
+++ b/daemon/face/unix-stream-channel.cpp
@@ -25,7 +25,6 @@
 
 #include "unix-stream-channel.hpp"
 #include "generic-link-service.hpp"
-#include "lp-face-wrapper.hpp"
 #include "unix-stream-transport.hpp"
 #include "core/global-io.hpp"
 
@@ -135,8 +134,7 @@
 
   auto linkService = make_unique<face::GenericLinkService>();
   auto transport = make_unique<face::UnixStreamTransport>(std::move(m_socket));
-  auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
-  auto face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
+  auto face = make_shared<Face>(std::move(linkService), std::move(transport));
   onFaceCreated(face);
 
   // prepare accepting the next connection
diff --git a/daemon/face/websocket-channel.cpp b/daemon/face/websocket-channel.cpp
index 520bb7d..75626ab 100644
--- a/daemon/face/websocket-channel.cpp
+++ b/daemon/face/websocket-channel.cpp
@@ -77,7 +77,7 @@
 {
   auto it = m_channelFaces.find(hdl);
   if (it != m_channelFaces.end()) {
-    static_cast<face::WebSocketTransport*>(it->second->getLpFace()->getTransport())->handlePongTimeout();
+    static_cast<face::WebSocketTransport*>(it->second->getTransport())->handlePongTimeout();
   }
   else {
     NFD_LOG_WARN("Pong timeout on unknown transport");
@@ -89,7 +89,7 @@
 {
   auto it = m_channelFaces.find(hdl);
   if (it != m_channelFaces.end()) {
-    static_cast<face::WebSocketTransport*>(it->second->getLpFace()->getTransport())->handlePong();
+    static_cast<face::WebSocketTransport*>(it->second->getTransport())->handlePong();
   }
   else {
     NFD_LOG_WARN("Pong received on unknown transport");
@@ -102,7 +102,7 @@
 {
   auto it = m_channelFaces.find(hdl);
   if (it != m_channelFaces.end()) {
-    static_cast<face::WebSocketTransport*>(it->second->getLpFace()->getTransport())->receiveMessage(msg->get_payload());
+    static_cast<face::WebSocketTransport*>(it->second->getTransport())->receiveMessage(msg->get_payload());
   }
   else {
     NFD_LOG_WARN("Message received on unknown transport");
@@ -114,16 +114,10 @@
 {
   auto linkService = make_unique<face::GenericLinkService>();
   auto transport = make_unique<face::WebSocketTransport>(hdl, ref(m_server), m_pingInterval);
-  auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
-  auto face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
+  auto face = make_shared<Face>(std::move(linkService), std::move(transport));
 
-  face->getLpFace()->afterStateChange.connect(
-    [this, hdl] (face::FaceState oldState, face::FaceState newState) {
-      if (newState == face::FaceState::CLOSED) {
-        m_channelFaces.erase(hdl);
-      }
-    });
   m_channelFaces[hdl] = face;
+  connectFaceClosedSignal(*face, [this, hdl] { m_channelFaces.erase(hdl); });
 
   m_onFaceCreatedCallback(face);
 }
@@ -133,7 +127,7 @@
 {
   auto it = m_channelFaces.find(hdl);
   if (it != m_channelFaces.end()) {
-    it->second->getLpFace()->close();
+    it->second->close();
   }
   else {
     NFD_LOG_WARN("Close on unknown transport");
diff --git a/daemon/face/websocket-channel.hpp b/daemon/face/websocket-channel.hpp
index 47eda8c..1d56731 100644
--- a/daemon/face/websocket-channel.hpp
+++ b/daemon/face/websocket-channel.hpp
@@ -1,12 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014  Regents of the University of California,
- *                     Arizona Board of Regents,
- *                     Colorado State University,
- *                     University Pierre & Marie Curie, Sorbonne University,
- *                     Washington University in St. Louis,
- *                     Beijing Institute of Technology,
- *                     The University of Memphis
+ * Copyright (c) 2014-2015,  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.
@@ -21,13 +21,12 @@
  *
  * 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_DAEMON_FACE_WEBSOCKET_CHANNEL_HPP
 #define NFD_DAEMON_FACE_WEBSOCKET_CHANNEL_HPP
 
 #include "channel.hpp"
-#include "lp-face-wrapper.hpp"
 #include "websocketpp.hpp"
 
 namespace nfd {
@@ -102,7 +101,7 @@
   websocket::Endpoint m_localEndpoint;
   websocket::Server m_server;
 
-  std::map<websocketpp::connection_hdl, shared_ptr<face::LpFaceWrapper>,
+  std::map<websocketpp::connection_hdl, shared_ptr<Face>,
            std::owner_less<websocketpp::connection_hdl>> m_channelFaces;
 
   FaceCreatedCallback m_onFaceCreatedCallback;
diff --git a/daemon/fw/access-strategy.cpp b/daemon/fw/access-strategy.cpp
index 5489837..b1ed449 100644
--- a/daemon/fw/access-strategy.cpp
+++ b/daemon/fw/access-strategy.cpp
@@ -115,7 +115,7 @@
 AccessStrategy::sendToLastNexthop(const Face& inFace, shared_ptr<pit::Entry> pitEntry, MtInfo& mi,
                                   shared_ptr<fib::Entry> fibEntry)
 {
-  if (mi.lastNexthop == INVALID_FACEID) {
+  if (mi.lastNexthop == face::INVALID_FACEID) {
     NFD_LOG_DEBUG(pitEntry->getInterest() << " no-last-nexthop");
     return false;
   }
@@ -231,7 +231,7 @@
 }
 
 AccessStrategy::MtInfo::MtInfo()
-  : lastNexthop(INVALID_FACEID)
+  : lastNexthop(face::INVALID_FACEID)
   , rtt(1, time::milliseconds(1), 0.1)
 {
 }
diff --git a/daemon/fw/client-control-strategy.cpp b/daemon/fw/client-control-strategy.cpp
index 7cc07fd..1066efa 100644
--- a/daemon/fw/client-control-strategy.cpp
+++ b/daemon/fw/client-control-strategy.cpp
@@ -58,7 +58,7 @@
 
   FaceId outFaceId = static_cast<FaceId>(*tag);
   shared_ptr<Face> outFace = this->getFace(outFaceId);
-  if (!static_cast<bool>(outFace)) {
+  if (outFace == nullptr) {
     // If outFace doesn't exist, it's better to reject the Interest
     // than to use BestRouteStrategy.
     NFD_LOG_WARN("Interest " << interest.getName() <<
diff --git a/daemon/fw/face-table.cpp b/daemon/fw/face-table.cpp
index a8a8053..b4bda23 100644
--- a/daemon/fw/face-table.cpp
+++ b/daemon/fw/face-table.cpp
@@ -27,6 +27,7 @@
 #include "forwarder.hpp"
 #include "core/global-io.hpp"
 #include "core/logger.hpp"
+#include "face/channel.hpp"
 
 namespace nfd {
 
@@ -34,7 +35,7 @@
 
 FaceTable::FaceTable(Forwarder& forwarder)
   : m_forwarder(forwarder)
-  , m_lastFaceId(FACEID_RESERVED_MAX)
+  , m_lastFaceId(face::FACEID_RESERVED_MAX)
 {
 }
 
@@ -59,22 +60,22 @@
 void
 FaceTable::add(shared_ptr<Face> face)
 {
-  if (face->getId() != INVALID_FACEID && m_faces.count(face->getId()) > 0) {
+  if (face->getId() != face::INVALID_FACEID && m_faces.count(face->getId()) > 0) {
     NFD_LOG_WARN("Trying to add existing face id=" << face->getId() << " to the face table");
     return;
   }
 
   FaceId faceId = ++m_lastFaceId;
-  BOOST_ASSERT(faceId > FACEID_RESERVED_MAX);
+  BOOST_ASSERT(faceId > face::FACEID_RESERVED_MAX);
   this->addImpl(face, faceId);
 }
 
 void
 FaceTable::addReserved(shared_ptr<Face> face, FaceId faceId)
 {
-  BOOST_ASSERT(face->getId() == INVALID_FACEID);
+  BOOST_ASSERT(face->getId() == face::INVALID_FACEID);
   BOOST_ASSERT(m_faces.count(face->getId()) == 0);
-  BOOST_ASSERT(faceId <= FACEID_RESERVED_MAX);
+  BOOST_ASSERT(faceId <= face::FACEID_RESERVED_MAX);
   this->addImpl(face, faceId);
 }
 
@@ -86,30 +87,26 @@
   NFD_LOG_INFO("Added face id=" << faceId << " remote=" << face->getRemoteUri()
                                           << " local=" << face->getLocalUri());
 
-  face->onReceiveInterest.connect(bind(&Forwarder::startProcessInterest,
-                                       &m_forwarder, ref(*face), _1));
-  face->onReceiveData.connect(bind(&Forwarder::startProcessData,
-                                   &m_forwarder, ref(*face), _1));
-  face->onReceiveNack.connect(bind(&Forwarder::startProcessNack,
-                                   &m_forwarder, ref(*face), _1));
-  face->onFail.connectSingleShot(bind(&FaceTable::remove, this, face, _1));
+  face->afterReceiveInterest.connect(bind(&Forwarder::startProcessInterest, &m_forwarder, ref(*face), _1));
+  face->afterReceiveData.connect(bind(&Forwarder::startProcessData, &m_forwarder, ref(*face), _1));
+  face->afterReceiveNack.connect(bind(&Forwarder::startProcessNack, &m_forwarder, ref(*face), _1));
+  connectFaceClosedSignal(*face, bind(&FaceTable::remove, this, face));
 
-  this->onAdd(face);
+  this->afterAdd(face);
 }
 
 void
-FaceTable::remove(shared_ptr<Face> face, const std::string& reason)
+FaceTable::remove(shared_ptr<Face> face)
 {
-  this->onRemove(face);
+  this->beforeRemove(face);
 
   FaceId faceId = face->getId();
   m_faces.erase(faceId);
-  face->setId(INVALID_FACEID);
+  face->setId(face::INVALID_FACEID);
 
   NFD_LOG_INFO("Removed face id=" << faceId <<
                " remote=" << face->getRemoteUri() <<
-               " local=" << face->getLocalUri() <<
-               " (" << reason << ")");
+               " local=" << face->getLocalUri());
 
   m_forwarder.getFib().removeNextHopFromAllEntries(face);
 
diff --git a/daemon/fw/face-table.hpp b/daemon/fw/face-table.hpp
index 67c7932..a9186f6 100644
--- a/daemon/fw/face-table.hpp
+++ b/daemon/fw/face-table.hpp
@@ -1,12 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014,  Regents of the University of California,
- *                      Arizona Board of Regents,
- *                      Colorado State University,
- *                      University Pierre & Marie Curie, Sorbonne University,
- *                      Washington University in St. Louis,
- *                      Beijing Institute of Technology,
- *                      The University of Memphis
+ * Copyright (c) 2014-2015,  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.
@@ -75,22 +75,20 @@
 public: // signals
   /** \brief fires after a Face is added
    */
-  signal::Signal<FaceTable, shared_ptr<Face>> onAdd;
+  signal::Signal<FaceTable, shared_ptr<Face>> afterAdd;
 
   /** \brief fires before a Face is removed
    *
    *  FaceId is valid when this event is fired
    */
-  signal::Signal<FaceTable, shared_ptr<Face>> onRemove;
+  signal::Signal<FaceTable, shared_ptr<Face>> beforeRemove;
 
 private:
   void
   addImpl(shared_ptr<Face> face, FaceId faceId);
 
-  // remove is private because it's a handler of face.onFail signal.
-  // face->close() closes the face and triggers .remove()
   void
-  remove(shared_ptr<Face> face, const std::string& reason);
+  remove(shared_ptr<Face> face);
 
   ForwardRange
   getForwardRange() const;
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index e96b87b..280c713 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -108,7 +108,7 @@
   ++m_counters.nInInterests;
 
   // /localhost scope control
-  bool isViolatingLocalhost = !inFace.isLocal() &&
+  bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
                               LOCALHOST_NAME.isPrefixOf(interest.getName());
   if (isViolatingLocalhost) {
     NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
@@ -151,7 +151,7 @@
                           shared_ptr<pit::Entry> pitEntry)
 {
   // if multi-access face, drop
-  if (inFace.isMultiAccess()) {
+  if (inFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
     NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
                   " interest=" << interest.getName() <<
                   " drop");
@@ -244,7 +244,7 @@
 {
   NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
 
-  data.setTag(make_shared<lp::IncomingFaceIdTag>(FACEID_CONTENT_STORE));
+  data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
   // XXX should we lookup PIT for other Interests that also match csMatch?
 
   // set PIT straggler timer
@@ -284,7 +284,7 @@
 Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
                               bool wantNewNonce)
 {
-  if (outFace.getId() == INVALID_FACEID) {
+  if (outFace.getId() == face::INVALID_FACEID) {
     NFD_LOG_WARN("onOutgoingInterest face=invalid interest=" << pitEntry->getName());
     return;
   }
@@ -374,7 +374,7 @@
   ++m_counters.nInData;
 
   // /localhost scope control
-  bool isViolatingLocalhost = !inFace.isLocal() &&
+  bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
                               LOCALHOST_NAME.isPrefixOf(data.getName());
   if (isViolatingLocalhost) {
     NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
@@ -439,7 +439,7 @@
 Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
 {
   // accept to cache?
-  bool acceptToCache = inFace.isLocal();
+  bool acceptToCache = inFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL;
   if (acceptToCache) {
     // CS insert
     m_cs.insert(data, true);
@@ -453,14 +453,14 @@
 void
 Forwarder::onOutgoingData(const Data& data, Face& outFace)
 {
-  if (outFace.getId() == INVALID_FACEID) {
+  if (outFace.getId() == face::INVALID_FACEID) {
     NFD_LOG_WARN("onOutgoingData face=invalid data=" << data.getName());
     return;
   }
   NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
 
   // /localhost scope control
-  bool isViolatingLocalhost = !outFace.isLocal() &&
+  bool isViolatingLocalhost = outFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
                               LOCALHOST_NAME.isPrefixOf(data.getName());
   if (isViolatingLocalhost) {
     NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
@@ -484,7 +484,7 @@
   ++m_counters.nInNacks;
 
   // if multi-access face, drop
-  if (inFace.isMultiAccess()) {
+  if (inFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
     NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
                   " nack=" << nack.getInterest().getName() <<
                   "~" << nack.getReason() << " face-is-multi-access");
@@ -537,7 +537,7 @@
 Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
                           const lp::NackHeader& nack)
 {
-  if (outFace.getId() == INVALID_FACEID) {
+  if (outFace.getId() == face::INVALID_FACEID) {
     NFD_LOG_WARN("onOutgoingNack face=invalid" <<
                   " nack=" << pitEntry->getInterest().getName() <<
                   "~" << nack.getReason() << " no-in-record");
@@ -556,7 +556,7 @@
   }
 
   // if multi-access face, drop
-  if (outFace.isMultiAccess()) {
+  if (outFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
     NFD_LOG_DEBUG("onOutgoingNack face=" << outFace.getId() <<
                   " nack=" << pitEntry->getInterest().getName() <<
                   "~" << nack.getReason() << " face-is-multi-access");
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index 7b0504e..00fe82f 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -33,8 +33,8 @@
 NFD_LOG_INIT("Strategy");
 
 Strategy::Strategy(Forwarder& forwarder, const Name& name)
-  : afterAddFace(forwarder.getFaceTable().onAdd)
-  , beforeRemoveFace(forwarder.getFaceTable().onRemove)
+  : afterAddFace(forwarder.getFaceTable().afterAdd)
+  , beforeRemoveFace(forwarder.getFaceTable().beforeRemove)
   , m_name(name)
   , m_forwarder(forwarder)
   , m_measurements(m_forwarder.getMeasurements(),
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index d773206..0cc40d5 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -27,7 +27,6 @@
 
 #include "core/network-interface.hpp"
 #include "face/generic-link-service.hpp"
-#include "face/lp-face-wrapper.hpp"
 #include "face/tcp-factory.hpp"
 #include "face/udp-factory.hpp"
 #include "fw/face-table.hpp"
@@ -77,9 +76,9 @@
 
   auto postNotification = registerNotificationStream("events");
   m_faceAddConn =
-    m_faceTable.onAdd.connect(bind(&FaceManager::afterFaceAdded, this, _1, postNotification));
+    m_faceTable.afterAdd.connect(bind(&FaceManager::afterFaceAdded, this, _1, postNotification));
   m_faceRemoveConn =
-    m_faceTable.onRemove.connect(bind(&FaceManager::afterFaceRemoved, this, _1, postNotification));
+    m_faceTable.beforeRemove.connect(bind(&FaceManager::afterFaceRemoved, this, _1, postNotification));
 }
 
 void
@@ -173,15 +172,14 @@
                                 const ControlParameters& parameters,
                                 const ndn::mgmt::CommandContinuation& done)
 {
-  auto result = extractLocalControlParameters(interest, parameters, done);
-  if (!result.isValid) {
+  Face* face = findFaceForLocalControl(interest, parameters, done);
+  if (!face) {
     return;
   }
 
   // TODO#3226 redesign enable-local-control
   // For now, enable-local-control will enable all local fields in GenericLinkService.
-  BOOST_ASSERT(result.lpFace != nullptr);
-  auto service = dynamic_cast<face::GenericLinkService*>(result.lpFace->getLinkService());
+  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
   if (service == nullptr) {
     return done(ControlResponse(503, "LinkService type not supported"));
   }
@@ -199,15 +197,14 @@
                                  const ControlParameters& parameters,
                                  const ndn::mgmt::CommandContinuation& done)
 {
-  auto result = extractLocalControlParameters(interest, parameters, done);
-  if (!result.isValid) {
+  Face* face = findFaceForLocalControl(interest, parameters, done);
+  if (!face) {
     return;
   }
 
   // TODO#3226 redesign disable-local-control
   // For now, disable-local-control will disable all local fields in GenericLinkService.
-  BOOST_ASSERT(result.lpFace != nullptr);
-  auto service = dynamic_cast<face::GenericLinkService*>(result.lpFace->getLinkService());
+  auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
   if (service == nullptr) {
     return done(ControlResponse(503, "LinkService type not supported"));
   }
@@ -220,15 +217,11 @@
               .setBody(parameters.wireEncode()));
 }
 
-FaceManager::ExtractLocalControlParametersResult
-FaceManager::extractLocalControlParameters(const Interest& request,
-                                           const ControlParameters& parameters,
-                                           const ndn::mgmt::CommandContinuation& done)
+Face*
+FaceManager::findFaceForLocalControl(const Interest& request,
+                                     const ControlParameters& parameters,
+                                     const ndn::mgmt::CommandContinuation& done)
 {
-  ExtractLocalControlParametersResult result;
-  result.isValid = false;
-  result.lpFace = nullptr;
-
   shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = request.getTag<lp::IncomingFaceIdTag>();
   // NDNLPv2 says "application MUST be prepared to receive a packet without IncomingFaceId field",
   // but it's fine to assert IncomingFaceId is available, because InternalFace lives inside NFD
@@ -239,22 +232,16 @@
   if (face == nullptr) {
     NFD_LOG_DEBUG("FaceId " << *incomingFaceIdTag << " not found");
     done(ControlResponse(410, "Face not found"));
-    return result;
+    return nullptr;
   }
 
-  if (!face->isLocal()) {
+  if (face->getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
     NFD_LOG_DEBUG("Cannot enable local control on non-local FaceId " << face->getId());
     done(ControlResponse(412, "Face is non-local"));
-    return result;
+    return nullptr;
   }
 
-  result.isValid = true;
-  auto lpFaceW = dynamic_pointer_cast<face::LpFaceWrapper>(face);
-  // LocalFace is gone, so a face that is local must be an LpFace.
-  BOOST_ASSERT(lpFaceW != nullptr);
-  result.lpFace = lpFaceW->getLpFace();
-
-  return result;
+  return face.get();
 }
 
 void
@@ -345,7 +332,7 @@
   }
 
   if (filter.hasFaceScope() &&
-      (filter.getFaceScope() == ndn::nfd::FACE_SCOPE_LOCAL) != face->isLocal()) {
+      filter.getFaceScope() != face->getScope()) {
     return false;
   }
 
@@ -355,7 +342,7 @@
   }
 
   if (filter.hasLinkType() &&
-      (filter.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) != face->isMultiAccess()) {
+      filter.getLinkType() != face->getLinkType()) {
     return false;
   }
 
@@ -363,8 +350,8 @@
 }
 
 template<typename FaceTraits>
-inline void
-collectLpFaceProperties(const face::LpFace& face, FaceTraits& traits)
+void
+FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
 {
   traits.setFaceId(face.getId())
         .setRemoteUri(face.getRemoteUri().toString())
@@ -372,27 +359,6 @@
         .setFaceScope(face.getScope())
         .setFacePersistency(face.getPersistency())
         .setLinkType(face.getLinkType());
-  // TODO#3172 replace this into FaceManager::collectFaceProperties
-}
-
-template<typename FaceTraits>
-void
-FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
-{
-  auto lpFace = dynamic_cast<const face::LpFace*>(&face);
-  if (lpFace != nullptr) {
-    collectLpFaceProperties(*lpFace, traits);
-    return;
-  }
-
-  traits.setFaceId(face.getId())
-        .setRemoteUri(face.getRemoteUri().toString())
-        .setLocalUri(face.getLocalUri().toString())
-        .setFaceScope(face.isLocal() ? ndn::nfd::FACE_SCOPE_LOCAL
-                                     : ndn::nfd::FACE_SCOPE_NON_LOCAL)
-        .setFacePersistency(face.getPersistency())
-        .setLinkType(face.isMultiAccess() ? ndn::nfd::LINK_TYPE_MULTI_ACCESS
-                                          : ndn::nfd::LINK_TYPE_POINT_TO_POINT);
 }
 
 void
@@ -717,7 +683,7 @@
       m_factories.insert(std::make_pair("udp6", factory));
     }
 
-    std::set<shared_ptr<face::LpFaceWrapper>> multicastFacesToRemove;
+    std::set<shared_ptr<Face>> multicastFacesToRemove;
     for (const auto& i : factory->getMulticastFaces()) {
       multicastFacesToRemove.insert(i.second);
     }
@@ -799,7 +765,7 @@
       m_factories.insert(std::make_pair("ether", factory));
     }
 
-    std::set<shared_ptr<face::LpFaceWrapper>> multicastFacesToRemove;
+    std::set<shared_ptr<Face>> multicastFacesToRemove;
     for (const auto& i : factory->getMulticastFaces()) {
       multicastFacesToRemove.insert(i.second);
     }
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index 8e90a73..c2f43bb 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -29,18 +29,14 @@
 #include "manager-base.hpp"
 #include <ndn-cxx/management/nfd-face-status.hpp>
 #include <ndn-cxx/management/nfd-face-query-filter.hpp>
+#include "face/face.hpp"
 
 namespace nfd {
 
-class Face;
 class FaceTable;
 class NetworkInterfaceInfo;
 class ProtocolFactory;
 
-namespace face {
-class LpFace;
-} // namespace face
-
 /**
  * @brief implement the Face Management of NFD Management Protocol.
  * @sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt
@@ -89,16 +85,10 @@
   afterCreateFaceFailure(const std::string& reason,
                          const ndn::mgmt::CommandContinuation& done);
 
-  struct ExtractLocalControlParametersResult
-  {
-    bool isValid;
-    face::LpFace* lpFace;
-  };
-
-  ExtractLocalControlParametersResult
-  extractLocalControlParameters(const Interest& request,
-                                const ControlParameters& parameters,
-                                const ndn::mgmt::CommandContinuation& done);
+  Face*
+  findFaceForLocalControl(const Interest& request,
+                          const ControlParameters& parameters,
+                          const ndn::mgmt::CommandContinuation& done);
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE: // StatusDataset
   void
diff --git a/daemon/nfd.cpp b/daemon/nfd.cpp
index bcc5926..5d9ce22 100644
--- a/daemon/nfd.cpp
+++ b/daemon/nfd.cpp
@@ -91,8 +91,8 @@
   initializeManagement();
 
   FaceTable& faceTable = m_forwarder->getFaceTable();
-  faceTable.addReserved(face::makeNullFace(), FACEID_NULL);
-  faceTable.addReserved(face::makeNullFace(FaceUri("contentstore://")), FACEID_CONTENT_STORE);
+  faceTable.addReserved(face::makeNullFace(), face::FACEID_NULL);
+  faceTable.addReserved(face::makeNullFace(FaceUri("contentstore://")), face::FACEID_CONTENT_STORE);
 
   PrivilegeHelper::drop();
 
@@ -145,7 +145,7 @@
 Nfd::initializeManagement()
 {
   std::tie(m_internalFace, m_internalClientFace) = face::makeInternalFace(m_keyChain);
-  m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
+  m_forwarder->getFaceTable().addReserved(m_internalFace, face::FACEID_INTERNAL_FACE);
   m_dispatcher.reset(new ndn::mgmt::Dispatcher(*m_internalClientFace, m_keyChain));
 
   m_validator.reset(new CommandValidator());
diff --git a/daemon/nfd.hpp b/daemon/nfd.hpp
index 57b5e8a..dd97cf4 100644
--- a/daemon/nfd.hpp
+++ b/daemon/nfd.hpp
@@ -34,19 +34,14 @@
 #include <ndn-cxx/util/network-monitor.hpp>
 
 namespace ndn {
-
 class Face;
-
 namespace mgmt {
-
 class Dispatcher;
-
-}
-}
+} // namespace mgmt
+} // namespace ndn
 
 namespace nfd {
 
-class Face;
 class Forwarder;
 class FibManager;
 class FaceManager;
@@ -54,6 +49,10 @@
 class ForwarderStatusManager;
 class CommandValidator;
 
+namespace face {
+class Face;
+} // namespace face
+
 /**
  * \brief Class representing NFD instance
  * This class can be used to initialize all components of NFD
@@ -110,7 +109,7 @@
   unique_ptr<Forwarder> m_forwarder;
 
   ndn::KeyChain&               m_keyChain;
-  shared_ptr<Face>             m_internalFace;
+  shared_ptr<face::Face>       m_internalFace;
   shared_ptr<ndn::Face>        m_internalClientFace;
   unique_ptr<CommandValidator> m_validator;
 
diff --git a/daemon/table/pit-entry.cpp b/daemon/table/pit-entry.cpp
index 85ea19c..22df4a4 100644
--- a/daemon/table/pit-entry.cpp
+++ b/daemon/table/pit-entry.cpp
@@ -1,12 +1,12 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014,  Regents of the University of California,
- *                      Arizona Board of Regents,
- *                      Colorado State University,
- *                      University Pierre & Marie Curie, Sorbonne University,
- *                      Washington University in St. Louis,
- *                      Beijing Institute of Technology,
- *                      The University of Memphis
+ * Copyright (c) 2014-2015,  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.
@@ -47,7 +47,7 @@
 Entry::hasLocalInRecord() const
 {
   return std::any_of(m_inRecords.begin(), m_inRecords.end(),
-                     [] (const InRecord& inRecord) { return inRecord.getFace()->isLocal(); });
+    [] (const InRecord& inRecord) { return inRecord.getFace()->getScope() == ndn::nfd::FACE_SCOPE_LOCAL; });
 }
 
 bool
@@ -78,14 +78,14 @@
 Entry::violatesScope(const Face& face) const
 {
   // /localhost scope
-  bool isViolatingLocalhost = !face.isLocal() &&
+  bool isViolatingLocalhost = face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
                               LOCALHOST_NAME.isPrefixOf(this->getName());
   if (isViolatingLocalhost) {
     return true;
   }
 
   // /localhop scope
-  bool isViolatingLocalhop = !face.isLocal() &&
+  bool isViolatingLocalhop = face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
                              LOCALHOP_NAME.isPrefixOf(this->getName()) &&
                              !this->hasLocalInRecord();
   if (isViolatingLocalhop) {