face: GenericLinkService encodes and decodes CongestionMark field

refs #3797

Change-Id: Ia6b00a36f3e7ed9ec98e41dee7e2f97eaf235ddd
diff --git a/daemon/face/generic-link-service.cpp b/daemon/face/generic-link-service.cpp
index a922cbe..2a7f527 100644
--- a/daemon/face/generic-link-service.cpp
+++ b/daemon/face/generic-link-service.cpp
@@ -58,9 +58,7 @@
 {
   lp::Packet lpPacket(interest.wireEncode());
 
-  if (m_options.allowLocalFields) {
-    encodeLocalFields(interest, lpPacket);
-  }
+  encodeLpFields(interest, lpPacket);
 
   this->sendNetPacket(std::move(lpPacket));
 }
@@ -70,9 +68,7 @@
 {
   lp::Packet lpPacket(data.wireEncode());
 
-  if (m_options.allowLocalFields) {
-    encodeLocalFields(data, lpPacket);
-  }
+  encodeLpFields(data, lpPacket);
 
   this->sendNetPacket(std::move(lpPacket));
 }
@@ -83,19 +79,24 @@
   lp::Packet lpPacket(nack.getInterest().wireEncode());
   lpPacket.add<lp::NackField>(nack.getHeader());
 
-  if (m_options.allowLocalFields) {
-    encodeLocalFields(nack, lpPacket);
-  }
+  encodeLpFields(nack, lpPacket);
 
   this->sendNetPacket(std::move(lpPacket));
 }
 
 void
-GenericLinkService::encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
+GenericLinkService::encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
 {
-  shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
-  if (incomingFaceIdTag != nullptr) {
-    lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
+  if (m_options.allowLocalFields) {
+    shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
+    if (incomingFaceIdTag != nullptr) {
+      lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
+    }
+  }
+
+  shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
+  if (congestionMarkTag != nullptr) {
+    lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
   }
 }
 
@@ -241,6 +242,10 @@
     NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
   }
 
+  if (firstPkt.has<lp::CongestionMarkField>()) {
+    interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
+  }
+
   this->receiveInterest(*interest);
 }
 
@@ -279,6 +284,10 @@
     NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
   }
 
+  if (firstPkt.has<lp::CongestionMarkField>()) {
+    data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
+  }
+
   this->receiveData(*data);
 }
 
@@ -307,6 +316,10 @@
     NFD_LOG_FACE_WARN("received IncomingFaceId: IGNORE");
   }
 
+  if (firstPkt.has<lp::CongestionMarkField>()) {
+    nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
+  }
+
   this->receiveNack(nack);
 }
 
diff --git a/daemon/face/generic-link-service.hpp b/daemon/face/generic-link-service.hpp
index c9adcd7..08ed9e1 100644
--- a/daemon/face/generic-link-service.hpp
+++ b/daemon/face/generic-link-service.hpp
@@ -145,11 +145,12 @@
   void
   doSendNack(const ndn::lp::Nack& nack) override;
 
-  /** \brief encode local fields from tags onto outgoing LpPacket
-   *  \param pkt LpPacket containing a complete network layer packet
+  /** \brief encode link protocol fields from tags onto an outgoing LpPacket
+   *  \param netPkt network-layer packet to extract tags from
+   *  \param lpPacket LpPacket to add link protocol fields to
    */
