face: Make congestion marking less aggressive

Implement something closer to the CoDel Algorithm (RFC 8289)

Refs: #5003
Change-Id: I909975e7ae1c50d08561a001b67cd9c2c2f150b1
diff --git a/daemon/face/generic-link-service.cpp b/daemon/face/generic-link-service.cpp
index 2ab9f7e..601c041 100644
--- a/daemon/face/generic-link-service.cpp
+++ b/daemon/face/generic-link-service.cpp
@@ -39,8 +39,6 @@
                                         tlv::sizeOfVarNumber(sizeof(uint64_t)) +        // length
                                         tlv::sizeOfNonNegativeInteger(UINT64_MAX);      // value
 
-constexpr uint32_t DEFAULT_CONGESTION_THRESHOLD_DIVISOR = 2;
-
 GenericLinkService::GenericLinkService(const GenericLinkService::Options& options)
   : m_options(options)
   , m_fragmenter(m_options.fragmenterOptions, this)
@@ -48,7 +46,6 @@
   , m_reliability(m_options.reliabilityOptions, this)
   , m_lastSeqNo(-2)
   , m_nextMarkTime(time::steady_clock::TimePoint::max())
-  , m_lastMarkTime(time::steady_clock::TimePoint::min())
   , m_nMarkedSinceInMarkingState(0)
 {
   m_reassembler.beforeTimeout.connect([this] (auto...) { ++this->nReassemblyTimeouts; });
@@ -232,34 +229,26 @@
 GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
 {
   ssize_t sendQueueLength = getTransport()->getSendQueueLength();
-  // This operation requires that the transport supports retrieving current send queue length
+  // The transport must support retrieving the current send queue length
   if (sendQueueLength < 0) {
     return;
   }
 
-  // To avoid overflowing the queue, set the congestion threshold to at least half of the send
-  // queue capacity.
-  size_t congestionThreshold = m_options.defaultCongestionThreshold;
-  if (getTransport()->getSendQueueCapacity() >= 0) {
-    congestionThreshold = std::min(congestionThreshold,
-                                   static_cast<size_t>(getTransport()->getSendQueueCapacity()) /
-                                                       DEFAULT_CONGESTION_THRESHOLD_DIVISOR);
-  }
-
   if (sendQueueLength > 0) {
-    NFD_LOG_FACE_TRACE("txqlen=" << sendQueueLength << " threshold=" << congestionThreshold <<
-                       " capacity=" << getTransport()->getSendQueueCapacity());
+    NFD_LOG_FACE_TRACE("txqlen=" << sendQueueLength << " threshold=" <<
+                       m_options.defaultCongestionThreshold << " capacity=" <<
+                       getTransport()->getSendQueueCapacity());
   }
 
-  if (static_cast<size_t>(sendQueueLength) > congestionThreshold) { // Send queue is congested
+  // sendQueue is above target
+  if (static_cast<size_t>(sendQueueLength) > m_options.defaultCongestionThreshold) {
     const auto now = time::steady_clock::now();
-    if (now >= m_nextMarkTime || now >= m_lastMarkTime + m_options.baseCongestionMarkingInterval) {
-      // Mark at most one initial packet per baseCongestionMarkingInterval
-      if (m_nMarkedSinceInMarkingState == 0) {
-        m_nextMarkTime = now;
-      }
 
-      // Time to mark packet
+    if (m_nextMarkTime == time::steady_clock::TimePoint::max()) {
+      m_nextMarkTime = now + m_options.baseCongestionMarkingInterval;
+    }
+    // Mark packet if sendQueue stays above target for one interval
+    else if (now >= m_nextMarkTime) {
       pkt.set<lp::CongestionMarkField>(1);
       ++nCongestionMarked;
       NFD_LOG_FACE_DEBUG("LpPacket was marked as congested");
@@ -267,10 +256,10 @@
       ++m_nMarkedSinceInMarkingState;
       // Decrease the marking interval by the inverse of the square root of the number of packets
       // marked in this incident of congestion
-      m_nextMarkTime += time::nanoseconds(static_cast<time::nanoseconds::rep>(
-                                            m_options.baseCongestionMarkingInterval.count() /
-                                            std::sqrt(m_nMarkedSinceInMarkingState)));
-      m_lastMarkTime = now;
+      time::nanoseconds interval(static_cast<time::nanoseconds::rep>(
+                                   m_options.baseCongestionMarkingInterval.count() /
+                                   std::sqrt(m_nMarkedSinceInMarkingState + 1)));
+      m_nextMarkTime += interval;
     }
   }
   else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {