face: EthernetTransport

This commit replaces NDNLPv1 fragmentation and reassembly
with NDNLPv2 fragmentation and reassembly.

Change-Id: I10751157fcced94d441167ce470aaed79c12bb54
Refs: #3170
diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp
index 3d88590..3592530 100644
--- a/daemon/face/ethernet-factory.cpp
+++ b/daemon/face/ethernet-factory.cpp
@@ -24,16 +24,16 @@
  */
 
 #include "ethernet-factory.hpp"
-#include "face/ethernet-face.hpp"
-
-#include "core/logger.hpp"
+#include "ethernet-transport.hpp"
+#include "generic-link-service.hpp"
+#include "lp-face-wrapper.hpp"
 #include "core/global-io.hpp"
 
 namespace nfd {
 
-shared_ptr<EthernetFace>
+shared_ptr<face::LpFaceWrapper>
 EthernetFactory::createMulticastFace(const NetworkInterfaceInfo& interface,
-                                     const ethernet::Address &address)
+                                     const ethernet::Address& address)
 {
   if (!address.isMulticast())
     BOOST_THROW_EXCEPTION(Error(address.toString() + " is not a multicast address"));
@@ -42,8 +42,14 @@
   if (face)
     return face;
 
-  face = make_shared<EthernetFace>(boost::asio::posix::stream_descriptor(getGlobalIoService()),
-                                   interface, address);
+  face::GenericLinkService::Options opts;
+  opts.allowFragmentation = true;
+  opts.allowReassembly = true;
+
+  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));
 
   auto key = std::make_pair(interface.name, address);
   face->onFail.connectSingleShot([this, key] (const std::string& reason) {
@@ -69,7 +75,7 @@
   return {};
 }
 
-shared_ptr<EthernetFace>
+shared_ptr<face::LpFaceWrapper>
 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 c14e093..c0a951d 100644
--- a/daemon/face/ethernet-factory.hpp
+++ b/daemon/face/ethernet-factory.hpp
@@ -31,7 +31,9 @@
 
 namespace nfd {
 
-class EthernetFace;
+namespace face {
+class LpFaceWrapper;
+} // namespace face
 
 class EthernetFactory : public ProtocolFactory
 {
@@ -50,7 +52,7 @@
   };
 
   typedef std::map<std::pair<std::string, ethernet::Address>,
-                   shared_ptr<EthernetFace>> MulticastFaceMap;
+                   shared_ptr<face::LpFaceWrapper>> MulticastFaceMap;
 
   /**
    * \brief Create an EthernetFace to communicate with the given multicast group
@@ -65,9 +67,9 @@
    * \returns always a valid shared pointer to an EthernetFace object,
    *          an exception will be thrown if the creation fails
    *
-   * \throws EthernetFactory::Error or EthernetFace::Error
+   * \throws EthernetFactory::Error or EthernetTransport::Error
    */
-  shared_ptr<EthernetFace>
+  shared_ptr<face::LpFaceWrapper>
   createMulticastFace(const NetworkInterfaceInfo& interface,
                       const ethernet::Address& address);
 
@@ -94,7 +96,7 @@
    * \returns shared pointer to the existing EthernetFace object
    *          or nullptr when such face does not exist
    */
-  shared_ptr<EthernetFace>
+  shared_ptr<face::LpFaceWrapper>
   findMulticastFace(const std::string& interfaceName,
                     const ethernet::Address& address) const;
 
diff --git a/daemon/face/ethernet-face.cpp b/daemon/face/ethernet-transport.cpp
similarity index 62%
rename from daemon/face/ethernet-face.cpp
rename to daemon/face/ethernet-transport.cpp
index f31a8f6..5318097 100644
--- a/daemon/face/ethernet-face.cpp
+++ b/daemon/face/ethernet-transport.cpp
@@ -23,17 +23,17 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "ethernet-face.hpp"
+#include "ethernet-transport.hpp"
 #include "core/global-io.hpp"
 
 #include <pcap/pcap.h>
 
 #include <cerrno>         // for errno
-#include <cstring>        // for std::strerror() and std::strncpy()
-#include <stdio.h>        // for snprintf()
+#include <cstring>        // for memcpy(), strerror(), strncpy()
 #include <arpa/inet.h>    // for htons() and ntohs()
 #include <net/ethernet.h> // for struct ether_header
 #include <net/if.h>       // for struct ifreq
+#include <stdio.h>        // for snprintf()
 #include <sys/ioctl.h>    // for ioctl()
 #include <unistd.h>       // for dup()
 
@@ -57,28 +57,32 @@
 #endif
 
 namespace nfd {
+namespace face {
 
-NFD_LOG_INIT("EthernetFace");
+NFD_LOG_INIT("EthernetTransport");
 
-const time::nanoseconds EthernetFace::REASSEMBLER_LIFETIME = time::seconds(60);
-
-EthernetFace::EthernetFace(boost::asio::posix::stream_descriptor socket,
-                           const NetworkInterfaceInfo& interface,
-                           const ethernet::Address& address)
-  : Face(FaceUri(address), FaceUri::fromDev(interface.name), false, true)
-  , m_pcap(nullptr, pcap_close)
-  , m_socket(std::move(socket))
+EthernetTransport::EthernetTransport(const NetworkInterfaceInfo& interface,
+                                     const ethernet::Address& mcastAddress)
+  : m_pcap(nullptr, pcap_close)
+  , m_socket(getGlobalIoService())
+  , m_srcAddress(interface.etherAddress)
+  , m_destAddress(mcastAddress)
+  , m_interfaceName(interface.name)
 #if defined(__linux__)
   , m_interfaceIndex(interface.index)
 #endif
-  , m_interfaceName(interface.name)
-  , m_srcAddress(interface.etherAddress)
-  , m_destAddress(address)
 #ifdef _DEBUG
   , m_nDropped(0)
 #endif
 {
-  NFD_LOG_FACE_INFO("Creating face on " << m_interfaceName << "/" << m_srcAddress);
+  this->setLocalUri(FaceUri::fromDev(interface.name));
+  this->setRemoteUri(FaceUri(mcastAddress));
+  this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
+  this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+  this->setLinkType(ndn::nfd::LINK_TYPE_MULTI_ACCESS);
+
+  NFD_LOG_FACE_INFO("Creating transport");
+
   pcapInit();
 
   int fd = pcap_get_selectable_fd(m_pcap.get());
@@ -90,10 +94,8 @@
   // same fd and one of them will fail
   m_socket.assign(::dup(fd));
 
-  m_interfaceMtu = getInterfaceMtu();
-  NFD_LOG_FACE_DEBUG("Interface MTU is: " << m_interfaceMtu);
-
-  m_slicer.reset(new ndnlp::Slicer(m_interfaceMtu));
+  // do this after assigning m_socket because getInterfaceMtu uses it
+  this->setMtu(getInterfaceMtu());
 
   char filter[100];
   // std::snprintf not found in some environments
@@ -105,62 +107,54 @@
            m_srcAddress.toString().c_str());
   setPacketFilter(filter);
 
-  if (!m_destAddress.isBroadcast() && !joinMulticastGroup())
-    {
-      NFD_LOG_FACE_WARN("Falling back to promiscuous mode");
-      pcap_set_promisc(m_pcap.get(), 1);
-    }
+  if (!m_destAddress.isBroadcast() && !joinMulticastGroup()) {
+    NFD_LOG_FACE_WARN("Falling back to promiscuous mode");
+    pcap_set_promisc(m_pcap.get(), 1);
+  }
 
   m_socket.async_read_some(boost::asio::null_buffers(),
-                           bind(&EthernetFace::handleRead, this,
+                           bind(&EthernetTransport::handleRead, this,
                                 boost::asio::placeholders::error,
                                 boost::asio::placeholders::bytes_transferred));
 }
 
-void
-EthernetFace::sendInterest(const Interest& interest)
+void EthernetTransport::beforeChangePersistency(ndn::nfd::FacePersistency newPersistency)
 {
-  NFD_LOG_FACE_TRACE(__func__);
-
-  this->emitSignal(onSendInterest, interest);
-
-  ndnlp::PacketArray pa = m_slicer->slice(interest.wireEncode());
-  for (const auto& packet : *pa) {
-    sendPacket(packet);
+  if (newPersistency != ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
+    BOOST_THROW_EXCEPTION(
+      std::invalid_argument("EthernetTransport supports only FACE_PERSISTENCY_PERMANENT"));
   }
 }
 
-void
-EthernetFace::sendData(const Data& data)
+void EthernetTransport::doSend(Transport::Packet&& packet)
 {
   NFD_LOG_FACE_TRACE(__func__);
 
-  this->emitSignal(onSendData, data);
-
-  ndnlp::PacketArray pa = m_slicer->slice(data.wireEncode());
-  for (const auto& packet : *pa) {
-    sendPacket(packet);
-  }
+  sendPacket(packet.packet);
 }
 
-void
-EthernetFace::close()
+void EthernetTransport::doClose()
 {
-  if (!m_pcap)
-    return;
+  NFD_LOG_FACE_TRACE(__func__);
 
-  NFD_LOG_FACE_INFO("Closing face");
-
-  boost::system::error_code error;
-  m_socket.cancel(error); // ignore errors
-  m_socket.close(error);  // ignore errors
+  if (m_socket.is_open()) {
+    // Cancel all outstanding operations and close the socket.
+    // Use the non-throwing variants and ignore errors, if any.
+    boost::system::error_code error;
+    m_socket.cancel(error);
+    m_socket.close(error);
+  }
   m_pcap.reset();
 
-  fail("Face closed");
+  // Ensure that the Transport stays alive at least
+  // until all pending handlers are dispatched
+  getGlobalIoService().post([this] {
+    this->setState(TransportState::CLOSED);
+  });
 }
 
 void
-EthernetFace::pcapInit()
+EthernetTransport::pcapInit()
 {
   char errbuf[PCAP_ERRBUF_SIZE] = {};
   m_pcap.reset(pcap_create(m_interfaceName.c_str(), errbuf));
@@ -187,7 +181,7 @@
 }
 
 void
-EthernetFace::setPacketFilter(const char* filterString)
+EthernetTransport::setPacketFilter(const char* filterString)
 {
   bpf_program filter;
   if (pcap_compile(m_pcap.get(), &filter, filterString, 1, PCAP_NETMASK_UNKNOWN) < 0)
@@ -200,14 +194,14 @@
 }
 
 bool
-EthernetFace::joinMulticastGroup()
+EthernetTransport::joinMulticastGroup()
 {
 #if defined(__linux__)
   packet_mreq mr{};
   mr.mr_ifindex = m_interfaceIndex;
   mr.mr_type = PACKET_MR_MULTICAST;
   mr.mr_alen = m_destAddress.size();
-  std::copy(m_destAddress.begin(), m_destAddress.end(), mr.mr_address);
+  std::memcpy(mr.mr_address, m_destAddress.data(), m_destAddress.size());
 
   if (::setsockopt(m_socket.native_handle(), SOL_PACKET,
                    PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == 0)
@@ -223,7 +217,7 @@
 #if defined(__APPLE__) || defined(__FreeBSD__)
   // see bug #2327
   using boost::asio::ip::udp;
-  udp::socket sock(ref(getGlobalIoService()), udp::v4());
+  udp::socket sock(getGlobalIoService(), udp::v4());
   int fd = sock.native_handle();
 
   /*
@@ -242,7 +236,7 @@
   sdl->sdl_len = sizeof(ifr.ifr_addr);
   sdl->sdl_family = AF_LINK;
   sdl->sdl_alen = m_destAddress.size();
-  std::copy(m_destAddress.begin(), m_destAddress.end(), LLADDR(sdl));
+  std::memcpy(LLADDR(sdl), m_destAddress.data(), m_destAddress.size());
 
   static_assert(sizeof(ifr.ifr_addr) >= offsetof(sockaddr_dl, sdl_data) + ethernet::ADDR_LEN,
                 "ifr_addr in struct ifreq is too small on this platform");
@@ -250,9 +244,9 @@
   int fd = m_socket.native_handle();
 
   ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
-  std::copy(m_destAddress.begin(), m_destAddress.end(), ifr.ifr_hwaddr.sa_data);
+  std::memcpy(ifr.ifr_hwaddr.sa_data, m_destAddress.data(), m_destAddress.size());
 
-  static_assert(sizeof(ifr.ifr_hwaddr) >= offsetof(sockaddr, sa_data) + ethernet::ADDR_LEN,
+  static_assert(sizeof(ifr.ifr_hwaddr.sa_data) >= ethernet::ADDR_LEN,
                 "ifr_hwaddr in struct ifreq is too small on this platform");
 #endif
 
@@ -266,26 +260,17 @@
 }
 
 void
-EthernetFace::sendPacket(const ndn::Block& block)
+EthernetTransport::sendPacket(const ndn::Block& block)
 {
-  if (!m_pcap)
-    {
-      NFD_LOG_FACE_WARN("Trying to send on closed face");
-      return fail("Face closed");
-    }
-
-  BOOST_ASSERT(block.size() <= m_interfaceMtu);
-
   /// \todo Right now there is no reserve when packet is received, but
   ///       we should reserve some space at the beginning and at the end
   ndn::EncodingBuffer buffer(block);
 
   // pad with zeroes if the payload is too short
-  if (block.size() < ethernet::MIN_DATA_LEN)
-    {
-      static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
-      buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
-    }
+  if (block.size() < ethernet::MIN_DATA_LEN) {
+    static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
+    buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
+  }
 
   // construct and prepend the ethernet header
   static uint16_t ethertype = htons(ethernet::ETHERTYPE_NDN);
@@ -296,66 +281,53 @@
   // send the packet
   int sent = pcap_inject(m_pcap.get(), buffer.buf(), buffer.size());
   if (sent < 0)
-    {
-      return fail("pcap_inject: " + std::string(pcap_geterr(m_pcap.get())));
-    }
+    NFD_LOG_FACE_ERROR("pcap_inject failed: " << pcap_geterr(m_pcap.get()));
   else if (static_cast<size_t>(sent) < buffer.size())
-    {
-      return fail("Failed to inject frame");
-    }
-
-  NFD_LOG_FACE_TRACE("Successfully sent: " << block.size() << " bytes");
-  this->getMutableCounters().getNOutBytes() += block.size();
+    NFD_LOG_FACE_ERROR("Failed to send the full frame: bufsize=" << buffer.size() << " sent=" << sent);
+  else
+    // print block size because we don't want to count the padding in buffer
+    NFD_LOG_FACE_TRACE("Successfully sent: " << block.size() << " bytes");
 }
 
 void
-EthernetFace::handleRead(const boost::system::error_code& error, size_t)
+EthernetTransport::handleRead(const boost::system::error_code& error, size_t)
 {
-  if (!m_pcap)
-    return fail("Face closed");
-
   if (error)
     return processErrorCode(error);
 
   pcap_pkthdr* header;
   const uint8_t* packet;
+
+  // read the pcap header and packet data
   int ret = pcap_next_ex(m_pcap.get(), &header, &packet);
   if (ret < 0)
-    {
-      return fail("pcap_next_ex: " + std::string(pcap_geterr(m_pcap.get())));
-    }
+    NFD_LOG_FACE_ERROR("pcap_next_ex failed: " << pcap_geterr(m_pcap.get()));
   else if (ret == 0)
-    {
-      NFD_LOG_FACE_WARN("Read timeout");
-    }
+    NFD_LOG_FACE_WARN("Read timeout");
   else
-    {
-      processIncomingPacket(header, packet);
-    }
+    processIncomingPacket(header, packet);
 
 #ifdef _DEBUG
   pcap_stat ps{};
   ret = pcap_stats(m_pcap.get(), &ps);
-  if (ret < 0)
-    {
-      NFD_LOG_FACE_DEBUG("pcap_stats failed: " << pcap_geterr(m_pcap.get()));
-    }
-  else if (ret == 0)
-    {
-      if (ps.ps_drop - m_nDropped > 0)
-        NFD_LOG_FACE_DEBUG("Detected " << ps.ps_drop - m_nDropped << " dropped packet(s)");
-      m_nDropped = ps.ps_drop;
-    }
+  if (ret < 0) {
+    NFD_LOG_FACE_DEBUG("pcap_stats failed: " << pcap_geterr(m_pcap.get()));
+  }
+  else if (ret == 0) {
+    if (ps.ps_drop - m_nDropped > 0)
+      NFD_LOG_FACE_DEBUG("Detected " << ps.ps_drop - m_nDropped << " dropped packet(s)");
+    m_nDropped = ps.ps_drop;
+  }
 #endif
 
   m_socket.async_read_some(boost::asio::null_buffers(),
-                           bind(&EthernetFace::handleRead, this,
+                           bind(&EthernetTransport::handleRead, this,
                                 boost::asio::placeholders::error,
                                 boost::asio::placeholders::bytes_transferred));
 }
 
 void
-EthernetFace::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet)
+EthernetTransport::processIncomingPacket(const pcap_pkthdr* header, const uint8_t* packet)
 {
   size_t length = header->caplen;
   if (length < ethernet::HDR_LEN + ethernet::MIN_DATA_LEN) {
@@ -377,77 +349,46 @@
   packet += ethernet::HDR_LEN;
   length -= ethernet::HDR_LEN;
 
-  /// \todo Reserve space in front and at the back of the underlying buffer
   bool isOk = false;
-  Block fragmentBlock;
-  std::tie(isOk, fragmentBlock) = Block::fromBuffer(packet, length);
+  Block element;
+  std::tie(isOk, element) = Block::fromBuffer(packet, length);
   if (!isOk) {
-    NFD_LOG_FACE_WARN("Block received from " << sourceAddress.toString()
-                      << " is invalid or too large to process");
+    NFD_LOG_FACE_WARN("Received invalid packet from " << sourceAddress.toString());
     return;
   }
 
-  NFD_LOG_FACE_TRACE("Received: " << fragmentBlock.size() << " bytes from "
-                     << sourceAddress.toString());
-  this->getMutableCounters().getNInBytes() += fragmentBlock.size();
+  NFD_LOG_FACE_TRACE("Received: " << element.size() << " bytes from " << sourceAddress.toString());
 
-  Reassembler& reassembler = m_reassemblers[sourceAddress];
-  if (!reassembler.pms) {
-    // new sender, setup a PartialMessageStore for it
-    reassembler.pms.reset(new ndnlp::PartialMessageStore);
-    reassembler.pms->onReceive.connect(
-      [this, sourceAddress] (const Block& block) {
-        NFD_LOG_FACE_TRACE("All fragments received from " << sourceAddress.toString());
-        if (!decodeAndDispatchInput(block))
-          NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << block.type()
-                            << " from " << sourceAddress.toString());
-      });
-  }
-
-  scheduler::cancel(reassembler.expireEvent);
-  reassembler.expireEvent = scheduler::schedule(REASSEMBLER_LIFETIME,
-    [this, sourceAddress] {
-      BOOST_VERIFY(m_reassemblers.erase(sourceAddress) == 1);
-    });
-
-  ndnlp::NdnlpData fragment;
-  std::tie(isOk, fragment) = ndnlp::NdnlpData::fromBlock(fragmentBlock);
-  if (!isOk) {
-    NFD_LOG_FACE_WARN("Received invalid NDNLP fragment from " << sourceAddress.toString());
-    return;
-  }
-
-  reassembler.pms->receive(fragment);
+  Transport::Packet tp(std::move(element));
+  static_assert(sizeof(tp.remoteEndpoint) >= ethernet::ADDR_LEN,
+                "Transport::Packet::remoteEndpoint is too small");
+  std::memcpy(&tp.remoteEndpoint, sourceAddress.data(), sourceAddress.size());
+  this->receive(std::move(tp));
 }
 
 void
-EthernetFace::processErrorCode(const boost::system::error_code& error)
+EthernetTransport::processErrorCode(const boost::system::error_code& error)
 {
-  if (error == boost::asio::error::operation_aborted)
-    // cancel() has been called on the socket
+  NFD_LOG_FACE_TRACE(__func__);
+
+  if (getState() == TransportState::CLOSING ||
+      getState() == TransportState::FAILED ||
+      getState() == TransportState::CLOSED ||
+      error == boost::asio::error::operation_aborted)
+    // transport is shutting down, ignore any errors
     return;
 
-  std::string msg;
-  if (error == boost::asio::error::eof)
-    {
-      msg = "Face closed";
-    }
-  else
-    {
-      msg = "Receive operation failed: " + error.message();
-      NFD_LOG_FACE_WARN(msg);
-    }
-  fail(msg);
+  NFD_LOG_FACE_WARN("Receive operation failed: " << error.message());
 }
 
 size_t
-EthernetFace::getInterfaceMtu()
+EthernetTransport::getInterfaceMtu()
 {
 #ifdef SIOCGIFMTU
 #if defined(__APPLE__) || defined(__FreeBSD__)
   // see bug #2328
   using boost::asio::ip::udp;
-  udp::socket sock(ref(getGlobalIoService()), udp::v4());
+  udp::socket sock(getGlobalIoService(), udp::v4());
   int fd = sock.native_handle();
 #else
   int fd = m_socket.native_handle();
@@ -456,13 +397,17 @@
   ifreq ifr{};
   std::strncpy(ifr.ifr_name, m_interfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
 
-  if (::ioctl(fd, SIOCGIFMTU, &ifr) == 0)
+  if (::ioctl(fd, SIOCGIFMTU, &ifr) == 0) {
+    NFD_LOG_FACE_DEBUG("Interface MTU is " << ifr.ifr_mtu);
     return static_cast<size_t>(ifr.ifr_mtu);
+  }
 
   NFD_LOG_FACE_WARN("Failed to get interface MTU: " << std::strerror(errno));
 #endif
 
+  NFD_LOG_FACE_DEBUG("Assuming default MTU of " << ethernet::MAX_DATA_LEN);
   return ethernet::MAX_DATA_LEN;
 }
 
+} // namespace face
 } // namespace nfd
diff --git a/daemon/face/ethernet-face.hpp b/daemon/face/ethernet-transport.hpp
similarity index 71%
rename from daemon/face/ethernet-face.hpp
rename to daemon/face/ethernet-transport.hpp
index 2bbd781..1d41008 100644
--- a/daemon/face/ethernet-face.hpp
+++ b/daemon/face/ethernet-transport.hpp
@@ -23,17 +23,13 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef NFD_DAEMON_FACE_ETHERNET_FACE_HPP
-#define NFD_DAEMON_FACE_ETHERNET_FACE_HPP
+#ifndef NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
+#define NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
 
 #include "common.hpp"
-#include "face.hpp"
-#include "ndnlp-partial-message-store.hpp"
-#include "ndnlp-slicer.hpp"
+#include "transport.hpp"
 #include "core/network-interface.hpp"
 
-#include <unordered_map>
-
 #ifndef HAVE_LIBPCAP
 #error "Cannot include this file when libpcap is not available"
 #endif
@@ -44,43 +40,41 @@
 struct pcap_pkthdr;
 
 namespace nfd {
+namespace face {
 
 /**
- * @brief Implementation of Face abstraction that uses raw
- *        Ethernet frames as underlying transport mechanism
+ * \brief A multicast Transport that uses raw Ethernet II frames
  */
-class EthernetFace : public Face
+class EthernetTransport DECL_CLASS_FINAL : public Transport
 {
 public:
-  /**
-   * @brief EthernetFace-related error
-   */
-  struct Error : public Face::Error
+  class Error : public std::runtime_error
   {
-    Error(const std::string& what) : Face::Error(what) {}
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
   };
 
-  EthernetFace(boost::asio::posix::stream_descriptor socket,
-               const NetworkInterfaceInfo& interface,
-               const ethernet::Address& address);
-
-  /// send an Interest
-  void
-  sendInterest(const Interest& interest) DECL_OVERRIDE;
-
-  /// send a Data
-  void
-  sendData(const Data& data) DECL_OVERRIDE;
-
   /**
-   * @brief Closes the face
-   *
-   * This terminates all communication on the face and triggers the onFail() event.
+   * @brief Creates an Ethernet-based transport for multicast communication
    */
-  void
-  close() DECL_OVERRIDE;
+  EthernetTransport(const NetworkInterfaceInfo& interface,
+                    const ethernet::Address& mcastAddress);
+
+protected:
+  virtual void
+  beforeChangePersistency(ndn::nfd::FacePersistency newPersistency) DECL_FINAL;
+
+  virtual void
+  doClose() DECL_FINAL;
 
 private:
+  virtual void
+  doSend(Transport::Packet&& packet) DECL_FINAL;
+
   /**
    * @brief Allocates and initializes a libpcap context for live capture
    */
@@ -139,26 +133,15 @@
   getInterfaceMtu();
 
 private:
-  struct Reassembler
-  {
-    unique_ptr<ndnlp::PartialMessageStore> pms;
-    scheduler::EventId expireEvent;
-  };
-
   unique_ptr<pcap_t, void(*)(pcap_t*)> m_pcap;
   boost::asio::posix::stream_descriptor m_socket;
 
+  ethernet::Address m_srcAddress;
+  ethernet::Address m_destAddress;
+  std::string m_interfaceName;
 #if defined(__linux__)
   int m_interfaceIndex;
 #endif
-  std::string m_interfaceName;
-  ethernet::Address m_srcAddress;
-  ethernet::Address m_destAddress;
-
-  size_t m_interfaceMtu;
-  unique_ptr<ndnlp::Slicer> m_slicer;
-  std::unordered_map<ethernet::Address, Reassembler> m_reassemblers;
-  static const time::nanoseconds REASSEMBLER_LIFETIME;
 
 #ifdef _DEBUG
   /// number of packets dropped by the kernel, as reported by libpcap
@@ -166,6 +149,7 @@
 #endif
 };
 
+} // namespace face
 } // namespace nfd
 
-#endif // NFD_DAEMON_FACE_ETHERNET_FACE_HPP
+#endif // NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
diff --git a/daemon/face/ndnlp-data.cpp b/daemon/face/ndnlp-data.cpp
deleted file mode 100644
index 7cfacac..0000000
--- a/daemon/face/ndnlp-data.cpp
+++ /dev/null
@@ -1,108 +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 "ndnlp-data.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-std::tuple<bool, NdnlpData>
-NdnlpData::fromBlock(const Block& wire)
-{
-  if (wire.type() != tlv::NdnlpData) {
-    // top element is not NdnlpData
-    return std::make_tuple(false, NdnlpData());
-  }
-  wire.parse();
-  const Block::element_container& elements = wire.elements();
-  if (elements.size() < 2) {
-    // NdnlpData element has incorrect number of children
-    return std::make_tuple(false, NdnlpData());
-  }
-
-  NdnlpData parsed;
-
-  const Block& sequenceElement = elements.front();
-  if (sequenceElement.type() != tlv::NdnlpSequence) {
-    // NdnlpSequence element is missing
-    return std::make_tuple(false, NdnlpData());
-  }
-  if (sequenceElement.value_size() != sizeof(uint64_t)) {
-    // NdnlpSequence element has incorrect length
-    return std::make_tuple(false, NdnlpData());
-  }
-  parsed.seq = be64toh(*reinterpret_cast<const uint64_t*>(&*sequenceElement.value_begin()));
-
-  const Block& payloadElement = elements.back();
-  if (payloadElement.type() != tlv::NdnlpPayload) {
-    // NdnlpPayload element is missing
-    return std::make_tuple(false, NdnlpData());
-  }
-  parsed.payload = payloadElement;
-
-  if (elements.size() == 2) { // single wire packet
-    parsed.fragIndex = 0;
-    parsed.fragCount = 1;
-    return std::make_tuple(true, parsed);
-  }
-  if (elements.size() != 4) {
-    // NdnlpData element has incorrect number of children
-    return std::make_tuple(false, NdnlpData());
-  }
-
-  const Block& fragIndexElement = elements.at(1);
-  if (fragIndexElement.type() != tlv::NdnlpFragIndex) {
-    // NdnlpFragIndex element is missing
-    return std::make_tuple(false, NdnlpData());
-  }
-  uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
-  if (fragIndex > std::numeric_limits<uint16_t>::max()) {
-    // NdnlpFragIndex is too large
-    return std::make_tuple(false, NdnlpData());
-  }
-  parsed.fragIndex = static_cast<uint16_t>(fragIndex);
-
-  const Block& fragCountElement = elements.at(2);
-  if (fragCountElement.type() != tlv::NdnlpFragCount) {
-    // NdnlpFragCount element is missing
-    return std::make_tuple(false, NdnlpData());
-  }
-  uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
-  if (fragCount > std::numeric_limits<uint16_t>::max()) {
-    // NdnlpFragCount is too large
-    return std::make_tuple(false, NdnlpData());
-  }
-  parsed.fragCount = static_cast<uint16_t>(fragCount);
-
-  if (parsed.fragIndex >= parsed.fragCount) {
-    // NdnlpFragIndex must be less than NdnlpFragCount
-    return std::make_tuple(false, NdnlpData());
-  }
-
-  return std::make_tuple(true, parsed);
-}
-
-} // namespace ndnlp
-} // namespace nfd
diff --git a/daemon/face/ndnlp-data.hpp b/daemon/face/ndnlp-data.hpp
deleted file mode 100644
index fd921e2..0000000
--- a/daemon/face/ndnlp-data.hpp
+++ /dev/null
@@ -1,62 +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_NDNLP_PARSE_HPP
-#define NFD_DAEMON_FACE_NDNLP_PARSE_HPP
-
-#include "common.hpp"
-#include "ndnlp-tlv.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-/** \brief represents a NdnlpData packet
- *
- *  NdnlpData ::= NDNLP-DATA-TYPE TLV-LENGTH
- *                  NdnlpSequence
- *                  NdnlpFragIndex?
- *                  NdnlpFragCount?
- *                  NdnlpPayload
- */
-class NdnlpData
-{
-public:
-  /** \brief parse a NdnlpData packet
-   *  \return whether \p wire has a valid NdnlpData packet, and the parsed packet
-   */
-  static std::tuple<bool, NdnlpData>
-  fromBlock(const Block& wire);
-
-public:
-  uint64_t seq;
-  uint16_t fragIndex;
-  uint16_t fragCount;
-  Block payload;
-};
-
-} // namespace ndnlp
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_NDNLP_PARSE_HPP
diff --git a/daemon/face/ndnlp-partial-message-store.cpp b/daemon/face/ndnlp-partial-message-store.cpp
deleted file mode 100644
index 252e77d..0000000
--- a/daemon/face/ndnlp-partial-message-store.cpp
+++ /dev/null
@@ -1,152 +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 "ndnlp-partial-message-store.hpp"
-#include "core/logger.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-NFD_LOG_INIT("NdnlpPartialMessageStore");
-
-PartialMessage::PartialMessage()
-  : m_fragCount(0)
-  , m_received(0)
-  , m_totalLength(0)
-{
-}
-
-bool
-PartialMessage::add(uint16_t fragIndex, uint16_t fragCount, const Block& payload)
-{
-  if (m_received == 0) { // first packet
-    m_fragCount = fragCount;
-    m_payloads.resize(fragCount);
-  }
-
-  if (m_fragCount != fragCount || fragIndex >= m_fragCount) {
-    return false;
-  }
-
-  if (!m_payloads[fragIndex].empty()) { // duplicate
-    return false;
-  }
-
-  m_payloads[fragIndex] = payload;
-  ++m_received;
-  m_totalLength += payload.value_size();
-  return true;
-}
-
-bool
-PartialMessage::isComplete() const
-{
-  return m_received == m_fragCount;
-}
-
-std::tuple<bool, Block>
-PartialMessage::reassemble()
-{
-  BOOST_ASSERT(this->isComplete());
-
-  ndn::BufferPtr buffer = make_shared<ndn::Buffer>(m_totalLength);
-  ndn::Buffer::iterator buf = buffer->begin();
-  for (const Block& payload : m_payloads) {
-    buf = std::copy(payload.value_begin(), payload.value_end(), buf);
-  }
-  BOOST_ASSERT(buf == buffer->end());
-
-  return Block::fromBuffer(buffer, 0);
-}
-
-std::tuple<bool, Block>
-PartialMessage::reassembleSingle(const NdnlpData& fragment)
-{
-  BOOST_ASSERT(fragment.fragCount == 1);
-
-  try {
-    return std::make_tuple(true, fragment.payload.blockFromValue());
-  }
-  catch (tlv::Error&) {
-    return std::make_tuple(false, Block());
-  }
-}
-
-PartialMessageStore::PartialMessageStore(const time::nanoseconds& idleDuration)
-  : m_idleDuration(idleDuration)
-{
-}
-
-void
-PartialMessageStore::receive(const NdnlpData& pkt)
-{
-  bool isReassembled = false;
-  Block reassembled;
-
-  if (pkt.fragCount == 1) { // single fragment
-    std::tie(isReassembled, reassembled) = PartialMessage::reassembleSingle(pkt);
-  }
-  else {
-    uint64_t messageIdentifier = pkt.seq - pkt.fragIndex;
-    PartialMessage& pm = m_partialMessages[messageIdentifier];
-    this->scheduleCleanup(messageIdentifier, pm);
-
-    pm.add(pkt.fragIndex, pkt.fragCount, pkt.payload);
-
-    if (pm.isComplete()) {
-      std::tie(isReassembled, reassembled) = pm.reassemble();
-      m_partialMessages.erase(messageIdentifier);
-    }
-    else {
-      return;
-    }
-  }
-
-  if (!isReassembled) {
-    NFD_LOG_TRACE(pkt.seq << " reassemble error");
-    return;
-  }
-
-  NFD_LOG_TRACE(pkt.seq << " deliver");
-  this->onReceive(reassembled);
-}
-
-void
-PartialMessageStore::scheduleCleanup(uint64_t messageIdentifier,
-                                     PartialMessage& partialMessage)
-{
-  partialMessage.expiry = scheduler::schedule(m_idleDuration,
-    bind(&PartialMessageStore::cleanup, this, messageIdentifier));
-}
-
-void
-PartialMessageStore::cleanup(uint64_t messageIdentifier)
-{
-  NFD_LOG_TRACE(messageIdentifier << " cleanup");
-  m_partialMessages.erase(messageIdentifier);
-}
-
-} // namespace ndnlp
-} // namespace nfd
diff --git a/daemon/face/ndnlp-partial-message-store.hpp b/daemon/face/ndnlp-partial-message-store.hpp
deleted file mode 100644
index 25afcd8..0000000
--- a/daemon/face/ndnlp-partial-message-store.hpp
+++ /dev/null
@@ -1,117 +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_NDNLP_PARTIAL_MESSAGE_STORE_HPP
-#define NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
-
-#include "ndnlp-data.hpp"
-#include "core/scheduler.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-/** \brief represents a partially received message
- */
-class PartialMessage
-{
-public:
-  PartialMessage();
-
-  PartialMessage(const PartialMessage&) = delete;
-
-  PartialMessage&
-  operator=(const PartialMessage&) = delete;
-
-  PartialMessage(PartialMessage&&) = default;
-
-  PartialMessage&
-  operator=(PartialMessage&&) = default;
-
-  bool
-  add(uint16_t fragIndex, uint16_t fragCount, const Block& payload);
-
-  bool
-  isComplete() const;
-
-  /** \brief reassemble network layer packet
-   *  \pre isComplete() == true
-   *  \return whether success, network layer packet
-   */
-  std::tuple<bool, Block>
-  reassemble();
-
-  /** \brief reassemble network layer packet from a single fragment
-   *  \pre fragment.fragCount == 1
-   *  \return whether success, network layer packet
-   */
-  static std::tuple<bool, Block>
-  reassembleSingle(const NdnlpData& fragment);
-
-public:
-  scheduler::ScopedEventId expiry;
-
-private:
-  size_t m_fragCount;
-  size_t m_received;
-  std::vector<Block> m_payloads;
-  size_t m_totalLength;
-};
-
-/** \brief provides reassembly feature at receiver
- */
-class PartialMessageStore : noncopyable
-{
-public:
-  explicit
-  PartialMessageStore(const time::nanoseconds& idleDuration = time::milliseconds(100));
-
-  /** \brief receive a NdnlpData packet
-   *
-   *  Reassembly errors will be ignored.
-   */
-  void
-  receive(const NdnlpData& pkt);
-
-  /** \brief fires when network layer packet is received
-   */
-  signal::Signal<PartialMessageStore, Block> onReceive;
-
-private:
-  void
-  scheduleCleanup(uint64_t messageIdentifier, PartialMessage& partialMessage);
-
-  void
-  cleanup(uint64_t messageIdentifier);
-
-private:
-  std::unordered_map<uint64_t, PartialMessage> m_partialMessages;
-
-  time::nanoseconds m_idleDuration;
-};
-
-} // namespace ndnlp
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_NDNLP_PARTIAL_MESSAGE_STORE_HPP
diff --git a/daemon/face/ndnlp-sequence-generator.cpp b/daemon/face/ndnlp-sequence-generator.cpp
deleted file mode 100644
index 842a319..0000000
--- a/daemon/face/ndnlp-sequence-generator.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- 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
- *
- * 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 "ndnlp-sequence-generator.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-SequenceBlock::SequenceBlock(uint64_t start, size_t count)
-  : m_start(start)
-  , m_count(count)
-{
-}
-
-SequenceGenerator::SequenceGenerator()
-  : m_next(0)
-{
-}
-
-SequenceBlock
-SequenceGenerator::nextBlock(size_t count)
-{
-  SequenceBlock sb(m_next, count);
-  m_next += count;
-  return sb;
-}
-
-} // namespace ndnlp
-} // namespace nfd
diff --git a/daemon/face/ndnlp-sequence-generator.hpp b/daemon/face/ndnlp-sequence-generator.hpp
deleted file mode 100644
index 3019933..0000000
--- a/daemon/face/ndnlp-sequence-generator.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- 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
- *
- * 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_NDNLP_SEQUENCE_GENERATOR_HPP
-#define NFD_DAEMON_FACE_NDNLP_SEQUENCE_GENERATOR_HPP
-
-#include "common.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-/** \brief represents a block of sequence numbers
- */
-class SequenceBlock
-{
-public:
-  SequenceBlock(uint64_t start, size_t count);
-
-  /** \return{ the pos-th sequence number }
-   */
-  uint64_t
-  operator[](size_t pos) const;
-
-  size_t
-  count() const;
-
-private:
-  uint64_t m_start;
-  size_t m_count;
-};
-
-inline uint64_t
-SequenceBlock::operator[](size_t pos) const
-{
-  if (pos >= m_count)
-    BOOST_THROW_EXCEPTION(std::out_of_range("pos"));
-  return m_start + static_cast<uint64_t>(pos);
-}
-
-inline size_t
-SequenceBlock::count() const
-{
-  return m_count;
-}
-
-/** \class SequenceGenerator
- *  \brief generates sequence numbers
- */
-class SequenceGenerator : noncopyable
-{
-public:
-  SequenceGenerator();
-
-  /** \brief generates a block of consecutive sequence numbers
-   *
-   *  This block must not overlap with a recent block.
-   */
-  SequenceBlock
-  nextBlock(size_t count);
-
-private:
-  /// next sequence number
-  uint64_t m_next;
-};
-
-} // namespace ndnlp
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_NDNLP_SEQUENCE_GENERATOR_HPP
diff --git a/daemon/face/ndnlp-slicer.cpp b/daemon/face/ndnlp-slicer.cpp
deleted file mode 100644
index 03b1454..0000000
--- a/daemon/face/ndnlp-slicer.cpp
+++ /dev/null
@@ -1,135 +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 "ndnlp-slicer.hpp"
-
-#include <ndn-cxx/encoding/encoding-buffer.hpp>
-
-namespace nfd {
-namespace ndnlp {
-
-Slicer::Slicer(size_t mtu)
-  : m_mtu(mtu)
-{
-  this->estimateOverhead();
-}
-
-Slicer::~Slicer()
-{
-}
-
-template<bool T>
-size_t
-Slicer::encodeFragment(ndn::EncodingImpl<T>& blk,
-                       uint64_t seq, uint16_t fragIndex, uint16_t fragCount,
-                       const uint8_t* payload, size_t payloadSize)
-{
-  size_t totalLength = 0;
-
-  // NdnlpPayload
-  size_t payloadLength = blk.prependByteArray(payload, payloadSize);
-  totalLength += payloadLength;
-  totalLength += blk.prependVarNumber(payloadLength);
-  totalLength += blk.prependVarNumber(tlv::NdnlpPayload);
-
-  bool needFragIndexAndCount = fragCount > 1;
-  if (needFragIndexAndCount) {
-    // NdnlpFragCount
-    size_t fragCountLength = blk.prependNonNegativeInteger(fragCount);
-    totalLength += fragCountLength;
-    totalLength += blk.prependVarNumber(fragCountLength);
-    totalLength += blk.prependVarNumber(tlv::NdnlpFragCount);
-
-    // NdnlpFragIndex
-    size_t fragIndexLength = blk.prependNonNegativeInteger(fragIndex);
-    totalLength += fragIndexLength;
-    totalLength += blk.prependVarNumber(fragIndexLength);
-    totalLength += blk.prependVarNumber(tlv::NdnlpFragIndex);
-  }
-
-  // NdnlpSequence
-  uint64_t sequenceBE = htobe64(seq);
-  size_t sequenceLength = blk.prependByteArray(
-    reinterpret_cast<uint8_t*>(&sequenceBE), sizeof(sequenceBE));
-  totalLength += sequenceLength;
-  totalLength += blk.prependVarNumber(sequenceLength);
-  totalLength += blk.prependVarNumber(tlv::NdnlpSequence);
-
-  // NdnlpData
-  totalLength += blk.prependVarNumber(totalLength);
-  totalLength += blk.prependVarNumber(tlv::NdnlpData);
-
-  return totalLength;
-}
-
-void
-Slicer::estimateOverhead()
-{
-  // estimate fragment size with all header fields at largest possible size
-  ndn::EncodingEstimator estimator;
-  size_t estimatedSize = this->encodeFragment(estimator,
-                                              std::numeric_limits<uint64_t>::max(),
-                                              std::numeric_limits<uint16_t>::max() - 1,
-                                              std::numeric_limits<uint16_t>::max(),
-                                              nullptr, m_mtu);
-
-  size_t overhead = estimatedSize - m_mtu; // minus payload length in estimation
-  m_maxPayload = m_mtu - overhead;
-}
-
-PacketArray
-Slicer::slice(const Block& block)
-{
-  BOOST_ASSERT(block.hasWire());
-  const uint8_t* networkPacket = block.wire();
-  size_t networkPacketSize = block.size();
-
-  uint16_t fragCount = static_cast<uint16_t>(
-                         (networkPacketSize / m_maxPayload) +
-                         (networkPacketSize % m_maxPayload == 0 ? 0 : 1)
-                       );
-  PacketArray pa = make_shared<std::vector<Block>>();
-  pa->reserve(fragCount);
-  SequenceBlock seqBlock = m_seqgen.nextBlock(fragCount);
-
-  for (uint16_t fragIndex = 0; fragIndex < fragCount; ++fragIndex) {
-    size_t payloadOffset = fragIndex * m_maxPayload;
-    const uint8_t* payload = networkPacket + payloadOffset;
-    size_t payloadSize = std::min(m_maxPayload, networkPacketSize - payloadOffset);
-
-    ndn::EncodingBuffer buffer(m_mtu, 0);
-    size_t pktSize = this->encodeFragment(buffer,
-      seqBlock[fragIndex], fragIndex, fragCount, payload, payloadSize);
-
-    BOOST_VERIFY(pktSize <= m_mtu);
-
-    pa->push_back(buffer.block());
-  }
-
-  return pa;
-}
-
-} // namespace ndnlp
-} // namespace nfd
diff --git a/daemon/face/ndnlp-slicer.hpp b/daemon/face/ndnlp-slicer.hpp
deleted file mode 100644
index 1e2985a..0000000
--- a/daemon/face/ndnlp-slicer.hpp
+++ /dev/null
@@ -1,79 +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_NDNLP_SLICER_HPP
-#define NFD_DAEMON_FACE_NDNLP_SLICER_HPP
-
-#include "ndnlp-tlv.hpp"
-#include "ndnlp-sequence-generator.hpp"
-
-namespace nfd {
-namespace ndnlp {
-
-typedef shared_ptr<std::vector<Block>> PacketArray;
-
-/** \brief provides fragmentation feature at sender
- */
-class Slicer : noncopyable
-{
-public:
-  /** \param mtu maximum size of NDNLP header and payload
-   *  \note If NDNLP packets are to be encapsulated in an additional header
-   *        (eg. in UDP packets), the caller must deduct such overhead.
-   */
-  explicit
-  Slicer(size_t mtu);
-
-  virtual
-  ~Slicer();
-
-  PacketArray
-  slice(const Block& block);
-
-private:
-  template<bool T>
-  size_t
-  encodeFragment(ndn::EncodingImpl<T>& blk,
-                 uint64_t seq, uint16_t fragIndex, uint16_t fragCount,
-                 const uint8_t* payload, size_t payloadSize);
-
-  /// estimate the size of NDNLP header and maximum payload size per packet
-  void
-  estimateOverhead();
-
-private:
-  SequenceGenerator m_seqgen;
-
-  /// maximum packet size
-  size_t m_mtu;
-
-  /// maximum payload size
-  size_t m_maxPayload;
-};
-
-} // namespace ndnlp
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_NDNLP_SLICER_HPP
diff --git a/daemon/face/ndnlp-tlv.hpp b/daemon/face/ndnlp-tlv.hpp
deleted file mode 100644
index 0c41f52..0000000
--- a/daemon/face/ndnlp-tlv.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- 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
- *
- * 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_NDNLP_TLV_HPP
-#define NFD_DAEMON_FACE_NDNLP_TLV_HPP
-
-namespace nfd {
-namespace tlv {
-
-enum
-{
-  NdnlpData      = 80,
-  NdnlpSequence  = 81,
-  NdnlpFragIndex = 82,
-  NdnlpFragCount = 83,
-  NdnlpPayload   = 84
-};
-
-} // namespace tlv
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_NDNLP_TLV_HPP