diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 5cfa4a69d0..35e99fbfff 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -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; diff --git a/tests/qemuhotplugmock.c b/tests/qemuhotplugmock.c index 29fac8a598..d2e32ecf7e 100644 --- a/tests/qemuhotplugmock.c +++ b/tests/qemuhotplugmock.c @@ -19,11 +19,13 @@ #include #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 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); +} diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 0948c8792d..f0f17022b8 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -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); diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-interface-vdpa.xml b/tests/qemuhotplugtestdevices/qemuhotplug-interface-vdpa.xml new file mode 100644 index 0000000000..e42ca08d31 --- /dev/null +++ b/tests/qemuhotplugtestdevices/qemuhotplug-interface-vdpa.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+interface-vdpa.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+interface-vdpa.xml new file mode 100644 index 0000000000..066180bb3c --- /dev/null +++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+interface-vdpa.xml @@ -0,0 +1,57 @@ + + hotplug + d091ea82-29e6-2e34-3005-f02617b36e87 + 4194304 + 4194304 + 4 + + hvm + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + +
+ + + +
+ + + +
+ + + + + + +
+ + + + + + +
+ + + + + + + + + + +