UdpThroughputSensor.cc 5.9 KB
Newer Older
1 2
/*
 * Copyright (c) 2006 University of Utah and the Flux Group.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 
 * {{{EMULAB-LICENSE
 * 
 * This file is part of the Emulab network testbed software.
 * 
 * This file is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This file is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * }}}
22 23
 */

24 25
#include "UdpThroughputSensor.h"

26 27 28
using namespace std;

UdpThroughputSensor::UdpThroughputSensor(UdpPacketSensor const * udpPacketSensorVal)
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	: lastAckTime(0),
	throughputKbps(0.0),
	packetHistory(udpPacketSensorVal)
{
	// Do nothing.

}

UdpThroughputSensor::~UdpThroughputSensor()
{

}

void UdpThroughputSensor::localSend(PacketInfo *packet)
{
	sendValid = true;
	ackValid = false;
}

void UdpThroughputSensor::localAck(PacketInfo *packet)
{
	// This is a re-ordered ACK - don't do anything
	// with it - just return.
	sendValid = false;

	if( packetHistory->isAckValid() != true )
	{
		ackValid = false;
		return;
	}
	else
		ackValid = true;

	// Find out how many redundant ACKs this packet is carrying - 0 to 121.
	unsigned char numRedunAcksChar = 0;
	memcpy(&numRedunAcksChar, &packet->payload[0], global::UCHAR_SIZE);
	int numRedunAcks = static_cast<int>(numRedunAcksChar);

	int numThroughputAcks = 1;
	double avgThroughput = 0;

	// This is the timestamp at the receiver, when the original packet was received.
	unsigned long long currentAckTimeStamp = *(unsigned long long *)(packet->payload + 1 + 2*global::USHORT_INT_SIZE ); 

	// This is the first ACK we have seen, store its receiver timestamp
	// and return, we cannot calculate throughput from just one ACK - at least 2.
	if(lastAckTime == 0)
	{
		lastAckTime = currentAckTimeStamp;
		return;
	}

	unsigned short int seqNum = *(unsigned int *)(packet->payload + 1);
	unsigned short int echoedPacketSize = *(unsigned short int *)(packet->payload + 1 + global::USHORT_INT_SIZE);

	unsigned long long ackTimeDiff = currentAckTimeStamp - lastAckTime;
	unsigned long long timeDiff = 0;
86
	vector<UdpPacketInfo > ackedPackets = packetHistory->getAckedPackets();
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	vector<UdpPacketInfo>::iterator vecIterator;

	// Average the throughput over all the packets being acknowledged.
	if(numRedunAcks > 0)
	{
		int i;
		unsigned short int redunSeqNum;
		unsigned short int redunPacketSize;

		for(i = 0;i < numRedunAcks; i++)
		{
			redunSeqNum = *(unsigned short int *)(packet->payload + 1 + global::udpMinAckPacketSize + i*global::udpRedunAckSize);
			redunPacketSize = *(unsigned short int *)(packet->payload + 1 + global::udpMinAckPacketSize + i*global::udpRedunAckSize + global::USHORT_INT_SIZE);

			// Find if this redundant ACK is useful - or it was acked before.
102
			vecIterator = find_if(ackedPackets.begin(), ackedPackets.end(), bind2nd(equalSeqNum(), redunSeqNum));
103

104
			if(vecIterator != ackedPackets.end())
105
			{
106 107 108 109 110 111 112

				timeDiff = *(unsigned long long *)(packet->payload + 1 + global::udpMinAckPacketSize + i*global::udpRedunAckSize + global::udpSeqNumSize);

				// Avoid dividing by zero.
				if(ackTimeDiff - timeDiff == 0)
					continue;

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
				// Calculate throughput for the packet being acked by
				// the redundant ACK.
				numThroughputAcks++;

				// We lost the record of the size of this packet due to libpcap
				// loss, use the length echoed back in the ACK.
				if((*vecIterator).isFake == true)
					avgThroughput += 8000000.0*( static_cast<double> ( redunPacketSize ))  / ( static_cast<double>(ackTimeDiff - timeDiff)*1024.0 );
				else
					avgThroughput += 8000000.0*( static_cast<double> ( (*vecIterator).packetSize ))  / ( static_cast<double>(ackTimeDiff - timeDiff)*1024.0 );

					ackTimeDiff = timeDiff;
			}

		}
	}

	// Calculate the throughput for the current packet being ACKed.
131
	vecIterator = find_if(ackedPackets.begin(), ackedPackets.end(), bind2nd(equalSeqNum(), seqNum));
132

133 134 135 136 137 138 139 140 141 142
	// Avoid dividing by zero.
	if(ackTimeDiff != 0)
	{
		// We lost the record of the size of this packet due to libpcap
		// loss, use the length echoed back in the ACK.
		if(packetHistory->isAckFake() == true)
			avgThroughput += 8000000.0*( static_cast<double> (echoedPacketSize ))  / ( static_cast<double>(ackTimeDiff)*1024.0 );
		else
			avgThroughput += 8000000.0*( static_cast<double> ((*vecIterator).packetSize ))  / ( static_cast<double>(ackTimeDiff)*1024.0 );
	}
143 144 145 146 147 148 149 150 151 152

	throughputKbps = avgThroughput / (static_cast<double> (numThroughputAcks) );

	unsigned long long timeStamp = packet->packetTime.toMicroseconds();
	// Send a message to the monitor with the new bandwidth.
	if(packetHistory->getPacketLoss() == 0)
	{
		// Send this available bandwidth as a tentative value.
		// To be used for dummynet events only if it is greater
		// than the last seen value.
153
		logWrite(SENSOR, "VALUE::Tentative bandwidth for seqNum = %d , value = %f, acktimeDiff = %llu,packet size = %u",seqNum, throughputKbps, ackTimeDiff, (*vecIterator).packetSize);
154

155 156 157
		//CHANGE:
		logWrite(SENSOR, "TPUT:TIME=%llu,TENTATIVE=%f",timeStamp,throughputKbps);
		//logWrite(SENSOR, "LOSS:TIME=%llu,LOSS=0", timeStamp);
158 159 160 161 162 163
	}
	else
	{
		// Send this as the authoritative available bandwidth value.
		logWrite(SENSOR,"VALUE::Authoritative bandwidth for seqNum = %d , value = %f ,ackTimeDiff = %llu ",seqNum,throughputKbps,ackTimeDiff);
		logWrite(SENSOR, "TPUT:TIME=%llu,AUTHORITATIVE=%f",timeStamp,throughputKbps);
164
		//logWrite(SENSOR,"LOSS:TIME=%llu,LOSS=%d",timeStamp,packetHistory->getPacketLoss());
165 166 167 168 169 170
	}

	// Save the receiver timestamp of this ACK packet, so that we can
	// use for calculating throughput for the next ACK packet.
	lastAckTime = currentAckTimeStamp;
}