chunks: react to congestion marks

Change-Id: I96efe1bc3ec7a54080c76676892114f2c79003ed
refs: #4289
diff --git a/tools/chunks/catchunks/ndncatchunks.cpp b/tools/chunks/catchunks/ndncatchunks.cpp
index 2242a83..822194a 100644
--- a/tools/chunks/catchunks/ndncatchunks.cpp
+++ b/tools/chunks/catchunks/ndncatchunks.cpp
@@ -26,6 +26,7 @@
  * @author Davide Pesavento
  * @author Weiwei Liu
  * @author Klaus Schneider
+ * @author Chavoosh Ghasemi
  */
 
 #include "aimd-statistics-collector.hpp"
@@ -58,7 +59,7 @@
 
   // congestion control parameters, CWA refers to conservative window adaptation,
   // i.e. only reduce window size at most once per RTT
-  bool disableCwa(false), resetCwndToInit(false);
+  bool disableCwa(false), resetCwndToInit(false), ignoreCongMarks(false);
   double aiStep(1.0), mdCoef(0.5), alpha(0.125), beta(0.25),
          minRto(200.0), maxRto(4000.0);
   int initCwnd(1), initSsthresh(std::numeric_limits<int>::max()), k(4);
@@ -104,7 +105,11 @@
                        "log file for AIMD rtt statistics")
     ("aimd-disable-cwa", po::bool_switch(&disableCwa),
                          "disable Conservative Window Adaptation, "
-                         "i.e. reduce window on each timeout (instead of at most once per RTT)")
+                         "i.e. reduce window on each congestion event (timeout or congestion mark) "
+                         "instead of at most once per RTT")
+    ("aimd-ignore-cong-marks",  po::bool_switch(&ignoreCongMarks),
+                                "disable reaction to congestion marks, "
+                                "the default is to decrease the window after receiving a congestion mark")
     ("aimd-reset-cwnd-to-init", po::bool_switch(&resetCwndToInit),
                                 "reset cwnd to initial cwnd when loss event occurs, default is "
                                 "resetting to ssthresh")
@@ -253,6 +258,7 @@
       optionsPipeline.initSsthresh = static_cast<double>(initSsthresh);
       optionsPipeline.aiStep = aiStep;
       optionsPipeline.mdCoef = mdCoef;
+      optionsPipeline.ignoreCongMarks = ignoreCongMarks;
 
       auto aimdPipeline = make_unique<PipelineInterestsAimd>(face, *rttEstimator, optionsPipeline);
 
