From patchwork Fri Mar 6 16:37:18 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gert Doering X-Patchwork-Id: 4808 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7001:a68f:b0:83c:d90d:321 with SMTP id wf15csp1678275mab; Fri, 6 Mar 2026 08:37:42 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCV+7W0ZQIbS3T2zN53fLobhALS+VVftakfzqz1cvOn8BlPRp0MzNnYL2PYvM1xDp5Hh5y0uG4t2x+o=@openvpn.net X-Received: by 2002:a05:6820:1508:b0:67b:8da7:5965 with SMTP id 006d021491bc7-67b944dcf2dmr3931129eaf.16.1772815062462; Fri, 06 Mar 2026 08:37:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1772815062; cv=none; d=google.com; s=arc-20240605; b=gVy7TyIbjE+ZsgL3iouU7ERIgDPJ5FU9pdDzITeeINSekO9M2RuZpW7mfOdlNW9P8m f10kOYWOGMMVaWFo1DRdM0aDsP1ig+jjMT7PRgraGh2XkdwSLUoG8Uo6oW+VUTZd/wkH eS4L3//ULt2Lhg9azglcv5Y7ISFI0W5565s2S3eQXQ5HTuFp2vnnxABmfKFpP6qZsk7o WVuCNCfkPujIhzGXeaqbY+pvxGOtwgmB2HIJVHt2EbMikbjuF1yOF6dxNSeFZEk+59Ky NLTjhztY+N5oicXd1fivPHFjuVFZmHA+OqQS2Tn0UO/8MaoBG6nCb7wI6iwN4TTfclT3 yEQA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:content-transfer-encoding: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; bh=QXHI7Kg9hCPvKWVmLEun9f/GJn0Swdw2+aMXp+tBxHI=; fh=4NbAC/LsuMLI0S0hprUlLSLCiHwg6SCAifhH718Jh0Q=; b=WY4a0r5YmDFXUF4P0hZv/hCjr9EDWZoIGXl1H46khz/AhnJi4CQ+JMygi5F4ehaVHK MFq+tq9FulJwliB2sJ3WDpRw7rACSatcEjJqDUyPZ35dXZJR+Wh1olehBu1t2dj4xI/A ILbMvea5PkgALC4EWA2/9nF8m1K6tPBDGn9BEjo5GfS42s8G4T12GZdLDdOj1o2jA0k7 YSA/9Tevnu5VJ/7wsDX0yF3+SFPjGPHz/Y07C3xvWgUW/kgSMOSIUr/5V9oZGvIQ9QQ0 5haF+DzMBsCjLYzZ0smm7c81V8OUGx9Jr9EO4EWna0LI6KqsPOYfar+4zTWRDwBx62em k4vA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=IguFlrmW; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=RGPS6mqr; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=O3WU8Y6Y; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 586e51a60fabf-416e65af94dsi1621881fac.85.2026.03.06.08.37.42 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 06 Mar 2026 08:37:42 -0800 (PST) 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=IguFlrmW; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=RGPS6mqr; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=O3WU8Y6Y; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=muc.de 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: 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:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=QXHI7Kg9hCPvKWVmLEun9f/GJn0Swdw2+aMXp+tBxHI=; b=IguFlrmWqpwet6sHOtTD94UH02 3QZbbkKiJxEcGVQH/GKe2IHt6lRxO5OelYwA65GQcAUiz7KSRugV3uySh78StKEgTEZaAQhHkNlfE K+OJ97lWTXypIz8vHEhz6Iv1GuU3KBB6jGuPTziI8PqT8jiuswFeoPe2tWjOrUiCocAo=; 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 1vyYBH-0003CV-0g; Fri, 06 Mar 2026 16:37:39 +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 1vyYBF-0003CO-FW for openvpn-devel@lists.sourceforge.net; Fri, 06 Mar 2026 16:37:37 +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:To:From:Sender:Reply-To:Cc: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=49jMfUr/2rg63Y+RHS4vQQCxuDMZV1odA+ZBhlr2Roo=; b=RGPS6mqrMrkaxj5h3XBJkLfLE9 uohihKmcQIhYcp8Y3AlBhiHuPTpvSGDML0ypgH6jWMcFVY1eXCW0i+sZy3befyWfIgRa9n+s+9Z3P EboK7k7srOVcJMAr/3k5vm4um6XhPgh/H6LnNXtx8RoqyHz95EKPqpzUXWU04yGkgVyI=; 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:To:From:Sender:Reply-To:Cc: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=49jMfUr/2rg63Y+RHS4vQQCxuDMZV1odA+ZBhlr2Roo=; b=O3WU8Y6YkVuiIHf98lKW2l8UdV NBnEOkl/VCouS+RQZR5z2d3Mf8Hy9KEkVEZ6aiuS1rPkmjoxi1QOVgbPe5vvoVLHZHXt75KBbfBX1 8Pf0V0D+qZOirM99HOgAQYiDSEgF/X+6gkPEsQG/v+RG0B5Mgez/htkJLGAT/N61mp84=; Received: from [193.149.48.129] (helo=blue.greenie.muc.de) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1vyYBE-0006Ku-92 for openvpn-devel@lists.sourceforge.net; Fri, 06 Mar 2026 16:37:37 +0000 Received: from blue.greenie.muc.de (localhost [127.0.0.1]) by blue.greenie.muc.de (8.18.1/8.18.1) with ESMTP id 626GbOuS003060 for ; Fri, 6 Mar 2026 17:37:24 +0100 Received: (from gert@localhost) by blue.greenie.muc.de (8.18.1/8.18.1/Submit) id 626GbOFM003059 for openvpn-devel@lists.sourceforge.net; Fri, 6 Mar 2026 17:37:24 +0100 From: Gert Doering To: openvpn-devel@lists.sourceforge.net Date: Fri, 6 Mar 2026 17:37:18 +0100 Message-ID: <20260306163724.3042-1-gert@greenie.muc.de> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Score: 1.3 (+) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-1.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: (1.3 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 1.3 RDNS_NONE Delivered to internal network by a host with no rDNS X-Headers-End: 1vyYBE-0006Ku-92 Subject: [Openvpn-devel] [PATCH v2] 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: , 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?1858931326488346636?= 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 2 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;