utils: Add tracing functionality of network-layer NACKs

Change-Id: I3d16bcf29f4858049d1040a3e421e1c7151a1ea1
Refs: #3872
diff --git a/utils/tracers/ndn-l3-rate-tracer.cpp b/utils/tracers/ndn-l3-rate-tracer.cpp
index efb09b1..c217dbb 100644
--- a/utils/tracers/ndn-l3-rate-tracer.cpp
+++ b/utils/tracers/ndn-l3-rate-tracer.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2011-2015  Regents of the University of California.
+ * Copyright (c) 2011-2016  Regents of the University of California.
  *
  * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
  * contributors.
@@ -25,6 +25,7 @@
 #include "ns3/simulator.h"
 #include "ns3/log.h"
 #include "ns3/node-list.h"
+#include "ns3/ndnSIM/model/ndn-l3-protocol.hpp"
 
 #include "daemon/table/pit-entry.hpp"
 
@@ -246,8 +247,10 @@
                        + /*old value*/ (1 - alpha) * STATS(3).fieldName;                           \
                                                                                                    \
   os << time.ToDouble(Time::S) << "\t" << m_node << "\t";                                          \
-  if (stats.first != nullptr) {                                                                    \
-    os << stats.first->getId() << "\t" << stats.first->getLocalUri() << "\t";                      \
+  if (stats.first != nfd::face::INVALID_FACEID) {                                                  \
+    os << stats.first << "\t";                                                                     \
+    NS_ASSERT(m_faceInfos.find(stats.first) != m_faceInfos.end());                                 \
+    os << m_faceInfos.find(stats.first)->second << "\t";                                           \
   }                                                                                                \
   else {                                                                                           \
     os << "-1\tall\t";                                                                             \
@@ -261,7 +264,7 @@
   Time time = Simulator::Now();
 
   for (auto& stats : m_stats) {
-    if (stats.first == nullptr)
+    if (stats.first == nfd::face::INVALID_FACEID)
       continue;
 
     PRINTER("InInterests", m_inInterests);
@@ -270,6 +273,9 @@
     PRINTER("InData", m_inData);
     PRINTER("OutData", m_outData);
 
+    PRINTER("InNacks", m_inNack);
+    PRINTER("OutNacks", m_outNack);
+
     PRINTER("InSatisfiedInterests", m_satisfiedInterests);
     PRINTER("InTimedOutInterests", m_timedOutInterests);
 
@@ -278,7 +284,7 @@
   }
 
   {
-    auto i = m_stats.find(nullptr);
+    auto i = m_stats.find(nfd::face::INVALID_FACEID);
     if (i != m_stats.end()) {
       auto& stats = *i;
       PRINTER("SatisfiedInterests", m_satisfiedInterests);
@@ -290,9 +296,10 @@
 void
 L3RateTracer::OutInterests(const Interest& interest, const Face& face)
 {
-  std::get<0>(m_stats[face.shared_from_this()]).m_outInterests++;
+  AddInfo(face);
+  std::get<0>(m_stats[face.getId()]).m_outInterests++;
   if (interest.hasWire()) {
-    std::get<1>(m_stats[face.shared_from_this()]).m_outInterests +=
+    std::get<1>(m_stats[face.getId()]).m_outInterests +=
       interest.wireEncode().size();
   }
 }
@@ -300,9 +307,10 @@
 void
 L3RateTracer::InInterests(const Interest& interest, const Face& face)
 {
-  std::get<0>(m_stats[face.shared_from_this()]).m_inInterests++;
+  AddInfo(face);
+  std::get<0>(m_stats[face.getId()]).m_inInterests++;
   if (interest.hasWire()) {
-    std::get<1>(m_stats[face.shared_from_this()]).m_inInterests +=
+    std::get<1>(m_stats[face.getId()]).m_inInterests +=
       interest.wireEncode().size();
   }
 }
@@ -310,9 +318,10 @@
 void
 L3RateTracer::OutData(const Data& data, const Face& face)
 {
-  std::get<0>(m_stats[face.shared_from_this()]).m_outData++;
+  AddInfo(face);
+  std::get<0>(m_stats[face.getId()]).m_outData++;
   if (data.hasWire()) {
-    std::get<1>(m_stats[face.shared_from_this()]).m_outData +=
+    std::get<1>(m_stats[face.getId()]).m_outData +=
       data.wireEncode().size();
   }
 }
@@ -320,40 +329,75 @@
 void
 L3RateTracer::InData(const Data& data, const Face& face)
 {
-  std::get<0>(m_stats[face.shared_from_this()]).m_inData++;
+  AddInfo(face);
+  std::get<0>(m_stats[face.getId()]).m_inData++;
   if (data.hasWire()) {
-    std::get<1>(m_stats[face.shared_from_this()]).m_inData +=
+    std::get<1>(m_stats[face.getId()]).m_inData +=
       data.wireEncode().size();
   }
 }
 
 void
+L3RateTracer::OutNack(const lp::Nack& nack, const Face& face)
+{
+  AddInfo(face);
+  std::get<0>(m_stats[face.getId()]).m_outNack++;
+  if (nack.getInterest().hasWire()) {
+    std::get<1>(m_stats[face.getId()]).m_outNack +=
+      nack.getInterest().wireEncode().size();
+  }
+}
+
+void
+L3RateTracer::InNack(const lp::Nack& nack, const Face& face)
+{
+  AddInfo(face);
+  std::get<0>(m_stats[face.getId()]).m_inNack++;
+  if (nack.getInterest().hasWire()) {
+    std::get<1>(m_stats[face.getId()]).m_inNack +=
+      nack.getInterest().wireEncode().size();
+  }
+}
+
+void
 L3RateTracer::SatisfiedInterests(const nfd::pit::Entry& entry, const Face&, const Data&)
 {
-  std::get<0>(m_stats[nullptr]).m_satisfiedInterests++;
+  std::get<0>(m_stats[nfd::face::INVALID_FACEID]).m_satisfiedInterests++;
   // no "size" stats
 
   for (const auto& in : entry.getInRecords()) {
-    std::get<0>(m_stats[(in.getFace()).shared_from_this()]).m_satisfiedInterests ++;
+    AddInfo(in.getFace());
+    std::get<0>(m_stats[(in.getFace()).getId()]).m_satisfiedInterests ++;
   }
 
   for (const auto& out : entry.getOutRecords()) {
-    std::get<0>(m_stats[(out.getFace()).shared_from_this()]).m_outSatisfiedInterests ++;
+    AddInfo(out.getFace());
+    std::get<0>(m_stats[(out.getFace()).getId()]).m_outSatisfiedInterests ++;
   }
 }
 
 void
 L3RateTracer::TimedOutInterests(const nfd::pit::Entry& entry)
 {
-  std::get<0>(m_stats[nullptr]).m_timedOutInterests++;
+  std::get<0>(m_stats[nfd::face::INVALID_FACEID]).m_timedOutInterests++;
   // no "size" stats
 
   for (const auto& in : entry.getInRecords()) {
-    std::get<0>(m_stats[(in.getFace()).shared_from_this()]).m_timedOutInterests++;
+    AddInfo(in.getFace());
+    std::get<0>(m_stats[(in.getFace()).getId()]).m_timedOutInterests++;
   }
 
   for (const auto& out : entry.getOutRecords()) {
-    std::get<0>(m_stats[(out.getFace()).shared_from_this()]).m_outTimedOutInterests++;
+    AddInfo(out.getFace());
+    std::get<0>(m_stats[(out.getFace()).getId()]).m_outTimedOutInterests++;
+  }
+}
+
+void
+L3RateTracer::AddInfo(const Face& face)
+{
+  if (m_faceInfos.find(face.getId()) == m_faceInfos.end()) {
+    m_faceInfos.insert(make_pair(face.getId(), boost::lexical_cast<std::string>(face.getLocalUri())));
   }
 }
 
diff --git a/utils/tracers/ndn-l3-rate-tracer.hpp b/utils/tracers/ndn-l3-rate-tracer.hpp
index 6370c26..0615aed 100644
--- a/utils/tracers/ndn-l3-rate-tracer.hpp
+++ b/utils/tracers/ndn-l3-rate-tracer.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2011-2015  Regents of the University of California.
+ * Copyright (c) 2011-2016  Regents of the University of California.
  *
  * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
  * contributors.
@@ -140,6 +140,12 @@
   InData(const Data& data, const Face& face);
 
   virtual void
+  OutNack(const lp::Nack& nack, const Face& face);
+
+  virtual void
+  InNack(const lp::Nack& nack, const Face& face);
+
+  virtual void
   SatisfiedInterests(const nfd::pit::Entry&, const Face&, const Data&);
 
   virtual void
@@ -155,12 +161,16 @@
   void
   Reset();
 
+  void
+  AddInfo(const Face& face);
+
 private:
   shared_ptr<std::ostream> m_os;
   Time m_period;
   EventId m_printEvent;
 
-  mutable std::map<shared_ptr<const Face>, std::tuple<Stats, Stats, Stats, Stats>> m_stats;
+  mutable std::map<nfd::FaceId, std::tuple<Stats, Stats, Stats, Stats>> m_stats;
+  std::map<nfd::FaceId, std::string> m_faceInfos; // needed, because face may no longer exists at the time of stat printing
 };
 
 } // namespace ndn
diff --git a/utils/tracers/ndn-l3-tracer.cpp b/utils/tracers/ndn-l3-tracer.cpp
index e19439b..64c93ce 100644
--- a/utils/tracers/ndn-l3-tracer.cpp
+++ b/utils/tracers/ndn-l3-tracer.cpp
@@ -61,6 +61,8 @@
   l3->TraceConnectWithoutContext("InInterests", MakeCallback(&L3Tracer::InInterests, this));
   l3->TraceConnectWithoutContext("OutData", MakeCallback(&L3Tracer::OutData, this));
   l3->TraceConnectWithoutContext("InData", MakeCallback(&L3Tracer::InData, this));
+  l3->TraceConnectWithoutContext("OutNack", MakeCallback(&L3Tracer::OutNack, this));
+  l3->TraceConnectWithoutContext("InNack", MakeCallback(&L3Tracer::InNack, this));
 
   // satisfied/timed out PIs
   l3->TraceConnectWithoutContext("SatisfiedInterests",
diff --git a/utils/tracers/ndn-l3-tracer.hpp b/utils/tracers/ndn-l3-tracer.hpp
index ed8e35b..15dd41f 100644
--- a/utils/tracers/ndn-l3-tracer.hpp
+++ b/utils/tracers/ndn-l3-tracer.hpp
@@ -94,6 +94,12 @@
   InData(const Data&, const Face&) = 0;
 
   virtual void
+  OutNack(const lp::Nack& nack, const Face&) = 0;
+
+  virtual void
+  InNack(const lp::Nack&, const Face&) = 0;
+
+  virtual void
   SatisfiedInterests(const nfd::pit::Entry&, const Face&, const Data&) = 0;
 
   virtual void
@@ -111,6 +117,8 @@
       m_outInterests = 0;
       m_inData = 0;
       m_outData = 0;
+      m_inNack = 0;
+      m_outNack = 0;
       m_satisfiedInterests = 0;
       m_timedOutInterests = 0;
 
@@ -122,6 +130,8 @@
     double m_outInterests;
     double m_inData;
     double m_outData;
+    double m_inNack;
+    double m_outNack;
     double m_satisfiedInterests;
     double m_timedOutInterests;
     double m_outSatisfiedInterests;