fw: process HopLimit

refs #4806

Change-Id: I20682570409a576a6f35784f34d33ef27bf801cd
diff --git a/daemon/face/face-counters.cpp b/daemon/face/face-counters.cpp
index 52b94ac..275783f 100644
--- a/daemon/face/face-counters.cpp
+++ b/daemon/face/face-counters.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2019,  Regents of the University of California,
+ * Copyright (c) 2014-2020,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -32,7 +32,7 @@
                            const Transport::Counters& transportCounters)
   : nInInterests(linkServiceCounters.nInInterests)
   , nOutInterests(linkServiceCounters.nOutInterests)
-  , nDroppedInterests(linkServiceCounters.nDroppedInterests)
+  , nInterestsExceededRetx(linkServiceCounters.nInterestsExceededRetx)
   , nInData(linkServiceCounters.nInData)
   , nOutData(linkServiceCounters.nOutData)
   , nInNacks(linkServiceCounters.nInNacks)
diff --git a/daemon/face/face-counters.hpp b/daemon/face/face-counters.hpp
index 51af2d9..aed0ba4 100644
--- a/daemon/face/face-counters.hpp
+++ b/daemon/face/face-counters.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2019,  Regents of the University of California,
+ * Copyright (c) 2014-2020,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -70,18 +70,25 @@
 public:
   const PacketCounter& nInInterests;
   const PacketCounter& nOutInterests;
-  const PacketCounter& nDroppedInterests;
+  const PacketCounter& nInterestsExceededRetx;
   const PacketCounter& nInData;
   const PacketCounter& nOutData;
   const PacketCounter& nInNacks;
   const PacketCounter& nOutNacks;
-  PacketCounter nKeptInterests;
 
   const PacketCounter& nInPackets;
   const PacketCounter& nOutPackets;
   const ByteCounter& nInBytes;
   const ByteCounter& nOutBytes;
 
+  /** \brief count of incoming Interests dropped due to HopLimit == 0
+   */
+  PacketCounter nInHopLimitZero;
+
+  /** \brief count of outgoing Interests dropped due to HopLimit == 0 on non-local faces
+   */
+  PacketCounter nOutHopLimitZero;
+
 private:
   const LinkService::Counters& m_linkServiceCounters;
   const Transport::Counters& m_transportCounters;
diff --git a/daemon/face/link-service.cpp b/daemon/face/link-service.cpp
index a382ebe..df0fe9c 100644
--- a/daemon/face/link-service.cpp
+++ b/daemon/face/link-service.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2019,  Regents of the University of California,
+ * Copyright (c) 2014-2020,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -117,7 +117,7 @@
 void
 LinkService::notifyDroppedInterest(const Interest& interest)
 {
-  ++this->nDroppedInterests;
+  ++this->nInterestsExceededRetx;
   onDroppedInterest(interest);
 }
 
diff --git a/daemon/face/link-service.hpp b/daemon/face/link-service.hpp
index fd35723..c239cf2 100644
--- a/daemon/face/link-service.hpp
+++ b/daemon/face/link-service.hpp
@@ -50,7 +50,7 @@
 
   /** \brief count of Interests dropped by reliability system for exceeding allowed number of retx
    */
-  PacketCounter nDroppedInterests;
+  PacketCounter nInterestsExceededRetx;
 
   /** \brief count of incoming Data packets
    */
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 5c529a8..8ab209a 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2019,  Regents of the University of California,
+ * Copyright (c) 2014-2020,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -92,6 +92,18 @@
   interest.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
   ++m_counters.nInInterests;
 
+  // drop if HopLimit zero, decrement otherwise (if present)
+  if (interest.getHopLimit()) {
+    if (*interest.getHopLimit() < 1) {
+      NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
+                    << " hop-limit=0");
+      ++const_cast<PacketCounter&>(ingress.face.getCounters().nInHopLimitZero);
+      return;
+    }
+
+    const_cast<Interest&>(interest).setHopLimit(*interest.getHopLimit() - 1);
+  }
+
   // /localhost scope control
   bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
                               scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
