From 27236f2218e57d839197e5b6479dc8e67e484e32 Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Tue, 29 Apr 2025 20:13:00 +0200 Subject: [PATCH] BUG/MINOR: dns: add tempo between 2 connection attempts for dns servers As reported by Lukas Tribus on the mailing list [1], trying to connect to a nameserver with invalid network settings causes haproxy to retry a new connection attempt immediately which eventually causes unexpected CPU usage on the thread responsible for the applet (namely 100% on one CPU will be observed). This can be reproduced with the test config below: resolvers default nameserver ns1 tcp4@8.8.8.8:53 source 192.168.99.99 listen listen mode http bind :8080 server s1 www.google.com resolvers default init-addr none To fix this the issue, we add a temporisation of one second between a new connection attempt is retried. We do this in dns_session_create() when we know that the applet was created in the release callback (when previous query attempt was unsuccessful), which means initial connection is not affected. [1]: https://www.mail-archive.com/haproxy@formilux.org/msg45665.html This should fix GH #2909 and may be backported to all stable versions. This patch depends on ("MINOR: applet: add appctx_schedule() macro") --- src/dns.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/dns.c b/src/dns.c index 14c811a108..ce7c9a28be 100644 --- a/src/dns.c +++ b/src/dns.c @@ -806,7 +806,7 @@ void dns_session_free(struct dns_session *ds) pool_free(dns_session_pool, ds); } -static struct appctx *dns_session_create(struct dns_session *ds); +static struct appctx *dns_session_create(struct dns_session *ds, int tempo); static int dns_session_init(struct appctx *appctx) { @@ -912,7 +912,7 @@ static void dns_session_release(struct appctx *appctx) /* Create a new appctx, We hope we can * create from the release callback! */ - ds->appctx = dns_session_create(ds); + ds->appctx = dns_session_create(ds, 1); if (!ds->appctx) { dns_session_free(ds); HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock); @@ -937,8 +937,10 @@ static struct applet dns_session_applet = { /* * Function used to create an appctx for a DNS session * It sets its context into appctx->svcctx. + * if is set, then the session startup will be delayed by 1 + * second */ -static struct appctx *dns_session_create(struct dns_session *ds) +static struct appctx *dns_session_create(struct dns_session *ds, int tempo) { struct appctx *appctx; @@ -947,10 +949,14 @@ static struct appctx *dns_session_create(struct dns_session *ds) goto out_close; appctx->svcctx = (void *)ds; - if (appctx_init(appctx) == -1) { - ha_alert("out of memory in dns_session_create().\n"); - goto out_free_appctx; + if (!tempo) { + if (appctx_init(appctx) == -1) { + ha_alert("out of memory in dns_session_create().\n"); + goto out_free_appctx; + } } + else + appctx_schedule(appctx, tick_add(now_ms, MS_TO_TICKS(1000))); return appctx; @@ -1072,7 +1078,7 @@ struct dns_session *dns_session_new(struct dns_stream_server *dss) ds->task_exp->process = dns_process_query_exp; ds->task_exp->context = ds; - ds->appctx = dns_session_create(ds); + ds->appctx = dns_session_create(ds, 0); if (!ds->appctx) goto error; -- 2.47.2