[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