From 0d59984ce837581ff78ce747d1fcf6e393b6beb5 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sat, 27 Sep 2014 09:03:17 +0200 Subject: core: Add NMUtilsIPv6IfaceId to nm-types.h We'd like to use it in nm-platform.h, but it's included by NetworkManagerUtils.h before the declaration occurs. --- src/NetworkManagerUtils.h | 4 ++-- src/nm-types.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) 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/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 */ -- cgit v1.2.1 From db5603e615f502e2fc96040e7f6b83a13fcb0f98 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sat, 27 Sep 2014 09:03:56 +0200 Subject: platform: Add support for IPv6 tokenized identifiers --- src/platform/nm-platform.c | 25 +++++++++++++++++++++++++ src/platform/nm-platform.h | 4 ++++ 2 files changed, 29 insertions(+) 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 @@ -747,6 +747,31 @@ nm_platform_link_uses_arp (int ifindex) return klass->link_uses_arp (platform, 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); -- cgit v1.2.1 From 24e7ea786058597fdb45842377045e73ba8f923d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sat, 27 Sep 2014 09:04:46 +0200 Subject: core: Use tokenized identifiers when constructing an address We trigger a new solicitation upon seeing the new token. Kernel triggers one too, but that one is of no use to us, since the advertisement might arrive sooner than we learn about the token change. --- src/devices/nm-device.c | 14 ++++++++++++-- src/rdisc/nm-rdisc.c | 32 +++++++++++++++++++++++++++++--- src/rdisc/nm-rdisc.h | 2 +- 3 files changed, 42 insertions(+), 6 deletions(-) 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/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__ */ -- cgit v1.2.1 From b47d55b5004c4028b27b9153eb4e3bab1b8b82b5 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sat, 27 Sep 2014 09:01:08 +0200 Subject: build: Check for tokenized identifier support in libnl-route-3 --- configure.ac | 7 +++++++ 1 file changed, 7 insertions(+) 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) -- cgit v1.2.1 From 954a4b69b83bf71397cbb27dc742b0244e478bca Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 29 Sep 2014 17:58:44 +0200 Subject: platform: refresh link cache when IPv6 tokenized identifier changes --- src/platform/nm-linux-platform.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a03abbebb3..fa7919b003 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -44,9 +44,9 @@ #include #include -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE +#if HAVE_LIBNL_INET6_ADDR_GEN_MODE || HAVE_LIBNL_INET6_TOKEN #include -#if HAVE_KERNEL_INET6_ADDR_GEN_MODE +#if HAVE_LIBNL_INET6_ADDR_GEN_MODE && HAVE_KERNEL_INET6_ADDR_GEN_MODE #include #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; -- cgit v1.2.1 From c2f9940470fc891e2c743e6e33e43b43687414d2 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 13 Oct 2014 08:26:52 +0200 Subject: platform: Add support for IPv6 tokenized identifiers on Linux --- src/platform/nm-linux-platform.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index fa7919b003..091791f4b8 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2514,6 +2514,38 @@ link_set_noarp (NMPlatform *platform, int ifindex) return link_change_flags (platform, ifindex, IFF_NOARP, TRUE); } +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) { @@ -4583,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; -- cgit v1.2.1