-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathiperf.py
More file actions
executable file
·237 lines (186 loc) · 9.6 KB
/
iperf.py
File metadata and controls
executable file
·237 lines (186 loc) · 9.6 KB
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#!/usr/bin/env python
from datetime import datetime
from pexpect import pxssh
import argparse
import csv
import pexpect
import re
import subprocess
import sys
import time
# Tested modulations with associated PIB value and list of bandwidths in Kbits/sec
modulations = {'FSK150': (8, [5, 15, 20, 25, 35, 40, 45, 55, 60, 65, 75, 150]),
'OFDM600': (46, [5, 35, 40, 60, 65, 120, 125, 295, 300, 310, 400, 600 ])}
payload_lengths = [64, 128, 256, 1024]
# Serial ports for devices under test
dut_ports = ['/dev/ttyUSB0', '/dev/ttyUSB1']
duration = '5'
def run_test(dual_test, modulation_name, server_addr, mgmt_addr, user_name):
# Dictionnary keys will be the different payload lengths
goodputs = {}
print 'dual:', dual_test, modulation_name, server_addr, mgmt_addr, user_name
dual_cmd_token = ' -d' if dual_test else ''
dual_filename_token = '_dual' if dual_test else ''
modulation_pib_value = modulations[modulation_name][0];
modulation_bandwidths = modulations[modulation_name][1];
print 'PIB value:', modulation_pib_value
print 'Bandwidths:', modulation_bandwidths
ping6_cmd = 'ping6 -c 1 -s 8 -W 10 ' + server_addr
for port in dut_ports:
# Connect to the Device Under Test and set RF modulation
dut = pexpect.spawn('screen ' + port + ' 115200', timeout=60)
dut.sendline()
dut.expect_exact('# ')
dut.sendline('pib -sn .rf_mac.static_config.pkt_mgr.forceTxModulation -v ' + str(modulation_pib_value))
# dut.sendline('date > /root/foobar')
dut.expect_exact('# ')
dut.sendcontrol('a')
dut.send('k')
dut.send('y')
dut.kill(1)
print 'Set RF modulation to', modulation_name, 'for DUT on serial port', port
for payload_len in payload_lengths:
goodputs[payload_len] = []
tmp_csv_filename = str(payload_len) + '_' + modulation_name + '_' + datetime.now().strftime('%b%d-%H-%M') + dual_filename_token + '.csv'
for bandwidth in modulation_bandwidths:
# Server reachability test loop
print str(datetime.now()), 'Entering server reachability test loop...'
while True:
ret = subprocess.call(ping6_cmd, shell=True, stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w'))
if (ret == 0):
print str(datetime.now()), 'iPerf server is reachable: proceeding with test'
break
iperf_server_cmd = 'iperf -s -u -V'
iperf_client_cmd = 'iperf -b ' + str(bandwidth) + 'K -c ' + server_addr + dual_cmd_token + ' -l ' + str(payload_len) + ' -t ' + duration + ' -u -V'
# print(iperf_server_cmd)
print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
# print(datetime.now())
print str(datetime.now()), iperf_server_cmd
# Start iPerf server
server = pxssh.pxssh()
server.login(mgmt_addr, user_name)
server.sendline()
server.prompt()
server.sendline(iperf_server_cmd)
print str(datetime.now()), "Server started"
# Start iPerf client and wait for it to finish
print str(datetime.now()), iperf_client_cmd
pexpect.run(iperf_client_cmd)
print str(datetime.now()), "Client Finished. Waiting for server to finish..."
# iPerf2 doesn't have the one-off option found in iPerf3 that makes
# the server return after it's done receiving packets. We need to
# wait sufficient time before killing the server process. This
# 'sufficient time' was determined empirically.
time.sleep(20)
# server.sendcontrol('c')
server.sendcontrol('z')
server.sendline()
ret = server.prompt()
if ret == True:
print str(datetime.now()), "Server has finished"
lines = server.before.split('\n')
for line in lines:
print str(datetime.now()), line
m = re.search(r'\s(\d+|\d+\.\d+)\sKbits/sec', line)
if ( m is not None ) and ( len(line.split('/')) > 2 ):
# print m.groups()[0]
goodputs[payload_len].append(float(m.groups()[0]))
break
# if nothing is found, append an empty slot
if m is None:
goodputs[payload_len].append("")
with open(tmp_csv_filename, 'w') as f:
writer = csv.writer(f, quoting=csv.QUOTE_NONE)
writer.writerow(['Input Data Rate (Kbps)', 'Goodput (kbps) for ' + str(payload_len) + 'B packets'])
writer.writerow([None, str(payload_len) + 'B'])
rows = zip(modulation_bandwidths, goodputs[payload_len])
for row in rows:
writer.writerow(row)
print str(datetime.now()), modulation_name, str(payload_len)+"B, " + str(bandwidth) + "K->", goodputs[payload_len]
server.sendline('pkill -KILL iperf')
else:
print "Error while retrieving from server. Killing server process."
server.logout
# Create CSV file for the current modulation
fmt = '%b%d-%H-%M'
now = datetime.now()
csv_filename = modulation_name + '_' + now.strftime(fmt) + dual_filename_token + '.csv'
with open(csv_filename, 'w') as f:
writer = csv.writer(f, quoting=csv.QUOTE_NONE)
writer.writerow(['Input Data Rate (Kbps)', 'Goodput (kbps) for different Packet Sizes', None, None, None])
writer.writerow([None, '64B', '128B', '256B', '1024B'])
rows = zip(modulation_bandwidths, goodputs[64], goodputs[128], goodputs[256], goodputs[1024])
# rows = zip(modulation_bandwidths, goodputs[256], goodputs[1024])
for row in rows:
writer.writerow(row)
for port in dut_ports:
# Connect to the Device Under Test and set RF modulation
dut = pexpect.spawn('screen ' + port + ' 115200', timeout=60)
dut.sendline()
dut.expect_exact('# ')
dut.sendline('pib -sn .mas.status.f0_core.TxTimeTable1hRf -v 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000')
# dut.sendline('date > /root/foobar')
dut.expect_exact('# ')
dut.sendcontrol('a')
dut.send('k')
dut.send('y')
dut.kill(1)
print 'TX time Accumulated on RF is RESET for DUT on serial port', port
if __name__ == "__main__":
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description='''
DESCRIPTION:
This script will perform a series of UDP goodput measurements for a
user-selected RF modulation for combination of varying payload lengths
and target bandwidths. The list of payload lengths and the the one of
target bandwidths are both hardcoded.
The script will interact with the local host, acting as the iPerf
client, and a remote host acting as the server. The remote host is
accessed using SSH. This script will also interact with the two
devices under test using a serial port connection. The list of serial
ports is hardcoded.
The results for the measurements are written to a CSV file created in
the current directory. File name starts with the selected modulation
name in uppercase.
EXAMPLES:
./iperf.py -m ofdm600 -s 3333::1 -t 192.168.2.2 -u kong
./iperf.py -d -m fsk150 -s 3333::1 -t 192.168.2.2 -u kong
DEPENDENCIES:
This script relies on the Pexpect Python module for automating
interaction with the Iperf client and server as well as with the
devices under test.
It also relies on the GNU Screen terminal multiplexer to access the
Linux console of the devices under test.
LIMITATIONS:
Only FSK150 and OFDM600 RF modulations are supported.
'''
)
parser.add_argument('-d', '--dualtest', action='store_true', help='do a bidirectional test simultaneously')
parser.add_argument('-m', '--modulation', required=True, help='RF modulation used in the ACT network; used to form results CSV file name')
parser.add_argument('-s', '--serveraddr', required=True, help='iPerf server IPv6 address')
parser.add_argument('-t', '--mgmtaddr', required=True, help='iPerf server IPv4 address to use for the SSH management connection')
parser.add_argument('-u', '--username', required=True, help='user name for the server management SSH connection')
args = parser.parse_args()
dual_test = args.dualtest
modulation = args.modulation.upper()
server_addr = args.serveraddr
mgmt_addr = args.mgmtaddr
user_name = args.username
# Check that GNU Screen is installed
if pexpect.which('screen') == None:
print "Please install GNU Screen with e.g. 'sudo apt install screen'"
sys.exit(1)
# Check that serial ports are valid and usable
for port in dut_ports:
cmd = "stty -F " + port + ' speed'
p = subprocess.Popen(cmd, shell=True, stderr=open("/dev/null", 'w'), stdout=open("/dev/null", 'w'))
while p.poll() is None:
continue
if (p.returncode != 0):
print port, 'is not a valid serial port or is already in use'
sys.exit(1)
if modulation not in modulations:
print args.modulation, 'is not a supported modulation'
sys.exit(1)
run_test(dual_test, modulation, server_addr, mgmt_addr, user_name)