From 9ef02ef7d0e8252a656650bc1426caafec6d906f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 13 Jul 2022 12:02:40 +0200 Subject: [PATCH 01/13] platform/netlink: ensure padding is zero in _nest_end() nla_reserve() also ensures that the padding is zero, and only the padding. Thus, when we call nla_reserve(), we need to zero the padding ourselves. --- src/libnm-platform/nm-netlink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index 77fffc0bff..f6b1d8b883 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -584,14 +584,18 @@ _nest_end(struct nl_msg *msg, struct nlattr *start, int keep_empty) pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; if (pad > 0) { + void *p; + /* * Data inside attribute does not end at a alignment boundary. * Pad accordingly and account for the additional space in * the message. nlmsg_reserve() may never fail in this situation, * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. */ - if (!nlmsg_reserve(msg, pad, 0)) + p = nlmsg_reserve(msg, pad, 0); + if (!p) g_return_val_if_reached(-NME_BUG); + memset(p, 0, pad); } return 0; From 3b58404712425093b40d36fe52cd6935d8bb94f6 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 7 Jul 2022 12:55:50 +0200 Subject: [PATCH 02/13] platform: add NMPGenlFamilyType enum for generic netlink types The genl types that we care about are well known. Add an enum for them, so we can do a lookup by index. To kernel, the corresponding names (like "wireguard") are also well known. However, the family-id, that we need when using genl are allocated dynamically. So we need to lookup the family-id, and by having an enum for the genl type, we can do so generically. --- .../platform/tests/test-platform-general.c | 60 ++++++++++++++++ src/libnm-platform/nm-platform.c | 70 +++++++++++++++++++ src/libnm-platform/nm-platform.h | 19 +++++ 3 files changed, 149 insertions(+) diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index 908ad4dd3e..c18886c96e 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -788,6 +788,64 @@ test_route_type_is_nodev(void) /*****************************************************************************/ +static void +test_nmp_genl_family_type_from_name(void) +{ + int n_run; + int i; + + for (i = 0; i < (int) _NMP_GENL_FAMILY_TYPE_NUM; i++) { + const char *name = nmp_genl_family_infos[i].name; + + g_assert(name); + if (i > 0) + g_assert_cmpint(strcmp(nmp_genl_family_infos[i - 1].name, name), <, 0); + } + + g_assert_cmpint(nmp_genl_family_type_from_name("ethtool"), ==, NMP_GENL_FAMILY_TYPE_ETHTOOL); + g_assert_cmpint(nmp_genl_family_type_from_name("mptcp_pm"), ==, NMP_GENL_FAMILY_TYPE_MPTCP_PM); + g_assert_cmpint(nmp_genl_family_type_from_name("nl80211"), ==, NMP_GENL_FAMILY_TYPE_NL80211); + g_assert_cmpint(nmp_genl_family_type_from_name("nl802154"), ==, NMP_GENL_FAMILY_TYPE_NL802154); + g_assert_cmpint(nmp_genl_family_type_from_name("wireguard"), + ==, + NMP_GENL_FAMILY_TYPE_WIREGUARD); + + g_assert_cmpint(nmp_genl_family_type_from_name(NULL), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("a"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("wireguara"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("wireguarb"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name(""), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("z"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + + for (n_run = 0; n_run < 20; n_run++) { + for (i = 0; i < (int) _NMP_GENL_FAMILY_TYPE_NUM; i++) { + const char *cname = nmp_genl_family_infos[i].name; + const int ch_idx = nmtst_get_rand_uint() % strlen(cname); + char name[200]; + char ch; + gsize l; + + l = g_strlcpy(name, cname, sizeof(name)); + g_assert_cmpint(l, <, sizeof(name)); + + if (n_run == 0) { + g_assert_cmpint(nmp_genl_family_type_from_name(cname), ==, i); + g_assert_cmpint(nmp_genl_family_type_from_name(name), ==, i); + } + + /* randomly change one character in the name. Such a name becomes invalid. + * There are no two valid names which only differ by one characters. */ + do { + ch = nmtst_get_rand_uint() % 256; + } while (cname[ch_idx] == ch); + name[ch_idx] = ch; + g_assert_cmpint(nmp_genl_family_type_from_name(name), ==, _NMP_GENL_FAMILY_TYPE_NONE); + } + } +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -808,6 +866,8 @@ main(int argc, char **argv) GINT_TO_POINTER(2), test_platform_ip_address_pretty_sort_cmp); g_test_add_func("/general/test_route_type_is_nodev", test_route_type_is_nodev); + g_test_add_func("/nm-platform/test_nmp_genl_family_type_from_name", + test_nmp_genl_family_type_from_name); return g_test_run(); } diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 50204abc5f..ab21f3f289 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -395,6 +395,76 @@ _nm_platform_kernel_support_init(NMPlatformKernelSupportType type, int value) /*****************************************************************************/ +const NMPGenlFamilyInfo nmp_genl_family_infos[_NMP_GENL_FAMILY_TYPE_NUM] = { + [NMP_GENL_FAMILY_TYPE_ETHTOOL] = + { + .name = "ethtool", + }, + [NMP_GENL_FAMILY_TYPE_MPTCP_PM] = + { + .name = "mptcp_pm", + }, + [NMP_GENL_FAMILY_TYPE_NL80211] = + { + .name = "nl80211", + }, + [NMP_GENL_FAMILY_TYPE_NL802154] = + { + .name = "nl802154", + }, + [NMP_GENL_FAMILY_TYPE_WIREGUARD] = + { + .name = "wireguard", + }, +}; + +NMPGenlFamilyType +nmp_genl_family_type_from_name(const char *name) +{ + int imin, imax, imid; + + if (NM_MORE_ASSERT_ONCE(50)) { + int i; + + for (i = 0; i < (int) G_N_ELEMENTS(nmp_genl_family_infos); i++) { + nm_assert(nmp_genl_family_infos[i].name); + if (i > 0) + nm_assert(strcmp(nmp_genl_family_infos[i - 1].name, nmp_genl_family_infos[i].name) + < 0); + } + } + + if (!name) + goto out; + + imin = 0; + imax = G_N_ELEMENTS(nmp_genl_family_infos) - 1; + imid = imax / 2; + + while (TRUE) { + int c; + + c = strcmp(nmp_genl_family_infos[imid].name, name); + if (c == 0) + return (NMPGenlFamilyType) imid; + + if (c < 0) + imin = imid + 1; + else + imax = imid - 1; + + if (imin > imax) + break; + + imid = (imax + imin) / 2; + } + +out: + return _NMP_GENL_FAMILY_TYPE_NONE; +} + +/*****************************************************************************/ + /** * nm_platform_process_events: * @self: platform instance diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index b921a2f562..e940f43b60 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -1103,6 +1103,25 @@ nm_platform_kernel_support_get(NMPlatformKernelSupportType type) return nm_platform_kernel_support_get_full(type, TRUE) != NM_OPTION_BOOL_FALSE; } +typedef enum { + NMP_GENL_FAMILY_TYPE_ETHTOOL, + NMP_GENL_FAMILY_TYPE_MPTCP_PM, + NMP_GENL_FAMILY_TYPE_NL80211, + NMP_GENL_FAMILY_TYPE_NL802154, + NMP_GENL_FAMILY_TYPE_WIREGUARD, + + _NMP_GENL_FAMILY_TYPE_NUM, + _NMP_GENL_FAMILY_TYPE_NONE = _NMP_GENL_FAMILY_TYPE_NUM, +} NMPGenlFamilyType; + +typedef struct { + const char *name; +} NMPGenlFamilyInfo; + +extern const NMPGenlFamilyInfo nmp_genl_family_infos[_NMP_GENL_FAMILY_TYPE_NUM]; + +NMPGenlFamilyType nmp_genl_family_type_from_name(const char *name); + /*****************************************************************************/ struct _NMPlatformPrivate; From baecadbe9862119b6dd2ad39839b44b97d5a805f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 7 Jul 2022 13:31:51 +0200 Subject: [PATCH 03/13] platform: rename RefreshAllInfo.addr_family to "addr_family_for_dump" The term "addr_family" is used very frequently, and it usually is an auto variable or a function parameter. It is interesting to search where this field is used. So rename to give it a unique (and better fitting) name. While at it, use gint8 to encode the addr_family. It's always sufficient, and this reduces the size of RefreshAllInfo from 8 bytes to two. --- src/libnm-platform/nm-linux-platform.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 6b39375136..d12d92d4a9 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -318,8 +318,9 @@ typedef enum { typedef struct { NMPObjectType obj_type; - /* for NLM_F_DUMP, which address family to request. */ - int addr_family; + /* For NLM_F_DUMP, which address family to request. + * Either AF_UNSPEC, AF_INET or AF_INET6. */ + gint8 addr_family_for_dump; } RefreshAllInfo; typedef enum { @@ -5799,8 +5800,8 @@ refresh_all_type_get_info(RefreshAllType refresh_all_type) static const RefreshAllInfo infos[] = { #define R(_refresh_all_type, _obj_type, _addr_family) \ [_refresh_all_type] = { \ - .obj_type = _obj_type, \ - .addr_family = _addr_family, \ + .obj_type = _obj_type, \ + .addr_family_for_dump = _addr_family, \ } R(REFRESH_ALL_TYPE_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), R(REFRESH_ALL_TYPE_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), @@ -5902,11 +5903,11 @@ refresh_all_type_init_lookup(RefreshAllType refresh_all_type, NMPLookup *lookup) if (NM_IN_SET(refresh_all_info->obj_type, NMP_OBJECT_TYPE_ROUTING_RULE)) { return nmp_lookup_init_object_by_addr_family(lookup, refresh_all_info->obj_type, - refresh_all_info->addr_family); + refresh_all_info->addr_family_for_dump); } /* not yet implemented. */ - nm_assert(refresh_all_info->addr_family == AF_UNSPEC); + nm_assert(refresh_all_info->addr_family_for_dump == AF_UNSPEC); return nmp_lookup_init_obj_type(lookup, refresh_all_info->obj_type); } @@ -6927,7 +6928,8 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action event_handler_read_netlink(platform, FALSE); - nlmsg = _nl_msg_new_dump(refresh_all_info->obj_type, refresh_all_info->addr_family); + nlmsg = + _nl_msg_new_dump(refresh_all_info->obj_type, refresh_all_info->addr_family_for_dump); if (!nlmsg) goto next_after_fail; From 6ff6c1dfc142e1893f8db73d79a62e436eb90761 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 7 Jul 2022 22:37:31 +0200 Subject: [PATCH 04/13] platform: tighter pack structs and enums Reorder fields in DelayedActionWaitForNlResponseData, so that the struct size is optimal due to the alignment constraints. Also, when we remember enum values and embed them somewhere, it's nice if they only take the space actually needed. _nm_packed solves that. --- src/libnm-platform/nm-linux-platform.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index d12d92d4a9..49873dae6c 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -323,7 +323,7 @@ typedef struct { gint8 addr_family_for_dump; } RefreshAllInfo; -typedef enum { +typedef enum _nm_packed { DELAYED_ACTION_TYPE_NONE = 0, #define F(val, name) ((sizeof(char[(((val)) == (name)) ? 1 : -1]) * 0) + (val)) @@ -378,7 +378,7 @@ typedef enum { }); \ (iflags) <<= 1) -typedef enum { +typedef enum _nm_packed { /* Negative values are errors from kernel. Add dummy member to * make enum signed. */ _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = G_MININT, @@ -393,24 +393,24 @@ typedef enum { WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS, } WaitForNlResponseResult; -typedef enum { +typedef enum _nm_packed { DELAYED_ACTION_RESPONSE_TYPE_VOID = 0, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS = 1, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET = 2, } DelayedActionWaitForNlResponseType; typedef struct { - guint32 seq_number; - WaitForNlResponseResult seq_result; - DelayedActionWaitForNlResponseType response_type; - gint64 timeout_abs_nsec; - WaitForNlResponseResult *out_seq_result; - char **out_errmsg; + WaitForNlResponseResult *out_seq_result; + char **out_errmsg; union { int *out_refresh_all_in_progress; NMPObject **out_route_get; gpointer out_data; } response; + gint64 timeout_abs_nsec; + guint32 seq_number; + WaitForNlResponseResult seq_result; + DelayedActionWaitForNlResponseType response_type; } DelayedActionWaitForNlResponseData; /*****************************************************************************/ From a27e9b21cfca03fc051f2e572128d82a36f31524 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 7 Jul 2022 13:44:09 +0200 Subject: [PATCH 05/13] platform: rename rtnetlink specific enum values to be clearly about rtnl We will have similar names which are about generic netlink. Rename to be clear. --- src/libnm-platform/nm-linux-platform.c | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 49873dae6c..3b9b96b677 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -342,7 +342,7 @@ typedef enum _nm_packed { DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9, DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10, - DELAYED_ACTION_TYPE_READ_NETLINK = 1 << 11, + DELAYED_ACTION_TYPE_READ_RTNL = 1 << 11, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = 1 << 12, __DELAYED_ACTION_TYPE_MAX, @@ -351,7 +351,7 @@ typedef enum _nm_packed { DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - DELAYED_ACTION_TYPE_REFRESH_ALL = + DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES @@ -5938,10 +5938,10 @@ static NM_UTILS_LOOKUP_STR_DEFINE( NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_RTNL, "read-rtnl"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_NONE), - NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL), + NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL), NM_UTILS_LOOKUP_ITEM_IGNORE(__DELAYED_ACTION_TYPE_MAX), ); @@ -6013,8 +6013,8 @@ delayed_action_refresh_all_in_progress(NMPlatform *platform, DelayedActionType a RefreshAllType refresh_all_type; nm_assert(nm_utils_is_power_of_two(action_type)); - nm_assert(NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_ALL)); - nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); + nm_assert(NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)); + nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)); if (NM_FLAGS_ANY(priv->delayed_action.flags, action_type)) return TRUE; @@ -6200,19 +6200,19 @@ delayed_action_handle_one(NMPlatform *platform) /* Next we prefer read-netlink, because the buffer size is limited and we want to process events * from netlink early. */ - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_READ_NETLINK)) { - _LOGt_delayed_action(DELAYED_ACTION_TYPE_READ_NETLINK, NULL, "handle"); - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_READ_NETLINK; + if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_READ_RTNL)) { + _LOGt_delayed_action(DELAYED_ACTION_TYPE_READ_RTNL, NULL, "handle"); + priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_READ_RTNL; delayed_action_handle_READ_NETLINK(platform); return TRUE; } - if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_ALL)) { + if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)) { DelayedActionType flags, iflags; - flags = priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_ALL; + flags = priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL; - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL; + priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL; if (_LOGt_ENABLED()) { FOR_EACH_DELAYED_ACTION (iflags, flags) @@ -6263,7 +6263,7 @@ delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink) priv->delayed_action.is_handling++; if (read_netlink) - delayed_action_schedule(platform, DELAYED_ACTION_TYPE_READ_NETLINK, NULL); + delayed_action_schedule(platform, DELAYED_ACTION_TYPE_READ_RTNL, NULL); while (delayed_action_handle_one(platform)) any = TRUE; priv->delayed_action.is_handling--; @@ -6870,8 +6870,8 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action DelayedActionType action_type_prune; DelayedActionType iflags; - nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); - action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL; + nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)); + action_type &= DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL; action_type_prune = action_type; From 8d42b5c52a19e08d3a8f600d1e5becd229f97d9a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 7 Jul 2022 14:52:38 +0200 Subject: [PATCH 06/13] platform: add delayed_action_schedule_refresh_all() helper and avoid refreshing tc cache If nm_platform_get_cache_tc() is disabled, there is no need to refresh it. Filter those flags out. Also, don't duplicate the code and add a helper function delayed_action_schedule_refresh_all(). --- src/libnm-platform/nm-linux-platform.c | 46 ++++++++++++++------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 3b9b96b677..e77945eba3 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -6317,6 +6317,24 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo } } +static void +delayed_action_schedule_refresh_all(NMPlatform *platform) +{ + DelayedActionType action_type; + + action_type = + DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL; + if (nm_platform_get_cache_tc(platform)) { + action_type |= + (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS); + } + + delayed_action_schedule(platform, action_type, NULL); +} + static void delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform *platform, guint32 seq_number, @@ -6476,8 +6494,10 @@ cache_on_change(NMPlatform *platform, | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, + | (nm_platform_get_cache_tc(platform) + ? (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS) + : DELAYED_ACTION_TYPE_NONE), NULL); } } @@ -9512,17 +9532,7 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) delayed_action_wait_for_nl_response_complete_all( platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); - - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); + delayed_action_schedule_refresh_all(platform); break; default: _LOGE("netlink: read: failed to retrieve incoming events: %s (%d)", @@ -9818,15 +9828,7 @@ constructed(GObject *_object) G_OBJECT_CLASS(nm_linux_platform_parent_class)->constructed(_object); _LOGD("populate platform cache"); - delayed_action_schedule( - platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); + delayed_action_schedule_refresh_all(platform); delayed_action_handle_all(platform, FALSE); From d83bd8c6a06c6970a4c7e0c1784921be2e30389f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 12 Jul 2022 10:59:49 +0200 Subject: [PATCH 07/13] platform: rename DELAYED_ACTION_TYPE_REFRESH_ALL_* enums to "all-rtnl" We'll also have generic netlink things. Rename. --- src/libnm-platform/nm-linux-platform.c | 306 +++++++++++++------------ 1 file changed, 160 insertions(+), 146 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index e77945eba3..05217528f6 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -302,15 +302,15 @@ typedef struct { typedef enum { _REFRESH_ALL_TYPE_FIRST = 0, - REFRESH_ALL_TYPE_LINKS = 0, - REFRESH_ALL_TYPE_IP4_ADDRESSES = 1, - REFRESH_ALL_TYPE_IP6_ADDRESSES = 2, - REFRESH_ALL_TYPE_IP4_ROUTES = 3, - REFRESH_ALL_TYPE_IP6_ROUTES = 4, - REFRESH_ALL_TYPE_ROUTING_RULES_IP4 = 5, - REFRESH_ALL_TYPE_ROUTING_RULES_IP6 = 6, - REFRESH_ALL_TYPE_QDISCS = 7, - REFRESH_ALL_TYPE_TFILTERS = 8, + REFRESH_ALL_TYPE_RTNL_LINKS = 0, + REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES = 1, + REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES = 2, + REFRESH_ALL_TYPE_RTNL_IP4_ROUTES = 3, + REFRESH_ALL_TYPE_RTNL_IP6_ROUTES = 4, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4 = 5, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6 = 6, + REFRESH_ALL_TYPE_RTNL_QDISCS = 7, + REFRESH_ALL_TYPE_RTNL_TFILTERS = 8, _REFRESH_ALL_TYPE_NUM, } RefreshAllType; @@ -327,36 +327,40 @@ typedef enum _nm_packed { DELAYED_ACTION_TYPE_NONE = 0, #define F(val, name) ((sizeof(char[(((val)) == (name)) ? 1 : -1]) * 0) + (val)) - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = 1 << F(0, REFRESH_ALL_TYPE_LINKS), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = 1 << F(1, REFRESH_ALL_TYPE_IP4_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = 1 << F(2, REFRESH_ALL_TYPE_IP6_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = 1 << F(3, REFRESH_ALL_TYPE_IP4_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = 1 << F(4, REFRESH_ALL_TYPE_IP6_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 = 1 - << F(5, REFRESH_ALL_TYPE_ROUTING_RULES_IP4), - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 = 1 - << F(6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6), - DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = 1 << F(7, REFRESH_ALL_TYPE_QDISCS), - DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = 1 << F(8, REFRESH_ALL_TYPE_TFILTERS), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS = 1 << F(0, REFRESH_ALL_TYPE_RTNL_LINKS), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES = + 1 << F(1, REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES = + 1 << F(2, REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES = 1 << F(3, REFRESH_ALL_TYPE_RTNL_IP4_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES = 1 << F(4, REFRESH_ALL_TYPE_RTNL_IP6_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4 = + 1 << F(5, REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6 = + 1 << F(6, REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS = 1 << F(7, REFRESH_ALL_TYPE_RTNL_QDISCS), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS = 1 << F(8, REFRESH_ALL_TYPE_RTNL_TFILTERS), #undef F - DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9, - DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10, - DELAYED_ACTION_TYPE_READ_RTNL = 1 << 11, - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = 1 << 12, + DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9, + DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10, + DELAYED_ACTION_TYPE_READ_RTNL = 1 << 11, + DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL = 1 << 12, __DELAYED_ACTION_TYPE_MAX, - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL = - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL = + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4 + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6, - DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL = - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, + DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX - 1, } DelayedActionType; @@ -420,7 +424,7 @@ typedef struct { struct nl_sock *sk_rtnl; - GSource *rtnl_event_source; + GSource *event_source_rtnl; guint32 nlh_seq_next; #if NM_MORE_LOGGING @@ -447,7 +451,7 @@ typedef struct { GPtrArray *list_master_connected; GPtrArray *list_refresh_link; - GArray *list_wait_for_nl_response; + GArray *list_wait_for_response_rtnl; int is_handling; } delayed_action; @@ -5803,15 +5807,15 @@ refresh_all_type_get_info(RefreshAllType refresh_all_type) .obj_type = _obj_type, \ .addr_family_for_dump = _addr_family, \ } - R(REFRESH_ALL_TYPE_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), - R(REFRESH_ALL_TYPE_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), - R(REFRESH_ALL_TYPE_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), - R(REFRESH_ALL_TYPE_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), + R(REFRESH_ALL_TYPE_RTNL_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), + R(REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), + R(REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), + R(REFRESH_ALL_TYPE_RTNL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), + R(REFRESH_ALL_TYPE_RTNL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), + R(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), + R(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), + R(REFRESH_ALL_TYPE_RTNL_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), + R(REFRESH_ALL_TYPE_RTNL_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), #undef R }; @@ -5827,19 +5831,22 @@ static NM_UTILS_LOOKUP_DEFINE( DelayedActionType, RefreshAllType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(0), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, REFRESH_ALL_TYPE_LINKS), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, - REFRESH_ALL_TYPE_IP4_ADDRESSES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, - REFRESH_ALL_TYPE_IP6_ADDRESSES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, REFRESH_ALL_TYPE_IP4_ROUTES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, REFRESH_ALL_TYPE_IP6_ROUTES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, - REFRESH_ALL_TYPE_ROUTING_RULES_IP4), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - REFRESH_ALL_TYPE_ROUTING_RULES_IP6), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, REFRESH_ALL_TYPE_QDISCS), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, REFRESH_ALL_TYPE_TFILTERS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS, REFRESH_ALL_TYPE_RTNL_LINKS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES, + REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES, + REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES, + REFRESH_ALL_TYPE_RTNL_IP4_ROUTES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, + REFRESH_ALL_TYPE_RTNL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS, REFRESH_ALL_TYPE_RTNL_QDISCS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, + REFRESH_ALL_TYPE_RTNL_TFILTERS), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER(), ); static DelayedActionType @@ -5861,25 +5868,25 @@ refresh_all_type_from_needle_object(const NMPObject *obj_needle) { switch (NMP_OBJECT_GET_TYPE(obj_needle)) { case NMP_OBJECT_TYPE_LINK: - return REFRESH_ALL_TYPE_LINKS; + return REFRESH_ALL_TYPE_RTNL_LINKS; case NMP_OBJECT_TYPE_IP4_ADDRESS: - return REFRESH_ALL_TYPE_IP4_ADDRESSES; + return REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES; case NMP_OBJECT_TYPE_IP6_ADDRESS: - return REFRESH_ALL_TYPE_IP6_ADDRESSES; + return REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES; case NMP_OBJECT_TYPE_IP4_ROUTE: - return REFRESH_ALL_TYPE_IP4_ROUTES; + return REFRESH_ALL_TYPE_RTNL_IP4_ROUTES; case NMP_OBJECT_TYPE_IP6_ROUTE: - return REFRESH_ALL_TYPE_IP6_ROUTES; + return REFRESH_ALL_TYPE_RTNL_IP6_ROUTES; case NMP_OBJECT_TYPE_QDISC: - return REFRESH_ALL_TYPE_QDISCS; + return REFRESH_ALL_TYPE_RTNL_QDISCS; case NMP_OBJECT_TYPE_TFILTER: - return REFRESH_ALL_TYPE_TFILTERS; + return REFRESH_ALL_TYPE_RTNL_TFILTERS; case NMP_OBJECT_TYPE_ROUTING_RULE: switch (NMP_OBJECT_CAST_ROUTING_RULE(obj_needle)->addr_family) { case AF_INET: - return REFRESH_ALL_TYPE_ROUTING_RULES_IP4; + return REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4; case AF_INET6: - return REFRESH_ALL_TYPE_ROUTING_RULES_IP6; + return REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6; } nm_assert_not_reached(); return 0; @@ -5923,26 +5930,30 @@ static NM_UTILS_LOOKUP_STR_DEFINE( delayed_action_to_string, DelayedActionType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, - "refresh-all-ip4-addresses"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, - "refresh-all-ip6-addresses"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, - "refresh-all-routing-rules-ip4"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - "refresh-all-routing-rules-ip6"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS, "refresh-all-rtnl-links"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES, + "refresh-all-rtnl-ip4-addresses"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES, + "refresh-all-rtnl-ip6-addresses"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES, + "refresh-all-rtnl-ip4-routes"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, + "refresh-all-rtnl-ip6-routes"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4, + "refresh-all-rtnl-routing-rules-ip4"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6, + "refresh-all-rtnl-routing-rules-ip6"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS, + "refresh-all-rtnl-qdiscs"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, + "refresh-all-rtnl-tfilters"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_RTNL, "read-rtnl"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, "wait-for-response-rtnl"), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_NONE), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL), - NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL), + NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL), NM_UTILS_LOOKUP_ITEM_IGNORE(__DELAYED_ACTION_TYPE_MAX), ); static const char * @@ -5962,7 +5973,7 @@ delayed_action_to_string_full(DelayedActionType action_type, case DELAYED_ACTION_TYPE_REFRESH_LINK: nm_strbuf_append(&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT(user_data)); break; - case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE: + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL: data = user_data; if (data) { @@ -6031,18 +6042,18 @@ delayed_action_wait_for_nl_response_complete(NMPlatform *platform, NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); DelayedActionWaitForNlResponseData *data; - nm_assert(NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); - nm_assert(idx < priv->delayed_action.list_wait_for_nl_response->len); + nm_assert(NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)); + nm_assert(idx < priv->delayed_action.list_wait_for_response_rtnl->len); nm_assert(seq_result); - data = &g_array_index(priv->delayed_action.list_wait_for_nl_response, + data = &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, DelayedActionWaitForNlResponseData, idx); - _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, data, "complete"); + _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, data, "complete"); - if (priv->delayed_action.list_wait_for_nl_response->len <= 1) - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE; + if (priv->delayed_action.list_wait_for_response_rtnl->len <= 1) + priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL; if (data->out_seq_result) *data->out_seq_result = seq_result; switch (data->response_type) { @@ -6063,7 +6074,7 @@ delayed_action_wait_for_nl_response_complete(NMPlatform *platform, break; } - g_array_remove_index_fast(priv->delayed_action.list_wait_for_nl_response, idx); + g_array_remove_index_fast(priv->delayed_action.list_wait_for_response_rtnl, idx); } static void @@ -6079,9 +6090,9 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf gint64 next_timeout_abs_ns = 0; gint64 now_nsec = 0; - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len;) { + for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len;) { const DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_nl_response, + &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, DelayedActionWaitForNlResponseData, i); @@ -6108,8 +6119,8 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) { nm_assert( - !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); - nm_assert(priv->delayed_action.list_wait_for_nl_response->len == 0); + !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)); + nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len == 0); } NM_SET_OUT(out_next_seq_number, next_seq_number); @@ -6243,9 +6254,9 @@ delayed_action_handle_one(NMPlatform *platform) return TRUE; } - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); - _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, NULL, "handle"); + if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { + nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); + _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, NULL, "handle"); delayed_action_handle_WAIT_FOR_NL_RESPONSE(platform); return TRUE; } @@ -6298,14 +6309,14 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo < 0) g_ptr_array_add(priv->delayed_action.list_master_connected, user_data); break; - case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE: - g_array_append_vals(priv->delayed_action.list_wait_for_nl_response, user_data, 1); + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL: + g_array_append_vals(priv->delayed_action.list_wait_for_response_rtnl, user_data, 1); break; default: nm_assert(!user_data); nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_REFRESH_LINK)); nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_MASTER_CONNECTED)); - nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); + nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)); break; } @@ -6322,14 +6333,15 @@ delayed_action_schedule_refresh_all(NMPlatform *platform) { DelayedActionType action_type; - action_type = - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL; + action_type = DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL; if (nm_platform_get_cache_tc(platform)) { - action_type |= - (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS); + action_type |= (DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS); } delayed_action_schedule(platform, action_type, NULL); @@ -6353,7 +6365,7 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform * .response.out_data = response_out_data, }; - delayed_action_schedule(platform, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, &data); + delayed_action_schedule(platform, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, &data); } /*****************************************************************************/ @@ -6488,17 +6500,18 @@ cache_on_change(NMPlatform *platform, ifindex = obj_new->link.ifindex; if (ifindex > 0) { - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | (nm_platform_get_cache_tc(platform) - ? (DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS) - : DELAYED_ACTION_TYPE_NONE), - NULL); + delayed_action_schedule( + platform, + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL + | (nm_platform_get_cache_tc(platform) + ? (DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS) + : DELAYED_ACTION_TYPE_NONE), + NULL); } } { @@ -6546,8 +6559,8 @@ cache_on_change(NMPlatform *platform, * think kernel does send RTM_DELROUTE events for IPv6 routes, so * we might not need to refresh IPv6 routes. */ delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, NULL); } } @@ -6655,8 +6668,8 @@ cache_on_change(NMPlatform *platform, if (cache_op == NMP_CACHE_OPS_REMOVED) { delayed_action_schedule(platform, (klass->obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS) - ? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - : DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + ? DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + : DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, NULL); } } break; @@ -6804,7 +6817,7 @@ do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char entry = nmp_cache_lookup_entry_link(nm_platform_get_cache(platform), ifindex); if (entry) { - priv->pruning[REFRESH_ALL_TYPE_LINKS] += 1; + priv->pruning[REFRESH_ALL_TYPE_RTNL_LINKS] += 1; nm_dedup_multi_entry_set_dirty(entry, TRUE); } } @@ -6899,14 +6912,14 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action * cache lookup for every entry. * * Avoid that, by special casing routing-rules here. */ - if (NM_FLAGS_ALL(action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL)) { + if (NM_FLAGS_ALL(action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL)) { NMPLookup lookup; - priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP4] += 1; - priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP6] += 1; + priv->pruning[REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4] += 1; + priv->pruning[REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6] += 1; nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup); - action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL; + action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL; } FOR_EACH_DELAYED_ACTION (iflags, action_type_prune) { @@ -6933,7 +6946,7 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action priv->delayed_action.flags &= ~iflags; _LOGt_delayed_action(iflags, NULL, "handle (do-request-all)"); - if (refresh_all_type == REFRESH_ALL_TYPE_LINKS) { + if (refresh_all_type == REFRESH_ALL_TYPE_RTNL_LINKS) { nm_assert( (priv->delayed_action.list_refresh_link->len > 0) == NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)); @@ -6988,11 +7001,11 @@ event_seq_check_refresh_all(NMPlatform *platform, guint32 seq_number) if (NM_IN_SET(seq_number, 0, priv->nlh_seq_last_seen)) return; - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); + if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { + nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) { - data = &g_array_index(priv->delayed_action.list_wait_for_nl_response, + for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len; i++) { + data = &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, DelayedActionWaitForNlResponseData, i); @@ -7022,11 +7035,11 @@ event_seq_check(NMPlatform *platform, if (seq_number == 0) return; - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); + if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { + nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) { - data = &g_array_index(priv->delayed_action.list_wait_for_nl_response, + for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len; i++) { + data = &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, DelayedActionWaitForNlResponseData, i); @@ -7148,13 +7161,13 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg, gboolean h nm_assert(is_ipv6 || !nmp_object_is_alive(obj)); priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); if (NM_FLAGS_HAS(priv->delayed_action.flags, - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { + DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { guint i; - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) { + nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); + for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len; i++) { DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_nl_response, + &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, DelayedActionWaitForNlResponseData, i); @@ -9546,7 +9559,7 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) after_read: - if (!NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) + if (!NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) return any; delayed_action_wait_for_nl_response_complete_check(platform, @@ -9556,7 +9569,8 @@ after_read: &next.now_nsec); if (!wait_for_acks - || !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) + || !NM_FLAGS_HAS(priv->delayed_action.flags, + DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) return any; nm_assert(next.seq_number); @@ -9742,7 +9756,7 @@ nm_linux_platform_init(NMLinuxPlatform *self) priv->delayed_action.list_master_connected = g_ptr_array_new(); priv->delayed_action.list_refresh_link = g_ptr_array_new(); - priv->delayed_action.list_wait_for_nl_response = + priv->delayed_action.list_wait_for_response_rtnl = g_array_new(FALSE, TRUE, sizeof(DelayedActionWaitForNlResponseData)); } @@ -9816,7 +9830,7 @@ constructed(GObject *_object) nl_socket_get_local_port(priv->sk_rtnl), fd); - priv->rtnl_event_source = + priv->event_source_rtnl = nm_g_unix_fd_add_source(fd, G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, rtnl_event_handler, @@ -9928,11 +9942,11 @@ finalize(GObject *object) g_ptr_array_unref(priv->delayed_action.list_master_connected); g_ptr_array_unref(priv->delayed_action.list_refresh_link); - g_array_unref(priv->delayed_action.list_wait_for_nl_response); + g_array_unref(priv->delayed_action.list_wait_for_response_rtnl); nl_socket_free(priv->sk_genl_sync); - nm_clear_g_source_inst(&priv->rtnl_event_source); + nm_clear_g_source_inst(&priv->event_source_rtnl); nl_socket_free(priv->sk_rtnl); From 355331b7790300dc393b33bead6a609aaf99a588 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 12 Jul 2022 18:18:30 +0200 Subject: [PATCH 08/13] platform: make FOR_EACH_DELAYED_ACTION() robust against integer overflow Currently there is no problem. However, DelayedActionType is a packed enum, and if we add a few more enum values, it might happen that DELAYED_ACTION_TYPE_MAX is 0x8000 and DelayedActionType effectively uint16_t. When that happens, the code would become an infinite loop, because 0x8000 is not larger than DELAYED_ACTION_TYPE_MAX, but `<<= 1` shifts out the bit, making it zero. Avoid that. --- src/libnm-platform/nm-linux-platform.c | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 05217528f6..be07c9ba07 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -365,21 +365,21 @@ typedef enum _nm_packed { DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX - 1, } DelayedActionType; -#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ - for ((iflags) = (DelayedActionType) 0x1LL; ({ \ - gboolean _good = FALSE; \ - \ - nm_assert(nm_utils_is_power_of_two(iflags)); \ - \ - while ((iflags) <= DELAYED_ACTION_TYPE_MAX) { \ - if (NM_FLAGS_ANY((flags_all), (iflags))) { \ - _good = TRUE; \ - break; \ - } \ - (iflags) <<= 1; \ - } \ - _good; \ - }); \ +#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ + for ((iflags) = (DelayedActionType) 0x1LL; ({ \ + gboolean _good = FALSE; \ + \ + nm_assert((iflags) == 0 || nm_utils_is_power_of_two(iflags)); \ + \ + while ((iflags) != 0 && (iflags) <= DELAYED_ACTION_TYPE_MAX) { \ + if (NM_FLAGS_ANY((flags_all), (iflags))) { \ + _good = TRUE; \ + break; \ + } \ + (iflags) <<= 1; \ + } \ + _good; \ + }); \ (iflags) <<= 1) typedef enum _nm_packed { From 3d4906a3da8930e1de48bd5cf1a7efc56a9bedfd Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 21 Jun 2022 22:01:28 +0200 Subject: [PATCH 09/13] platform: add genl socket support for events and genl family For generic netlink, the family-id is important. It changes when loading/unloading a module, so we should not cache it indefinitely. To get this right, takes some effort. For "nl80211", "nl802154" and "wireguard", we only cache the family ID in relation to an interface. If the module gets unloaded, the family ID also becomes irrelevant and we need to re-fetch it the next time. For generic families like "mptcp_pm" or "ethtool", they are commonly not kernel modules and cannot be unloaded. So caching them would be (probably) fine. Still. Some generic netlink families emit notifications, and it will be interesting to be able to handle them. Since that will be useful later, start by doing something simple: let the generic netlink family also be cached this way. Generic netlink will send notifications when a family gets added/deleted, and we can use that to reliably cache the family ID. We only care about a well-known set of generic families. Unlike libnl (which has "struct genl_family" object to handle any family), we can hard code the few we care about (NMPGenlFamilyType). This adds the necessary infrastructure of NMLinuxPlatform to listen to events on the generic netlink socket. --- src/libnm-platform/nm-linux-platform.c | 985 ++++++++++++++++--------- src/libnm-platform/nm-platform.c | 13 + src/libnm-platform/nm-platform.h | 7 + 3 files changed, 672 insertions(+), 333 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index be07c9ba07..2ab0251c32 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -79,6 +79,25 @@ enum { TCA_DEF_UNSPEC, TCA_DEF_TM, TCA_DEF_PARMS, TCA_DEF_DATA, TCA_DEF_PAD, __T /*****************************************************************************/ +typedef enum _nm_packed { + _NMP_NETLINK_FIRST = 0, + NMP_NETLINK_GENERIC = 0, + NMP_NETLINK_ROUTE, + _NMP_NETLINK_NUM, + _NMP_NETLINK_NONE = _NMP_NETLINK_NUM, +} NMPNetlinkProtocol; + +#define nmp_netlink_protocol_check(netlink_protocol) \ + ({ \ + const NMPNetlinkProtocol _netlink_protocol_2 = (netlink_protocol); \ + \ + nm_assert(NM_IN_SET(_netlink_protocol_2, NMP_NETLINK_ROUTE, NMP_NETLINK_GENERIC)); \ + \ + _netlink_protocol_2; \ + }) + +/*****************************************************************************/ + #ifndef IFLA_PROMISCUITY #define IFLA_PROMISCUITY 30 #endif @@ -279,6 +298,12 @@ struct _ifla_vf_vlan_info { /*****************************************************************************/ +typedef struct { + guint16 family_id; +} GenlFamilyData; + +/*****************************************************************************/ + typedef enum { INFINIBAND_ACTION_CREATE_CHILD, INFINIBAND_ACTION_DELETE_CHILD, @@ -312,12 +337,16 @@ typedef enum { REFRESH_ALL_TYPE_RTNL_QDISCS = 7, REFRESH_ALL_TYPE_RTNL_TFILTERS = 8, + REFRESH_ALL_TYPE_GENL_FAMILIES = 9, + _REFRESH_ALL_TYPE_NUM, } RefreshAllType; typedef struct { NMPObjectType obj_type; + NMPNetlinkProtocol protocol; + /* For NLM_F_DUMP, which address family to request. * Either AF_UNSPEC, AF_INET or AF_INET6. */ gint8 addr_family_for_dump; @@ -340,12 +369,16 @@ typedef enum _nm_packed { 1 << F(6, REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6), DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS = 1 << F(7, REFRESH_ALL_TYPE_RTNL_QDISCS), DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS = 1 << F(8, REFRESH_ALL_TYPE_RTNL_TFILTERS), + + DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES = 1 << F(9, REFRESH_ALL_TYPE_GENL_FAMILIES), #undef F - DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9, - DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10, - DELAYED_ACTION_TYPE_READ_RTNL = 1 << 11, + DELAYED_ACTION_TYPE_READ_RTNL = 1 << 10, + DELAYED_ACTION_TYPE_READ_GENL = 1 << 11, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL = 1 << 12, + DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL = 1 << 13, + DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 14, + DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 15, __DELAYED_ACTION_TYPE_MAX, @@ -362,6 +395,8 @@ typedef enum _nm_packed { | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, + DELAYED_ACTION_TYPE_REFRESH_GENL_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES, + DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX - 1, } DelayedActionType; @@ -420,17 +455,34 @@ typedef struct { /*****************************************************************************/ typedef struct { - struct nl_sock *sk_genl_sync; - - struct nl_sock *sk_rtnl; - - GSource *event_source_rtnl; - guint32 nlh_seq_next; + guint32 nlh_seq_last_seen; #if NM_MORE_LOGGING guint32 nlh_seq_last_handled; #endif - guint32 nlh_seq_last_seen; +} NetlinkProtocolPrivData; + +typedef struct { + struct nl_sock *sk_genl_sync; + + union { + struct { + struct nl_sock *sk_genl; + struct nl_sock *sk_rtnl; + }; + struct nl_sock *sk_x[_NMP_NETLINK_NUM]; + }; + + GSource *event_source_genl; + GSource *event_source_rtnl; + + union { + struct { + NetlinkProtocolPrivData proto_data_genl; + NetlinkProtocolPrivData proto_data_rtnl; + }; + NetlinkProtocolPrivData proto_data_x[_NMP_NETLINK_NUM]; + }; guint32 pruning[_REFRESH_ALL_TYPE_NUM]; @@ -451,7 +503,13 @@ typedef struct { GPtrArray *list_master_connected; GPtrArray *list_refresh_link; - GArray *list_wait_for_response_rtnl; + union { + struct { + GArray *list_wait_for_response_genl; + GArray *list_wait_for_response_rtnl; + }; + GArray *list_wait_for_response_x[_NMP_NETLINK_NUM]; + }; int is_handling; } delayed_action; @@ -467,6 +525,8 @@ typedef struct { gsize len; } netlink_recv_buf; + GenlFamilyData genl_family_data[_NMP_GENL_FAMILY_TYPE_NUM]; + } NMLinuxPlatformPrivate; struct _NMLinuxPlatform { @@ -567,7 +627,7 @@ NM_LINUX_PLATFORM_FROM_PRIVATE(NMLinuxPlatformPrivate *priv) static void delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpointer user_data); -static gboolean delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink); +static gboolean delayed_action_handle_all(NMPlatform *platform); static void do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char *name); static void do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action_type); static void cache_on_change(NMPlatform *platform, @@ -575,7 +635,36 @@ static void cache_on_change(NMPlatform *platform, const NMPObject *obj_old, const NMPObject *obj_new); static void cache_prune_all(NMPlatform *platform); -static gboolean event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks); +static gboolean event_handler_read_netlink(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + gboolean wait_for_acks); + +/*****************************************************************************/ + +static const struct { + gint8 netlink_protocol; + DelayedActionType delayed_action_type_read; + DelayedActionType delayed_action_type_wait_for_response; + const char name[5]; +} _nmp_netlink_protocol_infos[_NMP_NETLINK_NUM] = { + [NMP_NETLINK_ROUTE] = + { + .netlink_protocol = NETLINK_ROUTE, + .name = "rtnl", + .delayed_action_type_read = DELAYED_ACTION_TYPE_READ_RTNL, + .delayed_action_type_wait_for_response = DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, + }, + [NMP_NETLINK_GENERIC] = + { + .netlink_protocol = NETLINK_GENERIC, + .name = "genl", + .delayed_action_type_read = DELAYED_ACTION_TYPE_READ_GENL, + .delayed_action_type_wait_for_response = DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL, + }, +}; + +#define nmp_netlink_protocol_info(netlink_protocol) \ + (&_nmp_netlink_protocol_infos[nmp_netlink_protocol_check((netlink_protocol))]) /*****************************************************************************/ @@ -5793,7 +5882,10 @@ sysctl_get(NMPlatform *platform, const char *pathid, int dirfd, const char *path static void process_events(NMPlatform *platform) { - delayed_action_handle_all(platform, TRUE); + delayed_action_schedule(platform, + DELAYED_ACTION_TYPE_READ_RTNL | DELAYED_ACTION_TYPE_READ_GENL, + NULL); + delayed_action_handle_all(platform); } /*****************************************************************************/ @@ -5801,27 +5893,34 @@ process_events(NMPlatform *platform) static const RefreshAllInfo * refresh_all_type_get_info(RefreshAllType refresh_all_type) { - static const RefreshAllInfo infos[] = { -#define R(_refresh_all_type, _obj_type, _addr_family) \ - [_refresh_all_type] = { \ - .obj_type = _obj_type, \ - .addr_family_for_dump = _addr_family, \ +#define R(_protocol, _refresh_all_type, _obj_type, _addr_family) \ + [_refresh_all_type] = { \ + .protocol = _protocol, \ + .obj_type = _obj_type, \ + .addr_family_for_dump = _addr_family, \ } - R(REFRESH_ALL_TYPE_RTNL_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), - R(REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_RTNL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_RTNL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), - R(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), - R(REFRESH_ALL_TYPE_RTNL_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), - R(REFRESH_ALL_TYPE_RTNL_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), -#undef R +#define R_ROUTE(...) R(NMP_NETLINK_ROUTE, __VA_ARGS__) +#define R_GENERIC(...) R(NMP_NETLINK_GENERIC, __VA_ARGS__) + static const RefreshAllInfo infos[] = { + R_ROUTE(REFRESH_ALL_TYPE_RTNL_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), + R_GENERIC(REFRESH_ALL_TYPE_GENL_FAMILIES, NMP_OBJECT_TYPE_UNKNOWN, AF_UNSPEC), }; +#undef R_GENERIC +#undef R_ROUTE +#undef R nm_assert(_NM_INT_NOT_NEGATIVE(refresh_all_type)); nm_assert(refresh_all_type < G_N_ELEMENTS(infos)); - nm_assert(nmp_class_from_type(infos[refresh_all_type].obj_type)); + nm_assert(refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES + || nmp_class_from_type(infos[refresh_all_type].obj_type)); return &infos[refresh_all_type]; } @@ -5847,6 +5946,8 @@ static NM_UTILS_LOOKUP_DEFINE( NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS, REFRESH_ALL_TYPE_RTNL_QDISCS), NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, REFRESH_ALL_TYPE_RTNL_TFILTERS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES, + REFRESH_ALL_TYPE_GENL_FAMILIES), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER(), ); static DelayedActionType @@ -5947,15 +6048,25 @@ static NM_UTILS_LOOKUP_STR_DEFINE( "refresh-all-rtnl-qdiscs"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, "refresh-all-rtnl-tfilters"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES, + "refresh-all-genl-families"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_RTNL, "read-rtnl"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_GENL, "read-genl"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, "wait-for-response-rtnl"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL, "wait-for-response-genl"), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_NONE), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL), NM_UTILS_LOOKUP_ITEM_IGNORE(__DELAYED_ACTION_TYPE_MAX), ); +#define delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, idx) \ + (&g_array_index((priv)->delayed_action.list_wait_for_response_x[nmp_netlink_protocol_check( \ + (netlink_protocol))], \ + DelayedActionWaitForNlResponseData, \ + (idx))) + static const char * delayed_action_to_string_full(DelayedActionType action_type, gpointer user_data, @@ -5966,6 +6077,7 @@ delayed_action_to_string_full(DelayedActionType action_type, const DelayedActionWaitForNlResponseData *data; nm_strbuf_append_str(&buf, &buf_size, delayed_action_to_string(action_type)); + switch (action_type) { case DELAYED_ACTION_TYPE_MASTER_CONNECTED: nm_strbuf_append(&buf, &buf_size, " (master-ifindex %d)", GPOINTER_TO_INT(user_data)); @@ -5974,6 +6086,7 @@ delayed_action_to_string_full(DelayedActionType action_type, nm_strbuf_append(&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT(user_data)); break; case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL: + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL: data = user_data; if (data) { @@ -6035,25 +6148,26 @@ delayed_action_refresh_all_in_progress(NMPlatform *platform, DelayedActionType a } static void -delayed_action_wait_for_nl_response_complete(NMPlatform *platform, - guint idx, - WaitForNlResponseResult seq_result) +delayed_action_wait_for_response_complete(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + guint idx, + WaitForNlResponseResult seq_result) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); DelayedActionWaitForNlResponseData *data; + const DelayedActionType ACTION_TYPE = + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response; - nm_assert(NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)); - nm_assert(idx < priv->delayed_action.list_wait_for_response_rtnl->len); + nm_assert(NM_FLAGS_ANY(priv->delayed_action.flags, ACTION_TYPE)); + nm_assert(idx < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len); nm_assert(seq_result); - data = &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, - DelayedActionWaitForNlResponseData, - idx); + data = delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, idx); - _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, data, "complete"); + _LOGt_delayed_action(ACTION_TYPE, data, "complete"); - if (priv->delayed_action.list_wait_for_response_rtnl->len <= 1) - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL; + if (priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len <= 1) + priv->delayed_action.flags &= ~ACTION_TYPE; if (data->out_seq_result) *data->out_seq_result = seq_result; switch (data->response_type) { @@ -6074,15 +6188,16 @@ delayed_action_wait_for_nl_response_complete(NMPlatform *platform, break; } - g_array_remove_index_fast(priv->delayed_action.list_wait_for_response_rtnl, idx); + g_array_remove_index_fast(priv->delayed_action.list_wait_for_response_x[netlink_protocol], idx); } static void -delayed_action_wait_for_nl_response_complete_check(NMPlatform *platform, - WaitForNlResponseResult force_result, - guint32 *out_next_seq_number, - gint64 *out_next_timeout_abs_ns, - gint64 *p_now_nsec) +delayed_action_wait_for_response_complete_check(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + WaitForNlResponseResult force_result, + guint32 *out_next_seq_number, + gint64 *out_next_timeout_abs_ns, + gint64 *p_now_nsec) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); guint i; @@ -6090,24 +6205,25 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf gint64 next_timeout_abs_ns = 0; gint64 now_nsec = 0; - for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len;) { + for (i = 0; i < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len;) { const DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, - DelayedActionWaitForNlResponseData, - i); + delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, i); if (data->seq_result) - delayed_action_wait_for_nl_response_complete(platform, i, data->seq_result); + delayed_action_wait_for_response_complete(platform, + netlink_protocol, + i, + data->seq_result); else if (p_now_nsec && ((now_nsec ?: (now_nsec = nm_utils_get_monotonic_timestamp_nsec())) >= data->timeout_abs_nsec)) { /* the caller can optionally check for timeout by providing a p_now_nsec argument. */ - delayed_action_wait_for_nl_response_complete( - platform, - i, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); + delayed_action_wait_for_response_complete(platform, + netlink_protocol, + i, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); } else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - delayed_action_wait_for_nl_response_complete(platform, i, force_result); + delayed_action_wait_for_response_complete(platform, netlink_protocol, i, force_result); else { if (next_seq_number == 0 || next_timeout_abs_ns > data->timeout_abs_nsec) { next_seq_number = data->seq_number; @@ -6118,9 +6234,10 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf } if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) { - nm_assert( - !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)); - nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len == 0); + nm_assert(!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)); + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len == 0); } NM_SET_OUT(out_next_seq_number, next_seq_number); @@ -6130,9 +6247,15 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf static void delayed_action_wait_for_nl_response_complete_all(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, WaitForNlResponseResult fallback_result) { - delayed_action_wait_for_nl_response_complete_check(platform, fallback_result, NULL, NULL, NULL); + delayed_action_wait_for_response_complete_check(platform, + nmp_netlink_protocol_check(netlink_protocol), + fallback_result, + NULL, + NULL, + NULL); } /*****************************************************************************/ @@ -6167,15 +6290,15 @@ delayed_action_handle_REFRESH_ALL(NMPlatform *platform, DelayedActionType flags) } static void -delayed_action_handle_READ_NETLINK(NMPlatform *platform) +delayed_action_handle_READ_NETLINK(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol) { - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, netlink_protocol, FALSE); } static void -delayed_action_handle_WAIT_FOR_NL_RESPONSE(NMPlatform *platform) +delayed_action_handle_WAIT_FOR_RESPONSE(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol) { - event_handler_read_netlink(platform, TRUE); + event_handler_read_netlink(platform, netlink_protocol, TRUE); } static gboolean @@ -6183,6 +6306,8 @@ delayed_action_handle_one(NMPlatform *platform) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); gpointer user_data; + NMPNetlinkProtocol netlink_protocol; + DelayedActionType iflags; if (priv->delayed_action.flags == DELAYED_ACTION_TYPE_NONE) return FALSE; @@ -6209,28 +6334,46 @@ delayed_action_handle_one(NMPlatform *platform) } nm_assert(priv->delayed_action.list_master_connected->len == 0); - /* Next we prefer read-netlink, because the buffer size is limited and we want to process events + /* Next we prefer read-genl/read-rtnl, because the buffer size is limited and we want to process events * from netlink early. */ - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_READ_RTNL)) { - _LOGt_delayed_action(DELAYED_ACTION_TYPE_READ_RTNL, NULL, "handle"); - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_READ_RTNL; - delayed_action_handle_READ_NETLINK(platform); + for (netlink_protocol = _NMP_NETLINK_FIRST; netlink_protocol < _NMP_NETLINK_NUM; + netlink_protocol++) { + const DelayedActionType ACTION_TYPE = + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_read; + + if (NM_FLAGS_ANY(priv->delayed_action.flags, ACTION_TYPE)) { + _LOGt_delayed_action(ACTION_TYPE, NULL, "handle"); + priv->delayed_action.flags &= ~ACTION_TYPE; + delayed_action_handle_READ_NETLINK(platform, netlink_protocol); + return TRUE; + } + } + + if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_GENL_ALL)) { + const DelayedActionType FLAGS = + priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_GENL_ALL; + + if (_LOGt_ENABLED()) { + FOR_EACH_DELAYED_ACTION (iflags, FLAGS) + _LOGt_delayed_action(iflags, NULL, "handle"); + } + + priv->delayed_action.flags &= ~FLAGS; + delayed_action_handle_REFRESH_ALL(platform, FLAGS); return TRUE; } if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)) { - DelayedActionType flags, iflags; - - flags = priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL; - - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL; + const DelayedActionType FLAGS = + (priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL); if (_LOGt_ENABLED()) { - FOR_EACH_DELAYED_ACTION (iflags, flags) + FOR_EACH_DELAYED_ACTION (iflags, FLAGS) _LOGt_delayed_action(iflags, NULL, "handle"); } - delayed_action_handle_REFRESH_ALL(platform, flags); + priv->delayed_action.flags &= ~FLAGS; + delayed_action_handle_REFRESH_ALL(platform, FLAGS); return TRUE; } @@ -6254,18 +6397,24 @@ delayed_action_handle_one(NMPlatform *platform) return TRUE; } - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { - nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); - _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, NULL, "handle"); - delayed_action_handle_WAIT_FOR_NL_RESPONSE(platform); - return TRUE; + for (netlink_protocol = _NMP_NETLINK_FIRST; netlink_protocol < _NMP_NETLINK_NUM; + netlink_protocol++) { + const DelayedActionType ACTION_TYPE = + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response; + + if (NM_FLAGS_ANY(priv->delayed_action.flags, ACTION_TYPE)) { + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len > 0); + _LOGt_delayed_action(ACTION_TYPE, NULL, "handle"); + delayed_action_handle_WAIT_FOR_RESPONSE(platform, netlink_protocol); + return TRUE; + } } return FALSE; } static gboolean -delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink) +delayed_action_handle_all(NMPlatform *platform) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); gboolean any = FALSE; @@ -6273,8 +6422,6 @@ delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink) g_return_val_if_fail(priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; - if (read_netlink) - delayed_action_schedule(platform, DELAYED_ACTION_TYPE_READ_RTNL, NULL); while (delayed_action_handle_one(platform)) any = TRUE; priv->delayed_action.is_handling--; @@ -6312,11 +6459,18 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL: g_array_append_vals(priv->delayed_action.list_wait_for_response_rtnl, user_data, 1); break; + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL: + g_array_append_vals(priv->delayed_action.list_wait_for_response_genl, user_data, 1); + break; default: + /* For other action types, we support setting multiple flags at once. They + * also don't have any user-data. */ nm_assert(!user_data); - nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_REFRESH_LINK)); - nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_MASTER_CONNECTED)); - nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)); + nm_assert(!NM_FLAGS_ANY(action_type, + DELAYED_ACTION_TYPE_REFRESH_LINK + | DELAYED_ACTION_TYPE_MASTER_CONNECTED + | DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL + | DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL)); break; } @@ -6329,31 +6483,37 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo } static void -delayed_action_schedule_refresh_all(NMPlatform *platform) +delayed_action_schedule_refresh_all(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol) { DelayedActionType action_type; - action_type = DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS - | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL; - if (nm_platform_get_cache_tc(platform)) { - action_type |= (DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS); + if (netlink_protocol == NMP_NETLINK_ROUTE) { + action_type = DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL; + if (nm_platform_get_cache_tc(platform)) { + action_type |= (DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS); + } + } else { + nm_assert(netlink_protocol == NMP_NETLINK_GENERIC); + action_type = DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES; } delayed_action_schedule(platform, action_type, NULL); } static void -delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform *platform, - guint32 seq_number, - WaitForNlResponseResult *out_seq_result, - char **out_errmsg, - DelayedActionWaitForNlResponseType response_type, - gpointer response_out_data) +delayed_action_schedule_WAIT_FOR_RESPONSE(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + guint32 seq_number, + WaitForNlResponseResult *out_seq_result, + char **out_errmsg, + DelayedActionWaitForNlResponseType response_type, + gpointer response_out_data) { DelayedActionWaitForNlResponseData data = { .seq_number = seq_number, @@ -6365,7 +6525,10 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform * .response.out_data = response_out_data, }; - delayed_action_schedule(platform, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, &data); + delayed_action_schedule( + platform, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response, + &data); } /*****************************************************************************/ @@ -6417,6 +6580,9 @@ cache_prune_all(NMPlatform *platform) if (priv->pruning[refresh_all_type] == 0) continue; + + nm_assert(refresh_all_type != REFRESH_ALL_TYPE_GENL_FAMILIES); + priv->pruning[refresh_all_type] -= 1; if (priv->pruning[refresh_all_type] > 0) continue; @@ -6681,12 +6847,14 @@ cache_on_change(NMPlatform *platform, /*****************************************************************************/ static guint32 -_nlh_seq_next_get(NMLinuxPlatformPrivate *priv) +_nlh_seq_next_get(NMLinuxPlatformPrivate *priv, NMPNetlinkProtocol netlink_protocol) { + guint32 *p = &priv->proto_data_x[netlink_protocol].nlh_seq_next; + /* generate a new sequence number, but never return zero. * Wrapping numbers are not a problem, because we don't rely * on strictly increasing sequence numbers. */ - return (++priv->nlh_seq_next) ?: (++priv->nlh_seq_next); + return (++(*p)) ?: (++(*p)); } /** @@ -6713,7 +6881,7 @@ _nl_send_nlmsghdr(NMPlatform *platform, nm_assert(nlhdr); - seq = _nlh_seq_next_get(priv); + seq = _nlh_seq_next_get(priv, NMP_NETLINK_ROUTE); nlhdr->nlmsg_seq = seq; { @@ -6747,32 +6915,24 @@ again: } } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE(platform, - seq, - out_seq_result, - out_errmsg, - response_type, - response_out_data); + delayed_action_schedule_WAIT_FOR_RESPONSE(platform, + NMP_NETLINK_ROUTE, + seq, + out_seq_result, + out_errmsg, + response_type, + response_out_data); return 0; } -/** - * _nl_send_nlmsg: - * @platform: - * @nlmsg: - * @out_seq_result: - * @response_type: - * @response_out_data: - * - * Returns: 0 on success, or a negative libnl3 error code (beware, it's not an errno). - */ static int -_nl_send_nlmsg(NMPlatform *platform, - struct nl_msg *nlmsg, - WaitForNlResponseResult *out_seq_result, - char **out_errmsg, - DelayedActionWaitForNlResponseType response_type, - gpointer response_out_data) +_netlink_send_nlmsg(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + struct nl_msg *nlmsg, + WaitForNlResponseResult *out_seq_result, + char **out_errmsg, + DelayedActionWaitForNlResponseType response_type, + gpointer response_out_data) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); struct nlmsghdr *nlhdr; @@ -6780,24 +6940,40 @@ _nl_send_nlmsg(NMPlatform *platform, int nle; nlhdr = nlmsg_hdr(nlmsg); - seq = _nlh_seq_next_get(priv); + seq = _nlh_seq_next_get(priv, netlink_protocol); nlhdr->nlmsg_seq = seq; - nle = nl_send_auto(priv->sk_rtnl, nlmsg); + nle = nl_send_auto(priv->sk_x[netlink_protocol], nlmsg); if (nle < 0) { _LOGD("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle); return nle; } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE(platform, - seq, - out_seq_result, - out_errmsg, - response_type, - response_out_data); + delayed_action_schedule_WAIT_FOR_RESPONSE(platform, + netlink_protocol, + seq, + out_seq_result, + out_errmsg, + response_type, + response_out_data); return 0; } +static int +_netlink_send_nlmsg_rtnl(NMPlatform *platform, + struct nl_msg *nlmsg, + WaitForNlResponseResult *out_seq_result, + char **out_errmsg) +{ + return _netlink_send_nlmsg(platform, + NMP_NETLINK_ROUTE, + nlmsg, + out_seq_result, + out_errmsg, + DELAYED_ACTION_RESPONSE_TYPE_VOID, + NULL); +} + static void do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char *name) { @@ -6822,11 +6998,11 @@ do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char } } - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); nlmsg = _nl_msg_new_link(RTM_GETLINK, 0, ifindex, name); if (nlmsg) { - nle = _nl_send_nlmsg(platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, NULL, NULL); if (nle < 0) { _LOGE("do-request-link: %d %s: failed sending netlink request \"%s\" (%d)", ifindex, @@ -6842,11 +7018,11 @@ static void do_request_link(NMPlatform *platform, int ifindex, const char *name) { do_request_link_no_delayed_actions(platform, ifindex, name); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); } static struct nl_msg * -_nl_msg_new_dump(NMPObjectType obj_type, int preferred_addr_family) +_nl_msg_new_dump_rtnl(NMPObjectType obj_type, int preferred_addr_family) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; const NMPClass *klass; @@ -6896,6 +7072,26 @@ _nl_msg_new_dump(NMPObjectType obj_type, int preferred_addr_family) return g_steal_pointer(&nlmsg); } +static struct nl_msg * +_nl_msg_new_dump_genl_families(void) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + + nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN)); + + if (!genlmsg_put(nlmsg, + NL_AUTO_PORT, + NL_AUTO_SEQ, + GENL_ID_CTRL, + 0, + NLM_F_DUMP, + CTRL_CMD_GETFAMILY, + 1)) + g_return_val_if_reached(NULL); + + return g_steal_pointer(&nlmsg); +} + static void do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action_type) { @@ -6903,29 +7099,36 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action DelayedActionType action_type_prune; DelayedActionType iflags; - nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)); - action_type &= DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL; + nm_assert((NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL) + && !NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)) + || (NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_GENL_ALL) + && !NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_GENL_ALL))); action_type_prune = action_type; - /* calling nmp_cache_dirty_set_all_main() with a non-main lookup-index requires an extra - * cache lookup for every entry. - * - * Avoid that, by special casing routing-rules here. */ if (NM_FLAGS_ALL(action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL)) { NMPLookup lookup; + /* calling nmp_cache_dirty_set_all_main() with a non-main lookup-index requires an extra + * cache lookup for every entry. + * + * Avoid that, by special casing routing-rules here. */ priv->pruning[REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4] += 1; priv->pruning[REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6] += 1; nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup); action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL; } - FOR_EACH_DELAYED_ACTION (iflags, action_type_prune) { RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type(iflags); NMPLookup lookup; + if (refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES) { + /* genl families are not tracked in the NMPObject cache, because there is + * only a static number of objects we care about (NMPGenlFamilyType). */ + continue; + } + priv->pruning[refresh_all_type] += 1; refresh_all_type_init_lookup(refresh_all_type, &lookup); nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup); @@ -6959,24 +7162,30 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action } } - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, refresh_all_info->protocol, FALSE); + + if (refresh_all_info->protocol == NMP_NETLINK_ROUTE) { + nlmsg = _nl_msg_new_dump_rtnl(refresh_all_info->obj_type, + refresh_all_info->addr_family_for_dump); + } else { + nm_assert(refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES); + nlmsg = _nl_msg_new_dump_genl_families(); + } - nlmsg = - _nl_msg_new_dump(refresh_all_info->obj_type, refresh_all_info->addr_family_for_dump); if (!nlmsg) goto next_after_fail; - if (_nl_send_nlmsg(platform, - nlmsg, - NULL, - NULL, - DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, - out_refresh_all_in_progress) + if (_netlink_send_nlmsg(platform, + refresh_all_info->protocol, + nlmsg, + NULL, + NULL, + DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, + out_refresh_all_in_progress) < 0) goto next_after_fail; continue; - next_after_fail: nm_assert(*out_refresh_all_in_progress > 0); *out_refresh_all_in_progress -= 1; @@ -6988,86 +7197,94 @@ do_request_one_type_by_needle_object(NMPlatform *platform, const NMPObject *obj_ { do_request_all_no_delayed_actions(platform, delayed_action_refresh_from_needle_object(obj_needle)); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); } static void -event_seq_check_refresh_all(NMPlatform *platform, guint32 seq_number) +event_seq_check_refresh_all(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + guint32 seq_number) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionWaitForNlResponseData *data; - guint i; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + guint i; - if (NM_IN_SET(seq_number, 0, priv->nlh_seq_last_seen)) + if (NM_IN_SET(seq_number, 0, priv->proto_data_x[netlink_protocol].nlh_seq_last_seen)) return; - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { - nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); + if (!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) + goto out; - for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len; i++) { - data = &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, - DelayedActionWaitForNlResponseData, - i); + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len > 0); - if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS - && data->response.out_refresh_all_in_progress - && data->seq_number == priv->nlh_seq_last_seen) { - *data->response.out_refresh_all_in_progress -= 1; - data->response.out_refresh_all_in_progress = NULL; - break; - } + for (i = 0; i < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len; i++) { + DelayedActionWaitForNlResponseData *data = + delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, i); + + if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS + && data->response.out_refresh_all_in_progress + && data->seq_number == priv->proto_data_x[netlink_protocol].nlh_seq_last_seen) { + *data->response.out_refresh_all_in_progress -= 1; + data->response.out_refresh_all_in_progress = NULL; + break; } } - priv->nlh_seq_last_seen = seq_number; +out: + priv->proto_data_x[netlink_protocol].nlh_seq_last_seen = seq_number; } static void event_seq_check(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, guint32 seq_number, WaitForNlResponseResult seq_result, const char *msg) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionWaitForNlResponseData *data; - guint i; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + guint i; if (seq_number == 0) return; - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { - nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); + if (!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) + goto out; - for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len; i++) { - data = &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, - DelayedActionWaitForNlResponseData, - i); + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len > 0); - if (data->seq_number == seq_number) { - /* We potentially receive many parts partial responses for the same sequence number. + for (i = 0; i < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len; i++) { + DelayedActionWaitForNlResponseData *data = + delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, i); + + if (data->seq_number == seq_number) { + /* We potentially receive many parts partial responses for the same sequence number. * Thus, we only remember the result, and collect it later. */ - if (data->seq_result < 0) { - /* we already saw an error for this sequence number. + if (data->seq_result < 0) { + /* we already saw an error for this sequence number. * Preserve it. */ - } else if (seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN - || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - data->seq_result = seq_result; - if (data->out_errmsg && !*data->out_errmsg) - *data->out_errmsg = g_strdup(msg); - return; - } + } else if (seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN + || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) + data->seq_result = seq_result; + if (data->out_errmsg && !*data->out_errmsg) + *data->out_errmsg = g_strdup(msg); + return; } } +out: + #if NM_MORE_LOGGING - if (seq_number != priv->nlh_seq_last_handled) + if (seq_number != priv->proto_data_x[netlink_protocol].nlh_seq_last_handled) _LOGt("netlink: recvmsg: unwaited sequence number %u", seq_number); - priv->nlh_seq_last_handled = seq_number; + priv->proto_data_x[netlink_protocol].nlh_seq_last_handled = seq_number; #endif } static void -_rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg, gboolean handle_events) +_rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg) { char sbuf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; NMLinuxPlatformPrivate *priv; @@ -7080,9 +7297,6 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg, gboolean h NMPCache *cache = nm_platform_get_cache(platform); ParseNlmsgIter parse_nlmsg_iter; - if (!handle_events) - return; - msghdr = msg->nm_nlh; if (NM_IN_SET(msghdr->nlmsg_type, @@ -7167,9 +7381,7 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg, gboolean h nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len; i++) { DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_response_rtnl, - DelayedActionWaitForNlResponseData, - i); + delayed_action_get_list_wait_for_resonse(priv, NMP_NETLINK_ROUTE, i); if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET && data->response.out_route_get) { @@ -7311,14 +7523,9 @@ do_add_link_with_lookup(NMPlatform *platform, char s_buf[256]; NMPCache *cache = nm_platform_get_cache(platform); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", name, @@ -7329,7 +7536,7 @@ do_add_link_with_lookup(NMPlatform *platform, return nle; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -7365,14 +7572,9 @@ do_add_addrroute(NMPlatform *platform, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, @@ -7382,7 +7584,7 @@ do_add_addrroute(NMPlatform *platform, return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -7421,14 +7623,9 @@ do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *n gboolean success; const char *log_detail = ""; - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, @@ -7438,7 +7635,7 @@ do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *n return FALSE; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -7512,12 +7709,7 @@ do_change_link(NMPlatform *platform, } retry: - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { log_level = LOGL_ERR; log_detail_free = @@ -7530,7 +7722,7 @@ retry: * and we sometimes lack events. Nuke it from the orbit... */ delayed_action_schedule(platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER(ifindex)); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9009,7 +9201,7 @@ ip_route_get(NMPlatform *platform, return -NME_UNSPEC; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); /* Retry, if we failed due to a cache resync. That can happen when the netlink * socket fills up and we lost the response. */ @@ -9045,20 +9237,15 @@ routing_rule_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformRoutin msg = _nl_msg_new_routing_rule(RTM_NEWRULE, flags, routing_rule); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-rule: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9089,20 +9276,15 @@ qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) msg = _nl_msg_new_qdisc(RTM_NEWQDISC, flags, qdisc); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-qdisc: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9148,14 +9330,9 @@ tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboo if (nlmsg_append_struct(msg, &tcm) < 0) goto nla_put_failure; - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _NMLOG(log_error ? LOGL_ERR : LOGL_DEBUG, "%s: failed sending netlink request \"%s\" (%d)", @@ -9165,7 +9342,7 @@ tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboo return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9205,20 +9382,15 @@ tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tf msg = _nl_msg_new_tfilter(RTM_NEWTFILTER, flags, tfilter); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-tfilter: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9240,12 +9412,66 @@ tfilter_delete(NMPlatform *platform, int ifindex, guint32 parent, gboolean log_e /*****************************************************************************/ +static void +_genl_handle_msg_ctrl(NMPlatform *platform, const struct nlmsghdr *hdr) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + const struct genlmsghdr *ghdr = nlmsg_data(hdr); + + switch (ghdr->cmd) { + case CTRL_CMD_NEWFAMILY: + case CTRL_CMD_DELFAMILY: + { + struct nlattr *tb[G_N_ELEMENTS(genl_ctrl_policy)]; + NMPGenlFamilyType family_type; + const char *name; + guint16 family_id = 0; + + if (genlmsg_parse_arr(hdr, 0, tb, genl_ctrl_policy) < 0) + return; + + name = nla_get_string(tb[CTRL_ATTR_FAMILY_NAME]); + family_type = nmp_genl_family_type_from_name(name); + + if (family_type == _NMP_GENL_FAMILY_TYPE_NONE) + return; + + if (ghdr->cmd == CTRL_CMD_NEWFAMILY) + family_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]); + + if (priv->genl_family_data[family_type].family_id != family_id) { + if (family_id != 0) + _LOGD("genl:ctrl: new family-id for %s: 0x%04x", name, family_id); + else + _LOGD("genl:ctrl: del family-id for %s", name); + priv->genl_family_data[family_type].family_id = family_id; + } + } + } +} + +static void +_genl_handle_msg(NMPlatform *platform, guint32 pktinfo_group, const struct nl_msg_lite *msg) +{ + const struct nlmsghdr *hdr = msg->nm_nlh; + + if (!genlmsg_valid_hdr(hdr, 0)) + return; + + if (hdr->nlmsg_type == GENL_ID_CTRL) + _genl_handle_msg_ctrl(platform, hdr); +} + +/*****************************************************************************/ + static int _netlink_recv(NMPlatform *platform, struct nl_sock *sk, struct sockaddr_nl *nla, struct ucred *out_creds, - gboolean *out_creds_has) + gboolean *out_creds_has, + guint32 *out_pktinfo_group, + gboolean *out_pktinfo_has) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); unsigned char *buf = NULL; @@ -9255,7 +9481,10 @@ _netlink_recv(NMPlatform *platform, nm_assert(out_creds); nm_assert(out_creds_has); - /* We use a pre-allocated receive buffer. */ + /* We use a pre-allocated receive buffer. We use it both for sk_rtnl + * and sk_genl. We can do that, because we are deep inside the netlink + * handling, and we never will need to use it for both sockets at the + * same time. */ n = nl_recv(sk, priv->netlink_recv_buf.buf, @@ -9264,8 +9493,8 @@ _netlink_recv(NMPlatform *platform, &buf, out_creds, out_creds_has, - NULL, - NULL); + out_pktinfo_group, + out_pktinfo_has); nm_assert((n <= 0 && !buf) || (n > 0 && n <= priv->netlink_recv_buf.len && buf == priv->netlink_recv_buf.buf)); @@ -9286,19 +9515,33 @@ _netlink_recv(NMPlatform *platform, /*****************************************************************************/ static gboolean -rtnl_event_handler(int fd, GIOCondition io_condition, gpointer user_data) +_nl_event_handler(NMPlatform *platform, DelayedActionType action_type) { - delayed_action_handle_all(NM_PLATFORM(user_data), TRUE); + delayed_action_schedule(platform, action_type, NULL); + delayed_action_handle_all(platform); return TRUE; } +static gboolean +_nl_event_handler_genl(int fd, GIOCondition io_condition, gpointer user_data) +{ + return _nl_event_handler(user_data, DELAYED_ACTION_TYPE_READ_GENL); +} + +static gboolean +_nl_event_handler_rtnl(int fd, GIOCondition io_condition, gpointer user_data) +{ + return _nl_event_handler(user_data, DELAYED_ACTION_TYPE_READ_RTNL); +} + /*****************************************************************************/ static int -_netlink_recv_handle(NMPlatform *platform, int netlink_protocol, gboolean handle_events) +_netlink_recv_handle(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + gboolean handle_events) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - struct nl_sock *sk; int n; int retval = 0; gboolean multipart = 0; @@ -9307,15 +9550,19 @@ _netlink_recv_handle(NMPlatform *platform, int netlink_protocol, gboolean handle struct sockaddr_nl nla; struct ucred creds; gboolean creds_has; - const char *log_prefix; - - nm_assert(netlink_protocol == NETLINK_ROUTE); - sk = priv->sk_rtnl; - log_prefix = "rtnl"; + guint32 pktinfo_group = 0; + gboolean pktinfo_has = FALSE; + const char *const log_prefix = nmp_netlink_protocol_info(netlink_protocol)->name; continue_reading: - n = _netlink_recv(platform, sk, &nla, &creds, &creds_has); + n = _netlink_recv(platform, + priv->sk_x[netlink_protocol], + &nla, + &creds, + &creds_has, + &pktinfo_group, + netlink_protocol == NMP_NETLINK_GENERIC ? &pktinfo_has : NULL); if (n < 0) { if (n == -NME_NL_MSG_TRUNC && !handle_events) goto continue_reading; @@ -9337,7 +9584,7 @@ continue_reading: char buf_nlmsghdr[400]; const char *extack_msg = NULL; const struct nl_msg_lite msg = { - .nm_protocol = netlink_protocol, + .nm_protocol = nmp_netlink_protocol_info(netlink_protocol)->netlink_protocol, .nm_src = &nla, .nm_creds = &creds, .nm_size = NLMSG_ALIGN(hdr->nlmsg_len), @@ -9349,8 +9596,8 @@ continue_reading: _LOGt("%s: recvmsg: new message %s", log_prefix, - nl_nlmsghdr_to_str(netlink_protocol, - 0, + nl_nlmsghdr_to_str(nmp_netlink_protocol_info(netlink_protocol)->netlink_protocol, + pktinfo_group, msg.nm_nlh, buf_nlmsghdr, sizeof(buf_nlmsghdr))); @@ -9367,9 +9614,8 @@ continue_reading: interrupted = TRUE; } - /* Other side wishes to see an ack for this message */ if (msg.nm_nlh->nlmsg_flags & NLM_F_ACK) { - /* FIXME: implement */ + /* TODO: Other side wishes to see an ack for this message */ } seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; @@ -9426,7 +9672,8 @@ continue_reading: } /* Error message reported back from kernel. */ - _LOGD("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", + _LOGD("%s: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", + log_prefix, nm_strerror_native(errsv), errsv, NM_PRINT_FMT_QUOTED(extack_msg, " \"", extack_msg, "\"", ""), @@ -9437,34 +9684,31 @@ continue_reading: } else process_valid_msg = TRUE; - switch (netlink_protocol) { - default: - nm_assert_not_reached(); - /* fall-through */ - case NETLINK_ROUTE: - /* check whether the seq number is different from before, and - * whether the previous number (@nlh_seq_last_seen) is a pending - * refresh-all request. In that case, the pending request is thereby - * completed. - * - * We must do that before processing the message with _rtnl_handle_msg(), - * because we must track the completion of the pending request before that. */ - event_seq_check_refresh_all(platform, seq_number); + /* check whether the seq number is different from before, and + * whether the previous number (@nlh_seq_last_seen) is a pending + * refresh-all request. In that case, the pending request is thereby + * completed. + * + * We must do that before processing the message with _rtnl_handle_msg(), + * because we must track the completion of the pending request before that. */ + event_seq_check_refresh_all(platform, netlink_protocol, seq_number); - if (process_valid_msg) { + if (process_valid_msg) { + if (handle_events) { /* Valid message (not checking for MULTIPART bit to * get along with broken kernels. NL_SKIP has no * effect on this. */ - - _rtnl_handle_msg(platform, &msg, handle_events); - - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + if (netlink_protocol == NMP_NETLINK_ROUTE) { + _rtnl_handle_msg(platform, &msg); + } else { + _genl_handle_msg(platform, pktinfo_group, &msg); + } } - - event_seq_check(platform, seq_number, seq_result, extack_msg); - break; + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } + event_seq_check(platform, netlink_protocol, seq_number, seq_result, extack_msg); + if (retval != 0) goto stop; @@ -9492,7 +9736,9 @@ stop: /*****************************************************************************/ static gboolean -event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) +event_handler_read_netlink(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + gboolean wait_for_acks) { nm_auto_pop_netns NMPNetns *netns = NULL; NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); @@ -9506,8 +9752,11 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) gint64 now_nsec; } next; + nmp_netlink_protocol_check(netlink_protocol); + if (!nm_platform_netns_push(platform, &netns)) { delayed_action_wait_for_nl_response_complete_all(platform, + netlink_protocol, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS); return FALSE; } @@ -9516,20 +9765,24 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) for (;;) { int nle; - nle = _netlink_recv_handle(platform, NETLINK_ROUTE, TRUE); + nle = _netlink_recv_handle(platform, netlink_protocol, TRUE); if (nle < 0) { switch (nle) { case -EAGAIN: goto after_read; case -NME_NL_DUMP_INTR: - _LOGD("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", + _LOGD("netlink[%s]: read: uncritical failure to retrieve incoming events: %s " + "(%d)", + nmp_netlink_protocol_info(netlink_protocol)->name, nm_strerror(nle), nle); break; case -NME_NL_MSG_TRUNC: case -ENOBUFS: - _LOGI("netlink: read: %s. Need to resynchronize platform cache", ({ + _LOGI("netlink[%s]: read: %s. Need to resynchronize platform cache", + nmp_netlink_protocol_info(netlink_protocol)->name, + ({ const char *_reason = "unknown"; switch (nle) { case -NME_NL_MSG_TRUNC: @@ -9541,14 +9794,16 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) } _reason; })); - _netlink_recv_handle(platform, NETLINK_ROUTE, FALSE); + _netlink_recv_handle(platform, netlink_protocol, FALSE); delayed_action_wait_for_nl_response_complete_all( platform, + netlink_protocol, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); - delayed_action_schedule_refresh_all(platform); + delayed_action_schedule_refresh_all(platform, netlink_protocol); break; default: - _LOGE("netlink: read: failed to retrieve incoming events: %s (%d)", + _LOGE("netlink[%s]: read: failed to retrieve incoming events: %s (%d)", + nmp_netlink_protocol_info(netlink_protocol)->name, nm_strerror(nle), nle); break; @@ -9559,18 +9814,22 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) after_read: - if (!NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) + if (!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) return any; - delayed_action_wait_for_nl_response_complete_check(platform, - WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN, - &next.seq_number, - &next.timeout_abs_nsec, - &next.now_nsec); + delayed_action_wait_for_response_complete_check(platform, + netlink_protocol, + WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN, + &next.seq_number, + &next.timeout_abs_nsec, + &next.now_nsec); if (!wait_for_acks - || !NM_FLAGS_HAS(priv->delayed_action.flags, - DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) + || !NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) return any; nm_assert(next.seq_number); @@ -9606,6 +9865,7 @@ after_read: _LOGE("netlink: read: poll failed with %s", nm_strerror_native(errsv)); delayed_action_wait_for_nl_response_complete_all( platform, + netlink_protocol, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL); return any; } @@ -9616,6 +9876,27 @@ after_read: /*****************************************************************************/ +static guint16 +genl_get_family_id(NMPlatform *platform, NMPGenlFamilyType family_type) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + + nm_assert(_NM_INT_NOT_NEGATIVE(family_type)); + nm_assert(family_type < G_N_ELEMENTS(priv->genl_family_data)); + + if (priv->genl_family_data[family_type].family_id == 0) { + /* Unknown family ID. Try to read the netlink socket, maybe we have + * a message there to learn it. */ + delayed_action_schedule(platform, DELAYED_ACTION_TYPE_READ_GENL, NULL); + if (priv->delayed_action.is_handling == 0) + delayed_action_handle_all(platform); + } + + return priv->genl_family_data[family_type].family_id; +} + +/*****************************************************************************/ + static void cache_update_link_udev(NMPlatform *platform, int ifindex, struct udev_device *udevice) { @@ -9758,6 +10039,8 @@ nm_linux_platform_init(NMLinuxPlatform *self) priv->delayed_action.list_refresh_link = g_ptr_array_new(); priv->delayed_action.list_wait_for_response_rtnl = g_array_new(FALSE, TRUE, sizeof(DelayedActionWaitForNlResponseData)); + priv->delayed_action.list_wait_for_response_genl = + g_array_new(FALSE, TRUE, sizeof(DelayedActionWaitForNlResponseData)); } static void @@ -9799,6 +10082,32 @@ constructed(GObject *_object) /*************************************************************************/ + /* disable MSG_PEEK, we will handle lost messages ourselves. */ + nle = nl_socket_new(&priv->sk_genl, + NETLINK_GENERIC, + NL_SOCKET_FLAGS_NONBLOCK | NL_SOCKET_FLAGS_PASSCRED + | NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, + 8 * 1024 * 1024, + 0); + g_assert(!nle); + + nle = nl_socket_add_memberships(priv->sk_genl, GENL_ID_CTRL, 0); + g_assert(!nle); + + fd = nl_socket_get_fd(priv->sk_genl); + + _LOGD("genl: generic netlink socket created: port=%u, fd=%d", + nl_socket_get_local_port(priv->sk_genl), + fd); + + priv->event_source_genl = + nm_g_unix_fd_add_source(fd, + G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, + _nl_event_handler_genl, + platform); + + /*************************************************************************/ + /* disable MSG_PEEK, we will handle lost messages ourselves. */ nle = nl_socket_new(&priv->sk_rtnl, NETLINK_ROUTE, @@ -9833,7 +10142,7 @@ constructed(GObject *_object) priv->event_source_rtnl = nm_g_unix_fd_add_source(fd, G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, - rtnl_event_handler, + _nl_event_handler_rtnl, platform); /*************************************************************************/ @@ -9842,9 +10151,10 @@ constructed(GObject *_object) G_OBJECT_CLASS(nm_linux_platform_parent_class)->constructed(_object); _LOGD("populate platform cache"); - delayed_action_schedule_refresh_all(platform); + delayed_action_schedule_refresh_all(platform, NMP_NETLINK_ROUTE); + delayed_action_schedule_refresh_all(platform, NMP_NETLINK_GENERIC); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); /* Set up udev monitoring */ if (priv->udev_client) { @@ -9926,6 +10236,11 @@ dispose(GObject *object) _LOGD("dispose"); delayed_action_wait_for_nl_response_complete_all(platform, + NMP_NETLINK_GENERIC, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); + + delayed_action_wait_for_nl_response_complete_all(platform, + NMP_NETLINK_ROUTE, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE; @@ -9943,11 +10258,13 @@ finalize(GObject *object) g_ptr_array_unref(priv->delayed_action.list_master_connected); g_ptr_array_unref(priv->delayed_action.list_refresh_link); g_array_unref(priv->delayed_action.list_wait_for_response_rtnl); + g_array_unref(priv->delayed_action.list_wait_for_response_genl); - nl_socket_free(priv->sk_genl_sync); - + nm_clear_g_source_inst(&priv->event_source_genl); nm_clear_g_source_inst(&priv->event_source_rtnl); + nl_socket_free(priv->sk_genl_sync); + nl_socket_free(priv->sk_genl); nl_socket_free(priv->sk_rtnl); { @@ -10066,4 +10383,6 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->tfilter_delete = tfilter_delete; platform_class->process_events = process_events; + + platform_class->genl_get_family_id = genl_get_family_id; } diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index ab21f3f289..961c617cc6 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -9045,6 +9045,19 @@ nm_platform_ip_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatform /*****************************************************************************/ +guint16 +nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type) +{ + _CHECK_SELF(self, klass, 0); + + if (!_NM_INT_NOT_NEGATIVE(family_type) || family_type >= _NMP_GENL_FAMILY_TYPE_NUM) + g_return_val_if_reached(0); + + return klass->genl_get_family_id(self, family_type); +} + +/*****************************************************************************/ + GHashTable * nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex) { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index e940f43b60..984ad79cba 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -1328,6 +1328,9 @@ typedef struct { int (*tfilter_add)(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter); int (*tfilter_delete)(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error); + + guint16 (*genl_get_family_id)(NMPlatform *platform, NMPGenlFamilyType family_type); + } NMPlatformClass; /* NMPlatform signals @@ -2531,4 +2534,8 @@ gboolean nm_platform_ip_address_match(int addr_family, const NMPlatformIPAddress *addr, NMPlatformMatchFlags match_flag); +/*****************************************************************************/ + +guint16 nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type); + #endif /* __NETWORKMANAGER_PLATFORM_H__ */ From f40dcd65f75a2763c26966d4218b74ce5d79ba0e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 12 Jul 2022 20:06:10 +0200 Subject: [PATCH 10/13] platform: use new platform API to get genl family id for wireguard --- src/libnm-platform/nm-linux-platform.c | 64 ++++++++------------------ src/libnm-platform/nmp-object.c | 6 +-- src/libnm-platform/nmp-object.h | 5 -- 3 files changed, 19 insertions(+), 56 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 2ab0251c32..0e6f3c71e2 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -2493,7 +2493,7 @@ _wireguard_get_device_cb(struct nl_msg *msg, void *arg) static const NMPObject * _wireguard_read_info(NMPlatform *platform /* used only as logging context */, struct nl_sock *genl, - int wireguard_family_id, + guint16 wireguard_family_id, int ifindex) { nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -2507,10 +2507,12 @@ _wireguard_read_info(NMPlatform *platform /* used only as logging context */ guint i; nm_assert(genl); - nm_assert(wireguard_family_id >= 0); nm_assert(ifindex > 0); - _LOGT("wireguard: fetching information for ifindex %d (genl-id %d)...", + if (wireguard_family_id == 0) + return NULL; + + _LOGT("wireguard: fetching information for ifindex %d (genl-id %u)...", ifindex, wireguard_family_id); @@ -2623,25 +2625,8 @@ nla_put_failure: g_return_val_if_reached(NULL); } -static int -_wireguard_get_family_id(NMPlatform *platform, int ifindex_try) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - int wireguard_family_id = -1; - - if (ifindex_try > 0) { - const NMPlatformLink *plink; - - if (nm_platform_link_get_lnk_wireguard(platform, ifindex_try, &plink)) - wireguard_family_id = NMP_OBJECT_UP_CAST(plink)->_link.wireguard_family_id; - } - if (wireguard_family_id < 0) - wireguard_family_id = genl_ctrl_resolve(priv->sk_genl_sync, "wireguard"); - return wireguard_family_id; -} - static const NMPObject * -_wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifindex) +_wireguard_refresh_link(NMPlatform *platform, guint16 wireguard_family_id, int ifindex) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); nm_auto_nmpobj const NMPObject *obj_old = NULL; @@ -2651,7 +2636,7 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind const NMPObject *plink = NULL; nm_auto_nmpobj NMPObject *obj = NULL; - nm_assert(wireguard_family_id >= 0); + nm_assert(wireguard_family_id > 0); nm_assert(ifindex > 0); nm_platform_process_events(platform); @@ -2676,15 +2661,13 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind } } - if (plink->_link.wireguard_family_id == wireguard_family_id - && plink->_link.netlink.lnk == lnk_new) + if (plink->_link.netlink.lnk == lnk_new) return plink; /* we use nmp_cache_update_netlink() to re-inject the new object into the cache. * For that, we need to clone it, and tweak it so that it's suitable. It's a bit * of a hack, in particular that we need to clear driver and udev-device. */ - obj = nmp_object_clone(plink, FALSE); - obj->_link.wireguard_family_id = wireguard_family_id; + obj = nmp_object_clone(plink, FALSE); nmp_object_unref(obj->_link.netlink.lnk); obj->_link.netlink.lnk = g_steal_pointer(&lnk_new); obj->link.driver = NULL; @@ -2710,7 +2693,7 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind static int _wireguard_create_change_nlmsgs(NMPlatform *platform, int ifindex, - int wireguard_family_id, + guint16 wireguard_family_id, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, const NMPlatformWireGuardChangePeerFlags *peer_flags, @@ -2952,12 +2935,12 @@ link_wireguard_change(NMPlatform *platform, { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); gs_unref_ptrarray GPtrArray *msgs = NULL; - int wireguard_family_id; + guint16 wireguard_family_id; guint i; int r; - wireguard_family_id = _wireguard_get_family_id(platform, ifindex); - if (wireguard_family_id < 0) + wireguard_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_WIREGUARD); + if (wireguard_family_id == 0) return -NME_PL_NO_FIRMWARE; r = _wireguard_create_change_nlmsgs(platform, @@ -3337,22 +3320,11 @@ _new_from_nl_link(NMPlatform *platform, * notifications, so we don't actually update the cache. For * now, always refetch link data here. */ - _lookup_cached_link(cache, obj->link.ifindex, completed_from_cache, &link_cached); - if (link_cached && link_cached->_link.netlink.is_in_netlink - && link_cached->link.type == NM_LINK_TYPE_WIREGUARD) - obj->_link.wireguard_family_id = link_cached->_link.wireguard_family_id; - else - obj->_link.wireguard_family_id = -1; - - if (obj->_link.wireguard_family_id < 0) - obj->_link.wireguard_family_id = genl_ctrl_resolve(genl, "wireguard"); - - if (obj->_link.wireguard_family_id >= 0) { - lnk_data_new = _wireguard_read_info(platform, - genl, - obj->_link.wireguard_family_id, - obj->link.ifindex); - } + lnk_data_new = _wireguard_read_info( + platform, + genl, + nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_WIREGUARD), + obj->link.ifindex); if (lnk_data_new && obj->_link.netlink.lnk && nmp_object_equal(obj->_link.netlink.lnk, lnk_data_new)) diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index 99e2287691..d411043d0f 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -1149,10 +1149,7 @@ _vt_cmd_obj_hash_update_link(const NMPObject *obj, NMHashState *h) nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_LINK); nm_platform_link_hash_update(&obj->link, h); - nm_hash_update_vals(h, - obj->_link.netlink.is_in_netlink, - obj->_link.wireguard_family_id, - obj->_link.udev.device); + nm_hash_update_vals(h, obj->_link.netlink.is_in_netlink, obj->_link.udev.device); if (obj->_link.netlink.lnk) nmp_object_hash_update(obj->_link.netlink.lnk, h); } @@ -1232,7 +1229,6 @@ _vt_cmd_obj_cmp_link(const NMPObject *obj1, const NMPObject *obj2) NM_CMP_RETURN(nm_platform_link_cmp(&obj1->link, &obj2->link)); NM_CMP_DIRECT(obj1->_link.netlink.is_in_netlink, obj2->_link.netlink.is_in_netlink); NM_CMP_RETURN(nmp_object_cmp(obj1->_link.netlink.lnk, obj2->_link.netlink.lnk)); - NM_CMP_DIRECT(obj1->_link.wireguard_family_id, obj2->_link.wireguard_family_id); if (obj1->_link.udev.device != obj2->_link.udev.device) { if (!obj1->_link.udev.device) diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index d0c0463f13..7d2ebf979a 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -238,11 +238,6 @@ typedef struct { /* Auxiliary data object for Wi-Fi and WPAN */ GObject *ext_data; - - /* FIXME: not every NMPObjectLink should pay the price for tracking - * the wireguard family id. This should be tracked via ext_data, which - * would be exactly the right place. */ - int wireguard_family_id; } NMPObjectLink; typedef struct { From 36e6ac54509596c3d259dd0619142a92b34bf9dc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 12 Jul 2022 20:26:02 +0200 Subject: [PATCH 11/13] platform: use new platform API to get genl family id for nl80211/Wi-Fi --- src/libnm-platform/nm-linux-platform.c | 9 +++++---- .../wifi/nm-wifi-utils-nl80211.c | 20 +++++++++---------- .../wifi/nm-wifi-utils-nl80211.h | 2 +- src/libnm-platform/wifi/nm-wifi-utils.c | 6 +++--- src/libnm-platform/wifi/nm-wifi-utils.h | 3 ++- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 0e6f3c71e2..7dd831eca0 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -3296,10 +3296,11 @@ _new_from_nl_link(NMPlatform *platform, switch (obj->link.type) { case NM_LINK_TYPE_WIFI: case NM_LINK_TYPE_OLPC_MESH: - obj->_link.ext_data = - (GObject *) nm_wifi_utils_new(ifi->ifi_index, - NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, - TRUE); + obj->_link.ext_data = (GObject *) nm_wifi_utils_new( + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, + nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_NL80211), + ifi->ifi_index, + TRUE); break; case NM_LINK_TYPE_WPAN: obj->_link.ext_data = diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index 475b8a390a..bd56885ddd 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c @@ -46,9 +46,9 @@ typedef struct { NMWifiUtils parent; struct nl_sock *nl_sock; guint32 *freqs; - int id; int num_freqs; int phy; + guint16 genl_family_id; bool can_wowlan : 1; } NMWifiUtilsNl80211; @@ -83,12 +83,12 @@ error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) } static struct nl_msg * -_nl80211_alloc_msg(int id, int ifindex, int phy, guint32 cmd, guint32 flags) +_nl80211_alloc_msg(guint16 genl_family_id, int ifindex, int phy, guint32 cmd, guint32 flags) { nm_auto_nlmsg struct nl_msg *msg = NULL; msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, id, 0, flags, cmd, 0); + genlmsg_put(msg, 0, 0, genl_family_id, 0, flags, cmd, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (phy != -1) NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy); @@ -101,7 +101,7 @@ nla_put_failure: static struct nl_msg * nl80211_alloc_msg(NMWifiUtilsNl80211 *self, guint32 cmd, guint32 flags) { - return _nl80211_alloc_msg(self->id, self->parent.ifindex, self->phy, cmd, flags); + return _nl80211_alloc_msg(self->genl_family_id, self->parent.ifindex, self->phy, cmd, flags); } static int @@ -945,7 +945,7 @@ nm_wifi_utils_nl80211_class_init(NMWifiUtilsNl80211Class *klass) } NMWifiUtils * -nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl) +nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex) { gs_unref_object NMWifiUtilsNl80211 *self = NULL; nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -954,16 +954,14 @@ nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl) if (!genl) return NULL; + if (genl_family_id == 0) + return NULL; + self = g_object_new(NM_TYPE_WIFI_UTILS_NL80211, NULL); self->parent.ifindex = ifindex; self->nl_sock = genl; - - self->id = genl_ctrl_resolve(self->nl_sock, "nl80211"); - if (self->id < 0) { - _LOGD("genl_ctrl_resolve: failed to resolve \"nl80211\""); - return NULL; - } + self->genl_family_id = genl_family_id; self->phy = -1; diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h index 4a63330739..4783c572b4 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h @@ -24,6 +24,6 @@ GType nm_wifi_utils_nl80211_get_type(void); -NMWifiUtils *nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl); +NMWifiUtils *nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex); #endif /* __WIFI_UTILS_NL80211_H__ */ diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c index 08a8ec4ff3..0238b74aa9 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.c +++ b/src/libnm-platform/wifi/nm-wifi-utils.c @@ -32,16 +32,16 @@ nm_wifi_utils_class_init(NMWifiUtilsClass *klass) {} NMWifiUtils * -nm_wifi_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) +nm_wifi_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan) { NMWifiUtils *ret; g_return_val_if_fail(ifindex > 0, NULL); - ret = nm_wifi_utils_nl80211_new(ifindex, genl); + ret = nm_wifi_utils_nl80211_new(genl, genl_family_id, ifindex); #if HAVE_WEXT - if (ret == NULL) + if (!ret) ret = nm_wifi_utils_wext_new(ifindex, check_scan); #endif diff --git a/src/libnm-platform/wifi/nm-wifi-utils.h b/src/libnm-platform/wifi/nm-wifi-utils.h index 0d30c1a119..4dbeb21ff3 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.h +++ b/src/libnm-platform/wifi/nm-wifi-utils.h @@ -27,7 +27,8 @@ GType nm_wifi_utils_get_type(void); gboolean nm_wifi_utils_is_wifi(int dirfd, const char *ifname); -NMWifiUtils *nm_wifi_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan); +NMWifiUtils * +nm_wifi_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan); _NMDeviceWifiCapabilities nm_wifi_utils_get_caps(NMWifiUtils *data); From 9c349982811311a50e41caedfcad41a9c0d34e50 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 12 Jul 2022 20:26:02 +0200 Subject: [PATCH 12/13] platform: use new platform API to get genl family id for nl802154/wpan --- src/libnm-platform/nm-linux-platform.c | 9 +++++---- src/libnm-platform/wpan/nm-wpan-utils.c | 27 +++++++++++-------------- src/libnm-platform/wpan/nm-wpan-utils.h | 3 ++- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 7dd831eca0..cd4c4f9a97 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -3303,10 +3303,11 @@ _new_from_nl_link(NMPlatform *platform, TRUE); break; case NM_LINK_TYPE_WPAN: - obj->_link.ext_data = - (GObject *) nm_wpan_utils_new(ifi->ifi_index, - NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, - TRUE); + obj->_link.ext_data = (GObject *) nm_wpan_utils_new( + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, + nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_NL802154), + ifi->ifi_index, + TRUE); break; default: g_assert_not_reached(); diff --git a/src/libnm-platform/wpan/nm-wpan-utils.c b/src/libnm-platform/wpan/nm-wpan-utils.c index d9bbd0f0fa..8fa0003f60 100644 --- a/src/libnm-platform/wpan/nm-wpan-utils.c +++ b/src/libnm-platform/wpan/nm-wpan-utils.c @@ -37,9 +37,9 @@ struct NMWpanUtils { GObject parent; - int ifindex; struct nl_sock *nl_sock; - int id; + int ifindex; + guint16 genl_family_id; }; typedef struct { @@ -75,12 +75,12 @@ error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) } static struct nl_msg * -_nl802154_alloc_msg(int id, int ifindex, guint32 cmd, guint32 flags) +_nl802154_alloc_msg(guint16 genl_family_id, int ifindex, guint32 cmd, guint32 flags) { nm_auto_nlmsg struct nl_msg *msg = NULL; msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, id, 0, flags, cmd, 0); + genlmsg_put(msg, 0, 0, genl_family_id, 0, flags, cmd, 0); NLA_PUT_U32(msg, NL802154_ATTR_IFINDEX, ifindex); return g_steal_pointer(&msg); @@ -91,7 +91,7 @@ nla_put_failure: static struct nl_msg * nl802154_alloc_msg(NMWpanUtils *self, guint32 cmd, guint32 flags) { - return _nl802154_alloc_msg(self->id, self->ifindex, cmd, flags); + return _nl802154_alloc_msg(self->genl_family_id, self->ifindex, cmd, flags); } static int @@ -264,7 +264,7 @@ nm_wpan_utils_class_init(NMWpanUtilsClass *klass) {} NMWpanUtils * -nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) +nm_wpan_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan) { NMWpanUtils *self; @@ -273,16 +273,13 @@ nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) if (!genl) return NULL; - self = g_object_new(NM_TYPE_WPAN_UTILS, NULL); - self->ifindex = ifindex; - self->nl_sock = genl; - self->id = genl_ctrl_resolve(genl, "nl802154"); - - if (self->id < 0) { - _LOGD(LOGD_PLATFORM, "genl_ctrl_resolve: failed to resolve \"nl802154\""); - g_object_unref(self); + if (!genl_family_id) return NULL; - } + + self = g_object_new(NM_TYPE_WPAN_UTILS, NULL); + self->ifindex = ifindex; + self->nl_sock = genl; + self->genl_family_id = genl_family_id; return self; } diff --git a/src/libnm-platform/wpan/nm-wpan-utils.h b/src/libnm-platform/wpan/nm-wpan-utils.h index 6130c41e56..885d7195a8 100644 --- a/src/libnm-platform/wpan/nm-wpan-utils.h +++ b/src/libnm-platform/wpan/nm-wpan-utils.h @@ -23,7 +23,8 @@ typedef struct NMWpanUtils NMWpanUtils; GType nm_wpan_utils_get_type(void); -NMWpanUtils *nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan); +NMWpanUtils * +nm_wpan_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan); guint16 nm_wpan_utils_get_pan_id(NMWpanUtils *self); gboolean nm_wpan_utils_set_pan_id(NMWpanUtils *self, guint16 pan_id); From 19f14dbf37d4b024fc5d8ccdaa7aefc275a9bce2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 13 Jul 2022 11:26:00 +0200 Subject: [PATCH 13/13] platform/netlink: adjust integer types in netlink API - use proper integer types. A netlink message cannot be as large as size_t, because the length is tracked in an uint32_t. Use the right types. - fields like "nlmsg_type" or "nlmsg_flags" are uint16_t. Use the right types. - note that nlmsg_size() still returns and accepts "int". Maybe the should be adjusted too, but we use macros from kernel headers, which also use int. Even if that is not the type of the length on the binary protocol. So some of these functions still use int, to be closer and compatible with . --- src/libnm-platform/nm-linux-platform.c | 32 +++++---- src/libnm-platform/nm-netlink.c | 67 +++++++++++-------- src/libnm-platform/nm-netlink.h | 24 ++++--- .../wifi/nm-wifi-utils-nl80211.c | 6 +- src/libnm-platform/wpan/nm-wpan-utils.c | 6 +- 5 files changed, 77 insertions(+), 58 deletions(-) diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index cd4c4f9a97..185c9aed3e 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -4732,8 +4732,8 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_link_full(int nlmsg_type, - int nlmsg_flags, +_nl_msg_new_link_full(uint16_t nlmsg_type, + uint16_t nlmsg_flags, int ifindex, const char *ifname, guint8 family, @@ -4765,15 +4765,15 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_link(int nlmsg_type, int nlmsg_flags, int ifindex, const char *ifname) +_nl_msg_new_link(uint16_t nlmsg_type, uint16_t nlmsg_flags, int ifindex, const char *ifname) { return _nl_msg_new_link_full(nlmsg_type, nlmsg_flags, ifindex, ifname, AF_UNSPEC, 0, 0); } /* Copied and modified from libnl3's build_addr_msg(). */ static struct nl_msg * -_nl_msg_new_address(int nlmsg_type, - int nlmsg_flags, +_nl_msg_new_address(uint16_t nlmsg_type, + uint16_t nlmsg_flags, int family, int ifindex, gconstpointer address, @@ -4887,7 +4887,7 @@ ip_route_ignored_protocol(const NMPlatformIPRoute *route) /* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */ static struct nl_msg * -_nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) +_nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *obj) { nm_auto_nlmsg struct nl_msg *msg = NULL; const NMPClass *klass = NMP_OBJECT_GET_CLASS(obj); @@ -4914,7 +4914,7 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); nm_assert(NM_IN_SET(nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); - msg = nlmsg_alloc_simple(nlmsg_type, (int) nlmsgflags); + msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); if (nlmsg_append_struct(msg, &rtmsg) < 0) goto nla_put_failure; @@ -4998,7 +4998,9 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_routing_rule(int nlmsg_type, int nlmsg_flags, const NMPlatformRoutingRule *routing_rule) +_nl_msg_new_routing_rule(uint16_t nlmsg_type, + uint16_t nlmsg_flags, + const NMPlatformRoutingRule *routing_rule) { nm_auto_nlmsg struct nl_msg *msg = NULL; const guint8 addr_size = nm_utils_addr_family_to_size(routing_rule->addr_family); @@ -5111,7 +5113,7 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_qdisc(int nlmsg_type, int nlmsg_flags, const NMPlatformQdisc *qdisc) +_nl_msg_new_qdisc(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPlatformQdisc *qdisc) { nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *tc_options; @@ -5198,7 +5200,7 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_tfilter(int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tfilter) +_nl_msg_new_tfilter(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPlatformTfilter *tfilter) { nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *tc_options; @@ -9274,7 +9276,11 @@ qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) } static int -tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboolean log_error) +tc_delete(NMPlatform *platform, + uint16_t nlmsg_type, + int ifindex, + guint32 parent, + gboolean log_error) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; gs_free char *errmsg = NULL; @@ -9287,7 +9293,7 @@ tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboo .tcm_parent = parent, }; - switch (nlmsgtype) { + switch (nlmsg_type) { case RTM_DELQDISC: log_tag = "do-delete-qdisc"; break; @@ -9299,7 +9305,7 @@ tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboo log_tag = "do-delete-tc"; } - msg = nlmsg_alloc_simple(nlmsgtype, NMP_NLM_FLAG_F_ECHO); + msg = nlmsg_alloc_simple(nlmsg_type, NMP_NLM_FLAG_F_ECHO); if (nlmsg_append_struct(msg, &tcm) < 0) goto nla_put_failure; diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index f6b1d8b883..cb5bd4a896 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -38,7 +38,7 @@ struct nl_msg { struct sockaddr_nl nm_dst; struct ucred nm_creds; struct nlmsghdr *nm_nlh; - size_t nm_size; + uint32_t nm_size; bool nm_creds_has : 1; }; @@ -261,23 +261,26 @@ nlmsg_hdr(struct nl_msg *n) } void * -nlmsg_reserve(struct nl_msg *n, size_t len, int pad) +nlmsg_reserve(struct nl_msg *n, uint32_t len, uint32_t pad) { - char *buf = (char *) n->nm_nlh; - size_t nlmsg_len = n->nm_nlh->nlmsg_len; - size_t tlen; + char *buf = (char *) n->nm_nlh; + uint32_t tlen; - nm_assert(pad >= 0); + nm_assert(n); + nm_assert(pad == 0 || nm_utils_is_power_of_two(pad)); + nm_assert(n->nm_nlh->nlmsg_len <= n->nm_size); - if (len > n->nm_size) + if (pad != 0) { + tlen = (len + (pad - 1u)) & ~(pad - 1u); + if (tlen < len) + return NULL; + } else + tlen = len; + + if (tlen > n->nm_size - n->nm_nlh->nlmsg_len) return NULL; - tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; - - if ((tlen + nlmsg_len) > n->nm_size) - return NULL; - - buf += nlmsg_len; + buf += n->nm_nlh->nlmsg_len; n->nm_nlh->nlmsg_len += tlen; if (tlen > len) @@ -322,6 +325,8 @@ nlmsg_alloc_size(size_t len) if (len < sizeof(struct nlmsghdr)) len = sizeof(struct nlmsghdr); + else if (len > UINT32_MAX) + g_return_val_if_reached(NULL); nm = g_slice_new(struct nl_msg); *nm = (struct nl_msg){ @@ -359,7 +364,7 @@ nlmsg_alloc_convert(struct nlmsghdr *hdr) } struct nl_msg * -nlmsg_alloc_simple(int nlmsgtype, int flags) +nlmsg_alloc_simple(uint16_t nlmsgtype, uint16_t flags) { struct nl_msg *nm; struct nlmsghdr *new; @@ -384,20 +389,20 @@ nlmsg_free(struct nl_msg *msg) /*****************************************************************************/ int -nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad) +nlmsg_append(struct nl_msg *n, const void *data, uint32_t len, uint32_t pad) { void *tmp; nm_assert(n); - nm_assert(data); - nm_assert(len > 0); - nm_assert(pad >= 0); + nm_assert(len == 0 || data); tmp = nlmsg_reserve(n, len, pad); - if (tmp == NULL) + if (!tmp) return -ENOMEM; - memcpy(tmp, data, len); + if (len > 0) + memcpy(tmp, data, len); + return 0; } @@ -417,14 +422,17 @@ nlmsg_parse(const struct nlmsghdr *nlh, } struct nlmsghdr * -nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags) +nlmsg_put(struct nl_msg *n, + uint32_t pid, + uint32_t seq, + uint16_t type, + uint32_t payload, + uint16_t flags) { - struct nlmsghdr *nlh; + struct nlmsghdr *nlh = (struct nlmsghdr *) n->nm_nlh; - if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) - g_return_val_if_reached(NULL); + nm_assert(nlh->nlmsg_len >= NLMSG_HDRLEN); - nlh = (struct nlmsghdr *) n->nm_nlh; nlh->nlmsg_type = type; nlh->nlmsg_flags = flags; nlh->nlmsg_pid = pid; @@ -565,7 +573,8 @@ nla_nest_start(struct nl_msg *msg, int attrtype) static int _nest_end(struct nl_msg *msg, struct nlattr *start, int keep_empty) { - size_t pad, len; + size_t len; + uint32_t pad; len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start; @@ -734,9 +743,9 @@ void * genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, - int family, - int hdrlen, - int flags, + uint16_t family, + uint32_t hdrlen, + uint16_t flags, uint8_t cmd, uint8_t version) { diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index efc9585313..852c9c8f6d 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -60,7 +60,7 @@ struct nl_msg_lite { const struct sockaddr_nl *nm_dst; const struct ucred *nm_creds; const struct nlmsghdr *nm_nlh; - size_t nm_size; + uint32_t nm_size; }; /*****************************************************************************/ @@ -389,13 +389,13 @@ struct nl_msg *nlmsg_alloc_size(size_t max); struct nl_msg *nlmsg_alloc_convert(struct nlmsghdr *hdr); -struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags); +struct nl_msg *nlmsg_alloc_simple(uint16_t nlmsgtype, uint16_t flags); -void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad); +void *nlmsg_reserve(struct nl_msg *n, uint32_t len, uint32_t pad); -int nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad); +int nlmsg_append(struct nl_msg *n, const void *data, uint32_t len, uint32_t pad); -#define nlmsg_append_struct(n, data) nlmsg_append(n, (data), sizeof(*(data)), NLMSG_ALIGNTO) +#define nlmsg_append_struct(n, data) (nlmsg_append((n), (data), sizeof(*(data)), NLMSG_ALIGNTO)) void nlmsg_free(struct nl_msg *msg); @@ -502,8 +502,12 @@ int nlmsg_parse(const struct nlmsghdr *nlh, nlmsg_parse((nlh), (hdrlen), (tb), G_N_ELEMENTS(tb) - 1, (policy)); \ }) -struct nlmsghdr * -nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags); +struct nlmsghdr *nlmsg_put(struct nl_msg *n, + uint32_t pid, + uint32_t seq, + uint16_t type, + uint32_t payload, + uint16_t flags); /*****************************************************************************/ @@ -614,9 +618,9 @@ extern const struct nla_policy genl_ctrl_policy[8]; void *genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, - int family, - int hdrlen, - int flags, + uint16_t family, + uint32_t hdrlen, + uint16_t flags, uint8_t cmd, uint8_t version); void *genlmsg_data(const struct genlmsghdr *gnlh); diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index bd56885ddd..1875a42068 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c @@ -83,12 +83,12 @@ error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) } static struct nl_msg * -_nl80211_alloc_msg(guint16 genl_family_id, int ifindex, int phy, guint32 cmd, guint32 flags) +_nl80211_alloc_msg(guint16 genl_family_id, int ifindex, int phy, uint8_t cmd, uint16_t flags) { nm_auto_nlmsg struct nl_msg *msg = NULL; msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, genl_family_id, 0, flags, cmd, 0); + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family_id, 0, flags, cmd, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (phy != -1) NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy); @@ -99,7 +99,7 @@ nla_put_failure: } static struct nl_msg * -nl80211_alloc_msg(NMWifiUtilsNl80211 *self, guint32 cmd, guint32 flags) +nl80211_alloc_msg(NMWifiUtilsNl80211 *self, uint8_t cmd, uint16_t flags) { return _nl80211_alloc_msg(self->genl_family_id, self->parent.ifindex, self->phy, cmd, flags); } diff --git a/src/libnm-platform/wpan/nm-wpan-utils.c b/src/libnm-platform/wpan/nm-wpan-utils.c index 8fa0003f60..0afbe58d3e 100644 --- a/src/libnm-platform/wpan/nm-wpan-utils.c +++ b/src/libnm-platform/wpan/nm-wpan-utils.c @@ -75,12 +75,12 @@ error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) } static struct nl_msg * -_nl802154_alloc_msg(guint16 genl_family_id, int ifindex, guint32 cmd, guint32 flags) +_nl802154_alloc_msg(guint16 genl_family_id, int ifindex, uint8_t cmd, uint16_t flags) { nm_auto_nlmsg struct nl_msg *msg = NULL; msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, genl_family_id, 0, flags, cmd, 0); + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family_id, 0, flags, cmd, 0); NLA_PUT_U32(msg, NL802154_ATTR_IFINDEX, ifindex); return g_steal_pointer(&msg); @@ -89,7 +89,7 @@ nla_put_failure: } static struct nl_msg * -nl802154_alloc_msg(NMWpanUtils *self, guint32 cmd, guint32 flags) +nl802154_alloc_msg(NMWpanUtils *self, uint8_t cmd, uint16_t flags) { return _nl802154_alloc_msg(self->genl_family_id, self->ifindex, cmd, flags); }