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@xxxxxxxxxx> > --- > 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. -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list