fw: add strategy notification for Interests dropped by LpReliability

add dropped Interest counter to faces

refs #3823

Change-Id: I9910b66932d74383203e8f3732bb45cade83b972
diff --git a/daemon/face/face-counters.cpp b/daemon/face/face-counters.cpp
index 7c4dee4..bd3acb7 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-2015,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -32,6 +32,7 @@
                            const Transport::Counters& transportCounters)
   : nInInterests(linkServiceCounters.nInInterests)
   , nOutInterests(linkServiceCounters.nOutInterests)
+  , nDroppedInterests(linkServiceCounters.nDroppedInterests)
   , nInData(linkServiceCounters.nInData)
   , nOutData(linkServiceCounters.nOutData)
   , nInNacks(linkServiceCounters.nInNacks)
diff --git a/daemon/face/face-counters.hpp b/daemon/face/face-counters.hpp
index 08facf8..4438bd7 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-2015,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -70,6 +70,7 @@
 public:
   const PacketCounter& nInInterests;
   const PacketCounter& nOutInterests;
+  const PacketCounter& nDroppedInterests;
   const PacketCounter& nInData;
   const PacketCounter& nOutData;
   const PacketCounter& nInNacks;
diff --git a/daemon/face/face.cpp b/daemon/face/face.cpp
index 69d32c1..6422a39 100644
--- a/daemon/face/face.cpp
+++ b/daemon/face/face.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -32,6 +32,7 @@
   : afterReceiveInterest(service->afterReceiveInterest)
   , afterReceiveData(service->afterReceiveData)
   , afterReceiveNack(service->afterReceiveNack)
+  , onDroppedInterest(service->onDroppedInterest)
   , afterStateChange(transport->afterStateChange)
   , m_id(INVALID_FACEID)
   , m_service(std::move(service))
diff --git a/daemon/face/face.hpp b/daemon/face/face.hpp
index 4b99d2f..4a97b3f 100644
--- a/daemon/face/face.hpp
+++ b/daemon/face/face.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
@@ -23,13 +23,13 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef NFD_DAEMON_FACE_HPP
-#define NFD_DAEMON_FACE_HPP
+#ifndef NFD_DAEMON_FACE_FACE_HPP
+#define NFD_DAEMON_FACE_FACE_HPP
 
-#include "transport.hpp"
-#include "link-service.hpp"
 #include "face-counters.hpp"
 #include "face-log.hpp"
+#include "link-service.hpp"
+#include "transport.hpp"
 
 namespace nfd {
 namespace face {
@@ -107,6 +107,10 @@
    */
   signal::Signal<LinkService, lp::Nack>& afterReceiveNack;
 
+  /** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
+   */
+  signal::Signal<LinkService, Interest>& onDroppedInterest;
+
 public: // static properties
   /** \return face ID
    */
@@ -300,4 +304,4 @@
 
 } // namespace nfd
 
-#endif // NFD_DAEMON_FACE_HPP
+#endif // NFD_DAEMON_FACE_FACE_HPP
diff --git a/daemon/face/generic-link-service.cpp b/daemon/face/generic-link-service.cpp
index 000245e..bbd8e03 100644
--- a/daemon/face/generic-link-service.cpp
+++ b/daemon/face/generic-link-service.cpp
@@ -46,6 +46,7 @@
   , m_lastSeqNo(-2)
 {
   m_reassembler.beforeTimeout.connect(bind([this] { ++this->nReassemblyTimeouts; }));
+  m_reliability.onDroppedInterest.connect([this] (const Interest& i) { this->notifyDroppedInterest(i); });
   nReassembling.observe(&m_reassembler);
 }
 
@@ -90,7 +91,7 @@
 
   encodeLpFields(interest, lpPacket);
 
-  this->sendNetPacket(std::move(lpPacket));
+  this->sendNetPacket(std::move(lpPacket), true);
 }
 
 void
@@ -100,7 +101,7 @@
 
   encodeLpFields(data, lpPacket);
 
