[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