Re: [libvirt] [PATCH 10/10] network: internal API functions to manage assignment of physdev to guest
On 07/08/2011 04:37 PM, Eric Blake wrote: On 07/05/2011 01:45 AM, Laine Stump wrote: The network driver needs to assign physical devices for use by modes that use macvtap, keeping track of which physical devices are in use (and how many instances, when the devices can be shared). Three calls are added: networkAllocateActualDevice - finds a physical device for use by the domain, and sets up the virDomainActualNetDef accordingly. networkNotifyActualDevice - assumes that the domain was already running, but libvirtd was restarted, and needs to be notified by each already-running domain about what interfaces they are using. networkReleaseActualDevice - decrements the usage count of the allocated physical device, and frees the virDomainActualNetDef to avoid later accidentally using the device. bridge_driver.[hc] - the new APIs qemu_(command|driver|hotplug|process).c - add calls to the above APIs in the appropriate places. tests/Makefile.am - need to include libvirt_driver_network.la whenever libvirt_driver_qemu.la is linked, to avoid unreferenced symbols (in functions that are never called by the test programs...) --- src/network/bridge_driver.c | 398 +++ src/network/bridge_driver.h |6 + src/qemu/qemu_command.c | 11 ++ src/qemu/qemu_hotplug.c | 41 +++-- src/qemu/qemu_process.c | 26 +++- tests/Makefile.am | 12 +- 6 files changed, 476 insertions(+), 18 deletions(-) + +/* Find the most specific virtportprofile and copy it */ +if (iface-data.network.virtPortProfile) { +virtport = iface-data.network.virtPortProfile; +} else { +virPortGroupDefPtr portgroup + = virPortGroupFindByName(netdef, iface-data.network.portgroup); +if (portgroup) +virtport = portgroup-virtPortProfile; Nit: Indentation looks interesting there - the line starting with = has one less space. Perhaps something to do with how your preferred editor splits assignments. My editor uses 4 spaces instead of 3 in that instance. It defaults to a different style, and I sometimes forget to switch. +int +networkNotifyActualDevice(virDomainNetDefPtr iface) +{ + +/* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both require + * exclusive access to a device, so current usageCount must be + * 0 in those cases. + */ +if ((dev-usageCount 0) +((netdef-forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) || + ((netdef-forwardType == VIR_NETWORK_FORWARD_PRIVATE) + iface-data.network.actual-data.direct.virtPortProfile + (iface-data.network.actual-data.direct.virtPortProfile-virtPortType + == VIR_VIRTUALPORT_8021QBH { +networkReportError(VIR_ERR_INTERNAL_ERROR, + _(network '%s' claims dev='%s' is already in use by a different domain), Do we have a data race here? Suppose that libvirtd is restarted while one VM is already using device 0. Is there any chance that if I'm fast enough, I can cause the creation of a second domain, and that second domain will go to pick from the interface pool before the notification pass of the libvirtd restart has completed, and mistakenly claim device 0? That is, I think we need to somehow guarantee (if we don't already) that no new domains can be created until after all existing domains have been reloaded on a libvirtd restart. I was concerned about this at first too. Here's the call chain down to this function (it's only called from one place): networkNotifyActualDevice qemuProcessNotifyNets qemuProcessReconnect qemuProcessReconnectAll qemudStartup - aka the initialize function of the qemu state driver. At the top of qemudStartup, the lock for the driver is initialized, then locked. After this, a ton of stuff is initialized, including calling qemuProcessReconnectAll(), then the worker thread pool is created, and finally the driver lock is released. So as far as I understand it, it's not possible for a new domain to be created until after this is all finished. -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 10/10] network: internal API functions to manage assignment of physdev to guest
On 07/08/2011 04:23 PM, Eric Blake wrote: On 07/05/2011 10:18 PM, Laine Stump wrote: I realized that PATCH 10/10 would cause the build to fail if someone did a build --with-qemu but --without-network. I'm squashing the following into the original patch to remedy that. I'm not really a fan of putting #if all over the place, but this is similar to what's done with WITH_MACVTAP, so at least there's precedence. (This is necessary because this new backend API to the network driver isn't called via a pointer table filled in at runtime, as is done with the public API). Would it be any easier to instead guarantee that even when #if WITH_NETWORK is false, those same symbols are available as no-ops to allow compilation to proceed? That would mean either defining the functions inside qemu, or creating a dummy network module replacement to be built when WITH_NETWORK is false. I like both of those options even less. +#if WITH_NETWORK /* 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) goto error; - +#endif That is, make networkAllocateActualDevice() be a no-op that returns 0 if there is no network support compiled in, and therefore nothing to allocate. But where would that NOP function live? The natural place for a function called networkSomething is in a network driver, but there isn't one. +++ b/tests/Makefile.am @@ -319,8 +319,11 @@ endif if WITH_QEMU -qemu_LDADDS = ../src/libvirt_driver_qemu.la \ - ../src/libvirt_driver_network.la +qemu_LDADDS = ../src/libvirt_driver_qemu.la + +if WITH_NETWORK +qemu_LDADDS += ../src/libvirt_driver_network.la +endif Then again, if you are compiling --without-network, you don't want to link against a library that won't be built. That would imply that any no-op stubs would have to be provided by static inline functions in the header in the no-network case. Ah, you're doing this mail On the Road style (stream of consciousness with no going back to edit), so I'll respond that way too :-) Actually, I like this idea - in bridge_driver.h, I can put the function declrations inside #if WITH_NETWORK, and have a #else clause that contains inlines that return success but do nothing (exactly what is needed). That way the code in qemu won't need #if. I'll do it that way in the next version. -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 10/10] network: internal API functions to manage assignment of physdev to guest
On 07/05/2011 01:45 AM, Laine Stump wrote: The network driver needs to assign physical devices for use by modes that use macvtap, keeping track of which physical devices are in use (and how many instances, when the devices can be shared). Three calls are added: networkAllocateActualDevice - finds a physical device for use by the domain, and sets up the virDomainActualNetDef accordingly. networkNotifyActualDevice - assumes that the domain was already running, but libvirtd was restarted, and needs to be notified by each already-running domain about what interfaces they are using. networkReleaseActualDevice - decrements the usage count of the allocated physical device, and frees the virDomainActualNetDef to avoid later accidentally using the device. bridge_driver.[hc] - the new APIs qemu_(command|driver|hotplug|process).c - add calls to the above APIs in the appropriate places. tests/Makefile.am - need to include libvirt_driver_network.la whenever libvirt_driver_qemu.la is linked, to avoid unreferenced symbols (in functions that are never called by the test programs...) --- src/network/bridge_driver.c | 398 +++ src/network/bridge_driver.h |6 + src/qemu/qemu_command.c | 11 ++ src/qemu/qemu_hotplug.c | 41 +++-- src/qemu/qemu_process.c | 26 +++- tests/Makefile.am | 12 +- 6 files changed, 476 insertions(+), 18 deletions(-) + +/* Find the most specific virtportprofile and copy it */ +if (iface-data.network.virtPortProfile) { +virtport = iface-data.network.virtPortProfile; +} else { +virPortGroupDefPtr portgroup + = virPortGroupFindByName(netdef, iface-data.network.portgroup); +if (portgroup) +virtport = portgroup-virtPortProfile; Nit: Indentation looks interesting there - the line starting with = has one less space. Perhaps something to do with how your preferred editor splits assignments. My editor uses 4 spaces instead of 3 in that instance. +if (!netdef-forwardDev) { +networkReportError(VIR_ERR_INTERNAL_ERROR, + _(network '%s' uses a direct mode, but has no forward dev and no interface pool), + netdef-name); +goto cleanup; +} +iface-data.network.actual-data.direct.linkdev += strdup(netdef-forwardDev); And here you used a multiple of four spaces. +int +networkNotifyActualDevice(virDomainNetDefPtr iface) +{ + +/* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both require + * exclusive access to a device, so current usageCount must be + * 0 in those cases. + */ +if ((dev-usageCount 0) +((netdef-forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) || + ((netdef-forwardType == VIR_NETWORK_FORWARD_PRIVATE) + iface-data.network.actual-data.direct.virtPortProfile + (iface-data.network.actual-data.direct.virtPortProfile-virtPortType + == VIR_VIRTUALPORT_8021QBH { +networkReportError(VIR_ERR_INTERNAL_ERROR, + _(network '%s' claims dev='%s' is already in use by a different domain), Do we have a data race here? Suppose that libvirtd is restarted while one VM is already using device 0. Is there any chance that if I'm fast enough, I can cause the creation of a second domain, and that second domain will go to pick from the interface pool before the notification pass of the libvirtd restart has completed, and mistakenly claim device 0? That is, I think we need to somehow guarantee (if we don't already) that no new domains can be created until after all existing domains have been reloaded on a libvirtd restart. -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org signature.asc Description: OpenPGP digital signature -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 10/10] network: internal API functions to manage assignment of physdev to guest
The network driver needs to assign physical devices for use by modes that use macvtap, keeping track of which physical devices are in use (and how many instances, when the devices can be shared). Three calls are added: networkAllocateActualDevice - finds a physical device for use by the domain, and sets up the virDomainActualNetDef accordingly. networkNotifyActualDevice - assumes that the domain was already running, but libvirtd was restarted, and needs to be notified by each already-running domain about what interfaces they are using. networkReleaseActualDevice - decrements the usage count of the allocated physical device, and frees the virDomainActualNetDef to avoid later accidentally using the device. bridge_driver.[hc] - the new APIs qemu_(command|driver|hotplug|process).c - add calls to the above APIs in the appropriate places. tests/Makefile.am - need to include libvirt_driver_network.la whenever libvirt_driver_qemu.la is linked, to avoid unreferenced symbols (in functions that are never called by the test programs...) --- src/network/bridge_driver.c | 398 +++ src/network/bridge_driver.h |6 + src/qemu/qemu_command.c | 11 ++ src/qemu/qemu_hotplug.c | 41 +++-- src/qemu/qemu_process.c | 26 +++- tests/Makefile.am | 12 +- 6 files changed, 476 insertions(+), 18 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 69d4c35..02d7b8b 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2702,3 +2702,401 @@ int networkRegister(void) { virRegisterStateDriver(networkStateDriver); return 0; } + +// + +/* Private API to deal with logical switch capabilities. + * These functions are exported so that other parts of libvirt can + * call them, but are not part of the public API and not in the + * driver's function table. If we ever have more than one network + * driver, we will need to present these functions via a second + * backend function table. + */ + +/* networkAllocateActualDevice: + * @iface: the original NetDef from the domain + * + * Looks up the network reference by iface, allocates a physical + * device from that network (if appropriate), and returns with the + * virDomainActualNetDef filled in accordingly. If there are no + * changes to be made in the netdef, then just leave the actualdef + * empty. + * + * Returns 0 on success, -1 on failure. + */ +int +networkAllocateActualDevice(virDomainNetDefPtr iface) +{ +struct network_driver *driver = driverState; +virNetworkObjPtr network; +virNetworkDefPtr netdef; +int ret = -1; + +if (iface-type != VIR_DOMAIN_NET_TYPE_NETWORK) +return 0; + +virDomainActualNetDefFree(iface-data.network.actual); +iface-data.network.actual = NULL; + +networkDriverLock(driver); +network = virNetworkFindByName(driver-networks, iface-data.network.name); +networkDriverUnlock(driver); +if (!network) { +networkReportError(VIR_ERR_NO_NETWORK, + _(no network with matching name '%s'), + iface-data.network.name); +goto cleanup; +} + +netdef = network-def; +if ((netdef-forwardType == VIR_NETWORK_FORWARD_BRIDGE) +netdef-bridge) { + +/* forward type='bridge'/ bridge name='xxx'/ + * is VIR_DOMAIN_NET_TYPE_BRIDGE + */ + +if (VIR_ALLOC(iface-data.network.actual) 0) { +virReportOOMError(); +goto cleanup; +} + +iface-data.network.actual-type = VIR_DOMAIN_NET_TYPE_BRIDGE; +iface-data.network.actual-data.bridge.brname = strdup(netdef-bridge); +if (!iface-data.network.actual-data.bridge.brname) { +virReportOOMError(); +goto cleanup; +} + +} else if ((netdef-forwardType == VIR_NETWORK_FORWARD_BRIDGE) || + (netdef-forwardType == VIR_NETWORK_FORWARD_PRIVATE) || + (netdef-forwardType == VIR_NETWORK_FORWARD_VEPA) || + (netdef-forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH)) { +virVirtualPortProfileParamsPtr virtport = NULL; + +/* forward type='bridge|private|vepa|passthrough' are all + * VIR_DOMAIN_NET_TYPE_DIRECT. + */ + +if (VIR_ALLOC(iface-data.network.actual) 0) { +virReportOOMError(); +goto cleanup; +} + +/* Set type=direct and appropriate source mode='xxx'/ */ +iface-data.network.actual-type = VIR_DOMAIN_NET_TYPE_DIRECT; +switch (netdef-forwardType) { +case VIR_NETWORK_FORWARD_BRIDGE: +iface-data.network.actual-data.direct.mode = VIR_MACVTAP_MODE_BRIDGE; +break; +case VIR_NETWORK_FORWARD_PRIVATE: +iface-data.network.actual-data.direct.mode = VIR_MACVTAP_MODE_PRIVATE; +break; +case
Re: [libvirt] [PATCH 10/10] network: internal API functions to manage assignment of physdev to guest
I realized that PATCH 10/10 would cause the build to fail if someone did a build --with-qemu but --without-network. I'm squashing the following into the original patch to remedy that. I'm not really a fan of putting #if all over the place, but this is similar to what's done with WITH_MACVTAP, so at least there's precedence. (This is necessary because this new backend API to the network driver isn't called via a pointer table filled in at runtime, as is done with the public API). --- src/qemu/qemu_command.c |5 - src/qemu/qemu_hotplug.c |8 ++-- src/qemu/qemu_process.c |8 ++-- tests/Makefile.am |7 +-- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d6a0c6d..0b957cb 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3678,13 +3678,14 @@ qemuBuildCommandLine(virConnectPtr conn, else vlan = i; +#if WITH_NETWORK /* 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) goto error; - +#endif actualType = virDomainNetGetActualType(net); if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK || actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) { @@ -4682,8 +4683,10 @@ qemuBuildCommandLine(virConnectPtr conn, virReportOOMError(); error: /* free up any resources in the network driver */ +#if WITH_NETWORK for (i = 0 ; i def-nnets ; i++) networkReleaseActualDevice(def-nets[i]); +#endif for (i = 0; i = last_good_net; i++) virDomainConfNWFilterTeardown(def-nets[i]); virBufferFreeAndReset(rbd_hosts); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 37cfbef..5f1a424 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -613,13 +613,14 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, return -1; } +#if WITH_NETWORK /* 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) goto cleanup; - +#endif actualType = virDomainNetGetActualType(net); if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE || actualType == VIR_DOMAIN_NET_TYPE_NETWORK) { @@ -761,7 +762,9 @@ cleanup: if (iface_connected) virDomainConfNWFilterTeardown(net); +#if WITH_NETWORK networkReleaseActualDevice(net); +#endif } VIR_FREE(nicstr); @@ -1644,8 +1647,9 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver, } } +#if WITH_NETWORK networkReleaseActualDevice(detach); - +#endif if (vm-def-nnets 1) { memmove(vm-def-nets + i, vm-def-nets + i + 1, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index f4a57ff..709f187 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2168,6 +2168,7 @@ int qemuProcessStopCPUs(struct qemud_driver *driver, virDomainObjPtr vm, +#if WITH_NETWORK static int qemuProcessNotifyNets(virDomainDefPtr def) { @@ -2180,7 +2181,7 @@ qemuProcessNotifyNets(virDomainDefPtr def) } return 0; } - +#endif static int qemuProcessFiltersInstantiate(virConnectPtr conn, @@ -2294,9 +2295,10 @@ qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opa if (virSecurityManagerReserveLabel(driver-securityManager, obj) 0) goto error; +#if WITH_NETWORK if (qemuProcessNotifyNets(obj-def) 0) goto error; - +#endif if (qemuProcessFiltersInstantiate(conn, obj-def)) goto error; @@ -2932,7 +2934,9 @@ void qemuProcessStop(struct qemud_driver *driver, /* release the physical device (or any other resources used by * this interface in the network driver */ +#if WITH_NETWORK networkReleaseActualDevice(net); +#endif } retry: diff --git a/tests/Makefile.am b/tests/Makefile.am index a9ad759..6afec28 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -319,8 +319,11 @@ endif if WITH_QEMU -qemu_LDADDS = ../src/libvirt_driver_qemu.la \ - ../src/libvirt_driver_network.la +qemu_LDADDS = ../src/libvirt_driver_qemu.la + +if WITH_NETWORK +qemu_LDADDS += ../src/libvirt_driver_network.la +endif qemuxml2argvtest_SOURCES = \ qemuxml2argvtest.c testutilsqemu.c testutilsqemu.h \ -- 1.7.3.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list