diff --git a/tools/chunks/catchunks/pipeline-interests-aimd.cpp b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
index b979a51..61ed8f3 100644
--- a/tools/chunks/catchunks/pipeline-interests-aimd.cpp
+++ b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
@@ -33,6 +33,8 @@
 namespace chunks {
 namespace aimd {
 
+constexpr double PipelineInterestsAimd::MIN_SSTHRESH;
+
 PipelineInterestsAimd::PipelineInterestsAimd(Face& face, RttEstimator& rttEstimator,
                                              const Options& options)
   : PipelineInterests(face)
@@ -46,6 +48,7 @@
   , m_nInFlight(0)
   , m_nLossEvents(0)
   , m_nRetransmitted(0)
+  , m_nCongMarks(0)
   , m_cwnd(m_options.initCwnd)
   , m_ssthresh(m_options.initSsthresh)
   , m_hasFailure(false)
@@ -244,7 +247,30 @@
     m_nInFlight--;
   }
 
-  increaseWindow();
+  // upon finding congestion mark, decrease the window size
+  // without retransmitting any packet
+  if (data.getCongestionMark() > 0) {
+    m_nCongMarks++;
+    if (!m_options.ignoreCongMarks) {
+      if (m_options.disableCwa || m_highData > m_recPoint) {
+        m_recPoint = m_highInterest;  // react to only one congestion event (timeout or congestion mark)
+                                      // per RTT (conservative window adaptation)
+        decreaseWindow();
+
+        if (m_options.isVerbose) {
+          std::cerr << "Received congestion mark, value = " << data.getCongestionMark()
+                    << ", new cwnd = " << m_cwnd << std::endl;
+        }
+      }
+    }
+    else {
+      increaseWindow();
+    }
+  }
+  else {
+    increaseWindow();
+  }
+
   onData(data);
 
   if (segInfo.state == SegmentState::FirstTimeSent ||
@@ -324,7 +350,7 @@
     m_nLossEvents++;
 
     if (m_options.isVerbose) {
-      std::cerr << "Packet loss event, cwnd = " << m_cwnd
+      std::cerr << "Packet loss event, new cwnd = " << m_cwnd
                 << ", ssthresh = " << m_ssthresh << std::endl;
     }
   }
@@ -382,7 +408,7 @@
 PipelineInterestsAimd::decreaseWindow()
 {
   // please refer to RFC 5681, Section 3.1 for the rationale behind it
-  m_ssthresh = std::max(2.0, m_cwnd * m_options.mdCoef); // multiplicative decrease
+  m_ssthresh = std::max(MIN_SSTHRESH, m_cwnd * m_options.mdCoef); // multiplicative decrease
   m_cwnd = m_options.resetCwndToInit ? m_options.initCwnd : m_ssthresh;
 
   afterCwndChange(time::steady_clock::now() - getStartTime(), m_cwnd);
@@ -411,7 +437,8 @@
   std::cerr << "Total # of packet loss events: " << m_nLossEvents << "\n"
             << "Packet loss rate: "
             << static_cast<double>(m_nLossEvents) / static_cast<double>(m_nReceived) << "\n"
-            << "Total # of retransmitted segments: " << m_nRetransmitted << "\n";
+            << "Total # of retransmitted segments: " << m_nRetransmitted << "\n"
+            << "Total # of received congestion marks: " << m_nCongMarks << "\n";
 }
 
 std::ostream&
@@ -444,6 +471,7 @@
      << "\tMultiplicative decrease factor = " << options.mdCoef << "\n"
      << "\tRTO check interval = " << options.rtoCheckInterval << "\n"
      << "\tMax retries on timeout or Nack = " << options.maxRetriesOnTimeoutOrNack << "\n"
+     << "\tReaction to congestion marks " << (options.ignoreCongMarks ? "disabled" : "enabled") << "\n"
      << "\tConservative Window Adaptation " << (options.disableCwa ? "disabled" : "enabled") << "\n"
      << "\tResetting cwnd to " << (options.resetCwndToInit ? "initCwnd" : "ssthresh") << " upon loss event\n";
   return os;
diff --git a/tools/chunks/catchunks/pipeline-interests-aimd.hpp b/tools/chunks/catchunks/pipeline-interests-aimd.hpp
index 5aedbfb..bbc9940 100644
--- a/tools/chunks/catchunks/pipeline-interests-aimd.hpp
+++ b/tools/chunks/catchunks/pipeline-interests-aimd.hpp
@@ -56,6 +56,7 @@
   time::milliseconds rtoCheckInterval{10}; ///< interval for checking retransmission timer
   bool disableCwa = false; ///< disable Conservative Window Adaptation
   bool resetCwndToInit = false; ///< reduce cwnd to initCwnd when loss event occurs
+  bool ignoreCongMarks = false; ///< disable window decrease after congestion marks
 };
 
 /**
@@ -187,6 +188,7 @@
   printSummary() const final;
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  static constexpr double MIN_SSTHRESH = 2.0;
   const Options m_options;
   RttEstimator& m_rttEstimator;
   Scheduler m_scheduler;
@@ -200,6 +202,7 @@
   int64_t m_nInFlight; ///< # of segments in flight
   int64_t m_nLossEvents; ///< # of loss events occurred
   int64_t m_nRetransmitted; ///< # of segments retransmitted
+  int64_t m_nCongMarks; ///< # of data packets with congestion mark
 
   double m_cwnd; ///< current congestion window size (in segments)
   double m_ssthresh; ///< current slow start threshold