#!/usr/bin/env python import math """ Estimate upper bounds on TCP connection throughput, given MSS, RTT, and loss rate Implemented from slightly simplified equations on: http://www.slac.stanford.edu/comp/net/wan-mon/thru-vs-loss.html In particular: ''We have assumed the number of packets acknowledged by a received ACK is 2 (this is b in the Padhye et. al. formula 31)'' There are two functions you care about: tcp_bw(mss, rtt, loss_rate, ...) using the more sophisticated calculations tcp_bw_mathis(mss, rtt, loss_rate, ...) for the back-of-the-envelope calculation that started it all """ def tcp_bw_mathis(mss, rtt, loss_rate, want_bytes_per_second=False): """ Using the formula 'Rate <= (MSS/RTT)*(1 / sqrt{p})' from 'The macroscopic behavior of the TCP congestion avoidance algorithm' Mathis, et al. CCR 27(3), July 1997 calculate the expected bandwidth (in bits per second) of a TCP connection. Parameters: mss - Maximum Segment Size (bytes) rtt - Round Trip Time (seconds) loss_rate - ratio of packets that are lost (0.1 for 10%) Return: upper bound of the transfer rate (float), in bits per second unless @want_bytes_per_second """ if not want_bytes_per_second: mss = mss * 8.0 return (mss/rtt)*(1.0/math.sqrt(loss_rate)) def G(p): return (1 + p + 2.0*(p**2) + 4.0*(p**3) + 8.0*(p**4) + 16.0*(p**5) + 32.0*(p**6) ) def Q(p,w): return min(1.0, ( (1.0 - (1.0-p)**3) * (1.0 + (1.0-p)**3) * (1.0 - (1.0-p)**(w-3)) ) / ((1.0 - (1.0-p)**w)) ) def w(p): return (2.0/3.0)*(1.0 + math.sqrt(3.0*((1.0-p)/p) + 1.0)) def tcp_bw(mss, rtt, loss_rate, wmax=30, initial_rto=3.0, want_bytes_per_second=False ): """ Using the set of of formulas from 'Modelling TCP throughput: A simple model and its empirical validation' by J. Padhye, et al, SIGCOMM 1998 calculate the expected bandwidth (bits per second)of a TCP connection. While more complicated, these seem to give more accurate readings for high loss rates (> 2%). Parameters: mss - Maximum Segment Size (bytes) rtt - Round Trip Time (seconds) loss_rate - ratio of packets that are lost (0.1 for 10%) wmax - maximum window size (number of segments) initial_rto - Initial Retransmission Timeout (RTO) in seconds want_bytes_per_seconds - set to True if you want Bytes/second Return: upper bound of the transfer rate (float), in bits per second unless @want_bytes_per_second """ p = float(loss_rate) if not want_bytes_per_second: mss = mss * 8.0 if (w(p) < wmax): rate = (mss * (((1.0-p)/p) + w(p) + Q(p,w(p))/(1.0-p)) / (rtt * ((w(p)+1.0))+(Q(p,w(p))*G(p)*initial_rto)/(1.0-p)) ) else: rate = ( ( mss * ( ((1.0-p)/p) + wmax + Q(p,wmax)/(1.0-p) ) ) / ( ( rtt * ( 0.25*wmax + ((1.0-p)/(p*wmax) + 2.0) ) ) + (Q(p,wmax)*G(p)*initial_rto)/(1.0-p) ) ) return rate