mgmt: add capacity and enablement flags to CsInfo

refs #4050

Change-Id: I9363f6735c6917591e0907b3d94f36d7263d10e7
diff --git a/src/mgmt/nfd/cs-info.cpp b/src/mgmt/nfd/cs-info.cpp
index b776c53..c7b7f7d 100644
--- a/src/mgmt/nfd/cs-info.cpp
+++ b/src/mgmt/nfd/cs-info.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).
  *
@@ -31,7 +31,9 @@
 BOOST_CONCEPT_ASSERT((StatusDatasetItem<CsInfo>));
 
 CsInfo::CsInfo()
-  : m_nHits(0)
+  : m_capacity(0)
+  , m_nEntries(0)
+  , m_nHits(0)
   , m_nMisses(0)
 {
 }
@@ -49,6 +51,9 @@
 
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NMisses, m_nMisses);
   totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NHits, m_nHits);
+  totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::NCsEntries, m_nEntries);
+  totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags.to_ullong());
+  totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Capacity, m_capacity);
 
   totalLength += encoder.prependVarNumber(totalLength);
   totalLength += encoder.prependVarNumber(tlv::nfd::CsInfo);
@@ -83,6 +88,30 @@
   m_wire.parse();
   auto val = m_wire.elements_begin();
 
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::Capacity) {
+    m_nHits = readNonNegativeInteger(*val);
+    ++val;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("missing required Capacity field"));
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::Flags) {
+    m_flags = FlagsBitSet(static_cast<unsigned long long>(readNonNegativeInteger(*val)));
+    ++val;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("missing required Flags field"));
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::NCsEntries) {
+    m_nEntries = readNonNegativeInteger(*val);
+    ++val;
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("missing required NCsEntries field"));
+  }
+
   if (val != m_wire.elements_end() && val->type() == tlv::nfd::NHits) {
     m_nHits = readNonNegativeInteger(*val);
     ++val;
@@ -101,6 +130,38 @@
 }
 
 CsInfo&
+CsInfo::setCapacity(uint64_t capacity)
+{
+  m_wire.reset();
+  m_capacity = capacity;
+  return *this;
+}
+
+CsInfo&
+CsInfo::setEnableAdmit(bool enableAdmit)
+{
+  m_wire.reset();
+  m_flags[BIT_CS_ENABLE_ADMIT] = enableAdmit;
+  return *this;
+}
+
+CsInfo&
+CsInfo::setEnableServe(bool enableServe)
+{
+  m_wire.reset();
+  m_flags[BIT_CS_ENABLE_SERVE] = enableServe;
+  return *this;
+}
+
+CsInfo&
+CsInfo::setNEntries(uint64_t nEntries)
+{
+  m_wire.reset();
+  m_nEntries = nEntries;
+  return *this;
+}
+
+CsInfo&
 CsInfo::setNHits(uint64_t nHits)
 {
   m_wire.reset();
@@ -119,17 +180,18 @@
 bool
 operator==(const CsInfo& a, const CsInfo& b)
 {
-  return a.getNHits() == b.getNHits() &&
-         a.getNMisses() == b.getNMisses();
+  return a.wireEncode() == b.wireEncode();
 }
 
 std::ostream&
-operator<<(std::ostream& os, const CsInfo& status)
+operator<<(std::ostream& os, const CsInfo& csi)
 {
   os << "CS: "
-     << status.getNHits() << (status.getNHits() == 1 ? " hit" : " hits")
-     << ", "
-     << status.getNMisses() << (status.getNMisses() == 1 ? " miss" : " misses");
+     << csi.getNEntries() << " entries, " << csi.getCapacity() << " max, "
+     << (csi.getEnableAdmit() ? "admit enabled, " : "admit disabled, ")
+     << (csi.getEnableServe() ? "serve enabled, " : "serve disabled, ")
+     << csi.getNHits() << (csi.getNHits() == 1 ? " hit, " : " hits, ")
+     << csi.getNMisses() << (csi.getNMisses() == 1 ? " miss" : " misses");
   return os;
 }
 
diff --git a/src/mgmt/nfd/cs-info.hpp b/src/mgmt/nfd/cs-info.hpp
index 0b9ad0a..cdd38a9 100644
--- a/src/mgmt/nfd/cs-info.hpp
+++ b/src/mgmt/nfd/cs-info.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).
  *
@@ -23,14 +23,16 @@
 #define NDN_MGMT_NFD_CS_INFO_HPP
 
 #include "../../encoding/block.hpp"
