diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl
index 359c2d99e4..bc018c0093 100644
--- a/bin/named/bind9.xsl
+++ b/bin/named/bind9.xsl
@@ -941,6 +941,52 @@
+
+
+ Incoming Queries Response Time for View
+
+
+ | Milliseconds |
+ Count |
+
+
+
+
+ even
+ odd
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ Outgoing Queries Response Time for View
+
+
+ | Milliseconds |
+ Count |
+
+
+
+
+ even
+ odd
+
+
+
+ |
+ |
+
+
+
+
+
Memory Usage Summary
diff --git a/bin/named/server.c b/bin/named/server.c
index 85e8c68652..160e3d5990 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -3678,6 +3678,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
const cfg_obj_t *disablelist = NULL;
isc_stats_t *resstats = NULL;
dns_stats_t *resquerystats = NULL;
+ isc_histomulti_t *resqueryinrttstats = NULL;
+ isc_histomulti_t *resqueryoutrttstats = NULL;
bool auto_root = false;
named_cache_t *nsc = NULL;
bool zero_no_soattl;
@@ -4259,6 +4261,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
dns_resolver_getstats(pview->resolver, &resstats);
dns_resolver_getquerystats(pview->resolver,
&resquerystats);
+ dns_resolver_getqueryrttstats(pview->resolver,
+ &resqueryinrttstats,
+ &resqueryoutrttstats);
dns_view_detach(&pview);
}
}
@@ -4319,11 +4324,23 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
}
dns_resolver_setstats(view->resolver, resstats);
+
if (resquerystats == NULL) {
dns_rdatatypestats_create(mctx, &resquerystats);
}
dns_resolver_setquerystats(view->resolver, resquerystats);
+ if (resqueryinrttstats == NULL) {
+ isc_histomulti_create(mctx, DNS_RTTHISTO_SIGBITS,
+ &resqueryinrttstats);
+ }
+ if (resqueryoutrttstats == NULL) {
+ isc_histomulti_create(mctx, DNS_RTTHISTO_SIGBITS,
+ &resqueryoutrttstats);
+ }
+ dns_resolver_setqueryrttstats(view->resolver, resqueryinrttstats,
+ resqueryoutrttstats);
+
/*
* Set the ADB cache size to 1/8th of the max-cache-size or
* MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
@@ -5487,6 +5504,12 @@ cleanup:
if (resquerystats != NULL) {
dns_stats_detach(&resquerystats);
}
+ if (resqueryinrttstats != NULL) {
+ isc_histomulti_detach(&resqueryinrttstats);
+ }
+ if (resqueryoutrttstats != NULL) {
+ isc_histomulti_detach(&resqueryoutrttstats);
+ }
if (order != NULL) {
dns_order_detach(&order);
}
diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c
index 51184ffe44..08020fd494 100644
--- a/bin/named/statschannel.c
+++ b/bin/named/statschannel.c
@@ -164,6 +164,8 @@ static const char *tcpinsizestats_xmldesc[dns_sizecounter_in_max];
static const char *tcpoutsizestats_xmldesc[dns_sizecounter_out_max];
static const char *dnstapstats_xmldesc[dns_dnstapcounter_max];
static const char *gluecachestats_xmldesc[dns_gluecachestatscounter_max];
+static const char *queryrttinstats_xmldesc[dns_queryrttcounter_in_max];
+static const char *queryrttoutstats_xmldesc[dns_queryrttcounter_in_max];
#else /* if defined(EXTENDED_STATS) */
#define nsstats_xmldesc NULL
#define resstats_xmldesc NULL
@@ -203,6 +205,8 @@ static int tcpinsizestats_index[dns_sizecounter_in_max];
static int tcpoutsizestats_index[dns_sizecounter_out_max];
static int dnstapstats_index[dns_dnstapcounter_max];
static int gluecachestats_index[dns_gluecachestatscounter_max];
+static int queryrttinstats_index[dns_queryrttcounter_in_max];
+static int queryrttoutstats_index[dns_queryrttcounter_out_max];
static void
set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
@@ -223,7 +227,7 @@ set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
}
static const char *
-get_histo_desc(const char *prefix, int i, int inf, bool ext) {
+get_sizehisto_desc(const char *prefix, int i, int inf, bool ext) {
static char buf[(DNS_SIZEHISTO_MAXIN + DNS_SIZEHISTO_MAXOUT) * 80];
static size_t used = 0;
char *desc = buf + used;
@@ -246,6 +250,51 @@ get_histo_desc(const char *prefix, int i, int inf, bool ext) {
return desc;
}
+#if defined(EXTENDED_STATS)
+static const char *
+get_rtthisto_desc(const char *prefix, unsigned int i, unsigned int inf,
+ uint64_t min, uint64_t max, bool ext) {
+ static char buf[DNS_RTTHISTO_MAX * 80];
+ static size_t used = 0;
+ char *desc = buf + used;
+ size_t space = sizeof(buf) - used;
+ int len = 0;
+
+ if (!ext && i < inf) {
+ if (min == max) {
+ if (min == 0) {
+ len = snprintf(desc, space, "%s ~0 ms", prefix);
+ } else {
+ len = snprintf(desc, space, "%s %" PRIu64 " ms",
+ prefix, min);
+ }
+ } else {
+ len = snprintf(desc, space,
+ "%s %" PRIu64 "-%" PRIu64 " ms", prefix,
+ min, max);
+ }
+ } else if (!ext && i >= inf) {
+ len = snprintf(desc, space, "%s %" PRIu64 "+ ms", prefix, min);
+ } else if (ext && i < inf) {
+ if (min == max) {
+ if (min == 0) {
+ len = snprintf(desc, space, "~0");
+ } else {
+ len = snprintf(desc, space, "%" PRIu64, min);
+ }
+ } else {
+ len = snprintf(desc, space, "%" PRIu64 "-%" PRIu64, min,
+ max);
+ }
+ } else if (ext && i >= inf) {
+ len = snprintf(desc, space, "%" PRIu64 "+", min);
+ }
+ INSIST(0 < len && (size_t)len < space);
+ used += len + 1;
+ return desc;
+}
+#endif /* if defined(EXTENDED_STATS) */
+
static void
init_desc(void) {
int i;
@@ -441,28 +490,6 @@ init_desc(void) {
SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded",
"ValNegOk");
SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail");
- SET_RESSTATDESC(queryrtt0,
- "queries with RTT < " DNS_RESOLVER_QRYRTTCLASS0STR "ms",
- "QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR);
- SET_RESSTATDESC(queryrtt1,
- "queries with RTT " DNS_RESOLVER_QRYRTTCLASS0STR
- "-" DNS_RESOLVER_QRYRTTCLASS1STR "ms",
- "QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR);
- SET_RESSTATDESC(queryrtt2,
- "queries with RTT " DNS_RESOLVER_QRYRTTCLASS1STR
- "-" DNS_RESOLVER_QRYRTTCLASS2STR "ms",
- "QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR);
- SET_RESSTATDESC(queryrtt3,
- "queries with RTT " DNS_RESOLVER_QRYRTTCLASS2STR
- "-" DNS_RESOLVER_QRYRTTCLASS3STR "ms",
- "QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR);
- SET_RESSTATDESC(queryrtt4,
- "queries with RTT " DNS_RESOLVER_QRYRTTCLASS3STR
- "-" DNS_RESOLVER_QRYRTTCLASS4STR "ms",
- "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR);
- SET_RESSTATDESC(queryrtt5,
- "queries with RTT > " DNS_RESOLVER_QRYRTTCLASS4STR "ms",
- "QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
SET_RESSTATDESC(nfetch, "active fetches", "NumFetch");
SET_RESSTATDESC(buckets, "bucket size", "BucketSize");
SET_RESSTATDESC(refused, "REFUSED received", "REFUSED");
@@ -764,11 +791,11 @@ init_desc(void) {
for (i = 0; i < DNS_SIZEHISTO_MAXOUT; i++) {
udpoutsizestats_index[i] = i;
tcpoutsizestats_index[i] = i;
- udpoutsizestats_desc[i] = get_histo_desc(
+ udpoutsizestats_desc[i] = get_sizehisto_desc(
"responses sent", i, DNS_SIZEHISTO_MAXOUT, false);
tcpoutsizestats_desc[i] = udpoutsizestats_desc[i];
#if defined(EXTENDED_STATS)
- udpoutsizestats_xmldesc[i] = get_histo_desc(
+ udpoutsizestats_xmldesc[i] = get_sizehisto_desc(
"responses sent", i, DNS_SIZEHISTO_MAXOUT, true);
tcpoutsizestats_xmldesc[i] = udpoutsizestats_xmldesc[i];
#endif /* if defined(EXTENDED_STATS) */
@@ -777,7 +804,7 @@ init_desc(void) {
for (i = 0; i <= DNS_SIZEHISTO_MAXIN; i++) {
udpinsizestats_index[i] = i;
tcpinsizestats_index[i] = i;
- udpinsizestats_desc[i] = get_histo_desc(
+ udpinsizestats_desc[i] = get_sizehisto_desc(
"requests received", i, DNS_SIZEHISTO_MAXIN, false);
tcpinsizestats_desc[i] = udpinsizestats_desc[i];
#if defined(EXTENDED_STATS)
@@ -786,10 +813,25 @@ init_desc(void) {
tcpinsizestats_xmldesc[i] = tcpoutsizestats_xmldesc[i];
} else {
udpinsizestats_xmldesc[i] =
- get_histo_desc("requests received", i,
- DNS_SIZEHISTO_MAXIN, true);
+ get_sizehisto_desc("requests received", i,
+ DNS_SIZEHISTO_MAXIN, true);
tcpinsizestats_xmldesc[i] = udpinsizestats_xmldesc[i];
}
+#endif /* if defined(EXTENDED_STATS) */
+ }
+
+ for (i = 0; i <= DNS_RTTHISTO_MAX; i++) {
+ queryrttinstats_index[i] = i;
+ queryrttoutstats_index[i] = i;
+
+#if defined(EXTENDED_STATS)
+ /*
+ * The descriptions are filled in during dumping (only once),
+ * because we don't have the isc_histomulti_t objects here
+ * to determine their non-linear minimum and maximum values.
+ */
+ queryrttinstats_xmldesc[i] = NULL;
+ queryrttoutstats_xmldesc[i] = NULL;
#endif /* if defined(EXTENDED_STATS) */
}
}
@@ -832,13 +874,26 @@ dump_stats(isc_stats_t *stats, isc_statsformat_t type, void *arg,
#if defined(EXTENDED_STATS)
static isc_result_t
dump_histo(isc_histomulti_t *hm, isc_statsformat_t type, void *arg,
- const char *category, const char **desc, int ncounters, int *indices,
- uint64_t *values, int options) {
+ const char *category, const char **desc, const char *desc_prefix,
+ int ncounters, int *indices, uint64_t *values, int options) {
isc_histo_t *hg = NULL;
+ uint64_t min, max;
isc_histomulti_merge(&hg, hm);
for (int i = 0; i < ncounters; i++) {
- isc_histo_get(hg, i, NULL, NULL, &values[i]);
+ isc_histo_get(hg, i, &min, &max, &values[i]);
+
+ /*
+ * RTT descriptions are generated during the first call of
+ * this function for the corresponding histogram, the other
+ * descriptions are pregenerated and the caller shouldn't
+ * provide a prefix.
+ */
+ if (desc[i] == NULL && desc_prefix != NULL) {
+ desc[i] = get_rtthisto_desc(desc_prefix, i,
+ DNS_RTTHISTO_MAX, min, max,
+ true);
+ }
}
isc_histo_destroy(&hg);
@@ -1765,6 +1820,8 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
uint64_t udpoutsizestat_values[DNS_SIZEHISTO_MAXOUT + 1];
uint64_t tcpinsizestat_values[DNS_SIZEHISTO_MAXIN + 1];
uint64_t tcpoutsizestat_values[DNS_SIZEHISTO_MAXOUT + 1];
+ uint64_t queryrttinstat_values[DNS_RTTHISTO_MAX + 1];
+ uint64_t queryrttoutstat_values[DNS_RTTHISTO_MAX + 1];
#ifdef HAVE_DNSTAP
uint64_t dnstapstat_values[dns_dnstapcounter_max];
#endif /* ifdef HAVE_DNSTAP */
@@ -1921,7 +1978,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->udpinstats4, isc_statsformat_xml,
- writer, NULL, udpinsizestats_xmldesc,
+ writer, NULL, udpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, udpinsizestats_index,
udpinsizestat_values, 0));
@@ -1931,10 +1988,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
- CHECK(dump_histo(
- server->sctx->udpoutstats4, isc_statsformat_xml, writer,
- NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max,
- udpoutsizestats_index, udpoutsizestat_values, 0));
+ CHECK(dump_histo(server->sctx->udpoutstats4,
+ isc_statsformat_xml, writer, NULL,
+ udpoutsizestats_xmldesc, NULL,
+ dns_sizecounter_out_max, udpoutsizestats_index,
+ udpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* */
TRY0(xmlTextWriterEndElement(writer)); /* */
@@ -1945,7 +2003,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->tcpinstats4, isc_statsformat_xml,
- writer, NULL, tcpinsizestats_xmldesc,
+ writer, NULL, tcpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, tcpinsizestats_index,
tcpinsizestat_values, 0));
@@ -1954,10 +2012,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
- CHECK(dump_histo(
- server->sctx->tcpoutstats4, isc_statsformat_xml, writer,
- NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max,
- tcpoutsizestats_index, tcpoutsizestat_values, 0));
+ CHECK(dump_histo(server->sctx->tcpoutstats4,
+ isc_statsformat_xml, writer, NULL,
+ tcpoutsizestats_xmldesc, NULL,
+ dns_sizecounter_out_max, tcpoutsizestats_index,
+ tcpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* */
TRY0(xmlTextWriterEndElement(writer)); /* */
@@ -1970,7 +2029,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->udpinstats6, isc_statsformat_xml,
- writer, NULL, udpinsizestats_xmldesc,
+ writer, NULL, udpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, udpinsizestats_index,
udpinsizestat_values, 0));
@@ -1980,10 +2039,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
- CHECK(dump_histo(
- server->sctx->udpoutstats6, isc_statsformat_xml, writer,
- NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max,
- udpoutsizestats_index, udpoutsizestat_values, 0));
+ CHECK(dump_histo(server->sctx->udpoutstats6,
+ isc_statsformat_xml, writer, NULL,
+ udpoutsizestats_xmldesc, NULL,
+ dns_sizecounter_out_max, udpoutsizestats_index,
+ udpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* */
TRY0(xmlTextWriterEndElement(writer)); /* */
@@ -1994,7 +2054,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->tcpinstats6, isc_statsformat_xml,
- writer, NULL, tcpinsizestats_xmldesc,
+ writer, NULL, tcpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, tcpinsizestats_index,
tcpinsizestat_values, 0));
@@ -2004,10 +2064,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
- CHECK(dump_histo(
- server->sctx->tcpoutstats6, isc_statsformat_xml, writer,
- NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max,
- tcpoutsizestats_index, tcpoutsizestat_values, 0));
+ CHECK(dump_histo(server->sctx->tcpoutstats6,
+ isc_statsformat_xml, writer, NULL,
+ tcpoutsizestats_xmldesc, NULL,
+ dns_sizecounter_out_max, tcpoutsizestats_index,
+ tcpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* */
TRY0(xmlTextWriterEndElement(writer)); /* */
@@ -2027,6 +2088,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
isc_stats_t *istats = NULL;
dns_stats_t *dstats = NULL;
dns_adb_t *adb = NULL;
+ isc_histomulti_t *hmpin = NULL, *hmpout = NULL;
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
@@ -2120,6 +2182,40 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(dns_cache_renderxml(view->cache, writer));
TRY0(xmlTextWriterEndElement(writer)); /* */
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rtt"));
+
+ dns_resolver_getqueryrttstats(view->resolver, &hmpin, &hmpout);
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+ TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+ ISC_XMLCHAR "in-queries-rtt"));
+ if (hmpin != NULL) {
+ CHECK(dump_histo(hmpin, isc_statsformat_xml, writer,
+ NULL, queryrttinstats_xmldesc,
+ "RTT (in)", dns_queryrttcounter_in_max,
+ queryrttinstats_index,
+ queryrttinstat_values, 0));
+ isc_histomulti_detach(&hmpin);
+ }
+ TRY0(xmlTextWriterEndElement(writer)); /* */
+
+ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+ TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+ ISC_XMLCHAR
+ "out-queries-rtt"));
+ if (hmpout != NULL) {
+ CHECK(dump_histo(hmpout, isc_statsformat_xml, writer,
+ NULL, queryrttoutstats_xmldesc,
+ "RTT (out)",
+ dns_queryrttcounter_out_max,
+ queryrttoutstats_index,
+ queryrttoutstat_values, 0));
+ isc_histomulti_detach(&hmpout);
+ }
+ TRY0(xmlTextWriterEndElement(writer)); /* */
+
+ TRY0(xmlTextWriterEndElement(writer)); /* */
+
TRY0(xmlTextWriterEndElement(writer)); /* view */
view = ISC_LIST_NEXT(view, link);
@@ -2818,6 +2914,8 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
uint64_t udpoutsizestat_values[dns_sizecounter_out_max];
uint64_t tcpinsizestat_values[dns_sizecounter_in_max];
uint64_t tcpoutsizestat_values[dns_sizecounter_out_max];
+ uint64_t queryrttinstat_values[DNS_RTTHISTO_MAX + 1];
+ uint64_t queryrttoutstat_values[DNS_RTTHISTO_MAX + 1];
#ifdef HAVE_DNSTAP
uint64_t dnstapstat_values[dns_dnstapcounter_max];
#endif /* ifdef HAVE_DNSTAP */
@@ -3027,6 +3125,7 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
ISC_LIST_FOREACH(server->viewlist, view, link) {
json_object *za, *xa, *v = json_object_new_object();
dns_adb_t *adb = NULL;
+ isc_histomulti_t *hmpin = NULL, *hmpout = NULL;
CHECKMEM(v);
json_object_object_add(viewlist, view->name, v);
@@ -3170,6 +3269,45 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
json_object_object_add(res, "adb",
counters);
}
+
+ dns_resolver_getqueryrttstats(view->resolver,
+ &hmpin, &hmpout);
+ if (hmpin != NULL) {
+ counters = json_object_new_object();
+ CHECKMEM(counters);
+
+ CHECK(dump_histo(
+ hmpin, isc_statsformat_json,
+ counters, NULL,
+ queryrttinstats_xmldesc,
+ "RTT (in)",
+ dns_queryrttcounter_in_max,
+ queryrttinstats_index,
+ queryrttinstat_values, 0));
+ isc_histomulti_detach(&hmpin);
+
+ json_object_object_add(res,
+ "in-queries-rtt",
+ counters);
+ }
+ if (hmpout != NULL) {
+ counters = json_object_new_object();
+ CHECKMEM(counters);
+
+ CHECK(dump_histo(
+ hmpout, isc_statsformat_json,
+ counters, NULL,
+ queryrttoutstats_xmldesc,
+ "RTT (out)",
+ dns_queryrttcounter_out_max,
+ queryrttoutstats_index,
+ queryrttoutstat_values, 0));
+ isc_histomulti_detach(&hmpout);
+
+ json_object_object_add(
+ res, "out-queries-rtt",
+ counters);
+ }
}
}
}
@@ -3241,49 +3379,49 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
CHECK(dump_histo(server->sctx->udpinstats4,
isc_statsformat_json, udpreq4, NULL,
- udpinsizestats_xmldesc, dns_sizecounter_in_max,
- udpinsizestats_index, udpinsizestat_values,
- 0));
+ udpinsizestats_xmldesc, NULL,
+ dns_sizecounter_in_max, udpinsizestats_index,
+ udpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpoutstats4,
isc_statsformat_json, udpresp4, NULL,
- udpoutsizestats_xmldesc,
+ udpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, udpoutsizestats_index,
udpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpinstats4,
isc_statsformat_json, tcpreq4, NULL,
- tcpinsizestats_xmldesc, dns_sizecounter_in_max,
- tcpinsizestats_index, tcpinsizestat_values,
- 0));
+ tcpinsizestats_xmldesc, NULL,
+ dns_sizecounter_in_max, tcpinsizestats_index,
+ tcpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpoutstats4,
isc_statsformat_json, tcpresp4, NULL,
- tcpoutsizestats_xmldesc,
+ tcpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, tcpoutsizestats_index,
tcpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpinstats6,
isc_statsformat_json, udpreq6, NULL,
- udpinsizestats_xmldesc, dns_sizecounter_in_max,
- udpinsizestats_index, udpinsizestat_values,
- 0));
+ udpinsizestats_xmldesc, NULL,
+ dns_sizecounter_in_max, udpinsizestats_index,
+ udpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpoutstats6,
isc_statsformat_json, udpresp6, NULL,
- udpoutsizestats_xmldesc,
+ udpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, udpoutsizestats_index,
udpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpinstats6,
isc_statsformat_json, tcpreq6, NULL,
- tcpinsizestats_xmldesc, dns_sizecounter_in_max,
- tcpinsizestats_index, tcpinsizestat_values,
- 0));
+ tcpinsizestats_xmldesc, NULL,
+ dns_sizecounter_in_max, tcpinsizestats_index,
+ tcpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpoutstats6,
isc_statsformat_json, tcpresp6, NULL,
- tcpoutsizestats_xmldesc,
+ tcpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, tcpoutsizestats_index,
tcpoutsizestat_values, 0));
diff --git a/bin/tests/system/statschannel/ans5/ans.py b/bin/tests/system/statschannel/ans5/ans.py
new file mode 100644
index 0000000000..6f7dcc2a4a
--- /dev/null
+++ b/bin/tests/system/statschannel/ans5/ans.py
@@ -0,0 +1,56 @@
+"""
+Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+
+SPDX-License-Identifier: MPL-2.0
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, you can obtain one at https://mozilla.org/MPL/2.0/.
+
+See the COPYRIGHT file distributed with this work for additional
+information regarding copyright ownership.
+"""
+
+from collections.abc import AsyncGenerator
+
+import dns.rcode
+import dns.rdatatype
+import dns.rrset
+
+from isctest.asyncserver import (
+ ControllableAsyncDnsServer,
+ DnsResponseSend,
+ QueryContext,
+ ResponseHandler,
+)
+
+
+class DelayedAddressAnswerHandler(ResponseHandler):
+ async def get_responses(
+ self, qctx: QueryContext
+ ) -> AsyncGenerator[DnsResponseSend, None]:
+ if qctx.qtype in (dns.rdatatype.A, dns.rdatatype.AAAA):
+ addr = "192.0.2.1" if qctx.qtype == dns.rdatatype.A else "2001:db8:beef::1"
+ rrset = dns.rrset.from_text(qctx.qname, 300, qctx.qclass, qctx.qtype, addr)
+ qctx.response.answer.append(rrset)
+
+ delay = 0
+ if (
+ len(qctx.qname.labels) >= 2
+ and qctx.qname.labels[1] == b"latency"
+ and qctx.qname.labels[0].isdigit()
+ ):
+ delay = int(qctx.qname.labels[0]) / 1000
+ yield DnsResponseSend(qctx.response, delay=delay)
+
+
+def main() -> None:
+ server = ControllableAsyncDnsServer(
+ default_aa=True, default_rcode=dns.rcode.NOERROR
+ )
+ server.install_response_handler(DelayedAddressAnswerHandler())
+ server.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/bin/tests/system/statschannel/generic.py b/bin/tests/system/statschannel/generic.py
index 0b0ee82de0..02a7eea383 100644
--- a/bin/tests/system/statschannel/generic.py
+++ b/bin/tests/system/statschannel/generic.py
@@ -58,6 +58,11 @@ def check_zone_timers(loaded, expires, refresh, loaded_exp):
check_loaded(loaded, loaded_exp, now)
+def check_rtt(rtt, rtt_expected):
+ for val in rtt_expected:
+ assert rtt[val[0]] == val[1]
+
+
#
# The output is gibberish, but at least make sure it does not crash.
#
@@ -225,3 +230,33 @@ def test_traffic(fetch_traffic, **kwargs):
data = fetch_traffic(statsip, statsport)
check_traffic(data, exp)
+
+
+def test_rtt(fetch_views, **kwargs):
+ statsip = kwargs["statsip"]
+ statsport = kwargs["statsport"]
+
+ # auth query, 0 delay is expected, only for "in"
+ msg = create_msg("a.example2.", "TXT")
+ ans = isctest.query.tcp(msg, statsip, attempts=1)
+ isctest.check.noerror(ans)
+
+ # resolver query with a 530ms delay for both "in" and "out"
+ msg = create_msg("530.latency.example2.", "A")
+ ans = isctest.query.tcp(msg, statsip, attempts=1)
+ isctest.check.noerror(ans)
+
+ # resolver query with a 540ms delay for both "in" and "out"
+ msg = create_msg("540.latency.example2.", "A")
+ ans = isctest.query.tcp(msg, statsip, attempts=1)
+ isctest.check.noerror(ans)
+
+ # resolver query with a 730ms delay for both "in" and "out"
+ msg = create_msg("730.latency.example2.", "A")
+ ans = isctest.query.tcp(msg, statsip, attempts=1)
+ isctest.check.noerror(ans)
+
+ data = fetch_views(statsip, statsport)
+
+ check_rtt(data["in-queries-rtt"], [["~0", 1], ["512-575", 2], ["704-767", 1]])
+ check_rtt(data["out-queries-rtt"], [["512-575", 2], ["704-767", 1]])
diff --git a/bin/tests/system/statschannel/ns4/example2.db b/bin/tests/system/statschannel/ns4/example2.db
new file mode 100644
index 0000000000..2d623eb8cd
--- /dev/null
+++ b/bin/tests/system/statschannel/ns4/example2.db
@@ -0,0 +1,28 @@
+; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+;
+; SPDX-License-Identifier: MPL-2.0
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, you can obtain one at https://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$ORIGIN .
+$TTL 300 ; 5 minutes
+example2 IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+example2. NS ns4.example2.
+ns4.example2. A 10.53.0.4
+
+$ORIGIN example2.
+a A 10.0.0.1
+
+latency NS ns5.example2.
+ns5.example2. A 10.53.0.5
diff --git a/bin/tests/system/statschannel/ns4/named.conf.j2 b/bin/tests/system/statschannel/ns4/named.conf.j2
new file mode 100644
index 0000000000..4e2c17ee2b
--- /dev/null
+++ b/bin/tests/system/statschannel/ns4/named.conf.j2
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+options {
+ query-source address 10.53.0.4;
+ notify-source 10.53.0.4;
+ transfer-source 10.53.0.4;
+ port @PORT@;
+ pid-file "named.pid";
+ listen-on { 10.53.0.4; };
+ listen-on-v6 { none; };
+ recursion yes;
+ dnssec-validation no;
+ notify no;
+ minimal-responses no;
+ version none; // make statistics independent of the version number
+};
+
+statistics-channels { inet 10.53.0.4 port @EXTRAPORT1@ allow { localhost; }; };
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+zone "example2" {
+ type primary;
+ file "example2.db";
+ allow-transfer { any; };
+};
diff --git a/bin/tests/system/statschannel/tests_json.py b/bin/tests/system/statschannel/tests_json.py
index 30348f4e69..f1da9e9c82 100755
--- a/bin/tests/system/statschannel/tests_json.py
+++ b/bin/tests/system/statschannel/tests_json.py
@@ -24,6 +24,7 @@ pytestmark = [
isctest.mark.with_json_c,
pytest.mark.extra_artifacts(
[
+ "ans5/ans.run",
"ns2/*.jnl",
"ns2/*.signed",
"ns2/dsset-*",
@@ -62,6 +63,19 @@ def fetch_traffic_json(statsip, statsport):
return data["traffic"]
+def fetch_rtt_json(statsip, statsport):
+ r = requests.get(f"http://{statsip}:{statsport}/json/v1", timeout=600)
+ assert r.status_code == 200
+
+ views = r.json()["views"]
+ data = {
+ "in-queries-rtt": views["_default"]["resolver"]["in-queries-rtt"],
+ "out-queries-rtt": views["_default"]["resolver"]["out-queries-rtt"],
+ }
+
+ return data
+
+
def load_timers_json(zone, primary=True):
name = zone["name"]
@@ -119,3 +133,8 @@ def test_zone_with_many_keys_json(statsport):
@pytest.mark.flaky(max_runs=2)
def test_traffic_json(statsport):
generic.test_traffic(fetch_traffic_json, statsip="10.53.0.2", statsport=statsport)
+
+
+@pytest.mark.flaky(max_runs=2)
+def test_rtt_json(statsport):
+ generic.test_rtt(fetch_rtt_json, statsip="10.53.0.4", statsport=statsport)
diff --git a/bin/tests/system/statschannel/tests_sh_statschannel.py b/bin/tests/system/statschannel/tests_sh_statschannel.py
index 7b5788010d..473646cf1b 100644
--- a/bin/tests/system/statschannel/tests_sh_statschannel.py
+++ b/bin/tests/system/statschannel/tests_sh_statschannel.py
@@ -14,6 +14,7 @@ import pytest
pytestmark = pytest.mark.extra_artifacts(
[
"K*",
+ "ans5/ans.run",
"bind9.xsl.1",
"bind9.xsl.2",
"compressed.headers",
diff --git a/bin/tests/system/statschannel/tests_xml.py b/bin/tests/system/statschannel/tests_xml.py
index 0707681de7..133c2f0963 100755
--- a/bin/tests/system/statschannel/tests_xml.py
+++ b/bin/tests/system/statschannel/tests_xml.py
@@ -27,6 +27,7 @@ pytestmark = [
pytest.mark.extra_artifacts(
[
"ns2/K*",
+ "ans5/ans.run",
"ns2/*.jnl",
"ns2/*.signed",
"ns2/dsset-*",
@@ -91,6 +92,35 @@ def fetch_traffic_xml(statsip, statsport):
return traffic
+def fetch_rtt_xml(statsip, statsport):
+ def load_counters(data):
+ out = {}
+ for counter in data.findall("counter"):
+ out[counter.attrib["name"]] = int(counter.text)
+
+ return out
+
+ r = requests.get(f"http://{statsip}:{statsport}/xml/v3", timeout=600)
+ assert r.status_code == 200
+
+ root = ET.fromstring(r.text)
+
+ default_view = None
+ for view in root.find("views").iter("view"):
+ if view.attrib["name"] == "_default":
+ default_view = view
+ break
+ assert default_view is not None
+
+ rtt = {}
+ for counters in default_view.find("rtt").findall("counters"):
+ key = counters.attrib["type"]
+ values = load_counters(counters)
+ rtt[key] = values
+
+ return rtt
+
+
def load_timers_xml(zone, primary=True):
name = zone.attrib["name"]
@@ -149,3 +179,8 @@ def test_zone_with_many_keys_xml(statsport):
@pytest.mark.flaky(max_runs=2)
def test_traffic_xml(statsport):
generic.test_traffic(fetch_traffic_xml, statsip="10.53.0.2", statsport=statsport)
+
+
+@pytest.mark.flaky(max_runs=2)
+def test_rtt_xml(statsport):
+ generic.test_rtt(fetch_rtt_xml, statsip="10.53.0.4", statsport=statsport)
diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst
index 6e14b12959..341f1b3483 100644
--- a/doc/arm/reference.rst
+++ b/doc/arm/reference.rst
@@ -8468,9 +8468,6 @@ Resolver Statistics Counters
``ValFail``
This indicates the number of failed DNSSEC validations.
-``QryRTTnn``
- This provides a frequency table on query round-trip times (RTTs). Each ``nn`` specifies the corresponding frequency. In the sequence of ``nn_1``, ``nn_2``, ..., ``nn_m``, the value of ``nn_i`` is the number of queries whose RTTs are between ``nn_(i-1)`` (inclusive) and ``nn_i`` (exclusive) milliseconds. For the sake of convenience, we define ``nn_0`` to be 0. The last entry should be represented as ``nn_m+``, which means the number of queries whose RTTs are equal to or greater than ``nn_m`` milliseconds.
-
``NumFetch``
This indicates the number of active fetches.
@@ -8516,6 +8513,21 @@ Resolver Statistics Counters
``Priming``
This indicates the number of priming fetches performed by the resolver.
+.. _resolver_rtt_stats:
+
+Resolver Queries Response Time counters
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+:iscman:`named` provides query response round-trip time (RTT) counters
+(histogram) both for incoming and outgoing queries in milliseconds. Response
+times which are lower than 1ms are calculated under the ``~0`` counter.
+Response times from 1ms to 15ms are calculated under their own counters, e.g. a
+response that took 5ms to complete is calculated under the ``5`` counter.
+Response times starting from 16ms are calculated under the ``MinMS-MaxMS``
+(inclusive) range counters. For example, a response that took 18ms to complete
+is calculated under the ``18-19`` counter, and a response that took 550ms to
+complete is calculated under the ``512-575`` counter.
+
.. _socket_stats:
Socket I/O Statistics Counters
diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h
index 5c56d5d86d..6ec13fc631 100644
--- a/lib/dns/include/dns/resolver.h
+++ b/lib/dns/include/dns/resolver.h
@@ -49,6 +49,7 @@
#include
#include
+#include
#include
#include
#include
@@ -143,21 +144,6 @@ enum {
DNS_FETCHOPT_EDNSVERSIONMASK = 0xff000000,
};
-/*
- * Upper bounds of class of query RTT (ms). Corresponds to
- * dns_resstatscounter_queryrttX statistics counters.
- */
-#define DNS_RESOLVER_QRYRTTCLASS0 10
-#define DNS_RESOLVER_QRYRTTCLASS0STR "10"
-#define DNS_RESOLVER_QRYRTTCLASS1 100
-#define DNS_RESOLVER_QRYRTTCLASS1STR "100"
-#define DNS_RESOLVER_QRYRTTCLASS2 500
-#define DNS_RESOLVER_QRYRTTCLASS2STR "500"
-#define DNS_RESOLVER_QRYRTTCLASS3 800
-#define DNS_RESOLVER_QRYRTTCLASS3STR "800"
-#define DNS_RESOLVER_QRYRTTCLASS4 1600
-#define DNS_RESOLVER_QRYRTTCLASS4STR "1600"
-
/*
* XXXRTH Should this API be made semi-private? (I.e.
* _dns_resolver_create()).
@@ -586,8 +572,7 @@ dns_resolver_setstats(dns_resolver_t *res, isc_stats_t *stats);
*
* Requires:
* \li 'res' is valid.
- *
- *\li stats is a valid statistics supporting resolver statistics counters
+ * \li stats is a valid statistics supporting resolver statistics counters
* (see dns/stats.h).
*/
@@ -600,8 +585,7 @@ dns_resolver_getstats(dns_resolver_t *res, isc_stats_t **statsp);
*
* Requires:
* \li 'res' is valid.
- *
- *\li 'statsp' != NULL && '*statsp' != NULL
+ * \li 'statsp' != NULL && '*statsp' != NULL
*/
void
@@ -623,8 +607,7 @@ dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats);
*
* Requires:
* \li 'res' is valid.
- *
- *\li stats is a valid statistics created by dns_rdatatypestats_create().
+ * \li 'stats' is a valid statistics created by dns_rdatatypestats_create().
*/
void
@@ -636,8 +619,36 @@ dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp);
*
* Requires:
* \li 'res' is valid.
+ * \li 'statsp' != NULL && '*statsp' != NULL
+ */
+
+void
+dns_resolver_setqueryrttstats(dns_resolver_t *res, isc_histomulti_t *hmin,
+ isc_histomulti_t *hmout);
+/*%<
+ * Set a query RTT statistics histograms 'hmin' and 'hmout' for 'res'. Once the
+ * statistic histograms are installed, the resolver will start updating them
+ * with the incoming and outgoing queries' RTT values accordingly.
*
- *\li 'statsp' != NULL && '*statsp' != NULL
+ * Requires:
+ * \li 'res' is valid.
+ * \li 'stats' is a valid statistics created by dns_rdatatypestats_create().
+ * \li 'hmin' is a valid isc_histomulti_t object.
+ * \li 'hmout' is a valid isc_histomulti_t object.
+ */
+
+void
+dns_resolver_getqueryrttstats(dns_resolver_t *res, isc_histomulti_t **hmpin,
+ isc_histomulti_t **hmpout);
+/*%<
+ * Get the query RTT statistics histograms for 'res'. If the histograms are set
+ * then the corresponding '*hmp{in,out}' are attached to them; otherwise,
+ * '*hmp{in,out}' are untouched.
+ *
+ * Requires:
+ * \li 'res' is valid.
+ * \li 'hmpin' == NULL || '*hmpin' == NULL
+ * \li 'hmpout' == NULL || '*hmpout' == NULL
*/
void
diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h
index b40f5bc999..0bbdde4638 100644
--- a/lib/dns/include/dns/stats.h
+++ b/lib/dns/include/dns/stats.h
@@ -19,6 +19,7 @@
#include
+#include
#include
/*%
@@ -52,30 +53,24 @@ enum {
dns_resstatscounter_dispabort = 21,
dns_resstatscounter_dispsockfail = 22,
dns_resstatscounter_querytimeout = 23,
- dns_resstatscounter_queryrtt0 = 24,
- dns_resstatscounter_queryrtt1 = 25,
- dns_resstatscounter_queryrtt2 = 26,
- dns_resstatscounter_queryrtt3 = 27,
- dns_resstatscounter_queryrtt4 = 28,
- dns_resstatscounter_queryrtt5 = 29,
- dns_resstatscounter_nfetch = 30,
- dns_resstatscounter_disprequdp = 31,
- dns_resstatscounter_dispreqtcp = 32,
- dns_resstatscounter_buckets = 33,
- dns_resstatscounter_refused = 34,
- dns_resstatscounter_cookienew = 35,
- dns_resstatscounter_cookieout = 36,
- dns_resstatscounter_cookiein = 37,
- dns_resstatscounter_cookieok = 38,
- dns_resstatscounter_badvers = 39,
- dns_resstatscounter_badcookie = 40,
- dns_resstatscounter_zonequota = 41,
- dns_resstatscounter_serverquota = 42,
- dns_resstatscounter_clientquota = 43,
- dns_resstatscounter_nextitem = 44,
- dns_resstatscounter_priming = 45,
- dns_resstatscounter_forwardonlyfail = 46,
- dns_resstatscounter_max = 47,
+ dns_resstatscounter_nfetch = 24,
+ dns_resstatscounter_disprequdp = 25,
+ dns_resstatscounter_dispreqtcp = 26,
+ dns_resstatscounter_buckets = 27,
+ dns_resstatscounter_refused = 28,
+ dns_resstatscounter_cookienew = 29,
+ dns_resstatscounter_cookieout = 30,
+ dns_resstatscounter_cookiein = 31,
+ dns_resstatscounter_cookieok = 32,
+ dns_resstatscounter_badvers = 33,
+ dns_resstatscounter_badcookie = 34,
+ dns_resstatscounter_zonequota = 35,
+ dns_resstatscounter_serverquota = 36,
+ dns_resstatscounter_clientquota = 37,
+ dns_resstatscounter_nextitem = 38,
+ dns_resstatscounter_priming = 39,
+ dns_resstatscounter_forwardonlyfail = 40,
+ dns_resstatscounter_max = 41,
/*
* DNSSEC stats.
@@ -203,6 +198,24 @@ enum {
dns_sizecounter_out_max = DNS_SIZEHISTO_MAXOUT + 1,
};
+/*
+ * This gives enough amount of buckets in the lower end of the values (which
+ * are the values up to about 30000 milliseconds (MAXIMUM_QUERY_TIMEOUT) to make
+ * sense for the resolver) to be useful and not to be too many. E.g. bucket
+ * number 30 covers values between 56 and 59, while bucket number 102 covers the
+ * values between 28672 and 30719.
+ */
+#define DNS_RTTHISTO_SIGBITS 3
+#define DNS_RTTHISTO_MAX 102
+
+/*
+ * For consistency with other stats counters
+ */
+enum {
+ dns_queryrttcounter_in_max = DNS_RTTHISTO_MAX + 1,
+ dns_queryrttcounter_out_max = DNS_RTTHISTO_MAX + 1,
+};
+
/*%
* Attributes for statistics counters of RRset and Rdatatype types.
*
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 68efd7580f..3dc51cdb8b 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -207,7 +208,11 @@
#define DEFAULT_QUERY_TIMEOUT (MAX_SINGLE_QUERY_TIMEOUT + 1000U)
#endif /* ifndef DEFAULT_QUERY_TIMEOUT */
-/* The maximum time in seconds for the whole query to live. */
+/*
+ * The maximum time in seconds for the whole query to live.
+ *
+ * Note: if increased, DNS_RTTHISTO_MAX should also be updated.
+ */
#ifndef MAXIMUM_QUERY_TIMEOUT
#define MAXIMUM_QUERY_TIMEOUT 30000
#endif /* ifndef MAXIMUM_QUERY_TIMEOUT */
@@ -598,6 +603,8 @@ struct dns_resolver {
isc_result_t quotaresp[2];
isc_stats_t *stats;
dns_stats_t *querystats;
+ isc_histomulti_t *queryinrttstats;
+ isc_histomulti_t *queryoutrttstats;
/* Additions for serve-stale feature. */
unsigned int retryinterval; /* in milliseconds */
@@ -1255,31 +1262,17 @@ fctx_cancelquery(resquery_t **queryp, isc_time_t *finish, bool no_response,
* We have both the start and finish times for this
* packet, so we can compute a real RTT.
*/
- unsigned int rttms;
-
rtt = (unsigned int)isc_time_microdiff(finish,
&query->start);
- rttms = rtt / US_PER_MS;
factor = DNS_ADB_RTTADJDEFAULT;
- if (rttms < DNS_RESOLVER_QRYRTTCLASS0) {
- inc_stats(fctx->res,
- dns_resstatscounter_queryrtt0);
- } else if (rttms < DNS_RESOLVER_QRYRTTCLASS1) {
- inc_stats(fctx->res,
- dns_resstatscounter_queryrtt1);
- } else if (rttms < DNS_RESOLVER_QRYRTTCLASS2) {
- inc_stats(fctx->res,
- dns_resstatscounter_queryrtt2);
- } else if (rttms < DNS_RESOLVER_QRYRTTCLASS3) {
- inc_stats(fctx->res,
- dns_resstatscounter_queryrtt3);
- } else if (rttms < DNS_RESOLVER_QRYRTTCLASS4) {
- inc_stats(fctx->res,
- dns_resstatscounter_queryrtt4);
- } else {
- inc_stats(fctx->res,
- dns_resstatscounter_queryrtt5);
+ if (fctx->res->queryoutrttstats != NULL) {
+ const unsigned int rttms = rtt / US_PER_MS;
+ isc_histomulti_inc(
+ fctx->res->queryoutrttstats,
+ rttms < MAXIMUM_QUERY_TIMEOUT
+ ? rttms
+ : MAXIMUM_QUERY_TIMEOUT);
}
} else {
uint32_t value;
@@ -9642,6 +9635,12 @@ dns_resolver__destroy(dns_resolver_t *res) {
dns_nametree_detach(&res->algorithms);
dns_nametree_detach(&res->digests);
+ if (res->queryoutrttstats != NULL) {
+ isc_histomulti_detach(&res->queryoutrttstats);
+ }
+ if (res->queryinrttstats != NULL) {
+ isc_histomulti_detach(&res->queryinrttstats);
+ }
if (res->querystats != NULL) {
dns_stats_detach(&res->querystats);
}
@@ -10884,6 +10883,32 @@ dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp) {
}
}
+void
+dns_resolver_setqueryrttstats(dns_resolver_t *res, isc_histomulti_t *hmin,
+ isc_histomulti_t *hmout) {
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE(res->queryinrttstats == NULL);
+ REQUIRE(res->queryoutrttstats == NULL);
+
+ isc_histomulti_attach(hmin, &res->queryinrttstats);
+ isc_histomulti_attach(hmout, &res->queryoutrttstats);
+}
+
+void
+dns_resolver_getqueryrttstats(dns_resolver_t *res, isc_histomulti_t **hmpin,
+ isc_histomulti_t **hmpout) {
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE(hmpin == NULL || *hmpin == NULL);
+ REQUIRE(hmpout == NULL || *hmpout == NULL);
+
+ if (hmpin != NULL && res->queryinrttstats != NULL) {
+ isc_histomulti_attach(res->queryinrttstats, hmpin);
+ }
+ if (hmpout != NULL && res->queryoutrttstats != NULL) {
+ isc_histomulti_attach(res->queryoutrttstats, hmpout);
+ }
+}
+
void
dns_resolver_freefresp(dns_fetchresponse_t **frespp) {
REQUIRE(frespp != NULL);
diff --git a/lib/isc/histo.c b/lib/isc/histo.c
index aac7081db6..acfd3256c4 100644
--- a/lib/isc/histo.c
+++ b/lib/isc/histo.c
@@ -74,6 +74,7 @@ struct isc_histo {
struct isc_histomulti {
uint magic;
uint size;
+ isc_refcount_t references;
isc_histo_t *hg[];
};
@@ -386,22 +387,23 @@ isc_histomulti_create(isc_mem_t *mctx, uint sigbits, isc_histomulti_t **hmp) {
isc_histo_create(mctx, sigbits, &hm->hg[i]);
}
+ isc_refcount_init(&hm->references, 1);
+
*hmp = hm;
}
-void
-isc_histomulti_destroy(isc_histomulti_t **hmp) {
- REQUIRE(hmp != NULL);
- REQUIRE(HISTOMULTI_VALID(*hmp));
+static void
+isc__histomulti_destroy(isc_histomulti_t *hm) {
+ REQUIRE(HISTOMULTI_VALID(hm));
- isc_histomulti_t *hm = *hmp;
isc_mem_t *mctx = hm->hg[0]->mctx;
- *hmp = NULL;
for (uint i = 0; i < hm->size; i++) {
isc_histo_destroy(&hm->hg[i]);
}
+ isc_refcount_destroy(&hm->references);
+
isc_mem_put(mctx, hm, STRUCT_FLEX_SIZE(hm, hg, hm->size));
}
@@ -426,6 +428,12 @@ isc_histomulti_inc(isc_histomulti_t *hm, uint64_t value) {
isc_histomulti_add(hm, value, 1);
}
+#ifdef ISC_HISTO_TRACE
+ISC_REFCOUNT_TRACE_IMPL(isc_histomulti, isc__histomulti_destroy);
+#else
+ISC_REFCOUNT_IMPL(isc_histomulti, isc__histomulti_destroy);
+#endif /* ISC_HISTO_TRACE */
+
/**********************************************************************/
/*
diff --git a/lib/isc/include/isc/histo.h b/lib/isc/include/isc/histo.h
index 4c9123fbbc..80c2b15faf 100644
--- a/lib/isc/include/isc/histo.h
+++ b/lib/isc/include/isc/histo.h
@@ -278,20 +278,6 @@ isc_histomulti_create(isc_mem_t *mctx, uint sigbits, isc_histomulti_t **hmp);
*\li `*hmp` is a pointer to a multithreaded sharded histogram.
*/
-void
-isc_histomulti_destroy(isc_histomulti_t **hmp);
-/*%<
- * Destroy a multithreaded sharded histogram
- *
- * Requires:
- *\li `hmp != NULL`
- *\li `*hmp` is a pointer to a valid multithreaded sharded histogram
- *
- * Ensures:
- *\li all memory allocated by the histogram has been released
- *\li `*hmp == NULL`
- */
-
void
isc_histomulti_merge(isc_histo_t **targetp, const isc_histomulti_t *source);
/*%<
@@ -326,6 +312,21 @@ isc_histomulti_add(isc_histomulti_t *hm, uint64_t value, uint64_t inc);
*\li `hm` is a pointer to a valid histomulti
*/
+#ifdef ISC_HISTO_TRACE
+#define isc_histomulti_ref(ptr) \
+ dns_histomulti__ref(ptr, __func__, __FILE__, __LINE__)
+#define isc_histomulti_unref(ptr) \
+ isc_histomulti__unref(ptr, __func__, __FILE__, __LINE__)
+#define isc_histomulti_attach(ptr, ptrp) \
+ isc_histomulti__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
+#define isc_histomulti_detach(ptrp) \
+ isc_histomulti__detach(ptrp, __func__, __FILE__, __LINE__)
+
+ISC_REFCOUNT_TRACE_DECL(isc_histomulti);
+#else
+ISC_REFCOUNT_DECL(isc_histomulti);
+#endif /* ISC_HISTO_TRACE */
+
/**********************************************************************/
void
diff --git a/lib/ns/client.c b/lib/ns/client.c
index 3c42a85bf0..c0a5649a3b 100644
--- a/lib/ns/client.c
+++ b/lib/ns/client.c
@@ -325,7 +325,24 @@ client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
*/
client->inner.sendhandle = NULL;
- if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_SUCCESS) {
+ isc_histomulti_t *hmpin = NULL;
+
+ if (client->inner.view != NULL &&
+ client->inner.view->resolver != NULL)
+ {
+ dns_resolver_getqueryrttstats(
+ client->inner.view->resolver, &hmpin, NULL);
+ }
+ if (hmpin != NULL) {
+ const unsigned int rtt = (unsigned int)
+ isc_time_microdiff(&client->inner.tnow,
+ &client->inner.requesttime);
+ const unsigned int rttms = rtt / US_PER_MS;
+ isc_histomulti_inc(hmpin, rttms);
+ isc_histomulti_detach(&hmpin);
+ }
+ } else {
if (!TCP_CLIENT(client) && result == ISC_R_MAXSIZE) {
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
diff --git a/lib/ns/query.c b/lib/ns/query.c
index b457d61173..8e7891d60c 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -2703,7 +2703,8 @@ stale_refresh_aftermath(ns_client_t *client, isc_result_t result) {
* database, starting the stale-refresh-time window for it.
* This is a condensed form of query_lookup().
*/
- client->inner.now = isc_stdtime_now();
+ client->inner.tnow = isc_time_now();
+ client->inner.now = isc_time_seconds(&client->inner.tnow);
client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
qctx_init(client, NULL, 0, &qctx);
@@ -6076,7 +6077,8 @@ fetch_callback(void *arg) {
/*
* Update client->now.
*/
- client->inner.now = isc_stdtime_now();
+ client->inner.tnow = isc_time_now();
+ client->inner.now = isc_time_seconds(&client->inner.tnow);
} else {
/*
* This is a fetch completion event for a canceled fetch.
@@ -6538,7 +6540,8 @@ query_hookresume(void *arg) {
INSIST(rev->ctx == client->query.hookasyncctx);
client->query.hookasyncctx = NULL;
canceled = false;
- client->inner.now = isc_stdtime_now();
+ client->inner.tnow = isc_time_now();
+ client->inner.now = isc_time_seconds(&client->inner.tnow);
} else {
canceled = true;
}
diff --git a/lib/ns/server.c b/lib/ns/server.c
index e0843905d9..857c6d0b6a 100644
--- a/lib/ns/server.c
+++ b/lib/ns/server.c
@@ -176,29 +176,29 @@ ns_server_detach(ns_server_t **sctxp) {
}
if (sctx->udpinstats4 != NULL) {
- isc_histomulti_destroy(&sctx->udpinstats4);
+ isc_histomulti_detach(&sctx->udpinstats4);
}
if (sctx->tcpinstats4 != NULL) {
- isc_histomulti_destroy(&sctx->tcpinstats4);
+ isc_histomulti_detach(&sctx->tcpinstats4);
}
if (sctx->udpoutstats4 != NULL) {
- isc_histomulti_destroy(&sctx->udpoutstats4);
+ isc_histomulti_detach(&sctx->udpoutstats4);
}
if (sctx->tcpoutstats4 != NULL) {
- isc_histomulti_destroy(&sctx->tcpoutstats4);
+ isc_histomulti_detach(&sctx->tcpoutstats4);
}
if (sctx->udpinstats6 != NULL) {
- isc_histomulti_destroy(&sctx->udpinstats6);
+ isc_histomulti_detach(&sctx->udpinstats6);
}
if (sctx->tcpinstats6 != NULL) {
- isc_histomulti_destroy(&sctx->tcpinstats6);
+ isc_histomulti_detach(&sctx->tcpinstats6);
}
if (sctx->udpoutstats6 != NULL) {
- isc_histomulti_destroy(&sctx->udpoutstats6);
+ isc_histomulti_detach(&sctx->udpoutstats6);
}
if (sctx->tcpoutstats6 != NULL) {
- isc_histomulti_destroy(&sctx->tcpoutstats6);
+ isc_histomulti_detach(&sctx->tcpoutstats6);
}
sctx->magic = 0;