Commit b06bd1af authored by Pramod R Sanaga's avatar Pramod R Sanaga

*** empty log message ***

parent 4e734a21
ACIM for UDP applications
-------------------------
Contact: pramod@cs.utah.edu
Overview:
---------
UDP for Flexlab is implemented as two stand alone programs as of now -
it will soon be integrated into the exisiting Magent code.
The client applications sends UDP packets to the server at a specified rate. The
client records a timestamp for each packet sent and for each ACK received. The
server sends acknowledgements ( with some redundancy built in ) back to the client.
Based on the time taken for these acks to get back, since the original packets were
sent out: the client calculates the RTT,
the minimum delay ( which is interpreted as all delay except queuing ) ,the maximum
queuing delay, and the achieved throughput.
It has been tested in Emulab, with background cross traffic generated by IPerf TCP and
UDP sessions. I will check in the resulting throughput graphs soon.
How to run it:
--------------
Start the server program first:
1) cd to 'UdpServerDir'
2) Type 'make -f Makefile.server'
3) ./runServer.sh
Then start the client app ( on a different host ):
1) cd to 'UdpClientDir'
2) Type 'make -f Makefile.client'
3) ./runClient.sh
Depending on the arguments given in 'runClient.sh', the client app sends
some number of UDP packets to the server and calculates the achieved throughput values.
The client runs in an infinite loop and (as of now) does not terminate on its own, so
kill it after it stops printing to stdout.
4) Then type './showTputGraph.sh' in 'UdpClientDir'. This displayes a graph
of the throughput values for the session. ( Make sure that gnuplot is present on the system ).
Results and graphs:
------------------
Coming soon.
EXECUTABLE=UdpClient
CC=g++ -g
CFLAGS=
COMPILE_DIR=.OBJECTS
OBJECTS=${COMPILE_DIR}/UdpClient.o \
${COMPILE_DIR}/UdpPacketSensor.o \
${COMPILE_DIR}/UdpMinDelaySensor.o \
${COMPILE_DIR}/UdpMaxDelaySensor.o \
${COMPILE_DIR}/UdpThroughputSensor.o \
${COMPILE_DIR}/UdpPacketInfo.o \
${COMPILE_DIR}/UdpSensor.o
COMMON_INCLUDES=UdpLibs.h \
UdpState.h
${EXECUTABLE}: ${OBJECTS}
${CC} -o $@ ${CFLAGS} $+ -lpcap
${COMPILE_DIR}/UdpClient.o: UdpClient.cc UdpPacketSensor.h ${COMMON_INCLUDES}
${CC} -c ${CFLAGS} -o $@ $<
${COMPILE_DIR}/UdpMinDelaySensor.o: UdpMinDelaySensor.cc UdpMinDelaySensor.h ${COMMON_INCLUDES}
${CC} -c ${CFLAGS} -o $@ $<
${COMPILE_DIR}/UdpMaxDelaySensor.o: UdpMaxDelaySensor.cc UdpMaxDelaySensor.h ${COMMON_INCLUDES}
${CC} -c ${CFLAGS} -o $@ $<
${COMPILE_DIR}/UdpThroughputSensor.o: UdpThroughputSensor.cc UdpThroughputSensor.h ${COMMON_INCLUDES}
${CC} -c ${CFLAGS} -o $@ $<
${COMPILE_DIR}/UdpPacketSensor.o: UdpPacketSensor.cc UdpPacketSensor.h ${COMMON_INCLUDES}
${CC} -c ${CFLAGS} -o $@ $<
${COMPILE_DIR}/UdpPacketInfo.o: UdpPacketInfo.cc UdpPacketInfo.h ${COMMON_INCLUDES}
${CC} -c ${CFLAGS} -o $@ $<
${COMPILE_DIR}/UdpSensor.o: UdpSensor.cc UdpSensor.h ${COMMON_INCLUDES}
${CC} -c ${CFLAGS} -o $@ $<
clean:
rm -f ${COMPILE_DIR}/*.o ${EXECUTABLE}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef UDPLIBS_PELAB_H
#define UDPLIBS_PELAB_H
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <list>
#include <cstdlib>
#include <algorithm>
#include <functional>
#include <climits>
#include <limits.h>
#endif
#include "UdpMaxDelaySensor.h"
UdpMaxDelaySensor::UdpMaxDelaySensor(UdpState &udpStateVal)
: maxDelay(0),
udpStateInfo(udpStateVal)
{
}
void UdpMaxDelaySensor::localSend(char *packetData, int Len,int overheadLen, unsigned long long timeStamp)
{
}
void UdpMaxDelaySensor::localAck(char *packetData, int Len,int overheadLen, unsigned long long timeStamp)
{
int minSize = 1 + sizeof(unsigned int) + sizeof(unsigned long long);
unsigned long long tmpMaxDelay = maxDelay;
if(Len < minSize)
{
cout << "Error: UDP packet data sent to MaxDelaySensor::localAck was less than the "
" required minimum "<< minSize << " bytes\n";
return;
}
int numRedunAcks = static_cast<int>(packetData[0]);
vector<UdpPacketInfo * >::iterator vecIterator;
unsigned int seqNum = *(unsigned int *)(packetData + 1);
unsigned long long oneWayDelay;
bool eventFlag = false;
vecIterator = find_if(udpStateInfo.recentSentPackets.begin(), udpStateInfo.recentSentPackets.end(), bind2nd(equalSeqNum(), seqNum));
oneWayDelay = (timeStamp - (*vecIterator)->timeStamp)/2;
oneWayDelay = ( oneWayDelay )*1500 / (Len + 1);
// Set this as the new maximum one way delay.
if(oneWayDelay > tmpMaxDelay)
{
eventFlag = true;
tmpMaxDelay = oneWayDelay;
}
// Send an event message to the monitor to change the value of maximum one way delay.
maxDelay = tmpMaxDelay - udpStateInfo.minDelay;
if(udpStateInfo.packetLoss != 0 || eventFlag == true)
{
// Report the maximum delay
cout << "New Max Delay = " << maxDelay << "\n";
}
udpStateInfo.maxDelay = maxDelay;
}
#ifndef UDP_MAX_DELAY_SENSOR_PELAB_H
#define UDP_MAX_DELAY_SENSOR_PELAB_H
#include "UdpLibs.h"
#include "UdpState.h"
#include "UdpSensor.h"
class UdpSensor;
class UdpMaxDelaySensor:public UdpSensor{
public:
explicit UdpMaxDelaySensor(UdpState &udpStateVal);
void localSend(char *packetData, int Len,int overheadLen, unsigned long long timeStamp);
void localAck(char *packetData, int Len,int overheadLen, unsigned long long timeStamp);
private:
unsigned long long maxDelay;
UdpState &udpStateInfo;
};
#endif
#include "UdpMinDelaySensor.h"
UdpMinDelaySensor::UdpMinDelaySensor(UdpState &udpStateVal)
: minDelay(ULONG_LONG_MAX),
udpStateInfo(udpStateVal)
{
}
void UdpMinDelaySensor::localSend(char *packetData, int Len,int overheadLen,unsigned long long timeStamp)
{
// Do nothing.
}
void UdpMinDelaySensor::localAck(char *packetData, int Len,int overheadLen, unsigned long long timeStamp)
{
int minSize = 1 + sizeof(unsigned int) + sizeof(unsigned long long);
if(Len < minSize)
{
cout << "Error: UDP packet data sent to MinDelaySensor::localAck was less than the "
" required minimum "<< minSize << " bytes\n";
return;
}
int numRedunAcks = static_cast<int>(packetData[0]);
vector<UdpPacketInfo * >::iterator vecIterator;
unsigned int seqNum = *(unsigned int *)(packetData + 1);
unsigned long long oneWayDelay;
bool eventFlag = false;
vecIterator = find_if(udpStateInfo.recentSentPackets.begin(), udpStateInfo.recentSentPackets.end(), bind2nd(equalSeqNum(), seqNum));
oneWayDelay = (timeStamp - (*vecIterator)->timeStamp)/2;
long minDelayBytes = 0;
// Calculate the delay for the maximum possibly sized packet.
oneWayDelay = ( oneWayDelay ) * 1500 / (Len + 1);
// Set this as the new minimum one way delay.
if(oneWayDelay < minDelay)
{
eventFlag = true;
minDelay = oneWayDelay;
// One byte was chopped off in the base sensor class.
// Add that to the packet length.
minDelayBytes = Len + 1;
}
int redunAckSize = sizeof(unsigned int) + sizeof(unsigned long);
int seqNumSize = sizeof(unsigned int);
if(numRedunAcks > 0)
{
int i;
unsigned int redunSeqNum;
unsigned long timeDiff;
for(i = 0;i < numRedunAcks; i++)
{
redunSeqNum = *(unsigned int *)(packetData + minSize + i*redunAckSize);
timeDiff = *(unsigned long *)(packetData + minSize + i*redunAckSize + seqNumSize);
vecIterator = find_if(udpStateInfo.recentSentPackets.begin(), udpStateInfo.recentSentPackets.end(), bind2nd(equalSeqNum(), redunSeqNum));
if(vecIterator != udpStateInfo.recentSentPackets.end())
{
oneWayDelay = (timeStamp - timeDiff - (*vecIterator)->timeStamp ) /2;
oneWayDelay = ( oneWayDelay ) * 1500 / ( (*vecIterator)->packetSize );
if(oneWayDelay > 0 && oneWayDelay < minDelay)
{
eventFlag = true;
minDelay = oneWayDelay;
minDelayBytes = (*vecIterator)->packetSize;
}
}
}
}
// Send an event message to the monitor to change the value of minimum one way delay.
if(eventFlag == true)
{
cout << "New Min delay = " << minDelay << "\n";
}
udpStateInfo.minDelay = minDelay;
udpStateInfo.minDelayBytes = minDelayBytes;
}
#ifndef UDP_MIN_DELAY_SENSOR_PELAB_H
#define UDP_MIN_DELAY_SENSOR_PELAB_H
#include "UdpLibs.h"
#include "UdpState.h"
#include "UdpSensor.h"
class UdpSensor;
class UdpMinDelaySensor:public UdpSensor{
public:
explicit UdpMinDelaySensor(UdpState &udpStateVal);
void localSend(char *packetData, int Len,int overheadLen, unsigned long long timeStamp);
void localAck(char *packetData, int Len,int overheadLen, unsigned long long timeStamp);
private:
unsigned long long minDelay;
UdpState &udpStateInfo;
};
#endif
#include "UdpPacketInfo.h"
UdpPacketInfo::UdpPacketInfo(unsigned int seqVal, unsigned int packetSizeVal, unsigned long long timeStampVal, bool isFastPacketVal)
:seqNum(seqVal),
packetSize(packetSizeVal),
timeStamp(timeStampVal),
isFastPacket(isFastPacketVal),
lastTimeDiff(0)
{
}
#ifndef UDP_PACKET_INFO_PELAB_H
#define UDP_PACKET_INFO_PELAB_H
class UdpPacketInfo{
public:
UdpPacketInfo::UdpPacketInfo(unsigned int, unsigned int, unsigned long long, bool);
unsigned int seqNum;
unsigned int packetSize;
unsigned long long timeStamp;
bool isFastPacket;
unsigned long long lastTimeDiff;
};
#endif
#include "UdpPacketSensor.h"
UdpPacketSensor::UdpPacketSensor(UdpState &udpStateVal)
:udpStateInfo(udpStateVal)
{
lastPacketTime = 0;
}
void UdpPacketSensor::localSend(char *packetData, int Len, int overheadLen, unsigned long long timeStamp)
{
int minSize = 2*sizeof(unsigned int);
if(Len < minSize)
{
cout << "Error: UDP packet data sent to PacketSensor::localSend was less than the "
" required minimum "<< minSize << " bytes\n";
return;
}
unsigned int seqNum = *(unsigned int *)(packetData);
unsigned int packetSize = *(unsigned int *)(packetData + sizeof(unsigned int));
bool isFastPacket = false;
unsigned long long sendTimeDelta = 0;
if(lastPacketTime == 0)
lastPacketTime = timeStamp;
else
{
sendTimeDelta = timeStamp - lastPacketTime;
lastPacketTime = timeStamp;
if(sendTimeDelta < udpStateInfo.minDelay)
isFastPacket = 1;
// We did not receive an ACK back, so we dont know the minimum
// one way delay. Treat all packets as fast packets until we
// find out the min. delay - this lowers the throughput a bit
// in case of packet loss if the packets were not being sent
// faster than min delay.
if(udpStateInfo.minDelay == 0)
isFastPacket = 1;
}
if(! sentPacketList.empty())
sentPacketList.back()->lastTimeDiff = sendTimeDelta;
sentPacketList.push_back(new UdpPacketInfo(seqNum, packetSize, timeStamp, isFastPacket));
}
void UdpPacketSensor::localAck(char *packetData, int Len, int overheadLen, unsigned long long timeStamp)
{
int minSize = 1 + sizeof(unsigned int) + sizeof(unsigned long long);
int i;
// Remove the old state information.
for(i = 0;i < udpStateInfo.recentSentPackets.size(); i++)
delete udpStateInfo.recentSentPackets[i];
udpStateInfo.recentSentPackets.clear();
udpStateInfo.packetLoss = 0;
udpStateInfo.fastPacketLoss = 0;
udpStateInfo.lostPacketDelay = 0;
udpStateInfo.lastSentTime = (ULONG_LONG_MAX);
if(Len < minSize)
{
cout << "Error: UDP packet data sent to PacketSensor::localAck was less than the "
" minimum "<< minSize << " bytes\n";
return;
}
int redunAckSize = sizeof(unsigned int) + sizeof(unsigned long);
int numRedunAcks = static_cast<int>(packetData[0]);
unsigned int seqNum = *(unsigned int *)(packetData + 1);
// Find the entry for the packet this ACK is acknowledging, and
// remove it from the sent(&unacked) packet list.
list<UdpPacketInfo * >::iterator listIterator;
listIterator = find_if(sentPacketList.begin(), sentPacketList.end(), bind2nd(equalSeqNum(), seqNum));
if(listIterator == sentPacketList.end())
{
cout << "ERROR: Unacked packet list is incorrect Or incorrect"
"acknowledgement received for seqNum = "<<seqNum<<" in PacketSensor::localAck\n";
return;
}
// Store an iterator to the current seqNum being acknowledge, and delete it at the end.
list<UdpPacketInfo * >::iterator curPacketIterator = listIterator;
// Look at the redundant ACKs first.
if(numRedunAcks > 0)
{
unsigned int redunSeqNum;
for(i = 0; i < numRedunAcks; i++)
{
redunSeqNum = *(unsigned int *)(packetData + minSize + i*redunAckSize);
listIterator = sentPacketList.end();
// Check whether the packet that this redundant ACK refers to exists
// in our list of sent ( but unacked ) packets. It might not exist
// if its ACK was not lost earlier.
//listIterator = find_if(sentPacketList.begin(), sentPacketList.end(), bind2nd(equalSeqNum(), redunSeqNum));
listIterator = find_if(sentPacketList.begin(), curPacketIterator, bind2nd(equalSeqNum(), redunSeqNum));
// An unacked packet exists with this sequence number, delete it
// from the list and consider it acked.
if(listIterator != curPacketIterator && listIterator != sentPacketList.end())
{
udpStateInfo.recentSentPackets.push_back(new UdpPacketInfo((*listIterator)->seqNum, (*listIterator)->packetSize, (*listIterator)->timeStamp, (*listIterator)->isFastPacket) );
if( (*listIterator)->timeStamp < udpStateInfo.lastSentTime)
udpStateInfo.lastSentTime = (*listIterator)->timeStamp;
delete (*listIterator);
sentPacketList.erase(listIterator);
}
}
}
udpStateInfo.recentSentPackets.push_back(new UdpPacketInfo((*curPacketIterator)->seqNum, (*curPacketIterator)->packetSize, (*curPacketIterator)->timeStamp, (*curPacketIterator)->isFastPacket));
// Check for packet loss - if we have any unacked packets with sequence
// numbers less than the received ACK seq number, then the packets/or their ACKS
// were lost - treat this as congestion on the forward path.
// Find out how many packets were lost.
listIterator = find_if(sentPacketList.begin(), sentPacketList.end(), bind2nd(lessSeqNum(), seqNum ));
if(listIterator != sentPacketList.end())
{
do{
if( (*listIterator)->timeStamp < udpStateInfo.lastSentTime)
udpStateInfo.lastSentTime = (*listIterator)->timeStamp;
if( (*listIterator)->isFastPacket)
udpStateInfo.fastPacketLoss++;
udpStateInfo.lostPacketDelay += (*listIterator)->lastTimeDiff;
delete (*listIterator);
sentPacketList.erase(listIterator);
listIterator = sentPacketList.end();
udpStateInfo.packetLoss++;
listIterator = find_if(sentPacketList.begin(), curPacketIterator, bind2nd(lessSeqNum(), seqNum ));
}
while( (listIterator != sentPacketList.end()) && (listIterator != curPacketIterator) );
}
if( (*curPacketIterator)->timeStamp < udpStateInfo.lastSentTime)
udpStateInfo.lastSentTime = (*curPacketIterator)->timeStamp;
delete (*curPacketIterator);
sentPacketList.erase(curPacketIterator);
}
#ifndef UDP_PACKET_SENSOR_PELAB_H
#define UDP_PACKET_SENSOR_PELAB_H
#include "UdpLibs.h"
#include "UdpState.h"
#include "UdpSensor.h"
#include "UdpPacketInfo.h"
using namespace std;
class UdpPacketInfo;
//class equalSeqNum;
class UdpSensor;
class UdpPacketSensor:public UdpSensor{
public:
explicit UdpPacketSensor(UdpState &udpStateVal);
void localSend(char *packetData, int Len, int overheadLen, unsigned long long timeStamp);
void localAck(char *packetData, int Len,int overheadLen, unsigned long long timeStamp);
private:
list<UdpPacketInfo *> sentPacketList;
UdpState & udpStateInfo;
unsigned long long lastPacketTime;
};
#endif
#include "UdpSensor.h"
using namespace std;
UdpSensor::UdpSensor()
{
}
void UdpSensor::capturePacket(char *packetData, int Len, int overheadLen, unsigned long long timeStamp)
{
if(Len < 1)
{
cout << "Error: UDP packet data sent to Sensor was less than "
" 1 byte in size\n";
return;
}
if(packetData[0] == '0')
{
localSend( (packetData+1), Len - 1,overheadLen, timeStamp );
}
else if(packetData[0] == '1')
{
localAck( (packetData + 1), Len - 1,overheadLen, timeStamp );
}
}
#ifndef _UDP_SENSOR_PELAB_H
#define _UDP_SENSOR_PELAB_H
#include "UdpLibs.h"
class UdpSensor{
public:
UdpSensor();
virtual void localSend(char *packetData, int Len, int overheadLen,unsigned long long timeStamp)=0;
virtual void localAck(char *packetData, int Len,int overheadLen, unsigned long long timeStamp)=0;
void capturePacket(char *packetData, int Len, int overheadLen, unsigned long long timeStamp);
};
#endif
#ifndef UDP_STATE_PELAB_H
#define UDP_STATE_PELAB_H
#include "UdpLibs.h"
#include "UdpPacketInfo.h"
using namespace std;
class UdpPacketInfo;
struct UdpState{
// vector of info about packets sent from this host,
// sequence number, timestamp & size of the packet.
vector< UdpPacketInfo * > recentSentPackets;
// Indicates the number of packets lost ( in a batch of 4 sent packets )
// updated whenever an ACK is received.
int packetLoss, fastPacketLoss;
unsigned long long lastSentTime;
unsigned long long minDelay;
unsigned long long maxDelay;
unsigned long long minAckTimeDiff;
unsigned long long queuingDelay;
unsigned long long lostPacketDelay;
long minDelayBytes;
};
class equalSeqNum:public binary_function<const UdpPacketInfo * , unsigned int, bool> {
public:
bool operator()(const UdpPacketInfo *packet, unsigned int seqNum) const
{
return (packet->seqNum == seqNum);
}
};
class lessSeqNum:public binary_function<const UdpPacketInfo *, int, bool> {
public:
bool operator()(const UdpPacketInfo *packet,unsigned int seqNum) const
{
return (packet->seqNum < seqNum);
}
};
#endif
#include "UdpThroughputSensor.h"
UdpThroughputSensor::UdpThroughputSensor(UdpState &udpStateVal, ofstream &outStreamVal)
: lastAckTime(-1),
throughputKbps(0.0),
udpStateInfo(udpStateVal),
outStream(outStreamVal)
{
udpStateInfo.minAckTimeDiff = 999999999;
}
void UdpThroughputSensor::localSend(char *packetData, int Len, int overheadLen, unsigned long long timeStamp)
{
// Do nothing.
}
void UdpThroughputSensor::localAck(char *packetData, int Len, int overheadLen, unsigned long long timeStamp)
{
int minSize = 1 + sizeof(unsigned int) + sizeof(unsigned long long);
if(Len < minSize )
{
cout << "Error: UDP packet data sent to ThroughputSensor::localAck was less than the "