mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
qemu: support hotplug of vdpa devices
By using the new qemu monitor functions to handle passing and removing file descriptors, we can support hotplug of vdpa devices. Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
parent
b8998cc670
commit
b79abf9c3c
@ -1157,6 +1157,8 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
||||
virErrorPtr originalError = NULL;
|
||||
g_autofree char *slirpfdName = NULL;
|
||||
int slirpfd = -1;
|
||||
g_autofree char *vdpafdName = NULL;
|
||||
int vdpafd = -1;
|
||||
char **tapfdName = NULL;
|
||||
int *tapfd = NULL;
|
||||
size_t tapfdSize = 0;
|
||||
@ -1334,12 +1336,16 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
||||
/* hostdev interfaces were handled earlier in this function */
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_NET_TYPE_VDPA:
|
||||
if ((vdpafd = qemuInterfaceVDPAConnect(net)) < 0)
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
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:
|
||||
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
|
||||
_("hotplug of interface type of %s is not implemented yet"),
|
||||
@ -1386,13 +1392,29 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
||||
for (i = 0; i < vhostfdSize; i++)
|
||||
vhostfdName[i] = g_strdup_printf("vhostfd-%s%zu", net->info.alias, i);
|
||||
|
||||
qemuDomainObjEnterMonitor(driver, vm);
|
||||
|
||||
if (vdpafd > 0) {
|
||||
/* vhost-vdpa only accepts a filename. We can pass an open fd by
|
||||
* filename if we add the fd to an fdset and then pass a filename of
|
||||
* /dev/fdset/$FDSETID. */
|
||||
qemuMonitorAddFdInfo fdinfo;
|
||||
if (qemuMonitorAddFileHandleToSet(priv->mon, vdpafd, -1,
|
||||
net->data.vdpa.devicepath,
|
||||
&fdinfo) < 0) {
|
||||
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
||||
goto cleanup;
|
||||
}
|
||||
vdpafdName = g_strdup_printf("/dev/fdset/%d", fdinfo.fdset);
|
||||
}
|
||||
|
||||
if (!(netprops = qemuBuildHostNetStr(net,
|
||||
tapfdName, tapfdSize,
|
||||
vhostfdName, vhostfdSize,
|
||||
slirpfdName, NULL)))
|
||||
slirpfdName, vdpafdName))) {
|
||||
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
||||
goto cleanup;
|
||||
|
||||
qemuDomainObjEnterMonitor(driver, vm);
|
||||
}
|
||||
|
||||
if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
|
||||
if (qemuMonitorAttachCharDev(priv->mon, charDevAlias, net->data.vhostuser) < 0) {
|
||||
@ -1518,6 +1540,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
||||
VIR_FREE(vhostfdName);
|
||||
virDomainCCWAddressSetFree(ccwaddrs);
|
||||
VIR_FORCE_CLOSE(slirpfd);
|
||||
VIR_FORCE_CLOSE(vdpafd);
|
||||
|
||||
return ret;
|
||||
|
||||
@ -4598,8 +4621,39 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
||||
* to just ignore the error and carry on.
|
||||
*/
|
||||
}
|
||||
} else if (actualType == VIR_DOMAIN_NET_TYPE_VDPA) {
|
||||
int vdpafdset = -1;
|
||||
g_autoptr(qemuMonitorFdsets) fdsets = NULL;
|
||||
|
||||
/* query qemu for which fdset is associated with the fd that we passed
|
||||
* to qemu via 'add-fd' for this vdpa device. If we don't remove the
|
||||
* fd, qemu will keep it open */
|
||||
if (qemuMonitorQueryFdsets(priv->mon, &fdsets) == 0) {
|
||||
for (i = 0; i < fdsets->nfdsets && vdpafdset < 0; i++) {
|
||||
size_t j;
|
||||
qemuMonitorFdsetInfoPtr set = &fdsets->fdsets[i];
|
||||
|
||||
for (j = 0; j < set->nfds; j++) {
|
||||
qemuMonitorFdsetFdInfoPtr fdinfo = &set->fds[j];
|
||||
if (STREQ_NULLABLE(fdinfo->opaque, net->data.vdpa.devicepath)) {
|
||||
vdpafdset = set->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vdpafdset < 0) {
|
||||
VIR_WARN("Cannot determine fdset for vdpa device");
|
||||
} else {
|
||||
if (qemuMonitorRemoveFdset(priv->mon, vdpafdset) < 0) {
|
||||
/* if it fails, there's not much we can do... just carry on */
|
||||
VIR_WARN("failed to close vdpa device");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
||||
return -1;
|
||||
|
||||
|
@ -19,11 +19,13 @@
|
||||
#include <config.h>
|
||||
|
||||
#include "qemu/qemu_hotplug.h"
|
||||
#include "qemu/qemu_interface.h"
|
||||
#include "qemu/qemu_process.h"
|
||||
#include "conf/domain_conf.h"
|
||||
#include "virdevmapper.h"
|
||||
#include "virutil.h"
|
||||
#include "virmock.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
static int (*real_virGetDeviceID)(const char *path, int *maj, int *min);
|
||||
static bool (*real_virFileExists)(const char *path);
|
||||
@ -106,3 +108,10 @@ void
|
||||
qemuProcessKillManagedPRDaemon(virDomainObjPtr vm G_GNUC_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
qemuInterfaceVDPAConnect(virDomainNetDefPtr net G_GNUC_UNUSED)
|
||||
{
|
||||
/* need a valid fd or sendmsg won't work. Just open /dev/null */
|
||||
return open("/dev/null", O_RDONLY);
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
|
||||
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_PR_MANAGER_HELPER);
|
||||
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SCSI_BLOCK);
|
||||
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_USB_KBD);
|
||||
virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_NETDEV_VHOST_VDPA);
|
||||
|
||||
if (qemuTestCapsCacheInsert(driver.qemuCapsCache, priv->qemuCaps) < 0)
|
||||
return -1;
|
||||
@ -141,6 +142,9 @@ testQemuHotplugAttach(virDomainObjPtr vm,
|
||||
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
||||
ret = qemuDomainAttachHostDevice(&driver, vm, dev->data.hostdev);
|
||||
break;
|
||||
case VIR_DOMAIN_DEVICE_NET:
|
||||
ret = qemuDomainAttachNetDevice(&driver, vm, dev->data.net);
|
||||
break;
|
||||
default:
|
||||
VIR_TEST_VERBOSE("device type '%s' cannot be attached",
|
||||
virDomainDeviceTypeToString(dev->type));
|
||||
@ -163,6 +167,7 @@ testQemuHotplugDetach(virDomainObjPtr vm,
|
||||
case VIR_DOMAIN_DEVICE_SHMEM:
|
||||
case VIR_DOMAIN_DEVICE_WATCHDOG:
|
||||
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
||||
case VIR_DOMAIN_DEVICE_NET:
|
||||
ret = qemuDomainDetachDeviceLive(vm, dev, &driver, async);
|
||||
break;
|
||||
default:
|
||||
@ -824,6 +829,17 @@ mymain(void)
|
||||
DO_TEST_DETACH("pseries-base-live", "hostdev-pci", false, false,
|
||||
"device_del", QMP_DEVICE_DELETED("hostdev0") QMP_OK);
|
||||
|
||||
DO_TEST_ATTACH("base-live", "interface-vdpa", false, true,
|
||||
"add-fd", "{ \"return\": { \"fdset-id\": 1, \"fd\": 95 }}",
|
||||
"netdev_add", QMP_OK, "device_add", QMP_OK);
|
||||
DO_TEST_DETACH("base-live", "interface-vdpa", false, false,
|
||||
"device_del", QMP_DEVICE_DELETED("net0") QMP_OK,
|
||||
"netdev_del", QMP_OK,
|
||||
"query-fdsets",
|
||||
"{ \"return\": [{\"fds\": [{\"fd\": 95, \"opaque\": \"/dev/vhost-vdpa-0\"}], \"fdset-id\": 1}]}",
|
||||
"remove-fd", QMP_OK
|
||||
);
|
||||
|
||||
DO_TEST_ATTACH("base-live", "watchdog", false, true,
|
||||
"watchdog-set-action", QMP_OK,
|
||||
"device_add", QMP_OK);
|
||||
|
@ -0,0 +1,4 @@
|
||||
<interface type='vdpa'>
|
||||
<mac address='52:54:00:39:5f:04'/>
|
||||
<source dev='/dev/vhost-vdpa-0'/>
|
||||
</interface>
|
@ -0,0 +1,57 @@
|
||||
<domain type='kvm' id='7'>
|
||||
<name>hotplug</name>
|
||||
<uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
|
||||
<memory unit='KiB'>4194304</memory>
|
||||
<currentMemory unit='KiB'>4194304</currentMemory>
|
||||
<vcpu placement='static'>4</vcpu>
|
||||
<os>
|
||||
<type arch='x86_64' machine='pc'>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<features>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<pae/>
|
||||
</features>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>restart</on_crash>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu-system-x86_64</emulator>
|
||||
<controller type='usb' index='0'>
|
||||
<alias name='usb'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
|
||||
</controller>
|
||||
<controller type='ide' index='0'>
|
||||
<alias name='ide'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
|
||||
</controller>
|
||||
<controller type='scsi' index='0' model='virtio-scsi'>
|
||||
<alias name='scsi0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
|
||||
</controller>
|
||||
<controller type='pci' index='0' model='pci-root'>
|
||||
<alias name='pci'/>
|
||||
</controller>
|
||||
<controller type='virtio-serial' index='0'>
|
||||
<alias name='virtio-serial0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||
</controller>
|
||||
<interface type='vdpa'>
|
||||
<mac address='52:54:00:39:5f:04'/>
|
||||
<source dev='/dev/vhost-vdpa-0'/>
|
||||
<model type='virtio'/>
|
||||
<alias name='net0'/>
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
||||
</interface>
|
||||
<input type='mouse' bus='ps2'>
|
||||
<alias name='input0'/>
|
||||
</input>
|
||||
<input type='keyboard' bus='ps2'>
|
||||
<alias name='input1'/>
|
||||
</input>
|
||||
<memballoon model='none'/>
|
||||
</devices>
|
||||
<seclabel type='none' model='none'/>
|
||||
</domain>
|
Loading…
Reference in New Issue
Block a user