@@ -230,6 +242,14 @@
 Forwarder::onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry,
                               const FaceEndpoint& egress, const Interest& interest)
 {
+  // drop if HopLimit == 0 but sending on non-local face
+  if (interest.getHopLimit() == 0 && egress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
+    NFD_LOG_DEBUG("onOutgoingInterest out=" << egress << " interest=" << pitEntry->getName()
+                  << " non-local hop-limit=0");
+    ++const_cast<PacketCounter&>(egress.face.getCounters().nOutHopLimitZero);
+    return;
+  }
+
   NFD_LOG_DEBUG("onOutgoingInterest out=" << egress << " interest=" << pitEntry->getName());
 
   // insert out-record
diff --git a/tests/daemon/face/lp-reliability.t.cpp b/tests/daemon/face/lp-reliability.t.cpp
index 99223df..525ab97 100644
--- a/tests/daemon/face/lp-reliability.t.cpp
+++ b/tests/daemon/face/lp-reliability.t.cpp
@@ -171,7 +171,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 }
 
 BOOST_AUTO_TEST_CASE(SendUnfragmentedRetx)
@@ -190,7 +190,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+500ms
   // 1024 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -212,7 +212,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+1250ms
   // 1024 rto: 1000ms, txSeq: 4, started T+1000ms, retx 1
@@ -230,7 +230,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+2250ms
   // 1024 rto: 1000ms, txSeq: 6, started T+2000ms, retx 2
@@ -249,7 +249,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+3250ms
   // 1024 rto: 1000ms, txSeq: 8, started T+3000ms, retx 3
@@ -268,7 +268,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+4250ms
   // 1024 rto: expired, removed
@@ -286,7 +286,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 1);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 1);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 1);
 
   // T+4750ms
   // 1024 rto: expired, removed
@@ -299,7 +299,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 2);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 2);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 2);
 }
 
 BOOST_AUTO_TEST_CASE(SendFragmentedRetx)
@@ -329,7 +329,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+0ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -360,7 +360,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+250ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -394,7 +394,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+500ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -428,7 +428,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+750ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -462,7 +462,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   // T+850ms
   // 2048 rto: expired, removed
@@ -476,7 +476,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 1);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 1);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 1);
 }
 
 BOOST_AUTO_TEST_CASE(AckUnknownTxSeq)
@@ -491,7 +491,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   lp::Packet ackPkt;
   ackPkt.add<lp::AckField>(10101010);
@@ -505,7 +505,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 }
 
 BOOST_AUTO_TEST_CASE(LossByGreaterAcks)
@@ -537,7 +537,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   lp::Packet ackPkt1;
   ackPkt1.add<lp::AckField>(0);
@@ -565,7 +565,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 1);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   lp::Packet ackPkt2;
   ackPkt2.add<lp::AckField>(2);
@@ -593,7 +593,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 2);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   lp::Packet ackPkt3;
   ackPkt3.add<lp::AckField>(1);
@@ -622,7 +622,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 3);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 
   lp::Packet ackPkt4;
   ackPkt4.add<lp::AckField>(4);
@@ -645,7 +645,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 3);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 1);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 }
 
 BOOST_AUTO_TEST_CASE(SkipFragmentsRemovedInRtt)
@@ -707,7 +707,7 @@
   BOOST_CHECK_EQUAL(linkService->getCounters().nAcknowledged, 1);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetransmitted, 0);
   BOOST_CHECK_EQUAL(linkService->getCounters().nRetxExhausted, 0);
-  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nInterestsExceededRetx, 0);
 }
 
 BOOST_AUTO_TEST_CASE(ProcessIncomingPacket)
diff --git a/tests/daemon/fw/forwarder.t.cpp b/tests/daemon/fw/forwarder.t.cpp
index af362e1..67f1db7 100644
--- a/tests/daemon/fw/forwarder.t.cpp
+++ b/tests/daemon/fw/forwarder.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2019,  Regents of the University of California,
+ * Copyright (c) 2014-2020,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -171,6 +171,72 @@
   BOOST_CHECK_EQUAL(face2->sentInterests.front().getName(), "/A/B");
 }
 
