management: Finalizing LocalControlHeader implementation

IncomingFaceId and NextHopFaceId are now fully supported for specifying
to be efficiently sent towards the forwarding daemon, and to be
automatically decoded from incoming packet from the forwarding daemon.

The current implementation limits exactly one LocalControlHeader for
Interest/Data packet instance. This is not exactly correct (especially
inside NFD), where the same Interest is expected to have multiple
LocalControlHeader (for each individual local face).  The following
commits will fix this problem.

Change-Id: Ia6b124ed12271136d071f4822f13634897ce3228
refs: #1170
diff --git a/src/management/ndnd-controller.cpp b/src/management/ndnd-controller.cpp
index 486a611..b3b7821 100644
--- a/src/management/ndnd-controller.cpp
+++ b/src/management/ndnd-controller.cpp
@@ -199,7 +199,7 @@
 
   switch(val->type())
     {
-    case Tlv::FaceManagement::FaceInstance:
+    case tlv::ndnd::FaceInstance:
       {
         FaceInstance entry;
         entry.wireDecode(*val);
@@ -208,7 +208,7 @@
           onSuccess(entry);
         return;
       }
-    case Tlv::FaceManagement::StatusResponse:
+    case tlv::ndnd::StatusResponse:
       {
         StatusResponse resp;
         resp.wireDecode(*val);
@@ -245,7 +245,7 @@
 
   switch(val->type())
     {
-    case Tlv::FaceManagement::ForwardingEntry:
+    case tlv::ndnd::ForwardingEntry:
       {
         ForwardingEntry entry;
         entry.wireDecode(*val);
@@ -254,7 +254,7 @@
           onSuccess(entry);
         return;
       }
-    case Tlv::FaceManagement::StatusResponse:
+    case tlv::ndnd::StatusResponse:
       {
         StatusResponse resp;
         resp.wireDecode(*val);
diff --git a/src/management/ndnd-face-instance.hpp b/src/management/ndnd-face-instance.hpp
index 0de85ff..1da6b94 100644
--- a/src/management/ndnd-face-instance.hpp
+++ b/src/management/ndnd-face-instance.hpp
@@ -7,7 +7,7 @@
 #ifndef NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
 #define NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
 
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 #include "../encoding/block.hpp"
 #include "../name.hpp"
 
@@ -138,55 +138,55 @@
   //                  MulticastTTL?
   //                  FreshnessPeriod?
   
-  wire_ = Block(Tlv::FaceManagement::FaceInstance);
+  wire_ = Block(tlv::ndnd::FaceInstance);
 
   // Action
   if (!action_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Action, action_.c_str(), action_.size()));
+        (dataBlock(tlv::ndnd::Action, action_.c_str(), action_.size()));
     }
 
   // FaceID
   if (faceId_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::FaceID, faceId_));
+        (nonNegativeIntegerBlock(tlv::ndnd::FaceID, faceId_));
     }
 
   // IPProto
   if (ipProto_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::IPProto, ipProto_));
+        (nonNegativeIntegerBlock(tlv::ndnd::IPProto, ipProto_));
     }
   
   // Host
   if (!host_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Host, host_.c_str(), host_.size()));
+        (dataBlock(tlv::ndnd::Host, host_.c_str(), host_.size()));
     }
 
   // Port
   if (!port_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Port, port_.c_str(), port_.size()));
+        (dataBlock(tlv::ndnd::Port, port_.c_str(), port_.size()));
     }
 
   // MulticastInterface
   if (!multicastInterface_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::MulticastInterface, multicastInterface_.c_str(), multicastInterface_.size()));
+        (dataBlock(tlv::ndnd::MulticastInterface, multicastInterface_.c_str(), multicastInterface_.size()));
     }
 
   // MulticastTTL
   if (multicastTtl_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::MulticastTTL, multicastTtl_));
+        (nonNegativeIntegerBlock(tlv::ndnd::MulticastTTL, multicastTtl_));
     }
 
   // FreshnessPeriod
@@ -226,49 +226,49 @@
   //                  FreshnessPeriod?
 
   // Action
