Work around libnl address caching bug

rtnl_addr requires that all addresses have the "peer" attribute set in
order to be compared for equality, but this attribute is not normally
set. As a result, most addresses will not compare as equal even to
themselves, busting caching. We fix this for now by poking into the
guts of libnl if it is broken...
This commit is contained in:
Dan Winship 2009-08-24 10:10:46 -04:00
parent 58fcc8efe6
commit 67a5f31fc8
3 changed files with 84 additions and 0 deletions

View file

@ -208,6 +208,7 @@ AC_SUBST(UDEV_BASE_DIR)
PKG_CHECK_MODULES(LIBNL, libnl-1 >= 1.0-pre8)
AC_SUBST(LIBNL_CFLAGS)
AC_SUBST(LIBNL_LIBS)
NM_LIBNL_CHECK
PKG_CHECK_MODULES(UUID, uuid)
AC_SUBST(UUID_CFLAGS)

65
m4/libnl-check.m4 Normal file
View file

@ -0,0 +1,65 @@
AC_DEFUN([NM_LIBNL_CHECK], [
AC_MSG_CHECKING([for libnl address caching bug])
save_CFLAGS="$CFLAGS"
save_LDFLAGS="$LDFLAGS"
CFLAGS="$CFLAGS $LIBNL_CFLAGS"
LDFLAGS="$LDFLAGS $LIBNL_LIBS"
AC_RUN_IFELSE([
#include <stdio.h>
#include <netlink/route/addr.h>
#include <netlink/object-api.h>
int
main (int argc, char **argv)
{
struct nl_handle *nlh;
struct nl_cache *cache;
struct nl_object *obj;
nlh = nl_handle_alloc ();
if (nl_connect (nlh, NETLINK_ROUTE) < 0) {
fprintf (stderr, "couldn't connect to netlink: %s", nl_geterror ());
return 3;
}
cache = rtnl_addr_alloc_cache (nlh);
if (!cache || nl_cache_nitems (cache) == 0) {
fprintf (stderr, "couldn't fill address cache: %s", nl_geterror ());
return 3;
}
obj = nl_cache_get_first (cache);
if (nl_object_identical (obj, obj))
return 0;
nl_cache_get_ops (cache)->co_obj_ops->oo_id_attrs &= ~0x80;
if (nl_object_identical (obj, obj))
return 1;
else
return 2;
}
], libnl_bug=$?, libnl_bug=$?, libnl_bug=cross)
CFLAGS="$save_CFLAGS"
LDFLAGS="$save_LDFLAGS"
case $libnl_bug in
0) AC_MSG_RESULT([no])
;;
1) AC_MSG_RESULT([yes, using workaround])
AC_DEFINE(LIBNL_NEEDS_ADDR_CACHING_WORKAROUND, 1, [Define this to hack around buggy libnl rtnl_addr caching])
;;
2) AC_MSG_RESULT([yes, and workaround doesn't work])
AC_MSG_ERROR([Installed libnl has broken address caching; please patch or upgrade])
;;
cross) AC_MSG_RESULT([cross-compiling... assuming it works!])
;;
*) AC_MSG_RESULT([?])
AC_MSG_ERROR([libnl test program failed])
;;
esac
])

View file

@ -18,6 +18,8 @@
* Copyright (C) 2007 - 2008 Red Hat, Inc.
*/
#include "config.h"
#include "nm-netlink.h"
#include "nm-utils.h"
@ -25,6 +27,7 @@
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <netlink/object-api.h>
static struct nl_cache * link_cache = NULL;
static struct nl_handle * def_nl_handle = NULL;
@ -58,6 +61,9 @@ struct nl_handle *
nm_netlink_get_default_handle (void)
{
struct nl_cb *cb;
#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
struct nl_cache *addr_cache;
#endif
if (def_nl_handle)
return def_nl_handle;
@ -74,6 +80,18 @@ nm_netlink_get_default_handle (void)
return NULL;
}
#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
/* Work around apparent libnl bug; rtnl_addr requires that all
* addresses have the "peer" attribute set in order to be compared
* for equality, but this attribute is not normally set. As a
* result, most addresses will not compare as equal even to
* themselves, busting caching.
*/
addr_cache = rtnl_addr_alloc_cache (def_nl_handle);
nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80;
nl_cache_free (addr_cache);
#endif
return def_nl_handle;
}