-  this->sendNetPacket(std::move(lpPacket));
+  this->sendNetPacket(std::move(lpPacket), false);
 }
 
 void
@@ -111,11 +112,11 @@
 
   encodeLpFields(nack, lpPacket);
 
-  this->sendNetPacket(std::move(lpPacket));
+  this->sendNetPacket(std::move(lpPacket), false);
 }
 
 void
-GenericLinkService::encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket)
+GenericLinkService::encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket)
 {
   if (m_options.allowLocalFields) {
     shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
@@ -131,7 +132,7 @@
 }
 
 void
-GenericLinkService::sendNetPacket(lp::Packet&& pkt)
+GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
 {
   std::vector<lp::Packet> frags;
   ssize_t mtu = this->getTransport()->getMtu();
@@ -152,7 +153,12 @@
     }
   }
   else {
-    frags.push_back(std::move(pkt));
+    if (m_options.reliabilityOptions.isEnabled) {
+      frags.push_back(pkt);
+    }
+    else {
+      frags.push_back(std::move(pkt));
+    }
   }
 
   if (frags.size() == 1) {
@@ -169,7 +175,7 @@
   }
 
   if (m_options.reliabilityOptions.isEnabled && frags.front().has<lp::FragmentField>()) {
-    m_reliability.handleOutgoing(frags);
+    m_reliability.handleOutgoing(frags, std::move(pkt), isInterest);
   }
 
   for (lp::Packet& frag : frags) {
diff --git a/daemon/face/generic-link-service.hpp b/daemon/face/generic-link-service.hpp
index 4c347d6..1823b37 100644
--- a/daemon/face/generic-link-service.hpp
+++ b/daemon/face/generic-link-service.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
@@ -175,13 +175,14 @@
    *  \param lpPacket LpPacket to add link protocol fields to
    */
   void
-  encodeLpFields(const ndn::TagHost& netPkt, lp::Packet& lpPacket);
+  encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket);
 
   /** \brief send a complete network layer packet
    *  \param pkt LpPacket containing a complete network layer packet
+   *  \param isInterest whether the network layer packet is an Interest
    */
   void
-  sendNetPacket(lp::Packet&& pkt);
+  sendNetPacket(lp::Packet&& pkt, bool isInterest);
 
   /** \brief assign a sequence number to an LpPacket
    */
diff --git a/daemon/face/link-service.cpp b/daemon/face/link-service.cpp
index 00dd6f0..9b05c2a 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-2015,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -114,6 +114,13 @@
   afterReceiveNack(nack);
 }
 
