lp: add CongestionMark field and tag

refs #3797

Change-Id: I6ac6663c874abde1df2102af81fc03567ad87029
diff --git a/src/detail/face-impl.hpp b/src/detail/face-impl.hpp
index 998ab34..9ce4a69 100644
--- a/src/detail/face-impl.hpp
+++ b/src/detail/face-impl.hpp
@@ -93,6 +93,11 @@
       packet.add<lp::NextHopFaceIdField>(*nextHopFaceIdTag);
     }
 
+    shared_ptr<lp::CongestionMarkTag> congestionMarkTag = interest->getTag<lp::CongestionMarkTag>();
+    if (congestionMarkTag != nullptr) {
+      packet.add<lp::CongestionMarkField>(*congestionMarkTag);
+    }
+
     packet.add<lp::FragmentField>(std::make_pair(interest->wireEncode().begin(),
                                                  interest->wireEncode().end()));
 
diff --git a/src/face.cpp b/src/face.cpp
index d20f57c..430f65e 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -240,10 +240,22 @@
 {
   Block wire = data.wireEncode();
 
+  lp::Packet packet;
+  bool hasLpFields = false;
+
   shared_ptr<lp::CachePolicyTag> cachePolicyTag = data.getTag<lp::CachePolicyTag>();
   if (cachePolicyTag != nullptr) {
-    lp::Packet packet;
     packet.add<lp::CachePolicyField>(*cachePolicyTag);
+    hasLpFields = true;
+  }
+
+  shared_ptr<lp::CongestionMarkTag> congestionMarkTag = data.getTag<lp::CongestionMarkTag>();
+  if (congestionMarkTag != nullptr) {
+    packet.add<lp::CongestionMarkField>(*congestionMarkTag);
+    hasLpFields = true;
+  }
+
+  if (hasLpFields) {
     packet.add<lp::FragmentField>(std::make_pair(wire.begin(), wire.end()));
     wire = packet.wireEncode();
   }
@@ -264,6 +276,11 @@
   const Block& interestWire = nack.getInterest().wireEncode();
   packet.add<lp::FragmentField>(std::make_pair(interestWire.begin(), interestWire.end()));
 
+  shared_ptr<lp::CongestionMarkTag> congestionMarkTag = nack.getTag<lp::CongestionMarkTag>();
+  if (congestionMarkTag != nullptr) {
+    packet.add<lp::CongestionMarkField>(*congestionMarkTag);
+  }
+
   Block wire = packet.wireEncode();
 
   if (wire.size() > MAX_NDN_PACKET_SIZE)
@@ -500,13 +517,17 @@
 /**
  * @brief extract local fields from NDNLPv2 packet and tag onto a network layer packet
  */
-template<typename NETPKT>
+template<typename NetPkt>
 static void
-extractLpLocalFields(NETPKT& netPacket, const lp::Packet& lpPacket)
+extractLpLocalFields(NetPkt& netPacket, const lp::Packet& lpPacket)
 {
   if (lpPacket.has<lp::IncomingFaceIdField>()) {
     netPacket.setTag(make_shared<lp::IncomingFaceIdTag>(lpPacket.get<lp::IncomingFaceIdField>()));
   }
+
+  if (lpPacket.has<lp::CongestionMarkField>()) {
+    netPacket.setTag(make_shared<lp::CongestionMarkTag>(lpPacket.get<lp::CongestionMarkField>()));
+  }
 }
 
 void
diff --git a/src/lp/fields.hpp b/src/lp/fields.hpp
index ff9db28..7d898d0 100644
--- a/src/lp/fields.hpp
+++ b/src/lp/fields.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -68,6 +68,11 @@
                           tlv::IncomingFaceId> IncomingFaceIdField;
 BOOST_CONCEPT_ASSERT((Field<IncomingFaceIdField>));
 
+typedef detail::FieldDecl<field_location_tags::Header,
+                          uint64_t,
+                          tlv::CongestionMark> CongestionMarkField;
+BOOST_CONCEPT_ASSERT((Field<CongestionMarkField>));
+
 /**
  * The value of the wire encoded field is the data between the provided iterators. During
  * encoding, the data is copied from the Buffer into the wire buffer.
@@ -88,7 +93,8 @@
   NackField,
   NextHopFaceIdField,
   CachePolicyField,
-  IncomingFaceIdField
+  IncomingFaceIdField,
+  CongestionMarkField
   > FieldSet;
 
 } // namespace lp
diff --git a/src/lp/tags.hpp b/src/lp/tags.hpp
index c7fcefe..5e2b3d6 100644
--- a/src/lp/tags.hpp
+++ b/src/lp/tags.hpp
@@ -49,6 +49,13 @@
  */
 typedef SimpleTag<CachePolicy, 12> CachePolicyTag;
 
+/** \class CongestionMarkTag
+ *  \brief a packet tag for CongestionMark field
+ *
+ * This tag can be attached to Interest, Data, Nack.
+ */
+typedef SimpleTag<uint64_t, 13> CongestionMarkTag;
+
 } // namespace lp
 } // namespace ndn
 
diff --git a/src/lp/tlv.hpp b/src/lp/tlv.hpp
index 3231660..e7a5cca 100644
--- a/src/lp/tlv.hpp
+++ b/src/lp/tlv.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2015 Regents of the University of California.
+ * Copyright (c) 2013-2016 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -40,7 +40,8 @@
   NextHopFaceId = 816,
   CachePolicy = 820,
   CachePolicyType = 821,
-  IncomingFaceId = 817
+  IncomingFaceId = 817,
+  CongestionMark = 832
 };
 
 enum {
diff --git a/src/util/dummy-client-face.cpp b/src/util/dummy-client-face.cpp
index 43efff9..911d3bb 100644
--- a/src/util/dummy-client-face.cpp
+++ b/src/util/dummy-client-face.cpp
@@ -137,12 +137,18 @@
         if (lpPacket.has<lp::NextHopFaceIdField>()) {
           nack->setTag(make_shared<lp::NextHopFaceIdTag>(lpPacket.get<lp::NextHopFaceIdField>()));
         }
+        if (lpPacket.has<lp::CongestionMarkField>()) {
+          nack->setTag(make_shared<lp::CongestionMarkTag>(lpPacket.get<lp::CongestionMarkField>()));
+        }
         onSendNack(*nack);
       }
       else {
         if (lpPacket.has<lp::NextHopFaceIdField>()) {
           interest->setTag(make_shared<lp::NextHopFaceIdTag>(lpPacket.get<lp::NextHopFaceIdField>()));
         }
+        if (lpPacket.has<lp::CongestionMarkField>()) {
+          interest->setTag(make_shared<lp::CongestionMarkTag>(lpPacket.get<lp::CongestionMarkField>()));
+        }
         onSendInterest(*interest);
       }
     }
@@ -152,6 +158,9 @@
       if (lpPacket.has<lp::CachePolicyField>()) {
         data->setTag(make_shared<lp::CachePolicyTag>(lpPacket.get<lp::CachePolicyField>()));
       }
+      if (lpPacket.has<lp::CongestionMarkField>()) {
+        data->setTag(make_shared<lp::CongestionMarkTag>(lpPacket.get<lp::CongestionMarkField>()));
+      }
 
       onSendData(*data);
     }
@@ -208,23 +217,26 @@
   });
 }
 
