diff -Naur rpm/hwcompatible/compatibility.py oech/hwcompatible/compatibility.py --- rpm/hwcompatible/compatibility.py 2023-02-28 17:56:07.000000000 +0800 +++ oech/hwcompatible/compatibility.py 2023-06-13 23:26:19.339482340 +0800 @@ -518,6 +518,17 @@ self.test_factory.append(test) self.logger.info("add %s test %s" % (test["name"], test["device"].get_name())) + for index, test in enumerate(self.test_factory): + for test_new in test_factory: + if test["name"] != test_new["name"]: + continue + self_test_path = test["device"].path + new_test_path = test_new["device"].path + if not self_test_path and not new_test_path: + continue + if self_test_path == new_test_path: + self.test_factory[index]['device'] = test_new['device'] + self.test_factory.sort(key=lambda k: k["name"]) FactoryDocument(CertEnv.factoryfile, self.logger, self.test_factory).save() diff -Naur rpm/oec-hardware.spec oech/oec-hardware.spec --- rpm/oec-hardware.spec 2023-02-28 17:59:44.000000000 +0800 +++ oech/oec-hardware.spec 2023-06-13 23:26:19.339482340 +0800 @@ -25,7 +25,7 @@ Summary: openEuler Hardware Compatibility Test Server Group: Development/Tools Requires: python3, python3-devel, python3-flask, python3-uWSGI -Requires: nginx, tar, qperf, psmisc +Requires: nginx, tar, qperf, psmisc, dpdk, dpdk-tools, dpdk-devel %description openEuler Hardware Compatibility Test Suite @@ -75,7 +75,7 @@ rm -rf /var/lock/oech.lock %changelog -* Mon Feb 28 2023 cuixucui - 1.1.4-0 +* Tue Feb 28 2023 cuixucui - 1.1.4-0 1. Add board information in the test report 2. Add spdk test case 3. Add dpdk test case diff -Naur rpm/server/server.py oech/server/server.py --- rpm/server/server.py 2023-02-28 17:56:07.000000000 +0800 +++ oech/server/server.py 2023-06-13 23:26:19.343482340 +0800 @@ -25,6 +25,7 @@ from urllib.request import urlopen, Request from urllib.error import HTTPError from flask import Flask, render_template, redirect, url_for, abort, request, send_from_directory, flash +from werkzeug import secure_filename app = Flask(__name__) app.secret_key = os.urandom(24) @@ -32,6 +33,7 @@ dir_server = os.path.dirname(os.path.realpath(__file__)) dir_results = os.path.join(dir_server, 'results') dir_files = os.path.join(dir_server, 'files') +DPDK_DRIVER = "uio_pci_generic" @app.errorhandler(400) @@ -98,9 +100,9 @@ abort(404) try: - with open(json_info, 'r') as file_content: + with open(secure_filename(json_info), 'r') as file_content: info = json.load(file_content) - with open(json_results, 'r') as file_content: + with open(secure_filename(json_results), 'r') as file_content: results = json.load(file_content) except json.decoder.JSONDecodeError as error: sys.stderr.write("The file %s is not json file.\n") @@ -125,7 +127,7 @@ abort(404) try: - with open(json_results, 'r') as file_content: + with open(secure_filename(json_results), 'r') as file_content: results = json.load(file_content) except json.decoder.JSONDecodeError as error: sys.stderr.write("The file %s is not json file.\n") @@ -154,7 +156,7 @@ abort(404) try: - with open(json_devices, 'r') as file_content: + with open(secure_filename(json_devices), 'r') as file_content: devices = json.load(file_content) except json.decoder.JSONDecodeError as error: sys.stderr.write("The file %s is not json file.\n") @@ -194,7 +196,7 @@ if not os.path.exists(logpath): logpath = os.path.join(dir_job, 'job.log') - with open(logpath, 'r') as file_content: + with open(secure_filename(logpath), 'r') as file_content: log = file_content.read().split('\n') return render_template('log.html', host=host, id=oec_id, job=job, name=name, log=log) @@ -217,14 +219,14 @@ cert = "" try: - with open(json_cert, 'r') as file_content: + with open(secure_filename(json_cert), 'r') as file_content: cert = json.load(file_content) except json.decoder.JSONDecodeError: sys.stderr.write("The file %s is not json file.\n") return False attachment = "" - with open(tar_job, 'rb') as file_content: + with open(secure_filename(tar_job), 'rb') as file_content: attachment = base64.b64encode(file_content.read()) form = {} @@ -279,7 +281,7 @@ os.makedirs(dir_job) tar_job = dir_job + '.tar' - with open(tar_job, 'wb') as file_content: + with open(secure_filename(tar_job), 'wb') as file_content: file_content.write(ori_file) result = subprocess.getstatusoutput( "tar xf '%s' -C '%s'" % (tar_job, os.path.dirname(dir_job))) @@ -322,7 +324,7 @@ if not os.path.exists(dir_files): os.makedirs(dir_files) - with open(filepath, 'wb') as file_content: + with open(secure_filename(filepath), 'wb') as file_content: file_content.write(base64.b64decode(filetext)) return render_template('upload.html', filename=filename, filetext=filetext, @@ -356,31 +358,36 @@ return render_template('index.html') +@app.route('/api/get/ethpeer', methods=['GET', 'POST']) +def get_ethpeer(): + """ + get ethpeer + """ + dic = {} + card_id = request.values.get('cardid', '') + __setting_dpdk_env() + interface = __get_server_port(card_id) + ethpeer = subprocess.getoutput("ip link show dev %s | grep 'link/ether' | awk '{print $2}'" % interface) + dic = {'ethpeer': ethpeer} + + return dic + + @app.route('/api/bind/server', methods=['GET', 'POST']) def bind_server_card(): """ Bind server card """ - __setting_dpdk_env() + interface = "" card_id = request.values.get('cardid', '') - dpdk_driver = "uio_pci_generic" - ports = [] - dic = {} - ports = subprocess.getoutput("ip link show up | grep 'state UP' | awk -F ': ' '{print $2}'").split('\n') - for pt in ports: - pci_num = subprocess.getoutput("ethtool -i %s | grep 'bus-info' | awk '{print $2}'" % pt) - quad = __get_quad(pci_num) - if operator.eq(quad, eval(card_id)): - ethpeer = subprocess.getoutput("cat /sys/class/net/%s/address" % pt) - subprocess.getoutput("ip link set down %s" % pt) - dic = {'ethpeer': ethpeer} - cmd = subprocess.getstatusoutput("dpdk-devbind.py -b %s %s" % (dpdk_driver, pci_num)) - if cmd[0] != 0: - sys.stderr.write("Bind server card failed.\n") - return False - break + interface = __get_server_port(card_id) + pci_num = subprocess.getoutput("ethtool -i %s | grep 'bus-info' | awk '{print $2}'" % interface) + subprocess.getoutput("ip link set down %s" % interface) + cmd = subprocess.getstatusoutput("dpdk-devbind -b %s %s" % (DPDK_DRIVER, pci_num)) + if cmd[0] != 0: + sys.stderr.write("Bind server card failed.\n") - return dic + return render_template('index.html') @app.route('/api/unbind/server', methods=['GET', 'POST']) @@ -388,14 +395,13 @@ """ Unbind server card """ - dpdk_driver = "uio_pci_generic" card_id = request.values.get('cardid', '') - pci_num = subprocess.getoutput("dpdk-devbind.py -s | grep 'drv=%s' | awk '{print $1}'" % dpdk_driver) + pci_num = subprocess.getoutput("dpdk-devbind -s | grep 'drv=%s' | awk '{print $1}'" % DPDK_DRIVER) quad = __get_quad(pci_num) kernel_driver = subprocess.getoutput("lspci -s %s -v | grep 'Kernel modules' | awk '{print $3}'" % pci_num) if operator.eq(quad, eval(card_id)): - subprocess.getoutput("dpdk-devbind.py -b %s %s" % (kernel_driver, pci_num)) - result = subprocess.getoutput(("dpdk-devbind.py -s | grep {0}").format(pci_num)) + subprocess.getoutput("dpdk-devbind -b %s %s" % (kernel_driver, pci_num)) + result = subprocess.getoutput(("dpdk-devbind -s | grep {0}").format(pci_num)) interface = re.search(r'if=(\S*)', result).group(1) subprocess.getoutput("ip link set up %s") % interface @@ -410,11 +416,13 @@ valid_commands = ['rping', 'rcopy', 'ib_read_bw', 'ib_write_bw', 'ib_send_bw', 'qperf', 'dpdk-testpmd'] cmd = request.values.get('cmd', '') + pci_num = "" + interface = "" + card_id = request.values.get('cardid', '') cmd = cmd.split() if (not cmd) or (cmd[0] not in valid_commands + ['all']): sys.stdout.write("Invalid command: {0}.\n".format(cmd)) abort(400) - if act == 'start': if cmd[0] == 'rping': cmd = ['rping', '-s'] @@ -428,11 +436,17 @@ sys.stderr.write("No ibdev or ibport found.\n") abort(400) cmd.extend(['-d', ibdev, '-i', ibport]) - if cmd[0] == 'dpdk-testpmd': - result = subprocess.getstatusoutput("lspci | grep Mellanox") + if 'dpdk' in cmd[0]: + result = subprocess.getstatusoutput("dpdk-devbind -s | grep 'drv=%s'" % DPDK_DRIVER) if result[0] == 0: + pci_num = subprocess.getoutput("dpdk-devbind -s | grep 'drv=%s' | awk '{print $1}'" % DPDK_DRIVER) + else: __setting_dpdk_env() - cmd = ['dpdk-testpmd', '-l', '8-15', '-n', '4', '--', '--forward-mode=rxonly'] + interface = __get_server_port(card_id) + pci_num = subprocess.getoutput("ethtool -i %s | grep 'bus-info' | awk '{print $2}'" + % interface) + cmd = ['dpdk-testpmd', '-l', '0-1', '-n', '1', '-a', pci_num, '--', '--forward-mode=rxonly'] + time.sleep(3) __execute_cmd(cmd) elif act == 'stop': @@ -447,6 +461,24 @@ return render_template('index.html') +def __get_server_port(card_id): + """ + get server interface + """ + ports = [] + interface = "" + ports = subprocess.getoutput("ip link show up | grep 'state UP' | awk -F ': ' '{print $2}'").split('\n') + for pt in ports: + pci_num = subprocess.getoutput("ethtool -i %s | grep 'bus-info' | awk '{print $2}'" % pt) + quad = __get_quad(pci_num) + if operator.eq(quad, eval(card_id)): + result = subprocess.getoutput(("dpdk-devbind -s | grep {0}").format(pci_num)) + interface = re.search(r'if=(\S*)', result).group(1) + break + + return interface + + def __stop_process(process_name): check_cmd = subprocess.getstatusoutput( "ps -ef | grep %s | grep -v grep" % process_name) @@ -457,7 +489,8 @@ def __execute_cmd(cmd): - pipe = subprocess.Popen(cmd) + pipe = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8') time.sleep(3) if pipe.poll(): # supposed to be 0(foreground) or None(background) abort(400) @@ -511,9 +544,8 @@ """ Dpdk server environment setting """ - dpdk_driver = "uio_pci_generic" - subprocess.getoutput("modprobe uio; modprobe %s" % dpdk_driver) - if subprocess.getstatusoutput("lsmod | grep uio_pci_generic")[0] != 0: + subprocess.getoutput("modprobe uio; modprobe %s" % DPDK_DRIVER) + if subprocess.getstatusoutput("lsmod | grep %s" % DPDK_DRIVER)[0] != 0: sys.stderr.write("Dpdk driver moprobe failed.\n") return False subprocess.getoutput("dpdk-hugepages.py -u") diff -Naur rpm/tests/dpdk/dpdk.py oech/tests/dpdk/dpdk.py --- rpm/tests/dpdk/dpdk.py 2023-02-28 17:56:07.000000000 +0800 +++ oech/tests/dpdk/dpdk.py 2023-06-13 23:26:19.343482340 +0800 @@ -39,16 +39,19 @@ def __init__(self): Test.__init__(self) + self.requirements = ["dpdk", "dpdk-tools", "dpdk-devel"] self.config_data = dict() self.interface = None self.server_ip = "" self.server_port = 80 self.portmask = "0xffff" self.packet_size = 1514 - self.support_driver = ['mlx4_core', 'mlx5_core', 'ixgbe', 'i40e', 'ice', 'hinic'] + self.support_driver = ['mlx4_core', 'mlx5_core', 'ixgbe', 'ice', 'hinic', 'igc'] self.dpdk_driver = 'uio_pci_generic' self.kernel_driver = None self.retries = 3 + self.speed = 0 # Mb/s + self.target_bandwidth_percent = 0.8 self.device = "" self.pci = "" self.card_id = None @@ -78,6 +81,19 @@ self.server_ip = CertDocument(CertEnv.certificationfile, self.logger).get_server() self.test_prepare() + def get_interface_speed(self): + """ + Get speed on the interface + :return: + """ + speed = self.command.run_cmd( + "ethtool %s | grep Speed | awk '{print $2}'" % self.interface) + if speed[2] != 0: + self.logger.error("No speed found on the interface.") + return 0 + + return int(speed[0][:-5]) + def check_bind(self): """ Check whether binding card is required @@ -90,17 +106,17 @@ return False else: self.logger.info("DPDK driver is loading...") - subprocess.getoutput("modprobe uio; modprobe uio_pci_generic") - if self.command.run_cmd("lsmod | grep uio_pci_generic", terminal_print=True)[2] != 0: + subprocess.getoutput("modprobe uio; modprobe %s" % self.dpdk_driver) + if self.command.run_cmd("lsmod | grep %s" % self.dpdk_driver, terminal_print=True)[2] != 0: self.logger.error("DPDK driver is loaded failed!") return False else: + self.logger.info("Get server card's ethpeer...") + if not self.get_ethpeer(): + return False if self.kernel_driver == "mlx4_core" or self.kernel_driver == "mlx5_core": self.logger.info("The mellanox network card does not need to be bound.") self.command.run_cmd("modprobe -a ib_uverbs mlx5_core mlx5_ib mlx4_core", terminal_print=True) - self.ethpeer = self.command.run_cmd("grep %s /proc/net/arp | awk '{print $4}'" % - self.interface)[0].strip('\n') - self.logger.info("The mac of the server card is %s" % self.ethpeer) else: self.logger.info("Server dpdk is binding...") if not self.server_dpdk_bind(): @@ -110,6 +126,32 @@ return False return True + def get_ethpeer(self): + """ + Get ethpeer. + :return: + """ + form = {'serverip': self.server_ip, 'cardid': self.card_id} + url = 'http://{}:%s/api/get/ethpeer'.format(self.server_ip) % self.server_port + data = urlencode(form).encode('utf8') + headers = { + 'Content-type': 'application/x-www-form-urlencoded', + 'Accept': 'text/plain' + } + request = Request(url, data=data, headers=headers) + try: + response = urlopen(request) + except Exception: + self.logger.error("Call remote server url %s failed." % url) + return False + self.logger.info(str(response.headers), terminal_print=False) + self.ethpeer = json.loads(response.read())['ethpeer'] + self.logger.info("The mac of the server card is %s" % self.ethpeer) + self.logger.info("Status: %u %s" % (response.code, response.msg)) + if response.code != 200: + return False + return True + def client_dpdk_bind(self): """ Bind client card with dpdk driver @@ -149,8 +191,6 @@ self.logger.error("Call remote server url %s failed." % url) return False self.logger.info(str(response.headers), terminal_print=False) - self.ethpeer = json.loads(response.read())['ethpeer'] - self.logger.info("The mac of the server card is %s" % self.ethpeer) self.logger.info("Status: %u %s" % (response.code, response.msg)) if response.code != 200: return False @@ -217,19 +257,18 @@ Test speed :return: """ - self.logger.info("Running dpdk speed test...", terminal_print=False) command = [ 'dpdk-testpmd', - '-l', '8-15', - '-n', '4', + '-l', '0-1', + '-n', '1', '-a', self.pci, '--', - '--eth-peer=0,%s' % self.ethpeer, '--portmask=0x1', '--txpkts=%d' % self.packet_size, - '--rxq=2', - '--txq=2', + '--rxq=4', + '--txq=4', '--forward-mode=txonly', + '--eth-peer=0,%s' % self.ethpeer, '--stats-period=2' ] res = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -238,18 +277,26 @@ res.terminate() with os.fdopen(os.open(self.test_dpdk_file, FILE_FLAGS, FILE_MODES), "w") as log: log.write(str(res.stdout.read(), 'UTF-8')) - time.sleep(3) - res = self.command.run_cmd("grep Tx-pps %s | awk '{print $2}'" % self.test_dpdk_file)[0] - res_list = res.split("\n")[1:-1] + time.sleep(30) + res = self.command.run_cmd("grep Tx-bps %s | awk '{print $4}'" % self.test_dpdk_file) + if res[2] != 0: + self.logger.error("The test data result is empty, Please check if the server is configured properly!") + res_list = res[0].split("\n")[-10:-1] int_list = [int(x) for x in res_list] number = len(int_list) if number != 0: - pps = sum(int_list) / number - self.logger.info("The average speed is around %f Mb/s" % (8 * self.packet_size * pps / 1e6)) + bandwidth = float(sum(int_list) / number / 1e6) # 1e6 = 1000000.0 - return True + target_bandwidth = self.target_bandwidth_percent * self.speed + self.logger.info("Current bandwidth is around %.2f Mb/s, target is %.2fMb/s" % + (bandwidth, target_bandwidth)) + if bandwidth > target_bandwidth: + self.logger.info("Test dpdk bandwidth successfully.") + return True + self.logger.error("Test dpdk bandwidth failed!") + return False else: - self.logger.error("Test data acquisition failed!") + self.logger.error("No data obtained for testing dpdk, Please manually check!") return False def ifdown(self, interface): @@ -259,7 +306,7 @@ :return: """ self.command.run_cmd("ip link set down %s" % interface) - for _ in range(5): + for _ in range(10): result = self.command.run_cmd( "ip link show %s | grep 'state DOWN'" % interface, ignore_errors=True) if result[2] == 0: @@ -277,7 +324,7 @@ :return: """ self.command.run_cmd("ip link set up %s" % interface) - for _ in range(5): + for _ in range(10): result = self.command.run_cmd( "ip link show %s | grep 'state UP'" % interface, ignore_errors=True) if result[2] == 0: @@ -293,6 +340,13 @@ Test ICMP :return: """ + self.speed = self.get_interface_speed() + if self.speed: + self.logger.info("The speed of %s is %sMb/s." % + (self.interface, self.speed)) + else: + self.logger.error("Set speed of %s failed." % self.interface) + count = 500 cmd = "ping -q -c %d -i 0 %s | grep 'packet loss' | awk '{print $6}'" % ( count, self.server_ip) @@ -312,7 +366,7 @@ :return: """ form = dict() - form['cmd'] = cmd + form = {'cmd': cmd, 'serverip': self.server_ip, 'cardid': self.card_id} url = 'http://%s/api/%s' % (self.server_ip, act) data = urlencode(form).encode('utf8') headers = { @@ -323,7 +377,7 @@ try: response = urlopen(request) except Exception: - self.logger.error("Call remote server url %s failed." % url) + self.logger.error("Call remote dpdk server url %s failed." % url) return False self.logger.info("Status: %u %s" % (response.code, response.msg)) return int(response.code) == 200 diff -Naur rpm/tests/kabi/kabi.py oech/tests/kabi/kabi.py --- rpm/tests/kabi/kabi.py 2023-02-28 17:56:07.000000000 +0800 +++ oech/tests/kabi/kabi.py 2023-06-13 23:26:19.347482340 +0800 @@ -95,7 +95,7 @@ if data and hsdp[0] in data: continue elif data and hsdp[0] not in data: - if not self.changed_logpath.exists(): + if not os.path.exists(self.changed_logpath): self.command.run_cmd("echo 'standard_symvers cur_symvers' | tee %s" % ( self.changed_logpath), log_print=False) diff -Naur rpm/tests/network/network.py oech/tests/network/network.py --- rpm/tests/network/network.py 2023-02-28 17:56:07.000000000 +0800 +++ oech/tests/network/network.py 2023-06-13 23:26:19.355482340 +0800 @@ -136,7 +136,7 @@ :return: """ self.command.run_cmd("ip link set down %s" % interface) - for _ in range(5): + for _ in range(10): result = self.command.run_cmd( "ip link show %s | grep 'state DOWN'" % interface, ignore_errors=False) if result[2] == 0: @@ -154,7 +154,7 @@ :return: """ self.command.run_cmd("ip link set up %s" % interface) - for _ in range(5): + for _ in range(10): result = self.command.run_cmd( "ip link show %s | grep 'state UP'" % interface, ignore_errors=False) if result[2] == 0: