mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 11:22:23 +00:00
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.
This commit is contained in:
parent
8768149545
commit
2711ac8716
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user