|
|
c8c376 |
From 6ad2b5b70219158aa873058b4d4b1d94c481640d Mon Sep 17 00:00:00 2001
|
|
|
c8c376 |
Message-Id: <6ad2b5b70219158aa873058b4d4b1d94c481640d@dist-git>
|
|
|
c8c376 |
From: Michal Privoznik <mprivozn@redhat.com>
|
|
|
c8c376 |
Date: Tue, 8 Nov 2016 13:42:13 +0100
|
|
|
c8c376 |
Subject: [PATCH] qemu_hotplug: Support interface type of vhost-user hotplug
|
|
|
c8c376 |
|
|
|
c8c376 |
RHEL-7.3: https://bugzilla.redhat.com/show_bug.cgi?id=1366108
|
|
|
c8c376 |
RHEL-7.3.z: https://bugzilla.redhat.com/show_bug.cgi?id=1392032
|
|
|
c8c376 |
|
|
|
c8c376 |
There are couple of things that needs to be done in order to
|
|
|
c8c376 |
allow vhost-user hotplug. Firstly, vhost-user requires a chardev
|
|
|
c8c376 |
which is connected to vhost-user bridge and through which qemu
|
|
|
c8c376 |
communicates with the bridge (no acutal guest traffic is sent
|
|
|
c8c376 |
through there, just some metadata). In order to generate proper
|
|
|
c8c376 |
chardev alias, we must assign device alias way sooner.
|
|
|
c8c376 |
|
|
|
c8c376 |
Then, because we are plugging the chardev first, we need to do
|
|
|
c8c376 |
the proper undo if something fails - that is remove netdev too.
|
|
|
c8c376 |
We don't want anything to be left over in case attach fails at
|
|
|
c8c376 |
some point.
|
|
|
c8c376 |
|
|
|
c8c376 |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
c8c376 |
(cherry picked from commit ff89d5cbcf266e780b4ff93960969b3a6c2e9a01)
|
|
|
c8c376 |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
c8c376 |
---
|
|
|
c8c376 |
src/qemu/qemu_hotplug.c | 71 +++++++++++++++++++++++++++++++++++++++++--------
|
|
|
c8c376 |
1 file changed, 60 insertions(+), 11 deletions(-)
|
|
|
c8c376 |
|
|
|
c8c376 |
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
|
|
|
c8c376 |
index 011152762..8acbf370b 100644
|
|
|
c8c376 |
--- a/src/qemu/qemu_hotplug.c
|
|
|
c8c376 |
+++ b/src/qemu/qemu_hotplug.c
|
|
|
c8c376 |
@@ -902,6 +902,10 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
virNetDevBandwidthPtr actualBandwidth;
|
|
|
c8c376 |
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
c8c376 |
size_t i;
|
|
|
c8c376 |
+ char *charDevAlias = NULL;
|
|
|
c8c376 |
+ bool charDevPlugged = false;
|
|
|
c8c376 |
+ bool netdevPlugged = false;
|
|
|
c8c376 |
+ bool hostPlugged = false;
|
|
|
c8c376 |
|
|
|
c8c376 |
/* preallocate new slot for device */
|
|
|
c8c376 |
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
|
|
|
c8c376 |
@@ -940,6 +944,9 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
return -1;
|
|
|
c8c376 |
}
|
|
|
c8c376 |
|
|
|
c8c376 |
+ if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
|
|
|
c8c376 |
+ goto cleanup;
|
|
|
c8c376 |
+
|
|
|
c8c376 |
switch (actualType) {
|
|
|
c8c376 |
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
c8c376 |
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
c8c376 |
@@ -1014,8 +1021,18 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
break;
|
|
|
c8c376 |
|
|
|
c8c376 |
- case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
c8c376 |
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
|
|
c8c376 |
+ if (!qemuDomainSupportsNetdev(vm->def, priv->qemuCaps, net)) {
|
|
|
c8c376 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
c8c376 |
+ "%s", _("Netdev support unavailable"));
|
|
|
c8c376 |
+ goto cleanup;
|
|
|
c8c376 |
+ }
|
|
|
c8c376 |
+
|
|
|
c8c376 |
+ if (virAsprintf(&charDevAlias, "char%s", net->info.alias) < 0)
|
|
|
c8c376 |
+ goto cleanup;
|
|
|
c8c376 |
+ break;
|
|
|
c8c376 |
+
|
|
|
c8c376 |
+ case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
c8c376 |
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
c8c376 |
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
c8c376 |
case VIR_DOMAIN_NET_TYPE_MCAST:
|
|
|
c8c376 |
@@ -1051,9 +1068,6 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
}
|
|
|
c8c376 |
|
|
|
c8c376 |
- if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
|
|
|
c8c376 |
- goto cleanup;
|
|
|
c8c376 |
-
|
|
|
c8c376 |
if (qemuDomainMachineIsS390CCW(vm->def) &&
|
|
|
c8c376 |
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
|
|
|
c8c376 |
net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
|
|
|
c8c376 |
@@ -1111,23 +1125,36 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
}
|
|
|
c8c376 |
|
|
|
c8c376 |
qemuDomainObjEnterMonitor(driver, vm);
|
|
|
c8c376 |
+
|
|
|
c8c376 |
+ if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
|
|
|
c8c376 |
+ if (qemuMonitorAttachCharDev(priv->mon, charDevAlias, net->data.vhostuser) < 0) {
|
|
|
c8c376 |
+ ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
|
|
c8c376 |
+ virDomainAuditNet(vm, NULL, net, "attach", false);
|
|
|
c8c376 |
+ goto cleanup;
|
|
|
c8c376 |
+ }
|
|
|
c8c376 |
+ charDevPlugged = true;
|
|
|
c8c376 |
+ }
|
|
|
c8c376 |
+
|
|
|
c8c376 |
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
|
|
|
c8c376 |
if (qemuMonitorAddNetdev(priv->mon, netstr,
|
|
|
c8c376 |
tapfd, tapfdName, tapfdSize,
|
|
|
c8c376 |
vhostfd, vhostfdName, vhostfdSize) < 0) {
|
|
|
c8c376 |
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
|
|
c8c376 |
virDomainAuditNet(vm, NULL, net, "attach", false);
|
|
|
c8c376 |
- goto cleanup;
|
|
|
c8c376 |
+ goto try_remove;
|
|
|
c8c376 |
}
|
|
|
c8c376 |
+ netdevPlugged = true;
|
|
|
c8c376 |
} else {
|
|
|
c8c376 |
if (qemuMonitorAddHostNetwork(priv->mon, netstr,
|
|
|
c8c376 |
tapfd, tapfdName, tapfdSize,
|
|
|
c8c376 |
vhostfd, vhostfdName, vhostfdSize) < 0) {
|
|
|
c8c376 |
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
|
|
c8c376 |
virDomainAuditNet(vm, NULL, net, "attach", false);
|
|
|
c8c376 |
- goto cleanup;
|
|
|
c8c376 |
+ goto try_remove;
|
|
|
c8c376 |
}
|
|
|
c8c376 |
+ hostPlugged = true;
|
|
|
c8c376 |
}
|
|
|
c8c376 |
+
|
|
|
c8c376 |
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
|
|
|
c8c376 |
@@ -1230,6 +1257,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
}
|
|
|
c8c376 |
VIR_FREE(vhostfd);
|
|
|
c8c376 |
VIR_FREE(vhostfdName);
|
|
|
c8c376 |
+ VIR_FREE(charDevAlias);
|
|
|
c8c376 |
virObjectUnref(cfg);
|
|
|
c8c376 |
|
|
|
c8c376 |
return ret;
|
|
|
c8c376 |
@@ -1244,7 +1272,11 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
if (virAsprintf(&netdev_name, "host%s", net->info.alias) < 0)
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
qemuDomainObjEnterMonitor(driver, vm);
|
|
|
c8c376 |
- if (qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
|
|
|
c8c376 |
+ if (charDevPlugged &&
|
|
|
c8c376 |
+ qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0)
|
|
|
c8c376 |
+ VIR_WARN("Failed to remove associated chardev %s", charDevAlias);
|
|
|
c8c376 |
+ if (netdevPlugged &&
|
|
|
c8c376 |
+ qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
|
|
|
c8c376 |
VIR_WARN("Failed to remove network backend for netdev %s",
|
|
|
c8c376 |
netdev_name);
|
|
|
c8c376 |
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
|
|
c8c376 |
@@ -1257,7 +1289,8 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
qemuDomainObjEnterMonitor(driver, vm);
|
|
|
c8c376 |
- if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
|
|
|
c8c376 |
+ if (hostPlugged &&
|
|
|
c8c376 |
+ qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
|
|
|
c8c376 |
VIR_WARN("Failed to remove network backend for vlan %d, net %s",
|
|
|
c8c376 |
vlan, hostnet_name);
|
|
|
c8c376 |
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
|
|
c8c376 |
@@ -3357,10 +3390,12 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
virNetDevVPortProfilePtr vport;
|
|
|
c8c376 |
virObjectEventPtr event;
|
|
|
c8c376 |
char *hostnet_name = NULL;
|
|
|
c8c376 |
+ char *charDevAlias = NULL;
|
|
|
c8c376 |
size_t i;
|
|
|
c8c376 |
int ret = -1;
|
|
|
c8c376 |
+ int actualType = virDomainNetGetActualType(net);
|
|
|
c8c376 |
|
|
|
c8c376 |
- if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
c8c376 |
+ if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
|
|
|
c8c376 |
/* this function handles all hostdev and netdev cleanup */
|
|
|
c8c376 |
ret = qemuDomainRemoveHostDevice(driver, vm,
|
|
|
c8c376 |
virDomainNetGetActualHostdev(net));
|
|
|
c8c376 |
@@ -3370,9 +3405,11 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
VIR_DEBUG("Removing network interface %s from domain %p %s",
|
|
|
c8c376 |
net->info.alias, vm, vm->def->name);
|
|
|
c8c376 |
|
|
|
c8c376 |
- if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
|
|
|
c8c376 |
+ if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0 ||
|
|
|
c8c376 |
+ virAsprintf(&charDevAlias, "char%s", net->info.alias) < 0)
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
|
|
|
c8c376 |
+
|
|
|
c8c376 |
qemuDomainObjEnterMonitor(driver, vm);
|
|
|
c8c376 |
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
|
|
|
c8c376 |
if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
|
|
|
c8c376 |
@@ -3395,6 +3432,17 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
}
|
|
|
c8c376 |
}
|
|
|
c8c376 |
+
|
|
|
c8c376 |
+ if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
|
|
|
c8c376 |
+ /* vhostuser has a chardev too */
|
|
|
c8c376 |
+ if (qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0) {
|
|
|
c8c376 |
+ /* well, this is a messy situation. Guest visible PCI device has
|
|
|
c8c376 |
+ * been removed, netdev too but chardev not. The best seems to be
|
|
|
c8c376 |
+ * to just ignore the error and carry on.
|
|
|
c8c376 |
+ */
|
|
|
c8c376 |
+ }
|
|
|
c8c376 |
+ }
|
|
|
c8c376 |
+
|
|
|
c8c376 |
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
|
|
c8c376 |
goto cleanup;
|
|
|
c8c376 |
|
|
|
c8c376 |
@@ -3419,7 +3467,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
&net->mac));
|
|
|
c8c376 |
}
|
|
|
c8c376 |
|
|
|
c8c376 |
- if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
c8c376 |
+ if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
|
|
|
c8c376 |
ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
|
|
|
c8c376 |
net->ifname, &net->mac,
|
|
|
c8c376 |
virDomainNetGetActualDirectDev(net),
|
|
|
c8c376 |
@@ -3445,6 +3493,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
|
|
|
c8c376 |
|
|
|
c8c376 |
cleanup:
|
|
|
c8c376 |
virObjectUnref(cfg);
|
|
|
c8c376 |
+ VIR_FREE(charDevAlias);
|
|
|
c8c376 |
VIR_FREE(hostnet_name);
|
|
|
c8c376 |
return ret;
|
|
|
c8c376 |
}
|
|
|
c8c376 |
--
|
|
|
c8c376 |
2.11.0
|
|
|
c8c376 |
|