[libvirt] [PATCH 18/23] Add support for hotplug/unplug of NIC devices in LXC

Gao feng gaofeng at cn.fujitsu.com
Fri Dec 14 12:06:49 UTC 2012


On 2012/12/01 04:26, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <berrange at redhat.com>
> 
> Wire up the attach/detach device drivers in LXC to support the
> hotplug/unplug of NICs.
> 
> Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
> ---
>  src/lxc/lxc_driver.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 214 insertions(+), 5 deletions(-)
> 
> diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
> index a2bb497..08ac70d 100644
> --- a/src/lxc/lxc_driver.c
> +++ b/src/lxc/lxc_driver.c
> @@ -3073,9 +3073,141 @@ cleanup:
>  }
>  
>  
> +/* XXX conn required for network -> bridge resolution */
>  static int
> -lxcDomainAttachDeviceLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED,
> -                          virDomainObjPtr vm ATTRIBUTE_UNUSED,
> +lxcDomainAttachDeviceNetLive(virConnectPtr conn,
> +                             virDomainObjPtr vm,
> +                             virDomainNetDefPtr net)
> +{
> +    virLXCDomainObjPrivatePtr priv = vm->privateData;
> +    int ret = -1;
> +    int actualType;
> +    char *veth = NULL;
> +
> +    if (!priv->initpid) {
> +        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                       _("Cannot attach disk until init PID is known"));
> +        goto cleanup;
> +    }
> +
> +    /* preallocate new slot for device */
> +    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0) {
> +        virReportOOMError();
> +        return -1;
> +    }
> +
> +    /* If appropriate, grab a physical device from the configured
> +     * network's pool of devices, or resolve bridge device name
> +     * to the one defined in the network definition.
> +     */
> +    if (networkAllocateActualDevice(net) < 0)
> +        return -1;
> +
> +    actualType = virDomainNetGetActualType(net);
> +
> +    switch (actualType) {
> +    case VIR_DOMAIN_NET_TYPE_BRIDGE: {
> +        const char *brname = virDomainNetGetActualBridgeName(net);
> +        if (!brname) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("No bridge name specified"));
> +            goto cleanup;
> +        }
> +        if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
> +                                                        vm->def,
> +                                                        net,
> +                                                        brname)))
> +            goto cleanup;
> +    }   break;
> +    case VIR_DOMAIN_NET_TYPE_NETWORK: {
> +        virNetworkPtr network;
> +        char *brname = NULL;
> +        bool fail = false;
> +        int active;
> +        virErrorPtr errobj;
> +
> +        if (!(network = virNetworkLookupByName(conn,
> +                                               net->data.network.name)))
> +            goto cleanup;
> +
> +        active = virNetworkIsActive(network);
> +        if (active != 1) {
> +            fail = true;
> +            if (active == 0)
> +                virReportError(VIR_ERR_INTERNAL_ERROR,
> +                               _("Network '%s' is not active."),
> +                               net->data.network.name);
> +        }
> +
> +        if (!fail) {
> +            brname = virNetworkGetBridgeName(network);
> +            if (brname == NULL)
> +                fail = true;
> +        }
> +
> +        /* Make sure any above failure is preserved */
> +        errobj = virSaveLastError();
> +        virNetworkFree(network);
> +        virSetError(errobj);
> +        virFreeError(errobj);
> +
> +        if (fail)
> +            goto cleanup;
> +
> +        if (!(veth = virLXCProcessSetupInterfaceBridged(conn,
> +                                                        vm->def,
> +                                                        net,
> +                                                        brname))) {
> +            VIR_FREE(brname);
> +            goto cleanup;
> +        }
> +        VIR_FREE(brname);
> +    }   break;
> +    case VIR_DOMAIN_NET_TYPE_DIRECT: {
> +        if (!(veth = virLXCProcessSetupInterfaceDirect(conn,
> +                                                       vm->def,
> +                                                       net)))
> +            goto cleanup;
> +    }   break;
> +    default:
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("Network device type is not supported"));
> +        goto cleanup;
> +    }
> +
> +    if (virNetDevSetNamespace(veth, priv->initpid) < 0) {
> +        virDomainAuditNet(vm, NULL, net, "attach", false);


Maybe it's better to move failed audit to the cleanup path.


> +        goto cleanup;
> +    }
> +
> +    virDomainAuditNet(vm, NULL, net, "attach", true);
> +
> +    ret = 0;
> +
> +cleanup:
> +    if (!ret) {
> +        vm->def->nets[vm->def->nnets++] = net;
> +    } else if (veth) {
> +        switch (actualType) {
> +        case VIR_DOMAIN_NET_TYPE_BRIDGE:
> +        case VIR_DOMAIN_NET_TYPE_NETWORK:
> +            ignore_value(virNetDevVethDelete(veth));
> +            break;
> +
> +        case VIR_DOMAIN_NET_TYPE_DIRECT:
> +            ignore_value(virNetDevMacVLanDelete(veth));
> +            break;
> +        }
> +    }
> +
> +    return ret;
> +}
> +
> +
> +static int
> +lxcDomainAttachDeviceLive(virConnectPtr conn,
> +                          virLXCDriverPtr driver,
> +                          virDomainObjPtr vm,
>                            virDomainDeviceDefPtr dev)
>  {
>      int ret = -1;
> @@ -3087,6 +3219,13 @@ lxcDomainAttachDeviceLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED,
>              dev->data.disk = NULL;
>          break;
>  
> +    case VIR_DOMAIN_DEVICE_NET:
> +        ret = lxcDomainAttachDeviceNetLive(conn, vm,
> +                                           dev->data.net);
> +        if (!ret)
> +            dev->data.net = NULL;
> +        break;
> +
>      default:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                         _("device type '%s' cannot be attached"),
> @@ -3170,8 +3309,74 @@ cleanup:
>  
>  
>  static int
> -lxcDomainDetachDeviceLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED,
> -                          virDomainObjPtr vm ATTRIBUTE_UNUSED,
> +lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
> +                             virDomainDeviceDefPtr dev)
> +{
> +    int detachidx, ret = -1;
> +    virDomainNetDefPtr detach = NULL;
> +    char mac[VIR_MAC_STRING_BUFLEN];
> +    virNetDevVPortProfilePtr vport = NULL;
> +
> +    detachidx = virDomainNetFindIdx(vm->def, dev->data.net);
> +    if (detachidx == -2) {
> +        virReportError(VIR_ERR_OPERATION_FAILED,
> +                       _("multiple devices matching mac address %s found"),
> +                       virMacAddrFormat(&dev->data.net->mac, mac));
> +        goto cleanup;
> +    } else if (detachidx < 0) {
> +        virReportError(VIR_ERR_OPERATION_FAILED,
> +                       _("network device %s not found"),
> +                       virMacAddrFormat(&dev->data.net->mac, mac));
> +        goto cleanup;
> +    }
> +    detach = vm->def->nets[detachidx];
> +
> +    switch (virDomainNetGetActualType(detach)) {
> +    case VIR_DOMAIN_NET_TYPE_BRIDGE:
> +    case VIR_DOMAIN_NET_TYPE_NETWORK:
> +        if (virNetDevVethDelete(detach->ifname) < 0) {
> +            virDomainAuditNet(vm, detach, NULL, "detach", false);
> +            goto cleanup;
> +        }
> +        break;
> +
> +        /* It'd be nice to support this, but with macvlan
> +         * once assigned to a container nothing exists on
> +         * the host side. Further the container can change
> +         * the mac address of NIC name, so we can't easily
> +         * find out which guest NIC it maps to
> +    case VIR_DOMAIN_NET_TYPE_DIRECT:
> +        */
> +
> +    default:
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("Only bridged veth devices can be detached"));
> +        goto cleanup;
> +    }
> +
> +    virDomainAuditNet(vm, detach, NULL, "detach", true);
> +
> +    virDomainConfNWFilterTeardown(detach);
> +
> +    vport = virDomainNetGetActualVirtPortProfile(detach);
> +    if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)
> +        ignore_value(virNetDevOpenvswitchRemovePort(
> +                        virDomainNetGetActualBridgeName(detach),
> +                        detach->ifname));
> +    ret = 0;
> +cleanup:
> +    if (!ret) {
> +        networkReleaseActualDevice(detach);
> +        virDomainNetRemove(vm->def, detachidx);
> +        virDomainNetDefFree(detach);
> +    }

    else
        virDomainAuditNet(vm, detach, NULL, "detach", false);

ACK




More information about the libvir-list mailing list