Building a compehensible traffic generator with Libtins

As with many things I try to post here, this is something I was very enthusiastic to do.

Many times I found myself doing experiments and deriving performance metrics with generic traffic generators, like iPerf. Just to end up with a rejected paper arguing “unrealistic” or “simplistic” traffic models.

The reviewers are right (as shown in my CSMA/ECA QoS paper), precise traffic models are needed in order to gather accurate metrics that may reveal the real performance of our system. That why I needed to build my own :).

Libtins

I won’t go into much detail here, but basically, libtins is a set of C++ libraries that allows you to build fast sniffers and traffic generators (got speed problems with Scapy, another tool that you should definitely take a look at).

In order to test my generator, you must have libtins installed and C++11 support enabled (see installation instructions on their own website).

As with many opensource projects, libtins counts with a very complete API reference that will get you through most of C++ caveats. Further, tutorials and examples will help you build whatever it is you want.

Now, let’s overview my generator.

My generator with libtins

The master branch of the generator contains all the files you need. It is composed of:

  • generator objects and helpers.
  • sniffer objects and helpers.

I call <objects>.cpp the files the experimenter will use as templates for his/her own experiments. <helpers>.h contain all classes definitions and implementations (I know, I know is a mess, but while developing I find this distribution of files more useful than the traditional separation between implementation and header files for classes).

As this is an on-progress development effort, with no alternate goal other than to help me, you will surely find sketchy workarounds and other not-so-smart magic. But bear with me, libtins is cool.

A simple generator: myGeneratorObject.cpp

In order to create a generator, you will build a script pretty much like the following:


#include <tins/tins.h>
#include <sys/time.h>
#include <vector>
#include <unistd.h>
#include "generator_helpers.h"

using namespace Tins;
using namespace std;

#define MAX_FLOWS 1000
int main() {
    //Initialization
     MultipleCBRHelper exp;
     int num_flows = 5;

     //global parameters for this experiment
     struct global_settings settings;
     settings.eth.dst_addr("00:00:00:00:00:01"); //destination MAC
     settings.i_o = "eth0"; //output iface
     settings.dst_ip = "193.168.168.1";
     settings.src_ip = "193.168.168.2";
     settings.rate = 10e6; //Mbps
     settings.dst_udp = 9000;
     settings.src_udp = settings.dst_udp;

     if (num_flows < MAX_FLOWS)
     {
         for (int f = 0; f < num_flows; f++)
         {
             exp.addFlow(settings);
             settings.src_udp++;
             settings.dst_udp++;
         }
     }
 
    //Generating the sender and firing through the interface
    double duration = 5.0; //seconds
    exp.multiple_fire_for_duration(duration);

    return 0;
}

And that’s all. My Generator will create as many threads as num_flows and join them to the main thread when the experiment duration is reached.

Notice that at the time of writing only Constant Bit-Rate (CBR) generators are built. Nevertheless, if you take a look at generator_helpers.h you will figure out how to build on/off sources, or Variable Bit-Rate (VBR) generators (I will post about this later).

A simple sniffer: mySnifferObject.cpp

What’s the point of creating a generator without something on the other end of the link telling you how may packets were received? Or maybe the delay between packets? Well, that’s what I call a simple sniffer.

Again, in sniffer_helpers.h you will find a helper and at least two Processor classes, one for a single flow, and the other one that manages multiple generators. The Processor catches the packets libtins‘s Sniffer class passes, so you simply write code in Processor to do what you want with arriving packets (declaring operator() for the Processor class).

A simple sniffer for multiple generators can be build as simply as:

#include <tins/tins.h>
#include <sys/time.h>
#include <vector>
#include <tins/tcp_ip/stream_follower.h>
#include "sniffer_helpers.h"

using namespace Tins;
using namespace std;

int main() 
{
    //Initialization
    BasicHelper exp;

    //pcap filter
    const string filter = "udp dst portrange 9000-9999";
    exp.set_filter(filter);

    const string iface = "eth1";
    Sniffer sniffer(iface, exp.get_sniffer_conf());
    
    cout << "Ready to sniff: "<< iface << endl;

    MultiFlowProcessor processor;
    sniffer.sniff_loop(processor);

    return 0;
}

Compilation and what you should see

I have not implemented command-line tools (yet), so in order to setup your experiment you need to create scripts like the ones shown above.

In order to help you compile them, I have included a compile executable file in the repository. It takes only one *.cpp file as argument and returns the executable file with the same name but without the extension. That is:

# compiling a generator script
:~$ ./compile myGeneratorObject.cpp
# returns myGeneratorObject executable

Execution is as simple as:

# root priviledges required
:~$ sudo myGeneratorObject

Screenshots

Generator

Example of the output from a simple generator. Firing 5 flows with different UDP ports

Example of the output from a simple generator. Firing 5 flows with different UDP ports

Sniffer

As flows are created by the Generator, Sniffer registers them and shows its characteristics. The sniffer dies when it receives a all termination signals from the Generator.

As flows are created by the Generator, Sniffer registers them and shows its characteristics. The sniffer dies when it receives a all termination signals from the Generator.

Hopefully you’ll find this information useful. Keep pushing.

L.

Posted under: Experimental

Tagged as: , , ,

One comment

Leave a Reply