The new <driver> attribute backupAlias gives the alias name ("id" in QEMU parlance) of the virtio-net device that will be paired in the guest with a vfio-pci device for "failover" when the vfio-pci device is unplugged (e.g. during migration). This patch adds backupAlias for <interface type='hostdev'> (which has its <driver> stored in the child virDomainHostdevDef); an upcoming patch will handle the case of <interface type='network'> when the network is a pool of SRIOV VFs (in that case the <driver> subelement is stored in the virDomainNetDef). Since a MAC address must be set for the hostdev in order for the failover to work (a current guest driver limitation is that the MAC addresses of the two devices must match), and that isn't possible with plain <hostdev>, backupAlias is prohibited by validation in the case of a plain <hostdev>. An example usage: <interface type='network'> <source network='mybridge'/> <mac address='00:11:22:33:44:55'/> <model type='virtio'/> <alias name='ua-backup0'/> <driver failover='on'/> </interface> <interface type='hostdev' managed='yes'> <source> <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x1'/> </source> <mac address='00:11:22:33:44:55'/> <driver backupAlias='ua-backup0'/> </interface> QEMU will internally associate these two devices, and will automatically unplug the hostdev at the start of any migration, and re-plug a new device on the destination when migration is complete (it is up to the guest virtio driver to handle bonding the two devices). Signed-off-by: Laine Stump <laine@xxxxxxxxxx> --- docs/schemas/domaincommon.rng | 5 +++++ src/conf/domain_conf.c | 16 ++++++++++++++-- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 2 ++ src/qemu/qemu_domain.c | 6 ++++++ .../qemuxml2argvdata/net-virtio-failover.args | 6 +++++- tests/qemuxml2argvdata/net-virtio-failover.xml | 14 ++++++++++++++ tests/qemuxml2argvtest.c | 3 ++- .../qemuxml2xmloutdata/net-virtio-failover.xml | 18 +++++++++++++++++- tests/qemuxml2xmltest.c | 3 ++- 10 files changed, 68 insertions(+), 6 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 80aea47e36..e0977d28d3 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3002,6 +3002,11 @@ </optional> <optional> <element name="driver"> + <optional> + <attribute name="backupAlias"> + <ref name='aliasName'/> + </attribute> + </optional> <choice> <group> <attribute name="name"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 29636617a2..e0e47415ed 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2941,8 +2941,10 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def) case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: VIR_FREE(def->source.subsys.u.scsi_host.wwpn); break; - case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + VIR_FREE(def->source.subsys.u.pci.backupAlias); + break; + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; @@ -6360,6 +6362,12 @@ virDomainHostdevDefValidate(const virDomainHostdevDef *hostdev) "'unassigned' address type")); return -1; } + if (hostdev->source.subsys.u.pci.backupAlias && + !hostdev->parentnet) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("backupAlias is not supported for plain <hostdev> - <interface type='hostdev'> is required")); + return -1; + } break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: if (hostdev->info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && @@ -8410,6 +8418,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, } pcisrc->backend = backend; + pcisrc->backupAlias = virXPathString("string(./driver/@backupAlias)", ctxt); break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: @@ -25037,7 +25046,8 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf, virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi; if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && - pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) { + (pcisrc->backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT || + pcisrc->backupAlias)) { virBufferAddLit(buf, "<driver"); @@ -25054,6 +25064,8 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf, virBufferAsprintf(buf, " name='%s'", backend); } + virBufferEscapeString(buf, " backupAlias='%s'", pcisrc->backupAlias); + virBufferAddLit(buf, "/>\n"); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index af9691d62b..0bf1d2b6bf 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -235,6 +235,7 @@ struct _virDomainHostdevSubsysUSB { struct _virDomainHostdevSubsysPCI { virPCIDeviceAddress addr; /* host address */ int backend; /* enum virDomainHostdevSubsysPCIBackendType */ + char *backupAlias; /* alias id of backup virtio device for failover */ }; struct _virDomainHostdevSubsysSCSIHost { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d3c0cc0506..82a95e2474 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4706,6 +4706,8 @@ qemuBuildPCIHostdevDevStr(const virDomainDef *def, return NULL; if (qemuBuildRomStr(&buf, dev->info) < 0) return NULL; + if (pcisrc->backupAlias) + virBufferAsprintf(&buf, ",failover_pair_id=%s", pcisrc->backupAlias); return virBufferContentAndReset(&buf); } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 6f45d74bde..d32a3c0935 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -6664,6 +6664,12 @@ qemuDomainDeviceDefValidateHostdev(const virDomainHostdevDef *hostdev, return -1; } } + if (hostdev->source.subsys.u.pci.backupAlias && + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_FAILOVER)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("virtio-net failover / hostdev backupAlias is not supported with this QEMU binary")); + return -1; + } break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: diff --git a/tests/qemuxml2argvdata/net-virtio-failover.args b/tests/qemuxml2argvdata/net-virtio-failover.args index da41e19628..19e7260843 100644 --- a/tests/qemuxml2argvdata/net-virtio-failover.args +++ b/tests/qemuxml2argvdata/net-virtio-failover.args @@ -33,4 +33,8 @@ mac=00:11:22:33:44:55,bus=pci.0,addr=0x3 \ -netdev user,id=hostua-backup1 \ -device virtio-net-pci,failover=on,netdev=hostua-backup1,id=ua-backup1,\ mac=66:44:33:22:11:00,bus=pci.0,addr=0x4 \ --device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 +-device vfio-pci,host=0000:03:07.1,id=hostdev0,bus=pci.0,addr=0x5,\ +failover_pair_id=ua-backup0 \ +-device vfio-pci,host=0000:03:07.2,id=hostdev1,bus=pci.0,addr=0x6,\ +failover_pair_id=ua-backup1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 diff --git a/tests/qemuxml2argvdata/net-virtio-failover.xml b/tests/qemuxml2argvdata/net-virtio-failover.xml index 1f545b8d73..99ac37013a 100644 --- a/tests/qemuxml2argvdata/net-virtio-failover.xml +++ b/tests/qemuxml2argvdata/net-virtio-failover.xml @@ -31,6 +31,20 @@ <driver failover='on'/> <alias name='ua-backup1'/> </interface> + <interface type='hostdev' managed='yes'> + <mac address='00:11:22:33:44:55'/> + <driver backupAlias='ua-backup0'/> + <source> + <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x1'/> + </source> + </interface> + <interface type='hostdev' managed='yes'> + <mac address='66:44:33:22:11:00'/> + <driver backupAlias='ua-backup1'/> + <source> + <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x2'/> + </source> + </interface> <memballoon model='virtio'/> </devices> </domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index c4fbe321d8..411393a55a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1309,7 +1309,8 @@ mymain(void) QEMU_CAPS_VIRTIO_NET_TX_QUEUE_SIZE); DO_TEST_PARSE_ERROR("net-virtio-rxqueuesize-invalid-size", NONE); DO_TEST("net-virtio-failover", - QEMU_CAPS_VIRTIO_NET_FAILOVER); + QEMU_CAPS_VIRTIO_NET_FAILOVER, + QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST_PARSE_ERROR("net-virtio-failover", NONE); DO_TEST("net-eth", NONE); DO_TEST("net-eth-ifname", NONE); diff --git a/tests/qemuxml2xmloutdata/net-virtio-failover.xml b/tests/qemuxml2xmloutdata/net-virtio-failover.xml index 7895c03dd7..9c73a3bee7 100644 --- a/tests/qemuxml2xmloutdata/net-virtio-failover.xml +++ b/tests/qemuxml2xmloutdata/net-virtio-failover.xml @@ -41,10 +41,26 @@ <alias name='ua-backup1'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </interface> + <interface type='hostdev' managed='yes'> + <mac address='00:11:22:33:44:55'/> + <driver backupAlias='ua-backup0'/> + <source> + <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x1'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </interface> + <interface type='hostdev' managed='yes'> + <mac address='66:44:33:22:11:00'/> + <driver backupAlias='ua-backup1'/> + <source> + <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x2'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </interface> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <memballoon model='virtio'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </memballoon> </devices> </domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 326e49fbcd..c91690a030 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -452,7 +452,8 @@ mymain(void) DO_TEST("net-virtio-network-portgroup", NONE); DO_TEST("net-virtio-rxtxqueuesize", NONE); DO_TEST("net-virtio-failover", - QEMU_CAPS_VIRTIO_NET_FAILOVER); + QEMU_CAPS_VIRTIO_NET_FAILOVER, + QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST("net-hostdev", NONE); DO_TEST("net-hostdev-bootorder", NONE); DO_TEST("net-hostdev-vfio", QEMU_CAPS_DEVICE_VFIO_PCI); -- 2.24.1