+void
+LinkService::notifyDroppedInterest(const Interest& interest)
+{
+  ++this->nDroppedInterests;
+  onDroppedInterest(interest);
+}
+
 std::ostream&
 operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh)
 {
diff --git a/daemon/face/link-service.hpp b/daemon/face/link-service.hpp
index 618e863..b8e8749 100644
--- a/daemon/face/link-service.hpp
+++ b/daemon/face/link-service.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -27,8 +27,8 @@
 #define NFD_DAEMON_FACE_LINK_SERVICE_HPP
 
 #include "core/counter.hpp"
-#include "transport.hpp"
 #include "face-log.hpp"
+#include "transport.hpp"
 
 namespace nfd {
 namespace face {
@@ -50,11 +50,15 @@
    */
   PacketCounter nOutInterests;
 
-  /** \brief count of incoming Data
+  /** \brief count of Interests dropped by reliability system for exceeding allowed number of retx
+   */
+  PacketCounter nDroppedInterests;
+
+  /** \brief count of incoming Data packets
    */
   PacketCounter nInData;
 
-  /** \brief count of outgoing Data
+  /** \brief count of outgoing Data packets
    */
   PacketCounter nOutData;
 
@@ -138,6 +142,10 @@
    */
   signal::Signal<LinkService, lp::Nack> afterReceiveNack;
 
+  /** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
+   */
+  signal::Signal<LinkService, Interest> onDroppedInterest;
+
 public: // lower interface to be invoked by Transport
   /** \brief performs LinkService specific operations to receive a lower-layer packet
    */
@@ -166,6 +174,10 @@
   void
   sendPacket(Transport::Packet&& packet);
 
+protected:
+  void
+  notifyDroppedInterest(const Interest& packet);
+
 private: // upper interface to be overridden in subclass (send path entrypoint)
   /** \brief performs LinkService specific operations to send an Interest
    */
diff --git a/daemon/face/lp-reliability.cpp b/daemon/face/lp-reliability.cpp
index 2b587f9..0df5702 100644
--- a/daemon/face/lp-reliability.cpp
+++ b/daemon/face/lp-reliability.cpp
@@ -61,14 +61,14 @@
 }
 
 void
-LpReliability::handleOutgoing(std::vector<lp::Packet>& frags)
+LpReliability::handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt, bool isInterest)
 {
   BOOST_ASSERT(m_options.isEnabled);
 
   auto unackedFragsIt = m_unackedFrags.begin();
   auto sendTime = time::steady_clock::now();
 
-  auto netPkt = make_shared<NetPkt>();
+  auto netPkt = make_shared<NetPkt>(std::move(pkt), isInterest);
   netPkt->unackedFrags.reserve(frags.size());
 
   for (lp::Packet& frag : frags) {
@@ -250,6 +250,16 @@
     }
 
     ++m_linkService->nRetxExhausted;
+
+    // Notify strategy of dropped Interest (if any)
+    if (netPkt->isInterest) {
+      BOOST_ASSERT(netPkt->pkt.has<lp::FragmentField>());
+      ndn::Buffer::const_iterator fragBegin, fragEnd;
+      std::tie(fragBegin, fragEnd) = netPkt->pkt.get<lp::FragmentField>();
+      Block frag(&*fragBegin, std::distance(fragBegin, fragEnd));
+      onDroppedInterest(Interest(frag));
+    }
+
     deleteUnackedFrag(txSeqIt);
   }
   else {
@@ -337,5 +347,12 @@
 {
 }
 
+LpReliability::NetPkt::NetPkt(lp::Packet&& pkt, bool isInterest)
+  : pkt(std::move(pkt))
+  , isInterest(isInterest)
+  , didRetx(false)
+{
+}
+
 } // namespace face
 } // namespace nfd
diff --git a/daemon/face/lp-reliability.hpp b/daemon/face/lp-reliability.hpp
index d1f4622..328edb0 100644
--- a/daemon/face/lp-reliability.hpp
+++ b/daemon/face/lp-reliability.hpp
@@ -67,6 +67,10 @@
 
   LpReliability(const Options& options, GenericLinkService* linkService);
 
+  /** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
+   */
+  signal::Signal<LpReliability, Interest> onDroppedInterest;
+
   /** \brief set options for reliability
    */
   void
@@ -81,9 +85,11 @@
 
   /** \brief observe outgoing fragment(s) of a network packet and store for potential retransmission
    *  \param frags fragments of network packet
+   *  \param pkt encapsulated network packet
+   *  \param isInterest whether the network packet is an Interest
    */
   void
