network: Introduce network hooks

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@redhat.com>
This commit is contained in:
Michal Privoznik 2014-01-31 16:48:06 +01:00
parent e0a31274ec
commit f1ab06e43d
10 changed files with 218 additions and 42 deletions

View File

@ -13,9 +13,15 @@
actions occur:</p> actions occur:</p>
<ul> <ul>
<li>The libvirt daemon starts, stops, or reloads its <li>The libvirt daemon starts, stops, or reloads its
configuration<br/><br/></li> configuration
<li>A QEMU guest is started or stopped<br/><br/></li> (<span class="since">since 0.8.0</span>)<br/><br/></li>
<li>An LXC guest is started or stopped<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
plugged/unplugged to/from the network
(<span class="since">since 1.2.2</span>)<br/><br/></li>
</ul> </ul>
<h2><a name="location">Script location</a></h2> <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> Executed when a QEMU guest is started, stopped, or migrated<br/><br/></li>
<li><code>/etc/libvirt/hooks/lxc</code><br /><br/> <li><code>/etc/libvirt/hooks/lxc</code><br /><br/>
Executed when an LXC guest is started or stopped</li> 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 plugged/unplugged to/from the network</li>
</ul> </ul>
<br/> <br/>
@ -66,6 +75,39 @@
XML description for the domain on their stdin. This includes items XML description for the domain on their stdin. This includes items
such the UUID of the domain and its storage information, and is such the UUID of the domain and its storage information, and is
intended to provide all the libvirt information the script needs.</p> 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>&lt;hookData&gt;
&lt;network&gt;
&lt;name&gt;$network_name&lt;/name&gt;
&lt;uuid&gt;afca425a-2c3a-420c-b2fb-dd7b4950d722&lt;/uuid&gt;
...
&lt;/network&gt;
&lt;/hookData&gt;</pre>
<p>In the case of an interface
being plugged/unplugged to/from 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>&lt;hookData&gt;
&lt;network&gt;
&lt;name&gt;$network_name&lt;/name&gt;
&lt;uuid&gt;afca425a-2c3a-420c-b2fb-dd7b4950d722&lt;/uuid&gt;
...
&lt;/network&gt;
&lt;domain type='$domain_type' id='$domain_id'&gt;
&lt;name&gt;$domain_name&lt;/name&gt;
&lt;uuid&gt;afca425a-2c3a-420c-b2fb-dd7b4950d722&lt;/uuid&gt;
...
&lt;/domain&gt;
&lt;/hookData&gt;</pre>
<p>Please note that this approach is different from other cases such as
<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> <p>The command line arguments take this approach:</p>
<ol> <ol>
@ -181,25 +223,49 @@
<pre>/etc/libvirt/hooks/lxc guest_name reconnect begin -</pre> <pre>/etc/libvirt/hooks/lxc guest_name reconnect begin -</pre>
</li> </li>
</ul> </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 &and; 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, the hook script is called as:<br/>
<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/> <br/>
<h2><a name="execution">Script execution</a></h2> <h2><a name="execution">Script execution</a></h2>
<ul> <ul>
<li>The "start" operation for the guest hook scripts, qemu and lxc, <li>The "start" operation for the guest and network hook scripts,
executes <b>prior</b> to the guest being created. This allows the executes <b>prior</b> to the object (guest or network) being created.
guest start operation to be aborted if the script returns indicating This allows the object start operation to be aborted if the script
failure.<br/><br/></li> returns indicating failure.<br/><br/></li>
<li>The "shutdown" operation for the guest hook scripts, qemu and lxc, <li>The "shutdown" operation for the guest and network hook scripts,
executes <b>after</b> the guest has stopped. If the hook script executes <b>after</b> the object (guest or network) has stopped. If
indicates failure in its return, the shut down of the guest cannot the hook script indicates failure in its return, the shut down of the
be aborted because it has already been performed.<br/><br/></li> object cannot be aborted because it has already been performed.
<br/><br/></li>
<li>Hook scripts execute in a synchronous fashion. Libvirt waits <li>Hook scripts execute in a synchronous fashion. Libvirt waits
for them to return before continuing the given operation.<br/><br/> for them to return before continuing the given operation.<br/><br/>
This is most noticeable with the guest start operation, as a lengthy This is most noticeable with the guest or network start operation,
operation in the hook script can mean an extended wait for the guest as a lengthy operation in the hook script can mean an extended wait
to be available to end users.<br/><br/></li> 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 <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> daemon is started.<br/><br/></li>
<li>If a hook script is added to a host after the libvirt daemon is <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 already running, it won't be used until the libvirt daemon

View File

@ -3937,7 +3937,7 @@ lxcDomainAttachDeviceNetLive(virConnectPtr conn,
* network's pool of devices, or resolve bridge device name * network's pool of devices, or resolve bridge device name
* to the one defined in the network definition. * to the one defined in the network definition.
*/ */
if (networkAllocateActualDevice(net) < 0) if (networkAllocateActualDevice(vm->def, net) < 0)
return -1; return -1;
actualType = virDomainNetGetActualType(net); actualType = virDomainNetGetActualType(net);
@ -4485,7 +4485,7 @@ lxcDomainDetachDeviceNetLive(virDomainObjPtr vm,
ret = 0; ret = 0;
cleanup: cleanup:
if (!ret) { if (!ret) {
networkReleaseActualDevice(detach); networkReleaseActualDevice(vm->def, detach);
virDomainNetRemove(vm->def, detachidx); virDomainNetRemove(vm->def, detachidx);
virDomainNetDefFree(detach); virDomainNetDefFree(detach);
} }

View File

@ -198,7 +198,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver,
iface->ifname)); iface->ifname));
ignore_value(virNetDevVethDelete(iface->ifname)); ignore_value(virNetDevVethDelete(iface->ifname));
} }
networkReleaseActualDevice(iface); networkReleaseActualDevice(vm->def, iface);
} }
virDomainConfVMNWFilterTeardown(vm); virDomainConfVMNWFilterTeardown(vm);
@ -374,7 +374,7 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn,
* network's pool of devices, or resolve bridge device name * network's pool of devices, or resolve bridge device name
* to the one defined in the network definition. * to the one defined in the network definition.
*/ */
if (networkAllocateActualDevice(def->nets[i]) < 0) if (networkAllocateActualDevice(def, def->nets[i]) < 0)
goto cleanup; goto cleanup;
if (VIR_EXPAND_N(*veths, *nveths, 1) < 0) if (VIR_EXPAND_N(*veths, *nveths, 1) < 0)
@ -476,7 +476,7 @@ cleanup:
ignore_value(virNetDevOpenvswitchRemovePort( ignore_value(virNetDevOpenvswitchRemovePort(
virDomainNetGetActualBridgeName(iface), virDomainNetGetActualBridgeName(iface),
iface->ifname)); iface->ifname));
networkReleaseActualDevice(iface); networkReleaseActualDevice(def, iface);
} }
} }
return ret; return ret;

View File

@ -71,6 +71,7 @@
#include "virstring.h" #include "virstring.h"
#include "viraccessapicheck.h" #include "viraccessapicheck.h"
#include "network_event.h" #include "network_event.h"
#include "virhook.h"
#define VIR_FROM_THIS VIR_FROM_NETWORK #define VIR_FROM_THIS VIR_FROM_NETWORK
@ -134,6 +135,51 @@ networkObjFromNetwork(virNetworkPtr net)
return network; 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 * static char *
networkDnsmasqLeaseFileNameDefault(const char *netname) networkDnsmasqLeaseFileNameDefault(const char *netname)
{ {
@ -2008,6 +2054,13 @@ networkStartNetwork(virNetworkDriverStatePtr driver,
if (virNetworkObjSetDefTransient(network, true) < 0) if (virNetworkObjSetDefTransient(network, true) < 0)
goto cleanup; 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) { switch (network->def->forward.type) {
case VIR_NETWORK_FORWARD_NONE: case VIR_NETWORK_FORWARD_NONE:
@ -2027,6 +2080,12 @@ networkStartNetwork(virNetworkDriverStatePtr driver,
break; 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 /* Persist the live configuration now that anything autogenerated
* is setup. * is setup.
*/ */
@ -2087,6 +2146,10 @@ static int networkShutdownNetwork(virNetworkDriverStatePtr driver,
break; 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; network->active = 0;
virNetworkObjUnsetDefTransient(network); virNetworkObjUnsetDefTransient(network);
return ret; return ret;
@ -3239,6 +3302,7 @@ finish:
} }
/* networkAllocateActualDevice: /* networkAllocateActualDevice:
* @dom: domain definition that @iface belongs to
* @iface: the original NetDef from the domain * @iface: the original NetDef from the domain
* *
* Looks up the network reference by iface, allocates a physical * Looks up the network reference by iface, allocates a physical
@ -3250,7 +3314,8 @@ finish:
* Returns 0 on success, -1 on failure. * Returns 0 on success, -1 on failure.
*/ */
int int
networkAllocateActualDevice(virDomainNetDefPtr iface) networkAllocateActualDevice(virDomainDefPtr dom,
virDomainNetDefPtr iface)
{ {
virNetworkDriverStatePtr driver = driverState; virNetworkDriverStatePtr driver = driverState;
enum virDomainNetType actualType = iface->type; 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;
if (dev) { if (dev) {
/* we are now assured of success, so mark the allocation */ /* we are now assured of success, so mark the allocation */
dev->connections++; dev->connections++;
@ -3618,6 +3689,7 @@ error:
} }
/* networkNotifyActualDevice: /* networkNotifyActualDevice:
* @dom: domain definition that @iface belongs to
* @iface: the domain's NetDef with an "actual" device already filled in. * @iface: the domain's NetDef with an "actual" device already filled in.
* *
* Called to notify the network driver when libvirtd is restarted and * Called to notify the network driver when libvirtd is restarted and
@ -3628,7 +3700,8 @@ error:
* Returns 0 on success, -1 on failure. * Returns 0 on success, -1 on failure.
*/ */
int int
networkNotifyActualDevice(virDomainNetDefPtr iface) networkNotifyActualDevice(virDomainDefPtr dom,
virDomainNetDefPtr iface)
{ {
virNetworkDriverStatePtr driver = driverState; virNetworkDriverStatePtr driver = driverState;
enum virDomainNetType actualType = virDomainNetGetActualType(iface); enum virDomainNetType actualType = virDomainNetGetActualType(iface);
@ -3781,6 +3854,11 @@ networkNotifyActualDevice(virDomainNetDefPtr iface)
} }
success: 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++; netdef->connections++;
VIR_DEBUG("Using network %s, %d connections", VIR_DEBUG("Using network %s, %d connections",
netdef->name, netdef->connections); netdef->name, netdef->connections);
@ -3796,6 +3874,7 @@ error:
/* networkReleaseActualDevice: /* networkReleaseActualDevice:
* @dom: domain definition that @iface belongs to
* @iface: a domain's NetDef (interface definition) * @iface: a domain's NetDef (interface definition)
* *
* Given a domain <interface> element that previously had its <actual> * Given a domain <interface> element that previously had its <actual>
@ -3806,7 +3885,8 @@ error:
* Returns 0 on success, -1 on failure. * Returns 0 on success, -1 on failure.
*/ */
int int
networkReleaseActualDevice(virDomainNetDefPtr iface) networkReleaseActualDevice(virDomainDefPtr dom,
virDomainNetDefPtr iface)
{ {
virNetworkDriverStatePtr driver = driverState; virNetworkDriverStatePtr driver = driverState;
enum virDomainNetType actualType = virDomainNetGetActualType(iface); enum virDomainNetType actualType = virDomainNetGetActualType(iface);
@ -3925,6 +4005,11 @@ networkReleaseActualDevice(virDomainNetDefPtr iface)
success: success:
if (iface->data.network.actual) if (iface->data.network.actual)
netdef->connections--; 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", VIR_DEBUG("Releasing network %s, %d connections",
netdef->name, netdef->connections); netdef->name, netdef->connections);
ret = 0; ret = 0;

View File

@ -34,12 +34,15 @@
int networkRegister(void); int networkRegister(void);
# if WITH_NETWORK # if WITH_NETWORK
int networkAllocateActualDevice(virDomainNetDefPtr iface) int networkAllocateActualDevice(virDomainDefPtr dom,
ATTRIBUTE_NONNULL(1); virDomainNetDefPtr iface)
int networkNotifyActualDevice(virDomainNetDefPtr iface) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
ATTRIBUTE_NONNULL(1); int networkNotifyActualDevice(virDomainDefPtr dom,
int networkReleaseActualDevice(virDomainNetDefPtr iface) virDomainNetDefPtr iface)
ATTRIBUTE_NONNULL(1); 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) int networkGetNetworkAddress(const char *netname, char **netaddr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
@ -51,9 +54,9 @@ int networkDnsmasqConfContents(virNetworkObjPtr network,
dnsmasqCapsPtr caps); dnsmasqCapsPtr caps);
# else # else
/* Define no-op replacements that don't drag in any link dependencies. */ /* 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 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 networkGetNetworkAddress(netname, netaddr) (-2)
# define networkDnsmasqConfContents(network, pidfile, configstr, \ # define networkDnsmasqConfContents(network, pidfile, configstr, \
dctx, caps) 0 dctx, caps) 0

View File

@ -548,7 +548,7 @@ qemuNetworkPrepareDevices(virDomainDefPtr def)
* network's pool of devices, or resolve bridge device name * network's pool of devices, or resolve bridge device name
* to the one defined in the network definition. * to the one defined in the network definition.
*/ */
if (networkAllocateActualDevice(net) < 0) if (networkAllocateActualDevice(def, net) < 0)
goto cleanup; goto cleanup;
actualType = virDomainNetGetActualType(net); actualType = virDomainNetGetActualType(net);

View File

@ -837,7 +837,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
* network's pool of devices, or resolve bridge device name * network's pool of devices, or resolve bridge device name
* to the one defined in the network definition. * to the one defined in the network definition.
*/ */
if (networkAllocateActualDevice(net) < 0) if (networkAllocateActualDevice(vm->def, net) < 0)
goto cleanup; goto cleanup;
actualType = virDomainNetGetActualType(net); actualType = virDomainNetGetActualType(net);
@ -1082,7 +1082,7 @@ cleanup:
virDomainNetRemoveHostdev(vm->def, net); virDomainNetRemoveHostdev(vm->def, net);
networkReleaseActualDevice(net); networkReleaseActualDevice(vm->def, net);
} }
VIR_FREE(nicstr); VIR_FREE(nicstr);
@ -2017,7 +2017,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
* free it if we fail for any reason * free it if we fail for any reason
*/ */
if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK && if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
networkAllocateActualDevice(newdev) < 0) { networkAllocateActualDevice(vm->def, newdev) < 0) {
goto cleanup; goto cleanup;
} }
@ -2204,7 +2204,7 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
/* this function doesn't work with HOSTDEV networks yet, thus /* this function doesn't work with HOSTDEV networks yet, thus
* no need to change the pointer in the hostdev structure */ * no need to change the pointer in the hostdev structure */
networkReleaseActualDevice(olddev); networkReleaseActualDevice(vm->def, olddev);
virDomainNetDefFree(olddev); virDomainNetDefFree(olddev);
/* move newdev into the nets list, and NULL it out from the /* move newdev into the nets list, and NULL it out from the
* virDomainDeviceDef that we were given so that the caller * virDomainDeviceDef that we were given so that the caller
@ -2236,7 +2236,7 @@ cleanup:
* replace the entire device object. * replace the entire device object.
*/ */
if (newdev) if (newdev)
networkReleaseActualDevice(newdev); networkReleaseActualDevice(vm->def, newdev);
return ret; return ret;
} }
@ -2649,7 +2649,7 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
virDomainHostdevDefFree(hostdev); virDomainHostdevDefFree(hostdev);
if (net) { if (net) {
networkReleaseActualDevice(net); networkReleaseActualDevice(vm->def, net);
virDomainNetDefFree(net); virDomainNetDefFree(net);
} }
virObjectUnref(cfg); virObjectUnref(cfg);
@ -2717,7 +2717,7 @@ qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
virDomainNetGetActualBridgeName(net), virDomainNetGetActualBridgeName(net),
net->ifname)); net->ifname));
networkReleaseActualDevice(net); networkReleaseActualDevice(vm->def, net);
virDomainNetDefFree(net); virDomainNetDefFree(net);
virObjectUnref(cfg); virObjectUnref(cfg);
} }

