On 2012/12/01 04:26, Daniel P. Berrange wrote: > From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> > > Wire up the attach/detach device drivers in LXC to support the > hotplug/unplug of NICs. > > Signed-off-by: Daniel P. Berrange <berrange@xxxxxxxxxx> > --- > 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list