+template<typename Packet, typename Field, typename Tag>
+static void
+addFieldFromTag(lp::Packet& lpPacket, const Packet& packet)
+{
+  shared_ptr<Tag> tag = static_cast<const TagHost&>(packet).getTag<Tag>();
+  if (tag != nullptr) {
+    lpPacket.add<Field>(*tag);
+  }
+}
+
 template<typename Packet>
 void
 DummyClientFace::receive(const Packet& packet)
 {
   lp::Packet lpPacket(packet.wireEncode());
 
-  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag =
-    static_cast<const TagHost&>(packet).getTag<lp::IncomingFaceIdTag>();
-  if (incomingFaceIdTag != nullptr) {
-    lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
-  }
+  addFieldFromTag<Packet, lp::IncomingFaceIdField, lp::IncomingFaceIdTag>(lpPacket, packet);
+  addFieldFromTag<Packet, lp::NextHopFaceIdField, lp::NextHopFaceIdTag>(lpPacket, packet);
+  addFieldFromTag<Packet, lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, packet);
 
-  shared_ptr<lp::NextHopFaceIdTag> nextHopFaceIdTag =
-    static_cast<const TagHost&>(packet).getTag<lp::NextHopFaceIdTag>();
-  if (nextHopFaceIdTag != nullptr) {
-    lpPacket.add<lp::NextHopFaceIdField>(*nextHopFaceIdTag);
-  }
   static_pointer_cast<Transport>(getTransport())->receive(lpPacket.wireEncode());
 }
 
@@ -243,10 +255,8 @@
   Block interest = nack.getInterest().wireEncode();
   lpPacket.add<lp::FragmentField>(make_pair(interest.begin(), interest.end()));
 
-  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = nack.getTag<lp::IncomingFaceIdTag>();
-  if (incomingFaceIdTag != nullptr) {
-    lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
-  }
+  addFieldFromTag<lp::Nack, lp::IncomingFaceIdField, lp::IncomingFaceIdTag>(lpPacket, nack);
+  addFieldFromTag<lp::Nack, lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, nack);
 
   static_pointer_cast<Transport>(getTransport())->receive(lpPacket.wireEncode());
 }
diff --git a/tests/unit-tests/face.t.cpp b/tests/unit-tests/face.t.cpp
index dfaefd5..c25681b 100644
--- a/tests/unit-tests/face.t.cpp
+++ b/tests/unit-tests/face.t.cpp
@@ -316,12 +316,15 @@
   lp::CachePolicy cachePolicy;
   cachePolicy.setPolicy(lp::CachePolicyType::NO_CACHE);
   data.setTag(make_shared<lp::CachePolicyTag>(cachePolicy));
+  data.setTag(make_shared<lp::CongestionMarkTag>(1));
   face.put(data);
 
   advanceClocks(time::milliseconds(10));
   BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
   BOOST_CHECK(face.sentData[0].getTag<lp::CachePolicyTag>() == nullptr);
+  BOOST_CHECK(face.sentData[0].getTag<lp::CongestionMarkTag>() == nullptr);
   BOOST_CHECK(face.sentData[1].getTag<lp::CachePolicyTag>() != nullptr);
+  BOOST_CHECK(face.sentData[1].getTag<lp::CongestionMarkTag>() != nullptr);
 }
 
 BOOST_AUTO_TEST_CASE(PutNack)
@@ -332,6 +335,15 @@
 
   advanceClocks(time::milliseconds(10));
   BOOST_CHECK_EQUAL(face.sentNacks.size(), 1);
+
+  auto nack = makeNack(Interest("/another/prefix", time::milliseconds(50)), lp::NackReason::NO_ROUTE);
+  nack.setTag(make_shared<lp::CongestionMarkTag>(1));
+  face.put(nack);
+
+  advanceClocks(time::milliseconds(10));
+  BOOST_REQUIRE_EQUAL(face.sentNacks.size(), 2);
+  BOOST_CHECK(face.sentNacks[0].getTag<lp::CongestionMarkTag>() == nullptr);
+  BOOST_CHECK(face.sentNacks[1].getTag<lp::CongestionMarkTag>() != nullptr);
 }
 
 BOOST_AUTO_TEST_CASE(SetUnsetInterestFilter)