]> git.ipfire.org Git - thirdparty/hostap.git/blob - tests/remote/rutils.py
70ad82c877d878c9c905b0a3bde0ce4191ea982d
[thirdparty/hostap.git] / tests / remote / rutils.py
1 # Utils
2 # Copyright (c) 2016, Tieto Corporation
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6
7 import re
8 import time
9 from remotehost import Host
10 import hostapd
11 import config
12
13 class TestSkip(Exception):
14 def __init__(self, reason):
15 self.reason = reason
16 def __str__(self):
17 return self.reason
18
19 # get host based on name
20 def get_host(devices, dev_name):
21 dev = config.get_device(devices, dev_name)
22 host = Host(host=dev['hostname'],
23 ifname=dev['ifname'],
24 port=dev['port'],
25 name=dev['name'])
26 host.dev = dev
27 return host
28
29 # Run setup_hw - hardware specific
30 def setup_hw_host_iface(host, iface, setup_params, force_restart=False):
31 try:
32 setup_hw = setup_params['setup_hw']
33 restart = ""
34 try:
35 if setup_params['restart_device'] == True:
36 restart = "-R"
37 except:
38 pass
39
40 if force_restart:
41 restart = "-R"
42
43 host.execute([setup_hw, "-I", iface, restart])
44 except:
45 pass
46
47 def setup_hw_host(host, setup_params, force_restart=False):
48 ifaces = re.split('; | |, ', host.ifname)
49 for iface in ifaces:
50 setup_hw_host_iface(host, iface, setup_params, force_restart)
51
52 def setup_hw(hosts, setup_params, force_restart=False):
53 for host in hosts:
54 setup_hw_host(host, setup_params, force_restart)
55
56 # get traces - hw specific
57 def trace_start(hosts, setup_params):
58 for host in hosts:
59 trace_start_stop(host, setup_params, start=True)
60
61 def trace_stop(hosts, setup_params):
62 for host in hosts:
63 trace_start_stop(host, setup_params, start=False)
64
65 def trace_start_stop(host, setup_params, start):
66 if setup_params['trace'] == False:
67 return
68 try:
69 start_trace = setup_params['trace_start']
70 stop_trace = setup_params['trace_stop']
71 if start:
72 cmd = start_trace
73 else:
74 cmd = stop_trace
75 trace_dir = setup_params['log_dir'] + host.ifname + "/remote_traces"
76 host.add_log(trace_dir + "/*")
77 host.execute([cmd, "-I", host.ifname, "-D", trace_dir])
78 except:
79 pass
80
81 # get perf
82 def perf_start(hosts, setup_params):
83 for host in hosts:
84 perf_start_stop(host, setup_params, start=True)
85
86 def perf_stop(hosts, setup_params):
87 for host in hosts:
88 perf_start_stop(host, setup_params, start=False)
89
90 def perf_start_stop(host, setup_params, start):
91 if setup_params['perf'] == False:
92 return
93 try:
94 perf_start = setup_params['perf_start']
95 perf_stop = setup_params['perf_stop']
96 if start:
97 cmd = perf_start
98 else:
99 cmd = perf_stop
100 perf_dir = setup_params['log_dir'] + host.ifname + "/remote_perf"
101 host.add_log(perf_dir + "/*")
102 host.execute([cmd, "-I", host.ifname, "-D", perf_dir])
103 except:
104 pass
105
106 # hostapd/wpa_supplicant helpers
107 def run_hostapd(host, setup_params):
108 log_file = None
109 try:
110 tc_name = setup_params['tc_name']
111 log_dir = setup_params['log_dir']
112 log_file = log_dir + tc_name + "_hostapd_" + host.name + "_" + host.ifname + ".log"
113 host.execute(["rm", log_file])
114 log = " -f " + log_file
115 except:
116 log = ""
117
118 if log_file:
119 host.add_log(log_file)
120 status, buf = host.execute([setup_params['hostapd'], "-B", "-ddt", "-g", "udp:" + host.port, log])
121 if status != 0:
122 raise Exception("Could not run hostapd: " + buf)
123
124 def run_wpasupplicant(host, setup_params):
125 log_file = None
126 try:
127 tc_name = setup_params['tc_name']
128 log_dir = setup_params['log_dir']
129 log_file = log_dir + tc_name + "_wpa_supplicant_" + host.name + "_" + host.ifname + ".log"
130 host.execute(["rm", log_file])
131 log = " -f " + log_file
132 except:
133 log = ""
134
135 if log_file:
136 host.add_log(log_file)
137 status, buf = host.execute([setup_params['wpa_supplicant'], "-B", "-ddt", "-g", "udp:" + host.port, log])
138 if status != 0:
139 raise Exception("Could not run wpa_supplicant: " + buf)
140
141 def kill_wpasupplicant(host, setup_params):
142 host.execute(['killall', setup_params['wpa_supplicant']])
143
144 def kill_hostapd(host, setup_params):
145 host.execute(['killall', setup_params['hostapd']])
146
147 def get_ap_params(channel="1", bw="HT20", country="US", security="open", ht_capab=None, vht_capab=None):
148 ssid = "test_" + channel + "_" + security + "_" + bw
149
150 if bw == "b_only":
151 params = hostapd.b_only_params(channel, ssid, country)
152 elif bw == "g_only":
153 params = hostapd.g_only_params(channel, ssid, country)
154 elif bw == "g_only_wmm":
155 params = hostapd.g_only_params(channel, ssid, country)
156 params['wmm_enabled'] = "1"
157 elif bw == "a_only":
158 params = hostapd.a_only_params(channel, ssid, country)
159 elif bw == "a_only_wmm":
160 params = hostapd.a_only_params(channel, ssid, country)
161 params['wmm_enabled'] = "1"
162 elif bw == "HT20":
163 params = hostapd.ht20_params(channel, ssid, country)
164 if ht_capab:
165 try:
166 params['ht_capab'] = params['ht_capab'] + ht_capab
167 except:
168 params['ht_capab'] = ht_capab
169 elif bw == "HT40+":
170 params = hostapd.ht40_plus_params(channel, ssid, country)
171 if ht_capab:
172 params['ht_capab'] = params['ht_capab'] + ht_capab
173 elif bw == "HT40-":
174 params = hostapd.ht40_minus_params(channel, ssid, country)
175 if ht_capab:
176 params['ht_capab'] = params['ht_capab'] + ht_capab
177 elif bw == "VHT80":
178 params = hostapd.ht40_plus_params(channel, ssid, country)
179 if ht_capab:
180 params['ht_capab'] = params['ht_capab'] + ht_capab
181 if vht_capab:
182 try:
183 params['vht_capab'] = params['vht_capab'] + vht_capab
184 except:
185 params['vht_capab'] = vht_capab
186 params['ieee80211ac'] = "1"
187 params['vht_oper_chwidth'] = "1"
188 params['vht_oper_centr_freq_seg0_idx'] = str(int(channel) + 6)
189 else:
190 params = {}
191
192 # now setup security params
193 if security == "tkip":
194 sec_params = hostapd.wpa_params(passphrase="testtest")
195 elif security == "ccmp":
196 sec_params = hostapd.wpa2_params(passphrase="testtest")
197 elif security == "mixed":
198 sec_params = hostapd.wpa_mixed_params(passphrase="testtest")
199 elif security == "wep":
200 sec_params = {"wep_key0" : "123456789a",
201 "wep_default_key" : "0",
202 "auth_algs" : "1"}
203 elif security == "wep_shared":
204 sec_params = {"wep_key0" : "123456789a",
205 "wep_default_key" : "0",
206 "auth_algs" : "2"}
207 else:
208 sec_params = {}
209
210 params.update(sec_params)
211
212 return params
213
214 # ip helpers
215 def get_ipv4(client, ifname=None):
216 if ifname is None:
217 ifname = client.ifname
218 status, buf = client.execute(["ifconfig", ifname])
219 lines = buf.splitlines()
220
221 for line in lines:
222 res = line.find("inet addr:")
223 if res != -1:
224 break
225
226 if res != -1:
227 words = line.split()
228 addr = words[1].split(":")
229 return addr[1]
230
231 return "unknown"
232
233 def get_ipv6(client, ifname=None):
234 res = -1
235 if ifname is None:
236 ifname = client.ifname
237 status, buf = client.execute(["ifconfig", ifname])
238 lines = buf.splitlines()
239
240 for line in lines:
241 res = line.find("Scope:Link")
242 if res != -1:
243 break
244
245 if res != -1:
246 words = line.split()
247 if words[0] == "inet6" and words[1] == "addr:":
248 addr_mask = words[2]
249 addr = addr_mask.split("/")
250 return addr[0]
251
252 return "unknown"
253
254 def get_ip(client, addr_type="ipv6", iface=None):
255 if addr_type == "ipv6":
256 return get_ipv6(client, iface)
257 elif addr_type == "ipv4":
258 return get_ipv4(client, iface)
259 else:
260 return "unknown addr_type: " + addr_type
261
262 def get_ipv4_addr(setup_params, number):
263 try:
264 ipv4_base = setup_params['ipv4_test_net']
265 except:
266 ipv4_base = "172.16.12.0"
267
268 parts = ipv4_base.split('.')
269 ipv4 = parts[0] + "." + parts[1] + "." + parts[2] + "." + str(number)
270
271 return ipv4
272
273 def get_mac_addr(host, iface=None):
274 if iface == None:
275 iface = host.ifname
276 status, buf = host.execute(["ifconfig", iface])
277 if status != 0:
278 raise Exception("ifconfig " + iface)
279 words = buf.split()
280 found = 0
281 for word in words:
282 if found == 1:
283 return word
284 if word == "HWaddr":
285 found = 1
286 raise Exception("Could not find HWaddr")
287
288 # connectivity/ping helpers
289 def get_ping_packet_loss(ping_res):
290 loss_line = ""
291 lines = ping_res.splitlines()
292 for line in lines:
293 if line.find("packet loss") != -1:
294 loss_line = line
295 break;
296
297 if loss_line == "":
298 return "100%"
299
300 sections = loss_line.split(",")
301
302 for section in sections:
303 if section.find("packet loss") != -1:
304 words = section.split()
305 return words[0]
306
307 return "100%"
308
309 def ac_to_ping_ac(qos):
310 if qos == "be":
311 qos_param = "0x00"
312 elif qos == "bk":
313 qos_param = "0x20"
314 elif qos == "vi":
315 qos_param = "0xA0"
316 elif qos == "vo":
317 qos_param = "0xE0"
318 else:
319 qos_param = "0x00"
320 return qos_param
321
322 def ping_run(host, ip, result, ifname=None, addr_type="ipv4", deadline="5", qos=None):
323 if ifname is None:
324 ifname = host.ifname
325 if addr_type == "ipv6":
326 ping = ["ping6"]
327 else:
328 ping = ["ping"]
329
330 ping = ping + ["-w", deadline, "-I", ifname]
331 if qos:
332 ping = ping + ["-Q", ac_to_ping_ac(qos)]
333 ping = ping + [ip]
334
335 flush_arp_cache(host)
336
337 thread = host.execute_run(ping, result)
338 return thread
339
340 def ping_wait(host, thread, timeout=None):
341 host.wait_execute_complete(thread, timeout)
342 if thread.isAlive():
343 raise Exception("ping thread still alive")
344
345 def flush_arp_cache(host):
346 host.execute(["ip", "-s", "-s", "neigh", "flush", "all"])
347
348 def check_connectivity(a, b, addr_type="ipv4", deadline="5", qos=None):
349 addr_a = get_ip(a, addr_type)
350 addr_b = get_ip(b, addr_type)
351
352 if addr_type == "ipv4":
353 ping = ["ping"]
354 else:
355 ping = ["ping6"]
356
357 ping_a_b = ping + ["-w", deadline, "-I", a.ifname]
358 ping_b_a = ping + ["-w", deadline, "-I", b.ifname]
359 if qos:
360 ping_a_b = ping_a_b + ["-Q", ac_to_ping_ac(qos)]
361 ping_b_a = ping_b_a + ["-Q", ac_to_ping_ac(qos)]
362 ping_a_b = ping_a_b + [addr_b]
363 ping_b_a = ping_b_a + [addr_a]
364
365 # Clear arp cache
366 flush_arp_cache(a)
367 flush_arp_cache(b)
368
369 status, buf = a.execute(ping_a_b)
370 if status == 2 and ping == "ping6":
371 # tentative possible for a while, try again
372 time.sleep(3)
373 status, buf = a.execute(ping_a_b)
374 if status != 0:
375 raise Exception("ping " + a.name + "/" + a.ifname + " >> " + b.name + "/" + b.ifname)
376
377 a_b = get_ping_packet_loss(buf)
378
379 # Clear arp cache
380 flush_arp_cache(a)
381 flush_arp_cache(b)
382
383 status, buf = b.execute(ping_b_a)
384 if status != 0:
385 raise Exception("ping " + b.name + "/" + b.ifname + " >> " + a.name + "/" + a.ifname)
386
387 b_a = get_ping_packet_loss(buf)
388
389 if int(a_b[:-1]) > 40:
390 raise Exception("Too high packet lost: " + a_b)
391
392 if int(b_a[:-1]) > 40:
393 raise Exception("Too high packet lost: " + b_a)
394
395 return a_b, b_a
396
397
398 # iperf helpers
399 def get_iperf_speed(iperf_res, pattern="Mbits/sec"):
400 lines = iperf_res.splitlines()
401 sum_line = ""
402 last_line = ""
403 count = 0
404 res = -1
405
406 # first find last SUM line
407 for line in lines:
408 res = line.find("[SUM]")
409 if res != -1:
410 sum_line = line
411
412 # next check SUM status
413 if sum_line != "":
414 words = sum_line.split()
415 for word in words:
416 res = word.find(pattern)
417 if res != -1:
418 return words[count - 1] + " " + pattern
419 count = count + 1
420
421 # no SUM - one thread - find last line
422 for line in lines:
423 res = line.find(pattern)
424 if res != -1:
425 last_line = line
426
427 if last_line == "":
428 return "0 " + pattern
429
430 count = 0
431 words = last_line.split()
432 for word in words:
433 res = word.find(pattern)
434 if res != -1:
435 return words[count - 1] + " " + pattern
436 break;
437 count = count + 1
438 return "0 " + pattern
439
440 def ac_to_iperf_ac(qos):
441 if qos == "be":
442 qos_param = "0x00"
443 elif qos == "bk":
444 qos_param = "0x20"
445 elif qos == "vi":
446 qos_param = "0xA0"
447 elif qos == "vo":
448 qos_param = "0xE0"
449 else:
450 qos_param = "0x00"
451 return qos_param
452
453 def iperf_run(server, client, server_ip, client_res, server_res,
454 l4="udp", bw="30M", test_time="30", parallel="5",
455 qos="be", param=" -i 5 ", ifname=None, l3="ipv4",
456 port="5001", iperf="iperf"):
457 if ifname == None:
458 ifname = client.ifname
459
460 if iperf == "iperf":
461 iperf_server = [iperf]
462 elif iperf == "iperf3":
463 iperf_server = [iperf, "-1"]
464
465 if l3 == "ipv4":
466 iperf_client = [iperf, "-c", server_ip, "-p", port]
467 iperf_server = iperf_server + ["-p", port]
468 elif l3 == "ipv6":
469 iperf_client = [iperf, "-V", "-c", server_ip + "%" + ifname, "-p", port]
470 iperf_server = iperf_server + ["-V", "-p", port]
471 else:
472 return -1, -1
473
474 iperf_server = iperf_server + ["-s", "-f", "m", param]
475 iperf_client = iperf_client + ["-f", "m", "-t", test_time]
476
477 if parallel != "1":
478 iperf_client = iperf_client + ["-P", parallel]
479
480 if l4 == "udp":
481 if iperf != "iperf3":
482 iperf_server = iperf_server + ["-u"]
483 iperf_client = iperf_client + ["-u", "-b", bw]
484
485 if qos:
486 iperf_client = iperf_client + ["-Q", ac_to_iperf_ac(qos)]
487
488 flush_arp_cache(server)
489 flush_arp_cache(client)
490
491 server_thread = server.execute_run(iperf_server, server_res)
492 time.sleep(1)
493 client_thread = client.execute_run(iperf_client, client_res)
494
495 return server_thread, client_thread
496
497 def iperf_wait(server, client, server_thread, client_thread, timeout=None, iperf="iperf"):
498 client.wait_execute_complete(client_thread, timeout)
499 if client_thread.isAlive():
500 raise Exception("iperf client thread still alive")
501
502 server.wait_execute_complete(server_thread, 5)
503 if server_thread.isAlive():
504 server.execute(["killall", "-s", "INT", iperf])
505 time.sleep(1)
506
507 server.wait_execute_complete(server_thread, 5)
508 if server_thread.isAlive():
509 raise Exception("iperf server thread still alive")
510
511 return
512
513 def run_tp_test(server, client, l3="ipv4", iperf="iperf", l4="tcp", test_time="10", parallel="5",
514 qos="be", bw="30M", ifname=None, port="5001"):
515 client_res = []
516 server_res = []
517
518 server_ip = get_ip(server, l3)
519 time.sleep(1)
520 server_thread, client_thread = iperf_run(server, client, server_ip, client_res, server_res,
521 l3=l3, iperf=iperf, l4=l4, test_time=test_time,
522 parallel=parallel, qos=qos, bw=bw, ifname=ifname,
523 port=port)
524 iperf_wait(server, client, server_thread, client_thread, iperf=iperf, timeout=int(test_time) + 10)
525
526 if client_res[0] != 0:
527 raise Exception(iperf + " client: " + client_res[1])
528 if server_res[0] != 0:
529 raise Exception(iperf + " server: " + server_res[1])
530 if client_res[1] is None:
531 raise Exception(iperf + " client result issue")
532 if server_res[1] is None:
533 raise Exception(iperf + " server result issue")
534
535 if iperf == "iperf":
536 result = server_res[1]
537 if iperf == "iperf3":
538 result = client_res[1]
539
540 speed = get_iperf_speed(result)
541 return speed
542
543 def get_iperf_bw(bw, parallel, spacial_streams=2):
544 if bw == "b_only":
545 max_tp = 11
546 elif bw == "g_only" or bw == "g_only_wmm" or bw == "a_only" or bw == "a_only_wmm":
547 max_tp = 54
548 elif bw == "HT20":
549 max_tp = 72 * spacial_streams
550 elif bw == "HT40+" or bw == "HT40-":
551 max_tp = 150 * spacial_streams
552 elif bw == "VHT80":
553 max_tp = 433 * spacial_streams
554 else:
555 max_tp = 150
556
557 max_tp = 1.2 * max_tp
558
559 return str(int(max_tp/int(parallel))) + "M"