[libvirt] [PATCH v4 2/3] network: Introduce network hooks
Laine Stump
laine at laine.org
Wed Feb 12 18:20:37 UTC 2014
On 02/12/2014 07:07 PM, Michal Privoznik wrote:
> There might be some use cases, where user wants to prepare the host or
> its environment prior to starting a network and do some cleanup after
> the network has been shut down. Consider all the functionality that
> libvirt doesn't currently have as an example what a hook script can
> possibly do.
>
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
> docs/hooks.html.in | 98 ++++++++++++++++++++++++++++++++++++++-------
> src/lxc/lxc_driver.c | 4 +-
> src/lxc/lxc_process.c | 6 +--
> src/network/bridge_driver.c | 91 +++++++++++++++++++++++++++++++++++++++--
> src/network/bridge_driver.h | 19 +++++----
> src/qemu/qemu_command.c | 2 +-
> src/qemu/qemu_hotplug.c | 14 +++----
> src/qemu/qemu_process.c | 4 +-
> src/util/virhook.c | 13 +++++-
> src/util/virhook.h | 11 +++++
> 10 files changed, 220 insertions(+), 42 deletions(-)
>
> diff --git a/docs/hooks.html.in b/docs/hooks.html.in
> index f0f692b..29995f7 100644
> --- a/docs/hooks.html.in
> +++ b/docs/hooks.html.in
> @@ -13,9 +13,15 @@
> actions occur:</p>
> <ul>
> <li>The libvirt daemon starts, stops, or reloads its
> - configuration<br/><br/></li>
> - <li>A QEMU guest is started or stopped<br/><br/></li>
> - <li>An LXC guest is started or stopped<br/><br/></li>
> + configuration
> + (<span class="since">since 0.8.0</span>)<br/><br/></li>
> + <li>A QEMU guest is started or stopped
> + (<span class="since">since 0.8.0</span>)<br/><br/></li>
> + <li>An LXC guest is started or stopped
> + (<span class="since">since 0.8.0</span>)<br/><br/></li>
> + <li>A network is started or stopped or an interface is
> + un-/plugged from/to the network
> + (<span class="since">since 1.2.2</span>)<br/><br/></li>
> </ul>
>
> <h2><a name="location">Script location</a></h2>
> @@ -44,6 +50,9 @@
> Executed when a QEMU guest is started, stopped, or migrated<br/><br/></li>
> <li><code>/etc/libvirt/hooks/lxc</code><br /><br/>
> Executed when an LXC guest is started or stopped</li>
> + <li><code>/etc/libvirt/hooks/network</code><br/><br/>
> + Executed when a network is started or stopped or an
> + interface is un-/plugged from/to the network</li>
further down you use "plugged/unplugged", which I think looks better
(you'll then want to change "from/to" to "to/from" as well, or just use
"to" for simplicity)
> </ul>
> <br/>
>
> @@ -66,6 +75,39 @@
> XML description for the domain on their stdin. This includes items
> such the UUID of the domain and its storage information, and is
> intended to provide all the libvirt information the script needs.</p>
> + <p>For all cases, stdin of the network hook script is provided with the
> + full XML description of the network status in the following form:</p>
> +
> +<pre><hookData>
> + <network>
> + <name>$network_name</name>
> + <uuid>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</uuid>
> + ...
> + </network>
> +</hookData></pre>
> +
> + <p>In the case of an interface
> + being plugged/unplugged to the network, the network XML will be followed
> + with the full XML description of the domain containing the interface
> + that is being plugged/unplugged:</p>
> +
> +<pre><hookData>
> + <network>
> + <name>$network_name</name>
> + <uuid>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</uuid>
Do we use "XXXX..." for uuid examples anywhere else? The few examples I
found in the existing documentation were actual valid uuids.
> + ...
> + </network>
> + <domain type='$domain_type' id='$domain_id'>
> + <name>$domain_name</name>
> + <uuid>XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX</uuid>
> + ...
> + </domain>
> +</hookData></pre>
> +
> + <p>Please note that this approach is different to other cases such as
"different from other cases"
> + <code>daemon</code>, <code>qemu</code> or <code>lxc</code> hook scripts,
> + because two XMLs may be passed here, while in the other cases only a single
> + XML is passed.</p>
>
> <p>The command line arguments take this approach:</p>
> <ol>
> @@ -181,25 +223,51 @@
> <pre>/etc/libvirt/hooks/lxc guest_name reconnect begin -</pre>
> </li>
> </ul>
> +
> + <h5><a name="network">/etc/libvirt/hooks/network</a></h5>
> + <ul>
> + <li><span class="since">Since 1.2.2</span>, before a network is started,
> + this script is called as:<br/>
> + <pre>/etc/libvirt/hooks/network network_name start begin -</pre></li>
> + <li>After the network is started, up ∧ running, the script is
> + called as:<br/>
> + <pre>/etc/libvirt/hooks/network network_name started begin -</pre></li>
> + <li>When a network is shut down, this script is called as:<br/>
> + <pre>/etc/libvirt/hooks/network network_name stopped end -</pre></li>
> + <li>Later, when network is started and there's an interface from a
> + domain to be plugged into the network (plugged may not be the correct
> + expression when it comes to bridgeless networks, perhaps allocated is
> + better one then), the hook script is called as:<br/>
you can just remove that comment in ( )
> + <pre>/etc/libvirt/hooks/network network_name plugged begin -</pre>
> + Please note, that in this case, the script is passed both network and
> + domain XMLs on its stdin.</li>
> + <li>When the domain from previous case is shutting down, the interface
> + is unplugged. This leads to another script invocation:<br/>
> + <pre>/etc/libvirt/hooks/network network_name unplugged begin -</pre>
> + And again, as in previous case, both network and domain XMLs are passed
> + onto script's stdin.</li>
> + </ul>
> +
> <br/>
>
> <h2><a name="execution">Script execution</a></h2>
> <ul>
> - <li>The "start" operation for the guest hook scripts, qemu and lxc,
> - executes <b>prior</b> to the guest being created. This allows the
> - guest start operation to be aborted if the script returns indicating
> - failure.<br/><br/></li>
> - <li>The "shutdown" operation for the guest hook scripts, qemu and lxc,
> - executes <b>after</b> the guest has stopped. If the hook script
> - indicates failure in its return, the shut down of the guest cannot
> - be aborted because it has already been performed.<br/><br/></li>
> + <li>The "start" operation for the guest and network hook scripts,
> + executes <b>prior</b> to the object (guest or network) being created.
> + This allows the object start operation to be aborted if the script
> + returns indicating failure.<br/><br/></li>
> + <li>The "shutdown" operation for the guest and network hook scripts,
> + executes <b>after</b> the object (guest or network) has stopped. If
> + the hook script indicates failure in its return, the shut down of the
> + object cannot be aborted because it has already been performed.
> + <br/><br/></li>
> <li>Hook scripts execute in a synchronous fashion. Libvirt waits
> for them to return before continuing the given operation.<br/><br/>
> - This is most noticeable with the guest start operation, as a lengthy
> - operation in the hook script can mean an extended wait for the guest
> - to be available to end users.<br/><br/></li>
> + This is most noticeable with the guest or network start operation,
> + as a lengthy operation in the hook script can mean an extended wait
> + for the guest or network to be available to end users.<br/><br/></li>
> <li>For a hook script to be utilised, it must have its execute bit set
> - (ie. chmod o+rx <i>qemu</i>), and must be present when the libvirt
> + (e.g. chmod o+rx <i>qemu</i>), and must be present when the libvirt
> daemon is started.<br/><br/></li>
> <li>If a hook script is added to a host after the libvirt daemon is
> already running, it won't be used until the libvirt daemon
> diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
> index 687046e..c48177c 100644
> --- a/src/lxc/lxc_driver.c
> +++ b/src/lxc/lxc_driver.c
> @@ -3772,7 +3772,7 @@ lxcDomainAttachDeviceNetLive(virConnectPtr conn,
> * network's pool of devices, or resolve bridge device name
> * to the one defined in the network definition.
> */
> - if (networkAllocateActualDevice(net) < 0)
> + if (networkAllocateActualDevice(vm->def, net) < 0)
> return -1;
>
> actualType = virDomainNetGetActualType(net);
> @@ -4427,7 +4427,7 @@ lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
> ret = 0;
> cleanup:
> if (!ret) {
> - networkReleaseActualDevice(detach);
> + networkReleaseActualDevice(vm->def, detach);
> virDomainNetRemove(vm->def, detachidx);
> virDomainNetDefFree(detach);
> }
> diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
> index ed729f6..8989245 100644
> --- a/src/lxc/lxc_process.c
> +++ b/src/lxc/lxc_process.c
> @@ -198,7 +198,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver,
> iface->ifname));
> ignore_value(virNetDevVethDelete(iface->ifname));
> }
> - networkReleaseActualDevice(iface);
> + networkReleaseActualDevice(vm->def, iface);
> }
>
> virDomainConfVMNWFilterTeardown(vm);
> @@ -374,7 +374,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
> * network's pool of devices, or resolve bridge device name
> * to the one defined in the network definition.
> */
> - if (networkAllocateActualDevice(def->nets[i]) < 0)
> + if (networkAllocateActualDevice(def, def->nets[i]) < 0)
> goto cleanup;
>
> if (VIR_EXPAND_N(*veths, *nveths, 1) < 0)
> @@ -476,7 +476,7 @@ cleanup:
> ignore_value(virNetDevOpenvswitchRemovePort(
> virDomainNetGetActualBridgeName(iface),
> iface->ifname));
> - networkReleaseActualDevice(iface);
> + networkReleaseActualDevice(def, iface);
> }
> }
> return ret;
> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
> index 0964350..6a2d56a 100644
> --- a/src/network/bridge_driver.c
> +++ b/src/network/bridge_driver.c
> @@ -71,6 +71,7 @@
> #include "virstring.h"
> #include "viraccessapicheck.h"
> #include "network_event.h"
> +#include "virhook.h"
>
> #define VIR_FROM_THIS VIR_FROM_NETWORK
>
> @@ -134,6 +135,51 @@ networkObjFromNetwork(virNetworkPtr net)
> return network;
> }
>
> +static int
> +networkRunHook(virNetworkObjPtr network,
> + virDomainDefPtr dom,
> + int op,
> + int sub_op)
> +{
> + virBuffer buf = VIR_BUFFER_INITIALIZER;
> + char *xml = NULL, *net_xml = NULL, *dom_xml = NULL;
> + int hookret;
> + int ret = -1;
> +
> + if (virHookPresent(VIR_HOOK_DRIVER_NETWORK)) {
> + virBufferAddLit(&buf, "<hookData>\n");
> + virBufferAdjustIndent(&buf, 2);
> + if (virNetworkDefFormatBuf(&buf, network->def, 0) < 0)
> + goto cleanup;
> + if (dom && virDomainDefFormatInternal(dom, 0, &buf) < 0)
> + goto cleanup;
> +
> + virBufferAdjustIndent(&buf, -2);
> + virBufferAddLit(&buf, "</hookData>");
> +
> + if (virBufferError(&buf) ||
> + !(xml = virBufferContentAndReset(&buf)))
> + goto cleanup;
> +
> + hookret = virHookCall(VIR_HOOK_DRIVER_NETWORK, network->def->name,
> + op, sub_op, NULL, xml, NULL);
> +
> + /*
> + * If the script raised an error, pass it to the callee.
> + */
> + if (hookret < 0)
> + goto cleanup;
> + }
> +
> + ret = 0;
> +cleanup:
> + virBufferFreeAndReset(&buf);
> + VIR_FREE(xml);
> + VIR_FREE(net_xml);
> + VIR_FREE(dom_xml);
> + return ret;
> +}
> +
> static char *
> networkDnsmasqLeaseFileNameDefault(const char *netname)
> {
> @@ -2008,6 +2054,13 @@ networkStartNetwork(virNetworkDriverStatePtr driver,
> if (virNetworkObjSetDefTransient(network, true) < 0)
> goto cleanup;
>
> + /* Run an early hook to set-up missing devices.
> + * If the script raised an error abort the launch. */
> + if (networkRunHook(network, NULL,
> + VIR_HOOK_NETWORK_OP_START,
> + VIR_HOOK_SUBOP_BEGIN) < 0)
> + goto cleanup;
> +
> switch (network->def->forward.type) {
>
> case VIR_NETWORK_FORWARD_NONE:
> @@ -2027,6 +2080,12 @@ networkStartNetwork(virNetworkDriverStatePtr driver,
> break;
> }
>
> + /* finally we can call the 'started' hook script if any */
> + if (networkRunHook(network, NULL,
> + VIR_HOOK_NETWORK_OP_STARTED,
> + VIR_HOOK_SUBOP_BEGIN) < 0)
> + goto cleanup;
> +
> /* Persist the live configuration now that anything autogenerated
> * is setup.
> */
> @@ -2087,6 +2146,10 @@ static int networkShutdownNetwork(virNetworkDriverStatePtr driver,
> break;
> }
>
> + /* now that we know it's stopped call the hook if present */
> + networkRunHook(network, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
> + VIR_HOOK_SUBOP_END);
> +
> network->active = 0;
> virNetworkObjUnsetDefTransient(network);
> return ret;
> @@ -3239,6 +3302,7 @@ finish:
> }
>
> /* networkAllocateActualDevice:
> + * @dom: domain definition that @iface belongs to
> * @iface: the original NetDef from the domain
> *
> * Looks up the network reference by iface, allocates a physical
> @@ -3250,7 +3314,8 @@ finish:
> * Returns 0 on success, -1 on failure.
> */
> int
> -networkAllocateActualDevice(virDomainNetDefPtr iface)
> +networkAllocateActualDevice(virDomainDefPtr dom,
> + virDomainNetDefPtr iface)
> {
> virNetworkDriverStatePtr driver = driverState;
> enum virDomainNetType actualType = iface->type;
> @@ -3583,6 +3648,12 @@ validate:
> }
> }
>
> + /* finally we can call the 'plugged' hook script if any */
> + if (networkRunHook(network, dom,
> + VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
> + VIR_HOOK_SUBOP_BEGIN) < 0)
> + goto error;
> +
So did we decide that, unlike the network start needing a "start" and
"started" hook, the plug needs only "plugged", and doesn't need "plug"?
(and btw, what's the deal with the sub-ops anyway - you're following the
pattern established by the domain hooks, but I looked through the domain
hook documentation and they seem to be more or less a waste of an
argument. I would have figured that the hooks during a domain start
would be "start begin" then "start done", but instead they are "start
begin" followed by "started begin". ???)
> if (dev) {
> /* we are now assured of success, so mark the allocation */
> dev->connections++;
> @@ -3618,6 +3689,7 @@ error:
> }
>
> /* networkNotifyActualDevice:
> + * @dom: domain definition that @iface belongs to
> * @iface: the domain's NetDef with an "actual" device already filled in.
> *
> * Called to notify the network driver when libvirtd is restarted and
> @@ -3628,7 +3700,8 @@ error:
> * Returns 0 on success, -1 on failure.
> */
> int
> -networkNotifyActualDevice(virDomainNetDefPtr iface)
> +networkNotifyActualDevice(virDomainDefPtr dom,
> + virDomainNetDefPtr iface)
> {
> virNetworkDriverStatePtr driver = driverState;
> enum virDomainNetType actualType = virDomainNetGetActualType(iface);
> @@ -3781,6 +3854,11 @@ networkNotifyActualDevice(virDomainNetDefPtr iface)
> }
>
> success:
> + /* finally we can call the 'plugged' hook script if any */
> + if (networkRunHook(network, dom, VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
> + VIR_HOOK_SUBOP_BEGIN) < 0)
> + goto error;
> +
> netdef->connections++;
> VIR_DEBUG("Using network %s, %d connections",
> netdef->name, netdef->connections);
> @@ -3796,6 +3874,7 @@ error:
>
>
> /* networkReleaseActualDevice:
> + * @dom: domain definition that @iface belongs to
> * @iface: a domain's NetDef (interface definition)
> *
> * Given a domain <interface> element that previously had its <actual>
> @@ -3806,7 +3885,8 @@ error:
> * Returns 0 on success, -1 on failure.
> */
> int
> -networkReleaseActualDevice(virDomainNetDefPtr iface)
> +networkReleaseActualDevice(virDomainDefPtr dom,
> + virDomainNetDefPtr iface)
> {
> virNetworkDriverStatePtr driver = driverState;
> enum virDomainNetType actualType = virDomainNetGetActualType(iface);
> @@ -3925,6 +4005,11 @@ networkReleaseActualDevice(virDomainNetDefPtr iface)
> success:
> if (iface->data.network.actual)
> netdef->connections--;
> +
> + /* finally we can call the 'unplugged' hook script if any */
> + networkRunHook(network, dom, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
> + VIR_HOOK_SUBOP_BEGIN);
> +
> VIR_DEBUG("Releasing network %s, %d connections",
> netdef->name, netdef->connections);
> ret = 0;
> diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
> index 50258b5..0f80556 100644
> --- a/src/network/bridge_driver.h
> +++ b/src/network/bridge_driver.h
> @@ -34,12 +34,15 @@
> int networkRegister(void);
>
> # if WITH_NETWORK
> -int networkAllocateActualDevice(virDomainNetDefPtr iface)
> - ATTRIBUTE_NONNULL(1);
> -int networkNotifyActualDevice(virDomainNetDefPtr iface)
> - ATTRIBUTE_NONNULL(1);
> -int networkReleaseActualDevice(virDomainNetDefPtr iface)
> - ATTRIBUTE_NONNULL(1);
> +int networkAllocateActualDevice(virDomainDefPtr dom,
> + virDomainNetDefPtr iface)
> + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
> +int networkNotifyActualDevice(virDomainDefPtr dom,
> + virDomainNetDefPtr iface)
> + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
> +int networkReleaseActualDevice(virDomainDefPtr dom,
> + virDomainNetDefPtr iface)
> + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
>
> int networkGetNetworkAddress(const char *netname, char **netaddr)
> ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
> @@ -51,9 +54,9 @@ int networkDnsmasqConfContents(virNetworkObjPtr network,
> dnsmasqCapsPtr caps);
> # else
> /* Define no-op replacements that don't drag in any link dependencies. */
> -# define networkAllocateActualDevice(iface) 0
> +# define networkAllocateActualDevice(dom, iface) 0
> # define networkNotifyActualDevice(iface) (iface=iface, 0)
> -# define networkReleaseActualDevice(iface) (iface=iface, 0)
> +# define networkReleaseActualDevice(dom, iface) (dom=dom, iface=iface, 0)
> # define networkGetNetworkAddress(netname, netaddr) (-2)
> # define networkDnsmasqConfContents(network, pidfile, configstr, \
> dctx, caps) 0
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index e499d54..bce32b8 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -548,7 +548,7 @@ qemuNetworkPrepareDevices(virDomainDefPtr def)
> * network's pool of devices, or resolve bridge device name
> * to the one defined in the network definition.
> */
> - if (networkAllocateActualDevice(net) < 0)
> + if (networkAllocateActualDevice(def, net) < 0)
> goto cleanup;
>
> actualType = virDomainNetGetActualType(net);
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 7066be6..6703c92 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -837,7 +837,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
> * network's pool of devices, or resolve bridge device name
> * to the one defined in the network definition.
> */
> - if (networkAllocateActualDevice(net) < 0)
> + if (networkAllocateActualDevice(vm->def, net) < 0)
> goto cleanup;
>
> actualType = virDomainNetGetActualType(net);
> @@ -1082,7 +1082,7 @@ cleanup:
>
> virDomainNetRemoveHostdev(vm->def, net);
>
> - networkReleaseActualDevice(net);
> + networkReleaseActualDevice(vm->def, net);
> }
>
> VIR_FREE(nicstr);
> @@ -2017,7 +2017,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
> * free it if we fail for any reason
> */
> if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
> - networkAllocateActualDevice(newdev) < 0) {
> + networkAllocateActualDevice(vm->def, newdev) < 0) {
> goto cleanup;
> }
>
> @@ -2204,7 +2204,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
>
> /* this function doesn't work with HOSTDEV networks yet, thus
> * no need to change the pointer in the hostdev structure */
> - networkReleaseActualDevice(olddev);
> + networkReleaseActualDevice(vm->def, olddev);
> virDomainNetDefFree(olddev);
> /* move newdev into the nets list, and NULL it out from the
> * virDomainDeviceDef that we were given so that the caller
> @@ -2236,7 +2236,7 @@ cleanup:
> * replace the entire device object.
> */
> if (newdev)
> - networkReleaseActualDevice(newdev);
> + networkReleaseActualDevice(vm->def, newdev);
>
> return ret;
> }
> @@ -2649,7 +2649,7 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
> virDomainHostdevDefFree(hostdev);
>
> if (net) {
> - networkReleaseActualDevice(net);
> + networkReleaseActualDevice(vm->def, net);
> virDomainNetDefFree(net);
> }
> virObjectUnref(cfg);
> @@ -2717,7 +2717,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
> virDomainNetGetActualBridgeName(net),
> net->ifname));
>
> - networkReleaseActualDevice(net);
> + networkReleaseActualDevice(vm->def, net);
> virDomainNetDefFree(net);
> virObjectUnref(cfg);
> }
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 33d2a77..ffa939a 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -2773,7 +2773,7 @@ qemuProcessNotifyNets(virDomainDefPtr def)
>
> for (i = 0; i < def->nnets; i++) {
> virDomainNetDefPtr net = def->nets[i];
> - if (networkNotifyActualDevice(net) < 0)
> + if (networkNotifyActualDevice(def, net) < 0)
> return -1;
> }
> return 0;
> @@ -4393,7 +4393,7 @@ void qemuProcessStop(virQEMUDriverPtr driver,
>
> /* kick the device out of the hostdev list too */
> virDomainNetRemoveHostdev(def, net);
> - networkReleaseActualDevice(net);
> + networkReleaseActualDevice(vm->def, net);
> }
>
> retry:
> diff --git a/src/util/virhook.c b/src/util/virhook.c
> index 159efdb..0f5d0c5 100644
> --- a/src/util/virhook.c
> +++ b/src/util/virhook.c
> @@ -48,12 +48,14 @@ VIR_ENUM_DECL(virHookDaemonOp)
> VIR_ENUM_DECL(virHookSubop)
> VIR_ENUM_DECL(virHookQemuOp)
> VIR_ENUM_DECL(virHookLxcOp)
> +VIR_ENUM_DECL(virHookNetworkOp)
>
> VIR_ENUM_IMPL(virHookDriver,
> VIR_HOOK_DRIVER_LAST,
> "daemon",
> "qemu",
> - "lxc")
> + "lxc",
> + "network")
>
> VIR_ENUM_IMPL(virHookDaemonOp, VIR_HOOK_DAEMON_OP_LAST,
> "start",
> @@ -83,6 +85,13 @@ VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST,
> "started",
> "reconnect")
>
> +VIR_ENUM_IMPL(virHookNetworkOp, VIR_HOOK_NETWORK_OP_LAST,
> + "start",
> + "started",
> + "stopped",
> + "plugged",
> + "unplugged")
> +
> static int virHooksFound = -1;
>
> /**
> @@ -246,6 +255,8 @@ virHookCall(int driver,
> case VIR_HOOK_DRIVER_LXC:
> opstr = virHookLxcOpTypeToString(op);
> break;
> + case VIR_HOOK_DRIVER_NETWORK:
> + opstr = virHookNetworkOpTypeToString(op);
> }
> if (opstr == NULL) {
> virReportError(VIR_ERR_INTERNAL_ERROR,
> diff --git a/src/util/virhook.h b/src/util/virhook.h
> index 96bf4cf..7b09ac5 100644
> --- a/src/util/virhook.h
> +++ b/src/util/virhook.h
> @@ -30,6 +30,7 @@ enum virHookDriverType {
> VIR_HOOK_DRIVER_DAEMON = 0, /* Daemon related events */
> VIR_HOOK_DRIVER_QEMU, /* QEmu domains related events */
> VIR_HOOK_DRIVER_LXC, /* LXC domains related events */
> + VIR_HOOK_DRIVER_NETWORK, /* network related events */
>
> VIR_HOOK_DRIVER_LAST,
> };
> @@ -74,6 +75,16 @@ enum virHookLxcOpType {
> VIR_HOOK_LXC_OP_LAST,
> };
>
> +enum virHookNetworkOpType {
> + VIR_HOOK_NETWORK_OP_START, /* network is about to start */
> + VIR_HOOK_NETWORK_OP_STARTED, /* network has start */
> + VIR_HOOK_NETWORK_OP_STOPPED, /* network has stopped */
> + VIR_HOOK_NETWORK_OP_IFACE_PLUGGED, /* an interface has been plugged into the network */
> + VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED, /* an interface was unplugged from the network */
> +
> + VIR_HOOK_NETWORK_OP_LAST,
> +};
> +
> int virHookInitialize(void);
>
> int virHookPresent(int driver);
It all looks fine (aside from the few small grammar corrections in the
docs. I just want one last confirmation that we don't want both "plug"
and "plugged" events, and in that case ACK.
More information about the libvir-list
mailing list