diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2015-01-26 13:05:35 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2015-01-26 13:05:35 +0100 |
commit | 5f50c0480abb4db908ad2f5d05c1e53ae518f9f8 (patch) | |
tree | 62df07c353c7f1cd377a9673d7140fc2175a8539 | |
parent | 2d08e701a02e857f7301736f6f528cb149db32c2 (diff) | |
parent | c2f9940470fc891e2c743e6e33e43b43687414d2 (diff) | |
download | NetworkManager-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.ac | 7 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 4 | ||||
-rw-r--r-- | src/devices/nm-device.c | 14 | ||||
-rw-r--r-- | src/nm-types.h | 3 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 69 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 25 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 4 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.c | 32 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.h | 2 |
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__ */ |