diff options
author | Thomas Haller <thaller@redhat.com> | 2019-04-18 11:18:04 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-04-18 11:19:43 +0200 |
commit | 30bb93cd9364cfb647274aa6f023dd5b741fe891 (patch) | |
tree | 384d143d407c420e006ede5f0412d7027962412d | |
parent | 73e32e43c8ca08adc3500d603eacb9133e40ed3c (diff) | |
parent | 062be85d82a37910ad5bdb5c33e8fe2fca929f09 (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.c | 21 | ||||
-rw-r--r-- | src/nm-iface-helper.c | 6 | ||||
-rw-r--r-- | src/platform/nm-fake-platform.c | 4 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 225 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 196 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 57 | ||||
-rw-r--r-- | src/platform/tests/monitor.c | 2 | ||||
-rw-r--r-- | src/platform/tests/test-link.c | 3 |
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); |