-  handleOutgoing(std::vector<lp::Packet>& frags);
+  handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt, bool isInterest);
 
   /** \brief extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue
    *  \param pkt incoming LpPacket
@@ -182,8 +188,13 @@
   class NetPkt
   {
   public:
+    NetPkt(lp::Packet&& pkt, bool isInterest);
+
+  public:
     std::vector<UnackedFrags::iterator> unackedFrags;
-    bool didRetx = false;
+    lp::Packet pkt;
+    bool isInterest;
+    bool didRetx;
   };
 
 public:
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 69a93de..6d57a2d 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -61,6 +61,10 @@
       [this, &face] (const lp::Nack& nack) {
         this->startProcessNack(face, nack);
       });
+    face.onDroppedInterest.connect(
+      [this, &face] (const Interest& interest) {
+        this->onDroppedInterest(face, interest);
+      });
   });
 
   m_faceTable.beforeRemove.connect([this] (Face& face) {
@@ -481,6 +485,12 @@
   ++m_counters.nOutNacks;
 }
 
+void
+Forwarder::onDroppedInterest(Face& outFace, const Interest& interest)
+{
+  m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(outFace, interest);
+}
+
 static inline bool
 compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
 {
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index d2e73a8..6d50909 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -252,6 +252,9 @@
   VIRTUAL_WITH_TESTS void
   onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace, const lp::NackHeader& nack);
 
+  VIRTUAL_WITH_TESTS void
+  onDroppedInterest(Face& outFace, const Interest& interest);
+
 PROTECTED_WITH_TESTS_ELSE_PRIVATE:
   VIRTUAL_WITH_TESTS void
   setUnsatisfyTimer(const shared_ptr<pit::Entry>& pitEntry);
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index fea2164..284b1f2 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -171,6 +171,12 @@
 }
 
 void
+Strategy::onDroppedInterest(const Face& outFace, const Interest& interest)
+{
+  NFD_LOG_DEBUG("onDroppedInterest outFace=" << outFace.getId() << " name=" << interest.getName());
+}
+
+void
 Strategy::sendNacks(const shared_ptr<pit::Entry>& pitEntry, const lp::NackHeader& header,
                     std::initializer_list<const Face*> exceptFaces)
 {
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 99ed1dc..e09b590 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -1,5 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
+/*
  * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
@@ -181,6 +181,13 @@
   afterReceiveNack(const Face& inFace, const lp::Nack& nack,
                    const shared_ptr<pit::Entry>& pitEntry);
 
+  /** \brief trigger after Interest dropped for exceeding allowed retransmissions
+   *
+   *  In the base class this method does nothing.
+   */
+  virtual void
+  onDroppedInterest(const Face& outFace, const Interest& interest);
+
 protected: // actions
   /** \brief send Interest to outFace
    *  \param pitEntry PIT entry
diff --git a/tests/daemon/face/lp-reliability.t.cpp b/tests/daemon/face/lp-reliability.t.cpp
index 16fb88f..5c7bc27 100644
--- a/tests/daemon/face/lp-reliability.t.cpp
+++ b/tests/daemon/face/lp-reliability.t.cpp
@@ -54,7 +54,10 @@
   sendLpPackets(std::vector<lp::Packet> frags)
   {
     if (frags.front().has<lp::FragmentField>()) {
-      m_reliability.handleOutgoing(frags);
+      Interest interest("/test/prefix");
+      lp::Packet pkt;
+      pkt.add<lp::FragmentField>(make_pair(interest.wireEncode().begin(), interest.wireEncode().end()));
+      m_reliability.handleOutgoing(frags, std::move(pkt), true);
     }
 
     for (lp::Packet frag : frags) {
@@ -176,6 +179,7 @@
   linkService->sendLpPackets({pkt});
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.size(), 0);
   BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 }
 
 BOOST_AUTO_TEST_CASE(SendUnfragmentedRetx)
@@ -190,6 +194,7 @@
   BOOST_CHECK(!cached1.has<lp::SequenceField>());
   lp::Sequence firstTxSeq = cached1.get<lp::TxSequenceField>();
   BOOST_CHECK_EQUAL(getPktNo(cached1), 1024);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+500ms
   // 1024 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -208,6 +213,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.at(firstTxSeq + 1).retxCount, 0);
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, firstTxSeq);
   BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+1250ms
   // 1024 rto: 1000ms, txSeq: 4, started T+1000ms, retx 1
@@ -222,6 +228,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.at(firstTxSeq + 1).retxCount, 0);
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, firstTxSeq + 1);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 3);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+2250ms
   // 1024 rto: 1000ms, txSeq: 6, started T+2000ms, retx 2
@@ -237,6 +244,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.at(firstTxSeq + 3).retxCount, 1);
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, firstTxSeq + 3);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 5);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+3250ms
   // 1024 rto: 1000ms, txSeq: 8, started T+3000ms, retx 3
@@ -252,6 +260,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.at(firstTxSeq + 5).retxCount, 2);
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, firstTxSeq + 5);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 7);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+4250ms
   // 1024 rto: expired, removed
@@ -266,6 +275,8 @@
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, firstTxSeq + 7);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 8);
 
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 1);
+
   // T+4750ms
   // 1024 rto: expired, removed
   // 3000 rto: expired, removed
@@ -274,6 +285,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.size(), 0);
   BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 8);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 2);
 }
 
 BOOST_AUTO_TEST_CASE(SendFragmentedRetx)
@@ -297,6 +309,7 @@
   BOOST_REQUIRE(cached3.has<lp::TxSequenceField>());
   BOOST_CHECK_EQUAL(cached3.get<lp::TxSequenceField>(), 4);
   BOOST_CHECK_EQUAL(getPktNo(cached3), 2050);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+0ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -324,6 +337,7 @@
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 2);
   BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 3);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+250ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -354,6 +368,7 @@
   BOOST_CHECK(netPktHasUnackedFrag(reliability->m_unackedFrags.at(2).netPkt, 4));
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 2);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 4);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+500ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -384,6 +399,7 @@
   BOOST_CHECK(netPktHasUnackedFrag(reliability->m_unackedFrags.at(2).netPkt, 4));
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 2);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 5);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+750ms
   // 2048 rto: 1000ms, txSeq: 2, started T+0ms, retx 0
@@ -414,6 +430,7 @@
   BOOST_CHECK(netPktHasUnackedFrag(reliability->m_unackedFrags.at(2).netPkt, 4));
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 2);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 6);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   // T+850ms
   // 2048 rto: expired, removed
@@ -424,6 +441,7 @@
 
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.size(), 0);
   BOOST_CHECK_EQUAL(reliability->m_ackQueue.size(), 0);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 1);
 }
 
 BOOST_AUTO_TEST_CASE(LossByGreaterAcks) // detect loss by 3x greater Acks, also tests wraparound
@@ -449,6 +467,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.count(3), 1); // pkt5
   BOOST_CHECK(reliability->m_unackedFrags.at(3).netPkt);
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 0xFFFFFFFFFFFFFFFF);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   lp::Packet ackPkt1;
   ackPkt1.add<lp::AckField>(0);
@@ -473,6 +492,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.at(3).nGreaterSeqAcks, 0);
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 0xFFFFFFFFFFFFFFFF);
   BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 5);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   lp::Packet ackPkt2;
   ackPkt2.add<lp::AckField>(2);
@@ -497,6 +517,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.count(101010), 0);
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 0xFFFFFFFFFFFFFFFF);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 5);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   lp::Packet ackPkt3;
   ackPkt3.add<lp::AckField>(1);
@@ -523,6 +544,7 @@
   BOOST_CHECK_EQUAL(sentRetxPkt.get<lp::TxSequenceField>(), 4);
   BOOST_REQUIRE(sentRetxPkt.has<lp::FragmentField>());
   BOOST_CHECK_EQUAL(getPktNo(sentRetxPkt), 1);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 
   lp::Packet ackPkt4;
   ackPkt4.add<lp::AckField>(4);
@@ -542,6 +564,7 @@
   BOOST_CHECK_EQUAL(reliability->m_unackedFrags.count(4), 0); // pkt1 new TxSeq
   BOOST_CHECK_EQUAL(reliability->m_firstUnackedFrag->first, 3);
   BOOST_CHECK_EQUAL(transport->sentPackets.size(), 6);
+  BOOST_CHECK_EQUAL(linkService->getCounters().nDroppedInterests, 0);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // Sender