mgmt: add congestion marking parameters

refs #4465

Change-Id: I5090d93b59fe3fc425e5ce529c4f66b8211155dd
diff --git a/src/encoding/nfd-constants.hpp b/src/encoding/nfd-constants.hpp
index 5951311..01e8c2b 100644
--- a/src/encoding/nfd-constants.hpp
+++ b/src/encoding/nfd-constants.hpp
@@ -67,8 +67,9 @@
 /** \ingroup management
  */
 enum FaceFlagBit {
-  BIT_LOCAL_FIELDS_ENABLED = 0, ///< controls whether local fields are enabled on a face
-  BIT_LP_RELIABILITY_ENABLED = 1, ///< controls whether the link reliability feature is enabled on a face
+  BIT_LOCAL_FIELDS_ENABLED = 0, ///< whether local fields are enabled on a face
+  BIT_LP_RELIABILITY_ENABLED = 1, ///< whether the link reliability feature is enabled on a face
+  BIT_CONGESTION_MARKING_ENABLED = 2, ///< whether congestion detection and marking is enabled on a face
 };
 
 /** \ingroup management
diff --git a/src/encoding/tlv-nfd.hpp b/src/encoding/tlv-nfd.hpp
index 0326024..1c4d12d 100644
--- a/src/encoding/tlv-nfd.hpp
+++ b/src/encoding/tlv-nfd.hpp
@@ -59,16 +59,18 @@
   NCsEntries           = 135,
 
   // Face Management
-  FaceStatus            = 128,
-  LocalUri              = 129,
-  ChannelStatus         = 130,
-  UriScheme             = 131,
-  FaceScope             = 132,
-  FacePersistency       = 133,
-  LinkType              = 134,
-  FaceQueryFilter       = 150,
-  FaceEventNotification = 192,
-  FaceEventKind         = 193,
+  FaceStatus                    = 128,
+  LocalUri                      = 129,
+  ChannelStatus                 = 130,
+  UriScheme                     = 131,
+  FaceScope                     = 132,
+  FacePersistency               = 133,
+  LinkType                      = 134,
+  BaseCongestionMarkingInterval = 135,
+  DefaultCongestionThreshold    = 136,
+  FaceQueryFilter               = 150,
+  FaceEventNotification         = 192,
+  FaceEventKind                 = 193,
 
   // ForwarderStatus and FaceStatus counters
   NInInterests  = 144,
diff --git a/src/mgmt/nfd/control-command.cpp b/src/mgmt/nfd/control-command.cpp
index f85c870..472f329 100644
--- a/src/mgmt/nfd/control-command.cpp
+++ b/src/mgmt/nfd/control-command.cpp
@@ -103,6 +103,8 @@
     .required(CONTROL_PARAMETER_URI)
     .optional(CONTROL_PARAMETER_LOCAL_URI)
     .optional(CONTROL_PARAMETER_FACE_PERSISTENCY)
+    .optional(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL)
+    .optional(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD)
     .optional(CONTROL_PARAMETER_FLAGS)
     .optional(CONTROL_PARAMETER_MASK);
   m_responseValidator
@@ -110,6 +112,8 @@
     .required(CONTROL_PARAMETER_URI)
     .required(CONTROL_PARAMETER_LOCAL_URI)
     .required(CONTROL_PARAMETER_FACE_PERSISTENCY)
+    .required(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL)
+    .required(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD)
     .required(CONTROL_PARAMETER_FLAGS);
 }
 
@@ -137,11 +141,15 @@
   m_requestValidator
     .optional(CONTROL_PARAMETER_FACE_ID)
     .optional(CONTROL_PARAMETER_FACE_PERSISTENCY)
+    .optional(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL)
+    .optional(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD)
     .optional(CONTROL_PARAMETER_FLAGS)
     .optional(CONTROL_PARAMETER_MASK);
   m_responseValidator
     .required(CONTROL_PARAMETER_FACE_ID)
     .required(CONTROL_PARAMETER_FACE_PERSISTENCY)
+    .required(CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL)
+    .required(CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD)
     .required(CONTROL_PARAMETER_FLAGS);
 }
 
diff --git a/src/mgmt/nfd/control-parameters.cpp b/src/mgmt/nfd/control-parameters.cpp
index a98e807..1e4d9fe 100644
--- a/src/mgmt/nfd/control-parameters.cpp
+++ b/src/mgmt/nfd/control-parameters.cpp
@@ -51,6 +51,14 @@
 {
   size_t totalLength = 0;
 
+  if (this->hasDefaultCongestionThreshold()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::DefaultCongestionThreshold, m_defaultCongestionThreshold);
+  }
+  if (this->hasBaseCongestionMarkingInterval()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::BaseCongestionMarkingInterval, m_baseCongestionMarkingInterval.count());
+  }
   if (this->hasFacePersistency()) {
     totalLength += prependNonNegativeIntegerBlock(encoder,
                    tlv::nfd::FacePersistency, m_facePersistency);
@@ -200,6 +208,18 @@
   if (this->hasFacePersistency()) {
     m_facePersistency = readNonNegativeIntegerAs<FacePersistency>(*val);
   }
+
+  val = m_wire.find(tlv::nfd::BaseCongestionMarkingInterval);
+  m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL] = val != m_wire.elements_end();
+  if (this->hasBaseCongestionMarkingInterval()) {
+    m_baseCongestionMarkingInterval = time::nanoseconds(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::DefaultCongestionThreshold);
+  m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD] = val != m_wire.elements_end();
+  if (this->hasDefaultCongestionThreshold()) {
+    m_defaultCongestionThreshold = readNonNegativeInteger(*val);
+  }
 }
 
 bool
@@ -328,6 +348,14 @@
     os << "FacePersistency: " << parameters.getFacePersistency() << ", ";
   }
 
+  if (parameters.hasBaseCongestionMarkingInterval()) {
+    os << "BaseCongestionMarkingInterval: " << parameters.getBaseCongestionMarkingInterval() << ", ";
+  }
+
+  if (parameters.hasDefaultCongestionThreshold()) {
+    os << "DefaultCongestionThreshold: " << parameters.getDefaultCongestionThreshold() << ", ";
+  }
+
   os << ")";
   return os;
 }
diff --git a/src/mgmt/nfd/control-parameters.hpp b/src/mgmt/nfd/control-parameters.hpp
index 79b84e0..ca1d75d 100644
--- a/src/mgmt/nfd/control-parameters.hpp
+++ b/src/mgmt/nfd/control-parameters.hpp
@@ -46,6 +46,8 @@
   CONTROL_PARAMETER_STRATEGY,
   CONTROL_PARAMETER_EXPIRATION_PERIOD,
   CONTROL_PARAMETER_FACE_PERSISTENCY,
+  CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL,
+  CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD,
   CONTROL_PARAMETER_UBOUND
 };
 
@@ -61,7 +63,9 @@
   "Mask",
   "Strategy",
   "ExpirationPeriod",
-  "FacePersistency"
+  "FacePersistency",
+  "BaseCongestionMarkingInterval",
+  "DefaultCongestionThreshold"
 };
 
 /**
@@ -459,6 +463,70 @@
     return *this;
   }
 
+  bool
+  hasBaseCongestionMarkingInterval() const
+  {
+    return m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL];
+  }
+
+  time::nanoseconds
+  getBaseCongestionMarkingInterval() const
+  {
+    BOOST_ASSERT(this->hasBaseCongestionMarkingInterval());
+    return m_baseCongestionMarkingInterval;
+  }
+
+  ControlParameters&
+  setBaseCongestionMarkingInterval(time::nanoseconds interval)
+  {
+    m_wire.reset();
+    m_baseCongestionMarkingInterval = interval;
+    m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL] = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetBaseCongestionMarkingInterval()
+  {
+    m_wire.reset();
+    m_hasFields[CONTROL_PARAMETER_BASE_CONGESTION_MARKING_INTERVAL] = false;
+    return *this;
+  }
+
+  bool
+  hasDefaultCongestionThreshold() const
+  {
+    return m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD];
+  }
+
+  /** \brief get default congestion threshold (measured in bytes)
+   */
+  uint64_t
+  getDefaultCongestionThreshold() const
+  {
+    BOOST_ASSERT(this->hasDefaultCongestionThreshold());
+    return m_defaultCongestionThreshold;
+  }
+
+  /** \brief set default congestion threshold (measured in bytes)
+   */
+  ControlParameters&
+  setDefaultCongestionThreshold(uint64_t threshold)
+  {
+    m_wire.reset();
+    m_defaultCongestionThreshold = threshold;
+    m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD] = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetDefaultCongestionThreshold()
+  {
+    m_wire.reset();
+    m_hasFields[CONTROL_PARAMETER_DEFAULT_CONGESTION_THRESHOLD] = false;
+    return *this;
+  }
+
   const std::vector<bool>&
   getPresentFields() const
   {
@@ -512,6 +580,8 @@
   Name                m_strategy;
   time::milliseconds  m_expirationPeriod;
   FacePersistency     m_facePersistency;
+  time::nanoseconds   m_baseCongestionMarkingInterval;
+  uint64_t            m_defaultCongestionThreshold;
 
 private:
   mutable Block m_wire;
diff --git a/src/mgmt/nfd/face-status.cpp b/src/mgmt/nfd/face-status.cpp
index 360865a..0a284cd 100644
--- a/src/mgmt/nfd/face-status.cpp
+++ b/src/mgmt/nfd/face-status.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -32,7 +32,9 @@
 BOOST_CONCEPT_ASSERT((StatusDatasetItem<FaceStatus>));
 
 FaceStatus::FaceStatus()
-  : m_nInInterests(0)
+  : m_baseCongestionMarkingInterval(0)
+  , m_defaultCongestionThreshold(0)
+  , m_nInInterests(0)
   , m_nInData(0)
   , m_nInNacks(0)
   , m_nOutInterests(0)
@@ -63,6 +65,10 @@
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInNacks, m_nInNacks);
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInData, m_nInData);
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NInInterests, m_nInInterests);
+  totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::DefaultCongestionThreshold,
+                                                m_defaultCongestionThreshold);
+  totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::BaseCongestionMarkingInterval,
+                                                m_baseCongestionMarkingInterval.count());
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::LinkType, m_linkType);
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FacePersistency, m_facePersistency);
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceScope, m_faceScope);
@@ -163,6 +169,22 @@
     BOOST_THROW_EXCEPTION(Error("missing required LinkType field"));
   }
 
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::BaseCongestionMarkingInterval) {
+    m_baseCongestionMarkingInterval = time::nanoseconds(readNonNegativeInteger(*val));
+    ++val;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("missing required BaseCongestionMarkingInterval field"));
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::DefaultCongestionThreshold) {
+    m_defaultCongestionThreshold = readNonNegativeInteger(*val);
+    ++val;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("missing required DefaultCongestionThreshold field"));
+  }
+
   if (val != m_wire.elements_end() && val->type() == tlv::nfd::NInInterests) {
     m_nInInterests = readNonNegativeInteger(*val);
     ++val;
@@ -253,6 +275,22 @@
 }
 
 FaceStatus&