-  static void
-  encodeLocalFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
+  void
+  encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
 
   /** \brief send a complete network layer packet
    *  \param pkt LpPacket containing a complete network layer packet
diff --git a/tests/daemon/face/generic-link-service.t.cpp b/tests/daemon/face/generic-link-service.t.cpp
index dc5a8cf..28a3288 100644
--- a/tests/daemon/face/generic-link-service.t.cpp
+++ b/tests/daemon/face/generic-link-service.t.cpp
@@ -394,7 +394,7 @@
 BOOST_AUTO_TEST_SUITE_END() // Fragmentation
 
 
-BOOST_AUTO_TEST_SUITE(LocalFields)
+BOOST_AUTO_TEST_SUITE(LpFields)
 
 BOOST_AUTO_TEST_CASE(ReceiveNextHopFaceId)
 {
@@ -637,7 +637,91 @@
   BOOST_CHECK(receivedNacks.back().getTag<lp::IncomingFaceIdTag>() == nullptr);
 }
 
-BOOST_AUTO_TEST_SUITE_END() // LocalFields
+BOOST_AUTO_TEST_CASE(SendCongestionMarkInterest)
+{
+  shared_ptr<Interest> interest = makeInterest("/12345678");
+  interest->setTag(make_shared<lp::CongestionMarkTag>(1));
+
+  face->sendInterest(*interest);
+
+  BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
+  lp::Packet sent(transport->sentPackets.back().packet);
+  BOOST_REQUIRE(sent.has<lp::CongestionMarkField>());
+  BOOST_CHECK_EQUAL(sent.get<lp::CongestionMarkField>(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(SendCongestionMarkData)
+{
+  shared_ptr<Data> data = makeData("/12345678");
+  data->setTag(make_shared<lp::CongestionMarkTag>(0));
+
+  face->sendData(*data);
+
+  BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
+  lp::Packet sent(transport->sentPackets.back().packet);
+  BOOST_REQUIRE(sent.has<lp::CongestionMarkField>());
+  BOOST_CHECK_EQUAL(sent.get<lp::CongestionMarkField>(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(SendCongestionMarkNack)
+{
+  lp::Nack nack = makeNack("/localhost/test", 123, lp::NackReason::NO_ROUTE);
+  nack.setTag(make_shared<lp::CongestionMarkTag>(std::numeric_limits<uint64_t>::max()));
+
+  face->sendNack(nack);
+
+  BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
+  lp::Packet sent(transport->sentPackets.back().packet);
+  BOOST_REQUIRE(sent.has<lp::CongestionMarkField>());
+  BOOST_CHECK_EQUAL(sent.get<lp::CongestionMarkField>(), std::numeric_limits<uint64_t>::max());
+}
+
+BOOST_AUTO_TEST_CASE(ReceiveCongestionMarkInterest)
+{
+  shared_ptr<Interest> interest = makeInterest("/12345678");
+  lp::Packet packet(interest->wireEncode());
+  packet.set<lp::CongestionMarkField>(1);
+
+  transport->receivePacket(packet.wireEncode());
+
+  BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1);
+  shared_ptr<lp::CongestionMarkTag> tag = receivedInterests.back().getTag<lp::CongestionMarkTag>();
+  BOOST_REQUIRE(tag != nullptr);
+  BOOST_CHECK_EQUAL(*tag, 1);
+}
+
+BOOST_AUTO_TEST_CASE(ReceiveCongestionMarkData)
+{
+  shared_ptr<Data> data = makeData("/12345678");
+  lp::Packet packet(data->wireEncode());
+  packet.set<lp::CongestionMarkField>(1);
+
+  transport->receivePacket(packet.wireEncode());
+
+  BOOST_REQUIRE_EQUAL(receivedData.size(), 1);
+  shared_ptr<lp::CongestionMarkTag> tag = receivedData.back().getTag<lp::CongestionMarkTag>();
+  BOOST_REQUIRE(tag != nullptr);
+  BOOST_CHECK_EQUAL(*tag, 1);
+}
+
+BOOST_AUTO_TEST_CASE(ReceiveCongestionMarkNack)
+{
+  lp::Nack nack = makeNack("/localhost/test", 123, lp::NackReason::NO_ROUTE);
+  lp::Packet packet;
+  packet.set<lp::FragmentField>(std::make_pair(
+    nack.getInterest().wireEncode().begin(), nack.getInterest().wireEncode().end()));
+  packet.set<lp::NackField>(nack.getHeader());
+  packet.set<lp::CongestionMarkField>(1);
+
+  transport->receivePacket(packet.wireEncode());
+
+  BOOST_REQUIRE_EQUAL(receivedNacks.size(), 1);
+  shared_ptr<lp::CongestionMarkTag> tag = receivedNacks.back().getTag<lp::CongestionMarkTag>();
+  BOOST_REQUIRE(tag != nullptr);
+  BOOST_CHECK_EQUAL(*tag, 1);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // LpFields
 
 
 BOOST_AUTO_TEST_SUITE(Malformed) // receive malformed packets