From bf36fa11d23e667de9bfe97306b4a7d752a4932d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 07:57:29 +0200 Subject: [PATCH 1/9] platform: refactor detecting kernel features Next we will need to detect more kernel features. First refactor the handling of these to require less code changes and be more efficient. A plain nm_platform_kernel_support_get() only reqiures to access an array in the common case. The other important change is that the function no longer requires a NMPlatform instance. This allows us to check kernel support from anywhere. The only thing is that we require kernel support to be initialized before calling this function. That means, an NMPlatform instance must have detected support before. (cherry picked from commit ee269b318ef7f2cedfdb2e62af89fab7218edfba) --- src/devices/nm-device.c | 21 ++-- src/nm-iface-helper.c | 6 +- src/platform/nm-fake-platform.c | 4 + src/platform/nm-linux-platform.c | 186 ++++++------------------------- src/platform/nm-platform.c | 98 ++++++++++------ src/platform/nm-platform.h | 49 ++++++-- src/platform/tests/monitor.c | 2 - src/platform/tests/test-link.c | 3 +- 8 files changed, 152 insertions(+), 217 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..0e84f99f4c 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]); @@ -4654,32 +4546,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 +5715,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 +6325,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 +8969,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..88f2b0decf 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,79 @@ 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", + }, +}; + +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; - - checked = request_flags & ~priv->support_checked; - nm_assert (checked); - - if (klass->check_kernel_support) - response = klass->check_kernel_support (self, checked); - else { - /* fake platform. Pretend no support for anything. */ - response = 0; - } - - priv->support_checked |= checked; - priv->support_present = (priv->support_present & ~checked) | (response & checked); + if (value == 0) { + set_default = TRUE; + value = _nm_platform_kernel_support_info[type].compile_time_default + ? 1 + : -1; } - return priv->support_present & request_flags; + nm_assert (NM_IN_SET (value, -1, 1)); + + 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 + + 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 "); + } + +#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 +3948,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 +4148,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; diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index fa8200e68b..d5a7a2d182 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -818,12 +818,6 @@ typedef enum { NM_PLATFORM_LINK_DUPLEX_FULL, } 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), @@ -850,6 +844,43 @@ 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_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 +1085,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 +1696,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); From 6bfce3587ef4d94ba4c228ce640425323bea60b4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 09:07:00 +0200 Subject: [PATCH 2/9] platform: detect kernel support for FRA_PROTOCOL (cherry picked from commit cd62d43963647451d2a152e2c4cbf79e243d1123) --- src/platform/nm-linux-platform.c | 7 +++++++ src/platform/nm-platform.c | 5 +++++ src/platform/nm-platform.h | 1 + 3 files changed, 13 insertions(+) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 0e84f99f4c..662f3d7046 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3414,6 +3414,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]); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 88f2b0decf..b5636d60d5 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -296,6 +296,11 @@ static const struct { .name = "RTA_PREF", .desc = "ability to set router preference for IPv6 routes", }, + [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", + }, }; int diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index d5a7a2d182..1d5b18402a 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -848,6 +848,7 @@ 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_PROTOCOL, _NM_PLATFORM_KERNEL_SUPPORT_NUM, } NMPlatformKernelSupportType; From 4127583189e92e86f09565343d808abd8235a50c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 10:23:03 +0200 Subject: [PATCH 3/9] platform: detect kernel support for FRA_IP_PROTO, FRA_SPORT_RANGE, FRA_DPORT_RANGE (cherry picked from commit 91252bb2fbfd02d712ae556ecc816146155a6f85) --- src/platform/nm-linux-platform.c | 12 ++++++++++++ src/platform/nm-platform.c | 5 +++++ src/platform/nm-platform.h | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 662f3d7046..1fc7cc3908 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3431,6 +3431,18 @@ _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); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index b5636d60d5..f16e7aec2a 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -301,6 +301,11 @@ static const struct { .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 diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 1d5b18402a..639fe5a51f 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -849,6 +849,11 @@ typedef enum { NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL, NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF, 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; From ff686dd6c1071baa8952fd59c63c72cb40895a2d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 10:43:42 +0200 Subject: [PATCH 4/9] platform: detect kernel support for FRA_UID_RANGE (cherry picked from commit 1dd1dcb81e1e96db9d02ae18c2064a397e46448a) --- src/platform/nm-linux-platform.c | 10 ++++++++++ src/platform/nm-platform.c | 5 +++++ src/platform/nm-platform.h | 1 + 3 files changed, 16 insertions(+) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1fc7cc3908..93c7b61350 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3448,6 +3448,16 @@ _new_from_nl_routing_rule (struct nlmsghdr *nlh, gboolean id_only) 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; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index f16e7aec2a..f493951559 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -296,6 +296,11 @@ static const struct { .name = "RTA_PREF", .desc = "ability to set router preference for IPv6 routes", }, + [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", diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 639fe5a51f..4feb0e21f8 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -848,6 +848,7 @@ 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_UID_RANGE, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL, /* this also includes FRA_SPORT_RANGE and FRA_DPORT_RANGE which From a9cf54c4cef58c8267ee80c7eaaa42f9227de6a7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 11:43:00 +0200 Subject: [PATCH 5/9] platform: detect kernel support for FRA_L3MDEV (cherry picked from commit eba4fd56f5fa5e03fb854fb91874496b15ebc2e4) --- src/platform/nm-linux-platform.c | 10 ++++++++++ src/platform/nm-platform.c | 5 +++++ src/platform/nm-platform.h | 1 + 3 files changed, 16 insertions(+) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 93c7b61350..d8b18a3faf 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3402,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. * diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index f493951559..922804a4b9 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -296,6 +296,11 @@ static const struct { .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", diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 4feb0e21f8..97be88324e 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -848,6 +848,7 @@ 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, From f9fe2155991c37be5a6ab7b51ff27285cfed04c1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 09:17:51 +0200 Subject: [PATCH 6/9] platform: compare routing rules according to kernel support for FRA_PROTOCOL For routes and routing rules, kernel uses a certain (not stictly defined) set of attributes to decide whether to routes/rules are identical. That is a problem, as different kernel versions disagree on whether two routes/rules are the same (EEXIST) or not. Note that when NetworkManager tries to add a rule with protocol set to anything but RTPROT_UNSPEC, then kernel will ignore the attribute if it doesn't have support for it. Meaning: the added rule will have a different protocol setting then intended. Note that NMPRulesManager will add a rule if it doesn't find it in the platform cache so far. That means, when looking into the platform cache we must ignore or honor the protocol like kernel does. This does not only affect FRA_PROTOCOL, but all attributes where kernel and NetworkManager disagrees. But the protocol is the most prominent one, because the rules tracked by nmp_rules_manager_track_default() specify the protocol. (cherry picked from commit ef4f8ccf6dc7d9ed1d02321d1e5c72ad1580ea5c) --- src/platform/nm-platform.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 922804a4b9..cb69c6fabe 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -7405,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, @@ -7435,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, @@ -7464,7 +7467,10 @@ nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj, obj->tos, obj->src_len, obj->dst_len, - obj->protocol, + ( _routing_rule_compare (cmp_type, + NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL) + ? (guint16) obj->protocol + : G_MAXUINT16), obj->ip_proto); addr_size = nm_utils_addr_family_to_size (obj->addr_family); if (cmp_full || obj->src_len > 0) @@ -7550,7 +7556,10 @@ 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); + if (_routing_rule_compare (cmp_type, + NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)) + NM_CMP_FIELD (a, b, protocol); + NM_CMP_FIELD (a, b, ip_proto); addr_size = nm_utils_addr_family_to_size (a->addr_family); From 11fd01c50eed67da04755df7f477f226d52c89f5 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 09:17:51 +0200 Subject: [PATCH 7/9] platform: compare routing rules according to kernel support for FRA_IP_PROTO ... and FRA_SPORT_RANGE and FRA_DPORT_RANGE. (cherry picked from commit 6a6d982c01a2450d5ea0d3930bcd2f39c44d809f) --- src/platform/nm-platform.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index cb69c6fabe..aaefb37984 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -7470,8 +7470,7 @@ nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj, ( _routing_rule_compare (cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL) ? (guint16) obj->protocol - : G_MAXUINT16), - obj->ip_proto); + : 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); @@ -7479,8 +7478,12 @@ nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj, 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_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; @@ -7560,7 +7563,15 @@ nm_platform_routing_rule_cmp (const NMPlatformRoutingRule *a, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)) 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_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); @@ -7577,10 +7588,6 @@ nm_platform_routing_rule_cmp (const NMPlatformRoutingRule *a, 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; From d4403913508489ae6d5124a27b87a4b5b6d90c81 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 11:04:10 +0200 Subject: [PATCH 8/9] platform: compare routing rules according to kernel support for FRA_UID_RANGE (cherry picked from commit b843c1eab8a119663116bc487b9ade40bc7f5754) --- src/platform/nm-platform.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index aaefb37984..c9b99987cb 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -7457,7 +7457,10 @@ 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 @@ -7476,8 +7479,11 @@ nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj, 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); + 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); @@ -7582,10 +7588,13 @@ 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_STR (a, b, iifname); From 062be85d82a37910ad5bdb5c33e8fe2fca929f09 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 17 Apr 2019 11:04:10 +0200 Subject: [PATCH 9/9] platform: compare routing rules according to kernel support for FRA_L3MDEV Also, in nm_platform_routing_rule_cmp() always compare the routing table field, also if l3mdev is set. For kernel, we cannot set table and l3mdev together, hence such rules don't really exist (or if we try to configure it, it will be rejected by kernel). But as far as nm_platform_routing_rule_cmp() is concerned, if the table is set, always compare it. (cherry picked from commit b6ff02e76f352cf39d7d41a715ee637f24be9da0) --- src/platform/nm-platform.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index c9b99987cb..88508c97f7 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -7463,9 +7463,12 @@ nm_platform_routing_rule_hash_update (const NMPlatformRoutingRule *obj, : 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, @@ -7540,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);