gen_send, gen_recv: A Simple UDP Traffic Generater Application
In testing the quality of service functionality of networks, it is desireable to take measurements from the applications viewpoint. In this scenerio, the network is viewed as a black box. A simple unicast traffic generator application, gen_send and gen_recv is used. The traffic generator application is designed to be able to fill a 100Mbit Ethernet, and account for all data sent. Thus, reserved bandwidth flows and/or best effort flows can be sent, competing for the resources of a 100Mbit Ethernet. Packets are marked with a sequence number. Per second bandwidth and packet loss data are collected.
gen_send can send ~95Mbits/sec over a dedicated 100Mbit Ethernet with 0% packet loss.
gen_send has command line arguments to specify the address and port of the receiver, the desired KBPS to send, an initial packet size, and the time interval in usec between sends of packet size per second. The last two command line arguments control how bursty or smooth the data transmission is. A large initial packetsize and a large usec between packet sends means that all the data up to the input KBPS will be sent early on in a second, with the remainder of the second having no data sends. This produces a bursty UDP transmission. By decreasing the packet size and the usec between packet sends, the input KBPS can be spread evenly over each second producing a smooth UDP transmission. gen_send is self-adjusting in that the initial packet size is increased by two bytes each second until the input KBPS is achieved. Packets contain a sequence number that is incremented with each send. gen_send outputs the number of bits per second it sends, the packet size, and the sequence number of the first packet sent at each second boundary. The output sequence number and the usec between packet sends can be used to calculate what portion of a second is idle. The larger the idle time, the more bursty the UDP transmission.
gen_recv is started first. It opens a UDP socket and prints the port number, which is used as input to gen_send. gen_recv notes the time it was started. Each second, gen_recv writes the time in seconds and percent of second since it started, the received bandwidth and packets lost into an array in memory. The array is written to files when gen_recv receives a SIGKILL, or when collected data fills the internal array, currently of size 1024. Using the packet size and bits sent from gen_send, all data sent can be accounted for in gen_recv by multiplying the packets lost by the packet size and adding it to the bandwidth received.
I have yet to add a time stamp to the udp packets, so latency and jitter are not yet being measured. This will be straight forward considering gen_send is already noting the time per second in order to faithfully output the desired KBPS.
Send 40Mbits/sec from machine1 to machine 2. Start with an intial packet size of 496, with 100 usec between sends.
gen_send outputs to standard out. gen_recv outputs to files. After gen_send hits 40000000 bits and the packet size remains constant, you can see by subtaction technology that there were 9882 (69384 - 59502) out of 1000 sends (1,000,000/100) used, i.e. 98.82% of each second is used to send the 40Mbits, this is not a bursty send! Perhaps I'll code gen_send to output this stat. Note that 9882 sends 506 bytes * 8 bits = 40002336 bits. The extra 2336 bits is less than one packet - 506 * 8 = 4048 bits - the last packet sent by gen_send is sized to exactly fit the input KBPS.
gen_recv creates two files, recv_gen_bw which holds the recevied bandwidth data and recv_gen_pl which holds the received packet loss data. The first data points in both recv_gen_bw and recv_gen_pl are uninitialized and should be ignored. Each data line in recv_gen_bw shows <seconds.%of second since gen_recv was started>,< a space>, and then <the number of bits received since the last data line>. Each data line in recv_gen_pl shows <seconds.%of second since gen_recv was started>, <a space>, and then <the number of packets lost since the last data line>. The discrepency between the bandwidth sent (40000000 bits) and the bandwidth received (40008096) is due to the fact that 'sidea of the beginning of a second is offset from gen_send's.
machine1% gen_send machine2.domain.name 1402 40000 496 100
0 bits sent seq_no: 1893515247 msg len: 498
39589008 bits sent seq_no: 9936 msg len: 500 3
9752000 bits sent seq_no: 19874 msg len: 502
39931088 bits sent seq_no: 29817 msg len: 504
40000000 bits sent seq_no: 39738 msg len: 506
40000000 bits sent seq_no: 49620
40000000 bits sent seq_no: 59502
40000000 bits sent seq_no: 69384
40000000 bits sent seq_no: 79266
40000000 bits sent seq_no: 89148
40000000 bits sent seq_no: 99030
40000000 bits sent seq_no: 108912
40000000 bits sent seq_no: 118794
machine2% cat recv_gen_bw
machine2% cat recv_gen_pl