edecca
From 5ad0f7cc1b2444ee9355229316fb008919d22c71 Mon Sep 17 00:00:00 2001
edecca
Message-Id: <5ad0f7cc1b2444ee9355229316fb008919d22c71@dist-git>
edecca
From: Erik Skultety <eskultet@redhat.com>
edecca
Date: Thu, 19 Jul 2018 15:04:02 +0200
edecca
Subject: [PATCH] conf: Introduce new <hostdev> attribute 'display'
edecca
MIME-Version: 1.0
edecca
Content-Type: text/plain; charset=UTF-8
edecca
Content-Transfer-Encoding: 8bit
edecca
edecca
QEMU 2.12 introduced a new type of display for mediated devices using
edecca
vfio-pci backend which allows a mediated device to be used as a VGA
edecca
compatible device as an alternative to an emulated video device. QEMU
edecca
exposes this feature via a vfio device property 'display' with supported
edecca
values 'on/off/auto' (libvirt will default to 'off').
edecca
edecca
This patch adds the necessary bits to domain config handling in order to
edecca
expose this feature. Since there's no convenient way for libvirt to come
edecca
up with usable defaults for the display setting, simply because libvirt
edecca
is not able to figure out which of the display implementations - dma-buf
edecca
which requires OpenGL support vs vfio regions which doesn't need OpenGL
edecca
(works with OpenGL enabled too) - the underlying mdev uses.
edecca
edecca
Reviewed-by: Ján Tomko <jtomko@redhat.com>
edecca
Signed-off-by: Erik Skultety <eskultet@redhat.com>
edecca
(cherry picked from commit d54e45b6edd7623e488a19e30bc4148a21fa8b03)
edecca
edecca
https://bugzilla.redhat.com/show_bug.cgi?id=1475770
edecca
Signed-off-by: Erik Skultety <eskultet@redhat.com>
edecca
Reviewed-by: Ján Tomko <jtomko@redhat.com>
edecca
---
edecca
 docs/formatdomain.html.in                     | 20 +++-
edecca
 docs/schemas/domaincommon.rng                 |  5 +
edecca
 src/conf/domain_conf.c                        | 19 +++-
edecca
 src/conf/domain_conf.h                        |  1 +
edecca
 src/qemu/qemu_domain.c                        | 98 ++++++++++++++++++-
edecca
 .../qemuxml2argvdata/hostdev-mdev-display.xml | 39 ++++++++
edecca
 .../hostdev-mdev-display.xml                  | 47 +++++++++
edecca
 tests/qemuxml2xmltest.c                       |  1 +
edecca
 8 files changed, 222 insertions(+), 8 deletions(-)
edecca
 create mode 100644 tests/qemuxml2argvdata/hostdev-mdev-display.xml
edecca
 create mode 100644 tests/qemuxml2xmloutdata/hostdev-mdev-display.xml
edecca
edecca
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
edecca
index 9dd22554ad..3554c3dc30 100644
edecca
--- a/docs/formatdomain.html.in
edecca
+++ b/docs/formatdomain.html.in
edecca
@@ -4510,9 +4510,23 @@
edecca
           guest. Currently, model='vfio-pci' and
edecca
           model='vfio-ccw' (Since 4.4.0)
edecca
           is supported. Refer MDEV to create
edecca
-          a mediated device on the host. There are also some implications on the
edecca
-          usage of guest's address type depending on the model
edecca
-          attribute, see the address element below.
edecca
+          a mediated device on the host.
edecca
+          Since 4.6.0 (QEMU 2.12) an optional
edecca
+          display attribute may be used to enable or disable
edecca
+          support for an accelerated remote desktop backed by a mediated
edecca
+          device (such as NVIDIA vGPU or Intel GVT-g) as an alternative to
edecca
+          emulated video devices. This attribute
edecca
+          is limited to model='vfio-pci' only. Supported values
edecca
+          are either on or off (default is 'off').
edecca
+          It is required to use a
edecca
+          graphical framebuffer in order to
edecca
+          use this attribute, currently only supported with VNC, Spice and
edecca
+          egl-headless graphics devices.
edecca
+          

edecca
+            Note: There are also some implications on the usage of guest's
edecca
+            address type depending on the model attribute,
edecca
+            see the address element below.
edecca
+          

edecca
           
edecca
         
edecca
         

edecca
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
edecca
index 157726752c..be8430ab22 100644
edecca
--- a/docs/schemas/domaincommon.rng
edecca
+++ b/docs/schemas/domaincommon.rng
edecca
@@ -4579,6 +4579,11 @@
edecca
         <value>vfio-ccw</value>
edecca
       </choice>
edecca
     </attribute>
edecca
+    <optional>
edecca
+      <attribute name="display">
edecca
+        <ref name="virOnOff"/>
edecca
+      </attribute>
edecca
+    </optional>
edecca
     <element name="source">
edecca
       <ref name="mdevaddress"/>
edecca
     </element>
edecca
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
edecca
index 72086f9e86..830c298158 100644
edecca
--- a/src/conf/domain_conf.c
edecca
+++ b/src/conf/domain_conf.c
edecca
@@ -7656,6 +7656,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
edecca
     char *rawio = NULL;
edecca
     char *backendStr = NULL;
edecca
     char *model = NULL;
edecca
+    char *display = NULL;
edecca
     int backend;
edecca
     int ret = -1;
edecca
     virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
edecca
@@ -7675,6 +7676,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
edecca
     sgio = virXMLPropString(node, "sgio");
edecca
     rawio = virXMLPropString(node, "rawio");
edecca
     model = virXMLPropString(node, "model");
edecca
+    display = virXMLPropString(node, "display");
edecca
 
edecca
     /* @type is passed in from the caller rather than read from the
edecca
      * xml document, because it is specified in different places for
edecca
@@ -7762,6 +7764,15 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
edecca
                            model);
edecca
             goto cleanup;
edecca
         }
edecca
+
edecca
+        if (display &&
edecca
+            (mdevsrc->display = virTristateSwitchTypeFromString(display)) <= 0) {
edecca
+            virReportError(VIR_ERR_XML_ERROR,
edecca
+                           _("unknown value '%s' for <hostdev> attribute "
edecca
+                             "'display'"),
edecca
+                           display);
edecca
+            goto cleanup;
edecca
+        }
edecca
     }
edecca
 
edecca
     switch (def->source.subsys.type) {
edecca
@@ -7815,6 +7826,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
edecca
     VIR_FREE(rawio);
edecca
     VIR_FREE(backendStr);
edecca
     VIR_FREE(model);
edecca
+    VIR_FREE(display);
edecca
     return ret;
edecca
 }
edecca
 
edecca
@@ -26568,9 +26580,14 @@ virDomainHostdevDefFormat(virBufferPtr buf,
edecca
                               virTristateBoolTypeToString(scsisrc->rawio));
edecca
         }
edecca
 
edecca
-        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV)
edecca
+        if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV) {
edecca
             virBufferAsprintf(buf, " model='%s'",
edecca
                               virMediatedDeviceModelTypeToString(mdevsrc->model));
edecca
+            if (mdevsrc->display != VIR_TRISTATE_SWITCH_ABSENT)
edecca
+                virBufferAsprintf(buf, " display='%s'",
edecca
+                                  virTristateSwitchTypeToString(mdevsrc->display));
edecca
+        }
edecca
+
edecca
     }
edecca
     virBufferAddLit(buf, ">\n");
edecca
     virBufferAdjustIndent(buf, 2);
edecca
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
edecca
index 3deda1d978..8ca9558ceb 100644
edecca
--- a/src/conf/domain_conf.h
edecca
+++ b/src/conf/domain_conf.h
edecca
@@ -382,6 +382,7 @@ typedef struct _virDomainHostdevSubsysMediatedDev virDomainHostdevSubsysMediated
edecca
 typedef virDomainHostdevSubsysMediatedDev *virDomainHostdevSubsysMediatedDevPtr;
edecca
 struct _virDomainHostdevSubsysMediatedDev {
edecca
     int model;                          /* enum virMediatedDeviceModelType */
edecca
+    int display; /* virTristateSwitch */
edecca
     char uuidstr[VIR_UUID_STRING_BUFLEN];   /* mediated device's uuid string */
edecca
 };
edecca
 
edecca
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
edecca
index 9498594857..5337f1ce55 100644
edecca
--- a/src/qemu/qemu_domain.c
edecca
+++ b/src/qemu/qemu_domain.c
edecca
@@ -4451,9 +4451,48 @@ qemuDomainDeviceDefValidateNetwork(const virDomainNetDef *net)
edecca
 
edecca
 
edecca
 static int
edecca
-qemuDomainDeviceDefValidateHostdev(const virDomainHostdevDef *hostdev,
edecca
-                                   const virDomainDef *def)
edecca
+qemuDomainMdevDefValidate(const virDomainHostdevSubsysMediatedDev *mdevsrc,
edecca
+                          const virDomainDef *def,
edecca
+                          virQEMUCapsPtr qemuCaps)
edecca
 {
edecca
+    if (mdevsrc->display == VIR_TRISTATE_SWITCH_ABSENT)
edecca
+        return 0;
edecca
+
edecca
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VFIO_PCI_DISPLAY)) {
edecca
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
edecca
+                       _("display property of device vfio-pci is "
edecca
+                         "not supported by this version of QEMU"));
edecca
+        return -1;
edecca
+    }
edecca
+
edecca
+    if (mdevsrc->model != VIR_MDEV_MODEL_TYPE_VFIO_PCI) {
edecca
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
edecca
+                       _("<hostdev> attribute 'display' is only supported"
edecca
+                         " with model='vfio-pci'"));
edecca
+
edecca
+        return -1;
edecca
+    }
edecca
+
edecca
+    if (mdevsrc->display == VIR_TRISTATE_SWITCH_ON) {
edecca
+        if (def->ngraphics == 0) {
edecca
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
edecca
+                           _("graphics device is needed for attribute value "
edecca
+                             "'display=on' in <hostdev>"));
edecca
+            return -1;
edecca
+        }
edecca
+    }
edecca
+
edecca
+    return 0;
edecca
+}
edecca
+
edecca
+
edecca
+static int
edecca
+qemuDomainDeviceDefValidateHostdev(const virDomainHostdevDef *hostdev,
edecca
+                                   const virDomainDef *def,
edecca
+                                   virQEMUCapsPtr qemuCaps)
edecca
+{
edecca
+    const virDomainHostdevSubsysMediatedDev *mdevsrc;
edecca
+
edecca
     /* forbid capabilities mode hostdev in this kind of hypervisor */
edecca
     if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
edecca
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
edecca
@@ -4463,6 +4502,24 @@ qemuDomainDeviceDefValidateHostdev(const virDomainHostdevDef *hostdev,
edecca
         return -1;
edecca
     }
edecca
 
edecca
+    if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
edecca
+        switch ((virDomainHostdevSubsysType) hostdev->source.subsys.type) {
edecca
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
edecca
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
edecca
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
edecca
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
edecca
+            break;
edecca
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
edecca
+            mdevsrc = &hostdev->source.subsys.u.mdev;
edecca
+            return qemuDomainMdevDefValidate(mdevsrc, def, qemuCaps);
edecca
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
edecca
+        default:
edecca
+            virReportEnumRangeError(virDomainHostdevSubsysType,
edecca
+                                    hostdev->source.subsys.type);
edecca
+            return -1;
edecca
+        }
edecca
+    }
edecca
+
edecca
     return 0;
edecca
 }
edecca
 
edecca
@@ -5595,7 +5652,8 @@ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev,
edecca
         break;
edecca
 
edecca
     case VIR_DOMAIN_DEVICE_HOSTDEV:
edecca
-        ret = qemuDomainDeviceDefValidateHostdev(dev->data.hostdev, def);
edecca
+        ret = qemuDomainDeviceDefValidateHostdev(dev->data.hostdev, def,
edecca
+                                                 qemuCaps);
edecca
         break;
edecca
 
edecca
     case VIR_DOMAIN_DEVICE_VIDEO:
edecca
@@ -6205,6 +6263,35 @@ qemuDomainVsockDefPostParse(virDomainVsockDefPtr vsock)
edecca
 }
edecca
 
edecca
 
edecca
+static int
edecca
+qemuDomainHostdevDefMdevPostParse(virDomainHostdevSubsysMediatedDevPtr mdevsrc,
edecca
+                                  virQEMUCapsPtr qemuCaps)
edecca
+{
edecca
+    /* QEMU 2.12 added support for vfio-pci display type, we default to
edecca
+     * 'display=off' to stay safe from future changes */
edecca
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VFIO_PCI_DISPLAY) &&
edecca
+        mdevsrc->display == VIR_TRISTATE_SWITCH_ABSENT)
edecca
+        mdevsrc->display = VIR_TRISTATE_SWITCH_OFF;
edecca
+
edecca
+    return 0;
edecca
+}
edecca
+
edecca
+
edecca
+static int
edecca
+qemuDomainHostdevDefPostParse(virDomainHostdevDefPtr hostdev,
edecca
+                              virQEMUCapsPtr qemuCaps)
edecca
+{
edecca
+    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
edecca
+
edecca
+    if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
edecca
+        hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV &&
edecca
+        qemuDomainHostdevDefMdevPostParse(&subsys->u.mdev, qemuCaps) < 0)
edecca
+        return -1;
edecca
+
edecca
+    return 0;
edecca
+}
edecca
+
edecca
+
edecca
 static int
edecca
 qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
edecca
                              const virDomainDef *def,
edecca
@@ -6255,11 +6342,14 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
edecca
         ret = qemuDomainVsockDefPostParse(dev->data.vsock);
edecca
         break;
edecca
 
edecca
+    case VIR_DOMAIN_DEVICE_HOSTDEV:
edecca
+        ret = qemuDomainHostdevDefPostParse(dev->data.hostdev, qemuCaps);
edecca
+        break;
edecca
+
edecca
     case VIR_DOMAIN_DEVICE_LEASE:
edecca
     case VIR_DOMAIN_DEVICE_FS:
edecca
     case VIR_DOMAIN_DEVICE_INPUT:
edecca
     case VIR_DOMAIN_DEVICE_SOUND:
edecca
-    case VIR_DOMAIN_DEVICE_HOSTDEV:
edecca
     case VIR_DOMAIN_DEVICE_WATCHDOG:
edecca
     case VIR_DOMAIN_DEVICE_GRAPHICS:
edecca
     case VIR_DOMAIN_DEVICE_HUB:
