This article will show you how to reproduce TCP incast using a virtual network at an end host.
1. Topology
- VM1, VM2 and VM3 are clients (sender) and VM5 is a server (receiver). VM4 play the role of switch and you can realize your NF at it.
- start up the topology
#createVnet.sh
sudo ovs-vsctl add-br mgmt
echo "create mgmt"
sudo ovs-vsctl add-br exp_1
echo "create exp_1"
sudo ovs-vsctl add-br exp_2
echo "create exp_2"
#clear NAT
#sudo ifconfig docker0 down
sudo iptables -F
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo ifconfig mgmt 100.0.0.1/24 up
#sudo ifconfig exp_1 up
#sudo ifconfig exp_2 up
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 100.0.0.0/24 ! -d 100.0.0.0/24 -j MASQUERADE
#iptables -nvL
#sudo virsh create /etc/libvirt/qemu/vm0.xml
#sudo virsh create /etc/libvirt/qemu/vm1.xml
#sudo virsh create /etc/libvirt/qemu/vm2.xml
sudo virsh start vm1
sudo virsh start vm2
sudo virsh start vm3
sudo virsh start vm4
sudo virsh start vm5
#ovs-dpctl show
#sudo ovs-ofctl add-flow exp in_port=1,action=output:2
#sudo ovs-ofctl add-flow exp in_port=3,action=output:4
#sudo ovs-ofctl add-flow exp in_port=4,action=output:1
echo "finished!"
- destroy the virtual network
#destroyVnet.sh
sudo virsh destroy vm1
sudo virsh destroy vm2
sudo virsh destroy vm3
sudo virsh destroy vm4
sudo virsh destroy vm5
sudo ovs-vsctl del-br mgmt
echo "delete mgmt"
sudo ovs-vsctl del-br exp_1
echo "delete exp_1"
sudo ovs-vsctl del-br exp_2
echo "delete exp_2"
2. Incast
#!/bin/bash
protocol=("reno")
ip_arr=(10 20 30)
flow_arr=(1 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30)
#flow_arr=(1 2 4)
ssh_func()
{
# ${1}: protocol ${2}: ip ${3}: flow number
sshpass -p 1234 ssh [email protected].${2} > /dev/null 2>&1 << eeooff
#sudo sysctl -w net.ipv4.tcp_ecn=1
#sudo sysctl -w net.ipv4.tcp_congestion_control=${1}
iperf -c 10.0.0.50 -n 64K -P ${3} > /home/ubuntu/Desktop/iperf_${1}_${3}.txt
#iperf -c 10.0.0.50 -i 1 -t 5 > /home/ubuntu/Desktop/iperf_${1}_${3}.txt
exit
eeooff
}
ssh_server()
{
sshpass -p 1234 ssh [email protected] > /dev/null 2>&1 << eeooff
#sudo sysctl -w net.ipv4.tcp_ecn=1
#sudo sysctl -w net.ipv4.tcp_congestion_control=${1}
timeout -s SIGINT 3 iperf -s > /home/ubuntu/Desktop/iperf_${1}_${3}.txt
exit
eeooff
}
for proto in ${protocol[@]}
do
for flow in ${flow_arr[@]}
do
echo "protocol : "${proto} " flow number : "${flow}
#ssh_server ${proto} ${ip} ${flow} & # 3 seconds
#sleep 1
for ip in ${ip_arr[@]}
do
#echo ${proto} 10.0.0.${ip} ${flow}
ssh_func ${proto} ${ip} ${flow} & # 64K 10Gbps
done
echo ""
sleep 4
done
echo ""
done
echo "done!!!"
exit 0
3. Results
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import re
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
from pylab import *
import matplotlib.gridspec as gridspec
def read_iperf(path):
with open(path,'r') as iperf:
for line in iperf.readlines():
matchobj = re.search(r'\[.*\]',line,re.M|re.I)
if matchobj:
if re.search(r'SUM',line,re.M|re.I):
temp_1 = re.search(r'Bytes .* Mbits/sec',line,re.M|re.I)
temp_2 = re.search(r'Bytes .* Gbits/sec',line,re.M|re.I)
if temp_1:
aList = re.split(r'\s+',temp_1.group())
return float(aList[1])/1000
elif temp_2:
aList = re.split(r'\s+',temp_2.group())
return float(aList[1])
def path_gen():
dir_path = "/Users/yche/Desktop/results/"
folders = ["client_10","client_20","client_30"]
flow_num = [2*i + 2 for i in range(15)]
protos = ["dctcp","cubic","reno","reno_ecn_off"]
tput_list= []
for p in protos:
put_temp = []
for flow in flow_num:
good_put = 0
for folder in folders:
path = dir_path + folder + "/iperf_" + p + "_" + str(flow) + ".txt"
good_put = good_put + read_iperf(path)
#print (path)
put_temp.append(good_put)
tput_list.append(put_temp)
for item in tput_list:
print(item)
return tput_list
def plot(good_put):
patterns = ['b*-','g+-','cx-',"md-"]
legends = ["DCTCP","CUBIC","RENO","RENO (NO ECN)"]
dctcp = good_put[0]
cubic = good_put[1]
reno = good_put[2]
reno_ecn_off = good_put[3]
plt.figure(figsize=(6,3))
ax = plt.subplot(1,1,1)
x_data = [2*i+2 for i in range(len(dctcp))]
#print(x_data)
ax.plot(x_data,dctcp,patterns[0],label=legends[0])
ax.plot(x_data,cubic,patterns[1],label=legends[1])
ax.plot(x_data,reno,patterns[2],label=legends[2])
ax.plot(x_data,reno_ecn_off,patterns[3],label=legends[3])
ax.set_xlim(-1,31)
ax.set_ylim(0,10)
ax.set_xlabel("Number of senders in parallel")
ax.set_ylabel("goodput (Gbps)")
ax.yaxis.grid(True)
plt.legend(loc=0,prop={'size': 10})
plt.tight_layout()
pp = PdfPages("/Users/yche/Desktop/results/incast.pdf")
pp.savefig()
pp.close()
if __name__ == '__main__':
good_put = path_gen()
plot(good_put)