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

+ + + + + + + + + even + odd + + + + + + + +
MillisecondsCount
+
+
+ + +

Outgoing Queries Response Time for View

+ + + + + + + + + even + odd + + + + + + + +
MillisecondsCount
+
+

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;