+BOOST_AUTO_TEST_CASE(HopLimit)
+{
+  auto faceIn = addFace();
+  auto faceRemote = addFace("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_NON_LOCAL);
+  auto faceLocal = addFace("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+  Fib& fib = forwarder.getFib();
+  fib::Entry* entryRemote = fib.insert("/remote").first;
+  fib.addOrUpdateNextHop(*entryRemote, *faceRemote, 0);
+  fib::Entry* entryLocal = fib.insert("/local").first;
+  fib.addOrUpdateNextHop(*entryLocal, *faceLocal, 0);
+
+  // Incoming interest w/o HopLimit will not be dropped on send or receive paths
+  auto interestNoHopLimit = makeInterest("/remote/abcdefgh");
+  faceIn->receiveInterest(*interestNoHopLimit, 0);
+  this->advanceClocks(100_ms, 1_s);
+  BOOST_CHECK_EQUAL(faceRemote->sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nInHopLimitZero, 0);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nOutHopLimitZero, 0);
+  BOOST_REQUIRE_EQUAL(faceRemote->sentInterests.size(), 1);
+  BOOST_CHECK(!faceRemote->sentInterests.back().getHopLimit());
+
+  // Incoming interest w/ HopLimit > 1 will not be dropped on send/receive
+  auto interestHopLimit2 = makeInterest("/remote/ijklmnop");
+  interestHopLimit2->setHopLimit(2);
+  faceIn->receiveInterest(*interestHopLimit2, 0);
+  this->advanceClocks(100_ms, 1_s);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nOutInterests, 2);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nInHopLimitZero, 0);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nOutHopLimitZero, 0);
+  BOOST_REQUIRE_EQUAL(faceRemote->sentInterests.size(), 2);
+  BOOST_REQUIRE(faceRemote->sentInterests.back().getHopLimit());
+  BOOST_CHECK_EQUAL(*faceRemote->sentInterests.back().getHopLimit(), 1);
+
+  // Incoming interest w/ HopLimit == 1 will be dropped on send path if going out on remote face
+  auto interestHopLimit1Remote = makeInterest("/remote/qrstuvwx");
+  interestHopLimit1Remote->setHopLimit(1);
+  faceIn->receiveInterest(*interestHopLimit1Remote, 0);
+  this->advanceClocks(100_ms, 1_s);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nOutInterests, 2);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nInHopLimitZero, 0);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nOutHopLimitZero, 1);
+  BOOST_CHECK_EQUAL(faceRemote->sentInterests.size(), 2);
+
+  // Incoming interest w/ HopLimit == 1 will not be dropped on send path if going out on local face
+  auto interestHopLimit1Local = makeInterest("/local/abcdefgh");
+  interestHopLimit1Local->setHopLimit(1);
+  faceIn->receiveInterest(*interestHopLimit1Local, 0);
+  this->advanceClocks(100_ms, 1_s);
+  BOOST_CHECK_EQUAL(faceLocal->getCounters().nOutInterests, 1);
+  BOOST_CHECK_EQUAL(faceLocal->getCounters().nInHopLimitZero, 0);
+  BOOST_CHECK_EQUAL(faceLocal->getCounters().nOutHopLimitZero, 0);
+  BOOST_REQUIRE_EQUAL(faceLocal->sentInterests.size(), 1);
+  BOOST_REQUIRE(faceLocal->sentInterests.back().getHopLimit());
+  BOOST_CHECK_EQUAL(*faceLocal->sentInterests.back().getHopLimit(), 0);
+
+  // Interest w/ HopLimit == 0 will be dropped on receive path
+  auto interestHopLimit0 = makeInterest("/remote/yzabcdef");
+  interestHopLimit0->setHopLimit(0);
+  faceIn->receiveInterest(*interestHopLimit0, 0);
+  this->advanceClocks(100_ms, 1_s);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nOutInterests, 2);
+  BOOST_CHECK_EQUAL(faceIn->getCounters().nInHopLimitZero, 1);
+  BOOST_CHECK_EQUAL(faceRemote->getCounters().nOutHopLimitZero, 1);
+  BOOST_CHECK_EQUAL(faceRemote->sentInterests.size(), 2);
+}
+
 class ScopeLocalhostIncomingTestForwarder : public Forwarder
 {
 public: