[PATCH] hostdev:Introduce vDPA device to hostdev subsystem as a new subtype

libai posted 1 patch 1 year, 7 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20230424033607.16356-1-libai12@huawei.com
There is a newer version of this series
src/conf/domain_audit.c         |  4 +++
src/conf/domain_conf.c          | 47 +++++++++++++++++++++++++++++++++
src/conf/domain_conf.h          |  6 +++++
src/conf/domain_validate.c      |  1 +
src/conf/virconftypes.h         |  2 ++
src/qemu/qemu_command.c         | 19 +++++++++++++
src/qemu/qemu_command.h         |  3 +++
src/qemu/qemu_domain.c          |  6 +++++
src/qemu/qemu_hotplug.c         |  1 +
src/qemu/qemu_migration.c       |  2 ++
src/qemu/qemu_validate.c        |  2 ++
src/security/security_dac.c     |  2 ++
src/security/security_selinux.c |  2 ++
13 files changed, 97 insertions(+)
[PATCH] hostdev:Introduce vDPA device to hostdev subsystem as a new subtype
Posted by libai 1 year, 7 months ago
The following is the xml of vdpa device:
<devices>
    <hostdev mode='subsystem' type='vdpa'>
        <source dev='/dev/vhost-vdpa-0'/>
    </hostdev>
</devices>
And the command line passed to QEMU is as follows:
-device {"driver":"vhost-vdpa-device-pci","vhostdev":"/dev/vhost-vdpa-0"}

This solution is selected according to the previous discussion
on the solution of supporting the vDPA device.
For details, see the following:
https://listman.redhat.com/archives/libvir-list/2023-March/239018.html

Signed-off-by: libai <libai12@huawei.com>
---
 src/conf/domain_audit.c         |  4 +++
 src/conf/domain_conf.c          | 47 +++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h          |  6 +++++
 src/conf/domain_validate.c      |  1 +
 src/conf/virconftypes.h         |  2 ++
 src/qemu/qemu_command.c         | 19 +++++++++++++
 src/qemu/qemu_command.h         |  3 +++
 src/qemu/qemu_domain.c          |  6 +++++
 src/qemu/qemu_hotplug.c         |  1 +
 src/qemu/qemu_migration.c       |  2 ++
 src/qemu/qemu_validate.c        |  2 ++
 src/security/security_dac.c     |  2 ++
 src/security/security_selinux.c |  2 ++
 13 files changed, 97 insertions(+)

diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
index ae875188bd..6906ce7ade 100644
--- a/src/conf/domain_audit.c
+++ b/src/conf/domain_audit.c
@@ -344,6 +344,7 @@ virDomainAuditHostdev(virDomainObj *vm, virDomainHostdevDef *hostdev,
     virDomainHostdevSubsysSCSI *scsisrc = &hostdev->source.subsys.u.scsi;
     virDomainHostdevSubsysSCSIVHost *hostsrc = &hostdev->source.subsys.u.scsi_host;
     virDomainHostdevSubsysMediatedDev *mdevsrc = &hostdev->source.subsys.u.mdev;
+    virDomainHostdevSubsysVDPA *vdpasrc = &hostdev->source.subsys.u.vdpa;
 
     virUUIDFormat(vm->def->uuid, uuidstr);
     if (!(vmname = virAuditEncode("vm", vm->def->name))) {
@@ -383,6 +384,9 @@ virDomainAuditHostdev(virDomainObj *vm, virDomainHostdevDef *hostdev,
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
             address = g_strdup(mdevsrc->uuidstr);
             break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+            address = g_strdup(vdpasrc->devpath);
+            break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         default:
             VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b03a3ff011..e8f6d1457b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1047,6 +1047,7 @@ VIR_ENUM_IMPL(virDomainHostdevSubsys,
               "scsi",
               "scsi_host",
               "mdev",
+              "vdpa",
 );
 
 VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend,
@@ -2641,6 +2642,9 @@ virDomainHostdevDefClear(virDomainHostdevDef *def)
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
             g_clear_pointer(&def->source.subsys.u.pci.origstates, virBitmapFree);
             break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+            VIR_FREE(def->source.subsys.u.vdpa.devpath);
+            break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
@@ -6160,6 +6164,22 @@ virDomainHostdevSubsysMediatedDevDefParseXML(virDomainHostdevDef *def,
     return 0;
 }
 
+static int
+virDomainHostdevSubsysVDPADefParseXML(xmlNodePtr sourcenode,
+                                      virDomainHostdevDef *def)
+{
+    g_autofree char *devpath = NULL;
+    virDomainHostdevSubsysVDPA *vdpa = &def->source.subsys.u.vdpa;
+
+    if(!(devpath = virXMLPropString(sourcenode, "dev"))) {
+       virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                      _("Missing 'dev' attribute for element <source>"));
+       return -1;
+    }
+    vdpa->devpath = g_steal_pointer(&devpath);
+    return 0;
+}
+
 static int
 virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
                                   xmlXPathContextPtr ctxt,
@@ -6317,6 +6337,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
         if (virDomainHostdevSubsysMediatedDevDefParseXML(def, ctxt) < 0)
             return -1;
         break;
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+        if (virDomainHostdevSubsysVDPADefParseXML(sourcenode, def) < 0) {
+            return -1;
+        }
+        break;
 
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -12979,6 +13004,7 @@ virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt,
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
             break;
         }
@@ -14101,6 +14127,13 @@ virDomainHostdevMatchSubsys(virDomainHostdevDef *a,
             return 0;
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
         return virDomainHostdevMatchSubsysMediatedDev(a, b);
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+        if (STREQ(a->source.subsys.u.vdpa.devpath,
+                  b->source.subsys.u.vdpa.devpath)) {
+            return 1;
+        } else {
+            return 0;
+        }
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         return 0;
     }
@@ -23290,6 +23323,16 @@ virDomainHostdevDefFormatSubsysMdev(virBuffer *buf,
     virXMLFormatElement(buf, "source", NULL, &sourceChildBuf);
 }
 
+static void
+virDomainHostdevDefFormatSubsysVDPA(virBuffer *buf,
+                                    virDomainHostdevDef *def)
+{
+    g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER;
+    virDomainHostdevSubsysVDPA *vdpasrc = &def->source.subsys.u.vdpa;
+    virBufferAsprintf(&sourceAttrBuf, " dev='%s'", vdpasrc->devpath);
+    virXMLFormatElement(buf, "source", &sourceAttrBuf, NULL);
+}
+
 
 static int
 virDomainHostdevDefFormatSubsys(virBuffer *buf,
@@ -23317,6 +23360,10 @@ virDomainHostdevDefFormatSubsys(virBuffer *buf,
         virDomainHostdevDefFormatSubsysMdev(buf, def);
         return 0;
 
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+        virDomainHostdevDefFormatSubsysVDPA(buf, def);
+        return 0;
+
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
     default:
         virReportEnumRangeError(virDomainHostdevSubsysType, def->source.subsys.type);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 511067a050..ade8b0edec 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -197,6 +197,7 @@ typedef enum {
     VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
     VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST,
     VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV,
+    VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA,
 
     VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST
 } virDomainHostdevSubsysType;
@@ -289,6 +290,10 @@ struct _virDomainHostdevSubsysMediatedDev {
     virTristateSwitch ramfb;
 };
 
+struct _virDomainHostdevSubsysVDPA {
+    char *devpath; /* vDPA device path */
+};
+
 typedef enum {
     VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_NONE,
     VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST,
@@ -323,6 +328,7 @@ struct _virDomainHostdevSubsys {
         virDomainHostdevSubsysSCSI scsi;
         virDomainHostdevSubsysSCSIVHost scsi_host;
         virDomainHostdevSubsysMediatedDev mdev;
+        virDomainHostdevSubsysVDPA vdpa;
     } u;
 };
 
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index e04b85fee4..4af84c4f0c 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -2214,6 +2214,7 @@ virDomainHostdevDefValidate(const virDomainHostdevDef *hostdev)
             }
             break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
             break;
         }
diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index e07f967814..1756c54e7a 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -120,6 +120,8 @@ typedef struct _virDomainHostdevSubsys virDomainHostdevSubsys;
 
 typedef struct _virDomainHostdevSubsysMediatedDev virDomainHostdevSubsysMediatedDev;
 
+typedef struct _virDomainHostdevSubsysVDPA virDomainHostdevSubsysVDPA;
+
 typedef struct _virDomainHostdevSubsysPCI virDomainHostdevSubsysPCI;
 
 typedef struct _virDomainHostdevSubsysSCSI virDomainHostdevSubsysSCSI;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 4ca93bf3dc..121214f4d5 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4958,6 +4958,18 @@ qemuBuildHostdevMediatedDevProps(const virDomainDef *def,
     return g_steal_pointer(&props);
 }
 
+virJSONValue *
+qemuBuildHostdevVDPADevProps(virDomainHostdevDef *dev)
+{
+    g_autoptr(virJSONValue) props = NULL;
+    virDomainHostdevSubsysVDPA *vdpasrc = &dev->source.subsys.u.vdpa;
+    if (virJSONValueObjectAdd(&props,
+                              "s:driver", "vhost-vdpa-device-pci",
+                              "s:vhostdev", vdpasrc->devpath,
+                              NULL) < 0)
+        return NULL;
+    return g_steal_pointer(&props);
+}
 
 qemuBlockStorageSourceAttachData *
 qemuBuildHostdevSCSIDetachPrepare(virDomainHostdevDef *hostdev,
@@ -5154,6 +5166,13 @@ qemuBuildHostdevCommandLine(virCommand *cmd,
                 return -1;
             break;
 
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+            if (!(devprops = qemuBuildHostdevVDPADevProps(hostdev)))
+                return -1;
+            if (qemuBuildDeviceCommandlineFromJSON(cmd, devprops, def, qemuCaps) < 0)
+                return -1;
+            break;
+
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
             break;
         }
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 5fdb138030..dff18350b5 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -198,6 +198,9 @@ virJSONValue *
 qemuBuildHostdevMediatedDevProps(const virDomainDef *def,
                                  virDomainHostdevDef *dev);
 
+virJSONValue *
+qemuBuildHostdevVDPADevProps(virDomainHostdevDef *dev);
+
 virJSONValue *
 qemuBuildRedirdevDevProps(const virDomainDef *def,
                           virDomainRedirdevDef *dev);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 63b13b6875..0cd485a459 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -10533,6 +10533,8 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev,
     virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi;
     virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host;
     virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev;
+    virDomainHostdevSubsysVDPA *vdpasrc = &dev->source.subsys.u.vdpa;
+
     g_autoptr(virUSBDevice) usb = NULL;
     g_autoptr(virSCSIDevice) scsi = NULL;
     g_autoptr(virSCSIVHostDevice) host = NULL;
@@ -10603,6 +10605,10 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev,
             if (!(tmpPath = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr)))
                 return -1;
 
+            perm = VIR_CGROUP_DEVICE_RW;
+            break;
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+            tmpPath = g_strdup(vdpasrc->devpath);
             perm = VIR_CGROUP_DEVICE_RW;
             break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 5072798cb7..7d89899223 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -4546,6 +4546,7 @@ qemuDomainRemoveHostDevice(virQEMUDriver *driver,
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
         qemuDomainRemoveMediatedDevice(driver, vm, hostdev);
         break;
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         break;
     }
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index ed41a03851..9220ef1ab1 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1295,6 +1295,8 @@ qemuMigrationSrcIsAllowedHostdev(const virDomainDef *def)
             case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
             case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
             case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
+                /* The vDPA devices don't support migration for now */
+            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
                 virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                                _("cannot migrate a domain with <hostdev mode='subsystem' type='%1$s'>"),
                                virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index b8d5e9bd74..ea3d4e1a39 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -2566,6 +2566,8 @@ qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev,
             break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
             return qemuValidateDomainMdevDef(hostdev, def, qemuCaps);
+        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
+            break;
         case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         default:
             virReportEnumRangeError(virDomainHostdevSubsysType,
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index c7dc145621..24f3de5d15 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1313,6 +1313,7 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr,
         break;
     }
 
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         ret = 0;
         break;
@@ -1469,6 +1470,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr,
         break;
     }
 
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         ret = 0;
         break;
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index e3e6a6115f..5cb6612fbc 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -2265,6 +2265,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr,
         break;
     }
 
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         ret = 0;
         break;
@@ -2493,6 +2494,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr,
         break;
     }
 
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
     case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
         ret = 0;
         break;
-- 
2.33.0
Re: [PATCH] hostdev:Introduce vDPA device to hostdev subsystem as a new subtype
Posted by Jason Wang 1 year, 6 months ago
On Mon, Apr 24, 2023 at 11:55 AM libai <libai12@huawei.com> wrote:
>
> The following is the xml of vdpa device:
> <devices>
>     <hostdev mode='subsystem' type='vdpa'>
>         <source dev='/dev/vhost-vdpa-0'/>
>     </hostdev>
> </devices>
> And the command line passed to QEMU is as follows:
> -device {"driver":"vhost-vdpa-device-pci","vhostdev":"/dev/vhost-vdpa-0"}
>
> This solution is selected according to the previous discussion
> on the solution of supporting the vDPA device.
> For details, see the following:
> https://listman.redhat.com/archives/libvir-list/2023-March/239018.html

It would be also helpful if you can point to some links to explain the
generic vDPA device.

Adding Laine and Jonathon for comments.

Thanks

>
> Signed-off-by: libai <libai12@huawei.com>
> ---
>  src/conf/domain_audit.c         |  4 +++
>  src/conf/domain_conf.c          | 47 +++++++++++++++++++++++++++++++++
>  src/conf/domain_conf.h          |  6 +++++
>  src/conf/domain_validate.c      |  1 +
>  src/conf/virconftypes.h         |  2 ++
>  src/qemu/qemu_command.c         | 19 +++++++++++++
>  src/qemu/qemu_command.h         |  3 +++
>  src/qemu/qemu_domain.c          |  6 +++++
>  src/qemu/qemu_hotplug.c         |  1 +
>  src/qemu/qemu_migration.c       |  2 ++
>  src/qemu/qemu_validate.c        |  2 ++
>  src/security/security_dac.c     |  2 ++
>  src/security/security_selinux.c |  2 ++
>  13 files changed, 97 insertions(+)
>
> diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
> index ae875188bd..6906ce7ade 100644
> --- a/src/conf/domain_audit.c
> +++ b/src/conf/domain_audit.c
> @@ -344,6 +344,7 @@ virDomainAuditHostdev(virDomainObj *vm, virDomainHostdevDef *hostdev,
>      virDomainHostdevSubsysSCSI *scsisrc = &hostdev->source.subsys.u.scsi;
>      virDomainHostdevSubsysSCSIVHost *hostsrc = &hostdev->source.subsys.u.scsi_host;
>      virDomainHostdevSubsysMediatedDev *mdevsrc = &hostdev->source.subsys.u.mdev;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &hostdev->source.subsys.u.vdpa;
>
>      virUUIDFormat(vm->def->uuid, uuidstr);
>      if (!(vmname = virAuditEncode("vm", vm->def->name))) {
> @@ -383,6 +384,9 @@ virDomainAuditHostdev(virDomainObj *vm, virDomainHostdevDef *hostdev,
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>              address = g_strdup(mdevsrc->uuidstr);
>              break;
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            address = g_strdup(vdpasrc->devpath);
> +            break;
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          default:
>              VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index b03a3ff011..e8f6d1457b 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -1047,6 +1047,7 @@ VIR_ENUM_IMPL(virDomainHostdevSubsys,
>                "scsi",
>                "scsi_host",
>                "mdev",
> +              "vdpa",
>  );
>
>  VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend,
> @@ -2641,6 +2642,9 @@ virDomainHostdevDefClear(virDomainHostdevDef *def)
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
>              g_clear_pointer(&def->source.subsys.u.pci.origstates, virBitmapFree);
>              break;
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            VIR_FREE(def->source.subsys.u.vdpa.devpath);
> +            break;
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
> @@ -6160,6 +6164,22 @@ virDomainHostdevSubsysMediatedDevDefParseXML(virDomainHostdevDef *def,
>      return 0;
>  }
>
> +static int
> +virDomainHostdevSubsysVDPADefParseXML(xmlNodePtr sourcenode,
> +                                      virDomainHostdevDef *def)
> +{
> +    g_autofree char *devpath = NULL;
> +    virDomainHostdevSubsysVDPA *vdpa = &def->source.subsys.u.vdpa;
> +
> +    if(!(devpath = virXMLPropString(sourcenode, "dev"))) {
> +       virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                      _("Missing 'dev' attribute for element <source>"));
> +       return -1;
> +    }
> +    vdpa->devpath = g_steal_pointer(&devpath);
> +    return 0;
> +}
> +
>  static int
>  virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
>                                    xmlXPathContextPtr ctxt,
> @@ -6317,6 +6337,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
>          if (virDomainHostdevSubsysMediatedDevDefParseXML(def, ctxt) < 0)
>              return -1;
>          break;
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +        if (virDomainHostdevSubsysVDPADefParseXML(sourcenode, def) < 0) {
> +            return -1;
> +        }
> +        break;
>
>      default:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> @@ -12979,6 +13004,7 @@ virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt,
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>              break;
>          }
> @@ -14101,6 +14127,13 @@ virDomainHostdevMatchSubsys(virDomainHostdevDef *a,
>              return 0;
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>          return virDomainHostdevMatchSubsysMediatedDev(a, b);
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +        if (STREQ(a->source.subsys.u.vdpa.devpath,
> +                  b->source.subsys.u.vdpa.devpath)) {
> +            return 1;
> +        } else {
> +            return 0;
> +        }
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          return 0;
>      }
> @@ -23290,6 +23323,16 @@ virDomainHostdevDefFormatSubsysMdev(virBuffer *buf,
>      virXMLFormatElement(buf, "source", NULL, &sourceChildBuf);
>  }
>
> +static void
> +virDomainHostdevDefFormatSubsysVDPA(virBuffer *buf,
> +                                    virDomainHostdevDef *def)
> +{
> +    g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &def->source.subsys.u.vdpa;
> +    virBufferAsprintf(&sourceAttrBuf, " dev='%s'", vdpasrc->devpath);
> +    virXMLFormatElement(buf, "source", &sourceAttrBuf, NULL);
> +}
> +
>
>  static int
>  virDomainHostdevDefFormatSubsys(virBuffer *buf,
> @@ -23317,6 +23360,10 @@ virDomainHostdevDefFormatSubsys(virBuffer *buf,
>          virDomainHostdevDefFormatSubsysMdev(buf, def);
>          return 0;
>
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +        virDomainHostdevDefFormatSubsysVDPA(buf, def);
> +        return 0;
> +
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>      default:
>          virReportEnumRangeError(virDomainHostdevSubsysType, def->source.subsys.type);
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 511067a050..ade8b0edec 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -197,6 +197,7 @@ typedef enum {
>      VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
>      VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST,
>      VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV,
> +    VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA,
>
>      VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST
>  } virDomainHostdevSubsysType;
> @@ -289,6 +290,10 @@ struct _virDomainHostdevSubsysMediatedDev {
>      virTristateSwitch ramfb;
>  };
>
> +struct _virDomainHostdevSubsysVDPA {
> +    char *devpath; /* vDPA device path */
> +};
> +
>  typedef enum {
>      VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_NONE,
>      VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST,
> @@ -323,6 +328,7 @@ struct _virDomainHostdevSubsys {
>          virDomainHostdevSubsysSCSI scsi;
>          virDomainHostdevSubsysSCSIVHost scsi_host;
>          virDomainHostdevSubsysMediatedDev mdev;
> +        virDomainHostdevSubsysVDPA vdpa;
>      } u;
>  };
>
> diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
> index e04b85fee4..4af84c4f0c 100644
> --- a/src/conf/domain_validate.c
> +++ b/src/conf/domain_validate.c
> @@ -2214,6 +2214,7 @@ virDomainHostdevDefValidate(const virDomainHostdevDef *hostdev)
>              }
>              break;
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>              break;
>          }
> diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
> index e07f967814..1756c54e7a 100644
> --- a/src/conf/virconftypes.h
> +++ b/src/conf/virconftypes.h
> @@ -120,6 +120,8 @@ typedef struct _virDomainHostdevSubsys virDomainHostdevSubsys;
>
>  typedef struct _virDomainHostdevSubsysMediatedDev virDomainHostdevSubsysMediatedDev;
>
> +typedef struct _virDomainHostdevSubsysVDPA virDomainHostdevSubsysVDPA;
> +
>  typedef struct _virDomainHostdevSubsysPCI virDomainHostdevSubsysPCI;
>
>  typedef struct _virDomainHostdevSubsysSCSI virDomainHostdevSubsysSCSI;
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 4ca93bf3dc..121214f4d5 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -4958,6 +4958,18 @@ qemuBuildHostdevMediatedDevProps(const virDomainDef *def,
>      return g_steal_pointer(&props);
>  }
>
> +virJSONValue *
> +qemuBuildHostdevVDPADevProps(virDomainHostdevDef *dev)
> +{
> +    g_autoptr(virJSONValue) props = NULL;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &dev->source.subsys.u.vdpa;
> +    if (virJSONValueObjectAdd(&props,
> +                              "s:driver", "vhost-vdpa-device-pci",
> +                              "s:vhostdev", vdpasrc->devpath,
> +                              NULL) < 0)
> +        return NULL;
> +    return g_steal_pointer(&props);
> +}
>
>  qemuBlockStorageSourceAttachData *
>  qemuBuildHostdevSCSIDetachPrepare(virDomainHostdevDef *hostdev,
> @@ -5154,6 +5166,13 @@ qemuBuildHostdevCommandLine(virCommand *cmd,
>                  return -1;
>              break;
>
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            if (!(devprops = qemuBuildHostdevVDPADevProps(hostdev)))
> +                return -1;
> +            if (qemuBuildDeviceCommandlineFromJSON(cmd, devprops, def, qemuCaps) < 0)
> +                return -1;
> +            break;
> +
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>              break;
>          }
> diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
> index 5fdb138030..dff18350b5 100644
> --- a/src/qemu/qemu_command.h
> +++ b/src/qemu/qemu_command.h
> @@ -198,6 +198,9 @@ virJSONValue *
>  qemuBuildHostdevMediatedDevProps(const virDomainDef *def,
>                                   virDomainHostdevDef *dev);
>
> +virJSONValue *
> +qemuBuildHostdevVDPADevProps(virDomainHostdevDef *dev);
> +
>  virJSONValue *
>  qemuBuildRedirdevDevProps(const virDomainDef *def,
>                            virDomainRedirdevDef *dev);
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 63b13b6875..0cd485a459 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -10533,6 +10533,8 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev,
>      virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi;
>      virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host;
>      virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &dev->source.subsys.u.vdpa;
> +
>      g_autoptr(virUSBDevice) usb = NULL;
>      g_autoptr(virSCSIDevice) scsi = NULL;
>      g_autoptr(virSCSIVHostDevice) host = NULL;
> @@ -10603,6 +10605,10 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev,
>              if (!(tmpPath = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr)))
>                  return -1;
>
> +            perm = VIR_CGROUP_DEVICE_RW;
> +            break;
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            tmpPath = g_strdup(vdpasrc->devpath);
>              perm = VIR_CGROUP_DEVICE_RW;
>              break;
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 5072798cb7..7d89899223 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -4546,6 +4546,7 @@ qemuDomainRemoveHostDevice(virQEMUDriver *driver,
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>          qemuDomainRemoveMediatedDevice(driver, vm, hostdev);
>          break;
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          break;
>      }
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index ed41a03851..9220ef1ab1 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -1295,6 +1295,8 @@ qemuMigrationSrcIsAllowedHostdev(const virDomainDef *def)
>              case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
>              case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
>              case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
> +                /* The vDPA devices don't support migration for now */
> +            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>                  virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                                 _("cannot migrate a domain with <hostdev mode='subsystem' type='%1$s'>"),
>                                 virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
> diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
> index b8d5e9bd74..ea3d4e1a39 100644
> --- a/src/qemu/qemu_validate.c
> +++ b/src/qemu/qemu_validate.c
> @@ -2566,6 +2566,8 @@ qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev,
>              break;
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>              return qemuValidateDomainMdevDef(hostdev, def, qemuCaps);
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            break;
>          case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          default:
>              virReportEnumRangeError(virDomainHostdevSubsysType,
> diff --git a/src/security/security_dac.c b/src/security/security_dac.c
> index c7dc145621..24f3de5d15 100644
> --- a/src/security/security_dac.c
> +++ b/src/security/security_dac.c
> @@ -1313,6 +1313,7 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr,
>          break;
>      }
>
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          ret = 0;
>          break;
> @@ -1469,6 +1470,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr,
>          break;
>      }
>
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          ret = 0;
>          break;
> diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
> index e3e6a6115f..5cb6612fbc 100644
> --- a/src/security/security_selinux.c
> +++ b/src/security/security_selinux.c
> @@ -2265,6 +2265,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr,
>          break;
>      }
>
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          ret = 0;
>          break;
> @@ -2493,6 +2494,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr,
>          break;
>      }
>
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          ret = 0;
>          break;
> --
> 2.33.0
>
[RFC PATCH] hostdev:Introduce vDPA device to hostdev subsystem as a new subtype
Posted by libai (G) 1 year, 6 months ago
ping

在 2023/4/24 11:36, libai 写道:
> The following is the xml of vdpa device:
> <devices>
>      <hostdev mode='subsystem' type='vdpa'>
>          <source dev='/dev/vhost-vdpa-0'/>
>      </hostdev>
> </devices>
> And the command line passed to QEMU is as follows:
> -device {"driver":"vhost-vdpa-device-pci","vhostdev":"/dev/vhost-vdpa-0"}
>
> This solution is selected according to the previous discussion
> on the solution of supporting the vDPA device.
> For details, see the following:
> https://listman.redhat.com/archives/libvir-list/2023-March/239018.html
>
> Signed-off-by: libai <libai12@huawei.com>
> ---
>   src/conf/domain_audit.c         |  4 +++
>   src/conf/domain_conf.c          | 47 +++++++++++++++++++++++++++++++++
>   src/conf/domain_conf.h          |  6 +++++
>   src/conf/domain_validate.c      |  1 +
>   src/conf/virconftypes.h         |  2 ++
>   src/qemu/qemu_command.c         | 19 +++++++++++++
>   src/qemu/qemu_command.h         |  3 +++
>   src/qemu/qemu_domain.c          |  6 +++++
>   src/qemu/qemu_hotplug.c         |  1 +
>   src/qemu/qemu_migration.c       |  2 ++
>   src/qemu/qemu_validate.c        |  2 ++
>   src/security/security_dac.c     |  2 ++
>   src/security/security_selinux.c |  2 ++
>   13 files changed, 97 insertions(+)
>
> diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
> index ae875188bd..6906ce7ade 100644
> --- a/src/conf/domain_audit.c
> +++ b/src/conf/domain_audit.c
> @@ -344,6 +344,7 @@ virDomainAuditHostdev(virDomainObj *vm, virDomainHostdevDef *hostdev,
>       virDomainHostdevSubsysSCSI *scsisrc = &hostdev->source.subsys.u.scsi;
>       virDomainHostdevSubsysSCSIVHost *hostsrc = &hostdev->source.subsys.u.scsi_host;
>       virDomainHostdevSubsysMediatedDev *mdevsrc = &hostdev->source.subsys.u.mdev;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &hostdev->source.subsys.u.vdpa;
>   
>       virUUIDFormat(vm->def->uuid, uuidstr);
>       if (!(vmname = virAuditEncode("vm", vm->def->name))) {
> @@ -383,6 +384,9 @@ virDomainAuditHostdev(virDomainObj *vm, virDomainHostdevDef *hostdev,
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>               address = g_strdup(mdevsrc->uuidstr);
>               break;
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            address = g_strdup(vdpasrc->devpath);
> +            break;
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           default:
>               VIR_WARN("Unexpected hostdev type while encoding audit message: %d",
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index b03a3ff011..e8f6d1457b 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -1047,6 +1047,7 @@ VIR_ENUM_IMPL(virDomainHostdevSubsys,
>                 "scsi",
>                 "scsi_host",
>                 "mdev",
> +              "vdpa",
>   );
>   
>   VIR_ENUM_IMPL(virDomainHostdevSubsysPCIBackend,
> @@ -2641,6 +2642,9 @@ virDomainHostdevDefClear(virDomainHostdevDef *def)
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
>               g_clear_pointer(&def->source.subsys.u.pci.origstates, virBitmapFree);
>               break;
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            VIR_FREE(def->source.subsys.u.vdpa.devpath);
> +            break;
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
> @@ -6160,6 +6164,22 @@ virDomainHostdevSubsysMediatedDevDefParseXML(virDomainHostdevDef *def,
>       return 0;
>   }
>   
> +static int
> +virDomainHostdevSubsysVDPADefParseXML(xmlNodePtr sourcenode,
> +                                      virDomainHostdevDef *def)
> +{
> +    g_autofree char *devpath = NULL;
> +    virDomainHostdevSubsysVDPA *vdpa = &def->source.subsys.u.vdpa;
> +
> +    if(!(devpath = virXMLPropString(sourcenode, "dev"))) {
> +       virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                      _("Missing 'dev' attribute for element <source>"));
> +       return -1;
> +    }
> +    vdpa->devpath = g_steal_pointer(&devpath);
> +    return 0;
> +}
> +
>   static int
>   virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
>                                     xmlXPathContextPtr ctxt,
> @@ -6317,6 +6337,11 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
>           if (virDomainHostdevSubsysMediatedDevDefParseXML(def, ctxt) < 0)
>               return -1;
>           break;
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +        if (virDomainHostdevSubsysVDPADefParseXML(sourcenode, def) < 0) {
> +            return -1;
> +        }
> +        break;
>   
>       default:
>           virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> @@ -12979,6 +13004,7 @@ virDomainHostdevDefParseXML(virDomainXMLOption *xmlopt,
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>               break;
>           }
> @@ -14101,6 +14127,13 @@ virDomainHostdevMatchSubsys(virDomainHostdevDef *a,
>               return 0;
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>           return virDomainHostdevMatchSubsysMediatedDev(a, b);
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +        if (STREQ(a->source.subsys.u.vdpa.devpath,
> +                  b->source.subsys.u.vdpa.devpath)) {
> +            return 1;
> +        } else {
> +            return 0;
> +        }
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           return 0;
>       }
> @@ -23290,6 +23323,16 @@ virDomainHostdevDefFormatSubsysMdev(virBuffer *buf,
>       virXMLFormatElement(buf, "source", NULL, &sourceChildBuf);
>   }
>   
> +static void
> +virDomainHostdevDefFormatSubsysVDPA(virBuffer *buf,
> +                                    virDomainHostdevDef *def)
> +{
> +    g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &def->source.subsys.u.vdpa;
> +    virBufferAsprintf(&sourceAttrBuf, " dev='%s'", vdpasrc->devpath);
> +    virXMLFormatElement(buf, "source", &sourceAttrBuf, NULL);
> +}
> +
>   
>   static int
>   virDomainHostdevDefFormatSubsys(virBuffer *buf,
> @@ -23317,6 +23360,10 @@ virDomainHostdevDefFormatSubsys(virBuffer *buf,
>           virDomainHostdevDefFormatSubsysMdev(buf, def);
>           return 0;
>   
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +        virDomainHostdevDefFormatSubsysVDPA(buf, def);
> +        return 0;
> +
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>       default:
>           virReportEnumRangeError(virDomainHostdevSubsysType, def->source.subsys.type);
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 511067a050..ade8b0edec 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -197,6 +197,7 @@ typedef enum {
>       VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI,
>       VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST,
>       VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV,
> +    VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA,
>   
>       VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST
>   } virDomainHostdevSubsysType;
> @@ -289,6 +290,10 @@ struct _virDomainHostdevSubsysMediatedDev {
>       virTristateSwitch ramfb;
>   };
>   
> +struct _virDomainHostdevSubsysVDPA {
> +    char *devpath; /* vDPA device path */
> +};
> +
>   typedef enum {
>       VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_NONE,
>       VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST,
> @@ -323,6 +328,7 @@ struct _virDomainHostdevSubsys {
>           virDomainHostdevSubsysSCSI scsi;
>           virDomainHostdevSubsysSCSIVHost scsi_host;
>           virDomainHostdevSubsysMediatedDev mdev;
> +        virDomainHostdevSubsysVDPA vdpa;
>       } u;
>   };
>   
> diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
> index e04b85fee4..4af84c4f0c 100644
> --- a/src/conf/domain_validate.c
> +++ b/src/conf/domain_validate.c
> @@ -2214,6 +2214,7 @@ virDomainHostdevDefValidate(const virDomainHostdevDef *hostdev)
>               }
>               break;
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>               break;
>           }
> diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
> index e07f967814..1756c54e7a 100644
> --- a/src/conf/virconftypes.h
> +++ b/src/conf/virconftypes.h
> @@ -120,6 +120,8 @@ typedef struct _virDomainHostdevSubsys virDomainHostdevSubsys;
>   
>   typedef struct _virDomainHostdevSubsysMediatedDev virDomainHostdevSubsysMediatedDev;
>   
> +typedef struct _virDomainHostdevSubsysVDPA virDomainHostdevSubsysVDPA;
> +
>   typedef struct _virDomainHostdevSubsysPCI virDomainHostdevSubsysPCI;
>   
>   typedef struct _virDomainHostdevSubsysSCSI virDomainHostdevSubsysSCSI;
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 4ca93bf3dc..121214f4d5 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -4958,6 +4958,18 @@ qemuBuildHostdevMediatedDevProps(const virDomainDef *def,
>       return g_steal_pointer(&props);
>   }
>   
> +virJSONValue *
> +qemuBuildHostdevVDPADevProps(virDomainHostdevDef *dev)
> +{
> +    g_autoptr(virJSONValue) props = NULL;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &dev->source.subsys.u.vdpa;
> +    if (virJSONValueObjectAdd(&props,
> +                              "s:driver", "vhost-vdpa-device-pci",
> +                              "s:vhostdev", vdpasrc->devpath,
> +                              NULL) < 0)
> +        return NULL;
> +    return g_steal_pointer(&props);
> +}
>   
>   qemuBlockStorageSourceAttachData *
>   qemuBuildHostdevSCSIDetachPrepare(virDomainHostdevDef *hostdev,
> @@ -5154,6 +5166,13 @@ qemuBuildHostdevCommandLine(virCommand *cmd,
>                   return -1;
>               break;
>   
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            if (!(devprops = qemuBuildHostdevVDPADevProps(hostdev)))
> +                return -1;
> +            if (qemuBuildDeviceCommandlineFromJSON(cmd, devprops, def, qemuCaps) < 0)
> +                return -1;
> +            break;
> +
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>               break;
>           }
> diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
> index 5fdb138030..dff18350b5 100644
> --- a/src/qemu/qemu_command.h
> +++ b/src/qemu/qemu_command.h
> @@ -198,6 +198,9 @@ virJSONValue *
>   qemuBuildHostdevMediatedDevProps(const virDomainDef *def,
>                                    virDomainHostdevDef *dev);
>   
> +virJSONValue *
> +qemuBuildHostdevVDPADevProps(virDomainHostdevDef *dev);
> +
>   virJSONValue *
>   qemuBuildRedirdevDevProps(const virDomainDef *def,
>                             virDomainRedirdevDef *dev);
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 63b13b6875..0cd485a459 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -10533,6 +10533,8 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev,
>       virDomainHostdevSubsysSCSI *scsisrc = &dev->source.subsys.u.scsi;
>       virDomainHostdevSubsysSCSIVHost *hostsrc = &dev->source.subsys.u.scsi_host;
>       virDomainHostdevSubsysMediatedDev *mdevsrc = &dev->source.subsys.u.mdev;
> +    virDomainHostdevSubsysVDPA *vdpasrc = &dev->source.subsys.u.vdpa;
> +
>       g_autoptr(virUSBDevice) usb = NULL;
>       g_autoptr(virSCSIDevice) scsi = NULL;
>       g_autoptr(virSCSIVHostDevice) host = NULL;
> @@ -10603,6 +10605,10 @@ qemuDomainGetHostdevPath(virDomainHostdevDef *dev,
>               if (!(tmpPath = virMediatedDeviceGetIOMMUGroupDev(mdevsrc->uuidstr)))
>                   return -1;
>   
> +            perm = VIR_CGROUP_DEVICE_RW;
> +            break;
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            tmpPath = g_strdup(vdpasrc->devpath);
>               perm = VIR_CGROUP_DEVICE_RW;
>               break;
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 5072798cb7..7d89899223 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -4546,6 +4546,7 @@ qemuDomainRemoveHostDevice(virQEMUDriver *driver,
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>           qemuDomainRemoveMediatedDevice(driver, vm, hostdev);
>           break;
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           break;
>       }
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index ed41a03851..9220ef1ab1 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -1295,6 +1295,8 @@ qemuMigrationSrcIsAllowedHostdev(const virDomainDef *def)
>               case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
>               case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
>               case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
> +                /* The vDPA devices don't support migration for now */
> +            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>                   virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                                  _("cannot migrate a domain with <hostdev mode='subsystem' type='%1$s'>"),
>                                  virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
> diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
> index b8d5e9bd74..ea3d4e1a39 100644
> --- a/src/qemu/qemu_validate.c
> +++ b/src/qemu/qemu_validate.c
> @@ -2566,6 +2566,8 @@ qemuValidateDomainDeviceDefHostdev(const virDomainHostdevDef *hostdev,
>               break;
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
>               return qemuValidateDomainMdevDef(hostdev, def, qemuCaps);
> +        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
> +            break;
>           case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           default:
>               virReportEnumRangeError(virDomainHostdevSubsysType,
> diff --git a/src/security/security_dac.c b/src/security/security_dac.c
> index c7dc145621..24f3de5d15 100644
> --- a/src/security/security_dac.c
> +++ b/src/security/security_dac.c
> @@ -1313,6 +1313,7 @@ virSecurityDACSetHostdevLabel(virSecurityManager *mgr,
>           break;
>       }
>   
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           ret = 0;
>           break;
> @@ -1469,6 +1470,7 @@ virSecurityDACRestoreHostdevLabel(virSecurityManager *mgr,
>           break;
>       }
>   
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           ret = 0;
>           break;
> diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
> index e3e6a6115f..5cb6612fbc 100644
> --- a/src/security/security_selinux.c
> +++ b/src/security/security_selinux.c
> @@ -2265,6 +2265,7 @@ virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManager *mgr,
>           break;
>       }
>   
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           ret = 0;
>           break;
> @@ -2493,6 +2494,7 @@ virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManager *mgr,
>           break;
>       }
>   
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_VDPA:
>       case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>           ret = 0;
>           break;