edecca
diff --git a/tests/qemuxml2argvdata/hostdev-mdev-display.xml b/tests/qemuxml2argvdata/hostdev-mdev-display.xml
edecca
new file mode 100644
edecca
index 0000000000..f37e08e1b9
edecca
--- /dev/null
edecca
+++ b/tests/qemuxml2argvdata/hostdev-mdev-display.xml
edecca
@@ -0,0 +1,39 @@
edecca
+<domain type='qemu'>
edecca
+  <name>QEMUGuest2</name>
edecca
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
edecca
+  <memory unit='KiB'>219136</memory>
edecca
+  <currentMemory unit='KiB'>219136</currentMemory>
edecca
+  <vcpu placement='static'>1</vcpu>
edecca
+  <os>
edecca
+    <type arch='i686' machine='pc'>hvm</type>
edecca
+    <boot dev='hd'/>
edecca
+  </os>
edecca
+  <clock offset='utc'/>
edecca
+  <on_poweroff>destroy</on_poweroff>
edecca
+  <on_reboot>restart</on_reboot>
edecca
+  <on_crash>destroy</on_crash>
edecca
+  <devices>
edecca
+    <emulator>/usr/bin/qemu-system-i686</emulator>
edecca
+    <disk type='block' device='disk'>
edecca
+      <driver name='qemu' type='raw'/>
edecca
+      <source dev='/dev/HostVG/QEMUGuest2'/>
edecca
+      <target dev='hda' bus='ide'/>
edecca
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
edecca
+    </disk>
edecca
+    <controller type='usb' index='0'>
edecca
+    </controller>
edecca
+    <controller type='pci' index='0' model='pci-root'/>
edecca
+    <controller type='ide' index='0'>
edecca
+    </controller>
edecca
+    <graphics type='vnc'/>
edecca
+    <hostdev mode='subsystem' type='mdev' model='vfio-pci' display='on'>
edecca
+      <source>
edecca
+        <address uuid='53764d0e-85a0-42b4-af5c-2046b460b1dc'/>
edecca
+      </source>
edecca
+    </hostdev>
edecca
+    <video>
edecca
+      <model type='qxl' heads='1'/>
edecca
+    </video>
edecca
+    <memballoon model='none'/>
edecca
+  </devices>
edecca
+</domain>
edecca
diff --git a/tests/qemuxml2xmloutdata/hostdev-mdev-display.xml b/tests/qemuxml2xmloutdata/hostdev-mdev-display.xml
edecca
new file mode 100644
edecca
index 0000000000..94c11b1199
edecca
--- /dev/null
edecca
+++ b/tests/qemuxml2xmloutdata/hostdev-mdev-display.xml
edecca
@@ -0,0 +1,47 @@
edecca
+<domain type='qemu'>
edecca
+  <name>QEMUGuest2</name>
edecca
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
edecca
+  <memory unit='KiB'>219136</memory>
edecca
+  <currentMemory unit='KiB'>219136</currentMemory>
edecca
+  <vcpu placement='static'>1</vcpu>
edecca
+  <os>
edecca
+    <type arch='i686' machine='pc'>hvm</type>
edecca
+    <boot dev='hd'/>
edecca
+  </os>
edecca
+  <clock offset='utc'/>
edecca
+  <on_poweroff>destroy</on_poweroff>
edecca
+  <on_reboot>restart</on_reboot>
edecca
+  <on_crash>destroy</on_crash>
edecca
+  <devices>
edecca
+    <emulator>/usr/bin/qemu-system-i686</emulator>
edecca
+    <disk type='block' device='disk'>
edecca
+      <driver name='qemu' type='raw'/>
edecca
+      <source dev='/dev/HostVG/QEMUGuest2'/>
edecca
+      <target dev='hda' bus='ide'/>
edecca
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
edecca
+    </disk>
edecca
+    <controller type='usb' index='0'>
edecca
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
edecca
+    </controller>
edecca
+    <controller type='pci' index='0' model='pci-root'/>
edecca
+    <controller type='ide' index='0'>
edecca
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
edecca
+    </controller>
edecca
+    <input type='mouse' bus='ps2'/>
edecca
+    <input type='keyboard' bus='ps2'/>
edecca
+    <graphics type='vnc' port='-1' autoport='yes'>
edecca
+      <listen type='address'/>
edecca
+    </graphics>
edecca
+    <video>
edecca
+      <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
edecca
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
edecca
+    </video>
edecca
+    <hostdev mode='subsystem' type='mdev' managed='no' model='vfio-pci' display='on'>
edecca
+      <source>
edecca
+        <address uuid='53764d0e-85a0-42b4-af5c-2046b460b1dc'/>
edecca
+      </source>
edecca
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
edecca
+    </hostdev>
edecca
+    <memballoon model='none'/>
edecca
+  </devices>
edecca
+</domain>
edecca
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
edecca
index fa57221d62..e418e67f6c 100644
edecca
--- a/tests/qemuxml2xmltest.c
edecca
+++ b/tests/qemuxml2xmltest.c
edecca
@@ -479,6 +479,7 @@ mymain(void)
edecca
     DO_TEST("hostdev-pci-address", NONE);
edecca
     DO_TEST("hostdev-vfio", NONE);
edecca
     DO_TEST("hostdev-mdev-precreated", NONE);
edecca
+    DO_TEST("hostdev-mdev-display", QEMU_CAPS_VFIO_PCI_DISPLAY);
edecca
     DO_TEST("pci-rom", NONE);
edecca
     DO_TEST("pci-rom-disabled", NONE);
edecca
     DO_TEST("pci-rom-disabled-invalid", NONE);
edecca
-- 
edecca
2.18.0
edecca