Quick Start Tutorial

In this tutorial, we present how to integrate OML inside the well known traffic generator Iperf.

Iperf

Iperf is a traffic generator developed originally by the NLANR/DAST. This tool allows users to get metrics about the network such as:
  • available bandwidth
  • jitter
  • packet loss rate
    With ping this tool provides a complete set of measurement for TCP/IP networks.

On a practical point of view, a user can start this application by starting a measurement server and client. Then, both sides will display network information every "interval" second(s). The aim of this tutorial is too catch these measurements and send them to the OML server instead of the standard out.

Definition of Iperf's Measurement Points

Iperf provides two sets of measurement to the user, TCP measurements and UDP measurement. These two sets mainly differ by the addition of more information in the UDP measurements. Indeed, since UDP traffic is constant and set by the user, the server can compute the jitter of the connection and the packet loss rate.

In order to store this information in the OML server, we defined the following Measurement Points: tcp_measure, udp_measure, peer_information. The latest MP is defined to match connection ID and real address of client(s) and server.

These measurement points are declared in the file main.cpp as follows:

1 OmlMP* tcp_measure;
2 OmlMP* udp_measure;
3 OmlMP* peer_information;

These MP need to be associated with a definition a 2-uples. In Iperf, two kinds of network measurements are available in addition of the peers information. These three sets of information are translated using OML as follows:

 1 static OmlMPDef tcp_receiverport[] = {
 2   {"ID", OML_LONG_VALUE},
 3   {"Begin_interval", OML_DOUBLE_VALUE},
 4   {"End_interval", OML_DOUBLE_VALUE},
 5   {"Transfer", OML_DOUBLE_VALUE},
 6   {"Bandwidth", OML_DOUBLE_VALUE},
 7   {NULL, (OmlValueT)0}
 8 };
 9 
10 static OmlMPDef udp_receiverport[] = {
11   {"ID", OML_LONG_VALUE},
12   {"Begin_interval", OML_DOUBLE_VALUE},
13   {"End_interval", OML_DOUBLE_VALUE},
14   {"Transfer", OML_DOUBLE_VALUE},
15   {"Bandwidth", OML_DOUBLE_VALUE},
16   {"Jitter", OML_DOUBLE_VALUE},
17   {"Packet_Lost", OML_LONG_VALUE},
18   {"Total_Packet", OML_LONG_VALUE},
19   {"PLR", OML_DOUBLE_VALUE},
20   {NULL, (OmlValueT)0}
21 };
22 
23 static OmlMPDef peer_info[] = {
24   {"ID", OML_LONG_VALUE},
25   {"local_address", OML_STRING_VALUE},
26   {"local_port", OML_LONG_VALUE},
27   {"foreign_address", OML_STRING_VALUE},
28   {"foreign_port", OML_LONG_VALUE},
29   {NULL, (OmlValueT)0}
30 };

Starting OML

Once the definition of the MPs finished, we need now to start OML collection thread inside the Iperf. This has been done inside the main.cpp file as follows:

1 omlc_init("iperf", &argc,  (const char**) argv, NULL);

In this code, the function omlc init(...) initialises a internal structure called OMLCinstance that will store the different definition of the Measurement point. This function analyses the command line of the user application and extracts information according to the following options:

  • –oml-file file, in order to writes measurements to ‘file’;
  • –oml-id id, Name to identify this app instance;
  • –oml-exp-id expId, Name to experiment DB;
  • –oml-server uri, uri to send measurements, with a correct URI with a form such as tcp—udp:host:port:[bindAddr] or file:localPath;
  • –oml-config file, Reads configuration from ‘file’;
  • –oml-samples count, Default number of samples to collect;
  • –oml-interval seconds, Default interval between measurements;
  • –oml-log-file file, Writes log messages to ’file’;
  • –oml-log-level level, Log level used (error: 1 .. debug:4);
  • –oml-noop, Do not collect measurements;
  • –oml-help, print the usage message.

Associating MP definitions and MPs

Once OML is initialised, we now need to create the different Measurement Points based on MP definitions. In the case of Iperf four configurations are possible: client or server, TCP or UDP. Furthermore, in all these configurations we need the information about the connection available through the "peer_info" MP definitions.

The other Measurement Points used in Iperf can be summarised as follows:

