summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-04-18 11:18:04 +0200
committerThomas Haller <thaller@redhat.com>2019-04-18 11:19:43 +0200
commit30bb93cd9364cfb647274aa6f023dd5b741fe891 (patch)
tree384d143d407c420e006ede5f0412d7027962412d
parent73e32e43c8ca08adc3500d603eacb9133e40ed3c (diff)
parent062be85d82a37910ad5bdb5c33e8fe2fca929f09 (diff)
platform: merge branch 'th/platform-routing-rules-compare'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/115 (cherry picked from commit c76aaa94edbfab467a3b897b071bdd44120c08b6)
-rw-r--r--src/devices/nm-device.c21
-rw-r--r--src/nm-iface-helper.c6
-rw-r--r--src/platform/nm-fake-platform.c4
-rw-r--r--src/platform/nm-linux-platform.c225
-rw-r--r--src/platform/nm-platform.c196
-rw-r--r--src/platform/nm-platform.h57
-rw-r--r--src/platform/tests/monitor.c2
-rw-r--r--src/platform/tests/test-link.c3
8 files changed, 273 insertions, 241 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index d85393eb7a..253740a225 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -1546,8 +1546,7 @@ _set_ip_ifindex (NMDevice *self,
priv->ip_ifindex,
priv->ip_iface);
- if (nm_platform_check_kernel_support (platform,
- NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL))
+ if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL))
nm_platform_link_set_user_ipv6ll_enabled (platform, priv->ip_ifindex, TRUE);
if (!nm_platform_link_is_up (platform, priv->ip_ifindex))
@@ -4330,8 +4329,7 @@ realize_start_setup (NMDevice *self,
if (priv->firmware_version)
_notify (self, PROP_FIRMWARE_VERSION);
- if (nm_platform_check_kernel_support (nm_device_get_platform (self),
- NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL))
+ if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL))
priv->ipv6ll_handle = nm_platform_link_get_user_ipv6ll_enabled (nm_device_get_platform (self), priv->ifindex);
if (nm_platform_link_supports_sriov (nm_device_get_platform (self), priv->ifindex))
@@ -9234,8 +9232,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
* addresses as /128. The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address. */
ifa_flags = 0;
- if (nm_platform_check_kernel_support (nm_device_get_platform (self),
- NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)) {
+ if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) {
ifa_flags |= IFA_F_NOPREFIXROUTE;
if (NM_IN_SET (priv->ndisc_use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR))
@@ -9267,8 +9264,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
rdata->routes_n,
nm_device_get_route_table (self, AF_INET6, TRUE),
nm_device_get_route_metric (self, AF_INET6),
- nm_platform_check_kernel_support (nm_device_get_platform (self),
- NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF));
+ nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF));
if (priv->ac_ip6_config.current) {
nm_ip6_config_reset_routes_ndisc ((NMIP6Config *) priv->ac_ip6_config.current,
rdata->gateways,
@@ -9277,8 +9273,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
rdata->routes_n,
nm_device_get_route_table (self, AF_INET6, TRUE),
nm_device_get_route_metric (self, AF_INET6),
- nm_platform_check_kernel_support (nm_device_get_platform (self),
- NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF));
+ nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF));
}
}
@@ -9466,8 +9461,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
priv->ndisc_use_tempaddr = use_tempaddr;
if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
- && !nm_platform_check_kernel_support (nm_device_get_platform (self),
- NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)) {
+ && !nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) {
_LOGW (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for "
"IPv6 private addresses. This feature is not available");
}
@@ -9574,8 +9568,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex = nm_device_get_ip_ifindex (self);
- if (!nm_platform_check_kernel_support (nm_device_get_platform (self),
- NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL))
+ if (!nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL))
return;
priv->ipv6ll_handle = enable;
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 1ef9f5aea6..e53b446e3b 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -186,8 +186,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
* addresses as /128. The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address. */
ifa_flags = 0;
- if (nm_platform_check_kernel_support (NM_PLATFORM_GET,
- NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)) {
+ if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) {
ifa_flags |= IFA_F_NOPREFIXROUTE;
if (NM_IN_SET (global_opt.tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR))
@@ -212,8 +211,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
rdata->routes_n,
RT_TABLE_MAIN,
global_opt.priority_v6,
- nm_platform_check_kernel_support (NM_PLATFORM_GET,
- NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF));
+ nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF));
}
if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) {
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index 05f9667e97..40a85390b6 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -1401,6 +1401,10 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NMPlatformClass *platform_class = NM_PLATFORM_CLASS (klass);
+ NMPlatformKernelSupportType kernel_support;
+
+ for (kernel_support = 0; kernel_support < _NM_PLATFORM_KERNEL_SUPPORT_NUM; kernel_support++)
+ _nm_platform_kernel_support_init (kernel_support, -1);
object_class->finalize = finalize;
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 460b321bf6..d8b18a3faf 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -142,8 +142,6 @@ enum {
#define __IFLA_TUN_MAX 10
#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
-static const gboolean RTA_PREF_SUPPORTED_AT_COMPILETIME = (RTA_MAX >= 20 /* RTA_PREF */);
-
G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1));
#define RTA_PREF 20
#undef RTA_MAX
@@ -582,119 +580,6 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result,
return buf0;
}
-/*****************************************************************************
- * Support IFLA_INET6_ADDR_GEN_MODE
- *****************************************************************************/
-
-static int _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 ());
-
- /* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */
- 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
-_support_user_ipv6ll_get (void)
-{
- if (_support_user_ipv6ll_still_undecided ()) {
- _support_user_ipv6ll = 1;
- _LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume support");
- }
- return _support_user_ipv6ll >= 0;
-}
-
-/*****************************************************************************
- * extended IFA_FLAGS support
- *****************************************************************************/
-
-static int _support_kernel_extended_ifa_flags = 0;
-
-#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == 0))
-
-static void
-_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
-{
- struct nlmsghdr *msg_hdr;
- gboolean support;
-
- nm_assert (_support_kernel_extended_ifa_flags_still_undecided ());
- nm_assert (msg);
-
- msg_hdr = nlmsg_hdr (msg);
-
- nm_assert (msg_hdr && msg_hdr->nlmsg_type == RTM_NEWADDR);
-
- /* 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;
-
- /* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
- * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
- * and IFA_F_NOPREFIXROUTE for IPv6. They were added together in kernel 3.14,
- * dated 30 March, 2014.
- *
- * For IPv4, IFA_F_NOPREFIXROUTE was added later, but there is no easy
- * way to detect kernel support. */
- support = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS);
- _support_kernel_extended_ifa_flags = support ? 1 : -1;
- _LOG2D ("kernel-support: extended-ifa-flags: %s", support ? "detected" : "not detected");
-}
-
-static gboolean
-_support_kernel_extended_ifa_flags_get (void)
-{
- if (_support_kernel_extended_ifa_flags_still_undecided ()) {
- _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;
- }
- return _support_kernel_extended_ifa_flags >= 0;
-}
-
-/*****************************************************************************
- * Support RTA_PREF
- *****************************************************************************/
-
-static int _support_rta_pref = 0;
-#define _support_rta_pref_still_undecided() (G_UNLIKELY (_support_rta_pref == 0))
-
-static void
-_support_rta_pref_detect (struct nlattr **tb)
-{
- gboolean supported;
-
- nm_assert (_support_rta_pref_still_undecided ());
-
- /* RTA_PREF was added in kernel 4.1, dated 21 June, 2015. */
- supported = !!tb[RTA_PREF];
- _support_rta_pref = supported ? 1 : -1;
- _LOG2D ("kernel-support: RTA_PREF: ability to set router preference for IPv6 routes: %s",
- supported ? "detected" : "not detected");
-}
-
-static gboolean
-_support_rta_pref_get (void)
-{
- if (_support_rta_pref_still_undecided ()) {
- /* if we couldn't detect support, we fallback on compile-time check, whether
- * RTA_PREF is present in the kernel headers. */
- _support_rta_pref = RTA_PREF_SUPPORTED_AT_COMPILETIME ? 1 : -1;
- _LOG2D ("kernel-support: RTA_PREF: ability to set router preference for IPv6 routes: %s",
- RTA_PREF_SUPPORTED_AT_COMPILETIME ? "assume support" : "assume no support");
- }
- return _support_rta_pref >= 0;
-}
-
/******************************************************************
* Various utilities
******************************************************************/
@@ -1246,8 +1131,11 @@ _parse_af_inet6 (NMPlatform *platform,
/* Hack to detect support addrgenmode of the kernel. We only parse
* netlink messages that we receive from kernel, hence this check
* is valid. */
- if (_support_user_ipv6ll_still_undecided ())
- _support_user_ipv6ll_detect (tb);
+ if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) {
+ /* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */
+ _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL,
+ tb[IFLA_INET6_ADDR_GEN_MODE] ? 1 : -1);
+ }
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]));
@@ -3371,9 +3259,13 @@ rta_multipath_done:
obj->ip_route.lock_mtu = NM_FLAGS_HAS (lock, 1 << RTAX_MTU);
if (!is_v4) {
- /* Detect support for RTA_PREF by inspecting the netlink message. */
- if (_support_rta_pref_still_undecided ())
- _support_rta_pref_detect (tb);
+
+ if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)) {
+ /* Detect support for RTA_PREF by inspecting the netlink message.
+ * RTA_PREF was added in kernel 4.1, dated 21 June, 2015. */
+ _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF,
+ tb[RTA_PREF] ? 1 : -1);
+ }
if (tb[RTA_PREF])
obj->ip6_route.rt_pref = nla_get_u8 (tb[RTA_PREF]);
@@ -3510,6 +3402,16 @@ _new_from_nl_routing_rule (struct nlmsghdr *nlh, gboolean id_only)
props->tun_id = nla_get_be64 (tb[FRA_TUN_ID]);
if (tb[FRA_L3MDEV]) {
+
+ if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)) {
+ /* support for FRA_L3MDEV was added in 96c63fa7393d0a346acfe5a91e0c7d4c7782641b,
+ * kernel 4.8, 3 October 2017.
+ *
+ * We can only detect support if the attribute is present. A missing attribute
+ * is not conclusive. */
+ _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV, 1);
+ }
+
/* actually, kernel only allows this attribute to be missing or
* "1". Still, encode it as full uint8.
*
@@ -3522,6 +3424,13 @@ _new_from_nl_routing_rule (struct nlmsghdr *nlh, gboolean id_only)
else
nm_assert (props->protocol == RTPROT_UNSPEC);
+ if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)) {
+ /* FRA_PROTOCOL was added in kernel 4.17, dated 3 June, 2018.
+ * See commit 1b71af6053af1bd2f849e9fda4f71c1e3f145dcf. */
+ _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL,
+ tb[FRA_PROTOCOL] ? 1 : -1);
+ }
+
if (tb[FRA_IP_PROTO])
props->ip_proto = nla_get_u8 (tb[FRA_IP_PROTO]);
@@ -3532,11 +3441,33 @@ _new_from_nl_routing_rule (struct nlmsghdr *nlh, gboolean id_only)
nla_memcpy_checked_size (&props->sport_range, tb[FRA_SPORT_RANGE], sizeof (props->sport_range));
nla_memcpy_checked_size (&props->dport_range, tb[FRA_DPORT_RANGE], sizeof (props->dport_range));
+ if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) {
+ /* support for FRA_IP_PROTO, FRA_SPORT_RANGE, and FRA_DPORT_RANGE was added together
+ * by bfff4862653bb96001ab57c1edd6d03f48e5f035, kernel 4.17, 4 June 2018.
+ *
+ * Unfortunately, a missing attribute does not tell us anything about support.
+ * We can only tell for sure when we have support, but not when we don't have. */
+ if ( tb[FRA_IP_PROTO]
+ || tb[FRA_SPORT_RANGE]
+ || tb[FRA_DPORT_RANGE])
+ _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO, 1);
+ }
+
G_STATIC_ASSERT_EXPR (sizeof (NMFibRuleUidRange) == 8);
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRuleUidRange, start) == 0);
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMFibRuleUidRange, end) == 4);
if (tb[FRA_UID_RANGE]) {
+
+ if (!_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) {
+ /* support for FRA_UID_RANGE was added in 622ec2c9d52405973c9f1ca5116eb1c393adfc7d,
+ * kernel 4.10, 19 February 2017.
+ *
+ * We can only detect support if the attribute is present. A missing attribute
+ * is not conclusive. */
+ _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE, 1);
+ }
+
nla_memcpy_checked_size (&props->uid_range, tb[FRA_UID_RANGE], sizeof (props->uid_range));
props->uid_range_has = TRUE;
}
@@ -4654,32 +4585,6 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
/*****************************************************************************/
-static NMPlatformKernelSupportFlags
-check_kernel_support (NMPlatform *platform,
- NMPlatformKernelSupportFlags request_flags)
-{
- NMPlatformKernelSupportFlags response = 0;
-
- nm_assert (NM_IS_LINUX_PLATFORM (platform));
-
- if (NM_FLAGS_HAS (request_flags, NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)) {
- if (_support_kernel_extended_ifa_flags_get ())
- response |= NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS;
- }
-
- if (NM_FLAGS_HAS (request_flags, NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) {
- if (_support_user_ipv6ll_get ())
- response |= NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL;
- }
-
- if (NM_FLAGS_HAS (request_flags, NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF)) {
- if (_support_rta_pref_get ())
- response |= NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF;
- }
-
- return response;
-}
-
static void
process_events (NMPlatform *platform)
{
@@ -5849,9 +5754,27 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
msghdr = nlmsg_hdr (msg);
- if ( _support_kernel_extended_ifa_flags_still_undecided ()
- && msghdr->nlmsg_type == RTM_NEWADDR)
- _support_kernel_extended_ifa_flags_detect (msg);
+ if ( !_nm_platform_kernel_support_detected (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)
+ && msghdr->nlmsg_type == RTM_NEWADDR) {
+ /* 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 ( nlmsg_valid_hdr (msghdr, sizeof (struct ifaddrmsg))
+ && NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msghdr))->ifa_family,
+ AF_INET,
+ AF_INET6)) {
+ /* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
+ * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
+ * and IFA_F_NOPREFIXROUTE for IPv6. They were added together in kernel 3.14,
+ * dated 30 March, 2014.
+ *
+ * For IPv4, IFA_F_NOPREFIXROUTE was added later, but there is no easy
+ * way to detect kernel support. */
+ _nm_platform_kernel_support_init (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS,
+ !!nlmsg_find_attr (msghdr, sizeof (struct ifaddrmsg), IFA_FLAGS)
+ ? 1
+ : -1);
+ }
+ }
if (!handle_events)
return;
@@ -6441,7 +6364,7 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable
ifindex,
nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
- if (!_support_user_ipv6ll_get ()) {
+ if (!nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) {
_LOGD ("link: change %d: user-ipv6ll: not supported", ifindex);
return -NME_PL_OPNOTSUPP;
}
@@ -9085,8 +9008,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->qdisc_add = qdisc_add;
platform_class->tfilter_add = tfilter_add;
- platform_class->check_kernel_support = check_kernel_support;
-
platform_class->process_events = process_events;
}
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 53ad78caf0..88508c97f7 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -119,9 +119,6 @@ typedef struct _NMPlatformPrivate {
bool use_udev:1;
bool log_with_ptr:1;
- NMPlatformKernelSupportFlags support_checked;
- NMPlatformKernelSupportFlags support_present;
-
guint ip4_dev_route_blacklist_check_id;
guint ip4_dev_route_blacklist_gc_timeout_id;
GHashTable *ip4_dev_route_blacklist_hash;
@@ -277,40 +274,99 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_nmp_nlm_flag_to_string_lookup, NMPNlmFlags,
/*****************************************************************************/
-NMPlatformKernelSupportFlags
-nm_platform_check_kernel_support (NMPlatform *self,
- NMPlatformKernelSupportFlags request_flags)
+volatile int _nm_platform_kernel_support_state[_NM_PLATFORM_KERNEL_SUPPORT_NUM] = { };
+
+static const struct {
+ bool compile_time_default;
+ const char *name;
+ const char *desc;
+} _nm_platform_kernel_support_info[_NM_PLATFORM_KERNEL_SUPPORT_NUM] = {
+ [NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS] = {
+ .compile_time_default = TRUE,
+ .name = "EXTENDED_IFA_FLAGS",
+ .desc = "IPv6 temporary addresses support",
+ },
+ [NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL] = {
+ .compile_time_default = TRUE,
+ .name = "USER_IPV6LL",
+ .desc = "IFLA_INET6_ADDR_GEN_MODE support",
+ },
+ [NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF] = {
+ .compile_time_default = (RTA_MAX >= 20 /* RTA_PREF */),
+ .name = "RTA_PREF",
+ .desc = "ability to set router preference for IPv6 routes",
+ },
+ [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV] = {
+ .compile_time_default = (FRA_MAX >= 19 /* FRA_L3MDEV */),
+ .name = "FRA_L3MDEV",
+ .desc = "FRA_L3MDEV attribute for policy routing rules",
+ },
+ [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE] = {
+ .compile_time_default = (FRA_MAX >= 20 /* FRA_UID_RANGE */),
+ .name = "FRA_UID_RANGE",
+ .desc = "FRA_UID_RANGE attribute for policy routing rules",
+ },
+ [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL] = {
+ .compile_time_default = (FRA_MAX >= 21 /* FRA_PROTOCOL */),
+ .name = "FRA_PROTOCOL",
+ .desc = "FRA_PROTOCOL attribute for policy routing rules",
+ },
+ [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO] = {
+ .compile_time_default = (FRA_MAX >= 22 /* FRA_IP_PROTO */),
+ .name = "FRA_IP_PROTO",
+ .desc = "FRA_IP_PROTO, FRA_SPORT_RANGE, FRA_DPORT_RANGE attributes for policy routing rules",
+ },
+};
+
+int
+_nm_platform_kernel_support_init (NMPlatformKernelSupportType type,
+ int value)
{
- NMPlatformPrivate *priv;
+ volatile int *p_state;
+ gboolean set_default = FALSE;
- _CHECK_SELF (self, klass, TRUE);
+ nm_assert (_NM_INT_NOT_NEGATIVE (type) && type < G_N_ELEMENTS (_nm_platform_kernel_support_state));
- priv = NM_PLATFORM_GET_PRIVATE (self);
+ p_state = &_nm_platform_kernel_support_state[type];
- /* we cache the response from subclasses and only request it once.
- * This probably gives better performance, but more importantly,
- * we are guaranteed that the answer for a certain request_flag
- * is always the same. */
- if (G_UNLIKELY (!NM_FLAGS_ALL (priv->support_checked, request_flags))) {
- NMPlatformKernelSupportFlags checked, response;
+ if (value == 0) {
+ set_default = TRUE;
+ value = _nm_platform_kernel_support_info[type].compile_time_default
+ ? 1
+ : -1;
+ }
- checked = request_flags & ~priv->support_checked;
- nm_assert (checked);
+ nm_assert (NM_IN_SET (value, -1, 1));
- if (klass->check_kernel_support)
- response = klass->check_kernel_support (self, checked);
- else {
- /* fake platform. Pretend no support for anything. */
- response = 0;
- }
+ if (!g_atomic_int_compare_and_exchange (p_state, 0, value)) {
+ value = g_atomic_int_get (p_state);
+ nm_assert (NM_IN_SET (value, -1, 1));
+ return value;
+ }
+
+#undef NM_THREAD_SAFE_ON_MAIN_THREAD
+#define NM_THREAD_SAFE_ON_MAIN_THREAD 0
- priv->support_checked |= checked;
- priv->support_present = (priv->support_present & ~checked) | (response & checked);
+ if (set_default) {
+ nm_log_dbg (LOGD_PLATFORM, "platform: kernel-support for %s (%s) not detected: assume %ssupported",
+ _nm_platform_kernel_support_info[type].name,
+ _nm_platform_kernel_support_info[type].desc,
+ value >= 0 ? "" : "not ");
+ } else {
+ nm_log_dbg (LOGD_PLATFORM, "platform: kernel-support for %s (%s) detected: %ssupported",
+ _nm_platform_kernel_support_info[type].name,
+ _nm_platform_kernel_support_info[type].desc,
+ value >= 0 ? "" : "not ");
}
- return priv->support_present & request_flags;
+#undef NM_THREAD_SAFE_ON_MAIN_THREAD
+#define NM_THREAD_SAFE_ON_MAIN_THREAD 1
+
+ return value;
}
+/*****************************************************************************/
+
/**
* nm_platform_process_events:
* @self: platform instance
@@ -3912,7 +3968,7 @@ nm_platform_ip4_address_sync (NMPlatform *self,
if (!known_addresses)
return TRUE;
- ifa_flags = nm_platform_check_kernel_support (self, NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)
+ ifa_flags = nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)
? IFA_F_NOPREFIXROUTE
: 0;
@@ -4112,7 +4168,7 @@ next_plat:
if (!known_addresses)
return TRUE;
- ifa_flags = nm_platform_check_kernel_support (self, NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS)
+ ifa_flags = nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)
? IFA_F_NOPREFIXROUTE
: 0;
@@ -7349,6 +7405,10 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
| FIB_RULE_IIF_DETACHED \
| FIB_RULE_OIF_DETACHED)
+#define _routing_rule_compare(cmp_type, kernel_support_type) \
+ ( (cmp_type) == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL \
+ || nm_platform_kernel_support_get (kernel_support_type))
+
void
nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj,
NMPlatformRoutingRuleCmpType cmp_type,
@@ -7379,7 +7439,6 @@ nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj,
/* fall-through */
case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL:
-
nm_hash_update_vals (h,
obj->addr_family,
obj->tun_id,
@@ -7398,27 +7457,42 @@ nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj,
? obj->flow
: (guint32) 0u),
NM_HASH_COMBINE_BOOLS (guint8,
- obj->uid_range_has),
+ ( _routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)
+ ? obj->uid_range_has
+ : FALSE)),
obj->suppress_prefixlen_inverse,
obj->suppress_ifgroup_inverse,
- ( cmp_full
- ? obj->l3mdev
- : (guint8) !!obj->l3mdev),
+ ( _routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)
+ ? ( cmp_full
+ ? (guint16) obj->l3mdev
+ : (guint16) !!obj->l3mdev)
+ : G_MAXUINT16),
obj->action,
obj->tos,
obj->src_len,
obj->dst_len,
- obj->protocol,
- obj->ip_proto);
+ ( _routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)
+ ? (guint16) obj->protocol
+ : G_MAXUINT16));
addr_size = nm_utils_addr_family_to_size (obj->addr_family);
if (cmp_full || obj->src_len > 0)
nm_hash_update (h, &obj->src, addr_size);
if (cmp_full || obj->dst_len > 0)
nm_hash_update (h, &obj->dst, addr_size);
- if (cmp_full || obj->uid_range_has)
- nm_hash_update_valp (h, &obj->uid_range);
- nm_hash_update_valp (h, &obj->sport_range);
- nm_hash_update_valp (h, &obj->dport_range);
+ if (_routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) {
+ if (cmp_full || obj->uid_range_has)
+ nm_hash_update_valp (h, &obj->uid_range);
+ }
+ if (_routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) {
+ nm_hash_update_val (h, obj->ip_proto);
+ nm_hash_update_valp (h, &obj->sport_range);
+ nm_hash_update_valp (h, &obj->dport_range);
+ }
nm_hash_update_str (h, obj->iifname);
nm_hash_update_str (h, obj->oifname);
return;
@@ -7469,13 +7543,15 @@ nm_platform_routing_rule_cmp (const NMPlatformRoutingRule *a,
NM_CMP_FIELD (a, b, priority);
NM_CMP_FIELD (a, b, tun_id);
- if (cmp_full)
- NM_CMP_FIELD (a, b, l3mdev);
- else
- NM_CMP_FIELD_BOOL (a, b, l3mdev);
+ if (_routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)) {
+ if (cmp_full)
+ NM_CMP_FIELD (a, b, l3mdev);
+ else
+ NM_CMP_FIELD_BOOL (a, b, l3mdev);
+ }
- if (cmp_full || !a->l3mdev)
- NM_CMP_FIELD (a, b, table);
+ NM_CMP_FIELD (a, b, table);
NM_CMP_DIRECT (a->flags & flags_mask, b->flags & flags_mask);
@@ -7494,8 +7570,19 @@ nm_platform_routing_rule_cmp (const NMPlatformRoutingRule *a,
if (cmp_full || a->addr_family == AF_INET)
NM_CMP_FIELD (a, b, flow);
- NM_CMP_FIELD (a, b, protocol);
- NM_CMP_FIELD (a, b, ip_proto);
+ if (_routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL))
+ NM_CMP_FIELD (a, b, protocol);
+
+ if (_routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) {
+ NM_CMP_FIELD (a, b, ip_proto);
+ NM_CMP_FIELD (a, b, sport_range.start);
+ NM_CMP_FIELD (a, b, sport_range.end);
+ NM_CMP_FIELD (a, b, dport_range.start);
+ NM_CMP_FIELD (a, b, dport_range.end);
+ }
+
addr_size = nm_utils_addr_family_to_size (a->addr_family);
NM_CMP_FIELD (a, b, src_len);
@@ -7506,16 +7593,15 @@ nm_platform_routing_rule_cmp (const NMPlatformRoutingRule *a,
if (cmp_full || a->dst_len > 0)
NM_CMP_FIELD_MEMCMP_LEN (a, b, dst, addr_size);
- NM_CMP_FIELD_UNSAFE (a, b, uid_range_has);
- if (cmp_full || a->uid_range_has) {
- NM_CMP_FIELD (a, b, uid_range.start);
- NM_CMP_FIELD (a, b, uid_range.end);
+ if (_routing_rule_compare (cmp_type,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) {
+ NM_CMP_FIELD_UNSAFE (a, b, uid_range_has);
+ if (cmp_full || a->uid_range_has) {
+ NM_CMP_FIELD (a, b, uid_range.start);
+ NM_CMP_FIELD (a, b, uid_range.end);
+ }
}
- NM_CMP_FIELD (a, b, sport_range.start);
- NM_CMP_FIELD (a, b, sport_range.end);
- NM_CMP_FIELD (a, b, dport_range.start);
- NM_CMP_FIELD (a, b, dport_range.end);
NM_CMP_FIELD_STR (a, b, iifname);
NM_CMP_FIELD_STR (a, b, oifname);
return 0;
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index fa8200e68b..97be88324e 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -819,12 +819,6 @@ typedef enum {
} NMPlatformLinkDuplexType;
typedef enum {
- NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS = (1LL << 0),
- NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL = (1LL << 1),
- NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF = (1LL << 2),
-} NMPlatformKernelSupportFlags;
-
-typedef enum {
NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE = 0,
NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS = (1LL << 0),
NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY = (1LL << 1),
@@ -850,6 +844,51 @@ typedef enum {
/*****************************************************************************/
+typedef enum {
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE,
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL,
+
+ /* this also includes FRA_SPORT_RANGE and FRA_DPORT_RANGE which
+ * were added at the same time. */
+ NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO,
+
+ _NM_PLATFORM_KERNEL_SUPPORT_NUM,
+} NMPlatformKernelSupportType;
+
+extern volatile int _nm_platform_kernel_support_state[_NM_PLATFORM_KERNEL_SUPPORT_NUM];
+
+int _nm_platform_kernel_support_init (NMPlatformKernelSupportType type,
+ int value);
+
+#define _nm_platform_kernel_support_detected(type) \
+ G_LIKELY (({ \
+ const NMPlatformKernelSupportType _type = (type); \
+ \
+ nm_assert (_NM_INT_NOT_NEGATIVE (_type) && _type < G_N_ELEMENTS (_nm_platform_kernel_support_state)); \
+ \
+ (_nm_platform_kernel_support_state[_type] != 0); \
+ }))
+
+#define nm_platform_kernel_support_get(type) \
+ ({ \
+ const NMPlatformKernelSupportType _type = (type); \
+ int _v; \
+ \
+ nm_assert (_NM_INT_NOT_NEGATIVE (_type) && _type < G_N_ELEMENTS (_nm_platform_kernel_support_state)); \
+ \
+ _v = _nm_platform_kernel_support_state[_type]; \
+ if (G_UNLIKELY (_v == 0)) \
+ _v = _nm_platform_kernel_support_init (_type, 0); \
+ \
+ (_v >= 0); \
+ })
+
+/*****************************************************************************/
+
struct _NMPlatformPrivate;
struct _NMPlatform {
@@ -1054,9 +1093,6 @@ typedef struct {
int (*tfilter_add) (NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformTfilter *tfilter);
-
- NMPlatformKernelSupportFlags (*check_kernel_support) (NMPlatform * self,
- NMPlatformKernelSupportFlags request_flags);
} NMPlatformClass;
/* NMPlatform signals
@@ -1668,9 +1704,6 @@ void nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, N
void nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h);
void nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h);
-NMPlatformKernelSupportFlags nm_platform_check_kernel_support (NMPlatform *self,
- NMPlatformKernelSupportFlags request_flags);
-
const char *nm_platform_link_flags2str (unsigned flags, char *buf, gsize len);
const char *nm_platform_link_inet6_addrgenmode2str (guint8 mode, char *buf, gsize len);
const char *nm_platform_addr_flags2str (unsigned flags, char *buf, gsize len);
diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c
index f0e3e6cfd0..fff5967be9 100644
--- a/src/platform/tests/monitor.c
+++ b/src/platform/tests/monitor.c
@@ -77,8 +77,6 @@ main (int argc, char **argv)
nm_linux_platform_setup ();
- nm_platform_check_kernel_support (NM_PLATFORM_GET, ~((NMPlatformKernelSupportFlags) 0));
-
if (global_opt.persist)
g_main_loop_run (loop);
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 03999fede3..eb41813b2f 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -521,8 +521,7 @@ test_bridge_addr (void)
plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex);
g_assert (plink);
- if (nm_platform_check_kernel_support (NM_PLATFORM_GET,
- NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL)) {
+ if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) {
g_assert (!nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex));
g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_EUI64);