summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2015-01-26 13:05:35 +0100
committerLubomir Rintel <lkundrak@v3.sk>2015-01-26 13:05:35 +0100
commit5f50c0480abb4db908ad2f5d05c1e53ae518f9f8 (patch)
tree62df07c353c7f1cd377a9673d7140fc2175a8539
parent2d08e701a02e857f7301736f6f528cb149db32c2 (diff)
parentc2f9940470fc891e2c743e6e33e43b43687414d2 (diff)
downloadNetworkManager-5f50c0480abb4db908ad2f5d05c1e53ae518f9f8.tar.gz
platform: merge: branch 'lr/ipv6-tokens' (rh #1104689)
This adds support for tokenised identifier use as specified in draft-chown-6man-tokenised-ipv6-identifiers-02 Internet Draft, enabled if there's a support for tokenised identifiers in libnl. https://bugzilla.redhat.com/show_bug.cgi?id=1104689 https://tools.ietf.org/html/draft-chown-6man-tokenised-ipv6-identifiers-02
-rw-r--r--configure.ac7
-rw-r--r--src/NetworkManagerUtils.h4
-rw-r--r--src/devices/nm-device.c14
-rw-r--r--src/nm-types.h3
-rw-r--r--src/platform/nm-linux-platform.c69
-rw-r--r--src/platform/nm-platform.c25
-rw-r--r--src/platform/nm-platform.h4
-rw-r--r--src/rdisc/nm-rdisc.c32
-rw-r--r--src/rdisc/nm-rdisc.h2
9 files changed, 150 insertions, 10 deletions
diff --git a/configure.ac b/configure.ac
index a744755203..9fbfe00635 100644
--- a/configure.ac
+++ b/configure.ac
@@ -438,6 +438,13 @@ else
AC_DEFINE(HAVE_KERNEL_INET6_ADDR_GEN_MODE, 0, [Define if the kernel has IN6_ADDR_GEN_MODE_*])
fi
+# IPv6 tokenized identifiers support in libnl
+AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_token],
+ ac_have_ipv6_token="1",
+ ac_have_ipv6_token="0")
+AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_TOKEN,
+ $ac_have_ipv6_token, [Define if libnl has rtnl_link_inet6_get_token()])
+
# uuid library
PKG_CHECK_MODULES(UUID, uuid)
AC_SUBST(UUID_CFLAGS)
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 191c19ce9d..0498565562 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -186,12 +186,12 @@ gboolean nm_utils_is_specific_hostname (const char *name);
* and should not normally be treated as a %guint64, but this is done for
* convenience of validity checking and initialization.
*/
-typedef struct {
+struct _NMUtilsIPv6IfaceId {
union {
guint64 id;
guint8 id_u8[8];
};
-} NMUtilsIPv6IfaceId;
+};
#define NM_UTILS_IPV6_IFACE_ID_INIT { .id = 0 }
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index caed116f51..9f5ca4b2bb 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -1208,6 +1208,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
{
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMUtilsIPv6IfaceId token_iid;
gboolean ip_ifname_changed = FALSE;
if (info->udi && g_strcmp0 (info->udi, priv->udi)) {
@@ -1254,6 +1255,12 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
nm_device_enslave_slave (priv->master, self, NULL);
}
+ if (priv->rdisc && nm_platform_link_get_ipv6_token (priv->ifindex, &token_iid)) {
+ _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
+ if (nm_rdisc_set_iid (priv->rdisc, token_iid))
+ nm_rdisc_start (priv->rdisc);
+ }
+
if (klass->link_changed)
klass->link_changed (self, info);
@@ -4244,11 +4251,12 @@ addrconf6_start_with_link_ready (NMDevice *self)
g_assert (priv->rdisc);
- if (!nm_device_get_ip_iface_identifier (self, &iid)) {
+ if (nm_platform_link_get_ipv6_token (priv->ifindex, &iid)) {
+ _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
+ } else if (!nm_device_get_ip_iface_identifier (self, &iid)) {
_LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 cannot continue");
return FALSE;
}
- nm_rdisc_set_iid (priv->rdisc, iid);
/* Apply any manual configuration before starting RA */
if (!ip6_config_merge_and_apply (self, TRUE, NULL))
@@ -4267,6 +4275,8 @@ addrconf6_start_with_link_ready (NMDevice *self)
NM_RDISC_RA_TIMEOUT,
G_CALLBACK (rdisc_ra_timeout),
self);
+
+ nm_rdisc_set_iid (priv->rdisc, iid);
nm_rdisc_start (priv->rdisc);
return TRUE;
}
diff --git a/src/nm-types.h b/src/nm-types.h
index 4a93567e11..73a11e7567 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -111,4 +111,7 @@ typedef struct _NMSecretAgent NMSecretAgent;
typedef struct _NMSettings NMSettings;
typedef struct _NMSettingsConnection NMSettingsConnection;
+/* utils */
+typedef struct _NMUtilsIPv6IfaceId NMUtilsIPv6IfaceId;
+
#endif /* NM_TYPES_H */
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index a03abbebb3..091791f4b8 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -44,9 +44,9 @@
#include <netlink/route/route.h>
#include <gudev/gudev.h>
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE || HAVE_LIBNL_INET6_TOKEN
#include <netlink/route/link/inet6.h>
-#if HAVE_KERNEL_INET6_ADDR_GEN_MODE
+#if HAVE_LIBNL_INET6_ADDR_GEN_MODE && HAVE_KERNEL_INET6_ADDR_GEN_MODE
#include <linux/if_link.h>
#else
#define IN6_ADDR_GEN_MODE_EUI64 0
@@ -1900,6 +1900,37 @@ nm_nl_object_diff (ObjectType type, struct nl_object *_a, struct nl_object *_b)
return TRUE;
}
+#if HAVE_LIBNL_INET6_TOKEN
+ /* libnl ignores PROTINFO changes in object without AF assigned */
+ if (type == OBJECT_TYPE_LINK) {
+ struct rtnl_addr *a = (struct rtnl_addr *) _a;
+ struct rtnl_addr *b = (struct rtnl_addr *) _b;
+ auto_nl_addr struct nl_addr *token_a = NULL;
+ auto_nl_addr struct nl_addr *token_b = NULL;
+
+ if (rtnl_link_inet6_get_token ((struct rtnl_link *) a, &token_a) != 0)
+ token_a = NULL;
+ if (rtnl_link_inet6_get_token ((struct rtnl_link *) b, &token_b) != 0)
+ token_b = NULL;
+
+ if (token_a && token_b) {
+ if (nl_addr_get_family (token_a) == AF_INET6 &&
+ nl_addr_get_family (token_b) == AF_INET6 &&
+ nl_addr_get_len (token_a) == sizeof (struct in6_addr) &&
+ nl_addr_get_len (token_b) == sizeof (struct in6_addr) &&
+ memcmp (nl_addr_get_binary_addr (token_a),
+ nl_addr_get_binary_addr (token_b),
+ sizeof (struct in6_addr))) {
+ /* Token changed */
+ return TRUE;
+ }
+ } else if (token_a != token_b) {
+ /* Token added or removed (?). */
+ return TRUE;
+ }
+ }
+#endif
+
if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) {
struct rtnl_addr *a = (struct rtnl_addr *) _a;
struct rtnl_addr *b = (struct rtnl_addr *) _b;
@@ -2484,6 +2515,38 @@ link_set_noarp (NMPlatform *platform, int ifindex)
}
static gboolean
+link_get_ipv6_token (NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId *iid)
+{
+#if HAVE_LIBNL_INET6_TOKEN
+ auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
+ struct nl_addr *nladdr;
+ struct in6_addr *addr;
+
+ if (rtnllink &&
+ (rtnl_link_inet6_get_token (rtnllink, &nladdr)) == 0) {
+ if (nl_addr_get_family (nladdr) != AF_INET6 ||
+ nl_addr_get_len (nladdr) != sizeof (struct in6_addr)) {
+ nl_addr_put (nladdr);
+ return FALSE;
+ }
+
+ addr = nl_addr_get_binary_addr (nladdr);
+ iid->id_u8[7] = addr->s6_addr[15];
+ iid->id_u8[6] = addr->s6_addr[14];
+ iid->id_u8[5] = addr->s6_addr[13];
+ iid->id_u8[4] = addr->s6_addr[12];
+ iid->id_u8[3] = addr->s6_addr[11];
+ iid->id_u8[2] = addr->s6_addr[10];
+ iid->id_u8[1] = addr->s6_addr[9];
+ iid->id_u8[0] = addr->s6_addr[8];
+ nl_addr_put (nladdr);
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+static gboolean
link_get_user_ipv6ll_enabled (NMPlatform *platform, int ifindex)
{
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
@@ -4552,6 +4615,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_is_connected = link_is_connected;
platform_class->link_uses_arp = link_uses_arp;
+ platform_class->link_get_ipv6_token = link_get_ipv6_token;
+
platform_class->link_get_user_ipv6ll_enabled = link_get_user_ipv6ll_enabled;
platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index a2fd8f39a4..0540af8046 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -748,6 +748,31 @@ nm_platform_link_uses_arp (int ifindex)
}
/**
+ * nm_platform_link_get_ipv6_token:
+ * @ifindex: Interface index
+ * @iid: Tokenized interface identifier
+ *
+ * Returns IPv6 tokenized interface identifier. If the platform or OS doesn't
+ * support IPv6 tokenized interface identifiers, or the token is not set
+ * this call will fail and return %FALSE.
+ *
+ * Returns: %TRUE a tokenized identifier was available
+ */
+gboolean
+nm_platform_link_get_ipv6_token (int ifindex, NMUtilsIPv6IfaceId *iid)
+{
+ reset_error ();
+
+ g_return_val_if_fail (ifindex >= 0, FALSE);
+ g_return_val_if_fail (iid, FALSE);
+
+ if (klass->link_get_ipv6_token)
+ return klass->link_get_ipv6_token (platform, ifindex, iid);
+ return FALSE;
+}
+
+
+/**
* nm_platform_link_get_user_ip6vll_enabled:
* @ifindex: Interface index
*
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index b202de32a1..52362e4398 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -362,6 +362,8 @@ typedef struct {
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
gboolean (*link_uses_arp) (NMPlatform *, int ifindex);
+ gboolean (*link_get_ipv6_token) (NMPlatform *, int ifindex, NMUtilsIPv6IfaceId *iid);
+
gboolean (*link_get_user_ipv6ll_enabled) (NMPlatform *, int ifindex);
gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled);
@@ -509,6 +511,8 @@ gboolean nm_platform_link_is_up (int ifindex);
gboolean nm_platform_link_is_connected (int ifindex);
gboolean nm_platform_link_uses_arp (int ifindex);
+gboolean nm_platform_link_get_ipv6_token (int ifindex, NMUtilsIPv6IfaceId *iid);
+
gboolean nm_platform_link_get_user_ipv6ll_enabled (int ifindex);
gboolean nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled);
diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c
index 8729fa63df..58040c9d43 100644
--- a/src/rdisc/nm-rdisc.c
+++ b/src/rdisc/nm-rdisc.c
@@ -42,12 +42,38 @@ static guint signals[LAST_SIGNAL] = { 0 };
/******************************************************************/
-void
+/**
+ * nm_rdisc_set_iid:
+ * @rdisc: the #NMRDisc
+ * @iid: the new interface ID
+ *
+ * Sets the "Modified EUI-64" interface ID to be used when generating
+ * IPv6 addresses using received prefixes. Identifiers are either generated
+ * from the hardware addresses or manually set by the operator with
+ * "ip token" command.
+ *
+ * Upon token change (or initial setting) all addresses generated using
+ * the old identifier are removed. The caller should ensure the addresses
+ * will be reset by soliciting router advertisements.
+ *
+ * Returns: %TRUE if the token was changed, %FALSE otherwise.
+ **/
+gboolean
nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid)
{
- g_return_if_fail (NM_IS_RDISC (rdisc));
+ g_return_val_if_fail (NM_IS_RDISC (rdisc), FALSE);
+
+ if (rdisc->iid.id != iid.id) {
+ rdisc->iid = iid;
+ if (rdisc->addresses->len) {
+ debug ("(%s) IPv6 interface identifier changed, flushing addresses", rdisc->ifname);
+ g_array_remove_range (rdisc->addresses, 0, rdisc->addresses->len);
+ g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, NM_RDISC_CONFIG_ADDRESSES);
+ }
+ return TRUE;
+ }
- rdisc->iid = iid;
+ return FALSE;
}
void
diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h
index 2d83f0f020..8864c22f72 100644
--- a/src/rdisc/nm-rdisc.h
+++ b/src/rdisc/nm-rdisc.h
@@ -139,7 +139,7 @@ typedef struct {
GType nm_rdisc_get_type (void);
-void nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid);
+gboolean nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid);
void nm_rdisc_start (NMRDisc *rdisc);
#endif /* __NETWORKMANAGER_RDISC_H__ */