rutils.py 16 KB

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