diff options
author | Thomas Haller <thaller@redhat.com> | 2014-01-07 17:21:12 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-01-30 17:04:36 +0100 |
commit | 7841f9ea0a4efdcb4540628cf65d7d9356b748f7 (patch) | |
tree | 3f4f8489ee5a606f01e3bf2c4f262fbf8d5aeeb6 | |
parent | 2bc61d1ad3278d4fc38d17bd6178e7e304c6339a (diff) | |
download | NetworkManager-7841f9ea0a4efdcb4540628cf65d7d9356b748f7.tar.gz |
core/platform: add check_support_kernel_extended_ifa_flags function
The kernel adds a new capability to allow user space to manage
temporary IPv6 addresses. We need to detect this capability
to act differently, depending on whether NM has an older kernel
at hand.
This capability got introduced together when extending the
ifa_flags to 32 bit. So, we can check the netlink message,
whether we have such an nl attribute at hand.
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | src/platform/nm-linux-platform.c | 57 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 11 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 3 |
3 files changed, 71 insertions, 0 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index f6510eca79..d99cb1d580 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -67,6 +67,8 @@ typedef struct { GUdevClient *udev_client; GHashTable *udev_devices; + + int support_kernel_extended_ifa_flags; } NMLinuxPlatformPrivate; #define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate)) @@ -429,6 +431,45 @@ ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *s /******************************************************************/ +static void +_check_support_kernel_extended_ifa_flags_init (NMLinuxPlatformPrivate *priv, struct nl_msg *msg) +{ + struct nlmsghdr *msg_hdr = nlmsg_hdr (msg); + + g_return_if_fail (priv->support_kernel_extended_ifa_flags == 0); + g_return_if_fail (msg_hdr->nlmsg_type == RTM_NEWADDR); + + /* the extended address flags are only set for AF_INET6 */ + if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6) + return; + + /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, + * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR + * and IFA_F_NOPREFIXROUTE (they were added together). + **/ + priv->support_kernel_extended_ifa_flags = + nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */) + ? 1 : -1; +} + +static gboolean +check_support_kernel_extended_ifa_flags (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv; + + g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); + + priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + if (priv->support_kernel_extended_ifa_flags == 0) { + g_warn_if_reached (); + priv->support_kernel_extended_ifa_flags = -1; + } + + return priv->support_kernel_extended_ifa_flags > 0; +} + + /* Object type specific utilities */ static const char * @@ -1224,6 +1265,14 @@ event_notification (struct nl_msg *msg, gpointer user_data) int nle; event = nlmsg_hdr (msg)->nlmsg_type; + + if (priv->support_kernel_extended_ifa_flags == 0 && event == RTM_NEWADDR) { + /* if kernel support for extended ifa flags is still undecided, use the opportunity + * now and use @msg to decide it. This saves a blocking net link request. + **/ + _check_support_kernel_extended_ifa_flags_init (priv, msg); + } + nl_msg_parse (msg, ref_object, &object); g_return_val_if_fail (object, NL_OK); @@ -2806,6 +2855,12 @@ setup (NMPlatform *platform) g_list_free (devices); g_object_unref (enumerator); + /* request all IPv6 addresses (hopeing that there is at least one), to check for + * the IFA_FLAGS attribute. */ + nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP); + if (nle != 0) + nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle)); + return TRUE; } @@ -2910,4 +2965,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->ip6_route_delete = ip6_route_delete; platform_class->ip4_route_exists = ip4_route_exists; platform_class->ip6_route_exists = ip6_route_exists; + + platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 25f73fdf88..79eb06523a 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -220,6 +220,17 @@ nm_platform_check_support_libnl_extended_ifa_flags () return supported; } +gboolean +nm_platform_check_support_kernel_extended_ifa_flags () +{ + g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE); + + if (!klass->check_support_kernel_extended_ifa_flags) + return FALSE; + + return klass->check_support_kernel_extended_ifa_flags (platform); +} + /******************************************************************/ /** diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index bb9cd2efe6..a219a3794c 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -323,6 +323,8 @@ typedef struct { gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); gboolean (*ip4_route_exists) (NMPlatform *, int ifindex, in_addr_t network, int plen, int metric); gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr network, int plen, int metric); + + gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *); } NMPlatformClass; /* NMPlatform signals @@ -466,6 +468,7 @@ int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4R int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b); gboolean nm_platform_check_support_libnl_extended_ifa_flags (void); +gboolean nm_platform_check_support_kernel_extended_ifa_flags (void); #define auto_g_free __attribute__((cleanup(put_g_free))) static void __attribute__((unused)) |