[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