-  Block::element_const_iterator val = wire_.find(Tlv::FaceManagement::Action);
+  Block::element_const_iterator val = wire_.find(tlv::ndnd::Action);
   if (val != wire_.elements_end())
     {
       action_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // FaceID
-  val = wire_.find(Tlv::FaceManagement::FaceID);
+  val = wire_.find(tlv::ndnd::FaceID);
   if (val != wire_.elements_end())
     {
       faceId_ = readNonNegativeInteger(*val);
     }
 
   // IPProto
-  val = wire_.find(Tlv::FaceManagement::IPProto);
+  val = wire_.find(tlv::ndnd::IPProto);
   if (val != wire_.elements_end())
     {
       ipProto_ = readNonNegativeInteger(*val);
     }
 
   // Host
-  val = wire_.find(Tlv::FaceManagement::Host);
+  val = wire_.find(tlv::ndnd::Host);
   if (val != wire_.elements_end())
     {
       host_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // Port
-  val = wire_.find(Tlv::FaceManagement::Port);
+  val = wire_.find(tlv::ndnd::Port);
   if (val != wire_.elements_end())
     {
       port_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // MulticastInterface
-  val = wire_.find(Tlv::FaceManagement::MulticastInterface);
+  val = wire_.find(tlv::ndnd::MulticastInterface);
   if (val != wire_.elements_end())
     {
       multicastInterface_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // MulticastTTL
-  val = wire_.find(Tlv::FaceManagement::MulticastTTL);
+  val = wire_.find(tlv::ndnd::MulticastTTL);
   if (val != wire_.elements_end())
     {
       multicastTtl_ = readNonNegativeInteger(*val);
diff --git a/src/management/ndnd-forwarding-entry.hpp b/src/management/ndnd-forwarding-entry.hpp
index 5cd81ab..3d262f1 100644
--- a/src/management/ndnd-forwarding-entry.hpp
+++ b/src/management/ndnd-forwarding-entry.hpp
@@ -7,7 +7,7 @@
 #ifndef NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
 #define NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
 
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 #include "../name.hpp"
 #include "../encoding/block.hpp"
 
@@ -99,13 +99,13 @@
   //                       ForwardingFlags?
   //                       FreshnessPeriod?
   
-  wire_ = Block(Tlv::FaceManagement::ForwardingEntry);
+  wire_ = Block(tlv::ndnd::ForwardingEntry);
 
   // Action
   if (!action_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Action, action_.c_str(), action_.size()));
+        (dataBlock(tlv::ndnd::Action, action_.c_str(), action_.size()));
     }
 
   // Name
@@ -116,7 +116,7 @@
   if (faceId_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::FaceID, faceId_));
+        (nonNegativeIntegerBlock(tlv::ndnd::FaceID, faceId_));
     }
 
   // ForwardingFlags
@@ -154,7 +154,7 @@
   //                       FreshnessPeriod?
 
   // Action
-  Block::element_const_iterator val = wire_.find(Tlv::FaceManagement::Action);
+  Block::element_const_iterator val = wire_.find(tlv::ndnd::Action);
   if (val != wire_.elements_end())
     {
       action_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
@@ -168,14 +168,14 @@
     }
 
   // FaceID
-  val = wire_.find(Tlv::FaceManagement::FaceID);
+  val = wire_.find(tlv::ndnd::FaceID);
   if (val != wire_.elements_end())
     {
       faceId_ = readNonNegativeInteger(*val);
     }
 
   // ForwardingFlags
-  val = wire_.find(Tlv::FaceManagement::ForwardingFlags);
+  val = wire_.find(tlv::ndnd::ForwardingFlags);
   if (val != wire_.elements_end())
     {
       forwardingFlags_.wireDecode(*val);
diff --git a/src/management/ndnd-forwarding-flags.hpp b/src/management/ndnd-forwarding-flags.hpp
index 8b4ce78..f238d06 100644
--- a/src/management/ndnd-forwarding-flags.hpp
+++ b/src/management/ndnd-forwarding-flags.hpp
@@ -9,7 +9,7 @@
 #define NDN_FORWARDING_FLAGS_HPP
 
 #include "../encoding/block.hpp"
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 
 namespace ndn {
 namespace ndnd {
@@ -159,23 +159,23 @@
 
   uint32_t result = 0;
   if (active_)
-    result |= Tlv::FaceManagement::FORW_ACTIVE;
+    result |= tlv::ndnd::FORW_ACTIVE;
   if (childInherit_)
-    result |= Tlv::FaceManagement::FORW_CHILD_INHERIT;
+    result |= tlv::ndnd::FORW_CHILD_INHERIT;
   if (advertise_)
-    result |= Tlv::FaceManagement::FORW_ADVERTISE;
+    result |= tlv::ndnd::FORW_ADVERTISE;
   if (last_)
-    result |= Tlv::FaceManagement::FORW_LAST;
+    result |= tlv::ndnd::FORW_LAST;
   if (capture_)
-    result |= Tlv::FaceManagement::FORW_CAPTURE;
+    result |= tlv::ndnd::FORW_CAPTURE;
   if (local_)
-    result |= Tlv::FaceManagement::FORW_LOCAL;
+    result |= tlv::ndnd::FORW_LOCAL;
   if (tap_)
-    result |= Tlv::FaceManagement::FORW_TAP;
+    result |= tlv::ndnd::FORW_TAP;
   if (captureOk_)
-    result |= Tlv::FaceManagement::FORW_CAPTURE_OK;
+    result |= tlv::ndnd::FORW_CAPTURE_OK;
   
-  wire_ = nonNegativeIntegerBlock(Tlv::FaceManagement::ForwardingFlags, result);
+  wire_ = nonNegativeIntegerBlock(tlv::ndnd::ForwardingFlags, result);
 
   return wire_;
 }
@@ -187,14 +187,14 @@
 
   uint32_t flags = readNonNegativeInteger(wire_);
   
-  active_       = (flags & Tlv::FaceManagement::FORW_ACTIVE)        ? true : false;
-  childInherit_ = (flags & Tlv::FaceManagement::FORW_CHILD_INHERIT) ? true : false;
-  advertise_    = (flags & Tlv::FaceManagement::FORW_ADVERTISE)     ? true : false;
-  last_         = (flags & Tlv::FaceManagement::FORW_LAST)          ? true : false;
-  capture_      = (flags & Tlv::FaceManagement::FORW_CAPTURE)       ? true : false;
-  local_        = (flags & Tlv::FaceManagement::FORW_LOCAL)         ? true : false;
-  tap_          = (flags & Tlv::FaceManagement::FORW_TAP)           ? true : false;
-  captureOk_    = (flags & Tlv::FaceManagement::FORW_CAPTURE_OK)    ? true : false;
+  active_       = (flags & tlv::ndnd::FORW_ACTIVE)        ? true : false;
+  childInherit_ = (flags & tlv::ndnd::FORW_CHILD_INHERIT) ? true : false;
+  advertise_    = (flags & tlv::ndnd::FORW_ADVERTISE)     ? true : false;
+  last_         = (flags & tlv::ndnd::FORW_LAST)          ? true : false;
+  capture_      = (flags & tlv::ndnd::FORW_CAPTURE)       ? true : false;
+  local_        = (flags & tlv::ndnd::FORW_LOCAL)         ? true : false;
+  tap_          = (flags & tlv::ndnd::FORW_TAP)           ? true : false;
+  captureOk_    = (flags & tlv::ndnd::FORW_CAPTURE_OK)    ? true : false;
 }
 
 inline std::ostream&
diff --git a/src/management/ndnd-status-response.hpp b/src/management/ndnd-status-response.hpp
index 74e15fe..e58de7e 100644
--- a/src/management/ndnd-status-response.hpp
+++ b/src/management/ndnd-status-response.hpp
@@ -8,7 +8,7 @@
 #define NDN_MANAGEMENT_NDND_STATUS_RESPONSE_HPP
 
 #include "../encoding/block.hpp"
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 
 namespace ndn {
 namespace ndnd {
@@ -84,14 +84,14 @@
   if (wire_.hasWire())
     return wire_;
 
-  wire_ = Block(Tlv::FaceManagement::StatusResponse);
+  wire_ = Block(tlv::ndnd::StatusResponse);
   wire_.push_back
-    (nonNegativeIntegerBlock(Tlv::FaceManagement::StatusCode, code_));
+    (nonNegativeIntegerBlock(tlv::ndnd::StatusCode, code_));
 
   if (!info_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::StatusText, info_.c_str(), info_.size()));
+        (dataBlock(tlv::ndnd::StatusText, info_.c_str(), info_.size()));
     }
   
   wire_.encode();  
@@ -104,9 +104,9 @@
   wire_ = wire;
   wire_.parse();
 
-  code_ = readNonNegativeInteger(wire_.get(Tlv::FaceManagement::StatusCode));
+  code_ = readNonNegativeInteger(wire_.get(tlv::ndnd::StatusCode));
 
-  Block::element_const_iterator val = wire_.find(Tlv::FaceManagement::StatusText);
+  Block::element_const_iterator val = wire_.find(tlv::ndnd::StatusText);
   if (val != wire_.elements_end())
     {
       info_.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
diff --git a/src/management/nfd-control-response.hpp b/src/management/nfd-control-response.hpp
index 1e6ec24..c959407 100644
--- a/src/management/nfd-control-response.hpp
+++ b/src/management/nfd-control-response.hpp
@@ -8,7 +8,7 @@
 #define NDN_MANAGEMENT_CONTROL_RESPONSE_HPP
 
 #include "../encoding/block.hpp"
-#include "../encoding/tlv-nfd-control.hpp"
+#include "../encoding/tlv-nfd.hpp"
 
 namespace ndn {
 namespace nfd {
@@ -117,12 +117,12 @@
   if (m_wire.hasWire())
     return m_wire;
 
-  m_wire = Block(tlv::nfd_control::ControlResponse);
+  m_wire = Block(tlv::nfd::ControlResponse);
   m_wire.push_back
-    (nonNegativeIntegerBlock(tlv::nfd_control::StatusCode, m_code));
+    (nonNegativeIntegerBlock(tlv::nfd::StatusCode, m_code));
 
   m_wire.push_back
-    (dataBlock(tlv::nfd_control::StatusText, m_text.c_str(), m_text.size()));
+    (dataBlock(tlv::nfd::StatusText, m_text.c_str(), m_text.size()));
 
   if (m_body.hasWire())
     {
@@ -139,12 +139,12 @@
   m_wire = wire;
   m_wire.parse();
 
-  if (m_wire.type() != tlv::nfd_control::ControlResponse)
+  if (m_wire.type() != tlv::nfd::ControlResponse)
     throw Error("Requested decoding of ControlResponse, but Block is of different type");  
   
   Block::element_const_iterator val = m_wire.elements_begin();
   if (val == m_wire.elements_end() ||
-      val->type() != tlv::nfd_control::StatusCode)
+      val->type() != tlv::nfd::StatusCode)
     {
       throw Error("Incorrect ControlResponse format (StatusCode missing or not the first item)");
     }
@@ -153,7 +153,7 @@
   ++val;
 
   if (val == m_wire.elements_end() ||
-      val->type() != tlv::nfd_control::StatusText)
+      val->type() != tlv::nfd::StatusText)
     {
       throw Error("Incorrect ControlResponse format (StatusText missing or not the second item)");
     }
diff --git a/src/management/nfd-face-management-options.hpp b/src/management/nfd-face-management-options.hpp
index 20640df..7158352 100644
--- a/src/management/nfd-face-management-options.hpp
+++ b/src/management/nfd-face-management-options.hpp
@@ -8,7 +8,7 @@
 #define NDN_MANAGEMENT_NFD_FACE_MANAGEMENT_OPTIONS_HPP
 
 #include "../encoding/encoding-buffer.hpp"
-#include "../encoding/tlv-nfd-control.hpp"
+#include "../encoding/tlv-nfd.hpp"
 
 namespace ndn {
 namespace nfd {
@@ -87,7 +87,7 @@
       size_t var_len = blk.prependByteArray (reinterpret_cast<const uint8_t*>(m_uri.c_str()), m_uri.size());
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::Uri);
+      total_len += blk.prependVarNumber (tlv::nfd::Uri);
     }
 
   if (m_faceId != INVALID_FACE_ID)
@@ -95,11 +95,11 @@
       size_t var_len = blk.prependNonNegativeInteger (m_faceId);
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::FaceId);
+      total_len += blk.prependVarNumber (tlv::nfd::FaceId);
     }
 
   total_len += blk.prependVarNumber (total_len);
-  total_len += blk.prependVarNumber (tlv::nfd_control::FaceManagementOptions);
+  total_len += blk.prependVarNumber (tlv::nfd::FaceManagementOptions);
   return total_len;
 }
 
@@ -127,20 +127,20 @@
 
   wire_ = wire;
 
-  if (wire_.type() != tlv::nfd_control::FaceManagementOptions)
+  if (wire_.type() != tlv::nfd::FaceManagementOptions)
     throw Error("Requested decoding of FaceManagementOptions, but Block is of different type");
   
   wire_.parse ();
 
   // FaceID
-  Block::element_const_iterator val = wire_.find(tlv::nfd_control::FaceId);
+  Block::element_const_iterator val = wire_.find(tlv::nfd::FaceId);
   if (val != wire_.elements_end())
     {
       m_faceId = readNonNegativeInteger(*val);
     }
 
   // Uri
-  val = wire_.find(tlv::nfd_control::Uri);
+  val = wire_.find(tlv::nfd::Uri);
   if (val != wire_.elements_end())
     {
       m_uri.append(reinterpret_cast<const char*>(val->value()), val->value_size());
diff --git a/src/management/nfd-fib-management-options.hpp b/src/management/nfd-fib-management-options.hpp
index 33ac31f..c27e2fb 100644
--- a/src/management/nfd-fib-management-options.hpp
+++ b/src/management/nfd-fib-management-options.hpp
@@ -12,7 +12,7 @@
 
 #include "../encoding/block.hpp"
 #include "../encoding/encoding-buffer.hpp"
-#include "../encoding/tlv-nfd-control.hpp"
+#include "../encoding/tlv-nfd.hpp"
 #include "../name.hpp"
 
 namespace ndn {
@@ -105,7 +105,7 @@
       size_t var_len = blk.prependNonNegativeInteger (cost_);
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::Cost);
+      total_len += blk.prependVarNumber (tlv::nfd::Cost);
     }
 
   if (faceId_ != -1)
@@ -113,13 +113,13 @@
       size_t var_len = blk.prependNonNegativeInteger (faceId_);
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::FaceId);
+      total_len += blk.prependVarNumber (tlv::nfd::FaceId);
     }
 
   total_len += name_.wireEncode (blk);
 
   total_len += blk.prependVarNumber (total_len);