Client Server
TCP tcp_measure using tcp_receiverport called TCP_Info tcp_measure using tcp_receiverport called TCP_Info
UDP tcp_measure using tcp_receiverport called UDP_Periodic_Info udp_measure using udp_receiverport called UDP_Rich_Info
&
udp_measure using udp_receiverport called UDP_Rich_Info

These MP creations are translated inside Iperf code as follows:

 1 peer_information = omlc_add_mp("Peer_Info", peer_info);
 2 ...
 3 if ( gSettings->GetServerMode() == kMode_Server ) {
 4   // start up a listener
 5   theListener = new Listener( ext_gSettings );
 6   theListener->DeleteSelfAfterRun();
 7   if ( gSettings->GetProtocolMode() == false){//UDP
 8     udp_measure = omlc_add_mp("UDP_Rich_Info", udp_receiverport);
 9   }
10   else{
11     tcp_measure = omlc_add_mp("TCP_Info", tcp_receiverport);
12   }
13 ....
14 } else if ( gSettings->GetServerMode() == kMode_Client ) {
15 
16   theSpeaker = new Speaker(ext_gSettings);
17   theSpeaker->OwnSettings();
18   theSpeaker->DeleteSelfAfterRun();
19   if ( gSettings->GetProtocolMode() == false){//UDP
20     tcp_measure = omlc_add_mp("UDP_Periodic_Info", tcp_receiverport);
21     udp_measure = omlc_add_mp("UDP_Rich_Info", udp_receiverport);
22   }
23   else{//TCP
24     tcp_measure = omlc_add_mp("TCP_Info", tcp_receiverport);
25   }
26 ...
27 }
28 omlc_start();

Measurements Injection

Everything is now ready for the measurements. They are in Iperf displayed by the PerfSocket object defined in PerfSocket.cpp. In addition to the display on the standard out, we inject iperf metrics using the "omlc_inject" function from the liboml.

Peer Information Injection

 1 void PerfSocket::ReportPeer( int inSock ) {
 2 ...
 3   OmlValueU v[5];
 4   omlc_set_long(v[0], (long)inSock);
 5   omlc_set_const_string(v[1], local_addr);
 6   omlc_set_long(v[2], (long)local.getPort());
 7   omlc_set_const_string(v[3], remote_addr);
 8   omlc_set_long(v[4], (long)remote.getPort());
 9 
10   omlc_inject(peer_information, v);

TCP connection measurements

 1 void PerfSocket::ReportBW( max_size_t inBytes,
 2     double inStart,
 3     double inStop ) {
 4 ...
 5   OmlValueU v[5];
 6   omlc_set_long  (v[0], (long) mSock);
 7   omlc_set_double(v[1], (double) inStart);
 8   omlc_set_double(v[2], (double) inStop);
 9   omlc_set_double(v[3], (double) inBytes);
10   omlc_set_double(v[4], (double) inBytes / (inStop - inStart));
11 
12   omlc_inject(tcp_measure, v); 

UDP connection measurements

On the server side:

 1 void PerfSocket::ReportBW_Jitter_Loss( max_size_t inBytes,
 2     double inStart,
 3     double inStop,
 4     int32_t inErrorcnt,
 5     int32_t inOutofOrder,
 6     int32_t inDatagrams ){
 7 ...
 8   OmlValueU v[9];
 9 
10   omlc_set_long  (v[0], (long) mSock);
11   omlc_set_double(v[1], (double) inStart);
12   omlc_set_double(v[2], (double) inStop);
13   omlc_set_double(v[3], (double) inBytes);
14   omlc_set_double(v[4], (double) inBytes / (inStop - inStart));
15   omlc_set_double(v[5], (double) (mJitter*1000.0));
16   omlc_set_long  (v[6], (long) inErrorcnt);
17   omlc_set_long  (v[7], (long) inDatagrams);
18   omlc_set_double(v[8], (double) ((100.0 * inErrorcnt) / inDatagrams));
19 
20   omlc_inject(udp_measure, v);

On the client side

 1 void PerfSocket::ReportBW( max_size_t inBytes,
 2     double inStart,
 3     double inStop ) {
 4 ...
 5   OmlValueU v[5];
 6 
 7   omlc_set_long  (v[0], (long) mSock);
 8   omlc_set_double(v[1], (double) inStart);
 9   omlc_set_double(v[2], (double) inStop);
10   omlc_set_double(v[3], (double) inBytes);
11   omlc_set_double(v[4], (double) inBytes / (inStop - inStart));
12 
13   omlc_inject(tcp_measure, v);