[libvirt PATCH v3 3/3] qemu: add vdpa support

Laine Stump laine at redhat.com
Sun Sep 13 19:54:08 UTC 2020


On 9/11/20 5:17 PM, Jonathon Jongsma wrote:
> Enable <interface type='vdpa'> for qemu domains. This provides basic
> support and does not support hotplug or migration.
> 
> Signed-off-by: Jonathon Jongsma <jjongsma at redhat.com>
> ---

Just a couple nits about error message wording, but looks fine, assuming 
that it works with an actual device.

Reviewed-by: Laine Stump <laine at redhat.com>

(with the small error messages fixed and demonstrating that it works 
with a device)

>   src/qemu/qemu_command.c                       | 30 +++++++++++++--
>   src/qemu/qemu_command.h                       |  3 +-
>   src/qemu/qemu_domain.c                        |  6 ++-
>   src/qemu/qemu_hotplug.c                       | 12 +++---
>   src/qemu/qemu_interface.c                     | 23 ++++++++++++
>   src/qemu/qemu_interface.h                     |  2 +
>   src/qemu/qemu_migration.c                     | 10 ++++-
>   src/qemu/qemu_validate.c                      | 14 +++++++
>   .../net-vdpa.x86_64-latest.args               | 37 +++++++++++++++++++
>   tests/qemuxml2argvdata/net-vdpa.xml           | 28 ++++++++++++++
>   tests/qemuxml2argvmock.c                      | 11 +++++-
>   tests/qemuxml2argvtest.c                      |  1 +
>   tests/qemuxml2xmloutdata/net-vdpa.xml         | 34 +++++++++++++++++
>   tests/qemuxml2xmltest.c                       |  1 +
>   14 files changed, 199 insertions(+), 13 deletions(-)
>   create mode 100644 tests/qemuxml2argvdata/net-vdpa.x86_64-latest.args
>   create mode 100644 tests/qemuxml2argvdata/net-vdpa.xml
>   create mode 100644 tests/qemuxml2xmloutdata/net-vdpa.xml
> 
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 7b7176eb72..1c8c723d58 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -3553,7 +3553,8 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
>                       size_t tapfdSize,
>                       char **vhostfd,
>                       size_t vhostfdSize,
> -                    const char *slirpfd)
> +                    const char *slirpfd,
> +                    const char *vdpadev)
>   {
>       bool is_tap = false;
>       virDomainNetType netType = virDomainNetGetActualType(net);
> @@ -3692,6 +3693,12 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
>           break;
>   
>       case VIR_DOMAIN_NET_TYPE_VDPA:
> +        /* Caller will pass the fd to qemu with add-fd */
> +        if (virJSONValueObjectCreate(&netprops, "s:type", "vhost-vdpa", NULL) < 0 ||
> +            virJSONValueObjectAppendString(netprops, "vhostdev", vdpadev) < 0)
> +            return NULL;
> +        break;
> +
>       case VIR_DOMAIN_NET_TYPE_HOSTDEV:
>           /* Should have been handled earlier via PCI/USB hotplug code. */
>       case VIR_DOMAIN_NET_TYPE_LAST:
> @@ -8017,6 +8024,8 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
>       char **tapfdName = NULL;
>       char **vhostfdName = NULL;
>       g_autofree char *slirpfdName = NULL;
> +    g_autofree char *vdpafdName = NULL;
> +    int vdpafd = -1;
>       virDomainNetType actualType = virDomainNetGetActualType(net);
>       const virNetDevBandwidth *actualBandwidth;
>       bool requireNicdev = false;
> @@ -8102,13 +8111,17 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
>   
>           break;
>   
> +    case VIR_DOMAIN_NET_TYPE_VDPA:
> +        if ((vdpafd = qemuInterfaceVDPAConnect(net)) < 0)
> +            goto cleanup;
> +        break;
> +
>       case VIR_DOMAIN_NET_TYPE_USER:
>       case VIR_DOMAIN_NET_TYPE_SERVER:
>       case VIR_DOMAIN_NET_TYPE_CLIENT:
>       case VIR_DOMAIN_NET_TYPE_MCAST:
>       case VIR_DOMAIN_NET_TYPE_INTERNAL:
>       case VIR_DOMAIN_NET_TYPE_UDP:
> -    case VIR_DOMAIN_NET_TYPE_VDPA:
>       case VIR_DOMAIN_NET_TYPE_LAST:
>           /* nada */
>           break;
> @@ -8225,13 +8238,24 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver,
>           vhostfd[i] = -1;
>       }
>   
> +    if (vdpafd > 0) {
> +        g_autofree char *fdset = NULL;
> +
> +        virCommandPassFD(cmd, vdpafd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
> +        fdset = qemuVirCommandGetFDSet(cmd, vdpafd);
> +        if (!fdset)
> +            goto cleanup;
> +        virCommandAddArgList(cmd, "-add-fd", fdset, NULL);
> +        vdpafdName = qemuVirCommandGetDevSet(cmd, vdpafd);
> +    }
> +
>       if (chardev)
>           virCommandAddArgList(cmd, "-chardev", chardev, NULL);
>   
>       if (!(hostnetprops = qemuBuildHostNetStr(net,
>                                                tapfdName, tapfdSize,
>                                                vhostfdName, vhostfdSize,
> -                                             slirpfdName)))
> +                                             slirpfdName, vdpafdName)))
>           goto cleanup;
>   
>       if (!(host = virQEMUBuildNetdevCommandlineFromJSON(hostnetprops,
> diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
> index 89d99b111f..8db51f93b1 100644
> --- a/src/qemu/qemu_command.h
> +++ b/src/qemu/qemu_command.h
> @@ -99,7 +99,8 @@ virJSONValuePtr qemuBuildHostNetStr(virDomainNetDefPtr net,
>                                       size_t tapfdSize,
>                                       char **vhostfd,
>                                       size_t vhostfdSize,
> -                                    const char *slirpfd);
> +                                    const char *slirpfd,
> +                                    const char *vdpadev);
>   
>   /* Current, best practice */
>   char *qemuBuildNicDevStr(virDomainDefPtr def,
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 82a6a934e1..2bacd2753c 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -5184,8 +5184,10 @@ qemuDomainDeviceNetDefPostParse(virDomainNetDefPtr net,
>                                   const virDomainDef *def,
>                                   virQEMUCapsPtr qemuCaps)
>   {
> -    if (net->type != VIR_DOMAIN_NET_TYPE_VDPA &&
> -        net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
> +    if (net->type == VIR_DOMAIN_NET_TYPE_VDPA &&
> +        !virDomainNetGetModelString(net))
> +        net->model = VIR_DOMAIN_NET_MODEL_VIRTIO;
> +    else if (net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
>           !virDomainNetGetModelString(net) &&
>           virDomainNetResolveActualType(net) != VIR_DOMAIN_NET_TYPE_HOSTDEV)
>           net->model = qemuDomainDefaultNetModel(def, qemuCaps);
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 78dd5e9f19..45c07a7f4e 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -1389,7 +1389,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
>       if (!(netprops = qemuBuildHostNetStr(net,
>                                            tapfdName, tapfdSize,
>                                            vhostfdName, vhostfdSize,
> -                                         slirpfdName)))
> +                                         slirpfdName, NULL)))
>           goto cleanup;
>   
>       qemuDomainObjEnterMonitor(driver, vm);
> @@ -3484,8 +3484,9 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
>       olddev = *devslot;
>   
>       oldType = virDomainNetGetActualType(olddev);
> -    if (oldType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
> -        /* no changes are possible to a type='hostdev' interface */
> +    if (oldType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
> +        oldType == VIR_DOMAIN_NET_TYPE_VDPA) {
> +        /* no changes are possible to a type='hostdev' or type='vdpa' interface */
>           virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                          _("cannot change config of '%s' network type"),

Officially not your problem, but this message should have said "network 
interface type"...

>                          virDomainNetTypeToString(oldType));
> @@ -3672,8 +3673,9 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
>   
>       newType = virDomainNetGetActualType(newdev);
>   
> -    if (newType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
> -        /* can't turn it into a type='hostdev' interface */
> +    if (newType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
> +        newType == VIR_DOMAIN_NET_TYPE_VDPA) {
> +        /* can't turn it into a type='hostdev' or type='vdpa' interface */
>           virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                          _("cannot change network interface type to '%s'"),
>                          virDomainNetTypeToString(newType));
> diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
> index b24f9060a9..3714828fe1 100644
> --- a/src/qemu/qemu_interface.c
> +++ b/src/qemu/qemu_interface.c
> @@ -638,6 +638,29 @@ qemuInterfaceBridgeConnect(virDomainDefPtr def,
>   }
>   
>   
> +/* qemuInterfaceVDPAConnect:
> + * @net: pointer to the VM's interface description
> + *
> + * returns: file descriptor of the vdpa device
> + *
> + * Called *only* called if actualType is VIR_DOMAIN_NET_TYPE_VDPA
> + */
> +int
> +qemuInterfaceVDPAConnect(virDomainNetDefPtr net)
> +{
> +    int fd;
> +
> +    if ((fd = open(net->data.vdpa.devicepath, O_RDWR)) < 0) {
> +        virReportSystemError(errno,
> +                             _("Unable to open '%s' for vdpa device"),
> +                             net->data.vdpa.devicepath);
> +        return -1;
> +    }
> +
> +    return fd;
> +}
> +
> +
>   qemuSlirpPtr
>   qemuInterfacePrepareSlirp(virQEMUDriverPtr driver,
>                             virDomainNetDefPtr net)
> diff --git a/src/qemu/qemu_interface.h b/src/qemu/qemu_interface.h
> index 3dcefc6a12..1ba24f0a6f 100644
> --- a/src/qemu/qemu_interface.h
> +++ b/src/qemu/qemu_interface.h
> @@ -58,3 +58,5 @@ int qemuInterfaceOpenVhostNet(virDomainDefPtr def,
>   
>   qemuSlirpPtr qemuInterfacePrepareSlirp(virQEMUDriverPtr driver,
>                                          virDomainNetDefPtr net);
> +
> +int qemuInterfaceVDPAConnect(virDomainNetDefPtr net) G_GNUC_NO_INLINE;
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index a530c17582..d82de9455c 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -1372,7 +1372,15 @@ qemuMigrationSrcIsAllowed(virQEMUDriverPtr driver,
>   
>           for (i = 0; i < vm->def->nnets; i++) {
>               virDomainNetDefPtr net = vm->def->nets[i];
> -            qemuSlirpPtr slirp = QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp;
> +            qemuSlirpPtr slirp;
> +
> +            if (net->type == VIR_DOMAIN_NET_TYPE_VDPA) {
> +                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                               _("a vDPA device cannot be migrated"));

s/a vDPA device/vDPA devices/

Also, I wonder if the capitalization in the error messages should match 
the (lack of) capitalization in the XML (no strong opinion)

> +                return false;
> +            }
> +
> +            slirp = QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp;
>   
>               if (slirp && !qemuSlirpHasFeature(slirp, QEMU_SLIRP_FEATURE_MIGRATE)) {
>                   virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
> index 25f7866e5c..719cd19115 100644
> --- a/src/qemu/qemu_validate.c
> +++ b/src/qemu/qemu_validate.c
> @@ -1245,6 +1245,20 @@ qemuValidateDomainDeviceDefNetwork(const virDomainNetDef *net,
>                   }
>               }
>           }
> +    } else if (net->type == VIR_DOMAIN_NET_TYPE_VDPA) {
> +        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_NETDEV_VHOST_VDPA)) {
> +            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                           _("vDPA device is not supported with this QEMU binary"));

s/device is/devices are/

> +            return -1;
> +        }
> +
> +        if (net->model != VIR_DOMAIN_NET_MODEL_VIRTIO) {
> +            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                           _("invalid model for interface of type '%s': '%s'"),
> +                           virDomainNetTypeToString(net->type),
> +                           virDomainNetModelTypeToString(net->model));
> +            return -1;
> +        }
>       } else if (net->guestIP.nroutes || net->guestIP.nips) {
>           virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>                          _("Invalid attempt to set network interface "
> diff --git a/tests/qemuxml2argvdata/net-vdpa.x86_64-latest.args b/tests/qemuxml2argvdata/net-vdpa.x86_64-latest.args
> new file mode 100644
> index 0000000000..8e76ac7794
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/net-vdpa.x86_64-latest.args
> @@ -0,0 +1,37 @@
> +LC_ALL=C \
> +PATH=/bin \
> +HOME=/tmp/lib/domain--1-QEMUGuest1 \
> +USER=test \
> +LOGNAME=test \
> +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
> +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
> +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
> +QEMU_AUDIO_DRV=none \
> +/usr/bin/qemu-system-i386 \
> +-name guest=QEMUGuest1,debug-threads=on \
> +-S \
> +-object secret,id=masterKey0,format=raw,\
> +file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
> +-machine pc,accel=tcg,usb=off,dump-guest-core=off \
> +-cpu qemu64 \
> +-m 214 \
> +-overcommit mem-lock=off \
> +-smp 1,sockets=1,cores=1,threads=1 \
> +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
> +-display none \
> +-no-user-config \
> +-nodefaults \
> +-chardev socket,id=charmonitor,fd=1729,server,nowait \
> +-mon chardev=charmonitor,id=monitor,mode=control \
> +-rtc base=utc \
> +-no-shutdown \
> +-no-acpi \
> +-boot strict=on \
> +-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 \
> +-add-fd set=0,fd=1732 \
> +-netdev vhost-vdpa,vhostdev=/dev/fdset/0,id=hostnet0 \
> +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:95:db:c0,bus=pci.0,\
> +addr=0x2 \
> +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
> +resourcecontrol=deny \
> +-msg timestamp=on
> diff --git a/tests/qemuxml2argvdata/net-vdpa.xml b/tests/qemuxml2argvdata/net-vdpa.xml
> new file mode 100644
> index 0000000000..30cca7eb6e
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/net-vdpa.xml
> @@ -0,0 +1,28 @@
> +<domain type='qemu'>
> +  <name>QEMUGuest1</name>
> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> +  <memory unit='KiB'>219136</memory>
> +  <currentMemory unit='KiB'>219136</currentMemory>
> +  <vcpu placement='static'>1</vcpu>
> +  <os>
> +    <type arch='i686' machine='pc'>hvm</type>
> +    <boot dev='hd'/>
> +  </os>
> +  <clock offset='utc'/>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>destroy</on_crash>
> +  <devices>
> +    <emulator>/usr/bin/qemu-system-i386</emulator>
> +    <controller type='usb' index='0'/>
> +    <controller type='ide' index='0'/>
> +    <controller type='pci' index='0' model='pci-root'/>
> +    <interface type='vdpa'>
> +      <mac address='52:54:00:95:db:c0'/>
> +      <source dev='/dev/vhost-vdpa-0'/>
> +    </interface>
> +    <input type='mouse' bus='ps2'/>
> +    <input type='keyboard' bus='ps2'/>
> +    <memballoon model='none'/>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c
> index e5841bc8e3..516776697f 100644
> --- a/tests/qemuxml2argvmock.c
> +++ b/tests/qemuxml2argvmock.c
> @@ -205,7 +205,7 @@ virHostGetDRMRenderNode(void)
>   
>   static void (*real_virCommandPassFD)(virCommandPtr cmd, int fd, unsigned int flags);
>   
> -static const int testCommandPassSafeFDs[] = { 1730, 1731 };
> +static const int testCommandPassSafeFDs[] = { 1730, 1731, 1732 };
>   
>   void
>   virCommandPassFD(virCommandPtr cmd,
> @@ -283,3 +283,12 @@ qemuBuildTPMOpenBackendFDs(const char *tpmdev G_GNUC_UNUSED,
>       *cancelfd = 1731;
>       return 0;
>   }
> +
> +
> +int
> +qemuInterfaceVDPAConnect(virDomainNetDefPtr net G_GNUC_UNUSED)
> +{
> +    if (fcntl(1732, F_GETFD) != -1)
> +        abort();
> +    return 1732;
> +}
> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
> index e93948e3fc..000d6919f2 100644
> --- a/tests/qemuxml2argvtest.c
> +++ b/tests/qemuxml2argvtest.c
> @@ -1446,6 +1446,7 @@ mymain(void)
>               QEMU_CAPS_DEVICE_VFIO_PCI);
>       DO_TEST_FAILURE("net-hostdev-fail",
>                       QEMU_CAPS_DEVICE_VFIO_PCI);
> +    DO_TEST_CAPS_LATEST("net-vdpa");
>   
>       DO_TEST("hostdev-pci-multifunction",
>               QEMU_CAPS_KVM,
> diff --git a/tests/qemuxml2xmloutdata/net-vdpa.xml b/tests/qemuxml2xmloutdata/net-vdpa.xml
> new file mode 100644
> index 0000000000..b362405c14
> --- /dev/null
> +++ b/tests/qemuxml2xmloutdata/net-vdpa.xml
> @@ -0,0 +1,34 @@
> +<domain type='qemu'>
> +  <name>QEMUGuest1</name>
> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> +  <memory unit='KiB'>219136</memory>
> +  <currentMemory unit='KiB'>219136</currentMemory>
> +  <vcpu placement='static'>1</vcpu>
> +  <os>
> +    <type arch='i686' machine='pc'>hvm</type>
> +    <boot dev='hd'/>
> +  </os>
> +  <clock offset='utc'/>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>destroy</on_crash>
> +  <devices>
> +    <emulator>/usr/bin/qemu-system-i386</emulator>
> +    <controller type='usb' index='0'>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
> +    </controller>
> +    <controller type='ide' index='0'>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
> +    </controller>
> +    <controller type='pci' index='0' model='pci-root'/>
> +    <interface type='vdpa'>
> +      <mac address='52:54:00:95:db:c0'/>
> +      <source dev='/dev/vhost-vdpa-0'/>
> +      <model type='virtio'/>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
> +    </interface>
> +    <input type='mouse' bus='ps2'/>
> +    <input type='keyboard' bus='ps2'/>
> +    <memballoon model='none'/>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
> index 39a9da874f..ac33e87698 100644
> --- a/tests/qemuxml2xmltest.c
> +++ b/tests/qemuxml2xmltest.c
> @@ -497,6 +497,7 @@ mymain(void)
>       DO_TEST("net-mtu", NONE);
>       DO_TEST("net-coalesce", NONE);
>       DO_TEST("net-many-models", NONE);
> +    DO_TEST("net-vdpa", QEMU_CAPS_NETDEV_VHOST_VDPA);
>   
>       DO_TEST("serial-tcp-tlsx509-chardev", NONE);
>       DO_TEST("serial-tcp-tlsx509-chardev-notls", NONE);
> 




More information about the libvir-list mailing list