How to create a traffic generator ?

Question: How do I create a new traffic generator ?

Answer: It is possible to instanciate Packet objects, schedule events, and call functions from any piece of code in ns-3 so, technically, there is no single answer to the question of how we can write a new traffic generator. However, the Socket API was really designed to be the single point of entry for traffic generators or traffic analysers and the Application class was designed to hold together any number of sockets.

Implementing a new traffic generator thus boils down to:

The following "random" generator generates packets separated by a random delay and with a random size.

class RandomGenerator : public Application
{
public:
  RandomGenerator ();
  void SetDelay (RandomVariable delay);
  void SetSize (RandomVariable size);
  void SetRemote (std::string socketType, 
                  Address remote);
private:
  virtual void StartApplication (void);
  virtual void StopApplication (void);
  void DoGenerate (void);

  RandomVariable m_delay;
  RandomVariable m_size;
  Ptr<Socket> m_socket;
};

The socket is created in the SetRemote method:

void 
RandomGenerator::SetRemote (std::string socketType, 
                            Address remote)
{
  TypeId tid = TypeId::LookupByName (socketType);
  m_socket = Socket::CreateSocket (GetNode (), tid);
  m_socket->Bind ();
  m_socket->ShutdownRecv ();
  m_socket->Connect (remote);
}
While the the crux of the logic is located in the DoGenerate method which is called from within StartApplication:
void
RandomGenerator::DoGenerate (void)
{
  m_next = Simulator::Schedule (Seconds (m_delay.GetValue ()), 
                &RandomGenerator::DoGenerate, this);
  Ptr<Packet> p = Create<Packet> (m_size.GetIntValue ());
  m_socket->Send (p);
}

To make that application more integrated in ns-3, it needs an associated helper class:

class RandomAppHelper
{
public:
  RandomAppHelper (std::string protocol, Address remote);
  void SetPacketSize (RandomVariable packetSize);
  void SetDelay (RandomVariable delay);
  ApplicationContainer Install (NodeContainer nodes);
private:
  std::string m_protocol;
  Address m_remote;
  RandomVariable m_packetSize;
  RandomVariable m_delay;
};

which could be trivially implemented as:

ApplicationContainer 
RandomAppHelper::Install (NodeContainer nodes)
{
  ApplicationContainer applications;
  for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
    {
      Ptr<RandomAppHelper> app = CreateObject<RandomAppHelper> ();
      app->SetSize (m_packetSize);
      app->SetDelay (m_delay);
      app->SetRemote (m_protocol, m_remote);
      (*i)->AddApplication (app);
      applications.Add (app);
    }
  return applications;
}

Despite being functional, this API is not very consistant with the style of the other helper classes, all of which allow you to control the parameters of the underlying class through attributes and not explicit setters. The following API thus replaces the pair SetPacketSize/SetDelay with a single method SetAttribute:

class RandomAppHelper
{
public:
  RandomAppHelper (std::string protocol, Address remote);
  void SetAttribute (std::string name, const AttributeValue &value);
  ApplicationContainer Install (NodeContainer c);
private:
  std::string m_protocol;
  Address m_remote;
  ObjectFactory m_factory;
};

And which can be used as follows:

RandomAppHelper app = RandomAppHelper ("ns3::TcpSocketFactory", 
                       InetSocketAddress (Ipv4Address ("192.168.1.10"), 10));
app.SetAttribute ("Delay", StringValue ("Constant:2.5"));
app.SetAttribute ("Size", StringValue ("Constant:2100"));
app.Install (nodes);

The implementation, in this case, is not necessarily longer but its simplicity hides a lot of behind-the-scenes complexity:

void 
RandomAppHelper::SetAttribute (std::string name, const AttributeValue &value)
{
  m_factory.Set (name, value);
}
ApplicationContainer 
RandomAppHelper::Install (NodeContainer nodes)
{
  ApplicationContainer applications;
  for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
    {
      Ptr<RandomAppHelper> app = m_factory.Create<RandomAppHelper> ();
      app->SetRemote (m_socketType, m_remote);
      (*i)->AddApplication (app);
      applications.Add (app);
    }
  return applications;
}

The key difference between this implementation and the previous one is that this helper does not handle explicitely the attributes delay and packet size. Instead, it stores them in an ObjectFactory object. This, of course, does not work magically, and requires extra support from the underlying RandomGenerator class. Specifically, it requires that the underlying RandomGenerator defines its attributes in its TypeId in a new public static method:

class RandomGenerator
{
public:
  static TypeId GetTypeId (void);
};

The corresponding implementation is shown below:

TypeId
RandomGenerator::GetTypeId (void)
{
  static TypeId tid = TypeId ("RandomGenerator")
    .SetParent<Application> ()
    .AddConstructor<RandomGenerator> ()
    .AddAttribute ("Delay", "The delay between two packets (s)",
           RandomVariableValue (ConstantVariable (1.0)),
           MakeRandomVariableAccessor (&RandomGenerator::m_delay),
           MakeRandomVariableChecker ())
    .AddAttribute ("PacketSize", "The size of each packet (bytes)",
           RandomVariableValue (ConstantVariable (2000)),
           MakeRandomVariableAccessor (&RandomGenerator::m_size),
           MakeRandomVariableChecker ())
    ;
  return tid;
}   

Generated on Fri Apr 9 15:00:42 2010 for NS-3 by  doxygen 1.5.8