[libvirt] [PATCH] macvtap: Work-around failing nl_connect calls (weird problem)

Daniel P. Berrange berrange at redhat.com
Mon Feb 14 19:51:15 UTC 2011


On Mon, Feb 14, 2011 at 02:34:28PM -0500, Stefan Berger wrote:
> When trying to start / stop a domain with macvtap device (direct
> type of interface) having a device description like this one here
> 
> <interface type='direct'>
> <source dev='static' mode='vepa'/>
> </interface>
> 
> then I see netlink related errors when a 'virsh edit' session is
> happening at the same time.

Leaving 'virsh edit' active, means there is a virConnectPtr object
open in libvirtd. This in turn means there is a netcf instance
active in libvirtd. This in turn means there is a netlink socket
open by netcf in libvirtd.

> So, to reproduce this error you should try the following (on a
> kernel supporting macvtap):
> 
> virsh edit <macvtap domain>       -> do not terminate the edit sessions
> virsh start <macvtap domain>      -> works
> virsh destroy <macvtap domain>    -> leaves a macvtap device due to
> nl_connect failing
> virsh start <macvtap domain>      -> does not start anymore
> 
> That should make it fail.
> 
> The work-around basically keeps on allocating new netlink library
> handles until the nl_connect() succeeds. New netlink library handles
> cause the next available port (intern to libnl; nl_pid) to be
> allocated. For every ongoing virsh edit session, one new handle
> seems to be required. So for 2 virsh edit session, the 3rd one
> (usually) works. I do not know what in the system is causing this,
> but my guess it that 'something' is blocking the same port (nl_pid)
> -- it may not be in libvirt but in a dependent library that's not
> using libnl (?).

This problem sequence seems to imply something crazy like us only
being allowed to have one netlink socket open per $PID ??? Is that
really correct ? Looking at the kernel code they seem todo some
kind of hash based on PID & return EBUSY in that..which suggests
there may be some kind of restriction...

> 
>   Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
> 
> Index: libvirt-acl/src/util/macvtap.c
> ===================================================================
> --- libvirt-acl.orig/src/util/macvtap.c
> +++ libvirt-acl/src/util/macvtap.c
> @@ -120,13 +120,43 @@ int nlComm(struct nl_msg *nl_msg,
>      fd_set readfds;
>      int fd;
>      int n;
> -    struct nl_handle *nlhandle = nl_handle_alloc();
> +    struct nl_handle **nlhandles = NULL;
>      struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
> +    unsigned int idx = 0, num_elms = 1, i;
> 
> -    if (!nlhandle)
> -        return -1;
> +realloc:
> +    if (VIR_REALLOC_N(nlhandles, num_elms * sizeof(struct nl_handle
> *)) < 0) {
> +        virReportOOMError();
> +        rc = -1;
> +        goto err_exit;
> +    }
> +
> +    for (i = idx; i < num_elms ; i++)
> +        nlhandles[i] = NULL;
> +
> +next_handle:
> +    nlhandles[idx] = nl_handle_alloc();
> 
> -    if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
> +    if (nlhandles[idx] == NULL) {
> +        virReportOOMError();
> +        rc = -1;
> +        goto err_exit;
> +    }
> +
> +    if (nl_connect(nlhandles[idx], NETLINK_ROUTE) < 0) {
> +        VIR_DEBUG0("Could not create netlink socket - trying a new one\n");
> +         /* get a new handle and keep the ones we have */
> +        idx++;
> +        if (idx < num_elms)
> +            goto next_handle;
> +        /* need to reallocate */
> +        num_elms += 10;
> +        if (idx < 500)
> +            goto realloc;
> +
> +        macvtapError(VIR_ERR_INTERNAL_ERROR, "%s [%s]",
> +                     _("Could not create netlink socket"),
> +                     nl_geterror());
>          rc = -1;
>          goto err_exit;
>      }
> @@ -135,15 +165,16 @@ int nlComm(struct nl_msg *nl_msg,
> 
>      nlmsg->nlmsg_pid = getpid();
> 
> -    nbytes = nl_send_auto_complete(nlhandle, nl_msg);
> +    nbytes = nl_send_auto_complete(nlhandles[idx], nl_msg);
>      if (nbytes < 0) {
>          virReportSystemError(errno,
> -                             "%s", _("cannot send to netlink socket"));
> +                             "%s [%s]", _("cannot send to netlink socket"),
> +                             nl_geterror());
>          rc = -1;
>          goto err_exit;
>      }
> 
> -    fd = nl_socket_get_fd(nlhandle);
> +    fd = nl_socket_get_fd(nlhandles[idx]);
> 
>      FD_ZERO(&readfds);
>      FD_SET(fd, &readfds);
> @@ -160,7 +191,7 @@ int nlComm(struct nl_msg *nl_msg,
>          goto err_exit;
>      }
> 
> -    *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
> +    *respbuflen = nl_recv(nlhandles[idx], &nladdr, respbuf, NULL);
>      if (*respbuflen <= 0)
>          rc = -1;
> 
> @@ -171,7 +202,12 @@ err_exit:
>          *respbuflen = 0;
>      }
> 
> -    nl_handle_destroy(nlhandle);
> +    if (nlhandles)
> +        for (idx = 0; idx < num_elms; idx++)
> +            nl_handle_destroy(nlhandles[idx]);
> +
> +    VIR_FREE(nlhandles);
> +
>      return rc;
>  }

This approach feels like a nasty hack to me and potentially still leaves
us with a problem in netcf which is also using netlink sockets. I think
we need to get a clearer picture of what the root cause is before going
for this kind of patch

Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list