#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;
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;
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 */
{
struct dns_session *ds = appctx->svcctx;
struct dns_stream_server *dss __maybe_unused;
+ int consecutive_errors;
if (!ds)
return;
/* 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
*/
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;