diff options
Diffstat (limited to 'src/libnm-platform')
| -rw-r--r-- | src/libnm-platform/README.md | 22 | ||||
| -rw-r--r-- | src/libnm-platform/nm-linux-platform.c | 69 | ||||
| -rw-r--r-- | src/libnm-platform/nm-netlink.c | 9 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.c | 17 | ||||
| -rw-r--r-- | src/libnm-platform/nmp-object.c | 22 | ||||
| -rw-r--r-- | src/libnm-platform/wifi/nm-wifi-utils-nl80211.c | 94 |
6 files changed, 145 insertions, 88 deletions
diff --git a/src/libnm-platform/README.md b/src/libnm-platform/README.md new file mode 100644 index 00000000..c8e7cf76 --- /dev/null +++ b/src/libnm-platform/README.md @@ -0,0 +1,22 @@ +libnm-platform +============== + +A static helper library that provides `NMPlatform` and other utils. +This is NetworkManager's internal netlink library, but also contains +helpers for sysfs, ethtool and other kernel APIs. + +`NMPlaform` is also a cache of objects of the netlink API: `NMPCache` +and `NMPObject`. These objects are used throughout NetworkManager +also for generally tracking information about these types. For example, +`NMPlatformIP4Address` (the public part of a certain type of `NMPObject`) +is not only used to track platform addresses from netlink in the cache, +but to track information about IPv4 addresses in general. + +This depends on the following helper libraries + + - [../libnm-std-aux/](../libnm-std-aux/) + - [../libnm-base/](../libnm-base/) + - [../libnm-glib-aux/](../libnm-glib-aux/) + - [../libnm-udev-aux/](../libnm-udev-aux/) + - [../libnm-log-core/](../libnm-log-core/) + - [../linux-headers/](../linux-headers/) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 9ecac2d9..5b595a9b 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -3903,6 +3903,34 @@ _new_from_nl_addr(const struct nlmsghdr *nlh, gboolean id_only) return g_steal_pointer(&obj); } +static gboolean +ip_route_is_tracked(guint8 proto, guint8 type) +{ + if (proto > RTPROT_STATIC && !NM_IN_SET(proto, RTPROT_DHCP, RTPROT_RA)) { + /* We ignore certain rtm_protocol, because NetworkManager would only ever + * configure certain protocols. Other routes are not configured by NetworkManager + * and we don't track them in the platform cache. + * + * This is to help with the performance overhead of a huge number of + * routes, for example with the bird BGP software, that adds routes + * with RTPROT_BIRD protocol. */ + return FALSE; + } + + if (!NM_IN_SET(type, + RTN_UNICAST, + RTN_LOCAL, + RTN_BLACKHOLE, + RTN_UNREACHABLE, + RTN_PROHIBIT, + RTN_THROW)) { + /* Certain route types are ignored and not placed into the cache. */ + return FALSE; + } + + return TRUE; +} + /* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */ static NMPObject * _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter *parse_nlmsg_iter) @@ -3963,6 +3991,16 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter * only handle ~supported~ routes. *****************************************************************/ + /* If it's a route that we don't need to track, abort here to avoid unnecessary + * memory allocations to create the nmp_object. However, if the message has the + * NLM_F_REPLACE flag, it might be replacing a route that we were tracking so we + * have to stop tracking it. That means that we have to process all messages with + * NLM_F_REPLACE. See nmp_cache_update_netlink_route(). + */ + if (!ip_route_is_tracked(rtm->rtm_protocol, rtm->rtm_type) + && !(nlh->nlmsg_flags & NLM_F_REPLACE)) + return NULL; + addr_family = rtm->rtm_family; if (addr_family == AF_INET) @@ -5519,39 +5557,18 @@ ip_route_get_lock_flag(const NMPlatformIPRoute *route) static gboolean ip_route_is_alive(const NMPlatformIPRoute *route) { - guint8 prot; + guint8 proto, type; nm_assert(route); nm_assert(route->rt_source >= NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC && route->rt_source <= _NM_IP_CONFIG_SOURCE_RTPROT_LAST); - prot = route->rt_source - 1; - - nm_assert(nmp_utils_ip_config_source_from_rtprot(prot) == route->rt_source); - - if (prot > RTPROT_STATIC && !NM_IN_SET(prot, RTPROT_DHCP, RTPROT_RA)) { - /* We ignore certain rtm_protocol, because NetworkManager would only ever - * configure certain protocols. Other routes are not configured by NetworkManager - * and we don't track them in the platform cache. - * - * This is to help with the performance overhead of a huge number of - * routes, for example with the bird BGP software, that adds routes - * with RTPROT_BIRD protocol. */ - return FALSE; - } + proto = route->rt_source - 1; + type = nm_platform_route_type_uncoerce(route->type_coerced); - if (!NM_IN_SET(nm_platform_route_type_uncoerce(route->type_coerced), - RTN_UNICAST, - RTN_LOCAL, - RTN_BLACKHOLE, - RTN_UNREACHABLE, - RTN_PROHIBIT, - RTN_THROW)) { - /* Certain route types are ignored and not placed into the cache. */ - return FALSE; - } + nm_assert(nmp_utils_ip_config_source_from_rtprot(proto) == route->rt_source); - return TRUE; + return ip_route_is_tracked(proto, type); } /* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */ diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index 5684b8cd..6d153128 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -4,6 +4,7 @@ */ #include "libnm-glib-aux/nm-default-glib-i18n-lib.h" +#include "libnm-glib-aux/nm-random-utils.h" #include "nm-netlink.h" @@ -1105,7 +1106,7 @@ nl_socket_new(struct nl_sock **out_sk, { nm_auto_nlsock struct nl_sock *sk = NULL; nm_auto_close int fd = -1; - time_t t; + unsigned seq_init; int err; int nmerr; socklen_t addrlen; @@ -1121,7 +1122,7 @@ nl_socket_new(struct nl_sock **out_sk, if (fd < 0) return -nm_errno_from_native(errno); - t = time(NULL); + nm_random_get_bytes(&seq_init, sizeof(seq_init)); sk = g_slice_new(struct nl_sock); *sk = (struct nl_sock){ @@ -1138,8 +1139,8 @@ nl_socket_new(struct nl_sock **out_sk, .nl_family = AF_NETLINK, .nl_groups = 0, }, - .s_seq_expect = t, - .s_seq_next = t, + .s_seq_expect = seq_init, + .s_seq_next = seq_init, .s_bufsize = 0, .s_msg_peek = !NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_DISABLE_MSG_PEEK), .s_auto_ack = TRUE, diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index b89b0359..cd5a54bb 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -6147,9 +6147,9 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) link->initialized ? " init" : " not-init", link->inet6_addr_gen_mode_inv ? " addrgenmode " : "", link->inet6_addr_gen_mode_inv ? nm_platform_link_inet6_addrgenmode2str( - _nm_platform_uint8_inv(link->inet6_addr_gen_mode_inv), - str_addrmode, - sizeof(str_addrmode)) + _nm_platform_uint8_inv(link->inet6_addr_gen_mode_inv), + str_addrmode, + sizeof(str_addrmode)) : "", str_address[0] ? " addr " : "", str_address[0] ? str_address : "", @@ -7385,11 +7385,12 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz route->lock_mtu ? "lock " : "", route->mtu) : "", - route->rt_pref ? nm_sprintf_buf( - str_pref, - " pref %s", - nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2))) - : ""); + route->rt_pref + ? nm_sprintf_buf( + str_pref, + " pref %s", + nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2))) + : ""); return buf; } diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index 4090da71..cb4e9764 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -2988,6 +2988,13 @@ nmp_cache_update_netlink_route(NMPCache *cache, * Since we don't cache all routes (see "route_is_alive"), we cannot know * with certainty which route was replaced. * + * For example, the kernel might have 3 similar routes (same WEAK_ID), one + * of which is not tracked by us so we don't have it into the cache. If we + * receive a route replace message, we don't know to what of the 3 routes + * it affects (one of the 3 we don't even know that exists). Moreover, if + * we only have one route on cache, we don't know if the replace is for a + * different one that we don't track. + * * Even if we would cache *all* routes (which we cannot, if kernel adds new * routing features that modify the known nmp_object_id_equal()), it would * be hard to find the right route that was replaced. Well, probably we @@ -3002,15 +3009,14 @@ nmp_cache_update_netlink_route(NMPCache *cache, * [2] https://bugzilla.redhat.com/show_bug.cgi?id=1337860 * * We need to resync. + * + * However, a resync is expensive. Think of a routing daemon that updates + * hundreds of routes per second, the performance penalty is huge. We can + * optimize it: if we don't have any matching route on cache (by WEAK_ID), + * we don't have anything to replace and we don't need a full resync, but + * only to add or discard the new route as usual. */ - if (NMP_OBJECT_GET_TYPE(obj_hand_over) == NMP_OBJECT_TYPE_IP4_ROUTE - && !nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, obj_hand_over)) { - /* For IPv4, we can do a small optimization. We skip the resync, if we have - * no conflicting routes (by weak-id). - * - * This optimization does not work for IPv6 (maybe should be fixed). - */ - } else { + if (nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, obj_hand_over)) { entry_replace = NULL; resync_required = TRUE; goto out; diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index 6109849a..3c00898a 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c @@ -567,6 +567,7 @@ struct nl80211_device_info { int phy; Nl80211Freq *freqs; int num_freqs; + int num_freqs_alloc; guint32 freq; guint32 caps; gboolean can_scan; @@ -610,7 +611,6 @@ nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg) struct nlattr *nl_freq; int rem_freq; int rem_band; - guint num_alloc; #ifdef NL80211_FREQUENCY_ATTR_NO_IR G_STATIC_ASSERT_EXPR(NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR @@ -622,22 +622,16 @@ nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg) if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0) return NL_SKIP; - if (tb[NL80211_ATTR_WIPHY] == NULL || tb[NL80211_ATTR_WIPHY_BANDS] == NULL) + if (!tb[NL80211_ATTR_WIPHY]) return NL_SKIP; info->phy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); if (tb[NL80211_ATTR_WIPHY_FREQ]) info->freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - else - info->freq = 0; - if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) { + if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) info->can_scan_ssid = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) > 0; - } else { - /* old kernel that only had mac80211, so assume it can */ - info->can_scan_ssid = TRUE; - } if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { struct nlattr *nl_cmd; @@ -664,51 +658,57 @@ nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg) } } - /* Read supported frequencies */ - num_alloc = 32; - info->num_freqs = 0; - info->freqs = g_new(Nl80211Freq, num_alloc); + if (tb[NL80211_ATTR_WIPHY_BANDS]) { + /* Read supported frequencies */ - nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0) - return NL_SKIP; + if (!info->freqs) { + info->num_freqs = 0; + info->num_freqs_alloc = 32; + info->freqs = g_new(Nl80211Freq, info->num_freqs_alloc); + } - nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - Nl80211Freq *f; + nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { + if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0) + return NL_SKIP; - if (nla_parse_nested_arr(tb_freq, nl_freq, freq_policy) < 0) + if (!tb_band[NL80211_BAND_ATTR_FREQS]) continue; - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; + nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { + Nl80211Freq *f; - if (info->num_freqs >= num_alloc) { - num_alloc *= 2; - info->freqs = g_renew(Nl80211Freq, info->freqs, num_alloc); - } + if (nla_parse_nested_arr(tb_freq, nl_freq, freq_policy) < 0) + continue; + + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; - f = &info->freqs[info->num_freqs]; - *f = (Nl80211Freq){ - .freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]), - .disabled = !!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED], - .no_ir = !!tb_freq[NL80211_FREQUENCY_ATTR_NO_IR], - }; + if (info->num_freqs >= info->num_freqs_alloc) { + info->num_freqs_alloc *= 2; + info->freqs = g_renew(Nl80211Freq, info->freqs, info->num_freqs_alloc); + } - info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_VALID; + f = &info->freqs[info->num_freqs]; + *f = (Nl80211Freq){ + .freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]), + .disabled = !!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED], + .no_ir = !!tb_freq[NL80211_FREQUENCY_ATTR_NO_IR], + }; - if (f->freq >= 2401 && f->freq <= 2495) - info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_2GHZ; - if (f->freq >= 5150 && f->freq <= 5895) - info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_5GHZ; - if (f->freq >= 5925 && f->freq <= 7125) - info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_6GHZ; + info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_VALID; - info->num_freqs++; + if (f->freq >= 2401 && f->freq <= 2495) + info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_2GHZ; + if (f->freq >= 5150 && f->freq < 5950) + info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_5GHZ; + if (f->freq >= 5950 && f->freq <= 7125) + info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_6GHZ; + + info->num_freqs++; + } } } - info->freqs = g_renew(Nl80211Freq, info->freqs, info->num_freqs); - /* Read security/encryption support */ if (tb[NL80211_ATTR_CIPHER_SUITES]) { guint32 *ciphers = nla_data(tb[NL80211_ATTR_CIPHER_SUITES]); @@ -874,7 +874,10 @@ nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifin self->phy = -1; - msg = nl80211_alloc_msg(self, NL80211_CMD_GET_WIPHY, 0); + msg = nl80211_alloc_msg(self, NL80211_CMD_GET_WIPHY, NLM_F_DUMP); + NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); + + device_info.can_scan_ssid = TRUE; device_info.self = self; if (nl80211_send_and_recv(self, msg, nl80211_wiphy_info_handler, &device_info) < 0) { @@ -882,6 +885,10 @@ nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifin return NULL; } + if (device_info.freqs) { + device_info.freqs = g_renew(Nl80211Freq, device_info.freqs, device_info.num_freqs); + } + if (!device_info.success) { _LOGD("NL80211_CMD_GET_WIPHY request indicated failure"); return NULL; @@ -915,4 +922,7 @@ nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifin _LOGD("using nl80211 for Wi-Fi device control"); return (NMWifiUtils *) g_steal_pointer(&self); + +nla_put_failure: + g_return_val_if_reached(NULL); } |