model+helper+tests: Create an ndnSIM-specific transport for the NFD face system

This commit replaces the previous hack of implementing NS-3's inter-node
communication using the LinkService abstraction of the NFD face system.
The new implementation has higher memory overhead, but allows simulation
of any LinkService versions, including GenericLinkService that
implements NDNLPv2 protocol (i.e., fragmentation, network NACKs, etc.).

Change-Id: I3d16bcf29f4858049d1040a3e421e1c7151b3ba2
Refs: #3871, #3873
diff --git a/model/ndn-l3-protocol.cpp b/model/ndn-l3-protocol.cpp
index b6fa69c..74f18ca 100644
--- a/model/ndn-l3-protocol.cpp
+++ b/model/ndn-l3-protocol.cpp
@@ -29,7 +29,7 @@
 #include "ns3/pointer.h"
 #include "ns3/simulator.h"
 
-#include "ndn-net-device-link-service.hpp"
+#include "ndn-net-device-transport.hpp"
 
 #include "../helper/ndn-stack-helper.hpp"
 #include "cs/ndn-content-store.hpp"
@@ -91,6 +91,13 @@
 
       ////////////////////////////////////////////////////////////////////
 
+      .AddTraceSource("OutNack", "OutNack", MakeTraceSourceAccessor(&L3Protocol::m_outNack),
+                      "ns3::ndn::L3Protocol::NackTraceCallback")
+      .AddTraceSource("InNack", "InNack", MakeTraceSourceAccessor(&L3Protocol::m_inNack),
+                      "ns3::ndn::L3Protocol::NackTraceCallback")
+
+      ////////////////////////////////////////////////////////////////////
+
       .AddTraceSource("SatisfiedInterests", "SatisfiedInterests",
                       MakeTraceSourceAccessor(&L3Protocol::m_satisfiedInterests),
                       "ns3::ndn::L3Protocol::SatisfiedInterestsCallback")
@@ -434,7 +441,13 @@
         this->m_inData(data, *face);
       }
     });
-  // TODO Add nack signals
+
+  face->afterReceiveNack.connect([this, weakFace](const lp::Nack& nack) {
+      shared_ptr<Face> face = weakFace.lock();
+      if (face != nullptr) {
+        this->m_inNack(nack, *face);
+      }
+    });
 
   auto tracingLink = face->getLinkService();
   NS_LOG_LOGIC("Adding trace sources for afterSendInterest and afterSendData");
@@ -452,7 +465,12 @@
       }
     });
 
-  // TODO Add nack signals
+  tracingLink->afterSendNack.connect([this, weakFace](const lp::Nack& nack) {
+      shared_ptr<Face> face = weakFace.lock();
+      if (face != nullptr) {
+        this->m_outNack(nack, *face);
+      }
+    });
 
   return face->getId();
 }
@@ -467,11 +485,11 @@
 L3Protocol::getFaceByNetDevice(Ptr<NetDevice> netDevice) const
 {
   for (auto& i : m_impl->m_forwarder->getFaceTable()) {
-    auto linkService = dynamic_cast<NetDeviceLinkService*>(i.getLinkService());
-    if (linkService == nullptr)
+    auto transport = dynamic_cast<NetDeviceTransport*>(i.getTransport());
+    if (transport == nullptr)
       continue;
 
-    if (linkService->GetNetDevice() == netDevice)
+    if (transport->GetNetDevice() == netDevice)
       return i.shared_from_this();
   }
   return nullptr;