提交 2711ac87 编写于 作者: H Hendrik Schwartke 提交者: Laine Stump

qemu: support live change of the bridge used by a guest network device

This patch was created to resolve this upstream bug:

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

and is at least a partial solution to this RHEL RFE:

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

Previously the only attribute of a network device that could be
modified by virUpdateDeviceFlags() ("virsh update-device") was the
link state; attempts to change any other attribute would log an error
and fail.

This patch adds recognition of a change in bridge device name, and
supports reconnecting the guest's interface to the new device.
Standard audit logs for detaching and attaching a network device are
also generated. Although the current auditing function doesn't log the
bridge being attached to, this will later be changed in a separate
patch.
上级 87681495
......@@ -40,6 +40,8 @@
#include "qemu_cgroup.h"
#include "locking/domain_lock.h"
#include "network/bridge_driver.h"
#include "virnetdev.h"
#include "virnetdevbridge.h"
#include "virnetdevtap.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
......@@ -1191,6 +1193,53 @@ static virDomainNetDefPtr qemuDomainFindNet(virDomainObjPtr vm,
return NULL;
}
static
int qemuDomainChangeNetBridge(virDomainObjPtr vm,
virDomainNetDefPtr olddev,
virDomainNetDefPtr newdev)
{
int ret = -1;
char *oldbridge = olddev->data.bridge.brname;
char *newbridge = newdev->data.bridge.brname;
VIR_DEBUG("Change bridge for interface %s: %s -> %s",
olddev->ifname, oldbridge, newbridge);
if (virNetDevExists(newbridge) != 1) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
_("bridge %s doesn't exist"), newbridge);
return -1;
}
if (oldbridge) {
ret = virNetDevBridgeRemovePort(oldbridge, olddev->ifname);
virDomainAuditNet(vm, olddev, NULL, "detach", ret == 0);
if (ret < 0)
return -1;
}
/* move newbridge into olddev now so Audit log is correct */
olddev->data.bridge.brname = newbridge;
ret = virNetDevBridgeAddPort(newbridge, olddev->ifname);
virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
if (ret < 0) {
/* restore oldbridge to olddev */
olddev->data.bridge.brname = oldbridge;
ret = virNetDevBridgeAddPort(oldbridge, olddev->ifname);
virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
if (ret < 0) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
_("unable to recover former state by adding port"
"to bridge %s"), oldbridge);
}
return -1;
}
/* oldbridge no longer needed, and newbridge moved to olddev */
VIR_FREE(oldbridge);
newdev->data.bridge.brname = NULL;
return 0;
}
int qemuDomainChangeNetLinkState(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainNetDefPtr dev,
......@@ -1279,6 +1328,16 @@ int qemuDomainChangeNet(struct qemud_driver *driver,
break;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
/* allow changing brname, but not portprofile */
if (!virNetDevVPortProfileEqual(olddev->data.bridge.virtPortProfile,
dev->data.bridge.virtPortProfile)) {
qemuReportError(VIR_ERR_NO_SUPPORT,
_("cannot modify bridge network device configuration"));
return -1;
}
break;
case VIR_DOMAIN_NET_TYPE_INTERNAL:
if (STRNEQ_NULLABLE(olddev->data.internal.name, dev->data.internal.name)) {
qemuReportError(VIR_ERR_NO_SUPPORT,
......@@ -1321,6 +1380,13 @@ int qemuDomainChangeNet(struct qemud_driver *driver,
return -1;
}
if (olddev->type == VIR_DOMAIN_NET_TYPE_BRIDGE
&& STRNEQ_NULLABLE(olddev->data.bridge.brname,
dev->data.bridge.brname)) {
if ((ret = qemuDomainChangeNetBridge(vm, olddev, dev)) < 0)
return ret;
}
if (olddev->linkstate != dev->linkstate) {
if ((ret = qemuDomainChangeNetLinkState(driver, vm, olddev, dev->linkstate)) < 0)
return ret;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册