提交 ff89d5cb 编写于 作者: M Michal Privoznik

qemu_hotplug: Support interface type of vhost-user hotplug

https://bugzilla.redhat.com/show_bug.cgi?id=1366108

There are couple of things that needs to be done in order to
allow vhost-user hotplug. Firstly, vhost-user requires a chardev
which is connected to vhost-user bridge and through which qemu
communicates with the bridge (no acutal guest traffic is sent
through there, just some metadata). In order to generate proper
chardev alias, we must assign device alias way sooner.

Then, because we are plugging the chardev first, we need to do
the proper undo if something fails - that is remove netdev too.
We don't want anything to be left over in case attach fails at
some point.
Signed-off-by: NMichal Privoznik <mprivozn@redhat.com>
上级 e1844d85
...@@ -932,6 +932,10 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -932,6 +932,10 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virDomainCCWAddressSetPtr ccwaddrs = NULL; virDomainCCWAddressSetPtr ccwaddrs = NULL;
size_t i; size_t i;
char *charDevAlias = NULL;
bool charDevPlugged = false;
bool netdevPlugged = false;
bool hostPlugged = false;
/* preallocate new slot for device */ /* preallocate new slot for device */
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0) if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
...@@ -970,6 +974,9 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -970,6 +974,9 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
return -1; return -1;
} }
if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
goto cleanup;
switch (actualType) { switch (actualType) {
case VIR_DOMAIN_NET_TYPE_BRIDGE: case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_NETWORK:
...@@ -1044,8 +1051,18 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -1044,8 +1051,18 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
break; break;
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_VHOSTUSER: case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
if (!qemuDomainSupportsNetdev(vm->def, priv->qemuCaps, net)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Netdev support unavailable"));
goto cleanup;
}
if (virAsprintf(&charDevAlias, "char%s", net->info.alias) < 0)
goto cleanup;
break;
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_SERVER: case VIR_DOMAIN_NET_TYPE_SERVER:
case VIR_DOMAIN_NET_TYPE_CLIENT: case VIR_DOMAIN_NET_TYPE_CLIENT:
case VIR_DOMAIN_NET_TYPE_MCAST: case VIR_DOMAIN_NET_TYPE_MCAST:
...@@ -1081,9 +1098,6 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -1081,9 +1098,6 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
} }
if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
goto cleanup;
if (qemuDomainMachineIsS390CCW(vm->def) && if (qemuDomainMachineIsS390CCW(vm->def) &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) { virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW; net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
...@@ -1143,23 +1157,36 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -1143,23 +1157,36 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
} }
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
if (qemuMonitorAttachCharDev(priv->mon, charDevAlias, net->data.vhostuser) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditNet(vm, NULL, net, "attach", false);
goto cleanup;
}
charDevPlugged = true;
}
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) { if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
if (qemuMonitorAddNetdev(priv->mon, netstr, if (qemuMonitorAddNetdev(priv->mon, netstr,
tapfd, tapfdName, tapfdSize, tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize) < 0) { vhostfd, vhostfdName, vhostfdSize) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm)); ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditNet(vm, NULL, net, "attach", false); virDomainAuditNet(vm, NULL, net, "attach", false);
goto cleanup; goto try_remove;
} }
netdevPlugged = true;
} else { } else {
if (qemuMonitorAddHostNetwork(priv->mon, netstr, if (qemuMonitorAddHostNetwork(priv->mon, netstr,
tapfd, tapfdName, tapfdSize, tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize) < 0) { vhostfd, vhostfdName, vhostfdSize) < 0) {
ignore_value(qemuDomainObjExitMonitor(driver, vm)); ignore_value(qemuDomainObjExitMonitor(driver, vm));
virDomainAuditNet(vm, NULL, net, "attach", false); virDomainAuditNet(vm, NULL, net, "attach", false);
goto cleanup; goto try_remove;
} }
hostPlugged = true;
} }
if (qemuDomainObjExitMonitor(driver, vm) < 0) if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup; goto cleanup;
...@@ -1262,6 +1289,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -1262,6 +1289,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
} }
VIR_FREE(vhostfd); VIR_FREE(vhostfd);
VIR_FREE(vhostfdName); VIR_FREE(vhostfdName);
VIR_FREE(charDevAlias);
virObjectUnref(cfg); virObjectUnref(cfg);
virDomainCCWAddressSetFree(ccwaddrs); virDomainCCWAddressSetFree(ccwaddrs);
...@@ -1277,7 +1305,11 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -1277,7 +1305,11 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
if (virAsprintf(&netdev_name, "host%s", net->info.alias) < 0) if (virAsprintf(&netdev_name, "host%s", net->info.alias) < 0)
goto cleanup; goto cleanup;
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0) if (charDevPlugged &&
qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0)
VIR_WARN("Failed to remove associated chardev %s", charDevAlias);
if (netdevPlugged &&
qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
VIR_WARN("Failed to remove network backend for netdev %s", VIR_WARN("Failed to remove network backend for netdev %s",
netdev_name); netdev_name);
ignore_value(qemuDomainObjExitMonitor(driver, vm)); ignore_value(qemuDomainObjExitMonitor(driver, vm));
...@@ -1290,7 +1322,8 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, ...@@ -1290,7 +1322,8 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0) if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
goto cleanup; goto cleanup;
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) if (hostPlugged &&
qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
VIR_WARN("Failed to remove network backend for vlan %d, net %s", VIR_WARN("Failed to remove network backend for vlan %d, net %s",
vlan, hostnet_name); vlan, hostnet_name);
ignore_value(qemuDomainObjExitMonitor(driver, vm)); ignore_value(qemuDomainObjExitMonitor(driver, vm));
...@@ -3320,10 +3353,12 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver, ...@@ -3320,10 +3353,12 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
virNetDevVPortProfilePtr vport; virNetDevVPortProfilePtr vport;
virObjectEventPtr event; virObjectEventPtr event;
char *hostnet_name = NULL; char *hostnet_name = NULL;
char *charDevAlias = NULL;
size_t i; size_t i;
int ret = -1; int ret = -1;
int actualType = virDomainNetGetActualType(net);
if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
/* this function handles all hostdev and netdev cleanup */ /* this function handles all hostdev and netdev cleanup */
ret = qemuDomainRemoveHostDevice(driver, vm, ret = qemuDomainRemoveHostDevice(driver, vm,
virDomainNetGetActualHostdev(net)); virDomainNetGetActualHostdev(net));
...@@ -3333,9 +3368,11 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver, ...@@ -3333,9 +3368,11 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
VIR_DEBUG("Removing network interface %s from domain %p %s", VIR_DEBUG("Removing network interface %s from domain %p %s",
net->info.alias, vm, vm->def->name); net->info.alias, vm, vm->def->name);
if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0) if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0 ||
virAsprintf(&charDevAlias, "char%s", net->info.alias) < 0)
goto cleanup; goto cleanup;
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) { if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) { if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
...@@ -3358,6 +3395,17 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver, ...@@ -3358,6 +3395,17 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
} }
} }
if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
/* vhostuser has a chardev too */
if (qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0) {
/* well, this is a messy situation. Guest visible PCI device has
* been removed, netdev too but chardev not. The best seems to be
* to just ignore the error and carry on.
*/
}
}
if (qemuDomainObjExitMonitor(driver, vm) < 0) if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup; goto cleanup;
...@@ -3382,7 +3430,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver, ...@@ -3382,7 +3430,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
&net->mac)); &net->mac));
} }
if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) { if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
ignore_value(virNetDevMacVLanDeleteWithVPortProfile( ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
net->ifname, &net->mac, net->ifname, &net->mac,
virDomainNetGetActualDirectDev(net), virDomainNetGetActualDirectDev(net),
...@@ -3408,6 +3456,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver, ...@@ -3408,6 +3456,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
cleanup: cleanup:
virObjectUnref(cfg); virObjectUnref(cfg);
VIR_FREE(charDevAlias);
VIR_FREE(hostnet_name); VIR_FREE(hostnet_name);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册