-  total_len += blk.prependVarNumber (tlv::nfd_control::FibManagementOptions);
+  total_len += blk.prependVarNumber (tlv::nfd::FibManagementOptions);
   return total_len;
 }
 
@@ -148,7 +148,7 @@
 
   wire_ = wire;
 
-  if (wire_.type() != tlv::nfd_control::FibManagementOptions)
+  if (wire_.type() != tlv::nfd::FibManagementOptions)
     throw Error("Requested decoding of FibManagementOptions, but Block is of different type");
   
   wire_.parse ();
@@ -161,14 +161,14 @@
     }
 
   // FaceID
-  val = wire_.find(tlv::nfd_control::FaceId);
+  val = wire_.find(tlv::nfd::FaceId);
   if (val != wire_.elements_end())
     {
       faceId_ = readNonNegativeInteger(*val);
     }
 
   // Cost
-  val = wire_.find(tlv::nfd_control::Cost);
+  val = wire_.find(tlv::nfd::Cost);
   if (val != wire_.elements_end())
     {
       cost_ = readNonNegativeInteger(*val);
diff --git a/src/management/nfd-local-control-header.hpp b/src/management/nfd-local-control-header.hpp
new file mode 100644
index 0000000..e931f57
--- /dev/null
+++ b/src/management/nfd-local-control-header.hpp
@@ -0,0 +1,238 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
+#define NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
+
+#include "../encoding/encoding-buffer.hpp"
+#include "../encoding/tlv-nfd.hpp"
+
+namespace ndn {
+namespace nfd {
+
+const uint64_t INVALID_FACE_ID = std::numeric_limits<uint64_t>::max();
+const size_t   ESTIMATED_LOCAL_HEADER_RESERVE = 10;
+
+class LocalControlHeader
+{
+public:
+  LocalControlHeader()
+    : m_incomingFaceId(INVALID_FACE_ID)
+    , m_nextHopFaceId(INVALID_FACE_ID)
+  {
+  }
+
+  /**
+   * @brief Create wire encoding with options LocalControlHeader and the supplied item
+   *
+   * This method will return wire encoding of the item if none of the LocalControlHeader
+   * fields are set, otherwise it will encapsulate the item inside LocalControlHeader
+   *
+   * Note that this method will use default maximum packet size (8800 bytes) during the
+   * encoding process.
+   *
+   * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
+   */
+  template<class U>
+  inline const Block&
+  wireEncode(const U& item) const;
+  
+  /**
+   * @brief Decode from the wire format and set LocalControlHeader on the supplied item
+   *
+   * The supplied wire MUST contain LocalControlHeader.  Determination whether the optional
+   * LocalControlHeader should be done before calling this method.
+   */
+  inline void 
+  wireDecode(const Block& wire);
+
+  inline static const Block&
+  getPayload(const Block& wire);
+  
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  // Gettest/setters
+
+  bool
+  empty() const
+  {
+    return (!hasIncomingFaceId() && !hasNextHopFaceId());
+  }
+  
+  //
+  
+  bool
+  hasIncomingFaceId() const
+  {
+    return m_incomingFaceId != INVALID_FACE_ID;
+  }
+  
+  uint64_t
+  getIncomingFaceId() const
+  {
+    return m_incomingFaceId;
+  }
+
+  void
+  setIncomingFaceId(uint64_t incomingFaceId)
+  {
+    m_incomingFaceId = incomingFaceId;
+    m_wire.reset();
+  }
+
+  //
+
+  bool
+  hasNextHopFaceId() const
+  {
+    return m_nextHopFaceId != INVALID_FACE_ID;
+  }
+  
+  uint64_t
+  getNextHopFaceId() const
+  {
+    return m_nextHopFaceId;
+  }
+
+  void
+  setNextHopFaceId(uint64_t nextHopFaceId)
+  {
+    m_nextHopFaceId = nextHopFaceId;
+    m_wire.reset();
+  }
+
+private:
+  template<bool T, class U>
+  inline size_t
+  wireEncode(EncodingImpl<T>& block, const U& item) const;
+  
+private:
+  uint64_t m_incomingFaceId;
+  uint64_t m_nextHopFaceId;
+
+  mutable Block m_wire;
+};
+
+
+/**
+ * @brief Fast encoding or block size estimation
+ */
+template<bool T, class U>
+inline size_t
+LocalControlHeader::wireEncode(EncodingImpl<T>& block, const U& item) const
+{
+  size_t total_len = item.wireEncode().size();
+
+  if (hasIncomingFaceId())
+    {
+      total_len += prependNonNegativeIntegerBlock(block,
+                                                  tlv::nfd::IncomingFaceId, getIncomingFaceId());
+    }
+
+  if (hasNextHopFaceId())
+    {
+      total_len += prependNonNegativeIntegerBlock(block,
+                                                  tlv::nfd::NextHopFaceId, getNextHopFaceId());
+    }
+  
+  total_len += block.prependVarNumber(total_len);
+  total_len += block.prependVarNumber(tlv::nfd::LocalControlHeader);
+  return total_len;
+}
+
+template<class U>
+inline const Block&
+LocalControlHeader::wireEncode(const U& item) const
+{
+  if (item.hasWire() && m_wire.hasWire())
+    return m_wire;
+
+  if (empty())
+    {
+      if (item.hasWire())
+        return item.wireEncode();
+      else
+        {
+          EncodingBuffer buffer; // use default (maximum) packet size here
+          item.wireEncode(buffer);
+          item.m_wire = buffer.block();
+          m_wire = buffer.block();
+        }
+    }
+  else
+    {
+      if (item.hasWire())
+        {
+          // extend the existing buffer
+          EncodingBuffer buffer(item.wireEncode());
+          wireEncode(buffer, item);
+          m_wire = buffer.block();
+        }
+      else
+        {
+          EncodingBuffer buffer;
+          item.wireEncode(buffer);
+          item.m_wire = buffer.block();
+
+          wireEncode(buffer, item);
+          m_wire = buffer.block();
+        }
+    }
+  return m_wire;
+}
+
+inline void 
+LocalControlHeader::wireDecode(const Block& wire)
+{
+  BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
+  m_wire = wire;
+  m_wire.parse();
+
+  m_incomingFaceId = INVALID_FACE_ID;
+  m_nextHopFaceId = INVALID_FACE_ID;
+
+  for (Block::element_const_iterator i = m_wire.elements_begin();
+       i != m_wire.elements_end();
+       ++i)
+    {
+      switch(i->type())
+        {
+        case tlv::nfd::IncomingFaceId:
+          m_incomingFaceId = readNonNegativeInteger(*i);
+          break;
+        case tlv::nfd::NextHopFaceId:
+          m_nextHopFaceId = readNonNegativeInteger(*i);
+          break;
+        default:
+          // ignore all unsupported
+          break;
+        }
+    }
+}
+
+inline const Block&
+LocalControlHeader::getPayload(const Block& wire)
+{
+  if (wire.type() == tlv::nfd::LocalControlHeader)
+    {
+      wire.parse();
+      if (wire.elements_size() < 1)
+        return wire; // don't throw an error, but don't continue processing
+
+      return wire.elements()[wire.elements().size()-1];
+    }
+  else
+    {
+      return wire;
+    }
+}
+
+
+} // namespace nfd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP