From 67a5f31fc8232cf6f2b49373d3263db22a6383d5 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 24 Aug 2009 10:10:46 -0400 Subject: [PATCH] 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... --- configure.ac | 1 + m4/libnl-check.m4 | 65 +++++++++++++++++++++++++++++++++++++++++++++++ src/nm-netlink.c | 18 +++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 m4/libnl-check.m4 diff --git a/configure.ac b/configure.ac index a1b7fbee96..4be9c49836 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/m4/libnl-check.m4 b/m4/libnl-check.m4 new file mode 100644 index 0000000000..f7d6d70715 --- /dev/null +++ b/m4/libnl-check.m4 @@ -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 +#include +#include + +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 +]) diff --git a/src/nm-netlink.c b/src/nm-netlink.c index 643b3632a1..ad68790db1 100644 --- a/src/nm-netlink.c +++ b/src/nm-netlink.c @@ -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 #include #include +#include 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; }