+#include "../../encoding/nfd-constants.hpp"
+
+#include <bitset>
 
 namespace ndn {
 namespace nfd {
 
-/**
- * \ingroup management
- * \brief represents the CS Information dataset
- * \sa https://redmine.named-data.net/projects/nfd/wiki/CsMgmt#CS-Information-Dataset
+/** \ingroup management
+ *  \brief represents the CS Information dataset
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/CsMgmt#CS-Information-Dataset
  */
 class CsInfo
 {
@@ -60,6 +62,52 @@
   void
   wireDecode(const Block& wire);
 
+  /** \brief get CS capacity (in number of packets)
+   */
+  uint64_t
+  getCapacity() const
+  {
+    return m_capacity;
+  }
+
+  CsInfo&
+  setCapacity(uint64_t capacity);
+
+  /** \brief get CS_ENABLE_ADMIT flag
+   */
+  bool
+  getEnableAdmit() const
+  {
+    return m_flags.test(BIT_CS_ENABLE_ADMIT);
+  }
+
+  CsInfo&
+  setEnableAdmit(bool enableAdmit);
+
+  /** \brief get CS_ENABLE_SERVE flag
+   */
+  bool
+  getEnableServe() const
+  {
+    return m_flags.test(BIT_CS_ENABLE_SERVE);
+  }
+
+  CsInfo&
+  setEnableServe(bool enableServe);
+
+  /** \brief get number of stored CS entries
+   */
+  uint64_t
+  getNEntries() const
+  {
+    return m_nEntries;
+  }
+
+  CsInfo&
+  setNEntries(uint64_t nEntries);
+
+  /** \brief get number of CS lookup hits since NFD starts
+   */
   uint64_t
   getNHits() const
   {
@@ -69,6 +117,8 @@
   CsInfo&
   setNHits(uint64_t nHits);
 
+  /** \brief get number of CS lookup misses since NFD starts
+   */
   uint64_t
   getNMisses() const
   {
@@ -79,6 +129,11 @@
   setNMisses(uint64_t nMisses);
 
 private:
+  using FlagsBitSet = std::bitset<2>;
+
+  uint64_t m_capacity;
+  FlagsBitSet m_flags;
+  uint64_t m_nEntries;
   uint64_t m_nHits;
   uint64_t m_nMisses;
   mutable Block m_wire;
@@ -96,7 +151,7 @@
 }
 
 std::ostream&
-operator<<(std::ostream& os, const CsInfo& status);
+operator<<(std::ostream& os, const CsInfo& csi);
 
 } // namespace nfd
 } // namespace ndn
diff --git a/tests/unit-tests/mgmt/nfd/cs-info.t.cpp b/tests/unit-tests/mgmt/nfd/cs-info.t.cpp
index 6e55b85..9e499af 100644
--- a/tests/unit-tests/mgmt/nfd/cs-info.t.cpp
+++ b/tests/unit-tests/mgmt/nfd/cs-info.t.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).
  *
@@ -36,6 +36,10 @@
 makeCsInfo()
 {
   return CsInfo()
+    .setCapacity(20177)
+    .setEnableAdmit(false)
+    .setEnableServe(true)
+    .setNEntries(5509)
     .setNHits(12951)
     .setNMisses(28179);
 }
@@ -46,7 +50,10 @@
   Block wire = csi1.wireEncode();
 
   static const uint8_t EXPECTED[] = {
-    0x80, 0x08, // CsInfo
+    0x80, 0x13, // CsInfo
+          0x83, 0x02, 0x4E, 0xD1, // Capacity
+          0x6C, 0x01, 0x02,       // Flags
+          0x87, 0x02, 0x15, 0x85, // NCsEntries
           0x81, 0x02, 0x32, 0x97, // NHits
           0x82, 0x02, 0x6E, 0x13, // NMisses
   };
@@ -66,20 +73,44 @@
   csi2 = csi1;
   BOOST_CHECK_EQUAL(csi1, csi2);
 
-  csi2.setNHits(8267);
+  csi2.setCapacity(csi2.getCapacity() + 1);
   BOOST_CHECK_NE(csi1, csi2);
+  csi2 = csi1;
+
+  csi2.setEnableAdmit(!csi2.getEnableAdmit());
+  BOOST_CHECK_NE(csi1, csi2);
+  csi2 = csi1;
+
+  csi2.setEnableServe(!csi2.getEnableServe());
+  BOOST_CHECK_NE(csi1, csi2);
+  csi2 = csi1;
+
+  csi2.setNEntries(csi2.getNEntries() + 1);
+  BOOST_CHECK_NE(csi1, csi2);
+  csi2 = csi1;
+
+  csi2.setNHits(csi2.getNHits() + 1);
+  BOOST_CHECK_NE(csi1, csi2);
+  csi2 = csi1;
+
+  csi2.setNMisses(csi2.getNMisses() + 1);
+  BOOST_CHECK_NE(csi1, csi2);
+  csi2 = csi1;
 }
 
 BOOST_AUTO_TEST_CASE(Print)
 {
   CsInfo csi;
-  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(csi), "CS: 0 hits, 0 misses");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(csi),
+    "CS: 0 entries, 0 max, admit disabled, serve disabled, 0 hits, 0 misses");
 
   csi = makeCsInfo();
-  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(csi), "CS: 12951 hits, 28179 misses");
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(csi),
+    "CS: 5509 entries, 20177 max, admit disabled, serve enabled, 12951 hits, 28179 misses");
 
-  csi.setNHits(1).setNMisses(1);
-  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(csi), "CS: 1 hit, 1 miss");
+  csi.setEnableAdmit(true).setNHits(1).setNMisses(1);
+  BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(csi),
+    "CS: 5509 entries, 20177 max, admit enabled, serve enabled, 1 hit, 1 miss");
 }
 
 BOOST_AUTO_TEST_SUITE_END() // TestCsInfo