|
| 1 | +import re |
| 2 | + |
| 3 | +from virttest import env_process, error_context, utils_misc, utils_net |
| 4 | + |
| 5 | + |
| 6 | +@error_context.context_aware |
| 7 | +def run(test, params, env): |
| 8 | + """ |
| 9 | + Simulate high packet rate between host and device by running Python scripts |
| 10 | + on both server and client side. This test is executed on two VM guests: |
| 11 | +
|
| 12 | + 1) Start a VM guest as the server. |
| 13 | + 2) Start a VM guest as the client. |
| 14 | + 3) Simulate buffer allocation issues on the server node. |
| 15 | + 4) Use a Python script to connect the client to the server. |
| 16 | + 5) Adjust the MinRxBufferPercent parameter to work around the issue. |
| 17 | + 6) Ensure no BSOD occurs on the client node. |
| 18 | +
|
| 19 | + :param test: QEMU test object. |
| 20 | + :param params: Dictionary of test parameters. |
| 21 | + :param env: Dictionary of test environment details. |
| 22 | + """ |
| 23 | + |
| 24 | + def analyze_ping_results(session, dest, count, timeout): |
| 25 | + """ |
| 26 | + conduct a ping test to check the packet loss on slow memory buffer reallocation |
| 27 | +
|
| 28 | + :param session: Local execution hint or session to execute the ping command. |
| 29 | + :param count: Count of icmp packet. |
| 30 | + :param timeout: Timeout for the ping command. |
| 31 | + """ |
| 32 | + |
| 33 | + status, output = utils_net.ping( |
| 34 | + dest=dest, session=session, count=count, timeout=timeout |
| 35 | + ) |
| 36 | + if status != 0: |
| 37 | + test.fail("Ping failed, status: %s," " output: %s" % (status, output)) |
| 38 | + if match := re.search(r"(\d+)% loss", output): |
| 39 | + return match.group(1) |
| 40 | + |
| 41 | + def modify_and_analyze_params_result(vm, param_name, value): |
| 42 | + """ |
| 43 | + First set netkvm driver parameter 'param_name' |
| 44 | + to value 'param_value'. Then read the current and compare |
| 45 | + to 'param_value' to check identity Raised exception when |
| 46 | + checking netkvmco.exe setup was unsuccessful if something is wrong. |
| 47 | +
|
| 48 | + :param vm: the selected vm |
| 49 | + :param param_name: the netkvm driver parameter to modify |
| 50 | + :param value: the value to set to |
| 51 | + """ |
| 52 | + |
| 53 | + utils_net.set_netkvm_param_value(vm, param_name, value) |
| 54 | + cur_value = utils_net.get_netkvm_param_value(vm, param_name) |
| 55 | + if cur_value != value: |
| 56 | + test.fail(f"Failed to set '{param_name}' to '{value}'") |
| 57 | + |
| 58 | + def check_and_restart_port(session, port, script_to_run): |
| 59 | + """ |
| 60 | + Check if a Python process is listening on the specified port. |
| 61 | + If not, restart the appropriate Python script (server or client). |
| 62 | +
|
| 63 | + :param session: session to execute commands on the target machine. |
| 64 | + :param port: the port number to monitor. |
| 65 | + :param script_to_run: the path to the Python script to execute. |
| 66 | + """ |
| 67 | + |
| 68 | + check_live_python = params.get("check_live_python") |
| 69 | + status, output = session.cmd_status_output(check_live_python, timeout=1200) |
| 70 | + if status == 0: |
| 71 | + return |
| 72 | + if "server" in script_to_run: |
| 73 | + s_session.cmd(dest_location) |
| 74 | + error_context.context( |
| 75 | + "Run python3 code runs on the server node", test.log.info |
| 76 | + ) |
| 77 | + status, output = session.cmd_status_output(s_py_cmd, timeout=1200) |
| 78 | + if status != 0: |
| 79 | + test.fail("The server node failed to start.") |
| 80 | + else: |
| 81 | + c_session.cmd(dest_location) |
| 82 | + error_context.context( |
| 83 | + "Run python3 code runs on the client node", test.log.info |
| 84 | + ) |
| 85 | + status, output = session.cmd_status_output(c_py_cmd % s_vm_ip, timeout=1200) |
| 86 | + if status != 0: |
| 87 | + test.fail( |
| 88 | + "The client could not connect to the server node.", test.log.info |
| 89 | + ) |
| 90 | + |
| 91 | + timeout = params.get_numeric("login_timeout", 360) |
| 92 | + port_num = params.get("port_num") |
| 93 | + s_py_cmd = params.get("s_py_cmd") |
| 94 | + c_py_cmd = params.get("c_py_cmd") |
| 95 | + param_name = params.get("param_name") |
| 96 | + param_values = params.get("param_values") |
| 97 | + dest_location = params.get("dest_location") |
| 98 | + c_pip_copy_cmd = params.get("c_pip_copy_cmd") |
| 99 | + c_pip_cmd = params.get("c_pip_cmd") |
| 100 | + c_py_copy_cmd = params.get("c_py_copy_cmd") |
| 101 | + s_py_copy_cmd = params.get("s_py_copy_cmd") |
| 102 | + |
| 103 | + s_vm_name = params["vms"].split()[0] |
| 104 | + s_vm = env.get_vm(s_vm_name) |
| 105 | + s_vm.verify_alive() |
| 106 | + s_session = s_vm.wait_for_serial_login( |
| 107 | + timeout=int(params.get("login_timeout", 360)) |
| 108 | + ) |
| 109 | + s_vm_ip = s_vm.get_address() |
| 110 | + |
| 111 | + c_vm_name = params["vms"].split(s_vm_name)[1].strip() |
| 112 | + c_vm_params = params.object_params(c_vm_name) |
| 113 | + c_vm_params["nic_extra_params_nic1"] = "" |
| 114 | + c_vm_params["start_vm"] = "yes" |
| 115 | + env_process.preprocess_vm(test, c_vm_params, env, c_vm_name) |
| 116 | + c_vm = env.get_vm(c_vm_name) |
| 117 | + c_vm.verify_alive() |
| 118 | + c_session = c_vm.wait_for_serial_login( |
| 119 | + timeout=int(params.get("login_timeout", 360)) |
| 120 | + ) |
| 121 | + c_vm_ip = c_vm.get_address() |
| 122 | + |
| 123 | + # Here, we want to install some dependent packages |
| 124 | + s_session.cmd(dest_location) |
| 125 | + s_py_copy_cmd = utils_misc.set_winutils_letter(s_session, s_py_copy_cmd) |
| 126 | + s_session.cmd(s_py_copy_cmd) |
| 127 | + c_session.cmd(dest_location) |
| 128 | + c_pip_copy_cmd = utils_misc.set_winutils_letter(c_session, c_pip_copy_cmd) |
| 129 | + c_session.cmd(c_pip_copy_cmd) |
| 130 | + c_session.cmd(c_pip_cmd) |
| 131 | + c_py_copy_cmd = utils_misc.set_winutils_letter(c_session, c_py_copy_cmd) |
| 132 | + c_session.cmd(c_py_copy_cmd) |
| 133 | + |
| 134 | + ping_results = [] |
| 135 | + error_context.context( |
| 136 | + "Open the NIC properties and change the values in the server node", |
| 137 | + test.log.info, |
| 138 | + ) |
| 139 | + for value in param_values.split(" "): |
| 140 | + modify_and_analyze_params_result(vm=s_vm, param_name=param_name, value=value) |
| 141 | + check_and_restart_port(session=s_session, port=port_num, script_to_run=s_py_cmd) |
| 142 | + check_and_restart_port(session=c_session, port=port_num, script_to_run=c_py_cmd) |
| 143 | + ping_results.append( |
| 144 | + int( |
| 145 | + analyze_ping_results( |
| 146 | + session=c_session, dest=s_vm_ip, count=100, timeout=timeout |
| 147 | + ) |
| 148 | + ) |
| 149 | + ) |
| 150 | + |
| 151 | + error_context.context( |
| 152 | + "Get the packet loss percentage of the ping request", test.log.info |
| 153 | + ) |
| 154 | + if sum(ping_results) != 0: |
| 155 | + if not all( |
| 156 | + ping_results[i] > ping_results[i + 1] for i in range(len(ping_results) - 1) |
| 157 | + ): |
| 158 | + test.fail( |
| 159 | + "With the parameter, the number of lost packets should be " |
| 160 | + "less than without the parameter." |
| 161 | + ) |
| 162 | + |
| 163 | + error_context.context("no BSOD will occur on the client side", test.log.info) |
| 164 | + for value in param_values.split(" "): |
| 165 | + modify_and_analyze_params_result(vm=c_vm, param_name=param_name, value=value) |
| 166 | + status, output = utils_net.ping( |
| 167 | + dest=c_vm_ip, session=c_session, count=10, timeout=60 |
| 168 | + ) |
| 169 | + if status != 0: |
| 170 | + test.fail("Ping failed, status: %s," " output: %s" % (status, output)) |
0 commit comments