View File

@ -2773,7 +2773,7 @@ qemuProcessNotifyNets(virDomainDefPtr def)
for (i = 0; i < def->nnets; i++) { for (i = 0; i < def->nnets; i++) {
virDomainNetDefPtr net = def->nets[i]; virDomainNetDefPtr net = def->nets[i];
if (networkNotifyActualDevice(net) < 0) if (networkNotifyActualDevice(def, net) < 0)
return -1; return -1;
} }
return 0; return 0;
@ -4393,7 +4393,7 @@ void qemuProcessStop(virQEMUDriverPtr driver,
/* kick the device out of the hostdev list too */ /* kick the device out of the hostdev list too */
virDomainNetRemoveHostdev(def, net); virDomainNetRemoveHostdev(def, net);
networkReleaseActualDevice(net); networkReleaseActualDevice(vm->def, net);
} }
retry: retry:

View File

@ -48,12 +48,14 @@ VIR_ENUM_DECL(virHookDaemonOp)
VIR_ENUM_DECL(virHookSubop) VIR_ENUM_DECL(virHookSubop)
VIR_ENUM_DECL(virHookQemuOp) VIR_ENUM_DECL(virHookQemuOp)
VIR_ENUM_DECL(virHookLxcOp) VIR_ENUM_DECL(virHookLxcOp)
VIR_ENUM_DECL(virHookNetworkOp)
VIR_ENUM_IMPL(virHookDriver, VIR_ENUM_IMPL(virHookDriver,
VIR_HOOK_DRIVER_LAST, VIR_HOOK_DRIVER_LAST,
"daemon", "daemon",
"qemu", "qemu",
"lxc") "lxc",
"network")
VIR_ENUM_IMPL(virHookDaemonOp, VIR_HOOK_DAEMON_OP_LAST, VIR_ENUM_IMPL(virHookDaemonOp, VIR_HOOK_DAEMON_OP_LAST,
"start", "start",
@ -83,6 +85,13 @@ VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST,
"started", "started",
"reconnect") "reconnect")
VIR_ENUM_IMPL(virHookNetworkOp, VIR_HOOK_NETWORK_OP_LAST,
"start",
"started",
"stopped",
"plugged",
"unplugged")
static int virHooksFound = -1; static int virHooksFound = -1;
/** /**
@ -246,6 +255,8 @@ virHookCall(int driver,
case VIR_HOOK_DRIVER_LXC: case VIR_HOOK_DRIVER_LXC:
opstr = virHookLxcOpTypeToString(op); opstr = virHookLxcOpTypeToString(op);
break; break;
case VIR_HOOK_DRIVER_NETWORK:
opstr = virHookNetworkOpTypeToString(op);
} }
if (opstr == NULL) { if (opstr == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,

View File

@ -30,6 +30,7 @@ enum virHookDriverType {
VIR_HOOK_DRIVER_DAEMON = 0, /* Daemon related events */ VIR_HOOK_DRIVER_DAEMON = 0, /* Daemon related events */
VIR_HOOK_DRIVER_QEMU, /* QEmu domains related events */ VIR_HOOK_DRIVER_QEMU, /* QEmu domains related events */
VIR_HOOK_DRIVER_LXC, /* LXC domains related events */ VIR_HOOK_DRIVER_LXC, /* LXC domains related events */
VIR_HOOK_DRIVER_NETWORK, /* network related events */
VIR_HOOK_DRIVER_LAST, VIR_HOOK_DRIVER_LAST,
}; };
@ -74,6 +75,16 @@ enum virHookLxcOpType {
VIR_HOOK_LXC_OP_LAST, 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 virHookInitialize(void);
int virHookPresent(int driver); int virHookPresent(int driver);