From patchwork Fri Mar 13 10:49:55 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Lichtenheld X-Patchwork-Id: 4823 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:2755:b0:83c:d90d:321 with SMTP id j21csp1135647maq; Fri, 13 Mar 2026 03:50:26 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWF1toK4MUjUhPLVZPBMalkuYySFPeH+gig/rUwRFm+PmH7aZKAM4x6XGqFbPKn2jpiWnzoEriRtYo=@openvpn.net X-Received: by 2002:a05:7301:128a:b0:2ba:a1a5:b5b1 with SMTP id 5a478bee46e88-2bea5419e8emr1344086eec.7.1773399026246; Fri, 13 Mar 2026 03:50:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1773399026; cv=none; d=google.com; s=arc-20240605; b=J7eAkEPUFrqYiajfQoQcOJnRT2Na4NKEMDoX+02s3m9katZK1ib1uHpRqLhzqwG5xZ 3/Ybo44PQRDS13aInCMT5lnqj8arp/DfdTGF37zlspOUkMWeq9qyjdAjAZjaKe1b8EqR ZbJ8vlzJzn4+G1YnsLKgVZKXU0vaT1PtLX9uXMNaqvLtVknlm1wSqxK5+o84Voh/rBrP 9MOLmCJ/JzuZL4bZLiXzuScICn9X3hYbGYqiGI/O5rNIEdFtkq5kh/s334JRo8YRAFdM jDuhIAhXkVtk6Y+dOhL9VurBb5KYtZytYUu+K4kPUIeIiYyg/LEZjFDU3K4Y15t1zvq0 XnBQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:content-transfer-encoding:cc:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature:dkim-signature:dkim-signature; bh=RurqmADw/IBNsu58mzslRTztcbilFazneHvbell7QAU=; fh=CfxSpwd5kfiMJoL3kcov7PTxVKT7pGe/79idnx9XlBs=; b=SIbDdiRh4W56AhtVenUnSupcC+s1Ml6drvEEYJPnkVLC6MinAvNbBN0Bf6s9+lV+L/ a3GT0JstxG6E4ILol9U+1lWJDEFi8H9C4IQrFee3z5OL7HDOamvu5z1baobq0R23+RBS 7B0krXJPpoEh7gisx/FCoveaS/nyZ5oYboEui/M/THSEdFCQiR9JELDqy+D2qWeOPXcN +RwzWS3UIp1Cz6NLiue6t+fEHPqGJR1TIkqm0kmRG48JR81HvL7L3fU4GTVDo1thByau 1C1JF4kxPrroHbKQHv15CV6Jf4K20XpBXwTxC93Lsf5qN6aJAR0VqUxkLjzxrkYEKSyH c+YQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=fEfiKnjN; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=WGWySl3y; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=MqCLO+D4; dkim=neutral (body hash did not verify) header.i=@lichtenheld.com header.s=MBO0001 header.b=X4+2sSiW; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 5a478bee46e88-2beab593453si3540794eec.69.2026.03.13.03.50.25 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 13 Mar 2026 03:50:26 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=fEfiKnjN; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=WGWySl3y; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=MqCLO+D4; dkim=neutral (body hash did not verify) header.i=@lichtenheld.com header.s=MBO0001 header.b=X4+2sSiW; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type:Cc: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=RurqmADw/IBNsu58mzslRTztcbilFazneHvbell7QAU=; b=fEfiKnjNro/X7jFEuvh2Kp8ce2 5TiGODQmr6783Vyql2VW7wlrjtbLeApLT5dnmTV4qQNLLB/rk5w8xFlC9VShWmAa7X+Q6W7Hhfm1H yQNuYXXwWUxpkUG+QshrbbdVfkl89V5qpz9yifThZx9JWIu9kGCszw7jV1TzaZPeBGYo=; Received: from [127.0.0.1] (helo=sfs-ml-3.v29.lw.sourceforge.com) by sfs-ml-3.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1w1061-0008WC-3Z; Fri, 13 Mar 2026 10:50:21 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-3.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1w105s-0008Vz-NA for openvpn-devel@lists.sourceforge.net; Fri, 13 Mar 2026 10:50:12 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=EYnPYMV7JHSg/iy8wGKMqM16diobCrI0C0eG9IlUhkM=; b=WGWySl3y72IHUO0DY1rTMniMj1 clUM9IR0yI0+0i4MaT5rk74P4LOYgWFliZRtK7BU/n46CclBNGnawz+m93hNPOcoMdk73f8/a+lab Xt1CMR2w2ChOXldTeVs5S6+UIBfmvN1KlFJBMTWmpVPa2YF5iDbPOt6JFxV/9ogRy8jU=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=EYnPYMV7JHSg/iy8wGKMqM16diobCrI0C0eG9IlUhkM=; b=MqCLO+D4BnljZO2wLGY46OBpI9 GMUDAPds3WO0OxkhFiCSLI6jST3bReuXTmD2IY2iMx3oYdt5fgCelqP4ZtePmEiQUkuafqzUrTj0O NKs37uFlbaF+2/lJCkUuc24o6iDlFPa/n7NsbqgxYPBIcV2vKqaQswOXon5tG4U67TE4=; Received: from mout-p-202.mailbox.org ([80.241.56.172]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1w105r-0004A0-B8 for openvpn-devel@lists.sourceforge.net; Fri, 13 Mar 2026 10:50:12 +0000 Received: from smtp2.mailbox.org (smtp2.mailbox.org [IPv6:2001:67c:2050:b231:465::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-202.mailbox.org (Postfix) with ESMTPS id 4fXLpt0fwXz9tmS; Fri, 13 Mar 2026 11:49:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lichtenheld.com; s=MBO0001; t=1773398998; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EYnPYMV7JHSg/iy8wGKMqM16diobCrI0C0eG9IlUhkM=; b=X4+2sSiWZy+xsRzOTtwpaMKgWAY7ukE6ZuPEN7RpYWRd+bwwwh9J2TjxAHc6vhQjTDg1Zg rFuHumlu+bVMdKnMINA64XKRAiNLInNhJBZToZ66DkniLRpZYzXUSMUhJyk9C2rG2WU+xv FudrhGIB+fNuzbnIyqE+Tfjea9Yxh2a6pbTEgOxjuREcprM+y4BzoVrlrHB9Ajk75ZNlyl Llz8oTIXl689ixIFhXhGKG2FyOLwPmKIpXrK9FxWieisgVagsKVNTzYiY6eF+4HhotKYcY +WtbT2FY8lO5iul18y+D8iSBPTumPQ4xUpwANiMK5zo0mCfCUtHNA/aaEgBv3A== Authentication-Results: outgoing_mbo_mout; dkim=none; spf=pass (outgoing_mbo_mout: domain of frank@lichtenheld.com designates 2001:67c:2050:b231:465::2 as permitted sender) smtp.mailfrom=frank@lichtenheld.com From: Frank Lichtenheld To: openvpn-devel@lists.sourceforge.net Date: Fri, 13 Mar 2026 11:49:55 +0100 Message-ID: <20260313104955.16748-1-frank@lichtenheld.com> In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 4fXLpt0fwXz9tmS X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-2.hosts.colo.sdot.me", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Arne Schwabe The multi_context->iter is basically a hash with only one bucket. This makes m->iter a linear list. Instead of maintaining this extra list use m->instances instead. This is a fixed sized continuous ar [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-Headers-End: 1w105r-0004A0-B8 Subject: [Openvpn-devel] [PATCH v5] Remove multi_context->iter X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Arne Schwabe Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1858931326488346636?= X-GMAIL-MSGID: =?utf-8?q?1859543657024409200?= From: Arne Schwabe The multi_context->iter is basically a hash with only one bucket. This makes m->iter a linear list. Instead of maintaining this extra list use m->instances instead. This is a fixed sized continuous array, so iterating over it should be very quick. When the number of connected clients approaches max_clients, iterating over a static array should be faster than a linked list, especially when considering cache locality. Of the several places where m->iter is used only one is potentially on a critical path: the usage of m->iter in multi_bcast. However this performance difference would be only visible with a lightly loaded server with very few clients. And even in this scenario I could not manage to measure a difference. Change-Id: Ibf8865e451866e1fffc8dbc8ad5ecf6bc5577ce4 Signed-off-by: Arne Schwabe Acked-by: Frank Lichtenheld Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1556 --- This change was reviewed on Gerrit and approved by at least one developer. I request to merge it to master. Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1556 This mail reflects revision 5 of this Change. Signed-off-by line for the author was added as per our policy. Acked-by according to Gerrit (reflected above): Frank Lichtenheld diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 1625fd0..9d4ea49 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -300,14 +300,6 @@ m->vhash = hash_init(t->options.virtual_hash_size, (uint32_t)get_random(), mroute_addr_hash_function, mroute_addr_compare_function); - /* - * This hash table is a clone of m->hash but with a - * bucket size of one so that it can be used - * for fast iteration through the list. - */ - m->iter = hash_init(1, (uint32_t)get_random(), mroute_addr_hash_function, - mroute_addr_compare_function); - #ifdef ENABLE_MANAGEMENT m->cid_hash = hash_init(t->options.real_hash_size, 0, cid_hash_function, cid_compare_function); #endif @@ -591,10 +583,6 @@ { ASSERT(hash_remove(m->hash, &mi->real)); } - if (mi->did_iter) - { - ASSERT(hash_remove(m->iter, &mi->real)); - } #ifdef ENABLE_MANAGEMENT if (mi->did_cid_hash) { @@ -664,23 +652,19 @@ { if (m->hash) { - struct hash_iterator hi; - struct hash_element *he; - - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + for (int i = 0; i < m->max_clients; i++) { - struct multi_instance *mi = (struct multi_instance *)he->value; - mi->did_iter = false; - multi_close_instance(m, mi, true); + struct multi_instance *mi = m->instances[i]; + if (mi) + { + multi_close_instance(m, mi, true); + } } - hash_iterator_free(&hi); multi_reap_all(m); hash_free(m->hash); hash_free(m->vhash); - hash_free(m->iter); #ifdef ENABLE_MANAGEMENT hash_free(m->cid_hash); #endif @@ -760,14 +744,6 @@ generate_prefix(mi); } - if (!hash_add(m->iter, &mi->real, mi, false)) - { - msg(D_MULTI_LOW, "MULTI: unable to add real address [%s] to iterator hash table", - mroute_addr_print(&mi->real, &gc)); - goto err; - } - mi->did_iter = true; - #ifdef ENABLE_MANAGEMENT do { @@ -1348,27 +1324,21 @@ const char *new_cn = tls_common_name(new_mi->context.c2.tls_multi, true); if (new_cn) { - struct hash_iterator hi; - struct hash_element *he; int count = 0; - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + for (int i = 0; i < m->max_clients; i++) { - struct multi_instance *mi = (struct multi_instance *)he->value; - if (mi != new_mi && !mi->halt) + struct multi_instance *mi = m->instances[i]; + if (mi && mi != new_mi && !mi->halt) { const char *cn = tls_common_name(mi->context.c2.tls_multi, true); if (cn && !strcmp(cn, new_cn)) { - mi->did_iter = false; multi_close_instance(m, mi, false); - hash_iterator_delete_element(&hi); ++count; } } } - hash_iterator_free(&hi); if (count) { @@ -2906,9 +2876,6 @@ multi_bcast(struct multi_context *m, const struct buffer *buf, const struct multi_instance *sender_instance, uint16_t vid) { - struct hash_iterator hi; - struct hash_element *he; - struct multi_instance *mi; struct mbuf_buffer *mb; if (BLEN(buf) > 0) @@ -2917,12 +2884,12 @@ printf("BCAST len=%d\n", BLEN(buf)); #endif mb = mbuf_alloc_buf(buf); - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + for (int i = 0; i < m->max_clients; i++) { - mi = (struct multi_instance *)he->value; - if (mi != sender_instance && !mi->halt) + struct multi_instance *mi = m->instances[i]; + + if (mi && mi != sender_instance && !mi->halt) { if (vid != 0 && vid != mi->context.options.vlan_pvid) { @@ -2931,8 +2898,6 @@ multi_add_mbuf(m, mi, mb); } } - - hash_iterator_free(&hi); mbuf_free_buf(mb); } } @@ -3182,7 +3147,6 @@ /* remove old address from hash table before changing address */ ASSERT(hash_remove(m->hash, &mi->real)); - ASSERT(hash_remove(m->iter, &mi->real)); /* change external network address of the remote peer */ mi->real = real; @@ -3198,7 +3162,6 @@ tls_update_remote_addr(mi->context.c2.tls_multi, &mi->context.c2.from); ASSERT(hash_add(m->hash, &mi->real, mi, false)); - ASSERT(hash_add(m->iter, &mi->real, mi, false)); #ifdef ENABLE_MANAGEMENT ASSERT(hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); @@ -3830,22 +3793,17 @@ static void multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) { - struct hash_iterator hi; - struct hash_element *he; - /* tell all clients to restart */ - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + for (int i = 0; i < m->max_clients; i++) { - struct multi_instance *mi = (struct multi_instance *)he->value; - if (!mi->halt && proto_is_dgram(mi->context.c2.link_sockets[0]->info.proto)) + struct multi_instance *mi = m->instances[i]; + if (mi && !mi->halt && proto_is_dgram(mi->context.c2.link_sockets[0]->info.proto)) { send_control_channel_string(&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); multi_schedule_context_wakeup(m, mi); } } - hash_iterator_free(&hi); /* reschedule signal */ ASSERT(!openvpn_gettimeofday(&m->deferred_shutdown_signal.wakeup, NULL)); @@ -3916,15 +3874,12 @@ management_callback_kill_by_cn(void *arg, const char *del_cn) { struct multi_context *m = (struct multi_context *)arg; - struct hash_iterator hi; - struct hash_element *he; int count = 0; - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + for (int i = 0; i < m->max_clients; i++) { - struct multi_instance *mi = (struct multi_instance *)he->value; - if (!mi->halt) + struct multi_instance *mi = m->instances[i]; + if (mi && !mi->halt) { const char *cn = tls_common_name(mi->context.c2.tls_multi, false); if (cn && !strcmp(cn, del_cn)) @@ -3934,7 +3889,6 @@ } } } - hash_iterator_free(&hi); return count; } @@ -3942,8 +3896,6 @@ management_callback_kill_by_addr(void *arg, const in_addr_t addr, const uint16_t port, const uint8_t proto) { struct multi_context *m = (struct multi_context *)arg; - struct hash_iterator hi; - struct hash_element *he; struct openvpn_sockaddr saddr; struct mroute_addr maddr; int count = 0; @@ -3955,17 +3907,15 @@ maddr.proto = proto; if (mroute_extract_openvpn_sockaddr(&maddr, &saddr, true)) { - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + for (int i = 0; i < m->max_clients; i++) { - struct multi_instance *mi = (struct multi_instance *)he->value; - if (!mi->halt && mroute_addr_equal(&maddr, &mi->real)) + struct multi_instance *mi = m->instances[i]; + if (mi && !mi->halt && mroute_addr_equal(&maddr, &mi->real)) { multi_signal_instance(m, mi, SIGTERM); ++count; } } - hash_iterator_free(&hi); } return count; } diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index c686e47..498409d 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -132,7 +132,6 @@ struct in6_addr reporting_addr_ipv6; /* IPv6 address in status listing */ bool did_real_hash; - bool did_iter; #ifdef ENABLE_MANAGEMENT bool did_cid_hash; struct buffer_list *cc_config; @@ -168,9 +167,6 @@ * address of the remote peer. */ struct hash *vhash; /**< VPN tunnel instances indexed by * virtual address of remote hosts. */ - struct hash *iter; /**< VPN tunnel instances indexed by real - * address of the remote peer, optimized - * for iteration. */ struct schedule *schedule; struct mbuf_set *mbuf; /**< Set of buffers for passing data * channel packets between VPN tunnel diff --git a/src/openvpn/push_util.c b/src/openvpn/push_util.c index 51c7b5f..6456554 100644 --- a/src/openvpn/push_util.c +++ b/src/openvpn/push_util.c @@ -316,15 +316,12 @@ } int count = 0; - struct hash_iterator hi; - const struct hash_element *he; - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + for (int i = 0; i < m->max_clients; i++) { - struct multi_instance *curr_mi = he->value; + struct multi_instance *curr_mi = m->instances[i]; - if (curr_mi->halt || !support_push_update(curr_mi)) + if (!curr_mi || curr_mi->halt || !support_push_update(curr_mi)) { continue; } @@ -338,7 +335,6 @@ count++; } - hash_iterator_free(&hi); buffer_list_free(msgs); gc_free(&gc); return count;