From 4db7cb37bd033d91fb12ea96b7cf32968d052f32 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 1 Dec 2023 14:17:58 +0900 Subject: [PATCH 1/4] sd-netlink: change error code of the case that too many replies waiting ERANGE should be used when setting or parsing a number. --- src/libsystemd/sd-netlink/sd-netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 898f11d1abb..8b5c47366e8 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -477,7 +477,7 @@ int sd_netlink_call_async( assert_return(!netlink_pid_changed(nl), -ECHILD); if (hashmap_size(nl->reply_callbacks) >= REPLY_CALLBACKS_MAX) - return -ERANGE; + return -EXFULL; r = hashmap_ensure_allocated(&nl->reply_callbacks, &trivial_hash_ops); if (r < 0) From 4256379d99ce74ecddcdf9725e896e093e6a4d6c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 30 Nov 2023 19:04:37 +0900 Subject: [PATCH 2/4] sd-netlink: introduce netlink_get_reply_callback_count() --- src/libsystemd/sd-netlink/netlink-util.h | 2 ++ src/libsystemd/sd-netlink/sd-netlink.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 2f9f7e96766..369f5d50e47 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -107,5 +107,7 @@ int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, O void netlink_seal_message(sd_netlink *nl, sd_netlink_message *m); +size_t netlink_get_reply_callback_count(sd_netlink *nl); + /* TODO: to be exported later */ int sd_netlink_sendv(sd_netlink *nl, sd_netlink_message **messages, size_t msgcnt, uint32_t **ret_serial); diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 8b5c47366e8..b6730b71dc1 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -458,6 +458,12 @@ static int timeout_compare(const void *a, const void *b) { return CMP(x->timeout, y->timeout); } +size_t netlink_get_reply_callback_count(sd_netlink *nl) { + assert(nl); + + return hashmap_size(nl->reply_callbacks); +} + int sd_netlink_call_async( sd_netlink *nl, sd_netlink_slot **ret_slot, From b3a4f4f06d306643a5e1d6a202d516b4f658e3ce Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 1 Dec 2023 14:36:30 +0900 Subject: [PATCH 3/4] firewall-util: introduce fw_ctx_get_reply_callback_count() --- src/shared/firewall-util.c | 8 ++++++++ src/shared/firewall-util.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index 764ef5a0189..e96b24a72d8 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -8,6 +8,7 @@ #include "firewall-util.h" #include "firewall-util-private.h" #include "log.h" +#include "netlink-util.h" #include "string-table.h" static const char * const firewall_backend_table[_FW_BACKEND_MAX] = { @@ -90,6 +91,13 @@ FirewallContext *fw_ctx_free(FirewallContext *ctx) { return mfree(ctx); } +size_t fw_ctx_get_reply_callback_count(FirewallContext *ctx) { + if (!ctx || !ctx->nfnl) + return 0; + + return netlink_get_reply_callback_count(ctx->nfnl); +} + int fw_add_masquerade( FirewallContext **ctx, bool add, diff --git a/src/shared/firewall-util.h b/src/shared/firewall-util.h index 1e25a82a543..14e35bec8d6 100644 --- a/src/shared/firewall-util.h +++ b/src/shared/firewall-util.h @@ -15,6 +15,8 @@ FirewallContext *fw_ctx_free(FirewallContext *ctx); DEFINE_TRIVIAL_CLEANUP_FUNC(FirewallContext *, fw_ctx_free); +size_t fw_ctx_get_reply_callback_count(FirewallContext *ctx); + int fw_add_masquerade( FirewallContext **ctx, bool add, From 4e6a35e2b2fad0f167a71b63525f4210bc858bc6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 30 Nov 2023 19:07:36 +0900 Subject: [PATCH 4/4] network: do not send too many netlink messages in a single event Fixes #26743. --- src/network/networkd-queue.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c index 90caefbc72c..1695aacf765 100644 --- a/src/network/networkd-queue.c +++ b/src/network/networkd-queue.c @@ -7,6 +7,8 @@ #include "networkd-queue.h" #include "string-table.h" +#define REPLY_CALLBACK_COUNT_THRESHOLD 128 + static Request *request_free(Request *req) { if (!req) return NULL; @@ -220,6 +222,13 @@ int manager_process_requests(sd_event_source *s, void *userdata) { if (req->waiting_reply) continue; /* Waiting for netlink reply. */ + /* Typically, requests send netlink message asynchronously. If there are many requests + * queued, then this event may make reply callback queue in sd-netlink full. */ + if (netlink_get_reply_callback_count(manager->rtnl) >= REPLY_CALLBACK_COUNT_THRESHOLD || + netlink_get_reply_callback_count(manager->genl) >= REPLY_CALLBACK_COUNT_THRESHOLD || + fw_ctx_get_reply_callback_count(manager->fw_ctx) >= REPLY_CALLBACK_COUNT_THRESHOLD) + return 0; + r = req->process(req, link, req->userdata); if (r == 0) continue;