From patchwork Wed Mar 30 20:29:36 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janusz.Dziedzic@tieto.com X-Patchwork-Id: 603638 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qZzyC2m3pz9s6r for ; Thu, 31 Mar 2016 07:38:59 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=tieto.com header.i=@tieto.com header.b=V4JbY8AI; dkim-atps=neutral Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1alMt5-0000Ge-SE; Wed, 30 Mar 2016 20:38:47 +0000 Received: from mail-lf0-x22d.google.com ([2a00:1450:4010:c07::22d]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1alMkx-0006PL-KO for hostap@lists.infradead.org; Wed, 30 Mar 2016 20:31:00 +0000 Received: by mail-lf0-x22d.google.com with SMTP id k79so44721939lfb.2 for ; Wed, 30 Mar 2016 13:30:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tieto.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ewlBmX86t/ALsYFBvVI4/X8rq4g9jqi+hV85fCTyIAc=; b=V4JbY8AIexq8jY9+8lHR6MmR24S+XLG53+tGCy+PEfQCfDmHu9bhzuHUQuftFyinNC /WhLdns7CTB8H1+xo+pMGlxr96iCo29mG1dUh+0adh2hinqsv/8XMCVTJfH3KMVX8qq5 SHzc9GdlgGrR08n+2RPmDTNw3vQTdJnrZ5+q4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ewlBmX86t/ALsYFBvVI4/X8rq4g9jqi+hV85fCTyIAc=; b=iwdOD5YzlzP2T14B7NMYNBrkTPPBvopGqiRmDnSIDaHRxjno9rk+ZfSLFII5Yf1lLX 7Ig+F1cawnbroKVOfIViPJuUN9+/mWQnLDcMAYjRbMYdp0ZXpNA+4tqBPSiXYPMg5xHC zHPgEbmCxrCBhP7LyMSHt1jIZ3ymK5y30KGig3rfeO0Yt7rZL4YMVhxdhKDm3+JrxDr1 pryULSPvGik3cnZ+ua8MuIsdBBI0gmBh474apeXYAjow1Xs0poJZ2AHl1N7rXIZ9Z0aL LLaM+iBHdcM4otvb58FV8q5TwbkRQc/8VldTRdCegn6zjxaJiTS+jtWLOgZfRivwR128 7DLA== X-Gm-Message-State: AD7BkJIqE2s/o9eOICS77MDmUdpym4BbaygEUTc6eS0a62A3RscIL7C9NhhTRyH+XGAHAFnFIRRz6GqxhYZ92/6zWHwL5KDVp8RaaLUxRBKrlqyPTPA3GXgXWfpr9BNYM+/bps8kCMit1TzmCvea7OZPpGH3BLttDt+YoUv2uUxJilibIOGwpixO8sOx8h7OJ1P6 X-Received: by 10.25.85.145 with SMTP id j139mr4943543lfb.131.1459369801602; Wed, 30 Mar 2016 13:30:01 -0700 (PDT) Received: from localhost.localdomain (host-62-141-193-85.swidnica.mm.pl. [62.141.193.85]) by smtp.gmail.com with ESMTPSA id z123sm863071lfd.15.2016.03.30.13.30.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 30 Mar 2016 13:30:01 -0700 (PDT) From: Janusz Dziedzic To: hostap@lists.infradead.org Subject: [PATCH 3/5] tests/remote: add utils file Date: Wed, 30 Mar 2016 22:29:36 +0200 Message-Id: <1459369778-19522-4-git-send-email-janusz.dziedzic@tieto.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1459369778-19522-1-git-send-email-janusz.dziedzic@tieto.com> References: <1459369778-19522-1-git-send-email-janusz.dziedzic@tieto.com> X-DomainID: tieto.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160330_133024_715781_CF2D0007 X-CRM114-Status: GOOD ( 14.37 ) X-Spam-Score: -2.7 (--) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-2.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [2a00:1450:4010:c07:0:0:0:22d listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: j@w1.fi, Janusz Dziedzic MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Add rutils.py for remote tests. Signed-off-by: Janusz Dziedzic --- tests/hwsim/remotehost.py | 1 + tests/remote/run-tests.py | 4 + tests/remote/rutils.py | 524 +++++++++++++++++++++++++++++++++++++++++++ tests/remote/test_devices.py | 10 +- 4 files changed, 532 insertions(+), 7 deletions(-) create mode 100644 tests/remote/rutils.py diff --git a/tests/hwsim/remotehost.py b/tests/hwsim/remotehost.py index f5e88ae..6796e25 100644 --- a/tests/hwsim/remotehost.py +++ b/tests/hwsim/remotehost.py @@ -37,6 +37,7 @@ class Host(): self.logs = [] self.ifname = ifname self.port = port + self.dev = None if self.name == "" and host != None: self.name = host diff --git a/tests/remote/run-tests.py b/tests/remote/run-tests.py index 33ac8e6..c3cb16a 100755 --- a/tests/remote/run-tests.py +++ b/tests/remote/run-tests.py @@ -24,6 +24,7 @@ import wpaspy import config from test_devices import show_devices from test_devices import check_devices +from rutils import TestSkip def usage(): print "USAGE: " + sys.argv[0] + " -t devices" @@ -261,6 +262,9 @@ def main(): except KeyboardInterrupt: put_devices(devices, duts, refs, monitors) raise + except TestSkip, e: + end = datetime.now() + logger.warning("SKIP (" + str(e) + ") - " + str((end - start).total_seconds()) + "s") except Exception, e: end = datetime.now() logger.warning("FAILED (" + str(e) + ") - " + str((end - start).total_seconds()) + "s") diff --git a/tests/remote/rutils.py b/tests/remote/rutils.py new file mode 100644 index 0000000..e321fee --- /dev/null +++ b/tests/remote/rutils.py @@ -0,0 +1,524 @@ +# +# Utils +# Copyright (c) 2016, Tieto Corporation +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. +import time +from remotehost import Host +import hostapd +import config + +class TestSkip(Exception): + def __init__(self, reason): + self.reason = reason + def __str__(self): + return self.reason + +# get host based on name +def get_host(devices, dev_name): + dev = config.get_device(devices, dev_name) + host = Host(host = dev['hostname'], + ifname = dev['ifname'], + port = dev['port'], + name = dev['name']) + host.dev = dev + return host + +# run setup_hw - hw specyfic +def setup_hw(hosts, setup_params): + for host in hosts: + setup_hw_host(host, setup_params) + +def setup_hw_host(host, setup_params): + try: + setup_hw = setup_params['setup_hw'] + restart = "" + try: + if setup_params['restart_device'] == True: + restart = " -R " + except: + pass + host.execute(setup_hw + " -I " + host.ifname + restart) + except: + pass + +# get traces - hw specyfic +def trace_start(hosts, setup_params): + for host in hosts: + trace_start_stop(host, setup_params, start=True) + +def trace_stop(hosts, setup_params): + for host in hosts: + trace_start_stop(host, setup_params, start=False) + +def trace_start_stop(host, setup_params, start): + if setup_params['trace'] == False: + return + try: + start_trace = setup_params['trace_start'] + stop_trace = setup_params['trace_stop'] + if start: + cmd = start_trace + else: + cmd = stop_trace + trace_dir = setup_params['log_dir'] + host.ifname + "/remote_traces" + cmd = cmd + " -I " + host.ifname + " -D " + trace_dir + host.logs.append(trace_dir + "/*") + host.execute(cmd) + except: + pass + +# get perf +def perf_start(hosts, setup_params): + for host in hosts: + perf_start_stop(host, setup_params, start=True) + +def perf_stop(hosts, setup_params): + for host in hosts: + perf_start_stop(host, setup_params, start=False) + +def perf_start_stop(host, setup_params, start): + if setup_params['perf'] == False: + return + try: + perf_start = setup_params['perf_start'] + perf_stop = setup_params['perf_stop'] + if start: + cmd = perf_start + else: + cmd = perf_stop + perf_dir = setup_params['log_dir'] + host.ifname + "/remote_perf" + cmd = cmd + " -I " + host.ifname + " -D " + perf_dir + host.logs.append(perf_dir + "/*") + host.execute(cmd) + except: + pass + +# hostapd/wpa_supplicant helpers +def run_hostapd(host, setup_params): + log_file = None + try: + tc_name = setup_params['tc_name'] + log_dir = setup_params['log_dir'] + log_file = log_dir + tc_name + "_hostapd_" + host.name + "_" + host.ifname + ".log" + host.execute("rm " + log_file) + log = " -f " + log_file + except: + log = "" + + if log_file: + host.logs.append(log_file) + status, buf = host.execute(setup_params['hostapd'] + " -B -ddt -g udp:" + host.port + log) + if status != 0: + raise Exception("Could not run hostapd: " + buf) + +def run_wpasupplicant(host, setup_params): + log_file = None + try: + tc_name = setup_params['tc_name'] + log_dir = setup_params['log_dir'] + log_file = log_dir + tc_name + "_wpa_supplicant_" + host.name + "_" + host.ifname + ".log" + host.execute("rm " + log_file) + log = " -f " + log_file + except: + log = "" + + if log_file: + host.logs.append(log_file) + status, buf = host.execute(setup_params['wpa_supplicant'] + " -B -ddt -g udp:" + host.port + log) + if status != 0: + raise Exception("Could not run wpa_supplicant: " + buf) + +def get_ap_params(channel="1", bw="HT20", country="US", security="open", ht_capab=None, vht_capab=None): + ssid = "test_" + channel + "_" + security + "_" + bw + + if bw == "b_only": + params = hostapd.b_only_params(channel, ssid, country) + elif bw == "g_only": + params = hostapd.g_only_params(channel, ssid, country) + elif bw == "g_only_wmm": + params = hostapd.g_only_params(channel, ssid, country) + params['wmm_enabled'] = "1" + elif bw == "a_only": + params = hostapd.a_only_params(channel, ssid, country) + elif bw == "a_only_wmm": + params = hostapd.a_only_params(channel, ssid, country) + params['wmm_enabled'] = "1" + elif bw == "HT20": + params = hostapd.ht20_params(channel, ssid, country) + if ht_capab: + try: + params['ht_capab'] = params['ht_capab'] + ht_capab + except: + params['ht_capab'] = ht_capab + elif bw == "HT40+": + params = hostapd.ht40_plus_params(channel, ssid, country) + if ht_capab: + params['ht_capab'] = params['ht_capab'] + ht_capab + elif bw == "HT40-": + params = hostapd.ht40_minus_params(channel, ssid, country) + if ht_capab: + params['ht_capab'] = params['ht_capab'] + ht_capab + elif bw == "VHT80": + params = hostapd.ht40_plus_params(channel, ssid, country) + if ht_capab: + params['ht_capab'] = params['ht_capab'] + ht_capab + if vht_capab: + try: + params['vht_capab'] = params['vht_capab'] + vht_capab + except: + params['vht_capab'] = vht_capab + params['ieee80211ac'] = "1" + params['vht_oper_chwidth'] = "1" + params['vht_oper_centr_freq_seg0_idx'] = str(int(channel) + 6) + else: + params = {} + + # now setup security params + if security == "tkip": + sec_params = hostapd.wpa_params(passphrase="testtest") + elif security == "ccmp": + sec_params = hostapd.wpa2_params(passphrase="testtest") + elif security == "mixed": + sec_params = hostapd.wpa_mixed_params(passphrase="testtest") + elif security == "wep": + sec_params = { "wep_key0" : "123456789a", + "wep_default_key" : "0", + "auth_algs" : "1"} + elif security == "wep_shared": + sec_params = { "wep_key0" : "123456789a", + "wep_default_key" : "0", + "auth_algs" : "2" } + else: + sec_params = {} + + params.update(sec_params) + + return params + +# ip helpers +def get_ipv4(client, ifname=None): + if ifname is None: + ifname = client.ifname + status, buf = client.execute("ifconfig " + ifname) + lines = buf.splitlines() + + for line in lines: + res = line.find("inet addr:") + if res != -1: + break + + if res != -1: + words = line.split() + addr = words[1].split(":") + return addr[1] + + return "unknown" + +def get_ipv6(client, ifname=None): + res = -1 + if ifname is None: + ifname = client.ifname + status, buf = client.execute("ifconfig " + ifname) + lines = buf.splitlines() + + for line in lines: + res = line.find("Scope:Link") + if res != -1: + break + + if res != -1: + words = line.split() + if words[0] == "inet6" and words[1] == "addr:": + addr_mask = words[2] + addr = addr_mask.split("/") + return addr[0] + + return "unknown" + +def get_ip(client, addr_type="ipv6", iface=None): + if addr_type == "ipv6": + return get_ipv6(client, iface) + elif addr_type == "ipv4": + return get_ipv4(client, iface) + else: + return "unknown addr_type: " + addr_type + +def get_ipv4_addr(setup_params, number): + try: + ipv4_base = setup_params['ipv4_test_net'] + except: + ipv4_base = "172.16.12.0" + + parts = ipv4_base.split('.') + ipv4 = parts[0] + "." + parts[1] + "." + parts[2] + "." + str(number) + + return ipv4 + + +# connectivity/ping helpers +def get_ping_packet_loss(ping_res): + loss_line = "" + lines = ping_res.splitlines() + for line in lines: + if line.find("packet loss") != -1: + loss_line = line + break; + + if loss_line == "": + return "100%" + + sections = loss_line.split(",") + + for section in sections: + if section.find("packet loss") != -1: + words = section.split() + return words[0] + + return "100%" + +def ac_to_ping_ac(qos): + if qos == "be": + qos_param = "-Q 0x00" + elif qos == "bk": + qos_param = "-Q 0x20" + elif qos == "vi": + qos_param = "-Q 0xA0" + elif qos == "vo": + qos_param = "-Q 0xE0" + else: + qos_param = "-Q 0x00" + return qos_param + +def ping_run(host, ip, result, ifname=None, addr_type="ipv4", deadline="5", qos=None): + ping = "ping" + if ifname is None: + ifname = host.ifname + if addr_type == "ipv6": + ping = "ping6" + if qos: + qos = " " + ac_to_ping_ac(qos) + " " + else: + qos = "" + ping = ping + " -w " + deadline + " -I " + ifname + qos + " " + ip + + host.execute("ip -s -s neigh flush all") + + thread = host.execute_run(ping, result) + return thread + +def ping_wait(host, thread, timeout=None): + host.wait_execute_complete(thread, timeout) + if thread.isAlive(): + raise Exception("ping thread still alive") + +def check_connectivity(a, b, addr_type = "ipv4", deadline="5", qos=None): + addr_a = get_ip(a, addr_type) + addr_b = get_ip(b, addr_type) + + if addr_type == "ipv4": + ping = "ping" + else: + ping = "ping6" + + if qos: + qos = " " + ac_to_ping_ac(qos) + " " + else: + qos = "" + + # Clear arp cache + a.execute("ip -s -s neigh flush all") + b.execute("ip -s -s neigh flush all") + + status, buf = a.execute(ping + " -w " + deadline + qos + " -I " + a.ifname + " " + addr_b) + if status == 2 and ping == "ping6": + # tentative possible for a while, try again + time.sleep(3) + status, buf = a.execute(ping + " -w " + deadline + qos + " -I " + a.ifname + " " + addr_b) + if status != 0: + raise Exception("ping " + a.name + "/" + a.ifname + " >> " + b.name + "/" + b.ifname) + + a_b = get_ping_packet_loss(buf) + + # Clear arp cache + a.execute("ip -s -s neigh flush all") + b.execute("ip -s -s neigh flush all") + + status, buf = b.execute(ping + " -w " + deadline + qos + " -I " + b.ifname + " " + addr_a) + if status != 0: + raise Exception("ping " + b.name + "/" + b.ifname + " >> " + a.name + "/" + a.ifname) + + b_a = get_ping_packet_loss(buf) + + if int(a_b[:-1]) > 40: + raise Exception("Too high packet lost: " + a_b) + + if int(b_a[:-1]) > 40: + raise Exception("Too high packet lost: " + b_a) + + return a_b, b_a + + +# iperf helpers +def get_iperf_speed(iperf_res, pattern="Mbits/sec"): + lines = iperf_res.splitlines() + sum_line = "" + last_line = "" + count = 0 + res = -1 + + # first find last SUM line + for line in lines: + res = line.find("[SUM]") + if res != -1: + sum_line = line + + # next check SUM status + if sum_line != "": + words = sum_line.split() + for word in words: + res = word.find(pattern) + if res != -1: + return words[count - 1] + " " + pattern + count = count + 1 + + # no SUM - one thread - find last line + for line in lines: + res = line.find(pattern) + if res != -1: + last_line = line + + if last_line == "": + return "0 " + pattern + + count = 0 + words = last_line.split() + for word in words: + res = word.find(pattern) + if res != -1: + return words[count - 1] + " " + pattern + break; + count = count + 1 + return "0 " + pattern + +def ac_to_iperf_ac(qos): + if qos == "be": + qos_param = "-S 0x00" + elif qos == "bk": + qos_param = "-S 0x20" + elif qos == "vi": + qos_param = "-S 0xA0" + elif qos == "vo": + qos_param = "-S 0xE0" + else: + qos_param = "-S 0x00" + return qos_param + +def iperf_run(server, client, server_ip, client_res, server_res, + l4="udp", bw="30M", test_time="30", parallel="5", + qos="be", param=" -i 5 ", ifname=None, l3="ipv4", + port="5001", iperf="iperf"): + if ifname == None: + ifname = client.ifname + + if iperf == "iperf": + iperf_server = iperf + elif iperf == "iperf3": + iperf_server = iperf + " -1" + + if l3 == "ipv4": + iperf_client = iperf + " -c " + server_ip + " -p " + port + iperf_server = iperf_server + " -p " + port + elif l3 == "ipv6": + iperf_client = iperf + " -V -c " + server_ip + "%" + ifname + " -p " + port + iperf_server = iperf_server + " -V -p " + port + else: + return -1, -1 + + iperf_server = iperf_server + " -s -f m " + param + iperf_client = iperf_client + " -f m -t " + test_time + + if parallel != "1": + iperf_client = iperf_client + " -P" + parallel + + if l4 == "udp": + if iperf != "iperf3": + iperf_server = iperf_server + " -u" + iperf_client = iperf_client + " -u -b " + bw + + qos_param = ac_to_iperf_ac(qos) + iperf_client = iperf_client + " " + qos_param + + server.execute("ip -s -s neigh flush all") + client.execute("ip -s -s neigh flush all") + + server_thread = server.execute_run(iperf_server, server_res) + time.sleep(1) + client_thread = client.execute_run(iperf_client, client_res) + + return server_thread, client_thread + +def iperf_wait(server, client, server_thread, client_thread, timeout=None, iperf="iperf"): + client.wait_execute_complete(client_thread, timeout) + if client_thread.isAlive(): + raise Exception("iperf client thread still alive") + + server.wait_execute_complete(server_thread, 5) + if server_thread.isAlive(): + server.execute("killall -s INT " + iperf) + time.sleep(1) + + server.wait_execute_complete(server_thread, 5) + if server_thread.isAlive(): + raise Execption("iperf server thread still alive") + + return + +def run_tp_test(server, client, l3="ipv4", iperf="iperf", l4="tcp", test_time="10", parallel="5", + qos="be", bw="30M", ifname=None, port="5001"): + client_res = [] + server_res = [] + + server_ip = get_ip(server, l3) + time.sleep(1) + server_thread, client_thread = iperf_run(server, client, server_ip, client_res, server_res, + l3=l3, iperf=iperf, l4=l4, test_time=test_time, + parallel=parallel, qos=qos, bw=bw, ifname=ifname, + port=port) + iperf_wait(server, client, server_thread, client_thread, iperf=iperf, timeout=int(test_time) + 10) + + if client_res[0] != 0: + raise Exception(iperf + " client: " + client_res[1]) + if server_res[0] != 0: + raise Exception(iperf + " server: " + server_res[1]) + if client_res[1] is None: + raise Exception(iperf + " client result issue") + if server_res[1] is None: + raise Exception(iperf + " server result issue") + + if iperf == "iperf": + result = server_res[1] + if iperf == "iperf3": + result = client_res[1] + + speed = get_iperf_speed(result) + return speed + +def get_iperf_bw(bw, parallel, spacial_streams=2): + if bw == "b_only": + max_tp = 11 + elif bw == "g_only" or bw == "g_only_wmm" or bw == "a_only" or bw == "a_only_wmm": + max_tp = 54 + elif bw == "HT20": + max_tp = 72 * spacial_streams + elif bw == "HT40+" or bw == "HT40-": + max_tp = 150 * spacial_streams + elif bw == "VHT80": + max_tp = 433 * spacial_streams + else: + max_tp = 150 + + max_tp = 1.2 * max_tp + + return str(int(max_tp/int(parallel))) + "M" diff --git a/tests/remote/test_devices.py b/tests/remote/test_devices.py index 4a22d42..412c2ad 100644 --- a/tests/remote/test_devices.py +++ b/tests/remote/test_devices.py @@ -16,7 +16,7 @@ import re import logging logger = logging.getLogger() -import utils +import rutils from remotehost import Host from wpasupplicant import WpaSupplicant import hostapd @@ -25,9 +25,7 @@ def show_devices(devices, setup_params): """Show/check available devices""" print "Devices:" for device in devices: - dev = config.get_device(devices, device['name']) - host = Host(host = dev['hostname'], ifname = dev['ifname'], - port = dev['port'], name = dev['name']) + host = rutils.get_host(devices, device['name']) # simple check if authorized_keys works correctly status, buf = host.execute("id") if status != 0: @@ -83,9 +81,7 @@ def show_devices(devices, setup_params): print "" def check_device(devices, setup_params, dev_name, monitor=False): - dev = config.get_device(devices, dev_name) - host = Host(host = dev['hostname'], ifname = dev['ifname'], - port = dev['port'], name = dev['name']) + host = rutils.get_host(devices, dev_name) # simple check if authorized_keys works correctly status, buf = host.execute("id") if status != 0: