platform: cleanup detecting kernel support for IFA_FLAGS and IPv6LL
- cache the result in NMPlatformPrivate. No need to call the virtual function every time. The result is not ever going to change. - if we are unable to detect support, assume support. Those features were added quite a while ago to kernel, we should default to "support". Note, that we detect support based on the presence of the absence of certain netlink flags. That means, we will still detect no support. The only moment when we actually use the fallback value, is when we didn't encounter an RTM_NEWADDR or AF_INET6-IFLA_AF_SPEC message yet, which would be very unusual, because we fill the cache initially and usually will have some addresses there. - for no strong reason, track "undetected" as numerical value zero, and "support"/"no-support" as 1/-1. We already did that previously for _support_user_ipv6ll, so this just unifies the implementations. The minor reason is that this puts @_support_user_ipv6ll to the BSS section and allows us to omit initializing priv->check_support_user_ipv6ll_cached in platforms constructor. - detect _support_kernel_extended_ifa_flags also based on IPv4 RTM_NEWADDR messages. Originally, extended flags were added for IPv6, and later to IPv4 as well. Once we see an IPv4 message with IFA_FLAGS, we know we have support.
This commit is contained in:
@@ -297,60 +297,62 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, g
|
|||||||
static int _support_user_ipv6ll = 0;
|
static int _support_user_ipv6ll = 0;
|
||||||
#define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0))
|
#define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0))
|
||||||
|
|
||||||
|
static void
|
||||||
|
_support_user_ipv6ll_detect (struct nlattr **tb)
|
||||||
|
{
|
||||||
|
gboolean supported;
|
||||||
|
|
||||||
|
nm_assert (_support_user_ipv6ll_still_undecided ());
|
||||||
|
|
||||||
|
supported = !!tb[IFLA_INET6_ADDR_GEN_MODE];
|
||||||
|
_support_user_ipv6ll = supported ? 1 : -1;
|
||||||
|
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s",
|
||||||
|
supported ? "detected" : "not detected");
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_support_user_ipv6ll_get (void)
|
_support_user_ipv6ll_get (void)
|
||||||
{
|
{
|
||||||
if (_support_user_ipv6ll_still_undecided ()) {
|
if (_support_user_ipv6ll_still_undecided ()) {
|
||||||
_support_user_ipv6ll = -1;
|
_support_user_ipv6ll = 1;
|
||||||
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume no support");
|
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume support");
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return _support_user_ipv6ll > 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_support_user_ipv6ll_detect (struct nlattr **tb)
|
|
||||||
{
|
|
||||||
if (_support_user_ipv6ll_still_undecided ()) {
|
|
||||||
gboolean supported = !!tb[IFLA_INET6_ADDR_GEN_MODE];
|
|
||||||
|
|
||||||
_support_user_ipv6ll = supported ? 1 : -1;
|
|
||||||
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s",
|
|
||||||
supported ? "detected" : "not detected");
|
|
||||||
}
|
}
|
||||||
|
return _support_user_ipv6ll >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* extended IFA_FLAGS support
|
* extended IFA_FLAGS support
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
static int _support_kernel_extended_ifa_flags = -1;
|
static int _support_kernel_extended_ifa_flags = 0;
|
||||||
|
|
||||||
#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == -1))
|
#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == 0))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
|
_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
|
||||||
{
|
{
|
||||||
struct nlmsghdr *msg_hdr;
|
struct nlmsghdr *msg_hdr;
|
||||||
|
gboolean support;
|
||||||
|
|
||||||
if (!_support_kernel_extended_ifa_flags_still_undecided ())
|
nm_assert (_support_kernel_extended_ifa_flags_still_undecided ());
|
||||||
return;
|
nm_assert (msg);
|
||||||
|
|
||||||
msg_hdr = nlmsg_hdr (msg);
|
msg_hdr = nlmsg_hdr (msg);
|
||||||
if (msg_hdr->nlmsg_type != RTM_NEWADDR)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* the extended address flags are only set for AF_INET6 */
|
nm_assert (msg_hdr && msg_hdr->nlmsg_type == RTM_NEWADDR);
|
||||||
if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6)
|
|
||||||
|
/* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6,
|
||||||
|
* but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */
|
||||||
|
if (NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
|
/* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
|
||||||
* we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
|
* we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
|
||||||
* and IFA_F_NOPREFIXROUTE (they were added together).
|
* and IFA_F_NOPREFIXROUTE (they were added together).
|
||||||
**/
|
**/
|
||||||
_support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS);
|
support = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS);
|
||||||
_LOG2D ("kernel-support: extended-ifa-flags: %s", _support_kernel_extended_ifa_flags ? "detected" : "not detected");
|
_support_kernel_extended_ifa_flags = support ? 1 : -1;
|
||||||
|
_LOG2D ("kernel-support: extended-ifa-flags: %s", support ? "detected" : "not detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -360,7 +362,7 @@ _support_kernel_extended_ifa_flags_get (void)
|
|||||||
_LOG2D ("kernel-support: extended-ifa-flags: %s", "unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
|
_LOG2D ("kernel-support: extended-ifa-flags: %s", "unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
|
||||||
_support_kernel_extended_ifa_flags = 1;
|
_support_kernel_extended_ifa_flags = 1;
|
||||||
}
|
}
|
||||||
return _support_kernel_extended_ifa_flags;
|
return _support_kernel_extended_ifa_flags >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
@@ -978,7 +980,8 @@ _parse_af_inet6 (NMPlatform *platform,
|
|||||||
/* Hack to detect support addrgenmode of the kernel. We only parse
|
/* Hack to detect support addrgenmode of the kernel. We only parse
|
||||||
* netlink messages that we receive from kernel, hence this check
|
* netlink messages that we receive from kernel, hence this check
|
||||||
* is valid. */
|
* is valid. */
|
||||||
_support_user_ipv6ll_detect (tb);
|
if (_support_user_ipv6ll_still_undecided ())
|
||||||
|
_support_user_ipv6ll_detect (tb);
|
||||||
|
|
||||||
if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
|
if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
|
||||||
i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]));
|
i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]));
|
||||||
@@ -2992,7 +2995,7 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
|
|||||||
static gboolean
|
static gboolean
|
||||||
check_support_kernel_extended_ifa_flags (NMPlatform *platform)
|
check_support_kernel_extended_ifa_flags (NMPlatform *platform)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
|
nm_assert (NM_IS_LINUX_PLATFORM (platform));
|
||||||
|
|
||||||
return _support_kernel_extended_ifa_flags_get ();
|
return _support_kernel_extended_ifa_flags_get ();
|
||||||
}
|
}
|
||||||
@@ -3000,7 +3003,7 @@ check_support_kernel_extended_ifa_flags (NMPlatform *platform)
|
|||||||
static gboolean
|
static gboolean
|
||||||
check_support_user_ipv6ll (NMPlatform *platform)
|
check_support_user_ipv6ll (NMPlatform *platform)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
|
nm_assert (NM_IS_LINUX_PLATFORM (platform));
|
||||||
|
|
||||||
return _support_user_ipv6ll_get ();
|
return _support_user_ipv6ll_get ();
|
||||||
}
|
}
|
||||||
@@ -3863,7 +3866,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
|
|||||||
|
|
||||||
msghdr = nlmsg_hdr (msg);
|
msghdr = nlmsg_hdr (msg);
|
||||||
|
|
||||||
if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR)
|
if ( _support_kernel_extended_ifa_flags_still_undecided ()
|
||||||
|
&& msghdr->nlmsg_type == RTM_NEWADDR)
|
||||||
_support_kernel_extended_ifa_flags_detect (msg);
|
_support_kernel_extended_ifa_flags_detect (msg);
|
||||||
|
|
||||||
if (!handle_events)
|
if (!handle_events)
|
||||||
@@ -4423,15 +4427,15 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable
|
|||||||
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
|
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
|
||||||
guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64;
|
guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64;
|
||||||
|
|
||||||
|
_LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s",
|
||||||
|
ifindex,
|
||||||
|
nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
|
||||||
|
|
||||||
if (!_support_user_ipv6ll_get ()) {
|
if (!_support_user_ipv6ll_get ()) {
|
||||||
_LOGD ("link: change %d: user-ipv6ll: not supported", ifindex);
|
_LOGD ("link: change %d: user-ipv6ll: not supported", ifindex);
|
||||||
return NM_PLATFORM_ERROR_OPNOTSUPP;
|
return NM_PLATFORM_ERROR_OPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
_LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s",
|
|
||||||
ifindex,
|
|
||||||
nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
|
|
||||||
|
|
||||||
nlmsg = _nl_msg_new_link (RTM_NEWLINK,
|
nlmsg = _nl_msg_new_link (RTM_NEWLINK,
|
||||||
0,
|
0,
|
||||||
ifindex,
|
ifindex,
|
||||||
|
@@ -91,6 +91,10 @@ enum {
|
|||||||
typedef struct _NMPlatformPrivate {
|
typedef struct _NMPlatformPrivate {
|
||||||
bool use_udev:1;
|
bool use_udev:1;
|
||||||
bool log_with_ptr:1;
|
bool log_with_ptr:1;
|
||||||
|
|
||||||
|
gint8 check_support_kernel_extended_ifa_flags_cached;
|
||||||
|
gint8 check_support_user_ipv6ll_cached;
|
||||||
|
|
||||||
guint ip4_dev_route_blacklist_check_id;
|
guint ip4_dev_route_blacklist_check_id;
|
||||||
guint ip4_dev_route_blacklist_gc_timeout_id;
|
guint ip4_dev_route_blacklist_gc_timeout_id;
|
||||||
GHashTable *ip4_dev_route_blacklist_hash;
|
GHashTable *ip4_dev_route_blacklist_hash;
|
||||||
@@ -270,27 +274,35 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_nmp_nlm_flag_to_string_lookup, NMPNlmFlags,
|
|||||||
gboolean
|
gboolean
|
||||||
nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self)
|
nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self)
|
||||||
{
|
{
|
||||||
_CHECK_SELF (self, klass, FALSE);
|
NMPlatformPrivate *priv;
|
||||||
|
|
||||||
if (!klass->check_support_kernel_extended_ifa_flags)
|
_CHECK_SELF (self, klass, TRUE);
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return klass->check_support_kernel_extended_ifa_flags (self);
|
priv = NM_PLATFORM_GET_PRIVATE (self);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (priv->check_support_kernel_extended_ifa_flags_cached == 0)) {
|
||||||
|
priv->check_support_kernel_extended_ifa_flags_cached = ( klass->check_support_kernel_extended_ifa_flags
|
||||||
|
&& klass->check_support_kernel_extended_ifa_flags (self))
|
||||||
|
? 1 : -1;
|
||||||
|
}
|
||||||
|
return priv->check_support_kernel_extended_ifa_flags_cached >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
nm_platform_check_support_user_ipv6ll (NMPlatform *self)
|
nm_platform_check_support_user_ipv6ll (NMPlatform *self)
|
||||||
{
|
{
|
||||||
static int supported = -1;
|
NMPlatformPrivate *priv;
|
||||||
|
|
||||||
_CHECK_SELF (self, klass, FALSE);
|
_CHECK_SELF (self, klass, TRUE);
|
||||||
|
|
||||||
if (!klass->check_support_user_ipv6ll)
|
priv = NM_PLATFORM_GET_PRIVATE (self);
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (supported < 0)
|
if (G_UNLIKELY (priv->check_support_user_ipv6ll_cached == 0)) {
|
||||||
supported = klass->check_support_user_ipv6ll (self) ? 1 : 0;
|
priv->check_support_user_ipv6ll_cached = ( klass->check_support_user_ipv6ll
|
||||||
return !!supported;
|
&& klass->check_support_user_ipv6ll (self))
|
||||||
|
? 1 : -1;
|
||||||
|
}
|
||||||
|
return priv->check_support_user_ipv6ll_cached >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user