[Bug 414] No error model for SimpleNetDevice
authorTom Henderson <tomh@tomh.org>
Fri, 05 Mar 2010 11:56:10 -0800
changeset 6109 c204cb0f18d8
parent 6108 78c99e72daae
child 6110 597c0b4c2f05
[Bug 414] No error model for SimpleNetDevice
src/node/simple-channel.cc
src/node/simple-net-device.cc
src/node/simple-net-device.h
src/test/error-model-test-suite.cc
src/test/wscript
--- a/src/node/simple-channel.cc	Wed Mar 03 05:56:47 2010 -0800
+++ b/src/node/simple-channel.cc	Fri Mar 05 11:56:10 2010 -0800
@@ -22,6 +22,9 @@
 #include "ns3/simulator.h"
 #include "ns3/packet.h"
 #include "ns3/node.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("SimpleChannel");
 
 namespace ns3 {
 
@@ -43,6 +46,7 @@
 		     Mac48Address to, Mac48Address from,
 		     Ptr<SimpleNetDevice> sender)
 {
+  NS_LOG_FUNCTION (p << protocol << to << from << sender);
   for (std::vector<Ptr<SimpleNetDevice> >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i)
     {
       Ptr<SimpleNetDevice> tmp = *i;
--- a/src/node/simple-net-device.cc	Wed Mar 03 05:56:47 2010 -0800
+++ b/src/node/simple-net-device.cc	Fri Mar 05 11:56:10 2010 -0800
@@ -21,6 +21,12 @@
 #include "simple-channel.h"
 #include "node.h"
 #include "ns3/packet.h"
+#include "ns3/log.h"
+#include "ns3/pointer.h"
+#include "ns3/error-model.h"
+#include "ns3/trace-source-accessor.h"
+
+NS_LOG_COMPONENT_DEFINE ("SimpleNetDevice");
 
 namespace ns3 {
 
@@ -30,6 +36,14 @@
   static TypeId tid = TypeId ("ns3::SimpleNetDevice")
     .SetParent<NetDevice> ()
     .AddConstructor<SimpleNetDevice> ()
+    .AddAttribute ("ReceiveErrorModel",
+                   "The receiver error model used to simulate packet loss",
+                   PointerValue (),
+                   MakePointerAccessor (&SimpleNetDevice::m_receiveErrorModel),
+                   MakePointerChecker<ErrorModel> ())
+    .AddTraceSource ("PhyRxDrop",
+                     "Trace source indicating a packet has been dropped by the device during reception",
+                     MakeTraceSourceAccessor (&SimpleNetDevice::m_phyRxDropTrace))
     ;
   return tid;
 }
@@ -45,7 +59,15 @@
 SimpleNetDevice::Receive (Ptr<Packet> packet, uint16_t protocol, 
 			  Mac48Address to, Mac48Address from)
 {
+  NS_LOG_FUNCTION (packet << protocol << to << from);
   NetDevice::PacketType packetType;
+
+  if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) )
+    {
+      m_phyRxDropTrace (packet);
+      return;
+    }
+
   if (to == m_address)
     {
       packetType = NetDevice::PACKET_HOST;
@@ -76,6 +98,12 @@
   m_channel->Add (this);
 }
 
+void
+SimpleNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
+{
+  m_receiveErrorModel = em;
+}
+
 void 
 SimpleNetDevice::SetIfIndex(const uint32_t index)
 {
@@ -164,6 +192,7 @@
 bool 
 SimpleNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
 {
+  NS_LOG_FUNCTION (packet << dest << protocolNumber);
   Mac48Address to = Mac48Address::ConvertFrom (dest);
   m_channel->Send (packet, protocolNumber, to, m_address, this);
   return true;
@@ -203,6 +232,7 @@
 {
   m_channel = 0;
   m_node = 0;
+  m_receiveErrorModel = 0;
   NetDevice::DoDispose ();
 }
 
--- a/src/node/simple-net-device.h	Wed Mar 03 05:56:47 2010 -0800
+++ b/src/node/simple-net-device.h	Fri Mar 05 11:56:10 2010 -0800
@@ -24,14 +24,21 @@
 #include "mac48-address.h"
 #include <stdint.h>
 #include <string>
+#include "ns3/traced-callback.h"
 
 namespace ns3 {
 
 class SimpleChannel;
 class Node;
+class ErrorModel;
 
 /**
  * \ingroup netdevice
+ *
+ * This device does not have a helper and assumes 48-bit mac addressing;
+ * the default address assigned to each device is zero, so you must 
+ * assign a real address to use it.  There is also the possibility to
+ * add an ErrorModel if you want to force losses on the device.
  * 
  * \brief simple net device for simple things and testing
  */
@@ -44,6 +51,17 @@
   void Receive (Ptr<Packet> packet, uint16_t protocol, Mac48Address to, Mac48Address from);
   void SetChannel (Ptr<SimpleChannel> channel);
 
+  /**
+   * Attach a receive ErrorModel to the SimpleNetDevice.
+   *
+   * The SimpleNetDevice may optionally include an ErrorModel in
+   * the packet receive chain.
+   *
+   * \see ErrorModel
+   * \param em Ptr to the ErrorModel.
+   */
+  void SetReceiveErrorModel(Ptr<ErrorModel> em);
+
   // inherited from NetDevice base class.
   virtual void SetIfIndex(const uint32_t index);
   virtual uint32_t GetIfIndex(void) const;
@@ -82,6 +100,16 @@
   uint16_t m_mtu;
   uint32_t m_ifIndex;
   Mac48Address m_address;
+  Ptr<ErrorModel> m_receiveErrorModel;
+  /**
+   * The trace source fired when the phy layer drops a packet it has received
+   * due to the error model being active.  Although SimpleNetDevice doesn't 
+   * really have a Phy model, we choose this trace source name for alignment
+   * with other trace sources.
+   *
+   * \see class CallBackTraceSource
+   */
+  TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
 };
 
 } // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/error-model-test-suite.cc	Fri Mar 05 11:56:10 2010 -0800
@@ -0,0 +1,135 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include "ns3/test.h"
+#include "ns3/simple-net-device.h"
+#include "ns3/simple-channel.h"
+#include "ns3/address.h"
+#include "ns3/mac48-address.h"
+#include "ns3/packet.h"
+#include "ns3/callback.h"
+#include "ns3/node.h"
+#include "ns3/simulator.h"
+#include "ns3/error-model.h"
+#include "ns3/pointer.h"
+#include "ns3/double.h"
+#include "ns3/string.h"
+
+using namespace ns3;
+
+static void SendPacket (int num, Ptr<NetDevice> device, Address& addr)
+{
+  for (int i = 0; i < num; i++)
+    {
+      Ptr<Packet> pkt = Create<Packet> (1000);  // 1000 dummy bytes of data
+      device->Send (pkt, addr, 0);
+    }
+}
+
+// Two nodes, two devices, one channel
+static void BuildSimpleTopology (Ptr<Node> a, Ptr<Node> b, Ptr<SimpleNetDevice> input, Ptr<SimpleNetDevice> output, Ptr<SimpleChannel> channel)
+{
+  a->AddDevice (input);
+  b->AddDevice (output);
+  input->SetAddress (Mac48Address::Allocate ());
+  input->SetChannel (channel);
+  input->SetNode (a);
+  output->SetChannel (channel);
+  output->SetNode (b);
+  output->SetAddress (Mac48Address::Allocate ());
+}
+
+class ErrorModelSimple : public TestCase
+{
+public:
+  ErrorModelSimple ();
+  virtual ~ErrorModelSimple ();
+
+private:
+  virtual bool DoRun (void);
+  bool Receive (Ptr<NetDevice> nd, Ptr<const Packet> p, uint16_t protocol, const Address& addr);
+  void DropEvent (Ptr<const Packet> p);
+  uint32_t m_count;
+  uint32_t m_drops;
+};
+
+// Add some help text to this case to describe what it is intended to test
+ErrorModelSimple::ErrorModelSimple ()
+  : TestCase ("ErrorModel and PhyRxDrop trace for SimpleNetDevice"), m_count (0), m_drops (0)
+{
+}
+
+ErrorModelSimple::~ErrorModelSimple ()
+{
+}
+
+bool 
+ErrorModelSimple::Receive (Ptr<NetDevice> nd, Ptr<const Packet> p, uint16_t protocol, const Address& addr)
+{
+  m_count++;
+  return true;
+}
+
+void 
+ErrorModelSimple::DropEvent (Ptr<const Packet> p)
+{
+  m_drops++;
+}
+
+bool
+ErrorModelSimple::DoRun (void)
+{
+  bool retval = false;
+  // Set some arbitrary deterministic values
+  SeedManager::SetSeed (7);
+  SeedManager::SetRun (5);
+
+  Ptr<Node> a = CreateObject<Node> ();
+  Ptr<Node> b = CreateObject<Node> ();
+
+  Ptr<SimpleNetDevice> input = CreateObject<SimpleNetDevice> ();
+  Ptr<SimpleNetDevice> output = CreateObject<SimpleNetDevice> ();
+  Ptr<SimpleChannel> channel = CreateObject<SimpleChannel> ();
+  BuildSimpleTopology (a, b, input, output, channel);
+
+  output->SetReceiveCallback (MakeCallback (&ErrorModelSimple::Receive, this));
+
+  Ptr<RateErrorModel> em = CreateObjectWithAttributes<RateErrorModel> ("RanVar", RandomVariableValue (UniformVariable (0.0, 1.0)));
+  em->SetAttribute ("ErrorRate", DoubleValue (0.001));
+  em->SetAttribute ("ErrorUnit", StringValue ("EU_PKT"));
+
+  // The below hooks will cause drops and receptions to be counted
+  output->SetAttribute ("ReceiveErrorModel", PointerValue (em));
+  output->TraceConnectWithoutContext ("PhyRxDrop", MakeCallback (&ErrorModelSimple::DropEvent, this));
+
+  // Send 10000 packets
+  Simulator::Schedule (Seconds (0), &SendPacket, 10000, input, output->GetAddress());
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  // For this combination of values, we expect about 1 packet in 1000 to be
+  // dropped.  For this specific RNG stream, we see 9992 receptions and 8 drops
+  if (m_count != 9992 || m_drops != 8)
+    {
+      retval = true;
+    }
+  return retval;
+}
+
+// This is the start of an error model test suite.  For starters, this is
+// just testing that the SimpleNetDevice is working but this can be
+// extended to many more test cases in the future
+class ErrorModelTestSuite : public TestSuite
+{
+public:
+  ErrorModelTestSuite ();
+};
+
+ErrorModelTestSuite::ErrorModelTestSuite ()
+  : TestSuite ("error-model", BVT)
+{
+  AddTestCase (new ErrorModelSimple);
+}
+
+// Do not forget to allocate an instance of this TestSuite
+ErrorModelTestSuite errorModelTestSuite;
--- a/src/test/wscript	Wed Mar 03 05:56:47 2010 -0800
+++ b/src/test/wscript	Fri Mar 05 11:56:10 2010 -0800
@@ -7,6 +7,7 @@
     test = bld.create_ns3_module('test', ['core'])
     test.source = [
         'sample-test-suite.cc',
+        'error-model-test-suite.cc',
         ]
 
     headers = bld.new_task_gen('ns3header')