Add test that run x-query-virtio-status QMP command, and its
HMP analog.

Now QEMU crashes in these scenarios due to bugs, so the test-cases
are skipped. You may run them by setting QEMU_FAILING_TESTS
environment variable.

Following commits will fix bug and enable the test-cases.

Wrap QEMU run by "unshare" to access vhost-net without sudo.

Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]>
---
 MAINTAINERS                                   |  1 +
 tests/functional/qemu_test/testcase.py        |  9 +-
 tests/functional/x86_64/meson.build           |  2 +
 tests/functional/x86_64/test_virtio_status.py | 97 +++++++++++++++++++
 4 files changed, 105 insertions(+), 4 deletions(-)
 create mode 100755 tests/functional/x86_64/test_virtio_status.py

diff --git a/MAINTAINERS b/MAINTAINERS
index 6be9c5725b9..8bd7c8472d9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2535,6 +2535,7 @@ F: include/hw/virtio/
 F: docs/devel/virtio*
 F: docs/devel/migration/virtio.rst
 F: tests/functional/x86_64/test_virtio_version.py
+F: tests/functional/x86_64/test_virtio_status.py
 
 virtio-balloon
 M: Michael S. Tsirkin <[email protected]>
diff --git a/tests/functional/qemu_test/testcase.py 
b/tests/functional/qemu_test/testcase.py
index bf2dc1dc101..d719b79eb1e 100644
--- a/tests/functional/qemu_test/testcase.py
+++ b/tests/functional/qemu_test/testcase.py
@@ -387,12 +387,13 @@ def require_device(self, devicename):
         if helptxt.find(devicename) < 0:
             self.skipTest('no support for device ' + devicename)
 
-    def _new_vm(self, name, monitor_address):
+    def _new_vm(self, name, monitor_address, wrapper):
         vm = QEMUMachine(self.qemu_bin,
                          name=name,
                          base_temp_dir=self.workdir,
                          log_dir=self.log_file(),
-                         monitor_address=monitor_address)
+                         monitor_address=monitor_address,
+                         wrapper=wrapper)
         self.log.debug('QEMUMachine "%s" created', name)
         self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir)
 
@@ -407,11 +408,11 @@ def _new_vm(self, name, monitor_address):
     def vm(self):
         return self.get_vm(name='default')
 
-    def get_vm(self, name=None, monitor_address=None):
+    def get_vm(self, name=None, monitor_address=None, wrapper=()):
         if not name:
             name = str(uuid.uuid4())
         if self._vms.get(name) is None:
-            self._vms[name] = self._new_vm(name, monitor_address)
+            self._vms[name] = self._new_vm(name, monitor_address, wrapper)
             if self.cpu is not None:
                 self._vms[name].add_args('-cpu', self.cpu)
             if self.machine is not None:
diff --git a/tests/functional/x86_64/meson.build 
b/tests/functional/x86_64/meson.build
index 0353b2af8e1..62dedb2e203 100644
--- a/tests/functional/x86_64/meson.build
+++ b/tests/functional/x86_64/meson.build
@@ -7,6 +7,7 @@ test_x86_64_timeouts = {
   'netdev_ethtool' : 180,
   'replay' : 480,
   'virtio_balloon': 120,
+  'virtio_status': 120,
 }
 
 tests_x86_64_system_quick = [
@@ -50,5 +51,6 @@ tests_x86_64_system_thorough = [
   'vhost_user_bridge',
   'virtio_balloon',
   'virtio_gpu',
+  'virtio_status',
   'rebuild_vmfd',
 ]
diff --git a/tests/functional/x86_64/test_virtio_status.py 
b/tests/functional/x86_64/test_virtio_status.py
new file mode 100755
index 00000000000..c8cbdf7c42e
--- /dev/null
+++ b/tests/functional/x86_64/test_virtio_status.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: MIT
+
+import os
+import subprocess
+
+from qemu_test import (
+    Asset,
+    LinuxKernelTest,
+    skipIfMissingCommands,
+    skipIfMissingEnv,
+)
+
+
+class VirtioStatus(LinuxKernelTest):
+    ASSET_KERNEL = Asset(
+        "https://dl-cdn.alpinelinux.org/alpine/v3.24/releases/x86_64/";
+        "netboot-3.24.2/vmlinuz-virt",
+        "be8ae7782de532d1a791c97fbf9ddc955b9de78349382ad097c83ffe9db857f4")
+    ASSET_INITRD = Asset(
+        "https://dl-cdn.alpinelinux.org/alpine/v3.24/releases/x86_64/";
+        "netboot-3.24.2/initramfs-virt",
+        "385418a99b17c0ef44947d88ea448d43b2df4a2c3343da72e724c6cf3b05e9f7")
+
+    VIRTIO_PATH = "/machine/peripheral/net0/virtio-backend"
+
+    def setUp(self):
+        super().setUp()
+        self.qemu_wrapper = []
+        self.require_accelerator("kvm")
+        self.require_device("virtio-net-pci")
+        self.set_machine("q35")
+
+    def has_hmp(self, vm):
+        commands = vm.cmd('query-commands')
+        return any(cmd['name'] == 'human-monitor-command' for cmd in commands)
+
+    def check_commands(self, vm):
+        if self.has_hmp(vm):
+            vm.cmd(
+                "human-monitor-command",
+                command_line="info virtio-status " + self.VIRTIO_PATH,
+            )
+        vm.cmd("x-query-virtio-status", path=self.VIRTIO_PATH)
+
+    @skipIfMissingCommands("unshare")
+    @skipIfMissingEnv("QEMU_FAILING_TESTS")
+    def test_vhost(self):
+        self.require_netdev("tap")
+        for device in ("/dev/net/tun", "/dev/vhost-net"):
+            if not os.access(device, os.R_OK | os.W_OK):
+                self.skipTest(f"Read/write access to {device} is required")
+
+        wrapper = ["unshare", "-Urn", "--"]
+        probe = subprocess.run(wrapper + ["true"],
+                               capture_output=True,
+                               text=True, check=False)
+        if probe.returncode:
+            self.skipTest("User/network namespaces unavailable: " +
+                          probe.stderr.strip())
+
+        vm = self.get_vm("wrapped", wrapper=wrapper)
+
+        kernel = self.ASSET_KERNEL.fetch()
+        initrd = self.ASSET_INITRD.fetch()
+
+        vm.set_console()
+        vm.add_args("-accel", "kvm")
+        vm.add_args("-kernel", kernel,
+                    "-initrd", initrd,
+                    "-append", "console=ttyS0 modules=virtio_net",
+                    "-netdev",
+                    "tap,id=net,script=,downscript=,vhost=on",
+                    "-device",
+                    "virtio-net-pci,id=net0,netdev=net,romfile=")
+        vm.launch()
+
+        # modules=virtio_net ensures the driver is loaded by this point
+        self.wait_for_console_pattern("Loading boot drivers: ok.", vm=vm)
+        vm.cmd(
+            "x-query-virtio-vhost-queue-status", path=self.VIRTIO_PATH, queue=0
+        )
+
+        self.check_commands(vm)
+
+    @skipIfMissingEnv("QEMU_FAILING_TESTS")
+    def test_no_vhost(self):
+        self.vm.add_args("-accel", "kvm",
+                         "-S", "-net", "none", "-device",
+                         "virtio-net-pci,id=net0,romfile=")
+        self.vm.launch()
+        self.check_commands(self.vm)
+
+
+if __name__ == "__main__":
+    LinuxKernelTest.main()
-- 
2.43.0


Reply via email to