mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-09 01:04:59 +00:00
link-state: qemu: Add net intf modification to virUpdateDeviceFlags
This patch enables modifying network device configuration using the virUpdateDeviceFlags API method. Matching of devices is accomplished using MAC addresses. While updating live configuration of a running domain, the user is allowed only to change link state of the interface. Additional modifications may be added later. For now the code checks for unsupported changes and thereafter changes the link state, if applicable. When updating persistent configuration of guest's network interface the whole configuration (except for the MAC address) may be modified and is stored for the next startup. * src/qemu/qemu_driver.c - Add dispatching of virUpdateDevice for network devices update (live/config) * src/qemu/qemu_hotplug.c - add setting of initial link state on live device addition - add function to change network device configuration. By now it supports only changing of link state * src/qemu/qemu_hotplug.h - Headers to above functions * src/qemu/qemu_process.c - set link states before virtual machine start. Qemu does not support setting of this on the command line.
This commit is contained in:
parent
8277c15151
commit
e0a07bb1f2
@ -5492,6 +5492,9 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
|
||||
case VIR_DOMAIN_DEVICE_GRAPHICS:
|
||||
ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
|
||||
break;
|
||||
case VIR_DOMAIN_DEVICE_NET:
|
||||
ret = qemuDomainChangeNet(driver, vm, dom, dev->data.net);
|
||||
break;
|
||||
default:
|
||||
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("device type '%s' cannot be updated"),
|
||||
@ -5626,6 +5629,7 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
|
||||
virDomainDeviceDefPtr dev)
|
||||
{
|
||||
virDomainDiskDefPtr orig, disk;
|
||||
virDomainNetDefPtr net;
|
||||
int pos;
|
||||
|
||||
switch (dev->type) {
|
||||
@ -5664,6 +5668,26 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
|
||||
}
|
||||
disk->src = NULL;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_DEVICE_NET:
|
||||
net = dev->data.net;
|
||||
if ((pos = virDomainNetIndexByMac(vmdef, net->mac)) < 0) {
|
||||
char macbuf[VIR_MAC_STRING_BUFLEN];
|
||||
virFormatMacAddr(net->mac, macbuf);
|
||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||
_("mac %s doesn't exist"), macbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_FREE(vmdef->nets[pos]);
|
||||
|
||||
vmdef->nets[pos] = net;
|
||||
dev->data.net = NULL;
|
||||
|
||||
if (qemuDomainAssignPCIAddresses(vmdef) < 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("persistent update of device is not supported"));
|
||||
|
@ -751,6 +751,30 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
|
||||
}
|
||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||
|
||||
/* set link state */
|
||||
if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
|
||||
if (!net->info.alias) {
|
||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("device alias not found: cannot set link state to down"));
|
||||
} else {
|
||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||
|
||||
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
|
||||
if (qemuMonitorSetLink(priv->mon, net->info.alias, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) < 0) {
|
||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||
virDomainAuditNet(vm, NULL, net, "attach", false);
|
||||
goto try_remove;
|
||||
}
|
||||
} else {
|
||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("setting of link state not supported: Link is up"));
|
||||
}
|
||||
|
||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||
}
|
||||
/* link set to down */
|
||||
}
|
||||
|
||||
virDomainAuditNet(vm, NULL, net, "attach", true);
|
||||
|
||||
ret = 0;
|
||||
@ -1082,6 +1106,158 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static virDomainNetDefPtr qemuDomainFindNet(virDomainObjPtr vm,
|
||||
virDomainNetDefPtr dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vm->def->nnets; i++) {
|
||||
if (memcmp(vm->def->nets[i]->mac, dev->mac, VIR_MAC_BUFLEN) == 0)
|
||||
return vm->def->nets[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int qemuDomainChangeNetLinkState(struct qemud_driver *driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainNetDefPtr dev,
|
||||
int linkstate)
|
||||
{
|
||||
int ret = -1;
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
|
||||
VIR_DEBUG("dev: %s, state: %d", dev->info.alias, linkstate);
|
||||
|
||||
if (!dev->info.alias) {
|
||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("can't change link state: device alias not found"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||
|
||||
ret = qemuMonitorSetLink(priv->mon, dev->info.alias, linkstate);
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* modify the device configuration */
|
||||
dev->linkstate = linkstate;
|
||||
|
||||
cleanup:
|
||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qemuDomainChangeNet(struct qemud_driver *driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainPtr dom ATTRIBUTE_UNUSED,
|
||||
virDomainNetDefPtr dev)
|
||||
|
||||
{
|
||||
virDomainNetDefPtr olddev = qemuDomainFindNet(vm, dev);
|
||||
int ret = 0;
|
||||
|
||||
if (!olddev) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot find existing network device to modify"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (olddev->type != dev->type) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot change network interface type"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (olddev->type) {
|
||||
case VIR_DOMAIN_NET_TYPE_USER:
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||
if (STRNEQ_NULLABLE(olddev->data.ethernet.dev, dev->data.ethernet.dev) ||
|
||||
STRNEQ_NULLABLE(olddev->data.ethernet.script, dev->data.ethernet.script) ||
|
||||
STRNEQ_NULLABLE(olddev->data.ethernet.ipaddr, dev->data.ethernet.ipaddr)) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot modify ethernet network device configuration"));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_NET_TYPE_SERVER:
|
||||
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
||||
case VIR_DOMAIN_NET_TYPE_MCAST:
|
||||
if (STRNEQ_NULLABLE(olddev->data.socket.address, dev->data.socket.address) ||
|
||||
olddev->data.socket.port != dev->data.socket.port) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot modify network socket device configuration"));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
||||
if (STRNEQ_NULLABLE(olddev->data.network.name, dev->data.network.name) ||
|
||||
STRNEQ_NULLABLE(olddev->data.network.portgroup, dev->data.network.portgroup) ||
|
||||
!virVirtualPortProfileEqual(olddev->data.network.virtPortProfile, dev->data.network.virtPortProfile)) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot modify 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,
|
||||
_("cannot modify internal network device configuration"));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
||||
if (STRNEQ_NULLABLE(olddev->data.direct.linkdev, dev->data.direct.linkdev) ||
|
||||
olddev->data.direct.mode != dev->data.direct.mode ||
|
||||
!virVirtualPortProfileEqual(olddev->data.direct.virtPortProfile, dev->data.direct.virtPortProfile)) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot modify direct network device configuration"));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unable to change config on '%s' network type"),
|
||||
virDomainNetTypeToString(dev->type));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* all other unmodifiable parameters */
|
||||
if (STRNEQ_NULLABLE(olddev->model, dev->model) ||
|
||||
STRNEQ_NULLABLE(olddev->filter, dev->filter)) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot modify network device configuration"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check if device name has been set, if no, retain the autogenerated one */
|
||||
if (dev->ifname &&
|
||||
STRNEQ_NULLABLE(olddev->ifname, dev->ifname)) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot modify network device configuration"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (olddev->linkstate != dev->linkstate) {
|
||||
if ((ret = qemuDomainChangeNetLinkState(driver, vm, olddev, dev->linkstate)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static virDomainGraphicsDefPtr qemuDomainFindGraphics(virDomainObjPtr vm,
|
||||
virDomainGraphicsDefPtr dev)
|
||||
|
@ -67,6 +67,14 @@ int qemuDomainChangeGraphicsPasswords(struct qemud_driver *driver,
|
||||
int type,
|
||||
virDomainGraphicsAuthDefPtr auth,
|
||||
const char *defaultPasswd);
|
||||
int qemuDomainChangeNet(struct qemud_driver *driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainPtr dom,
|
||||
virDomainNetDefPtr dev);
|
||||
int qemuDomainChangeNetLinkState(struct qemud_driver *driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainNetDefPtr dev,
|
||||
int linkstate);
|
||||
int qemuDomainDetachPciDiskDevice(struct qemud_driver *driver,
|
||||
virDomainObjPtr vm,
|
||||
virDomainDeviceDefPtr dev);
|
||||
|
@ -1453,7 +1453,40 @@ qemuProcessInitCpuAffinity(virDomainObjPtr vm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set CPU affinites for vcpus if vcpupin xml provided. */
|
||||
/* set link states to down on interfaces at qemu start */
|
||||
static int
|
||||
qemuProcessSetLinkStates(virDomainObjPtr vm)
|
||||
{
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
virDomainDefPtr def = vm->def;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < def->nnets; i++) {
|
||||
if (def->nets[i]->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
|
||||
VIR_DEBUG("Setting link state: %s", def->nets[i]->info.alias);
|
||||
|
||||
if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
|
||||
qemuReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("Setting of link state is not supported by this qemu"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = qemuMonitorSetLink(priv->mon,
|
||||
def->nets[i]->info.alias,
|
||||
VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN);
|
||||
if (ret != 0) {
|
||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Couldn't set link state on interface: %s"), def->nets[i]->info.alias);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set CPU affinities for vcpus if vcpupin xml provided. */
|
||||
static int
|
||||
qemuProcessSetVcpuAffinites(virConnectPtr conn,
|
||||
virDomainObjPtr vm)
|
||||
@ -3081,6 +3114,18 @@ int qemuProcessStart(virConnectPtr conn,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* set default link states */
|
||||
/* qemu doesn't support setting this on the command line, so
|
||||
* enter the monitor */
|
||||
VIR_DEBUG("Setting network link states");
|
||||
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||
if (qemuProcessSetLinkStates(vm) < 0) {
|
||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||
|
||||
/* Technically, qemuProcessStart can be called from inside
|
||||
* QEMU_ASYNC_JOB_MIGRATION_IN, but we are okay treating this like
|
||||
* a sync job since no other job can call into the domain until
|
||||
|
Loading…
Reference in New Issue
Block a user