From: Evan Hunt Date: Thu, 26 May 2022 09:33:52 +0000 (-0700) Subject: add "rndc fetchlimit" to show fetchlimited servers X-Git-Tag: v9.19.3~3^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=617589747854f07a570ff459deeae2e082f36efb;p=thirdparty%2Fbind9.git add "rndc fetchlimit" to show fetchlimited servers this command runs dns_adb_dumpquota() to display all servers in the ADB that are being actively fetchlimited by the fetches-per-server controls (i.e, servers with a nonzero average timeout ratio or with the quota having been reduced from the default value). the "fetchlimit" system test has been updated to use the new command to check quota values instead of "rndc dumpdb". --- diff --git a/bin/named/control.c b/bin/named/control.c index 29c848b0703..0b742407fe1 100644 --- a/bin/named/control.c +++ b/bin/named/control.c @@ -218,6 +218,8 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly, result = ISC_R_SUCCESS; } else if (command_compare(command, NAMED_COMMAND_DUMPSTATS)) { result = named_server_dumpstats(named_g_server); + } else if (command_compare(command, NAMED_COMMAND_FETCHLIMIT)) { + result = named_server_fetchlimit(named_g_server, lex, text); } else if (command_compare(command, NAMED_COMMAND_FLUSH)) { result = named_server_flushcache(named_g_server, lex); } else if (command_compare(command, NAMED_COMMAND_FLUSHNAME)) { diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h index 1ea4c490fbb..425b50696f8 100644 --- a/bin/named/include/named/control.h +++ b/bin/named/include/named/control.h @@ -70,6 +70,7 @@ #define NAMED_COMMAND_DNSTAP "dnstap" #define NAMED_COMMAND_TCPTIMEOUTS "tcp-timeouts" #define NAMED_COMMAND_SERVESTALE "serve-stale" +#define NAMED_COMMAND_FETCHLIMIT "fetchlimit" isc_result_t named_controls_create(named_server_t *server, named_controls_t **ctrlsp); diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index d1c97cd8533..ce45b440c1d 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -401,3 +401,10 @@ named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text); isc_result_t named_server_servestale(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text); + +/*% + * Report fetch-limited ADB server addresses. + */ +isc_result_t +named_server_fetchlimit(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text); diff --git a/bin/named/server.c b/bin/named/server.c index dcb7a708f40..b1096837119 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -16600,3 +16600,70 @@ cleanup: return (result); } + +isc_result_t +named_server_fetchlimit(named_server_t *server, isc_lex_t *lex, + isc_buffer_t **text) { + isc_result_t result = ISC_R_SUCCESS; + dns_view_t *view = NULL; + char *ptr = NULL, *viewname = NULL; + bool first = true; + + REQUIRE(text != NULL); + + /* Skip the command name. */ + ptr = next_token(lex, text); + if (ptr == NULL) { + return (ISC_R_UNEXPECTEDEND); + } + + /* Look for the view name. */ + viewname = next_token(lex, text); + for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; + view = ISC_LIST_NEXT(view, link)) + { + char tbuf[BUFSIZ]; + unsigned int used; + uint32_t val; + int s; + + if (view->rdclass != dns_rdataclass_in) { + continue; + } + + if (viewname != NULL && strcasecmp(view->name, viewname) != 0) { + continue; + } + + if (view->adb == NULL) { + continue; + } + + if (!first) { + putstr(text, "\n"); + } + putstr(text, "Rate limited servers, view "); + putstr(text, view->name); + + dns_adb_getquota(view->adb, &val, NULL, NULL, NULL, NULL); + s = snprintf(tbuf, sizeof(tbuf), + " (fetches-per-server %u):", val); + if (s < 0 || (unsigned)s > sizeof(tbuf)) { + return (ISC_R_NOSPACE); + } + first = false; + putstr(text, tbuf); + used = isc_buffer_usedlength(*text); + CHECK(dns_adb_dumpquota(view->adb, text)); + if (used == isc_buffer_usedlength(*text)) { + putstr(text, "\n None."); + } + } + +cleanup: + if (isc_buffer_usedlength(*text) > 0) { + (void)putnull(text); + } + + return (result); +} diff --git a/bin/rndc/rndc.rst b/bin/rndc/rndc.rst index 6717e242d1d..2236d1d911f 100644 --- a/bin/rndc/rndc.rst +++ b/bin/rndc/rndc.rst @@ -204,6 +204,11 @@ Currently supported commands are: (See the ``dump-file`` option in the BIND 9 Administrator Reference Manual.) +.. option:: fetchlimit [view] + + This command dumps a list of servers which are currently being + rate-limited as a result of ``fetches-per-server`` settings. + .. option:: flush This command flushes the server's cache. diff --git a/bin/tests/system/fetchlimit/tests.sh b/bin/tests/system/fetchlimit/tests.sh index c10bee66777..a96caafa9d2 100644 --- a/bin/tests/system/fetchlimit/tests.sh +++ b/bin/tests/system/fetchlimit/tests.sh @@ -58,12 +58,11 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status+ret)) echo_i "dumping ADB data" -$RNDCCMD dumpdb -adb -info=`grep '10.53.0.4' ns3/named_dump.db | sed 's/.*\(atr [.0-9]*\).*\(quota [0-9]*\).*/\1 \2/'` +info=$($RNDCCMD fetchlimit | grep 10.53.0.4 | sed 's/.*quota .*(\([0-9]*\).*atr \([.0-9]*\).*/\2 \1/') echo_i $info set -- $info -quota=$5 -[ ${5:-200} -lt 200 ] || ret=1 +quota=$2 +[ ${quota:-200} -lt 200 ] || ret=1 echo_i "checking servfail statistics" ret=0 @@ -92,12 +91,11 @@ for try in 1 2 3 4 5; do done echo_i "dumping ADB data" -$RNDCCMD dumpdb -adb -info=`grep '10.53.0.4' ns3/named_dump.db | sed 's/.*\(atr [.0-9]*\).*\(quota [0-9]*\).*/\1 \2/'` +info=$($RNDCCMD fetchlimit | grep 10.53.0.4 | sed 's/.*quota .*(\([0-9]*\).*atr \([.0-9]*\).*/\2 \1/') echo_i $info set -- $info -[ ${5:-${quota}} -lt $quota ] || ret=1 -quota=$5 +[ ${2:-${quota}} -lt $quota ] || ret=1 +quota=$2 for try in 1 2 3 4 5 6 7 8 9 10; do burst c $try @@ -107,12 +105,11 @@ for try in 1 2 3 4 5 6 7 8 9 10; do done echo_i "dumping ADB data" -$RNDCCMD dumpdb -adb -info=`grep '10.53.0.4' ns3/named_dump.db | sed 's/.*\(atr [.0-9]*\).*\(quota [0-9]*\).*/\1 \2/'` +info=$($RNDCCMD fetchlimit | grep 10.53.0.4 | sed 's/.*quota .*(\([0-9]*\).*atr \([.0-9]*\).*/\2 \1/') echo_i $info set -- $info -[ ${5:-${quota}} -gt $quota ] || ret=1 -quota=$5 +[ ${2:-${quota}} -gt $quota ] || ret=1 +quota=$2 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status+ret)) diff --git a/doc/man/rndc.8in b/doc/man/rndc.8in index 4023b82ee23..c21fab7a61e 100644 --- a/doc/man/rndc.8in +++ b/doc/man/rndc.8in @@ -226,6 +226,12 @@ Manual.) .UNINDENT .INDENT 0.0 .TP +.B fetchlimit [view] +This command dumps a list of servers which are currently being +rate\-limited as a result of \fBfetches\-per\-server\fP settings. +.UNINDENT +.INDENT 0.0 +.TP .B flush This command flushes the server\(aqs cache. .UNINDENT diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 7d549aa5eea..b97f3e63905 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -2976,6 +2976,67 @@ print_find_list(FILE *f, dns_adbname_t *name) { } } +static isc_result_t +putstr(isc_buffer_t **b, const char *str) { + isc_result_t result; + + result = isc_buffer_reserve(b, strlen(str)); + if (result != ISC_R_SUCCESS) { + return (result); + } + + isc_buffer_putstr(*b, str); + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_adb_dumpquota(dns_adb_t *adb, isc_buffer_t **buf) { + isc_result_t result; + isc_ht_iter_t *it = NULL; + + REQUIRE(DNS_ADB_VALID(adb)); + + RWLOCK(&adb->entries_lock, isc_rwlocktype_read); + isc_ht_iter_create(adb->entrybuckets, &it); + for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS; + result = isc_ht_iter_next(it)) + { + dns_adbentrybucket_t *ebucket = NULL; + dns_adbentry_t *entry = NULL; + + isc_ht_iter_current(it, (void **)&ebucket); + LOCK(&ebucket->lock); + for (entry = ISC_LIST_HEAD(ebucket->entries); entry != NULL; + entry = ISC_LIST_NEXT(entry, plink)) + { + char addrbuf[ISC_NETADDR_FORMATSIZE]; + char text[BUFSIZ]; + isc_netaddr_t netaddr; + + if (entry->atr == 0.0 && entry->quota == adb->quota) { + continue; + } + + isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr); + isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf)); + + snprintf(text, sizeof(text), + "\n- quota %s (%" PRIuFAST32 "/%d) atr %0.2f", + addrbuf, atomic_load_relaxed(&entry->quota), + adb->quota, entry->atr); + putstr(buf, text); + } + UNLOCK(&ebucket->lock); + } + RWUNLOCK(&adb->entries_lock, isc_rwlocktype_read); + isc_ht_iter_destroy(&it); + + if (result == ISC_R_NOMORE) { + result = ISC_R_SUCCESS; + } + return (result); +} + static isc_result_t dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) { isc_result_t result; @@ -3965,6 +4026,32 @@ dns_adb_setquota(dns_adb_t *adb, uint32_t quota, uint32_t freq, double low, adb->atr_discount = discount; } +void +dns_adb_getquota(dns_adb_t *adb, uint32_t *quotap, uint32_t *freqp, + double *lowp, double *highp, double *discountp) { + REQUIRE(DNS_ADB_VALID(adb)); + + if (quotap != NULL) { + *quotap = adb->quota; + } + + if (freqp != NULL) { + *freqp = adb->atr_freq; + } + + if (lowp != NULL) { + *lowp = adb->atr_low; + } + + if (highp != NULL) { + *highp = adb->atr_high; + } + + if (discountp != NULL) { + *discountp = adb->atr_discount; + } +} + bool dns_adbentry_overquota(dns_adbentry_t *entry) { uint_fast32_t quota, active; diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 4bfe6d0a42f..1daa6b8e08d 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -748,6 +748,20 @@ dns_adb_setquota(dns_adb_t *adb, uint32_t quota, uint32_t freq, double low, *\li 'adb' is valid. */ +void +dns_adb_getquota(dns_adb_t *adb, uint32_t *quotap, uint32_t *freqp, + double *lowp, double *highp, double *discountp); +/*%< + * Get the quota values set by dns_adb_setquota(). + * If any of the 'quotap', 'freqp', 'lowp', 'highp', and + * 'discountp' parameters are non-NULL, then the memory they + * point to will be updated to hold the corresponding quota + * or parameter value. + * + * Requires: + *\li 'adb' is valid. + */ + bool dns_adbentry_overquota(dns_adbentry_t *entry); /*%< @@ -782,4 +796,16 @@ dns_adb_getstats(dns_adb_t *adb); * Requires: * \li 'adb' is valid. */ + +isc_result_t +dns_adb_dumpquota(dns_adb_t *adb, isc_buffer_t **buf); +/*% + * Dump the addresses, current quota values, and current ATR values + * for all servers that are currently being fetchlimited. Servers + * for which the quota is still equal to the default and the ATR + * is zero are not printed. + * + * Requires: + * \li 'adb' is valid. + */ ISC_LANG_ENDDECLS