diff --git a/include/haproxy/dns-t.h b/include/haproxy/dns-t.h index 428676a06..2a99bfbbf 100644 --- a/include/haproxy/dns-t.h +++ b/include/haproxy/dns-t.h @@ -42,6 +42,11 @@ #define DNS_TCP_MSG_MAX_SIZE 65535 #define DNS_TCP_MSG_RING_MAX_SIZE (1 + 1 + 3 + DNS_TCP_MSG_MAX_SIZE) // varint_bytes(DNS_TCP_MSG_MAX_SIZE) == 3 +/* threshold to consider that the link to dns server is failing + * and we should stop creating new sessions + */ +#define DNS_MAX_DSS_CONSECUTIVE_ERRORS 100 + /* DNS request or response header structure */ struct dns_header { uint16_t id; @@ -79,6 +84,7 @@ struct dns_additional_record { struct dns_stream_server { struct server *srv; struct dns_ring *ring_req; + int consecutive_errors; /* number of errors since last successful query (atomically updated without lock) */ int maxconn; int idle_conns; int cur_conns; diff --git a/src/dns.c b/src/dns.c index ce7c9a28b..c0494ae0d 100644 --- a/src/dns.c +++ b/src/dns.c @@ -578,6 +578,7 @@ static void dns_session_io_handler(struct appctx *appctx) LIST_APPEND(&ds->queries, &query->list); eb32_insert(&ds->query_ids, &query->qid); ds->onfly_queries++; + HA_ATOMIC_STORE(&ds->dss->consecutive_errors, 0); } /* update the tx_offset to handle output in 16k streams */ @@ -844,6 +845,7 @@ static void dns_session_release(struct appctx *appctx) { struct dns_session *ds = appctx->svcctx; struct dns_stream_server *dss __maybe_unused; + int consecutive_errors; if (!ds) return; @@ -906,6 +908,17 @@ static void dns_session_release(struct appctx *appctx) /* reset offset to be sure to start from message start */ ds->tx_msg_offset = 0; + consecutive_errors = HA_ATOMIC_LOAD(&ds->dss->consecutive_errors); + /* we know ds encountered an error because it failed to send all + * its queries: increase consecutive_errors (we take some precautions + * to prevent the counter from overflowing since it is atomically + * updated) + */ + while (consecutive_errors < DNS_MAX_DSS_CONSECUTIVE_ERRORS && + !HA_ATOMIC_CAS(&ds->dss->consecutive_errors, + &consecutive_errors, consecutive_errors + 1) && + __ha_cpu_relax()); + /* here the ofs and the attached counter * are kept unchanged */ @@ -1043,6 +1056,9 @@ struct dns_session *dns_session_new(struct dns_stream_server *dss) if (dss->maxconn && (dss->maxconn <= dss->cur_conns)) return NULL; + if (HA_ATOMIC_LOAD(&dss->consecutive_errors) >= DNS_MAX_DSS_CONSECUTIVE_ERRORS) + return NULL; + ds = pool_zalloc(dns_session_pool); if (!ds) return NULL;