-
Notifications
You must be signed in to change notification settings - Fork 184
Migrate pktgen perf tests from tp-qemu to tp-libvirt #6781
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| - virtual_network.qemu_test.pktgen_perf_test: | ||
| type = pktgen_burst_mode_test | ||
| no Windows | ||
| only virtio_net | ||
| no Host_RHEL.m5, Host_RHEL.m6 | ||
| vm_ping_host = "pass" | ||
| pkg_dir = "tx rx" | ||
| pktgen_script = "pktgen_sample01_simple pktgen_sample03_burst_single_flow pktgen_sample05_flow_per_thread" | ||
| pktgen_threads = 1 | ||
| pkt_size = 64 | ||
| burst = 1 | ||
| pktgen_test_timeout = 30 | ||
| record_list = pkt_size run_threads burst mpps | ||
| guest_ver_cmd = "uname -r" | ||
| kvm_ver_chk_cmd = "rpm -qa qemu-kvm-rhev qemu-kvm" | ||
| test_vm = no | ||
| flush_firewall_rules_cmd = "iptables -F ; nft flush ruleset" | ||
| queues_nic1 = "8" | ||
| create_vm_libvirt = "yes" | ||
| kill_vm_libvirt = "yes" | ||
| ovmf: | ||
| kill_vm_libvirt_options = " --nvram" | ||
| master_images_clone = img1 | ||
| remove_image_image1 = yes | ||
|
|
||
| variants: | ||
| - @default: | ||
| - vhost_vdpa: | ||
| # Run pktgen perf test with vhost-vdpa interface. | ||
| # Default intent is VM <-> external host traffic testing. | ||
| dev_type = "vdpa" | ||
| driver_queues = 9 | ||
| vm_iface_driver = "virtio_net" | ||
| mac_addr = "52:54:00:00:00:00" | ||
| iface_dict = {'model': 'virtio', 'source': {'dev': '/dev/vhost-vdpa-0'}, 'type_name': 'vdpa', 'driver': {'driver_attr': {'queues': '${driver_queues}'}}, 'mac_address': mac_addr} | ||
| vm_attrs = {'vcpu': 10, 'current_vcpu': 10} | ||
| # Please modify the commented-out example values below | ||
| # client = ip | ||
| # username_client = your_username | ||
| # password_client = your_password | ||
| # shell_port_client = 22 | ||
| # shell_client_client = ssh | ||
| # shell_prompt_client = [$#%] | ||
| # client_pktgen_iface = ethX # external host iface used by pktgen | ||
| # pktgen_tx_dst_mac = xx:xx:xx:xx:xx:xx | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -12,12 +12,16 @@ | |||||
| from avocado.utils import distro | ||||||
| from avocado.utils import process | ||||||
|
|
||||||
| from virttest import virsh | ||||||
| from virttest import utils_misc | ||||||
| from virttest import utils_net | ||||||
| from virttest.libvirt_xml import vm_xml | ||||||
| from virttest.utils_libvirt import libvirt_vmxml | ||||||
| from virttest.utils_test import libvirt | ||||||
|
|
||||||
| from provider.virtual_network import pktgen_utils | ||||||
| from provider.virtual_network import network_base | ||||||
| from provider.interface import interface_base | ||||||
|
|
||||||
|
|
||||||
| def write_to_result_file(test, params): | ||||||
|
|
@@ -61,10 +65,36 @@ def run_test(): | |||||
| pktgen_utils.install_package(host_ver) | ||||||
|
|
||||||
| test.log.debug("TEST_STEP 2: Test with guest and host connectivity") | ||||||
| recreate_serial_console = False | ||||||
| # vhost-vdpa needs XML updates before starting VM | ||||||
| if params.get("dev_type") == "vdpa" and params.get("iface_dict"): | ||||||
| # Ensure VM is stopped before XML changes | ||||||
| virsh.destroy(vm_name, debug=True, ignore_status=True) | ||||||
| recreate_serial_console = True | ||||||
|
|
||||||
| libvirt_vmxml.remove_vm_devices_by_type(vm, "interface") | ||||||
| vm_attrs = eval(params.get("vm_attrs", "{}")) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use
Suggested fixAdd the import at the top: import os
+import astThen replace eval: - vm_attrs = eval(params.get("vm_attrs", "{}"))
+ vm_attrs = ast.literal_eval(params.get("vm_attrs", "{}"))📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.14.13)76-76: Use of possibly insecure function; consider using (S307) 🤖 Prompt for AI Agents |
||||||
| if vm_attrs: | ||||||
| vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) | ||||||
| vmxml.setup_attrs(**vm_attrs) | ||||||
| vmxml.sync() | ||||||
|
|
||||||
| # Add a single vhost-vdpa interface | ||||||
| vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) | ||||||
| iface_dict = interface_base.parse_iface_dict(params) | ||||||
| iface_dev = interface_base.create_iface(params.get("dev_type"), iface_dict) | ||||||
| libvirt.add_vm_device(vmxml, iface_dev) | ||||||
|
|
||||||
| if vm.virtnet: | ||||||
| vm.virtnet[0].mac = params.get("mac_addr") | ||||||
| vm.virtnet[0].nettype = "vdpa" | ||||||
|
|
||||||
| if not vm.is_alive(): | ||||||
| vm.start() | ||||||
| test.log.debug("Test with Guest xml:%s", vm_xml.VMXML.new_from_dumpxml(vm_name)) | ||||||
| session = vm.wait_for_serial_login(restart_network=True) | ||||||
| session = vm.wait_for_serial_login( | ||||||
| restart_network=True, recreate_serial_console=recreate_serial_console | ||||||
| ) | ||||||
| network_base.ping_check(params, ips, session, force_ipv4=True) | ||||||
|
|
||||||
| test.log.debug("TEST_STEP 3: Install package and Run pktgen in burst mode.") | ||||||
|
|
@@ -86,7 +116,15 @@ def run_test(): | |||||
| params, result_file, test_vm, vm, session) | ||||||
|
|
||||||
| test.log.debug("TEST_STEP: Check the guest dmesg without error messages.") | ||||||
| vm.verify_dmesg() | ||||||
| if params.get("dev_type") == "vdpa": | ||||||
| # vhost-vdpa may not have a guest IP (ARP/arping), so vm.verify_dmesg() | ||||||
| # can fail by attempting a network login. | ||||||
| utils_misc.verify_dmesg( | ||||||
| ignore_result=False, | ||||||
| session=session, | ||||||
| ) | ||||||
| else: | ||||||
| vm.verify_dmesg() | ||||||
| vm.verify_kernel_crash() | ||||||
|
|
||||||
| result_file.close() | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||||||||||||||||
| from avocado.utils import process | ||||||||||||||||||||
|
|
||||||||||||||||||||
| from virttest import data_dir | ||||||||||||||||||||
| from virttest import remote | ||||||||||||||||||||
| from virttest import utils_net | ||||||||||||||||||||
| from virttest import utils_misc | ||||||||||||||||||||
| from virttest import utils_package | ||||||||||||||||||||
|
|
@@ -25,26 +26,56 @@ def configure_pktgen( | |||||||||||||||||||
| pkt_cate, | ||||||||||||||||||||
| vm=None, | ||||||||||||||||||||
| session_serial=None, | ||||||||||||||||||||
| script=None, | ||||||||||||||||||||
| params=None | ||||||||||||||||||||
| ): | ||||||||||||||||||||
| """ | ||||||||||||||||||||
| Configure pktgen test environment for different packet categories. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| :param pkt_cate: Packet category (tx, rx, loopback) | ||||||||||||||||||||
| :param vm: VM instance | ||||||||||||||||||||
| :param session_serial: Serial session for guest command execution | ||||||||||||||||||||
| :param params: Dictionary with the test parameters | ||||||||||||||||||||
| :param script: Script name to execute | ||||||||||||||||||||
| :return: Configured PktgenConfig instance | ||||||||||||||||||||
| """ | ||||||||||||||||||||
| source_path = os.path.join(data_dir.get_shared_dir(), "scripts/pktgen_perf") | ||||||||||||||||||||
| params = params or {} | ||||||||||||||||||||
| guest_mac = vm.get_mac_address(0) | ||||||||||||||||||||
| guest_eth = utils_net.get_linux_ifname(session_serial, guest_mac) | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
Comment on lines
+43
to
46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing null checks for
Suggested fixAdd validation at the start: params = params or {}
+ if vm is None or session_serial is None:
+ raise ValueError("vm and session_serial are required for configure_pktgen")
guest_mac = vm.get_mac_address(0)
guest_eth = utils_net.get_linux_ifname(session_serial, guest_mac)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| if pkt_cate == "tx": | ||||||||||||||||||||
| LOG_JOB.info("test guest tx pps performance") | ||||||||||||||||||||
| vm.copy_files_to(source_path, self.dest_path) | ||||||||||||||||||||
| guest_mac = vm.get_mac_address(0) | ||||||||||||||||||||
| self.interface = utils_net.get_linux_ifname(session_serial, guest_mac) | ||||||||||||||||||||
| host_iface = libvirt.get_ifname_host(vm.name, guest_mac) | ||||||||||||||||||||
| dsc_dev = utils_net.Interface(host_iface) | ||||||||||||||||||||
| self.dsc = dsc_dev.get_mac() | ||||||||||||||||||||
| if params.get("pktgen_tx_dst_mac"): | ||||||||||||||||||||
| self.dsc = params.get("pktgen_tx_dst_mac") | ||||||||||||||||||||
| else: | ||||||||||||||||||||
| host_iface = libvirt.get_ifname_host(vm.name, guest_mac) | ||||||||||||||||||||
| dsc_dev = utils_net.Interface(host_iface) | ||||||||||||||||||||
| self.dsc = dsc_dev.get_mac() | ||||||||||||||||||||
| self.interface = guest_eth | ||||||||||||||||||||
| self.runner = session_serial.cmd | ||||||||||||||||||||
| elif pkt_cate == "rx": | ||||||||||||||||||||
| LOG_JOB.info("test guest rx pps performance") | ||||||||||||||||||||
| if params.get("client"): | ||||||||||||||||||||
| client_ip = params.get("client") | ||||||||||||||||||||
| username = params.get("username_client", "root") | ||||||||||||||||||||
| password = params.get("password_client") | ||||||||||||||||||||
| remote.copy_files_to( | ||||||||||||||||||||
| client_ip, "scp", username, password, 22, | ||||||||||||||||||||
| source_path, self.dest_path, timeout=600 | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| self.interface = params.get("pktgen_rx_iface") | ||||||||||||||||||||
| remote_session = remote.remote_login( | ||||||||||||||||||||
| "ssh", client_ip, "22", | ||||||||||||||||||||
| username, password, r'[$#%]' | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| self.runner = remote_session.cmd | ||||||||||||||||||||
| else: | ||||||||||||||||||||
| process.run("cp -r %s %s" % (source_path, self.dest_path)) | ||||||||||||||||||||
| self.interface = libvirt.get_ifname_host(vm.name, guest_mac) | ||||||||||||||||||||
| self.runner = process.run | ||||||||||||||||||||
| self.dsc = guest_mac | ||||||||||||||||||||
| return self | ||||||||||||||||||||
|
|
||||||||||||||||||||
| def generate_pktgen_cmd( | ||||||||||||||||||||
|
|
@@ -82,44 +113,48 @@ def generate_pktgen_cmd( | |||||||||||||||||||
|
|
||||||||||||||||||||
| if ( | ||||||||||||||||||||
| session_serial | ||||||||||||||||||||
| and self.runner.__name__ == session_serial.cmd.__name__ | ||||||||||||||||||||
| and self.runner == session_serial.cmd | ||||||||||||||||||||
| ): | ||||||||||||||||||||
| cmd = f"{cmd} &" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| return cmd | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| def run_test(script, cmd, runner, interface, timeout): | ||||||||||||||||||||
| def run_test(script, cmd, runner, interface, timeout, session_serial=None, pkt_cate="tx"): | ||||||||||||||||||||
| """ | ||||||||||||||||||||
| Run pktgen script on remote and gather packet numbers/time and | ||||||||||||||||||||
| calculate mpps. | ||||||||||||||||||||
| :param script: pktgen script name. | ||||||||||||||||||||
| :param cmd: The command to execute the pktgen script | ||||||||||||||||||||
| :param runner: The command runner function | ||||||||||||||||||||
| :param interface: The network interface used by pktgen. | ||||||||||||||||||||
| :param interface: The VM Ethernet interface used to collect packet counters. | ||||||||||||||||||||
| :param timeout: The maximum time allowed for the test to run | ||||||||||||||||||||
| :param session_serial: Session serial for VM | ||||||||||||||||||||
| :param pkt_cate: Packet category (tx/rx), used to select counter type | ||||||||||||||||||||
| :return: The calculated MPPS (Million Packets Per Second) | ||||||||||||||||||||
| """ | ||||||||||||||||||||
|
|
||||||||||||||||||||
| packets = "cat /sys/class/net/%s/statistics/tx_packets" % interface | ||||||||||||||||||||
| counter = "rx_packets" if pkt_cate == "rx" else "tx_packets" | ||||||||||||||||||||
| packets = "cat /sys/class/net/%s/statistics/%s" % (interface, counter) | ||||||||||||||||||||
| LOG_JOB.info("Start pktgen test by cmd '%s'", cmd) | ||||||||||||||||||||
| try: | ||||||||||||||||||||
| packet_b = runner(packets) | ||||||||||||||||||||
| packet_b = session_serial.cmd(packets) | ||||||||||||||||||||
| packet_a = None | ||||||||||||||||||||
| runner(cmd, timeout) | ||||||||||||||||||||
| packet_a = session_serial.cmd(packets) | ||||||||||||||||||||
| except aexpect.ShellTimeoutError: | ||||||||||||||||||||
| # when pktgen script is running on guest, the pktgen process | ||||||||||||||||||||
| # need to be killed. | ||||||||||||||||||||
| kill_cmd = ( | ||||||||||||||||||||
| "kill -9 `ps -ef | grep %s --color | grep -v grep | " | ||||||||||||||||||||
| "awk '{print $2}'`" % script | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| runner(kill_cmd) | ||||||||||||||||||||
| packet_a = runner(packets) | ||||||||||||||||||||
| if session_serial and runner == session_serial.cmd: | ||||||||||||||||||||
| kill_cmd = ( | ||||||||||||||||||||
| "kill -9 `ps -ef | grep %s --color | grep -v grep | " | ||||||||||||||||||||
| "awk '{print $2}'`" % script | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| runner(kill_cmd) | ||||||||||||||||||||
| packet_a = session_serial.cmd(packets) | ||||||||||||||||||||
| except process.CmdError: | ||||||||||||||||||||
| # when pktgen script is running on host, the pktgen process | ||||||||||||||||||||
| # will be quit when timeout triggers, so no need to kill it. | ||||||||||||||||||||
| packet_a = runner(packets) | ||||||||||||||||||||
| packet_a = session_serial.cmd(packets) | ||||||||||||||||||||
|
Comment on lines
+123
to
+157
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Lines 136, 139, 149, and 153 all call Either make Suggested fix - make parameter required-def run_test(script, cmd, runner, interface, timeout, session_serial=None, pkt_cate="tx"):
+def run_test(script, cmd, runner, interface, timeout, session_serial, pkt_cate="tx"):🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| return "{:.2f}".format((int(packet_a) - int(packet_b)) / timeout / 10 ** 6) | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
@@ -193,6 +228,8 @@ def run_tests_for_category( | |||||||||||||||||||
| # Get single values for threads and burst instead of looping | ||||||||||||||||||||
| threads = params.get("pktgen_threads", "") | ||||||||||||||||||||
| burst = params.get("burst", "") | ||||||||||||||||||||
| guest_mac = vm.get_mac_address(0) | ||||||||||||||||||||
| guest_eth = utils_net.get_linux_ifname(session_serial, guest_mac) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| record_line = "" | ||||||||||||||||||||
| for record in record_list: | ||||||||||||||||||||
|
|
@@ -210,7 +247,7 @@ def run_tests_for_category( | |||||||||||||||||||
| size = params.get("pkt_size", "") | ||||||||||||||||||||
| if pkt_cate != "loopback": | ||||||||||||||||||||
| pktgen_config = pktgen_config.configure_pktgen( | ||||||||||||||||||||
| pkt_cate, vm, session_serial | ||||||||||||||||||||
| pkt_cate, vm, session_serial, script=script, params=params | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| exec_cmd = pktgen_config.generate_pktgen_cmd( | ||||||||||||||||||||
| script, | ||||||||||||||||||||
|
|
@@ -222,14 +259,19 @@ def run_tests_for_category( | |||||||||||||||||||
| burst, | ||||||||||||||||||||
| session_serial, | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| pkt_cate_r = None | ||||||||||||||||||||
| if exec_cmd: | ||||||||||||||||||||
| pkt_cate_r = run_test( | ||||||||||||||||||||
| script, | ||||||||||||||||||||
| exec_cmd, | ||||||||||||||||||||
| pktgen_config.runner, | ||||||||||||||||||||
| pktgen_config.interface, | ||||||||||||||||||||
| guest_eth, | ||||||||||||||||||||
| timeout, | ||||||||||||||||||||
| session_serial, | ||||||||||||||||||||
| pkt_cate=pkt_cate, | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| else: | ||||||||||||||||||||
| pkt_cate_r = None | ||||||||||||||||||||
|
|
||||||||||||||||||||
| line = "%s|" % format_result(size) | ||||||||||||||||||||
| line += "%s|" % format_result(threads) | ||||||||||||||||||||
|
|
||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parameter name mismatch with pktgen_utils.py.
The config defines
client_pktgen_ifacebutpktgen_utils.pyline 66 retrieves it aspktgen_rx_iface. This mismatch will cause the interface to beNonewhen running rx tests with a client.Suggested fix
Either rename here to match the code:
Or update
pktgen_utils.pyline 66:📝 Committable suggestion
🤖 Prompt for AI Agents