-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtfo.py
197 lines (175 loc) · 6.56 KB
/
tfo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#!/usr/bin/python
"OMSCS 6250 Project 4: TCP Fast Open"
from mininet.topo import Topo
from mininet.node import CPULimitedHost
from mininet.link import TCLink
from mininet.net import Mininet
from mininet.log import lg
from mininet.util import dumpNodeConnections
from mininet.cli import CLI
import subprocess
from subprocess import Popen, PIPE
from multiprocessing import Process
import termcolor as T
from argparse import ArgumentParser
import sys
import os
import time
import signal
import string
def cprint(s, color, cr=True):
if cr:
print T.colored(s, color)
else:
print T.colored(s, color),
def kill_proc(proc):
Popen(("ps -ef | grep %s | grep '^root' | grep -v python | "
+ "sed -s 's/ */ /g' | "
+ "cut -f2 -d' ' | xargs kill -9 2> /dev/null") % proc,
shell=True).wait()
parser = ArgumentParser(description="TCP Fast Open")
parser.add_argument('--bwhome', help="Home network bandwidth (Mb/s)",
type=float, default=1000)
parser.add_argument('--delayhome', help="Home network delay (ms)",
type=int, default=1)
parser.add_argument('--bwnet', help="Internet bandwidth (Mb/s)",
type=float, default=4) # Experiment is 4Mbps/256Kbps.
parser.add_argument('--delaynet', help="Internet delays to test (ms)",
type=int, default=10)
parser.add_argument('--name',
help=("Name for the Webpages/ directory, " +
"and the associated Webpages.pages and " +
"Webpages.fetchlog files."),
type=str)
parser.add_argument('--port', help="Default server port.",
type=int, default=8000)
parser.add_argument('--tfo', help="Enable TFO.",
type=int, default=0)
parser.add_argument('--testruns', help="Number of test runs.",
type=int, default=2)
args = parser.parse_args()
lg.setLogLevel('info')
def sanitize_file(file):
"Turn a URL into a valid filename."
valid = "-_.() %s%s" % (string.ascii_letters, string.digits)
return ''.join(c for c in file if c in valid)
class StarTopo(Topo):
"Star topology for TCP Fast Open experiment"
def __init__(self):
super(StarTopo, self ).__init__()
def create_topology(self):
user = self.addHost('user')
directories = os.listdir(args.name)
servers = []
index = 0
for directory in directories:
server = self.addHost('server' + str(index))
servers.append([directory, server])
index += 1
home_switch = self.addSwitch('s0')
self.addLink(user, home_switch,
bw=args.bwhome,
delay=str(args.delayhome) + 'ms', use_htb=True)
# Assumes args.name directory _only_ has directories in it.
for name, server in servers:
self.addLink(server, home_switch,
bw=args.bwnet,
delay=str(args.delaynet) + 'ms', use_htb=True)
return servers
def start_servers(net, servers):
time.sleep(2) # Give Mininet some time to start everything.
hack_dns = []
cwd = os.getcwd()
cprint("Starting " + str(len(servers)) + " servers...",
"green")
for hostname, server_name in servers:
server = net.getNodeByName(server_name)
outdir = (cwd + "/serverlogs/" +
str(args.delaynet) + "-" +
"tfo-" + str(args.tfo) + "/")
if not os.path.exists(outdir):
os.makedirs(outdir)
outfile = open(outdir + sanitize_file(hostname), "w+")
dir = cwd + '/' + args.name + '/' + hostname
server.popen('cd ' + dir, shell=True).wait()
# Run Python without buffering.
server.popen('python -u ' + cwd + '/tfo-test/http_tfo.py ' +
'--port=' + str(args.port),
shell=True,
stderr=subprocess.STDOUT,
cwd=dir,
stdout=outfile)
hack_dns.append(hostname + " " + server.IP() +
" " + str(args.port))
# Write out the hack DNS file that the Chrome shell (the client)
# will use to remap its requests to the servers we started above.
# Format is: 'hostname' space 'ip' space 'port' newline.
with open("hack_dns", "w+") as f:
for line in hack_dns:
f.write(line + "\n")
def run(topo, net, page, testrun, delay):
cwd = os.getcwd()
dir = (cwd + "/client/" +
str(args.delaynet) + "-" + str(testrun) +
"-tfo-" + str(args.tfo) + "/")
if not os.path.exists(dir):
os.makedirs(dir)
outfile = open(dir + sanitize_file(page), "w+")
command_tfo = ""
if args.tfo:
command_tfo = "--enable-tcp-fastopen=1"
command = (cwd + "/test_shell "
" --stats --savefiles " +
command_tfo +
" --hack_dns=" + cwd + "/hack_dns " +
page)
client = net.getNodeByName("user")
# This is an informative measurement but includes the shell's
# start time, so it shouldn't be used as the actual benchmark.
# The Chrome shell outputs more accurate results in its log file.
# Python's timer also isn't quite accurate on some platforms.
start = time.time()
client.popen(
command,
stderr=subprocess.STDOUT,
stdout=outfile,
shell=True, cwd=dir).wait()
end = time.time()
cprint(((" Fetching %s took %6.3fs.") %
(page, end - start)), "green")
if __name__ == '__main__':
net = None
try:
start = time.time()
topo = StarTopo()
servers = topo.create_topology()
net = Mininet(topo=topo, link=TCLink)
#net = Mininet(topo=topo, host=CPULimitedHost, link=TCLink)
net.start()
dumpNodeConnections(net.hosts)
start_servers(net, servers)
time.sleep(2) # Let the servers start properly.
#CLI(net)
pages = []
with open(args.name + '.pages', 'r') as namefile:
pages = namefile.readlines()
pages = [p.strip() for p in pages if len(p.strip()) != 0]
for testrun in range(args.testruns):
for page in pages:
cprint(("Experiment %s %s @ %sms delay" %
(testrun, page, args.delaynet)), "blue")
# Make sure the Chrome shell doesn't server from cache.
with open('/dev/null', 'w+') as null:
Popen("rm -r ./cache",
shell=True, stdout=null, stderr=null).wait()
run(topo, net, page, testrun, args.delaynet)
Popen("rm -r ./cache",
shell=True, stdout=null, stderr=null).wait()
cprint("Experiment done", "green")
finally:
cprint("Cleaning up", "red")
sys.stdout.flush()
if net: net.stop()
[kill_proc(proc) for proc in ["ping", "bwm-ng", "tcpprobe",
"simhost", "wget", "test_shell"]]
cprint("Done", "green")