[libvirt] [PATCH 1/2] Add netlink message event service

Daniel P. Berrange berrange at redhat.com
Thu Jan 26 16:57:29 UTC 2012


On Fri, Jan 20, 2012 at 03:56:26PM +0100, D. Herrendoerfer wrote:
> From: "D. Herrendoerfer" <d.herrendoerfer at herrendoerfer.name>
> 
> This code adds an event service for netlink messages addressed
> to libvirt and passes the message to registered callback handlers.
> Itself, it makes use of the polling file event service and follows
> a similar design.
> 
> Signed-off-by: D. Herrendoerfer <d.herrendoerfer at herrendoerfer.name>
> ---
>  daemon/Makefile.am       |    3 +-
>  daemon/libvirtd.c        |    7 +
>  src/Makefile.am          |    1 +
>  src/libvirt_private.syms |    7 +
>  src/util/netlink-event.c |  363 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/util/netlink-event.h |   63 ++++++++

Our current practice is to use a 'vir' prefix on the files,
so I'd just use  'virnetlink.[ch]' for this code.

> diff --git a/daemon/Makefile.am b/daemon/Makefile.am
> index 73a6e1f..d027ff6 100644
> --- a/daemon/Makefile.am
> +++ b/daemon/Makefile.am
> @@ -114,7 +114,8 @@ libvirtd_LDADD += ../src/probes.o
>  endif
>  
>  libvirtd_LDADD += \
> -	../src/libvirt-qemu.la
> +	../src/libvirt-qemu.la				\
> +	../src/libvirt_util.la

Don't do this. This is a sign that you need to add some
APIs in src/libvirt_private.syms instead.


>  
>  if ! WITH_DRIVER_MODULES
>  if WITH_QEMU
> diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
> index d7a03d7..b118fd0 100644
> --- a/daemon/libvirtd.c
> +++ b/daemon/libvirtd.c
> @@ -1577,6 +1579,11 @@ int main(int argc, char **argv) {
>          goto cleanup;
>      }
>  
> +    /* Register the netlink event service */
> +    if (netlinkEventServiceStart() < 0) {
> +    	VIR_WARN("Netlink service did not start. Netlink events are not available.");
> +    }

Looking at the code I think it is reasonable to treat this
failure as a hard fail. On linux this should always succeed.
On non-Linux we should be compiling to a no-op variant.

>      /* Run event loop. */
>      virNetServerRun(srv);

Probably need to call the Stop method too somewhere....

> diff --git a/src/util/netlink-event.c b/src/util/netlink-event.c
> new file mode 100644
> index 0000000..7c6746d
> --- /dev/null
> +++ b/src/util/netlink-event.c
> @@ -0,0 +1,363 @@
> +/*
> + * lldpad-event.c: event loop for monitoring netlink messages
> + *
> + * Copyright (C) 2011,2012 IBM Corporation.
> + * Copyright (C) 2011,2012 Dirk Herrendoerfer

 s/2011,2012/2011-2012/

> +#define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__)

Don't do this - just use VIR_DEBUG directly.

> +/* State for a single netlink event handle */
> +struct netlinkEventHandle {
> +	int watch;
> +    netlinkEventHandleCallback cb;
> +    void *opaque;
> +    unsigned char macaddr[6];
> +    int deleted;
> +};
> +
> +/* State for the main netlink event loop */
> +struct netlinkEventLoop {
> +	virMutex lock;
> +    int handeled;
> +    size_t handlesCount;
> +    size_t handlesAlloc;
> +    struct netlinkEventHandle *handles;
> +};
> +
> +/* Only have one event loop */
> +static struct netlinkEventLoop eventLoop;
> +
> +/* Unique ID for the next netlink watch to be registered */
> +static int nextWatch = 1;
> +
> +/* Allocate extra slots for virEventPollHandle/virEventPollTimeout
> +   records in this multiple */
> +#define NETLINK_EVENT_ALLOC_EXTENT 10
> +
> +static netlinkEventSrvPrivatePtr server = 0;

I'm not really seeing the point in having two global structs,
both with their own lock.  I'd say we should just have one
struct with all neccessary state in it.

> +    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
> +        if (eventLoop.handles[i].deleted) {
> +            continue;
> +        }
> +
> +        VIR_INFO("dispatching client %d.",i);
> +
> +        netlinkEventHandleCallback cb = eventLoop.handles[i].cb;
> +        void *cpopaque = eventLoop.handles[i].opaque;
> +        (cb)( msg, length, &peer, &handeled, cpopaque);
> +    }
> +
> +    virMutexUnlock(&eventLoop.lock);
> +
> +    if (handeled == 0) {
> +    	VIR_INFO("nobody cared.");
> +    }
> +
> +    free(msg);


s/free/VIR_FREE/

> +int
> +netlinkEventServiceStop(void) {
> +	netlinkEventSrvPrivatePtr srv = server;
> +
> +	VIR_INFO("stopping netlink event service");
> +
> +	if (server) {
> +		errno = EINVAL;
> +		return -1;
> +	}

IMHO just return 0 here and skip errno.

> +
> +	netlinkEventServerLock(srv);
> +
> +	nl_close(srv->netlinknh);
> +	nl_handle_destroy(srv->netlinknh);
> +
> +	virEventRemoveHandle(srv->eventwatch);
> +	server=0;
> +
> +    netlinkEventServerUnlock(srv);
> +    return 0;
> +}
> +int
> +netlinkEventAddClient(netlinkEventHandleCallback cb,
> +					  void *opaque,
> +					  const unsigned char *macaddr) {
> +	int i;
> +
> +    virMutexLock(&eventLoop.lock);
> +
> +    VIR_INFO("adding client: %d.",nextWatch);
> +
> +    /* first try to re-use deleted free slots */
> +    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
> +        if (eventLoop.handles[i].deleted == 2) {
> +            eventLoop.handles[i].watch = nextWatch;
> +            eventLoop.handles[i].cb = cb;
> +            eventLoop.handles[i].opaque = opaque;
> +            eventLoop.handles[i].deleted = 0;
> +            if (!macaddr)
> +            	memcpy(eventLoop.handles[i].macaddr, macaddr,6);

s/6/VIR_MAC_BUFLEN/

> +    	memcpy(eventLoop.handles[i].macaddr, macaddr,6);

And again.

> +
> +    VIR_INFO("added client to loop slot: %d.",(int)eventLoop.handlesCount);
> +
> +    eventLoop.handlesCount++;
> +
> +cleanup:
> +    virMutexUnlock(&eventLoop.lock);
> +
> +    return nextWatch++;
> +}
> +

> +int
> +netlinkEventRemoveClient(int watch, const unsigned char *macaddr) {

> +        if (watch == 0 && memcmp(macaddr, eventLoop.handles[i].macaddr, 6)) {

And here, etc

> diff --git a/src/util/netlink-event.h b/src/util/netlink-event.h
> new file mode 100644
> index 0000000..da97395
> --- /dev/null
> +++ b/src/util/netlink-event.h
> @@ -0,0 +1,63 @@
> +/*
> + * lldpad-event.h: event loop for monitoring netlink messages

Wrong filename 

> + *
> + * Copyright (C) 2011,2012 IBM Corporation.
> + * Copyright (C) 2011,2012 Dirk Herrendoerfer
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
> + *
> + * Author: Dirk Herrendoerfer <herrend[at]de[dot]ibm[dot]com>
> + */
> +
> +#ifndef NETLINK_EVENT_CONF_H
> +# define NETLINK_EVENT_CONF_H
> +
> +#include <netlink/netlink.h>
> +
> +#include "internal.h"
> +#include "threads.h"
> +
> +typedef struct _netlinkEventSrvPrivate netlinkEventSrvPrivate;
> +typedef netlinkEventSrvPrivate *netlinkEventSrvPrivatePtr;
> +struct _netlinkEventSrvPrivate {
> +    virMutex lock;
> +    int eventwatch;
> +    int netlinkfd;
> +    struct nl_handle *netlinknh;
> +};

This shouldn't be made public, and can be merged into the other
global state struct.

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