Flowgen is a tool for generating network traffic based on a given traffic model. The sender side of flowgen takes input from a config file (packet sizes, burst sizes, burst intervals) and generates appropriate levels of traffic. The receiver side of flowgen receives traffic from several sources, computes loss (for UDP flows) and throughput statistics, and saves the application-level header to a file. Flowgen uses the GNU Scientific Library to allow users to generate traffic flows that have characteristics based on random distributions. A companion tool, flowparse, parses flowgen output files.
Implementation | Usage | Configuration Files | Output | Processing Output | Performance Issues |
Flowgen and flowparse are both implemented in C/C++ on FreeBSD-2.2.8. C++
was used solely for the Standard Template Library, which makes building and
using dynamic arrays very easy.
Each flow is broken down into a series of bursts, which can be described by
either a number of bytes per burst, or a number of packets per burst. Flowgen
uses polling to send packets at the desired time. There is a continuous loop
that checks each flow to see if a packet is ready to be sent. Every time a
packet is sent, the next packet for that flow is computed. By default, if
this next packet is part of a burst, it will be sent before checking other
flows. In this way, flowgen can generate bursty traffic.
If the sender is unable to send a packet (out of buffer space, for
example), flowgen will try sending it again the next time through the main
loop. Every time a packet send time is computed, the next packet send time is
also computed, so that if a packet cannot be sent before the sending time of
the next packet, the current packet will be skipped. The next packet inherits
the current packet's application-level sequence number, so that the skipped
packet does not show up as a loss on the receiver end. Skipped packets are
kept track of and the total number for each flow is reported at the end of an
experiment.
By default, flowgen adds a 32-byte header to each packet sent. This header
contains the packet size, flow id, sending time, sequence number, burst
number, packet in burst, and burst size (in packets). This header is saved in
the output file (if specified) on the receiver side.
No matter the packet size, flowgen will send packets as they are specified.
When using TCP, large packets are at the mercy of TCP's Max Segment Size.
Flowgen will pass packets to the operating system when they are ready to be
sent, but makes no guarantees of their actual sending time.
-b: To send high bit-rates of data, the socket send and recv buffer
sizes should be sufficiently large. Use this option to increase the default
socket buffer size.
Implementation
Usage
Usage: flowgen -f config_file [-bcghnpq]
-b bytes: set socket send/recv buffer size
-c: force UDP sender to connect
-g num: debugging level
level 1 = lost & ooo packets
level 2 = level 1 + out of buffer space warnings
level 3 = level 2 + all packet headers
-h: no app-level header
-n: non-blocking sockets
-p: packet-by-packet scheduling
-q: quit when packets would be skipped
-c: When connecting a UDP socket, if the receiver is not
available, the sender will report an error and quit. By default, UDP senders
do not connect to their remote hosts. If you would like to ensure that your
receivers will see the entire run, use the -c option to force the UDP sender
to connect.
-g: According to the level, debugging information will be
displayed. For level 1, lost and out-of-order packet warnings when using UDP
will be displayed by the receiver. For level 2, all level 1 messages, plus
out of buffer space warnings will be displayed by the sender. For level 3,
all level 2 messages, plus all packet headers will be displayed, by both the
sender and receiver.
-h: Flowgen adds a 32-byte application-level header to each packet
in order to collect loss and throughput statistics. If you wish to forfeit
these statistics in order to have packet sizes less than 32 bytes, invoke
flowgen with the -h option.
-n: Flowgen by default uses blocking send() calls. In some
instances, non-blocking sockets would result in better perfomance.
-p: By default, flowgen will schedule a burst of packets to be sent
at once. Using the -p option, flowgen will send one packet at a time from
each available flow.
-q: As described in the implementation section, flowgen skips
sending those packets that would have actually been sent more than one burst
interval late. If using the -q option, when this occurs, flowgen will report
an error and quit.
Configuration Files
Legend
TERMINAL
Non_Terminal
user input
(one or more)+
[optional]
Grammar
Config_File | := | [OUTPUT output_file] | |||
(OutFlow)+ | | |||||
(InFlow)+ | |||||
OutFlow | := | OUTFLOW | Inflow | := | INFLOW |
(Hdr)+ | (Hdr)+ | ||||
(Traffic)+ | [END_TIME seconds] | ||||
(Footer)+ | |||||
Hdr | := | [SENDER hostname or IP addr] | |||
RECEIVER hostname or IP addr | |||||
PORT port | |||||
PROTOCOL (TCP | UDP) | |||||
Traffic | := | PACKET_SIZE expression | | |||
BURST_PACKETS expression | | |||||
BURST_BYTES expression | | |||||
BURST_INTERVAL expression | |||||
Footer | := | START_TIME seconds | | |||
END_TIME seconds | | |||||
[SEED integer] |
# sender.cfg # OUTPUT /tmp/sender.flg # output file # OUTFLOW # this is a new outgoing flow SENDER tyagi # sender's address RECEIVER thurston # receiver's address PORT [7003:1:7005] # receiver's port to send to # (The range specification says to create # three flows with port numbers # 7003, 7004, 7005, respectively.) PROTOCOL UDP # use UDP PACKET_SIZE 3000 # constant packet size BURST_PACKETS 5 # constant burst size BURST_INTERVAL poisson ([0.500:.5:1.5]) # burst interval -- poisson distributed # mu = 0.5, 1.0, 1.5, respectively START_TIME 0 # start as soon as flowgen starts END_TIME 60.75 # end 60.75 seconds after start SEED 123456 # use this specific seed # OUTFLOW # this is a new outgoing flow RECEIVER thurston # receiver's address PORT 7004 # receiver's port PROTOCOL TCP # use TCP BURST_BYTES normal (2900, 100) # bytes per burst -- normal distributed # mu = 2900, sigma = 100 BURST_INTERVAL 0.500 # constant burst interval START_TIME 15 # start 15 seconds after flowgen starts END_TIME 90 # end 90 seconds after flowgen starts
# recvr.cfg # OUTPUT /tmp/recv.flg # output file # INFLOW # this is a new incoming flow RECEIVER thurston # listen at this address PORT [7003:1:7005] # listen on this port # (3 flows on ports 7003, 7004, 7005) PROTOCOL UDP # listen for UDP END_TIME 65 # quit 65 seconds after start # INFLOW # this is a new incoming flow PORT 7004 # listen on port PROTOCOL TCP # listen for TCPNote: Make sure there's a newline after the last line in the config files.
Output
Flowgen creates two types of output. The main output file, specified in
the configuration file, stores statistics for each flow. First, the host,
time, and date of the experiment is saved, followed by the configuration file
used. On the sender's end, this information is followed by throughput
statistics in text format. On the receiver's side, the configuration file is
followed by the application-level packet headers in binary form. Both files
can be processed by flowparse. Flowgen also produces
status messages to stdout.
tyagi% flowgen -f sender.cfg
Opened /tmp/sender.flg for output. [flow 1]: (9216 byte send buffer, blocking) [flow 2]: (9216 byte send buffer, blocking) [flow 3]: (9216 byte send buffer, blocking) [flow 4]: (16384 byte send buffer, blocking) [flow 1] -- starting @ 0.000005... [flow 2] -- starting @ 0.003097... [flow 3] -- starting @ 0.006091... [flow 4] -- starting @ 15.037742... [flow 3] -- DONE @ 60.75 [flow 1] -- DONE @ 60.80 [flow 2] -- DONE @ 60.81 [flow 4] -- DONE @ 90.05 flow # sent skipped sent duration tput [ 1] 565 pckts ( 0) 113 bursts 60.75 s 0.223 Mbps [ 2] 300 pckts ( 0) 60 bursts 60.75 s 0.119 Mbps [ 3] 170 pckts ( 0) 34 bursts 60.75 s 0.067 Mbps [ 4] 150 pckts ( 0) 150 bursts 75.00 s 0.046 Mbps Closed /tmp/sender.flgthurston% flowgen -f recvr.cfg
Opened /tmp/recv.flg for output. [flow 1]: (41600 byte recv buffer) [flow 2]: (41600 byte recv buffer) [flow 3]: (41600 byte recv buffer) [flow 1] (1) -- receiving @ 2.346063... [flow 2] (2) -- receiving @ 2.446094... [flow 3] (3) -- receiving @ 2.449487... [flow 4]: (17280 byte recv buffer) [flow 4] (4) -- receiving @ 17.046145... [flow 2] (2) -- DONE @ 65.00 [flow 3] (3) -- DONE @ 65.05 [flow 1] (1) -- DONE @ 65.05 [flow 4] (4) -- DONE @ 91.86 All connections closed. flow # sender received lost % lost duration tput [ 1] ( 1) 408 pckts 157 lost 27.788 % 58.59 s 0.167 Mbps [ 2] ( 2) 260 pckts 40 lost 13.333 % 58.49 s 0.107 Mbps [ 3] ( 3) 168 pckts 2 lost 1.176 % 59.49 s 0.068 Mbps [ 4] ( 4) 150 pckts 0 lost 0.000 % 74.30 s 0.047 Mbps Closed /tmp/recv.flg
Processing Output (flowparse)
Usage
flowparse -f flowgen_file [-ciprs]
-c flow: print config info for flow [0 = all]
-i : print info on all flows [default]
-p flow: print packet headers for flow [0 = all]
-r flow: print receiver's stats for flow [0 = all]
-s flow: print sender's stats for flow [0 = all]
Examples
thurston% flowparse -f /tmp/recv.flg
Run on thurston at Thu Nov 2 10:42:15 1999
[flow 1] {sender} --> thurston:7003 UDP
[flow 2] {sender} --> thurston:7004 UDP
[flow 3] {sender} --> thurston:7005 UDP
[flow 4] {sender} --> thurston:7004 TCP
thurston% flowparse -f /tmp/recv.flg -c 0
Run on thurston at Tue Nov 2 10:42:15 1999
# recvr.cfg
#
OUTPUT /tmp/recv.flg # output file
#
INFLOW # this is a new incoming flow
RECEIVER thurston # listen at this address
PORT [7003:1:7005] # listen on port
# (3 flows on ports 7003, 7004, 7005)
PROTOCOL UDP # listen for UDP
END_TIME 65 # quit 65 seconds after start
#
INFLOW # this is a new incoming flow
PORT 7004 # listen on port
PROTOCOL TCP # listen for TCP
thurston% flowparse -f /tmp/recv.flg -c 1
INFLOW # this is a new incoming flow
RECEIVER thurston # listen at this address
PORT 7003 # listen on port
PROTOCOL UDP # listen for UDP
END_TIME 65 # quit 65 seconds after start
thurston% flowparse -f /tmp/recv.flg -r 0
flow # sender received lost % lost duration tput
[ 1] ( 1) 408 pckts 157 lost 27.788 % 58.59 s 0.167 Mbps
[ 2] ( 2) 260 pckts 40 lost 13.333 % 58.49 s 0.107 Mbps
[ 3] ( 3) 168 pckts 2 lost 1.176 % 59.49 s 0.068 Mbps
[ 4] ( 4) 150 pckts 0 lost 0.000 % 74.30 s 0.047 Mbps
thurston% flowparse -f /tmp/recv.flg -p 1
recv_flow sender_flow recv_time size seq_num send_time burst packet_in_burst burst_size
1 1 944766578.121739 3000 1 944766577.573220 1 1 5
1 1 944766578.228574 3000 2 944766577.573426 1 2 5
1 1 944766578.228711 3000 3 944766577.573574 1 3 5
1 1 944766578.228827 3000 4 944766577.573727 1 4 5
1 1 944766578.228937 3000 5 944766577.573872 1 5 5
1 1 944766579.594936 3000 6 944766579.570934 2 1 5
1 1 944766579.595006 3000 7 944766579.571103 2 2 5
1 1 944766579.595058 3000 8 944766579.571244 2 3 5
1 1 944766579.595110 3000 9 944766579.571385 2 4 5
...
thurston% flowparse -f /tmp/sender.flg -s 0
flow # sent skipped sent duration tput
[ 1] 565 pckts ( 0) 113 bursts 60.75 s 0.223 Mbps
[ 2] 300 pckts ( 0) 60 bursts 60.75 s 0.119 Mbps
[ 3] 170 pckts ( 0) 34 bursts 60.75 s 0.067 Mbps
[ 4] 150 pckts ( 0) 150 bursts 75.00 s 0.046 Mbps
Performance Issues
Flowgen is currently undergoing preliminary performance testing. So far,
we've tested TCP and UDP throughput on a 100 Mbps link. UDP maximum
throughput is over 95 Mbps, and TCP maximum throughput is almost 70 Mbps.
Issues that affect TCP throughput are the TCP window size, socket buffer size,
and loss rate. Seemingly negligible loss rates for UDP can cause TCP's
throughput to suffer dramatically.
Other
DiRT documents
Author: Michele Clark