+FaceStatus::setBaseCongestionMarkingInterval(time::nanoseconds interval)
+{
+  m_wire.reset();
+  m_baseCongestionMarkingInterval = interval;
+  return *this;
+}
+
+FaceStatus&
+FaceStatus::setDefaultCongestionThreshold(uint64_t threshold)
+{
+  m_wire.reset();
+  m_defaultCongestionThreshold = threshold;
+  return *this;
+}
+
+FaceStatus&
 FaceStatus::setNInInterests(uint64_t nInInterests)
 {
   m_wire.reset();
@@ -328,6 +366,8 @@
       a.getFlags() == b.getFlags() &&
       a.hasExpirationPeriod() == b.hasExpirationPeriod() &&
       (!a.hasExpirationPeriod() || a.getExpirationPeriod() == b.getExpirationPeriod()) &&
+      a.getBaseCongestionMarkingInterval() == b.getBaseCongestionMarkingInterval() &&
+      a.getDefaultCongestionThreshold() == b.getDefaultCongestionThreshold() &&
       a.getNInInterests() == b.getNInInterests() &&
       a.getNInData() == b.getNInData() &&
       a.getNInNacks() == b.getNInNacks() &&
@@ -355,6 +395,8 @@
   os << "     FaceScope: " << status.getFaceScope() << ",\n"
      << "     FacePersistency: " << status.getFacePersistency() << ",\n"
      << "     LinkType: " << status.getLinkType() << ",\n"
+     << "     BaseCongestionMarkingInterval: " << status.getBaseCongestionMarkingInterval() << ",\n"
+     << "     DefaultCongestionThreshold: " << status.getDefaultCongestionThreshold() << " bytes,\n"
      << "     Flags: " << AsHex{status.getFlags()} << ",\n"
      << "     Counters: {Interests: {in: " << status.getNInInterests() << ", "
      << "out: " << status.getNOutInterests() << "},\n"
diff --git a/src/mgmt/nfd/face-status.hpp b/src/mgmt/nfd/face-status.hpp
index aa7accb..7835dba 100644
--- a/src/mgmt/nfd/face-status.hpp
+++ b/src/mgmt/nfd/face-status.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -77,6 +77,28 @@
   FaceStatus&
   unsetExpirationPeriod();
 
+  time::nanoseconds
+  getBaseCongestionMarkingInterval() const
+  {
+    return m_baseCongestionMarkingInterval;
+  }
+
+  FaceStatus&
+  setBaseCongestionMarkingInterval(time::nanoseconds interval);
+
+  /** \brief get default congestion threshold (measured in bytes)
+   */
+  uint64_t
+  getDefaultCongestionThreshold() const
+  {
+    return m_defaultCongestionThreshold;
+  }
+
+  /** \brief set default congestion threshold (measured in bytes)
+   */
+  FaceStatus&
+  setDefaultCongestionThreshold(uint64_t threshold);
+
   uint64_t
   getNInInterests() const
   {
@@ -151,6 +173,8 @@
 
 private:
   optional<time::milliseconds> m_expirationPeriod;
+  time::nanoseconds m_baseCongestionMarkingInterval;
+  uint64_t m_defaultCongestionThreshold;
   uint64_t m_nInInterests;
   uint64_t m_nInData;
   uint64_t m_nInNacks;