Tutorial 2 - IPv6 & TCP

Submission process:

  • Submission deadline is November 18, 16:00 CET (before the lecture) .
  • Commit and push your solution as separate notebook files per subtask via git as ./tutorial/tutorial2/tutorial2_3.ipynb. Please take care of the correct subfolder/filename since submission is denied otherwise.
  • During the first lecture after the deadline we will discuss a sample solution in class.
  • Afterwards, you have time until November 22, 23:59 CET to submit a corrected version of your submission:
    1. Rework your solution according to our discussion in class.
    2. Commit and push the corrected version as a separate file per subtask via git as ./tutorial/tutorial2/tutorial2_3.ipynb. Please take care of the correct filename since submission is denied otherwise.

Remarks:

  • Grading is done based on both versions of your submission.
  • If the first submission is missing your submission will not be graded.
  • If the second submission contains major flaws after revision not more than half of the credits for this tutorial can be achieved.
  • A sample solution is provided after November 22, 23:59 CET eventually.
  • Do NOT duplicate cells or change the type of cells, otherwise you might receive zero points for your submission
  • Please use acn@net.in.tum.de for questions regarding lecture, tutorial, and project of ACN.

Problem 3 TCP Congestion Control Fairness (4 credits)

This problem is focused on TCP congestion control. Different algorithms are observed and the fairness between them is evaluated.

In the following we consider two TCP flows which share the same bottleneck link. The next cell visualizes the sending rates of the two flows.

In [1]:
%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt

# Download RTT CSV from ACN website
#TODO Replace again
!wget -N https://acn.net.in.tum.de/exercise/tcp_cc.npz
#!wget -N "http://[::1]:8000/generated/tcp_cc.npz"

# Load file into Python
data = np.load('tcp_cc.npz')
ts, flow1, flow2 = data['ts'], data['flow1'], data['flow2']

7[Files: 0  Bytes: 0  [0 B/s] Re]8
7[https://acn.net.in.tum.de/exer]87tcp_cc.npz             0% [<=>                           ]       0          B/s87HTTP response 304  [https://acn.net.in.tum.de/exercise/tcp_cc.npz]
87tcp_cc.npz             0% [ <=>                          ]       0          B/s87[Files: 0  Bytes: 0  [0 B/s] Re]8
In [2]:
# Helper function to plot data
def plot(*data, x_label=None, y_label=None, legends=[], y_min=None, y_max=None):
    plt.figure(figsize=(18, 6))
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    for xs, ys in data:
        plt.plot(xs, ys)
    plt.legend(legends)
    plt.gca().set_ylim(bottom=y_min, top=y_max)


plot((ts, flow1), (ts, flow2), x_label='Time in s', y_label='Sending Rate in bps', legends=['Flow1', 'Flow2'], y_min=0)
No description has been provided for this image

a) [0.5 credits] One of the flows uses Cubic congestion control, the other one BBR. Identify which of the flows uses BBR. No credits without short reasoning.

Flow2 uses BBR.

The Probe RTT phases in which BBR reduces its sending rate are visible every tenth second.

b) [0.5 credits] Write a function compute_sum() which computes the total sending rate of two flows. It receives two lists and should return a list of the same size.

In [3]:
def compute_sum(flow1, flow2):
    # begin insert code
    return [sum(x) for x in zip(flow1, flow2)]
    # end insert code

    return flow1

plot((ts, flow1), (ts, flow2), (ts, compute_sum(flow1, flow2)),
     x_label='Time in s', y_label='Sending Rate in bps', legends=['flow1', 'flow2', 'total'], y_min=0)
No description has been provided for this image

c) [0.5 credits] Based on your results from b) estimate the bottleneck link's capacity. What happens if the total sending rate of the two flows exceeds this value?

In [4]:
BtlBw = 0

# Enter bottleneck capacity in Mbit/s by changing value of BtlBw 
# begin insert code
BtlBw = 10
#end inser code

What happens if the total sending rate of the two flows exceeds this value?

If the sending rate exceeds the capacity packets are arriving faster at the bottleneck than theey can be processed. This results in the packets getting queued.

d) [0.5 credits] The minimum RTT of both flows is 50ms. Compute the path's BDP using the results from b) in kbit.

In [5]:
BDP = 0
# begin insert code
# BDP : Bandwidth-Delay Product
# BDP = RTT * Bandwidth
# kbit = 10^3 bit
# From b): Bandwidth is 10 Mbit = 10 * 10^6 bit
# RTT is 50ms = 50 * 10^(-3) s

BDP = 50 * 10**(-3) * BtlBw * 10**6 / 10**3
# end insert code
print('BDP: {:.2f} kbit'.format(BDP))
BDP: 500.00 kbit

e) [0.5 credits] In the following you will quantify the fairness of the two flows using Jain's Fairness Index. Explain two advantages of this index.

  • It is within a fixed interval and always returns a value between 0 and 1
  • It is scale free which means that its input does not have to be normalized
  • It can be computed over an arbitrary number of flows
  • It can be easily interpreted by humans. It is $\frac{k}{n}$ if there are $k$ flows are perfectly fair while the other $n − k$ shares are 0

f) [1 credits] Write a function compute_fairness() which receives a list of equal sized lists an then computes Jain's Index elementwise.

In [6]:
# Example:
# input: [[1, 2, 3], [4, 5, 6]]
# output: [jain(1,4), jain(2, 5), jain(3, 6)]
# with jain(x1, x2, ...): jain index of x1, x2, ...

def compute_fairness(*lists):
    
    # this checks is all input lists have same size
    assert len(set(map(len, lists))) == 1
    
    # begin insert code
    output = []
    for i in range(len(lists[0])):
        
        # From RFC 5166
        # J = ( sum_i x_i )^2 / (n * sum_i ( (x_i)^2 ))
        
        sum_normal = 0
        sum_squared = 0
        
        for l in lists:
            sum_normal += l[i]
            sum_squared += l[i]**2
        
        output.append( sum_normal**2 / sum_squared / len(lists))
    return output
    # end insert code

    # Dummy output
    # returns [1,1, ...] of the same length as the first parameter
    return [1, ] * len(lists[0])

plot((ts, compute_fairness(flow1, flow2)), x_label='Time in s', y_label='Jain\'s Index', y_min=0.5, y_max=1)
No description has been provided for this image

g) [0.5 credits] Considering the results from e), assess the fairness between Cubic and BBR. Also take the results from the next cell into account (assuming you implemented the compute_fairness function).

In [7]:
print('Flow1 transmitted {:.2f} Mbit/s on average.'.format(np.mean(flow1) / 10**6))
print('Flow2 transmitted {:.2f} Mbit/s on average.'.format(np.mean(flow2) / 10**6))

total_fairness = compute_fairness([np.mean(flow1)], [np.mean(flow2)])
print('This results in a total fairness of {:.5f}'.format(total_fairness[0]))
Flow1 transmitted 4.98 Mbit/s on average.
Flow2 transmitted 4.75 Mbit/s on average.
This results in a total fairness of 0.99945
  • The two flows alternately receive more bandwidth than the other.
  • Thus, the bandwidth is not shared fairly at a given point in time.
  • However, considering the overall transmitted data it shows that the flows can share the bandwidth well over time.
  • So, both approaches have to be considered when comparing the fairness TCP flows.

Remark: this is one of the few cases where Cubic and BBR share then bandwidth fairly. This fairness is mainly influenced by the size of the bottleneck buffer (in this case about 2.5 BDP). With smaller buffers BBR causes many retransmissions and thus pushes Cubic back, while larger buffers favor Cubic. If you want to read more about the fairness between Cubic and BBR you can have a look at this.

Advanced Computer Networking by Prof. Dr.-Ing. Georg Carle

Teaching assistants: Christian Dietze, Sebastian Gallenmüller, Marcel Kempf, Lorenz Lehle, Nikolas Gauder, Patrick Dirks