[libvirt] [PATCH v3 4/5] link-state: qemu: Add net intf modification to virUpdateDeviceFlags

Daniel Veillard veillard at redhat.com
Tue Sep 6 08:30:43 UTC 2011


On Mon, Sep 05, 2011 at 05:26:53PM +0200, Peter Krempa wrote:
> 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 tereafer changes the link state, if applicable.

  thereafter I guess :-)

> 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.
> ---
>  src/qemu/qemu_driver.c  |   24 +++++++
>  src/qemu/qemu_hotplug.c |  176 +++++++++++++++++++++++++++++++++++++++++++++++
>  src/qemu/qemu_hotplug.h |    8 ++
>  src/qemu/qemu_process.c |   47 ++++++++++++-
>  4 files changed, 254 insertions(+), 1 deletions(-)
> 
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 7028d72..648afae 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -5474,6 +5474,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"),
> @@ -5608,6 +5611,7 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
>                               virDomainDeviceDefPtr dev)
>  {
>      virDomainDiskDefPtr orig, disk;
> +    virDomainNetDefPtr net;
>      int pos;
> 
>      switch (dev->type) {
> @@ -5646,6 +5650,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"));
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 6ae834c..ad57b2f 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -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)
> diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
> index ea1cca0..65d1d30 100644
> --- a/src/qemu/qemu_hotplug.h
> +++ b/src/qemu/qemu_hotplug.h
> @@ -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);
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index c22974f..357bab4 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -1443,7 +1443,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)
> @@ -2981,6 +3014,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

  ACK, but that part is not simple, I wonder how hard it would be to
have regression tests for the various scenarios,

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list