summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-01-07 17:21:12 +0100
committerThomas Haller <thaller@redhat.com>2014-01-30 17:04:36 +0100
commit7841f9ea0a4efdcb4540628cf65d7d9356b748f7 (patch)
tree3f4f8489ee5a606f01e3bf2c4f262fbf8d5aeeb6
parent2bc61d1ad3278d4fc38d17bd6178e7e304c6339a (diff)
downloadNetworkManager-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.c57
-rw-r--r--src/platform/nm-platform.c11
-rw-r--r--src/platform/nm-platform.h3
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))