platform: add support for kernel IPv6LL address generation modes
This patch requires both upstream kernel support for IFLA_INET6_ADDR_GEN_MODE which was merged in this patch: ipv6: addrconf: implement address generation modes bc91b0f07ada5535427373a4e2050877bcc12218 and corresponding libnl support, merged in these patches: veth: add kernel header linux/veth.h for VETH defines 9dc6e6da90016a33929f262bea0187396e1a061b link: update copy of kernel header include/linux/if_link.h b51815a9dbd8e45fd2558bbe337fb360ca2fd861 link/inet6: add link IPv6 address generation mode support 558f966782539f6d975da705fd73cea561c9dc83
This commit is contained in:
19
configure.ac
19
configure.ac
@@ -386,6 +386,25 @@ PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8 libnl-route-3.0 libnl-genl-3.0)
|
|||||||
AC_SUBST(LIBNL_CFLAGS)
|
AC_SUBST(LIBNL_CFLAGS)
|
||||||
AC_SUBST(LIBNL_LIBS)
|
AC_SUBST(LIBNL_LIBS)
|
||||||
|
|
||||||
|
AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_addr_gen_mode],
|
||||||
|
ac_have_addr_gen_mode="1",
|
||||||
|
ac_have_addr_gen_mode="0")
|
||||||
|
AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_ADDR_GEN_MODE,
|
||||||
|
$ac_have_addr_gen_mode, [Define if libnl has rtnl_link_inet6_get_addr_gen_mode()])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([Linux kernel IN6_ADDR_GEN_MODE enum])
|
||||||
|
AC_COMPILE_IFELSE(
|
||||||
|
[AC_LANG_PROGRAM(
|
||||||
|
[[#ifndef __user
|
||||||
|
#define __user
|
||||||
|
#endif
|
||||||
|
#include <linux/if_link.h>]],
|
||||||
|
[[int a = IN6_ADDR_GEN_MODE_EUI64; a++;]])],
|
||||||
|
[ac_have_kernel_gen_mode="1"],
|
||||||
|
[ac_have_kernel_gen_mode="0"])
|
||||||
|
AC_DEFINE_UNQUOTED(HAVE_KERNEL_INET6_ADDR_GEN_MODE,
|
||||||
|
$ac_have_kernel_gen_mode, [Define if the kernel has IN6_ADDR_GEN_MODE_*])
|
||||||
|
|
||||||
# uuid library
|
# uuid library
|
||||||
PKG_CHECK_MODULES(UUID, uuid)
|
PKG_CHECK_MODULES(UUID, uuid)
|
||||||
AC_SUBST(UUID_CFLAGS)
|
AC_SUBST(UUID_CFLAGS)
|
||||||
|
@@ -44,6 +44,16 @@
|
|||||||
#include <netlink/route/route.h>
|
#include <netlink/route/route.h>
|
||||||
#include <gudev/gudev.h>
|
#include <gudev/gudev.h>
|
||||||
|
|
||||||
|
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
||||||
|
#include <netlink/route/link/inet6.h>
|
||||||
|
#if HAVE_KERNEL_INET6_ADDR_GEN_MODE
|
||||||
|
#include <linux/if_link.h>
|
||||||
|
#else
|
||||||
|
#define IN6_ADDR_GEN_MODE_EUI64 0
|
||||||
|
#define IN6_ADDR_GEN_MODE_NONE 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "NetworkManagerUtils.h"
|
#include "NetworkManagerUtils.h"
|
||||||
#include "nm-linux-platform.h"
|
#include "nm-linux-platform.h"
|
||||||
#include "NetworkManagerUtils.h"
|
#include "NetworkManagerUtils.h"
|
||||||
@@ -83,6 +93,7 @@ typedef struct {
|
|||||||
GHashTable *wifi_data;
|
GHashTable *wifi_data;
|
||||||
|
|
||||||
int support_kernel_extended_ifa_flags;
|
int support_kernel_extended_ifa_flags;
|
||||||
|
int support_user_ipv6ll;
|
||||||
} NMLinuxPlatformPrivate;
|
} NMLinuxPlatformPrivate;
|
||||||
|
|
||||||
#define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate))
|
#define NM_LINUX_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate))
|
||||||
@@ -669,6 +680,23 @@ check_support_kernel_extended_ifa_flags (NMPlatform *platform)
|
|||||||
return priv->support_kernel_extended_ifa_flags > 0;
|
return priv->support_kernel_extended_ifa_flags > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
check_support_user_ipv6ll (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_user_ipv6ll == 0) {
|
||||||
|
nm_log_warn (LOGD_PLATFORM, "Unable to detect kernel support for IFLA_INET6_ADDR_GEN_MODE. Assume no kernel support.");
|
||||||
|
priv->support_user_ipv6ll = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return priv->support_user_ipv6ll > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Object type specific utilities */
|
/* Object type specific utilities */
|
||||||
|
|
||||||
@@ -1529,8 +1557,20 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
|
|||||||
switch (object_type) {
|
switch (object_type) {
|
||||||
case OBJECT_TYPE_LINK:
|
case OBJECT_TYPE_LINK:
|
||||||
{
|
{
|
||||||
NMPlatformLink device;
|
|
||||||
struct rtnl_link *rtnl_link = (struct rtnl_link *) object;
|
struct rtnl_link *rtnl_link = (struct rtnl_link *) object;
|
||||||
|
NMPlatformLink device;
|
||||||
|
|
||||||
|
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
||||||
|
/* If we ever see a link with valid IPv6 link-local address
|
||||||
|
* generation modes, the kernel supports it.
|
||||||
|
*/
|
||||||
|
if (priv->support_user_ipv6ll == 0) {
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
if (rtnl_link_inet6_get_addr_gen_mode (rtnl_link, &mode) == 0)
|
||||||
|
priv->support_user_ipv6ll = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!init_link (platform, &device, rtnl_link))
|
if (!init_link (platform, &device, rtnl_link))
|
||||||
return;
|
return;
|
||||||
@@ -2405,6 +2445,46 @@ link_set_noarp (NMPlatform *platform, int ifindex)
|
|||||||
return link_change_flags (platform, ifindex, IFF_NOARP, TRUE);
|
return link_change_flags (platform, ifindex, IFF_NOARP, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
link_get_user_ipv6ll_enabled (NMPlatform *platform, int ifindex)
|
||||||
|
{
|
||||||
|
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
||||||
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||||
|
|
||||||
|
if (priv->support_user_ipv6ll > 0) {
|
||||||
|
auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
|
||||||
|
uint8_t mode = 0;
|
||||||
|
|
||||||
|
if (rtnllink) {
|
||||||
|
if (rtnl_link_inet6_get_addr_gen_mode (rtnllink, &mode) != 0) {
|
||||||
|
/* Default to "disabled" on error */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return mode == IN6_ADDR_GEN_MODE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled)
|
||||||
|
{
|
||||||
|
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
||||||
|
if (check_support_user_ipv6ll (platform)) {
|
||||||
|
auto_nl_object struct rtnl_link *change = _nm_rtnl_link_alloc (ifindex, NULL);
|
||||||
|
guint8 mode = enabled ? IN6_ADDR_GEN_MODE_NONE : IN6_ADDR_GEN_MODE_EUI64;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
rtnl_link_inet6_set_addr_gen_mode (change, mode);
|
||||||
|
debug ("link: change %d: set IPv6 address generation mode to %s",
|
||||||
|
ifindex, rtnl_link_inet6_addrgenmode2str (mode, buf, sizeof (buf)));
|
||||||
|
return link_change (platform, ifindex, change);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
supports_ethtool_carrier_detect (const char *ifname)
|
supports_ethtool_carrier_detect (const char *ifname)
|
||||||
{
|
{
|
||||||
@@ -4060,6 +4140,24 @@ setup (NMPlatform *platform)
|
|||||||
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object))
|
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object))
|
||||||
_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
|
_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
|
||||||
|
|
||||||
|
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
||||||
|
/* Initial check for user IPv6LL support once the link cache is allocated
|
||||||
|
* and filled. If there are no links in the cache yet then we'll check
|
||||||
|
* when a new link shows up in announce_object().
|
||||||
|
*/
|
||||||
|
object = nl_cache_get_first (priv->link_cache);
|
||||||
|
if (object) {
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
if (rtnl_link_inet6_get_addr_gen_mode ((struct rtnl_link *) object, &mode) == 0)
|
||||||
|
priv->support_user_ipv6ll = 1;
|
||||||
|
else
|
||||||
|
priv->support_user_ipv6ll = -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
priv->support_user_ipv6ll = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set up udev monitoring */
|
/* Set up udev monitoring */
|
||||||
priv->udev_client = g_udev_client_new (udev_subsys);
|
priv->udev_client = g_udev_client_new (udev_subsys);
|
||||||
g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
|
g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
|
||||||
@@ -4147,6 +4245,9 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||||||
platform_class->link_is_connected = link_is_connected;
|
platform_class->link_is_connected = link_is_connected;
|
||||||
platform_class->link_uses_arp = link_uses_arp;
|
platform_class->link_uses_arp = link_uses_arp;
|
||||||
|
|
||||||
|
platform_class->link_get_user_ipv6ll_enabled = link_get_user_ipv6ll_enabled;
|
||||||
|
platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled;
|
||||||
|
|
||||||
platform_class->link_get_address = link_get_address;
|
platform_class->link_get_address = link_get_address;
|
||||||
platform_class->link_set_address = link_set_address;
|
platform_class->link_set_address = link_set_address;
|
||||||
platform_class->link_get_mtu = link_get_mtu;
|
platform_class->link_get_mtu = link_get_mtu;
|
||||||
@@ -4213,4 +4314,5 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||||||
platform_class->ip6_route_exists = ip6_route_exists;
|
platform_class->ip6_route_exists = ip6_route_exists;
|
||||||
|
|
||||||
platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags;
|
platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags;
|
||||||
|
platform_class->check_support_user_ipv6ll = check_support_user_ipv6ll;
|
||||||
}
|
}
|
||||||
|
@@ -215,6 +215,21 @@ nm_platform_check_support_kernel_extended_ifa_flags ()
|
|||||||
return klass->check_support_kernel_extended_ifa_flags (platform);
|
return klass->check_support_kernel_extended_ifa_flags (platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
nm_platform_check_support_user_ipv6ll (void)
|
||||||
|
{
|
||||||
|
static int supported = -1;
|
||||||
|
|
||||||
|
g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE);
|
||||||
|
|
||||||
|
if (!klass->check_support_user_ipv6ll)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (supported < 0)
|
||||||
|
supported = klass->check_support_user_ipv6ll (platform) ? 1 : 0;
|
||||||
|
return !!supported;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -729,6 +744,52 @@ nm_platform_link_uses_arp (int ifindex)
|
|||||||
return klass->link_uses_arp (platform, ifindex);
|
return klass->link_uses_arp (platform, ifindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nm_platform_link_get_user_ip6vll_enabled:
|
||||||
|
* @ifindex: Interface index
|
||||||
|
*
|
||||||
|
* Check whether NM handles IPv6LL address creation for the link. If the
|
||||||
|
* platform or OS doesn't support changing the IPv6LL address mode, this call
|
||||||
|
* will fail and return %FALSE.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if NM handles the IPv6LL address for @ifindex
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
nm_platform_link_get_user_ipv6ll_enabled (int ifindex)
|
||||||
|
{
|
||||||
|
reset_error ();
|
||||||
|
|
||||||
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
||||||
|
g_return_val_if_fail (klass->check_support_user_ipv6ll, FALSE);
|
||||||
|
|
||||||
|
if (klass->link_get_user_ipv6ll_enabled)
|
||||||
|
return klass->link_get_user_ipv6ll_enabled (platform, ifindex);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nm_platform_link_set_user_ip6vll_enabled:
|
||||||
|
* @ifindex: Interface index
|
||||||
|
*
|
||||||
|
* Set whether NM handles IPv6LL address creation for the link. If the
|
||||||
|
* platform or OS doesn't support changing the IPv6LL address mode, this call
|
||||||
|
* will fail and return %FALSE.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the operation was successful, %FALSE if it failed.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled)
|
||||||
|
{
|
||||||
|
reset_error ();
|
||||||
|
|
||||||
|
g_return_val_if_fail (ifindex >= 0, FALSE);
|
||||||
|
g_return_val_if_fail (klass->check_support_user_ipv6ll, FALSE);
|
||||||
|
|
||||||
|
if (klass->link_set_user_ipv6ll_enabled)
|
||||||
|
return klass->link_set_user_ipv6ll_enabled (platform, ifindex, enabled);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nm_platform_link_set_address:
|
* nm_platform_link_set_address:
|
||||||
* @ifindex: Interface index
|
* @ifindex: Interface index
|
||||||
|
@@ -388,6 +388,9 @@ typedef struct {
|
|||||||
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
|
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
|
||||||
gboolean (*link_uses_arp) (NMPlatform *, int ifindex);
|
gboolean (*link_uses_arp) (NMPlatform *, int ifindex);
|
||||||
|
|
||||||
|
gboolean (*link_get_user_ipv6ll_enabled) (NMPlatform *, int ifindex);
|
||||||
|
gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled);
|
||||||
|
|
||||||
gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length);
|
gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length);
|
||||||
gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
|
gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
|
||||||
guint32 (*link_get_mtu) (NMPlatform *, int ifindex);
|
guint32 (*link_get_mtu) (NMPlatform *, int ifindex);
|
||||||
@@ -463,6 +466,7 @@ typedef struct {
|
|||||||
gboolean (*ip6_route_exists) (NMPlatform *, int ifindex, struct in6_addr 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 *);
|
gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *);
|
||||||
|
gboolean (*check_support_user_ipv6ll) (NMPlatform *);
|
||||||
} NMPlatformClass;
|
} NMPlatformClass;
|
||||||
|
|
||||||
/* NMPlatform signals
|
/* NMPlatform signals
|
||||||
@@ -528,6 +532,9 @@ gboolean nm_platform_link_is_up (int ifindex);
|
|||||||
gboolean nm_platform_link_is_connected (int ifindex);
|
gboolean nm_platform_link_is_connected (int ifindex);
|
||||||
gboolean nm_platform_link_uses_arp (int ifindex);
|
gboolean nm_platform_link_uses_arp (int ifindex);
|
||||||
|
|
||||||
|
gboolean nm_platform_link_get_user_ipv6ll_enabled (int ifindex);
|
||||||
|
gboolean nm_platform_link_set_user_ipv6ll_enabled (int ifindex, gboolean enabled);
|
||||||
|
|
||||||
gconstpointer nm_platform_link_get_address (int ifindex, size_t *length);
|
gconstpointer nm_platform_link_get_address (int ifindex, size_t *length);
|
||||||
gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t length);
|
gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t length);
|
||||||
guint32 nm_platform_link_get_mtu (int ifindex);
|
guint32 nm_platform_link_get_mtu (int ifindex);
|
||||||
@@ -623,6 +630,7 @@ int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6R
|
|||||||
|
|
||||||
gboolean nm_platform_check_support_libnl_extended_ifa_flags (void);
|
gboolean nm_platform_check_support_libnl_extended_ifa_flags (void);
|
||||||
gboolean nm_platform_check_support_kernel_extended_ifa_flags (void);
|
gboolean nm_platform_check_support_kernel_extended_ifa_flags (void);
|
||||||
|
gboolean nm_platform_check_support_user_ipv6ll (void);
|
||||||
|
|
||||||
void nm_platform_addr_flags2str (int flags, char *buf, size_t size);
|
void nm_platform_addr_flags2str (int flags, char *buf, size_t size);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user