From 8907d8fa04fdaa65baf0bc6b01230b2ebde93106 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 3 Apr 2008 05:55:52 +0000 Subject: [PATCH] 2355. [func] Extend the number statistics counters available. [RT #17590] --- CHANGES | 3 + bin/named/bind9.xsl | 313 ++++++++++++++- bin/named/bind9.xsl.h | 386 +++++++++++++++++- bin/named/client.c | 66 ++- bin/named/convertxsl.pl | 39 +- bin/named/include/named/server.h | 57 ++- bin/named/include/named/statschannel.h | 8 +- bin/named/query.c | 50 ++- bin/named/server.c | 133 +++--- bin/named/statschannel.c | 536 ++++++++++++++++++++++++- bin/named/update.c | 110 +++-- bin/named/xfrout.c | 35 +- bin/named/zoneconf.c | 15 +- lib/dns/adb.c | 23 +- lib/dns/db.c | 12 +- lib/dns/dispatch.c | 19 +- lib/dns/include/dns/adb.h | 3 +- lib/dns/include/dns/db.h | 18 +- lib/dns/include/dns/dispatch.h | 17 +- lib/dns/include/dns/stats.h | 297 ++++++++++++-- lib/dns/include/dns/types.h | 4 +- lib/dns/include/dns/view.h | 57 ++- lib/dns/include/dns/zone.h | 66 ++- lib/dns/rbtdb.c | 67 +++- lib/dns/resolver.c | 61 ++- lib/dns/sdb.c | 3 +- lib/dns/sdlz.c | 3 +- lib/dns/stats.c | 462 ++++++++++++++++++--- lib/dns/view.c | 76 ++-- lib/dns/zone.c | 198 +++++---- 30 files changed, 2731 insertions(+), 406 deletions(-) diff --git a/CHANGES b/CHANGES index 47ca261d63..db796547d2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2355. [func] Extend the number statistics counters available. + [RT #17590] + 2354. [bug] Failed to initialise sone rdatasetheader_t elements. [RT #17927] diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl index 97d75806d6..c385289541 100644 --- a/bin/named/bind9.xsl +++ b/bin/named/bind9.xsl @@ -15,7 +15,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + - - + + - - + +
Server statistics
Incoming Requests
-
+
+ + + + + + + + + +
Incoming Queries
+ +
+ + + + + + + + + + + + +
Outgoing Queries from View
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Server Statistics
Requestv4Requestv6ReqEdns0ReqBadEDNSVerReqTSIGReqSIG0ReqBadSIGReqTCPAuthQryRejRecQryRej
XfrRejUpdateRejResponseRespTruncatedRespEDNS0RespTSIGRespSIG0QrySuccessQryAuthAnsQryNoauthAns
QryReferralQryNxrrsetQrySERVFAILQryFORMERRQryNXDOMAINQryRecursionQryDuplicateQryDroppedQryFailureXfrReqDone
UpdateReqFwdUpdateRespFwdUpdateFwdFailUpdateDoneUpdateFailUpdateBadPrereqRespMismatch + + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Zone Maintenance Statistics
NotifyOutv4NotifyOutv6NotifyInv4NotifyInv6NotifyRejSOAOutv4SOAOutv6AXFRReqv4AXFRReqv6IXFRReqv4
IXFRReqv6XfrSuccessXfrFail + + + + + + +
+ + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Resolver Statistics for View
Queryv4Queryv6Responsev4Responsev6NXDOMAINSERVFAILFORMERROtherErrorEDNS0FailTruncated
LameRetryGlueFetchv4GlueFetchv6GlueFetchv4FailGlueFetchv6FailValAttemptValOkValNegOkValFail
+
+
+ +
+ + + + + + + + + + + + +
Cache DB RRsets for View
+
+
+ +
- + @@ -123,10 +400,9 @@ tr.lrow { - - - + + @@ -140,28 +416,25 @@ tr.lrow { - diff --git a/bin/named/bind9.xsl.h b/bin/named/bind9.xsl.h index b26ca2cb50..e409e20b38 100644 --- a/bin/named/bind9.xsl.h +++ b/bin/named/bind9.xsl.h @@ -2,7 +2,7 @@ * Generated by convertxsl.pl 1.11 2008/04/02 23:46:57 tbox Exp * From bind9.xsl 1.15 2008/04/01 23:47:10 tbox Exp */ -static char msg[] = +static char xslmsg[] = "\n" "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Zones for View Zones for View
NameReferral NXRRSET NXDOMAINRecursion FailureDuplicateDroppedXfrReqDoneXfrRej
- + - + - + - + - + - + - - - +
Requestv4Requestv6ReqEdns0ReqBadEDNSVerReqTSIGReqSIG0ReqBadSIGReqTCPAuthQryRejRecQryRej
XfrRejUpdateRejResponseRespTruncatedRespEDNS0RespTSIGRespSIG0QrySuccessQryAuthAnsQryNoauthAns
QryReferralQryNxrrsetQrySERVFAILQryFORMERRQryNXDOMAINQryRecursionQryDuplicateQryDroppedQryFailureXfrReqDone
UpdateReqFwdUpdateRespFwdUpdateFwdFailUpdateDoneUpdateFailUpdateBadPrereqRespMismatch\n" + " \n" + " \n" + "
\n" + " \n" + " \n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Zone Maintenance Statistics
NotifyOutv4NotifyOutv6NotifyInv4NotifyInv6NotifyRejSOAOutv4SOAOutv6AXFRReqv4AXFRReqv6IXFRReqv4
IXFRReqv6XfrSuccessXfrFail\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Resolver Statistics for View
Queryv4Queryv6Responsev4Responsev6NXDOMAINSERVFAILFORMERROtherErrorEDNS0FailTruncated
LameRetryGlueFetchv4GlueFetchv6GlueFetchv4FailGlueFetchv6FailValAttemptValOkValNegOkValFail
\n" + "
\n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Cache DB RRsets for View
\n" + "
\n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -128,10 +405,9 @@ static char msg[] = " \n" " \n" " \n" - " \n" " \n" - " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -145,28 +421,25 @@ static char msg[] = " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" - " \n" " \n" " \n" @@ -348,3 +621,76 @@ static char msg[] = " \n" " \n" "\n"; +static const char *nsstats_xmldesc[] = { "Requestv4", + "Requestv6", + "ReqEdns0", + "ReqBadEDNSVer", + "ReqTSIG", + "ReqSIG0", + "ReqBadSIG", + "ReqTCP", + "AuthQryRej", + "RecQryRej", + "XfrRej", + "UpdateRej", + "Response", + "TruncatedResp", + "RespEDNS0", + "RespTSIG", + "RespSIG0", + "QrySuccess", + "QryAuthAns", + "QryNoauthAns", + "QryReferral", + "QryNxrrset", + "QrySERVFAIL", + "QryFORMERR", + "QryNXDOMAIN", + "QryRecursion", + "QryDuplicate", + "QryDropped", + "QryFailure", + "XfrReqDone", + "UpdateReqFwd", + "UpdateRespFwd", + "UpdateFwdFail", + "UpdateDone", + "UpdateFail", + "UpdateBadPrereq" +}; +static const char *zonestats_xmldesc[] = { "NotifyOutv4", + "NotifyOutv6", + "NotifyInv4", + "NotifyInv6", + "NotifyRej", + "SOAOutv4", + "SOAOutv6", + "AXFRReqv4", + "AXFRReqv6", + "IXFRReqv4", + "IXFRReqv6", + "XfrSuccess", + "XfrFail" +}; +static const char *resstats_xmldesc[] = { "Queryv4", + "Queryv6", + "Responsev4", + "Responsev6", + "NXDOMAIN", + "SERVFAIL", + "FORMERR", + "OtherError", + "EDNS0Fail", + "Mismatch", + "Truncated", + "Lame", + "Retry", + "GlueFetchv4", + "GlueFetchv6", + "GlueFetchv4Fail", + "GlueFetchv6Fail", + "ValAttempt", + "ValOk", + "ValNegOk", + "ValFail" +}; diff --git a/bin/named/client.c b/bin/named/client.c index eab2fc18a1..3a6f2884f1 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.c,v 1.255 2008/04/03 02:01:08 marka Exp $ */ +/* $Id: client.c,v 1.256 2008/04/03 05:55:51 marka Exp $ */ #include @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -918,6 +919,7 @@ ns_client_send(ns_client_t *client) { unsigned char sendbuf[SEND_BUFFER_SIZE]; unsigned int dnssec_opts; unsigned int preferred_glue; + isc_boolean_t opt_included = ISC_FALSE; REQUIRE(NS_CLIENT_VALID(client)); @@ -958,6 +960,7 @@ ns_client_send(ns_client_t *client) { if (client->opt != NULL) { result = dns_message_setopt(client->message, client->opt); + opt_included = ISC_TRUE; client->opt = NULL; if (result != ISC_R_SUCCESS) goto done; @@ -1013,6 +1016,26 @@ ns_client_send(ns_client_t *client) { result = client_sendpkg(client, &tcpbuffer); } else result = client_sendpkg(client, &buffer); + + /* update statistics (XXXJT: is it okay to access message->xxxkey?) */ + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_response); + if (opt_included) { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_edns0out); + } + if (client->message->tsigkey != NULL) { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_tsigout); + } + if (client->message->sig0key != NULL) { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_sig0out); + } + if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0) + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_truncatedresp); + if (result == ISC_R_SUCCESS) return; @@ -1329,6 +1352,7 @@ client_request(isc_task_t *task, isc_event_t *event) { isc_buffer_t tbuffer; dns_view_t *view; dns_rdataset_t *opt; + dns_name_t *signame; isc_boolean_t ra; /* Recursion available. */ isc_netaddr_t netaddr; isc_netaddr_t destaddr; @@ -1486,6 +1510,20 @@ client_request(isc_task_t *task, isc_event_t *event) { } } + /* + * Update some statistics counters. Don't count responses. + */ + if (isc_sockaddr_pf(&client->peeraddr) == PF_INET) { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_requestv4); + } else { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_requestv6); + } + if (TCP_CLIENT(client)) + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_tcp); + /* * Hash the incoming request here as it is after * dns_dispatch_importrecv(). @@ -1507,6 +1545,8 @@ client_request(isc_task_t *task, isc_event_t *event) { goto cleanup; } + dns_opcodestats_increment(ns_g_server->opcodestats, + client->message->opcode); switch (client->message->opcode) { case dns_opcode_query: case dns_opcode_update: @@ -1554,6 +1594,8 @@ client_request(isc_task_t *task, isc_event_t *event) { */ client->ednsversion = (opt->ttl & 0x00FF0000) >> 16; if (client->ednsversion > 0) { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_badednsver); result = client_addopt(client); if (result == ISC_R_SUCCESS) result = DNS_R_BADVERS; @@ -1578,6 +1620,9 @@ client_request(isc_task_t *task, isc_event_t *event) { } } + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_edns0in); + /* * Create an OPT for our reply. */ @@ -1722,6 +1767,17 @@ client_request(isc_task_t *task, isc_event_t *event) { client->signer = NULL; dns_name_init(&client->signername, NULL); result = dns_message_signer(client->message, &client->signername); + if (result != ISC_R_NOTFOUND) { + signame = NULL; + if (dns_message_gettsig(client->message, &signame) != NULL) { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_tsigin); + } else { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_sig0in); + } + + } if (result == ISC_R_SUCCESS) { ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), @@ -1738,15 +1794,17 @@ client_request(isc_task_t *task, isc_event_t *event) { } else { char tsigrcode[64]; isc_buffer_t b; - dns_name_t *name = NULL; dns_rcode_t status; isc_result_t tresult; /* There is a signature, but it is bad. */ - if (dns_message_gettsig(client->message, &name) != NULL) { + dns_generalstats_increment(ns_g_server->nsstats, + dns_nsstatscounter_invalidsig); + signame = NULL; + if (dns_message_gettsig(client->message, &signame) != NULL) { char namebuf[DNS_NAME_FORMATSIZE]; char cnamebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(name, namebuf, sizeof(namebuf)); + dns_name_format(signame, namebuf, sizeof(namebuf)); status = client->message->tsigstatus; isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1); tresult = dns_tsigrcode_totext(status, &b); diff --git a/bin/named/convertxsl.pl b/bin/named/convertxsl.pl index ea6a2d2d04..6b4d2d70df 100755 --- a/bin/named/convertxsl.pl +++ b/bin/named/convertxsl.pl @@ -14,19 +14,19 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: convertxsl.pl,v 1.11 2008/04/02 23:46:57 tbox Exp $ +# $Id: convertxsl.pl,v 1.12 2008/04/03 05:55:51 marka Exp $ use strict; use warnings; -my $rev = '$Id: convertxsl.pl,v 1.11 2008/04/02 23:46:57 tbox Exp $'; +my $rev = '$Id: convertxsl.pl,v 1.12 2008/04/03 05:55:51 marka Exp $'; $rev =~ s/\$//g; $rev =~ s/,v//g; $rev =~ s/Id: //; my $xsl = "unknown"; - my $lines = ''; +my (@nsstatsdesc, @zonestatsdesc, @resstatsdesc); while (<>) { chomp; @@ -34,6 +34,13 @@ while (<>) { $xsl = $_ if (//); # convert Id string to a form not recognisable by cvs. $_ =~ s///; + if (/server\/nsstats\/(\w+)\"/) { + push(@nsstatsdesc, $1); + } elsif (/server\/zonestats\/(\w+)\"/) { + push(@zonestatsdesc, $1); + } elsif (/\"resstats\/(\w+)\"/) { + push(@resstatsdesc, $1); + } s/[\ \t]+/ /g; s/\>\ \\.*//; $xsl =~ s/,v//; print "/*\n * Generated by $rev \n * From $xsl\n */\n"; -print 'static char msg[] =',"\n"; +print 'static char xslmsg[] =',"\n"; print $lines; print ';', "\n"; + +print "static const char *nsstats_xmldesc[] = {"; +while (my $desc = shift(@nsstatsdesc)) { + print "\t\"$desc\""; + print "," if (@nsstatsdesc); + print "\n"; +} +print "};\n"; + +print "static const char *zonestats_xmldesc[] = {"; +while (my $desc = shift(@zonestatsdesc)) { + print "\t\"$desc\""; + print "," if (@zonestatsdesc); + print "\n"; +} +print "};\n"; + +print "static const char *resstats_xmldesc[] = {"; +while (my $desc = shift(@resstatsdesc)) { + print "\t\"$desc\""; + print "," if (@resstatsdesc); + print "\n"; +} +print "};\n"; diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 1bf0524472..d3a75fd933 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.h,v 1.92 2008/01/24 02:00:44 jinmei Exp $ */ +/* $Id: server.h,v 1.93 2008/04/03 05:55:51 marka Exp $ */ #ifndef NAMED_SERVER_H #define NAMED_SERVER_H 1 @@ -91,7 +91,11 @@ struct ns_server { isc_boolean_t flushonshutdown; isc_boolean_t log_queries; /*%< For BIND 8 compatibility */ - dns_stats_t * querystats; /*%< Query statistics counters */ + dns_stats_t * nsstats; /*%< Server statistics */ + dns_stats_t * rcvquerystats; /*% Incoming query statistics */ + dns_stats_t * opcodestats; /*%< Incoming message statistics */ + dns_stats_t * zonestats; /*% Zone management statistics */ + dns_stats_t * resolverstats; /*% Resolver statistics */ ns_controls_t * controls; /*%< Control channels */ unsigned int dispatchgen; @@ -105,6 +109,55 @@ struct ns_server { #define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') #define NS_SERVER_VALID(s) ISC_MAGIC_VALID(s, NS_SERVER_MAGIC) +/*% + * Server statistics counters. Used as dns_statscounter_t values. + */ +enum { + dns_nsstatscounter_requestv4 = 0, + dns_nsstatscounter_requestv6 = 1, + dns_nsstatscounter_edns0in = 2, + dns_nsstatscounter_badednsver = 3, + dns_nsstatscounter_tsigin = 4, + dns_nsstatscounter_sig0in = 5, + dns_nsstatscounter_invalidsig = 6, + dns_nsstatscounter_tcp = 7, + + dns_nsstatscounter_authrej = 8, + dns_nsstatscounter_recurserej = 9, + dns_nsstatscounter_xfrrej = 10, + dns_nsstatscounter_updaterej = 11, + + dns_nsstatscounter_response = 12, + dns_nsstatscounter_truncatedresp = 13, + dns_nsstatscounter_edns0out = 14, + dns_nsstatscounter_tsigout = 15, + dns_nsstatscounter_sig0out = 16, + + dns_nsstatscounter_success = 17, + dns_nsstatscounter_authans = 18, + dns_nsstatscounter_nonauthans = 19, + dns_nsstatscounter_referral = 20, + dns_nsstatscounter_nxrrset = 21, + dns_nsstatscounter_servfail = 22, + dns_nsstatscounter_formerr = 23, + dns_nsstatscounter_nxdomain = 24, + dns_nsstatscounter_recursion = 25, + dns_nsstatscounter_duplicate = 26, + dns_nsstatscounter_dropped = 27, + dns_nsstatscounter_failure = 28, + + dns_nsstatscounter_xfrdone = 29, + + dns_nsstatscounter_updatereqfwd = 30, + dns_nsstatscounter_updaterespfwd = 31, + dns_nsstatscounter_updatefwdfail = 32, + dns_nsstatscounter_updatedone = 33, + dns_nsstatscounter_updatefail = 34, + dns_nsstatscounter_updatebadprereq = 35, + + dns_nsstatscounter_max = 36 +}; + void ns_server_create(isc_mem_t *mctx, ns_server_t **serverp); /*%< diff --git a/bin/named/include/named/statschannel.h b/bin/named/include/named/statschannel.h index 13c941ae06..0c36d8c706 100644 --- a/bin/named/include/named/statschannel.h +++ b/bin/named/include/named/statschannel.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: statschannel.h,v 1.2 2008/01/17 00:15:13 jinmei Exp $ */ +/* $Id: statschannel.h,v 1.3 2008/04/03 05:55:51 marka Exp $ */ #ifndef NAMED_STATSCHANNEL_H #define NAMED_STATSCHANNEL_H 1 @@ -52,4 +52,10 @@ ns_statschannels_shutdown(ns_server_t *server); * Initiate shutdown of all the statistics channel listeners. */ +isc_result_t +ns_stats_dump(ns_server_t *server, FILE *fp); +/*%< + * Dump statistics counters managed by the server to the file fp. + */ + #endif /* NAMED_STATSCHANNEL_H */ diff --git a/bin/named/query.c b/bin/named/query.c index 21c47f5ffc..ea5109a7f5 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.c,v 1.304 2008/04/01 01:37:24 marka Exp $ */ +/* $Id: query.c,v 1.305 2008/04/03 05:55:51 marka Exp $ */ /*! \file */ @@ -128,35 +128,37 @@ static inline void inc_stats(ns_client_t *client, dns_statscounter_t counter) { dns_zone_t *zone = client->query.authzone; - REQUIRE(counter < DNS_STATS_NCOUNTERS); - - dns_stats_incrementcounter(ns_g_server->querystats, counter); + dns_generalstats_increment(ns_g_server->nsstats, counter); if (zone != NULL) { - dns_stats_t *zonestats = dns_zone_getstats(zone); + dns_stats_t *zonestats = dns_zone_getrequeststats(zone); if (zonestats != NULL) - dns_stats_incrementcounter(zonestats, counter); + dns_generalstats_increment(zonestats, counter); } } static void query_send(ns_client_t *client) { dns_statscounter_t counter; + if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0) + inc_stats(client, dns_nsstatscounter_nonauthans); + else + inc_stats(client, dns_nsstatscounter_authans); if (client->message->rcode == dns_rcode_noerror) { if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER])) { if (client->query.isreferral) { - counter = dns_statscounter_referral; + counter = dns_nsstatscounter_referral; } else { - counter = dns_statscounter_nxrrset; + counter = dns_nsstatscounter_nxrrset; } } else { - counter = dns_statscounter_success; + counter = dns_nsstatscounter_success; } } else if (client->message->rcode == dns_rcode_nxdomain) { - counter = dns_statscounter_nxdomain; + counter = dns_nsstatscounter_nxdomain; } else { /* We end up here in case of YXDOMAIN, and maybe others */ - counter = dns_statscounter_failure; + counter = dns_nsstatscounter_failure; } inc_stats(client, counter); ns_client_send(client); @@ -164,18 +166,28 @@ query_send(ns_client_t *client) { static void query_error(ns_client_t *client, isc_result_t result) { - inc_stats(client, dns_statscounter_failure); + switch (result) { + case DNS_R_SERVFAIL: + inc_stats(client, dns_nsstatscounter_servfail); + break; + case DNS_R_FORMERR: + inc_stats(client, dns_nsstatscounter_formerr); + break; + default: + inc_stats(client, dns_nsstatscounter_failure); + break; + } ns_client_error(client, result); } static void query_next(ns_client_t *client, isc_result_t result) { if (result == DNS_R_DUPLICATE) - inc_stats(client, dns_statscounter_duplicate); + inc_stats(client, dns_nsstatscounter_duplicate); else if (result == DNS_R_DROP) - inc_stats(client, dns_statscounter_dropped); + inc_stats(client, dns_nsstatscounter_dropped); else - inc_stats(client, dns_statscounter_failure); + inc_stats(client, dns_nsstatscounter_failure); ns_client_next(client, result); } @@ -2935,7 +2947,7 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, dns_rdataset_t *rdataset, *sigrdataset; isc_sockaddr_t *peeraddr; - inc_stats(client, dns_statscounter_recursion); + inc_stats(client, dns_nsstatscounter_recursion); /* * We are about to recurse, which means that this client will @@ -3494,6 +3506,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) } if (result != ISC_R_SUCCESS) { if (result == DNS_R_REFUSED) { + if (WANTRECURSION(client)) { + inc_stats(client, + dns_nsstatscounter_recurserej); + } else + inc_stats(client, dns_nsstatscounter_authrej); if (!PARTIALANSWER(client)) QUERY_ERROR(DNS_R_REFUSED); } else @@ -4550,6 +4567,7 @@ ns_query_start(ns_client_t *client) { rdataset = ISC_LIST_HEAD(client->query.qname->list); INSIST(rdataset != NULL); qtype = rdataset->type; + dns_rdatatypestats_increment(ns_g_server->rcvquerystats, qtype); if (dns_rdatatype_ismeta(qtype)) { switch (qtype) { case dns_rdatatype_any: diff --git a/bin/named/server.c b/bin/named/server.c index fb018b6ce9..b6dbd7370e 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.504 2008/04/03 02:01:08 marka Exp $ */ +/* $Id: server.c,v 1.505 2008/04/03 05:55:51 marka Exp $ */ /*! \file */ @@ -942,6 +942,24 @@ check_dbtype(dns_zone_t **zonep, unsigned int dbtypec, const char **dbargv, isc_mem_free(mctx, argv); } +static isc_result_t +setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) { + isc_result_t result; + dns_stats_t *zoneqrystats; + + zoneqrystats = NULL; + if (on) { + result = dns_generalstats_create(mctx, &zoneqrystats, + dns_nsstatscounter_max); + if (result != ISC_R_SUCCESS) + return (result); + } + dns_zone_setrequeststats(zone, zoneqrystats); + if (zoneqrystats != NULL) + dns_stats_detach(&zoneqrystats); + + return (ISC_R_SUCCESS); +} /* * Configure 'view' according to 'vconfig', taking defaults from 'config' @@ -998,6 +1016,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, isc_boolean_t empty_zones_enable; const cfg_obj_t *disablelist = NULL; isc_uint32_t nqports, qports_updateinterval; + dns_stats_t *resstats = NULL; + dns_stats_t *resquerystats = NULL; REQUIRE(DNS_VIEW_VALID(view)); @@ -1142,6 +1162,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, * Configure the view's cache. Try to reuse an existing * cache if possible, otherwise create a new cache. * Note that the ADB is not preserved in either case. + * When a matching view is found, the associated statistics are + * also retrieved and reused. * * XXX Determining when it is safe to reuse a cache is * tricky. When the view's configuration changes, the cached @@ -1163,6 +1185,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, "reusing existing cache"); reused_cache = ISC_TRUE; dns_cache_attach(pview->cache, &cache); + dns_view_getresstats(pview, &resstats); + dns_view_getresquerystats(pview, &resquerystats); dns_view_detach(&pview); } else { CHECK(isc_mem_create(0, 0, &cmctx)); @@ -1344,6 +1368,15 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, * 60)); } + if (resstats == NULL) { + CHECK(dns_generalstats_create(mctx, &resstats, + dns_resstatscounter_max)); + } + dns_view_setresstats(view, resstats); + if (resquerystats == NULL) + CHECK(dns_rdatatypestats_create(mctx, &resquerystats)); + dns_view_setresquerystats(view, resquerystats); + /* * Set the ADB cache size to 1/8th of the max-cache-size. */ @@ -1835,6 +1868,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, const char *empty_dbtype[4] = { "_builtin", "empty", NULL, NULL }; int empty_dbtypec = 4; + isc_boolean_t zonestats_on; dns_fixedname_init(&fixed); name = dns_fixedname_name(&fixed); @@ -1869,6 +1903,11 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, } else empty_dbtype[3] = "."; + obj = NULL; + result = ns_config_get(maps, "zone-statistics", &obj); + INSIST(result == ISC_R_SUCCESS); + zonestats_on = cfg_obj_asboolean(obj); + logit = ISC_TRUE; for (empty = empty_zones[empty_zone].zone; empty != NULL; @@ -1893,6 +1932,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, */ (void)dns_view_findzone(view, name, &zone); if (zone != NULL) { + CHECK(setquerystats(zone, mctx, zonestats_on)); dns_zone_detach(&zone); continue; } @@ -1943,6 +1983,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, if (zone != NULL) { dns_zone_setview(zone, view); CHECK(dns_view_addzone(view, zone)); + CHECK(setquerystats(zone, mctx, + zonestats_on)); dns_zone_detach(&zone); continue; } @@ -1954,6 +1996,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); dns_zone_setclass(zone, view->rdclass); dns_zone_settype(zone, dns_zone_master); + dns_zone_setstats(zone, ns_g_server->zonestats); CHECK(dns_zone_setdbtype(zone, empty_dbtypec, empty_dbtype)); if (view->queryacl != NULL) @@ -1964,6 +2007,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_zone_setnotifytype(zone, dns_notifytype_no); dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, ISC_TRUE); + CHECK(setquerystats(zone, mctx, zonestats_on)); CHECK(dns_view_addzone(view, zone)); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_INFO, @@ -1982,6 +2026,10 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, dns_dispatch_detach(&dispatch4); if (dispatch6 != NULL) dns_dispatch_detach(&dispatch6); + if (resstats != NULL) + dns_stats_detach(&resstats); + if (resquerystats != NULL) + dns_stats_detach(&resquerystats); if (order != NULL) dns_order_detach(&order); if (cmctx != NULL) @@ -2430,6 +2478,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, if (view->acache != NULL) dns_zone_setacache(zone, view->acache); CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone)); + dns_zone_setstats(zone, ns_g_server->zonestats); } /* @@ -3613,6 +3662,8 @@ run_server(isc_task_t *task, isc_event_t *event) { &ns_g_dispatchmgr), "creating dispatch manager"); + dns_dispatchmgr_setstats(ns_g_dispatchmgr, server->resolverstats); + CHECKFATAL(ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_socketmgr, ns_g_dispatchmgr, &server->interfacemgr), @@ -3801,7 +3852,11 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->statsfile = isc_mem_strdup(server->mctx, "named.stats"); CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, "isc_mem_strdup"); - server->querystats = NULL; + server->nsstats = NULL; + server->rcvquerystats = NULL; + server->opcodestats = NULL; + server->zonestats = NULL; + server->resolverstats = NULL; server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db"); CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS, @@ -3818,8 +3873,24 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { server->server_usehostname = ISC_FALSE; server->server_id = NULL; - CHECKFATAL(dns_stats_create(ns_g_mctx, &server->querystats), - "dns_stats_create"); + CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->nsstats, + dns_nsstatscounter_max), + "dns_stats_create (server)"); + + CHECKFATAL(dns_rdatatypestats_create(ns_g_mctx, + &server->rcvquerystats), + "dns_stats_create (rcvquery)"); + + CHECKFATAL(dns_opcodestats_create(ns_g_mctx, &server->opcodestats), + "dns_stats_create (opcode)"); + + CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->zonestats, + dns_zonestatscounter_max), + "dns_stats_create (zone)"); + + CHECKFATAL(dns_generalstats_create(ns_g_mctx, &server->resolverstats, + dns_resstatscounter_max), + "dns_stats_create (resolver)"); server->flushonshutdown = ISC_FALSE; server->log_queries = ISC_FALSE; @@ -3843,7 +3914,11 @@ ns_server_destroy(ns_server_t **serverp) { ns_controls_destroy(&server->controls); - dns_stats_destroy(server->mctx, &server->querystats); + dns_stats_detach(&server->nsstats); + dns_stats_detach(&server->rcvquerystats); + dns_stats_detach(&server->opcodestats); + dns_stats_detach(&server->zonestats); + dns_stats_detach(&server->resolverstats); isc_mem_free(server->mctx, server->statsfile); isc_mem_free(server->mctx, server->dumpfile); @@ -4407,60 +4482,14 @@ ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config, isc_result_t ns_server_dumpstats(ns_server_t *server) { isc_result_t result; - dns_zone_t *zone, *next; - isc_stdtime_t now; FILE *fp = NULL; - int i; - int ncounters; - isc_uint64_t counters[DNS_STATS_NCOUNTERS]; - - isc_stdtime_get(&now); CHECKMF(isc_stdio_open(server->statsfile, "a", &fp), "could not open statistics dump file", server->statsfile); - ncounters = DNS_STATS_NCOUNTERS; - fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); - - dns_stats_copy(server->querystats, counters); - for (i = 0; i < ncounters; i++) - fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT "u\n", - dns_statscounter_names[i], counters[i]); - - zone = NULL; - for (result = dns_zone_first(server->zonemgr, &zone); - result == ISC_R_SUCCESS; - next = NULL, result = dns_zone_next(zone, &next), zone = next) - { - dns_stats_t *zonestats = dns_zone_getstats(zone); - if (zonestats != NULL) { - char zonename[DNS_NAME_FORMATSIZE]; - dns_view_t *view; - char *viewname; - - dns_stats_copy(zonestats, counters); - dns_name_format(dns_zone_getorigin(zone), - zonename, sizeof(zonename)); - view = dns_zone_getview(zone); - viewname = view->name; - for (i = 0; i < ncounters; i++) { - fprintf(fp, "%s %" ISC_PRINT_QUADFORMAT - "u %s", - dns_statscounter_names[i], - counters[i], - zonename); - if (strcmp(viewname, "_default") != 0) - fprintf(fp, " %s", viewname); - fprintf(fp, "\n"); - } - } - } - if (result == ISC_R_NOMORE) - result = ISC_R_SUCCESS; + result = ns_stats_dump(server, fp); CHECK(result); - fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); - cleanup: if (fp != NULL) (void)isc_stdio_close(fp); diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 3bdef8bddf..d3be869727 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: statschannel.c,v 1.6 2008/03/31 05:00:29 marka Exp $ */ +/* $Id: statschannel.c,v 1.7 2008/04/03 05:55:51 marka Exp $ */ /*! \file */ @@ -27,13 +27,20 @@ #include #include +#include +#include +#include +#include #include #include +#include #include #include #include +#include "bind9.xsl.h" + struct ns_statschannel { /* Unlocked */ isc_httpdmgr_t *httpdmgr; @@ -51,6 +58,188 @@ struct ns_statschannel { ISC_LINK(struct ns_statschannel) link; }; +typedef enum { statsformat_file, statsformat_xml } statsformat_t; + +typedef struct +stats_dumparg { + statsformat_t type; + void *arg; /* type dependent argument */ + const char **desc; /* used for general statistics */ + int ncounters; /* used for general statistics */ +} stats_dumparg_t; + +static void +generalstat_dump(dns_statscounter_t counter, isc_uint64_t val, void *arg) { + stats_dumparg_t *dumparg = arg; + FILE *fp; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + + REQUIRE(counter < dumparg->ncounters); + + switch (dumparg->type) { + case statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, + dumparg->desc[counter]); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR + dumparg->desc[counter]); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + val); + xmlTextWriterEndElement(writer); +#endif + break; + } +} + +static void +rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) { + char typebuf[64]; + const char *typestr; + stats_dumparg_t *dumparg = arg; + FILE *fp; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + + if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) + == 0) { + dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, + sizeof(typebuf)); + typestr = typebuf; + } else + typestr = "Others"; + + switch (dumparg->type) { + case statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdtype"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR typestr); + xmlTextWriterEndElement(writer); /* name */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + val); + xmlTextWriterEndElement(writer); /* counter */ + + xmlTextWriterEndElement(writer); /* rdtype */ +#endif + break; + } +} + +static void +rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) { + stats_dumparg_t *dumparg = arg; + FILE *fp; + char typebuf[64]; + const char *typestr; + isc_boolean_t nxrrset = ISC_FALSE; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + + if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) + != 0) { + typestr = "NXDOMAIN"; + } else if ((DNS_RDATASTATSTYPE_ATTR(type) & + DNS_RDATASTATSTYPE_ATTR_OTHERTYPE) != 0) { + typestr = "Others"; + } else { + dns_rdatatype_format(DNS_RDATASTATSTYPE_BASE(type), typebuf, + sizeof(typebuf)); + typestr = typebuf; + } + + if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_NXRRSET) + != 0) + nxrrset = ISC_TRUE; + + switch (dumparg->type) { + case statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s\n", val, + nxrrset ? "!" : "", typestr); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteFormatString(writer, "%s%s", + nxrrset ? "!" : "", typestr); + xmlTextWriterEndElement(writer); /* name */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + val); + xmlTextWriterEndElement(writer); /* counter */ + + xmlTextWriterEndElement(writer); /* rrset */ +#endif + break; + } +} + +static void +opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) { + FILE *fp = arg; + isc_buffer_t b; + char codebuf[64]; + stats_dumparg_t *dumparg = arg; +#ifdef HAVE_LIBXML2 + xmlTextWriterPtr writer; +#endif + + isc_buffer_init(&b, codebuf, sizeof(codebuf) - 1); + dns_opcode_totext(code, &b); + codebuf[isc_buffer_usedlength(&b)] = '\0'; + + switch (dumparg->type) { + case statsformat_file: + fp = dumparg->arg; + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf); + break; + case statsformat_xml: +#ifdef HAVE_LIBXML2 + writer = dumparg->arg; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "opcode"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR codebuf); + xmlTextWriterEndElement(writer); /* name */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + val); + xmlTextWriterEndElement(writer); /* counter */ + + xmlTextWriterEndElement(writer); /* opcode */ +#endif + break; + } +} + #ifdef HAVE_LIBXML2 /* XXXMLG below here sucks. */ @@ -58,8 +247,50 @@ struct ns_statschannel { #define TRY(a) do { result = (a); INSIST(result == ISC_R_SUCCESS); } while(0); #define TRY0(a) do { xmlrc = (a); INSIST(xmlrc >= 0); } while(0); -#define NODES 8 -#define SPACES 3 +static isc_result_t +zone_xmlrender(dns_zone_t *zone, void *arg) { + char buf[1024 + 32]; /* sufficiently large for zone name and class */ + dns_rdataclass_t rdclass; + isc_uint32_t serial; + xmlTextWriterPtr writer = arg; + stats_dumparg_t dumparg; + dns_stats_t *zonestats; + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "zone"); + + dns_zone_name(zone, buf, sizeof(buf)); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR buf); + xmlTextWriterEndElement(writer); + + rdclass = dns_zone_getclass(zone); + dns_rdataclass_format(rdclass, buf, sizeof(buf)); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "rdataclass"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR buf); + xmlTextWriterEndElement(writer); + + serial = dns_zone_getserial(zone); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "serial"); + xmlTextWriterWriteFormatString(writer, "%u", serial); + xmlTextWriterEndElement(writer); + + dumparg.type = statsformat_xml; + dumparg.arg = writer; + dumparg.desc = nsstats_xmldesc; + dumparg.ncounters = dns_nsstatscounter_max; + + zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"); + dns_generalstats_dump(zonestats, generalstat_dump, + &dumparg, DNS_STATSDUMP_VERBOSE); + xmlTextWriterEndElement(writer); /* counters */ + } + + xmlTextWriterEndElement(writer); /* zone */ + + return (ISC_R_SUCCESS); +} static void generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { @@ -70,8 +301,8 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { xmlDocPtr doc; int xmlrc; dns_view_t *view; - int i; - isc_uint64_t counters[DNS_STATS_NCOUNTERS]; + stats_dumparg_t dumparg; + dns_stats_t *cachestats; isc_time_now(&now); isc_time_formatISO8601(&ns_g_boottime, boottime, sizeof boottime); @@ -90,6 +321,10 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", ISC_XMLCHAR "1.0")); + /* Set common fields for statistics dump */ + dumparg.type = statsformat_xml; + dumparg.arg = writer; + /* * Start by rendering the views we know of here. For each view we * know of, call its rendering function. @@ -97,7 +332,43 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { view = ISC_LIST_HEAD(server->viewlist); TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views")); while (view != NULL) { - dns_view_xmlrender(view, writer, ISC_XML_RENDERALL); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR view->name); + xmlTextWriterEndElement(writer); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "zones"); + dns_zt_apply(view->zonetable, ISC_FALSE, zone_xmlrender, + writer); + xmlTextWriterEndElement(writer); + + if (view->resquerystats != NULL) { + dns_rdatatypestats_dump(view->resquerystats, + rdtypestat_dump, &dumparg, 0); + } + + if (view->resstats != NULL) { + xmlTextWriterStartElement(writer, + ISC_XMLCHAR "resstats"); + dumparg.ncounters = dns_resstatscounter_max; + dumparg.desc = resstats_xmldesc; /* auto-generated */ + dns_generalstats_dump(view->resstats, generalstat_dump, + &dumparg, DNS_STATSDUMP_VERBOSE); + xmlTextWriterEndElement(writer); /* resstats */ + } + + cachestats = dns_db_getrrsetstats(view->cachedb); + if (cachestats != NULL) { + xmlTextWriterStartElement(writer, + ISC_XMLCHAR "cache"); + dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, + &dumparg, 0); + xmlTextWriterEndElement(writer); /* cache */ + } + + xmlTextWriterEndElement(writer); /* view */ + view = ISC_LIST_NEXT(view, link); } TRY0(xmlTextWriterEndElement(writer)); /* views */ @@ -117,17 +388,38 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"); xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr); xmlTextWriterEndElement(writer); - TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters")); - dns_stats_copy(server->querystats, counters); - for (i = 0; i < DNS_STATS_NCOUNTERS; i++) { - xmlTextWriterStartElement(writer, - ISC_XMLCHAR dns_statscounter_names[i]); - xmlTextWriterWriteFormatString(writer, - "%" ISC_PRINT_QUADFORMAT "u", - counters[i]); - xmlTextWriterEndElement(writer); - } - xmlTextWriterEndElement(writer); /* counters */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "requests")); + dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, + 0); + xmlTextWriterEndElement(writer); /* requests */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "queries-in")); + dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump, + &dumparg, 0); + xmlTextWriterEndElement(writer); /* queries-in */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "nsstats")); + dumparg.desc = nsstats_xmldesc; /* auto-generated in bind9.xsl.h */ + dumparg.ncounters = dns_nsstatscounter_max; + dns_generalstats_dump(server->nsstats, generalstat_dump, &dumparg, + DNS_STATSDUMP_VERBOSE); + xmlTextWriterEndElement(writer); /* nsstats */ + + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zonestats")); + dumparg.desc = zonestats_xmldesc; /* auto-generated in bind9.xsl.h */ + dumparg.ncounters = dns_zonestatscounter_max; + dns_generalstats_dump(server->zonestats, generalstat_dump, &dumparg, + DNS_STATSDUMP_VERBOSE); + xmlTextWriterEndElement(writer); /* zonestats */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "resstats"); + dumparg.ncounters = dns_resstatscounter_max; + dumparg.desc = resstats_xmldesc; + dns_generalstats_dump(server->resolverstats, generalstat_dump, + &dumparg, DNS_STATSDUMP_VERBOSE); + xmlTextWriterEndElement(writer); /* resstats */ + xmlTextWriterEndElement(writer); /* server */ TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory")); @@ -187,8 +479,6 @@ render_xsl(const char *url, const char *querystring, void *args, isc_buffer_t *b, isc_httpdfree_t **freecb, void **freecb_args) { -#include "bind9.xsl.h" - UNUSED(url); UNUSED(querystring); UNUSED(args); @@ -196,8 +486,8 @@ render_xsl(const char *url, const char *querystring, void *args, *retcode = 200; *retmsg = "OK"; *mimetype = "text/xslt+xml"; - isc_buffer_reinit(b, msg, strlen(msg)); - isc_buffer_add(b, strlen(msg)); + isc_buffer_reinit(b, xslmsg, strlen(xslmsg)); + isc_buffer_add(b, strlen(xslmsg)); *freecb = NULL; *freecb_args = NULL; @@ -533,3 +823,207 @@ ns_statschannels_shutdown(ns_server_t *server) { shutdown_listener(listener); } } + +/* name server statistics */ +static const char *nsstats_desc[] = { + "IPv4 requests received", /* dns_nsstatscounter_requestv4 */ + "IPv6 requests received", /* dns_nsstatscounter_requestv6 */ + "requests with EDNS(0) received", /* dns_nsstatscounter_edns0in */ + "requests with unsupported EDNS " + "version received", /* dns_nsstatscounter_badednsver */ + "requests with TSIG received", /* dns_nsstatscounter_tsigin */ + "requests with SIG(0) received", /* dns_nsstatscounter_sig0in */ + "requests with invalid signature",/* dns_nsstatscounter_invalidsig */ + "TCP requests received", /* dns_nsstatscounter_tcp */ + + "auth queries rejected", /* dns_nsstatscounter_authrej */ + "recursive queries rejected", /* dns_nsstatscounter_recurserej */ + "transfer requests rejected", /* dns_nsstatscounter_xfrrej */ + "update requests rejected", /* dns_nsstatscounter_updaterej */ + + "responses sent", /* dns_nsstatscounter_response */ + "truncated responses sent", /* dns_nsstatscounter_truncatedresp */ + "responses with EDNS(0) sent", /* dns_nsstatscounter_edns0out */ + "responses with TSIG sent", /* dns_nsstatscounter_tsigout */ + "responses with SIG(0) sent", /* dns_nsstatscounter_sig0out */ + + "queries resulted in successful answer",/* dns_nsstatscounter_success */ + "queries resulted in " + "authoritative answer", /* dns_nsstatscounter_authans */ + "queries resulted in non " + "authoritative answer", /* dns_nsstatscounter_nonauthans */ + "queries resulted in referral answer", /* dns_nsstatscounter_referral */ + "queries resulted in nxrrset", /* dns_nsstatscounter_nxrrset */ + "queries resulted in SERVFAIL", /* dns_nsstatscounter_servfail */ + "queries resulted in FORMERR", /* dns_nsstatscounter_formerr */ + "queries resulted in NXDOMAIN", /* dns_nsstatscounter_nxdomain */ + "queries caused recursion", /* dns_nsstatscounter_recursion */ + "duplicate queries received", /* dns_nsstatscounter_duplicate */ + "queries dropped", /* dns_nsstatscounter_dropped */ + "other query failures", /* dns_nsstatscounter_failure */ + + "requested transfers completed", /* dns_nsstatscounter_xfrdone */ + + "update requests forwarded", /* dns_nsstatscounter_updatereqfwd */ + "update responses forwarded", /* dns_nsstatscounter_updaterespfwd */ + "update forward failed", /* dns_nsstatscounter_updatefwdfail */ + "updates completed", /* dns_nsstatscounter_updatedone */ + "updates failed", /* dns_nsstatscounter_updatefail */ + "updates rejected due to " + "prerequisite failure" /* dns_nsstatscounter_updatebadprereq */ +}; + +/* resolver statistics */ +static const char *resstats_desc[] = { + "IPv4 queries sent", /* dns_resstatscounter_queryv4 */ + "IPv6 queries sent", /* dns_resstatscounter_queryv6 */ + "IPv4 responses received", /* dns_resstatscounter_responsev4 */ + "IPv6 responses received", /* dns_resstatscounter_responsev6 */ + "NXDOMAIN received", /* dns_resstatscounter_nxdomain */ + "SERVFAIL received", /* dns_resstatscounter_servfail */ + "FORMERR received", /* dns_resstatscounter_formerr */ + "other errors received", /* dns_resstatscounter_othererror */ + "EDNS(0) query failures", /* dns_resstatscounter_edns0fail */ + "mismatch responses received", /* dns_resstatscounter_mismatch */ + "truncated responses received", /* dns_resstatscounter_truncated */ + "lame delegations received", /* dns_resstatscounter_lame */ + "query retries", /* dns_resstatscounter_retry */ + "IPv4 NS address fetches", /* dns_resstatscounter_gluefetchv4 */ + "IPv6 NS address fetches", /* dns_resstatscounter_gluefetchv6 */ + "IPv4 NS address fetch failed", /* dns_resstatscounter_gluefetchv4fail */ + "IPv6 NS address fetch failed", /* dns_resstatscounter_gluefetchv6fail */ + "DNSSEC validation attempted", /* dns_resstatscounter_val */ + "DNSSEC validation failed", /* dns_resstatscounter_valfail */ + "DNSSEC validation succeeded", /* dns_resstatscounter_valsuccess */ + "DNSSEC NX validation succeeded"/* dns_resstatscounter_valnegsuccess */ +}; + +/* zone statistics */ +static const char *zonestats_desc[] = { + "IPv4 notifies sent", /* dns_zonestatscounter_notifyoutv4 */ + "IPv6 notifies sent", /* dns_zonestatscounter_notifyoutv6 */ + "IPv4 notifies received", /* dns_zonestatscounter_notifyinv4 */ + "IPv6 notifies received", /* dns_zonestatscounter_notifyinv6 */ + "notifies rejected", /* dns_zonestatscounter_notifyrej */ + "IPv4 SOA queries sent", /* dns_zonestatscounter_soaoutv4 */ + "IPv6 SOA queries sent", /* dns_zonestatscounter_soaoutv6 */ + "IPv4 AXFR requested", /* dns_zonestatscounter_axfrreqv4 */ + "IPv6 AXFR requested", /* dns_zonestatscounter_axfrreqv6 */ + "IPv4 IXFR requested", /* dns_zonestatscounter_ixfrreqv4 */ + "IPv6 IXFR requested", /* dns_zonestatscounter_ixfrreqv6 */ + "transfer requests succeeded", /* dns_zonestatscounter_xfrsuccess */ + "transfer requests failed" /* dns_zonestatscounter_xfrfail */ +}; + +isc_result_t +ns_stats_dump(ns_server_t *server, FILE *fp) { + isc_stdtime_t now; + isc_result_t result; + dns_view_t *view; + dns_zone_t *zone, *next; + stats_dumparg_t dumparg; + + /* Set common fields */ + dumparg.type = statsformat_file; + dumparg.arg = fp; + + isc_stdtime_get(&now); + fprintf(fp, "+++ Statistics Dump +++ (%lu)\n", (unsigned long)now); + + fprintf(fp, "++ Incoming Requests ++\n"); + dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg, + 0); + + fprintf(fp, "++ Incoming Queries ++\n"); + dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump, + &dumparg, 0); + + fprintf(fp, "++ Outgoing Queries ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->resquerystats == NULL) + continue; + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s]\n", view->name); + dns_rdatatypestats_dump(view->resquerystats, rdtypestat_dump, + &dumparg, 0); + } + + fprintf(fp, "++ Name Server Statistics ++\n"); + dumparg.desc = nsstats_desc; + dumparg.ncounters = dns_nsstatscounter_max; + dns_generalstats_dump(server->nsstats, generalstat_dump, &dumparg, 0); + fprintf(fp, "++ Zone Maintenance Statistics ++\n"); + dumparg.desc = zonestats_desc; + dumparg.ncounters = dns_zonestatscounter_max; + dns_generalstats_dump(server->zonestats, generalstat_dump, &dumparg, 0); + + fprintf(fp, "++ Resolver Statistics ++\n"); + fprintf(fp, "[Common]\n"); + dumparg.desc = resstats_desc; + dumparg.ncounters = dns_resstatscounter_max; + dns_generalstats_dump(server->resolverstats, generalstat_dump, &dumparg, + 0); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->resstats == NULL) + continue; + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s]\n", view->name); + dns_generalstats_dump(view->resstats, generalstat_dump, + &dumparg, 0); + } + + fprintf(fp, "++ Cache DB RRsets ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + dns_stats_t *cachestats; + + cachestats = dns_db_getrrsetstats(view->cachedb); + if (cachestats == NULL) + continue; + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s]\n", view->name); + dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg, + 0); + } + + fprintf(fp, "++ Per Zone Query Statistics ++\n"); + zone = NULL; + for (result = dns_zone_first(server->zonemgr, &zone); + result == ISC_R_SUCCESS; + next = NULL, result = dns_zone_next(zone, &next), zone = next) + { + dns_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) { + char zonename[DNS_NAME_FORMATSIZE]; + + dns_name_format(dns_zone_getorigin(zone), + zonename, sizeof(zonename)); + view = dns_zone_getview(zone); + + fprintf(fp, "[%s", zonename); + if (strcmp(view->name, "_default") != 0) + fprintf(fp, " (view: %s)", view->name); + fprintf(fp, "]\n"); + + dumparg.desc = nsstats_desc; + dumparg.ncounters = dns_nsstatscounter_max; + dns_generalstats_dump(zonestats, generalstat_dump, + &dumparg, 0); + } + } + + fprintf(fp, "--- Statistics Dump --- (%lu)\n", (unsigned long)now); + + return (ISC_R_SUCCESS); /* this function currently always succeeds */ +} diff --git a/bin/named/update.c b/bin/named/update.c index 4d06542931..67b67b679d 100644 --- a/bin/named/update.c +++ b/bin/named/update.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: update.c,v 1.145 2008/04/02 02:37:41 marka Exp $ */ +/* $Id: update.c,v 1.146 2008/04/03 05:55:51 marka Exp $ */ #include @@ -43,12 +43,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include /*! \file @@ -119,6 +121,11 @@ msg, isc_result_totext(result)); \ if (result != ISC_R_SUCCESS) goto failure; \ } while (0) +#define PREREQFAILC(code, msg) \ + do { \ + inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ + FAILC(code, msg); \ + } while (0) #define FAILN(code, name, msg) \ do { \ @@ -140,6 +147,11 @@ } \ if (result != ISC_R_SUCCESS) goto failure; \ } while (0) +#define PREREQFAILN(code, name, msg) \ + do { \ + inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ + FAILN(code, name, msg); \ + } while (0) #define FAILNT(code, name, type, msg) \ do { \ @@ -164,6 +176,12 @@ } \ if (result != ISC_R_SUCCESS) goto failure; \ } while (0) +#define PREREQFAILNT(code, name, type, msg) \ + do { \ + inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ + FAILNT(code, name, type, msg); \ + } while (0) + /*% * Fail unconditionally and log as a server error. * The test against ISC_R_SUCCESS is there to keep the Solaris compiler @@ -247,6 +265,20 @@ update_log(ns_client_t *client, dns_zone_t *zone, namebuf, classbuf, message); } +/*% + * Increment updated-related statistics counters. + */ +static inline void +inc_stats(dns_zone_t *zone, dns_statscounter_t counter) { + dns_generalstats_increment(ns_g_server->nsstats, counter); + + if (zone != NULL) { + dns_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) + dns_generalstats_increment(zonestats, counter); + } +} + /*% * Override the default acl logging when checking whether a client * can update the zone or whether we can forward the request to the @@ -2393,6 +2425,10 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) { return; failure: + if (result == DNS_R_REFUSED) { + INSIST(dns_zone_gettype(zone) == dns_zone_slave); + inc_stats(zone, dns_nsstatscounter_updaterej); + } /* * We failed without having sent an update event to the zone. * We are still in the client task context, so we can @@ -2646,54 +2682,59 @@ update_action(isc_task_t *task, isc_event_t *event) { &name, &rdata, &covers, &ttl, &update_class); if (ttl != 0) - FAILC(DNS_R_FORMERR, "prerequisite TTL is not zero"); + PREREQFAILC(DNS_R_FORMERR, + "prerequisite TTL is not zero"); if (! dns_name_issubdomain(name, zonename)) - FAILN(DNS_R_NOTZONE, name, - "prerequisite name is out of zone"); + PREREQFAILN(DNS_R_NOTZONE, name, + "prerequisite name is out of zone"); if (update_class == dns_rdataclass_any) { if (rdata.length != 0) - FAILC(DNS_R_FORMERR, + PREREQFAILC(DNS_R_FORMERR, "class ANY prerequisite " "RDATA is not empty"); if (rdata.type == dns_rdatatype_any) { CHECK(name_exists(db, ver, name, &flag)); if (! flag) { - FAILN(DNS_R_NXDOMAIN, name, - "'name in use' prerequisite " - "not satisfied"); + PREREQFAILN(DNS_R_NXDOMAIN, name, + "'name in use' " + "prerequisite not " + "satisfied"); } } else { CHECK(rrset_exists(db, ver, name, rdata.type, covers, &flag)); if (! flag) { /* RRset does not exist. */ - FAILNT(DNS_R_NXRRSET, name, rdata.type, + PREREQFAILNT(DNS_R_NXRRSET, name, rdata.type, "'rrset exists (value independent)' " "prerequisite not satisfied"); } } } else if (update_class == dns_rdataclass_none) { if (rdata.length != 0) - FAILC(DNS_R_FORMERR, - "class NONE prerequisite " - "RDATA is not empty"); + PREREQFAILC(DNS_R_FORMERR, + "class NONE prerequisite " + "RDATA is not empty"); if (rdata.type == dns_rdatatype_any) { CHECK(name_exists(db, ver, name, &flag)); if (flag) { - FAILN(DNS_R_YXDOMAIN, name, - "'name not in use' prerequisite " - "not satisfied"); + PREREQFAILN(DNS_R_YXDOMAIN, name, + "'name not in use' " + "prerequisite not " + "satisfied"); } } else { CHECK(rrset_exists(db, ver, name, rdata.type, covers, &flag)); if (flag) { /* RRset exists. */ - FAILNT(DNS_R_YXRRSET, name, rdata.type, - "'rrset does not exist' " - "prerequisite not satisfied"); + PREREQFAILNT(DNS_R_YXRRSET, name, + rdata.type, + "'rrset does not exist' " + "prerequisite not " + "satisfied"); } } } else if (update_class == zoneclass) { @@ -2706,7 +2747,7 @@ update_action(isc_task_t *task, isc_event_t *event) { FAIL(ISC_R_UNEXPECTED); } } else { - FAILC(DNS_R_FORMERR, "malformed prerequisite"); + PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite"); } } if (result != ISC_R_NOMORE) @@ -3209,6 +3250,9 @@ update_action(isc_task_t *task, isc_event_t *event) { goto common; failure: + if (result == DNS_R_REFUSED) + inc_stats(zone, dns_nsstatscounter_updaterej); + /* * The reason for failure should have been logged at this point. */ @@ -3231,11 +3275,10 @@ update_action(isc_task_t *task, isc_event_t *event) { if (ssutable != NULL) dns_ssutable_detach(&ssutable); - if (zone != NULL) - dns_zone_detach(&zone); - isc_task_detach(&task); uev->result = result; + if (zone != NULL) + INSIST(uev->zone == zone); /* we use this later */ uev->ev_type = DNS_EVENT_UPDATEDONE; uev->ev_action = updatedone_action; isc_task_send(client->task, &event); @@ -3253,6 +3296,19 @@ updatedone_action(isc_task_t *task, isc_event_t *event) { INSIST(task == client->task); INSIST(client->nupdates > 0); + switch (uev->result) { + case ISC_R_SUCCESS: + inc_stats(uev->zone, dns_nsstatscounter_updatedone); + break; + case DNS_R_REFUSED: + inc_stats(uev->zone, dns_nsstatscounter_updaterej); + break; + default: + inc_stats(uev->zone, dns_nsstatscounter_updatefail); + break; + } + if (uev->zone != NULL) + dns_zone_detach(&uev->zone); client->nupdates--; respond(client, uev->result); isc_event_free(&event); @@ -3281,17 +3337,21 @@ static void forward_callback(void *arg, isc_result_t result, dns_message_t *answer) { update_event_t *uev = arg; ns_client_t *client = uev->ev_arg; + dns_zone_t *zone = uev->zone; if (result != ISC_R_SUCCESS) { INSIST(answer == NULL); uev->ev_type = DNS_EVENT_UPDATEDONE; uev->ev_action = forward_fail; + inc_stats(zone, dns_nsstatscounter_updatefwdfail); } else { uev->ev_type = DNS_EVENT_UPDATEDONE; uev->ev_action = forward_done; uev->answer = answer; + inc_stats(zone, dns_nsstatscounter_updaterespfwd); } isc_task_send(client->task, ISC_EVENT_PTR(&uev)); + dns_zone_detach(&zone); } static void @@ -3322,8 +3382,10 @@ forward_action(isc_task_t *task, isc_event_t *event) { uev->ev_type = DNS_EVENT_UPDATEDONE; uev->ev_action = forward_fail; isc_task_send(client->task, &event); - } - dns_zone_detach(&zone); + inc_stats(zone, dns_nsstatscounter_updatefwdfail); + dns_zone_detach(&zone); + } else + inc_stats(zone, dns_nsstatscounter_updatereqfwd); isc_task_detach(&task); } diff --git a/bin/named/xfrout.c b/bin/named/xfrout.c index 6cc8f7064a..cde32ff98e 100644 --- a/bin/named/xfrout.c +++ b/bin/named/xfrout.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrout.c,v 1.126 2007/06/18 23:47:19 tbox Exp $ */ +/* $Id: xfrout.c,v 1.127 2008/04/03 05:55:51 marka Exp $ */ #include @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -148,6 +149,16 @@ db_rr_iterator_current(db_rr_iterator_t *it, dns_name_t **name, static void db_rr_iterator_destroy(db_rr_iterator_t *it); +static inline void +inc_stats(dns_zone_t *zone, dns_statscounter_t counter) { + dns_generalstats_increment(ns_g_server->nsstats, counter); + if (zone != NULL) { + dns_stats_t *zonestats = dns_zone_getrequeststats(zone); + if (zonestats != NULL) + dns_generalstats_increment(zonestats, counter); + } +} + static isc_result_t db_rr_iterator_init(db_rr_iterator_t *it, dns_db_t *db, dns_dbversion_t *ver, isc_stdtime_t now) @@ -818,6 +829,7 @@ typedef struct { dns_name_t *qname; /* Question name of request */ dns_rdatatype_t qtype; /* dns_rdatatype_{a,i}xfr */ dns_rdataclass_t qclass; + dns_zone_t *zone; /* (necessary for stats) */ dns_db_t *db; dns_dbversion_t *ver; isc_quota_t *quota; @@ -841,7 +853,7 @@ typedef struct { static isc_result_t xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, - dns_rdataclass_t qclass, + dns_rdataclass_t qclass, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, rrstream_t *stream, dns_tsigkey_t *tsigkey, isc_buffer_t *lasttsig, @@ -1211,8 +1223,9 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { #ifdef DLZ if (is_dlz) CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, - reqtype, question_class, db, ver, quota, - stream, dns_message_gettsigkey(request), + reqtype, question_class, zone, db, ver, + quota, stream, + dns_message_gettsigkey(request), tsigbuf, 3600, 3600, @@ -1222,8 +1235,9 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { else #endif CHECK(xfrout_ctx_create(mctx, client, request->id, question_name, - reqtype, question_class, db, ver, quota, - stream, dns_message_gettsigkey(request), + reqtype, question_class, zone, db, ver, + quota, stream, + dns_message_gettsigkey(request), tsigbuf, dns_zone_getmaxxfrout(zone), dns_zone_getidleout(zone), @@ -1261,6 +1275,8 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { result = ISC_R_SUCCESS; failure: + if (result == DNS_R_REFUSED) + inc_stats(zone, dns_nsstatscounter_xfrrej); if (quota != NULL) isc_quota_detach("a); if (current_soa_tuple != NULL) @@ -1291,7 +1307,7 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) { static isc_result_t xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, dns_name_t *qname, dns_rdatatype_t qtype, - dns_rdataclass_t qclass, + dns_rdataclass_t qclass, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, isc_quota_t *quota, rrstream_t *stream, dns_tsigkey_t *tsigkey, isc_buffer_t *lasttsig, unsigned int maxtime, @@ -1314,8 +1330,10 @@ xfrout_ctx_create(isc_mem_t *mctx, ns_client_t *client, unsigned int id, xfr->qname = qname; xfr->qtype = qtype; xfr->qclass = qclass; + xfr->zone = NULL; xfr->db = NULL; xfr->ver = NULL; + dns_zone_attach(zone, &xfr->zone); dns_db_attach(db, &xfr->db); dns_db_attachversion(db, ver, &xfr->ver); xfr->end_of_stream = ISC_FALSE; @@ -1691,6 +1709,8 @@ xfrout_ctx_destroy(xfrout_ctx_t **xfrp) { isc_quota_detach(&xfr->quota); if (xfr->ver != NULL) dns_db_closeversion(xfr->db, &xfr->ver, ISC_FALSE); + if (xfr->zone != NULL) + dns_zone_detach(&xfr->zone); if (xfr->db != NULL) dns_db_detach(&xfr->db); @@ -1724,6 +1744,7 @@ xfrout_senddone(isc_task_t *task, isc_event_t *event) { sendstream(xfr); } else { /* End of zone transfer stream. */ + inc_stats(xfr->zone, dns_nsstatscounter_xfrdone); xfrout_log(xfr, ISC_LOG_INFO, "%s ended", xfr->mnemonic); ns_client_next(xfr->client, ISC_R_SUCCESS); xfrout_ctx_destroy(&xfr); diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index db16b50040..9cc6b5e25e 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zoneconf.c,v 1.143 2008/04/02 02:37:41 marka Exp $ */ +/* $Id: zoneconf.c,v 1.144 2008/04/03 05:55:51 marka Exp $ */ /*% */ @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -365,6 +366,8 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE; isc_boolean_t ixfrdiff; dns_masterformat_t masterformat; + dns_stats_t *zoneqrystats; + isc_boolean_t zonestats_on; int seconds; i = 0; @@ -493,7 +496,15 @@ ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, obj = NULL; result = ns_config_get(maps, "zone-statistics", &obj); INSIST(result == ISC_R_SUCCESS); - RETERR(dns_zone_setstatistics(zone, cfg_obj_asboolean(obj))); + zonestats_on = cfg_obj_asboolean(obj); + zoneqrystats = NULL; + if (zonestats_on) { + RETERR(dns_generalstats_create(mctx, &zoneqrystats, + dns_nsstatscounter_max)); + } + dns_zone_setrequeststats(zone, zoneqrystats); + if (zoneqrystats != NULL) + dns_stats_detach(&zoneqrystats); /* * Configure master functionality. This applies diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 2be4d4bc8a..205ce990ff 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.c,v 1.236 2008/03/20 19:23:42 jinmei Exp $ */ +/* $Id: adb.c,v 1.237 2008/04/03 05:55:51 marka Exp $ */ /*! \file * @@ -55,6 +55,7 @@ #include #include #include +#include #define DNS_ADB_MAGIC ISC_MAGIC('D', 'a', 'd', 'b') #define DNS_ADB_VALID(x) ISC_MAGIC_VALID(x, DNS_ADB_MAGIC) @@ -498,6 +499,15 @@ DP(int level, const char *format, ...) { va_end(args); } +/*% + * Increment resolver-related statistics counters. + */ +static inline void +inc_stats(dns_adb_t *adb, dns_statscounter_t counter) { + if (adb->view->resstats != NULL) + dns_generalstats_increment(adb->view->resstats, counter); +} + static inline dns_ttl_t ttlclamp(dns_ttl_t ttl) { if (ttl < ADB_CACHE_MINIMUM) @@ -3394,6 +3404,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { name->fetch_err = FIND_ERR_NXDOMAIN; else name->fetch_err = FIND_ERR_NXRRSET; + inc_stats(adb, dns_resstatscounter_gluefetchv4fail); } else { DP(NCACHE_LEVEL, "adb fetch name %p: " "caching negative entry for AAAA (ttl %u)", @@ -3404,6 +3415,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { name->fetch6_err = FIND_ERR_NXDOMAIN; else name->fetch6_err = FIND_ERR_NXRRSET; + inc_stats(adb, dns_resstatscounter_gluefetchv6fail); } goto out; } @@ -3443,9 +3455,11 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { if (address_type == DNS_ADBFIND_INET) { name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); name->fetch_err = FIND_ERR_FAILURE; + inc_stats(adb, dns_resstatscounter_gluefetchv4fail); } else { name->expire_v6 = ISC_MIN(name->expire_v6, now + 300); name->fetch6_err = FIND_ERR_FAILURE; + inc_stats(adb, dns_resstatscounter_gluefetchv6fail); } goto out; } @@ -3530,10 +3544,13 @@ fetch_name(dns_adbname_t *adbname, if (result != ISC_R_SUCCESS) goto cleanup; - if (type == dns_rdatatype_a) + if (type == dns_rdatatype_a) { adbname->fetch_a = fetch; - else + inc_stats(adb, dns_resstatscounter_gluefetchv4); + } else { adbname->fetch_aaaa = fetch; + inc_stats(adb, dns_resstatscounter_gluefetchv6); + } fetch = NULL; /* Keep us from cleaning this up below. */ cleanup: diff --git a/lib/dns/db.c b/lib/dns/db.c index 7d4d038d11..5539962dc1 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.c,v 1.86 2008/04/01 23:47:10 tbox Exp $ */ +/* $Id: db.c,v 1.87 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -859,6 +859,16 @@ dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { return (ISC_R_NOTFOUND); } +dns_stats_t * +dns_db_getrrsetstats(dns_db_t *db) { + REQUIRE(DNS_DB_VALID(db)); + + if (db->methods->getrrsetstats != NULL) + return ((db->methods->getrrsetstats)(db)); + + return (NULL); +} + isc_result_t dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 4d310b673f..d75c45a39d 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.c,v 1.138 2008/04/03 02:01:08 marka Exp $ */ +/* $Id: dispatch.c,v 1.139 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,7 @@ struct dns_dispatchmgr { isc_mem_t *mctx; dns_acl_t *blackhole; dns_portlist_t *portlist; + dns_stats_t *stats; /* Locked by "lock". */ isc_mutex_t lock; @@ -652,6 +654,8 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) { bucket, (resp == NULL ? "not found" : "found")); if (resp == NULL) { + dns_generalstats_increment(mgr->stats, + dns_resstatscounter_mismatch); free_buffer(disp, ev->region.base, ev->region.length); goto unlock; } @@ -1056,6 +1060,9 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) { if (mgr->portlist != NULL) dns_portlist_detach(&mgr->portlist); + if (mgr->stats != NULL) + dns_stats_detach(&mgr->stats); + isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t)); isc_mem_detach(&mctx); } @@ -1110,6 +1117,7 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, mgr->blackhole = NULL; mgr->portlist = NULL; + mgr->stats = NULL; result = isc_mutex_init(&mgr->lock); if (result != ISC_R_SUCCESS) @@ -1305,6 +1313,15 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { destroy_mgr(&mgr); } +void +dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, dns_stats_t *stats) { + REQUIRE(VALID_DISPATCHMGR(mgr)); + REQUIRE(ISC_LIST_EMPTY(mgr->list)); + REQUIRE(mgr->stats == NULL); + + dns_stats_attach(stats, &mgr->stats); +} + static isc_boolean_t blacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock, isc_sockaddr_t *sockaddrp) diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 0e8fc997cd..4a3ecdb960 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.h,v 1.83 2007/06/19 23:47:16 tbox Exp $ */ +/* $Id: adb.h,v 1.84 2008/04/03 05:55:52 marka Exp $ */ #ifndef DNS_ADB_H #define DNS_ADB_H 1 @@ -629,7 +629,6 @@ dns_adb_flushname(dns_adb_t *adb, dns_name_t *name); *\li 'name' is valid. */ - ISC_LANG_ENDDECLS #endif /* DNS_ADB_H */ diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 6c5163ae1f..05115325a2 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.h,v 1.91 2008/04/01 23:47:10 tbox Exp $ */ +/* $Id: db.h,v 1.92 2008/04/03 05:55:52 marka Exp $ */ #ifndef DNS_DB_H #define DNS_DB_H 1 @@ -157,6 +157,7 @@ typedef struct dns_dbmethods { void (*resigned)(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version); isc_boolean_t (*isdnssec)(dns_db_t *db); + dns_stats_t *(*getrrsetstats)(dns_db_t *db); } dns_dbmethods_t; typedef isc_result_t @@ -1388,6 +1389,21 @@ dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, */ +dns_stats_t * +dns_db_getrrsetstats(dns_db_t *db); +/*%< + * Get statistics information counting RRsets stored in the DB, when available. + * The statistics may not be available depending on the DB implementation. + * + * Requires: + * + * \li 'db' is a valid database (zone or cache). + * + * Returns: + * \li when available, a pointer to a statistics object created by + * dns_rdatasetstats_create(); otherwise NULL. + */ + ISC_LANG_ENDDECLS #endif /* DNS_DB_H */ diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 71922d7780..1891f0ab4a 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dispatch.h,v 1.56 2007/06/26 02:52:15 marka Exp $ */ +/* $Id: dispatch.h,v 1.57 2008/04/03 05:55:52 marka Exp $ */ #ifndef DNS_DISPATCH_H #define DNS_DISPATCH_H 1 @@ -206,7 +206,20 @@ dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr); *\li mgr is a valid dispatchmgr */ - +void +dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, dns_stats_t *stats); +/*%< + * Sets statistics counter for the dispatchmgr. This function is expected to + * be called only on zone creation (when necessary). + * Once installed, it cannot be removed or replaced. Also, there is no + * interface to get the installed stats from the zone; the caller must keep the + * stats to reference (e.g. dump) it later. + * + * Requires: + *\li mgr is a valid dispatchmgr with no managed dispatch. + *\li stats is a valid statistics supporting resolver statistics counters + * (see dns/stats.h). + */ isc_result_t dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h index 9134e1fbbe..5831e9d064 100644 --- a/lib/dns/include/dns/stats.h +++ b/lib/dns/include/dns/stats.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.h,v 1.15 2008/01/24 23:47:00 tbox Exp $ */ +/* $Id: stats.h,v 1.16 2008/04/03 05:55:52 marka Exp $ */ #ifndef DNS_STATS_H #define DNS_STATS_H 1 @@ -25,9 +25,58 @@ #include /*% - * Query statistics counter types. + * Statistics counters. Used as dns_statscounter_t values. */ -typedef enum { +enum { + /*% + * Resolver statistics counters. + */ + dns_resstatscounter_queryv4 = 0, + dns_resstatscounter_queryv6 = 1, + dns_resstatscounter_responsev4 = 2, + dns_resstatscounter_responsev6 = 3, + dns_resstatscounter_nxdomain = 4, + dns_resstatscounter_servfail = 5, + dns_resstatscounter_formerr = 6, + dns_resstatscounter_othererror = 7, + dns_resstatscounter_edns0fail = 8, + dns_resstatscounter_mismatch = 9, + dns_resstatscounter_truncated = 10, + dns_resstatscounter_lame = 11, + dns_resstatscounter_retry = 12, + dns_resstatscounter_gluefetchv4 = 13, + dns_resstatscounter_gluefetchv6 = 14, + dns_resstatscounter_gluefetchv4fail = 15, + dns_resstatscounter_gluefetchv6fail = 16, + dns_resstatscounter_val = 17, + dns_resstatscounter_valsuccess = 18, + dns_resstatscounter_valnegsuccess = 19, + dns_resstatscounter_valfail = 20, + + dns_resstatscounter_max = 21, + + /*% + * Zone statistics counters. + */ + dns_zonestatscounter_notifyoutv4 = 0, + dns_zonestatscounter_notifyoutv6 = 1, + dns_zonestatscounter_notifyinv4 = 2, + dns_zonestatscounter_notifyinv6 = 3, + dns_zonestatscounter_notifyrej = 4, + dns_zonestatscounter_soaoutv4 = 5, + dns_zonestatscounter_soaoutv6 = 6, + dns_zonestatscounter_axfrreqv4 = 7, + dns_zonestatscounter_axfrreqv6 = 8, + dns_zonestatscounter_ixfrreqv4 = 9, + dns_zonestatscounter_ixfrreqv6 = 10, + dns_zonestatscounter_xfrsuccess = 11, + dns_zonestatscounter_xfrfail = 12, + + dns_zonestatscounter_max = 13, + + /*% + * Query statistics counters (obsolete). + */ dns_statscounter_success = 0, /*%< Successful lookup */ dns_statscounter_referral = 1, /*%< Referral result */ dns_statscounter_nxrrset = 2, /*%< NXRRSET result */ @@ -35,39 +84,242 @@ typedef enum { dns_statscounter_recursion = 4, /*%< Recursion was used */ dns_statscounter_failure = 5, /*%< Some other failure */ dns_statscounter_duplicate = 6, /*%< Duplicate query */ - dns_statscounter_dropped = 7 /*%< Duplicate query */ -} dns_statscounter_t; + dns_statscounter_dropped = 7 /*%< Duplicate query (dropped) */ +}; #define DNS_STATS_NCOUNTERS 8 +/*%< + * Flag(s) for dns_xxxstats_dump(). + */ +#define DNS_STATSDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */ + +/*%< + * (Obsoleted) + */ LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[]; -isc_result_t -dns_stats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*% + * Attributes for statistics counters of RRset and Rdatatype types. + * + * _OTHERTYPE + * The rdata type is not explicitly supported and the corresponding counter + * is counted for other such types, too. When this attribute is set, + * the base type is of no use. + * + * _NXRRSET + * RRset type counters only. Indicates the RRset is non existent. + * + * _NXDOMAIN + * RRset type counters only. Indicates a non existent name. When this + * attribute is set, the base type is of no use. + */ +#define DNS_RDATASTATSTYPE_ATTR_OTHERTYPE 0x0001 +#define DNS_RDATASTATSTYPE_ATTR_NXRRSET 0x0002 +#define DNS_RDATASTATSTYPE_ATTR_NXDOMAIN 0x0004 + /*%< - * Create a statistics counter structure. + * Conversion macros among dns_rdatatype_t, attributes and dns_statscounter_t. + */ +#define DNS_RDATASTATSTYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF)) +#define DNS_RDATASTATSTYPE_ATTR(type) ((type) >> 16) +#define DNS_RDATASTATSTYPE_VALUE(b, a) (((a) << 16) | (b)) + +/*%< + * Types of dump callbacks. + */ +typedef void (*dns_generalstats_dumper_t)(dns_statscounter_t, isc_uint64_t, + void *); +typedef void (*dns_rdatatypestats_dumper_t)(dns_rdatastatstype_t, isc_uint64_t, + void *); +typedef void (*dns_opcodestats_dumper_t)(dns_opcode_t, isc_uint64_t, void *); + +isc_result_t +dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters); +/*%< + * Create a statistics counter structure of general type. It counts a general + * set of counters indexed by an ID between 0 and ncounters -1. * * Requires: - * *\li 'mctx' must be a valid memory context. * *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per rdatatype. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per RRset. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per opcode. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure */ void -dns_stats_destroy(isc_mem_t *mctx, dns_stats_t **statsp); +dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp); /*%< - * Destroy a statistics counter structure. + * Attach to a statistics set. * * Requires: + *\li 'stats' is a valid dns_stats_t. * - *\li 'mctx' must be a valid memory context. + *\li 'statsp' != NULL && '*statsp' == NULL + */ + +void +dns_stats_detach(dns_stats_t **statsp); +/*%< + * Detaches from the statistics set. * - *\li 'statsp' != NULL and '*statsp' be valid dns_stats_t. + * Requires: + *\li 'statsp' != NULL and '*statsp' is a valid dns_stats_t. + */ + +void +dns_generalstats_increment(dns_stats_t *stats, dns_statscounter_t counter); +/*%< + * Increment the counter-th counter of stats. * - * Ensures: + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). * - *\li '*statsp' == NULL + *\li counter is less than the maximum available ID for the stats specified + * on creation. + */ + +void +dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type); +/*%< + * Increment the statistics counter for 'type'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatatypestats_create(). + */ + +void +dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype); +/*%< + * Increment the statistics counter for 'rrsettype'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatasetstats_create(). + */ + +void +dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype); +/*%< + * Decrement the statistics counter for 'rrsettype'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatasetstats_create(). + */ + +void +dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code); +/*%< + * Increment the statistics counter for 'code'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_opcodestats_create(). + */ + +void +dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with its current value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the DNS_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding type in the form of + * dns_rdatastatstype_t, the current counter value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the DNS_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding type in the form of + * dns_rdatastatstype_t, the current counter value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the DNS_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding opcode, the current + * counter value and the given argument arg. By default counters that have a + * value of 0 is skipped; if options has the DNS_STATSDUMP_VERBOSE flag, even + * such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). */ void @@ -82,26 +334,13 @@ dns_stats_incrementcounter(dns_stats_t *stat, dns_statscounter_t counter); *\li counter < DNS_STATS_NCOUNTERS */ -void -dns_stats_copy(dns_stats_t *src, isc_uint64_t *dst); -/*%< - * Copy statistics counter fields of 'src' to the 'dst' array. - * - * Requires: - * - *\li 'src' be a valid dns_stats_t. - * - *\li 'dst' be sufficiently large to store DNS_STATS_NCOUNTERS 64-bit - * integers. - */ - isc_result_t dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp); /*%< * Allocate an array of query statistics counters from the memory * context 'mctx'. * - * This function is obsoleted. Use dns_stats_create() instead. + * This function is obsoleted. Use dns_xxxstats_create() instead. */ void diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 6ead6a9c36..705cfb091b 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.128 2008/01/24 23:47:00 tbox Exp $ */ +/* $Id: types.h,v 1.129 2008/04/03 05:55:52 marka Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -107,6 +107,8 @@ typedef struct dns_signature dns_signature_t; typedef struct dns_ssurule dns_ssurule_t; typedef struct dns_ssutable dns_ssutable_t; typedef struct dns_stats dns_stats_t; +typedef int dns_statscounter_t; +typedef isc_uint32_t dns_rdatastatstype_t; typedef struct dns_tkeyctx dns_tkeyctx_t; typedef isc_uint16_t dns_trust_t; typedef struct dns_tsig_keyring dns_tsig_keyring_t; diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 7b95cc9aef..8b08da8611 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.h,v 1.108 2008/04/03 02:01:08 marka Exp $ */ +/* $Id: view.h,v 1.109 2008/04/03 05:55:52 marka Exp $ */ #ifndef DNS_VIEW_H #define DNS_VIEW_H 1 @@ -70,7 +70,6 @@ #include #include #include -#include #include #include @@ -101,6 +100,8 @@ struct dns_view { isc_event_t resevent; isc_event_t adbevent; isc_event_t reqevent; + dns_stats_t * resstats; + dns_stats_t * resquerystats; /* Configurable data. */ dns_tsig_keyring_t * statickeys; @@ -820,11 +821,55 @@ dns_view_freezezones(dns_view_t *view, isc_boolean_t freeze); * \li 'view' is valid. */ -#ifdef HAVE_LIBXML2 +void +dns_view_setresstats(dns_view_t *view, dns_stats_t *stats); +/*%< + * Set a general resolver statistics counter set 'stats' for 'view'. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics supporting resolver statistics counters + * (see dns/stats.h). + */ -isc_result_t -dns_view_xmlrender(dns_view_t *view, xmlTextWriterPtr xml, int flags); +void +dns_view_getresstats(dns_view_t *view, dns_stats_t **statsp); +/*%< + * Get the general statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ -#endif +void +dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats); +/*%< + * Set a statistics counter set of rdata type, 'stats', for 'view'. Once the + * statistic set is installed, view's resolver will count outgoing queries + * per rdata type. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics created by dns_rdatatypestats_create(). + */ + +void +dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp); +/*%< + * Get the rdatatype statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ #endif /* DNS_VIEW_H */ diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index d5b80e364e..2158cc6a43 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.158 2008/04/02 02:37:42 marka Exp $ */ +/* $Id: zone.h,v 1.159 2008/04/03 05:55:52 marka Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -148,6 +147,15 @@ dns_zone_getclass(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +isc_uint32_t +dns_zone_getserial(dns_zone_t *zone); +/*%< + * Returns the current serial number of the zone. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + void dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type); /*%< @@ -1502,28 +1510,55 @@ dns_zone_isforced(dns_zone_t *zone); isc_result_t dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on); /*%< - * Make the zone keep or not keep an array of statistics - * counter. - * - * Requires: - * \li zone be a valid zone. + * This function is obsoleted by dns_zone_setrequeststats(). */ isc_uint64_t * dns_zone_getstatscounters(dns_zone_t *zone); /*%< - * This function is obsoleted by dns_zone_getstats(). + * This function is obsoleted by dns_zone_getrequeststats(). + */ + +void +dns_zone_setstats(dns_zone_t *zone, dns_stats_t *stats); +/*%< + * Set a general zone-maintenance statistics set 'stats' for 'zone'. This + * function is expected to be called only on zone creation (when necessary). + * Once installed, it cannot be removed or replaced. Also, there is no + * interface to get the installed stats from the zone; the caller must keep the + * stats to reference (e.g. dump) it later. + * + * Requires: + * \li 'zone' to be a valid zone and does not have a statistics set already + * installed. + * + *\li stats is a valid statistics supporting zone statistics counters + * (see dns/stats.h). + */ + +void +dns_zone_setrequeststats(dns_zone_t *zone, dns_stats_t *stats); +/*%< + * Set an additional statistics set to zone. It is attached in the zone + * but is not counted in the zone module; only the caller updates the counters. + * + * Requires: + * \li 'zone' to be a valid zone. + * + *\li stats is a valid statistics. */ dns_stats_t * -dns_zone_getstats(dns_zone_t *zone); +dns_zone_getrequeststats(dns_zone_t *zone); /*%< + * Get the additional statistics for zone, if one is installed. + * * Requires: - * zone be a valid zone. + * \li 'zone' to be a valid zone. * * Returns: - * \li A pointer to the zone's array of statistics counters, - * or NULL if it has none. + * \li when available, a pointer to the statistics set installed in zone; + * otherwise NULL. */ void @@ -1688,13 +1723,6 @@ dns_zone_getprivatetype(dns_zone_t *zone); * will not be permanent. */ -#ifdef HAVE_LIBXML2 - -isc_result_t -dns_zone_xmlrender(dns_zone_t *zone, xmlTextWriterPtr xml, int flags); - -#endif - ISC_LANG_ENDDECLS #endif /* DNS_ZONE_H */ diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 35d2241abe..e4e2552c77 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.c,v 1.256 2008/04/03 04:00:38 marka Exp $ */ +/* $Id: rbtdb.c,v 1.257 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -277,6 +278,7 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t; #define RDATASET_ATTR_RETAIN 0x0008 #define RDATASET_ATTR_NXDOMAIN 0x0010 #define RDATASET_ATTR_RESIGN 0x0020 +#define RDATASET_ATTR_STATCOUNT 0x0040 #define RDATASET_ATTR_CACHE 0x1000 /* for debug */ #define RDATASET_ATTR_CANCELED 0x2000 /* for debug */ @@ -399,6 +401,7 @@ typedef struct { unsigned int node_lock_count; rbtdb_nodelock_t * node_locks; dns_rbtnode_t * origin_node; + dns_stats_t * rrsetstats; /* cache DB only */ /* Locked by lock. */ unsigned int active; isc_refcount_t references; @@ -661,6 +664,32 @@ free_rbtdb_callback(isc_task_t *task, isc_event_t *event) { free_rbtdb(rbtdb, ISC_TRUE, event); } +static void +update_rrsetstats(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_boolean_t increment) +{ + dns_rdatastatstype_t statattributes = 0; + dns_rdatastatstype_t base = 0; + dns_rdatastatstype_t type; + + /* At the moment we count statistics only for cache DB */ + INSIST(IS_CACHE(rbtdb)); + + if (NXDOMAIN(header)) + statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN; + else if (RBTDB_RDATATYPE_BASE(header->type) == 0) { + statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET; + base = RBTDB_RDATATYPE_EXT(header->type); + } else + base = RBTDB_RDATATYPE_BASE(header->type); + + type = DNS_RDATASTATSTYPE_VALUE(base, statattributes); + if (increment) + dns_rdatasetstats_increment(rbtdb->rrsetstats, type); + else + dns_rdatasetstats_decrement(rbtdb->rrsetstats, type); +} + static void set_ttl(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, dns_ttl_t newttl) { int idx; @@ -887,6 +916,9 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { sizeof(isc_heap_t *)); } + if (rbtdb->rrsetstats != NULL) + dns_stats_detach(&rbtdb->rrsetstats); + isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks, rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t)); isc_rwlock_destroy(&rbtdb->tree_lock); @@ -1198,6 +1230,11 @@ free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset) unsigned int size; int idx; + if (EXISTS(rdataset) && + (rdataset->attributes & RDATASET_ATTR_STATCOUNT) != 0) { + update_rrsetstats(rbtdb, rdataset, ISC_FALSE); + } + #ifdef LRU_DEBUG /* * for debug: statistics update. @@ -5583,6 +5620,11 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); + if (rbtdb->rrsetstats != NULL) { + newheader->attributes |= RDATASET_ATTR_STATCOUNT; + update_rrsetstats(rbtdb, newheader, ISC_TRUE); + } + #ifdef LRU_DEBUG /* for debug: statistics update */ if (IS_CACHE(rbtdb) && rdataset->rdclass == dns_rdataclass_in) { @@ -6282,6 +6324,16 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read); } +static dns_stats_t * +getrrsetstats(dns_db_t *db) { + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + + REQUIRE(VALID_RBTDB(rbtdb)); + REQUIRE(IS_CACHE(rbtdb)); /* current restriction */ + + return (rbtdb->rrsetstats); +} + static dns_dbmethods_t zone_methods = { attach, detach, @@ -6316,6 +6368,7 @@ static dns_dbmethods_t zone_methods = { getsigningtime, resigned, isdnssec, + NULL }; static dns_dbmethods_t cache_methods = { @@ -6351,7 +6404,8 @@ static dns_dbmethods_t cache_methods = { NULL, NULL, NULL, - isdnssec + isdnssec, + getrrsetstats }; isc_result_t @@ -6415,12 +6469,16 @@ dns_rbtdb_create goto cleanup_tree_lock; } + rbtdb->rrsetstats = NULL; if (IS_CACHE(rbtdb)) { + result = dns_rdatasetstats_create(mctx, &rbtdb->rrsetstats); + if (result != ISC_R_SUCCESS) + goto cleanup_node_locks; rbtdb->rdatasets = isc_mem_get(mctx, rbtdb->node_lock_count * sizeof(rdatasetheaderlist_t)); if (rbtdb->rdatasets == NULL) { result = ISC_R_NOMEMORY; - goto cleanup_node_locks; + goto cleanup_rrsetstats; } for (i = 0; i < (int)rbtdb->node_lock_count; i++) ISC_LIST_INIT(rbtdb->rdatasets[i]); @@ -6603,6 +6661,9 @@ dns_rbtdb_create if (rbtdb->rdatasets != NULL) isc_mem_put(mctx, rbtdb->rdatasets, rbtdb->node_lock_count * sizeof(rdatasetheaderlist_t)); + cleanup_rrsetstats: + if (rbtdb->rrsetstats != NULL) + dns_stats_detach(&rbtdb->rrsetstats); cleanup_node_locks: isc_mem_put(mctx, rbtdb->node_locks, diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 9b827c8482..5d6bc1a073 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.364 2008/04/03 02:01:08 marka Exp $ */ +/* $Id: resolver.c,v 1.365 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -419,6 +420,15 @@ static void maybe_destroy(fetchctx_t *fctx); static void timer_dump(isc_task_t *task, isc_event_t *ev); #endif +/*% + * Increment resolver-related statistics counters. + */ +static inline void +inc_stats(dns_resolver_t *res, dns_statscounter_t counter) { + if (res->view->resstats != NULL) + dns_generalstats_increment(res->view->resstats, counter); +} + static isc_result_t valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset, @@ -445,6 +455,7 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, valoptions, task, validated, valarg, &validator); if (result == ISC_R_SUCCESS) { + inc_stats(fctx->res, dns_resstatscounter_val); if ((valoptions & DNS_VALIDATOR_DEFER) == 0) { INSIST(fctx->validator == NULL); fctx->validator = validator; @@ -1304,6 +1315,13 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, ISC_LIST_APPEND(fctx->queries, query, link); query->fctx->nqueries++; + if (isc_sockaddr_pf(&addrinfo->sockaddr) == PF_INET) + inc_stats(res, dns_resstatscounter_queryv4); + else + inc_stats(res, dns_resstatscounter_queryv6); + if (res->view->resquerystats != NULL) + dns_rdatatypestats_increment(res->view->resquerystats, + fctx->type); return (ISC_R_SUCCESS); @@ -2667,6 +2685,9 @@ fctx_try(fetchctx_t *fctx) { REQUIRE(!ADDRWAIT(fctx)); + if (fctx->restarts > 0) + inc_stats(fctx->res, dns_resstatscounter_retry); + addrinfo = fctx_nextaddress(fctx); if (addrinfo == NULL) { /* @@ -3597,6 +3618,7 @@ validated(isc_task_t *task, isc_event_t *event) { if (vevent->result != ISC_R_SUCCESS) { FCTXTRACE("validation failed"); + inc_stats(fctx->res, dns_resstatscounter_valfail); result = ISC_R_NOTFOUND; if (vevent->rdataset != NULL) result = dns_db_findnode(fctx->cache, vevent->name, @@ -3631,6 +3653,8 @@ validated(isc_task_t *task, isc_event_t *event) { dns_rdatatype_t covers; FCTXTRACE("nonexistence validation OK"); + inc_stats(fctx->res, dns_resstatscounter_valnegsuccess); + if (fctx->rmessage->rcode == dns_rcode_nxdomain) covers = dns_rdatatype_any; else @@ -3658,7 +3682,8 @@ validated(isc_task_t *task, isc_event_t *event) { if (result != ISC_R_SUCCESS) goto noanswer_response; goto answer_response; - } + } else + inc_stats(fctx->res, dns_resstatscounter_valsuccess); FCTXTRACE("validation OK"); @@ -5616,6 +5641,11 @@ resquery_response(isc_task_t *task, isc_event_t *event) { QTRACE("response"); + if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) + inc_stats(fctx->res, dns_resstatscounter_responsev4); + else + inc_stats(fctx->res, dns_resstatscounter_responsev6); + (void)isc_timer_touch(fctx->timer); keep_trying = ISC_FALSE; @@ -5717,6 +5747,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); + inc_stats(fctx->res, + dns_resstatscounter_edns0fail); } else { broken_server = result; keep_trying = ISC_TRUE; @@ -5745,6 +5777,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); + inc_stats(fctx->res, + dns_resstatscounter_edns0fail); } else { broken_server = DNS_R_UNEXPECTEDRCODE; keep_trying = ISC_TRUE; @@ -5800,6 +5834,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { truncated = ISC_TRUE; if (truncated) { + inc_stats(fctx->res, dns_resstatscounter_truncated); if ((options & DNS_FETCHOPT_TCP) != 0) { broken_server = DNS_R_TRUNCATEDTCP; keep_trying = ISC_TRUE; @@ -5820,6 +5855,26 @@ resquery_response(isc_task_t *task, isc_event_t *event) { goto done; } + /* + * Update statistics about erroneous responses. + */ + if (message->rcode != dns_rcode_noerror) { + switch (message->rcode) { + case dns_rcode_nxdomain: + inc_stats(fctx->res, dns_resstatscounter_nxdomain); + break; + case dns_rcode_servfail: + inc_stats(fctx->res, dns_resstatscounter_servfail); + break; + case dns_rcode_formerr: + inc_stats(fctx->res, dns_resstatscounter_formerr); + break; + default: + inc_stats(fctx->res, dns_resstatscounter_othererror); + break; + } + } + /* * Is the remote server broken, or does it dislike us? */ @@ -5845,6 +5900,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); + inc_stats(fctx->res, dns_resstatscounter_edns0fail); } else if (message->rcode == dns_rcode_formerr) { if (ISFORWARDER(query->addrinfo)) { /* @@ -5918,6 +5974,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { */ if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) && is_lame(fctx)) { + inc_stats(fctx->res, dns_resstatscounter_lame); log_lame(fctx, query->addrinfo); result = dns_adb_marklame(fctx->adb, query->addrinfo, &fctx->name, fctx->type, diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index c3284803d6..a0db995704 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdb.c,v 1.63 2008/04/01 01:37:25 marka Exp $ */ +/* $Id: sdb.c,v 1.64 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -1251,6 +1251,7 @@ static dns_dbmethods_t sdb_methods = { NULL, NULL, NULL, + NULL, NULL }; diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index 9992cf2426..8fbb5971bc 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -50,7 +50,7 @@ * USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: sdlz.c,v 1.16 2008/04/01 23:47:10 tbox Exp $ */ +/* $Id: sdlz.c,v 1.17 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -1055,6 +1055,7 @@ static dns_dbmethods_t sdlzdb_methods = { NULL, NULL, NULL, + NULL, NULL }; diff --git a/lib/dns/stats.c b/lib/dns/stats.c index db4e436252..deb9b089fd 100644 --- a/lib/dns/stats.c +++ b/lib/dns/stats.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: stats.c,v 1.14 2008/01/24 23:47:00 tbox Exp $ */ +/* $Id: stats.c,v 1.15 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -24,24 +24,48 @@ #include #include +#include +#include #include #include +#include #include #include +#include +#include #include -LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] = - { - "success", - "referral", - "nxrrset", - "nxdomain", - "recursion", - "failure", - "duplicate", - "dropped" - }; +#define DNS_STATS_MAGIC ISC_MAGIC('D', 's', 't', 't') +#define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC) + +/*% + * Statistics types. + */ +typedef enum { + dns_statstype_general = 0, + dns_statstype_rdtype = 1, + dns_statstype_rdataset = 2, + dns_statstype_opcode = 3 +} dns_statstype_t; + +/*% + * It doesn't make sense to have 2^16 counters for all possible types since + * most of them won't be used. We have counters for the first 256 types and + * those explicitly supported in the rdata implementation. + * XXXJT: this introduces tight coupling with the rdata implementation. + * Ideally, we should have rdata handle this type of details. + */ +enum { + /* For 0-255, we use the rdtype value as counter indices */ + rdtypecounter_dlv = 256, /* for dns_rdatatype_dlv */ + rdtypecounter_others = 257, /* anything else */ + rdtypecounter_max = 258, + /* The following are used for rdataset */ + rdtypenxcounter_max = rdtypecounter_max * 2, + rdtypecounter_nxdomain = rdtypenxcounter_max, + rdatasettypecounter_max = rdtypecounter_nxdomain + 1 +}; #ifndef DNS_STATS_USEMULTIFIELDS #if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEXADD) && !defined(ISC_PLATFORM_HAVEXADDQ) @@ -61,15 +85,42 @@ typedef isc_uint64_t dns_stat_t; #endif struct dns_stats { - /* XXXJT: do we need a magic? */ + /*% Unlocked */ + unsigned int magic; + dns_statstype_t type; + isc_mem_t *mctx; + int ncounters; + + isc_mutex_t lock; + unsigned int references; /* locked by lock */ + + /*% + * Locked by counterlock or unlocked if efficient rwlock is not + * available. + */ #ifdef ISC_RWLOCK_USEATOMIC - isc_rwlock_t lock; + isc_rwlock_t counterlock; #endif - dns_stat_t counters[DNS_STATS_NCOUNTERS]; + dns_stat_t *counters; + + /*% + * We don't want to lock the counters while we are dumping, so we first + * copy the current counter values into a local array. This buffer + * will be used as the copy destination. It's allocated on creation + * of the stats structure so that the dump operation won't fail due + * to memory allocation failure. + * XXX: this approach is weird for non-threaded build because the + * additional memory and the copy overhead could be avoided. We prefer + * simplicity here, however, under the assumption that this function + * should be only rarely called. + */ + isc_uint64_t *copiedcounters; }; -isc_result_t -dns_stats_create(isc_mem_t *mctx, dns_stats_t **statsp) { +static isc_result_t +create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters, + dns_stats_t **statsp) +{ dns_stats_t *stats; isc_result_t result = ISC_R_SUCCESS; @@ -78,43 +129,100 @@ dns_stats_create(isc_mem_t *mctx, dns_stats_t **statsp) { stats = isc_mem_get(mctx, sizeof(*stats)); if (stats == NULL) return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&stats->lock); + if (result != ISC_R_SUCCESS) + goto clean_stats; + + stats->counters = isc_mem_get(mctx, sizeof(dns_stat_t) * ncounters); + if (stats->counters == NULL) { + result = ISC_R_NOMEMORY; + goto clean_mutex; + } + stats->copiedcounters = isc_mem_get(mctx, + sizeof(isc_uint64_t) * ncounters); + if (stats->copiedcounters == NULL) { + result = ISC_R_NOMEMORY; + goto clean_counters; + } #ifdef ISC_RWLOCK_USEATOMIC - result = isc_rwlock_init(&stats->lock, 0, 0); - if (result != ISC_R_SUCCESS) { - isc_mem_put(mctx, stats, sizeof(*stats)); - return (result); - } + result = isc_rwlock_init(&stats->counterlock, 0, 0); + if (result != ISC_R_SUCCESS) + goto clean_copiedcounters; #endif - memset(stats->counters, 0, sizeof(dns_stat_t) * DNS_STATS_NCOUNTERS); + stats->type = type; + stats->references = 1; + memset(stats->counters, 0, sizeof(dns_stat_t) * ncounters); + stats->mctx = NULL; + isc_mem_attach(mctx, &stats->mctx); + stats->ncounters = ncounters; + stats->magic = DNS_STATS_MAGIC; *statsp = stats; + return (result); + +clean_counters: + isc_mem_put(mctx, stats->counters, sizeof(dns_stat_t) * ncounters); + +#ifdef ISC_RWLOCK_USEATOMIC +clean_copiedcounters: + isc_mem_put(mctx, stats->copiedcounters, + sizeof(dns_stat_t) * ncounters); +#endif + +clean_mutex: + DESTROYLOCK(&stats->lock); + +clean_stats: + isc_mem_put(mctx, stats, sizeof(*stats)); + return (result); } void -dns_stats_destroy(isc_mem_t *mctx, dns_stats_t **statsp) { - dns_stats_t *stats; +dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) { + REQUIRE(DNS_STATS_VALID(stats)); + REQUIRE(statsp != NULL && *statsp == NULL); - REQUIRE(statsp != NULL && *statsp != NULL); + LOCK(&stats->lock); + stats->references++; + UNLOCK(&stats->lock); - stats = *statsp; - -#ifdef ISC_RWLOCK_USEATOMIC - isc_rwlock_destroy(&stats->lock); -#endif - isc_mem_put(mctx, stats, sizeof(*stats)); - - *statsp = NULL; + *statsp = stats; } void -dns_stats_incrementcounter(dns_stats_t *stats, dns_statscounter_t counter) { - isc_int32_t prev; +dns_stats_detach(dns_stats_t **statsp) { + dns_stats_t *stats; - REQUIRE(counter < DNS_STATS_NCOUNTERS); + REQUIRE(statsp != NULL && DNS_STATS_VALID(*statsp)); + + stats = *statsp; + *statsp = NULL; + + LOCK(&stats->lock); + stats->references--; + UNLOCK(&stats->lock); + + if (stats->references == 0) { + isc_mem_put(stats->mctx, stats->copiedcounters, + sizeof(dns_stat_t) * stats->ncounters); + isc_mem_put(stats->mctx, stats->counters, + sizeof(dns_stat_t) * stats->ncounters); + DESTROYLOCK(&stats->lock); +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_destroy(&stats->counterlock); +#endif + isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); + } +} + +static inline void +incrementcounter(dns_stats_t *stats, int counter) { + isc_int32_t prev; #ifdef ISC_RWLOCK_USEATOMIC /* @@ -122,7 +230,7 @@ dns_stats_incrementcounter(dns_stats_t *stats, dns_statscounter_t counter) { * counter while we "writing" a counter field. The write access itself * is protected by the atomic operation. */ - isc_rwlock_lock(&stats->lock, isc_rwlocktype_read); + isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read); #endif #if DNS_STATS_USEMULTIFIELDS @@ -146,40 +254,296 @@ dns_stats_incrementcounter(dns_stats_t *stats, dns_statscounter_t counter) { #endif #ifdef ISC_RWLOCK_USEATOMIC - isc_rwlock_unlock(&stats->lock, isc_rwlocktype_read); + isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read); #endif } -void -dns_stats_copy(dns_stats_t *src, isc_uint64_t *dst) { - int i; +static inline void +decrementcounter(dns_stats_t *stats, int counter) { + isc_int32_t prev; +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read); +#endif + +#if DNS_STATS_USEMULTIFIELDS + prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, -1); + if (prev == 0) + isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi, + -1); +#elif defined(ISC_PLATFORM_HAVEXADDQ) + UNUSED(prev); + isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], -1); +#else + UNUSED(prev); + stats->counters[counter]--; +#endif + +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read); +#endif +} + +static void +copy_counters(dns_stats_t *stats) { + int i; + #ifdef ISC_RWLOCK_USEATOMIC /* * We use a "write" lock before "reading" the statistics counters as * an exclusive lock. */ - isc_rwlock_lock(&src->lock, isc_rwlocktype_write); + isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write); #endif #if DNS_STATS_USEMULTIFIELDS - for (i = 0; i < DNS_STATS_NCOUNTERS; i++) { - dst[i] = ((isc_uint64_t)src->counters[i].hi) << 32 | - src->counters[i].lo; + for (i = 0; i < stats->ncounters; i++) { + stats->copiedcounters[i] = + (isc_uint64_t)(stats->counters[i].hi) << 32 | + stats->counters[i].lo; } #else UNUSED(i); - memcpy(dst, src->counters, DNS_STATS_NCOUNTERS * sizeof(dst[0])); + memcpy(stats->copiedcounters, stats->counters, + stats->ncounters * sizeof(dns_stat_t)); #endif #ifdef ISC_RWLOCK_USEATOMIC - isc_rwlock_unlock(&src->lock, isc_rwlocktype_write); + isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write); #endif } +/*% + * Create methods + */ +isc_result_t +dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_general, ncounters, statsp)); +} + +isc_result_t +dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_rdtype, rdtypecounter_max, + statsp)); +} + +isc_result_t +dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_rdataset, + (rdtypecounter_max * 2) + 1, statsp)); +} + +isc_result_t +dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, dns_statstype_opcode, 16, statsp)); +} + +/*% + * Increment/Decrement methods + */ +void +dns_generalstats_increment(dns_stats_t *stats, dns_statscounter_t counter) { + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); + REQUIRE(counter < stats->ncounters); + + incrementcounter(stats, (int)counter); +} + +void +dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) { + int counter; + + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); + + if (type == dns_rdatatype_dlv) + counter = rdtypecounter_dlv; + else if (type > dns_rdatatype_any) + counter = rdtypecounter_others; + else + counter = (int)type; + + incrementcounter(stats, counter); +} + +static inline void +update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype, + isc_boolean_t increment) +{ + int counter; + dns_rdatatype_t rdtype; + + if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & + DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) { + counter = rdtypecounter_nxdomain; + } else { + rdtype = DNS_RDATASTATSTYPE_BASE(rrsettype); + if (rdtype == dns_rdatatype_dlv) + counter = (int)rdtypecounter_dlv; + else if (rdtype > dns_rdatatype_any) + counter = (int)rdtypecounter_others; + else + counter = (int)rdtype; + + if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & + DNS_RDATASTATSTYPE_ATTR_NXRRSET) != 0) + counter += rdtypecounter_max; + } + + if (increment) + incrementcounter(stats, counter); + else + decrementcounter(stats, counter); +} + +void +dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) +{ + REQUIRE(DNS_STATS_VALID(stats) && + stats->type == dns_statstype_rdataset); + + update_rdatasetstats(stats, rrsettype, ISC_TRUE); +} + +void +dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) +{ + REQUIRE(DNS_STATS_VALID(stats) && + stats->type == dns_statstype_rdataset); + + update_rdatasetstats(stats, rrsettype, ISC_FALSE); +} +void +dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) { + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); + + incrementcounter(stats, (int)code); +} + +/*% + * Dump methods + */ +void +dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, + void *arg, unsigned int options) +{ + int i; + + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); + + copy_counters(stats); + + for (i = 0; i < stats->ncounters; i++) { + if ((options & DNS_STATSDUMP_VERBOSE) == 0 && + stats->copiedcounters[i] == 0) + continue; + dump_fn(i, stats->copiedcounters[i], arg); + } +} + +static void +dump_rdentry(dns_stats_t *stats, int counter, int rdcounter, + dns_rdatastatstype_t attributes, + dns_rdatatypestats_dumper_t dump_fn, void * arg, + unsigned int options) +{ + dns_rdatatype_t rdtype = dns_rdatatype_none; /* sentinel */ + dns_rdatastatstype_t type; + + if ((options & DNS_STATSDUMP_VERBOSE) == 0 && + stats->copiedcounters[counter] == 0) + return; + if (rdcounter == rdtypecounter_others) + attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE; + else { + if (rdcounter == rdtypecounter_dlv) + rdtype = dns_rdatatype_dlv; + else + rdtype = (dns_rdatatype_t)rdcounter; + } + type = DNS_RDATASTATSTYPE_VALUE((dns_rdatastatstype_t)rdtype, + attributes); + dump_fn(type, stats->copiedcounters[counter], arg); +} + +void +dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options) +{ + int i; + + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); + + copy_counters(stats); + + for (i = 0; i < stats->ncounters; i++) + dump_rdentry(stats, i, i, 0, dump_fn, arg, options); +} + +void +dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options) +{ + int i; + + REQUIRE(DNS_STATS_VALID(stats) && + stats->type == dns_statstype_rdataset); + + copy_counters(stats); + + for (i = 0; i < rdtypecounter_max; i++) + dump_rdentry(stats, i, i, 0, dump_fn, arg, options); + for (i = rdtypecounter_max; i < rdtypenxcounter_max; i++) { + dump_rdentry(stats, i, i - rdtypecounter_max, + DNS_RDATASTATSTYPE_ATTR_NXRRSET, + dump_fn, arg, options); + } + dump_rdentry(stats, rdtypecounter_nxdomain, 0, + DNS_RDATASTATSTYPE_ATTR_NXDOMAIN, dump_fn, arg, options); + + INSIST(i < stats->ncounters); +} + +void +dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, + void *arg, unsigned int options) +{ + int i; + + REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); + + copy_counters(stats); + + for (i = 0; i < stats->ncounters; i++) { + if ((options & DNS_STATSDUMP_VERBOSE) == 0 && + stats->copiedcounters[i] == 0) + continue; + dump_fn((dns_opcode_t)i, stats->copiedcounters[i], arg); + } +} + /*** - *** Obsolete functions follow + *** Obsolete variables and functions follow: ***/ +LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] = + { + "success", + "referral", + "nxrrset", + "nxdomain", + "recursion", + "failure", + "duplicate", + "dropped" + }; + isc_result_t dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp) { int i; diff --git a/lib/dns/view.c b/lib/dns/view.c index 3a4489b8b2..cd740c79ef 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: view.c,v 1.145 2008/04/01 23:47:10 tbox Exp $ */ +/* $Id: view.c,v 1.146 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -25,7 +25,6 @@ #include /* Required for HP/UX (and others?) */ #include #include -#include #include #include @@ -44,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -152,6 +152,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->delonly = NULL; view->rootdelonly = ISC_FALSE; view->rootexclude = NULL; + view->resstats = NULL; + view->resquerystats = NULL; /* * Initialize configuration data with default values. @@ -332,6 +334,10 @@ destroy(dns_view_t *view) { sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH); view->rootexclude = NULL; } + if (view->resstats != NULL) + dns_stats_detach(&view->resstats); + if (view->resquerystats != NULL) + dns_stats_detach(&view->resquerystats); dns_keytable_detach(&view->trustedkeys); dns_keytable_detach(&view->secroots); dns_fwdtable_destroy(&view->fwdtable); @@ -1408,46 +1414,38 @@ dns_view_freezezones(dns_view_t *view, isc_boolean_t value) { return (dns_zt_freezezones(view->zonetable, value)); } -#ifdef HAVE_LIBXML2 +void +dns_view_setresstats(dns_view_t *view, dns_stats_t *stats) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(!view->frozen); + REQUIRE(view->resstats == NULL); -struct xmlarg { - int flags; - xmlTextWriterPtr xml; -}; - -static isc_result_t -zone_xmlrender(dns_zone_t *zone, void *arg) { - struct xmlarg *xmlarg = arg; - - return (dns_zone_xmlrender(zone, xmlarg->xml, xmlarg->flags)); + dns_stats_attach(stats, &view->resstats); } -isc_result_t -dns_view_xmlrender(dns_view_t *view, xmlTextWriterPtr xml, int flags) -{ - struct xmlarg xmlargs; +void +dns_view_getresstats(dns_view_t *view, dns_stats_t **statsp) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(statsp != NULL && *statsp == NULL); - xmlargs.flags = flags; - xmlargs.xml = xml; - - /* XXXMLG render config data here */ - - if ((flags & ISC_XML_RENDERSTATS) != 0) { - xmlTextWriterStartElement(xml, ISC_XMLCHAR "view"); - - xmlTextWriterStartElement(xml, ISC_XMLCHAR "name"); - xmlTextWriterWriteString(xml, ISC_XMLCHAR view->name); - xmlTextWriterEndElement(xml); - - xmlTextWriterStartElement(xml, ISC_XMLCHAR "zones"); - dns_zt_apply(view->zonetable, ISC_FALSE, zone_xmlrender, - &xmlargs); - xmlTextWriterEndElement(xml); - - xmlTextWriterEndElement(xml); - } - - return (ISC_R_SUCCESS); + if (view->resstats != NULL) + dns_stats_attach(view->resstats, statsp); } -#endif /* HAVE_LIBXML2 */ +void +dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(!view->frozen); + REQUIRE(view->resquerystats == NULL); + + dns_stats_attach(stats, &view->resquerystats); +} + +void +dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(statsp != NULL && *statsp == NULL); + + if (view->resquerystats != NULL) + dns_stats_attach(view->resquerystats, statsp); +} diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 8bc3204188..680187913f 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.477 2008/04/03 02:01:08 marka Exp $ */ +/* $Id: zone.c,v 1.478 2008/04/03 05:55:52 marka Exp $ */ /*! \file */ @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -264,9 +263,15 @@ struct dns_zone { ISC_LINK(dns_zone_t) statelink; dns_zonelist_t *statelist; /*% - * Optional per-zone statistics counters (NULL if not present). + * Statistics counters about zone management. */ - dns_stats_t *counters; + dns_stats_t *stats; + /*% + * Optional per-zone statistics counters. Counted outside of this + * module. + */ + isc_boolean_t requeststats_on; + dns_stats_t *requeststats; isc_uint32_t notifydelay; dns_isselffunc_t isself; void *isselfarg; @@ -592,6 +597,15 @@ static const char *dbargv_default[] = { "rbt" }; } \ } while (0) +/*% + * Increment resolver-related statistics counters. Zone must be locked. + */ +static inline void +inc_stats(dns_zone_t *zone, dns_statscounter_t counter) { + if (zone->stats != NULL) + dns_generalstats_increment(zone->stats, counter); +} + /*** *** Public functions. ***/ @@ -712,7 +726,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { zone->checkns = NULL; ISC_LINK_INIT(zone, statelink); zone->statelist = NULL; - zone->counters = NULL; + zone->stats = NULL; + zone->requeststats_on = ISC_FALSE; + zone->requeststats = NULL; zone->notifydelay = 5; zone->isself = NULL; zone->isselfarg = NULL; @@ -797,8 +813,10 @@ zone_free(dns_zone_t *zone) { if (zone->journal != NULL) isc_mem_free(zone->mctx, zone->journal); zone->journal = NULL; - if (zone->counters != NULL) - dns_stats_destroy(zone->mctx, &zone->counters); + if (zone->stats != NULL) + dns_stats_detach(&zone->stats); + if (zone->requeststats != NULL) + dns_stats_detach(&zone->requeststats); if (zone->db != NULL) zone_detachdb(zone); if (zone->acache != NULL) @@ -876,7 +894,7 @@ dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) { } dns_rdataclass_t -dns_zone_getclass(dns_zone_t *zone){ +dns_zone_getclass(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); return (zone->rdclass); @@ -891,6 +909,19 @@ dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) { UNLOCK_ZONE(zone); } +isc_uint32_t +dns_zone_getserial(dns_zone_t *zone) { + isc_uint32_t serial; + + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + serial = zone->serial; + UNLOCK_ZONE(zone); + + return (serial); +} + /* * Single shot. */ @@ -5288,6 +5319,16 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) { timeout * 3, timeout, notify->zone->task, notify_done, notify, ¬ify->request); + if (result == ISC_R_SUCCESS) { + if (isc_sockaddr_pf(¬ify->dst) == AF_INET) { + inc_stats(notify->zone, + dns_zonestatscounter_notifyoutv4); + } else { + inc_stats(notify->zone, + dns_zonestatscounter_notifyoutv6); + } + } + cleanup_key: if (key != NULL) dns_tsigkey_detach(&key); @@ -6561,6 +6602,11 @@ soa_query(isc_task_t *task, isc_event_t *event) { "dns_request_createvia2() failed: %s", dns_result_totext(result)); goto cleanup; + } else { + if (isc_sockaddr_pf(&zone->masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_soaoutv4); + else + inc_stats(zone, dns_zonestatscounter_soaoutv6); } cancel = ISC_FALSE; @@ -7219,6 +7265,10 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, * We only handle NOTIFY (SOA) at the present. */ LOCK_ZONE(zone); + if (isc_sockaddr_pf(from) == PF_INET) + inc_stats(zone, dns_zonestatscounter_notifyinv4); + else + inc_stats(zone, dns_zonestatscounter_notifyinv6); if (msg->counts[DNS_SECTION_QUESTION] == 0 || dns_message_findname(msg, DNS_SECTION_QUESTION, &zone->origin, dns_rdatatype_soa, dns_rdatatype_none, @@ -7273,6 +7323,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, UNLOCK_ZONE(zone); dns_zone_log(zone, ISC_LOG_INFO, "refused notify from non-master: %s", fromtext); + inc_stats(zone, dns_zonestatscounter_notifyrej); return (DNS_R_REFUSED); } @@ -8241,6 +8292,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { dns_result_totext(result)); } + inc_stats(zone, dns_zonestatscounter_xfrsuccess); break; case DNS_R_BADIXFR: @@ -8275,6 +8327,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); again = ISC_TRUE; } + inc_stats(zone, dns_zonestatscounter_xfrfail); break; } zone_settimer(zone, &now); @@ -8578,6 +8631,21 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { zone->tsigkey, zone->mctx, zone->zmgr->timermgr, zone->zmgr->socketmgr, zone->task, zone_xfrdone, &zone->xfr); + if (result == ISC_R_SUCCESS) { + LOCK_ZONE(zone); + if (xfrtype == dns_rdatatype_axfr) { + if (isc_sockaddr_pf(&masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_axfrreqv4); + else + inc_stats(zone, dns_zonestatscounter_axfrreqv6); + } else if (xfrtype == dns_rdatatype_ixfr) { + if (isc_sockaddr_pf(&masteraddr) == PF_INET) + inc_stats(zone, dns_zonestatscounter_ixfrreqv4); + else + inc_stats(zone, dns_zonestatscounter_ixfrreqv6); + } + UNLOCK_ZONE(zone); + } cleanup: /* * Any failure in this function is handled like a failed @@ -9569,35 +9637,66 @@ dns_zone_isforced(dns_zone_t *zone) { isc_result_t dns_zone_setstatistics(dns_zone_t *zone, isc_boolean_t on) { - isc_result_t result = ISC_R_SUCCESS; - - LOCK_ZONE(zone); - if (on) { - if (zone->counters != NULL) - goto done; - result = dns_stats_create(zone->mctx, &zone->counters); - } else { - if (zone->counters == NULL) - goto done; - dns_stats_destroy(zone->mctx, &zone->counters); - } - done: - UNLOCK_ZONE(zone); - return (result); + /* + * This function is obsoleted. + */ + UNUSED(zone); + UNUSED(on); + return (ISC_R_NOTIMPLEMENTED); } isc_uint64_t * dns_zone_getstatscounters(dns_zone_t *zone) { /* - * This function is obsoleted by dns_zone_getstats(). + * This function is obsoleted. */ UNUSED(zone); return (NULL); } +void +dns_zone_setstats(dns_zone_t *zone, dns_stats_t *stats) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(zone->stats == NULL); + + LOCK_ZONE(zone); + zone->stats = NULL; + dns_stats_attach(stats, &zone->stats); + UNLOCK_ZONE(zone); +} + +void +dns_zone_setrequeststats(dns_zone_t *zone, dns_stats_t *stats) { + REQUIRE(DNS_ZONE_VALID(zone)); + + LOCK_ZONE(zone); + if (zone->requeststats_on && stats == NULL) + zone->requeststats_on = ISC_FALSE; + else if (!zone->requeststats_on && stats != NULL) { + if (zone->requeststats == NULL) { + dns_stats_attach(stats, &zone->requeststats); + zone->requeststats_on = ISC_TRUE; + } + } + UNLOCK_ZONE(zone); + + return; +} + dns_stats_t * -dns_zone_getstats(dns_zone_t *zone) { - return (zone->counters); +dns_zone_getrequeststats(dns_zone_t *zone) { + /* + * We don't lock zone for efficiency reason. This is not catastrophic + * because requeststats must always be valid when requeststats_on is + * true. + * Some counters may be incremented while requeststats_on is becoming + * false, or some cannot be incremented just after the statistics are + * installed, but it shouldn't matter much in practice. + */ + if (zone->requeststats_on) + return (zone->requeststats); + else + return (NULL); } void @@ -9908,50 +10007,3 @@ zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid) { } return (result); } - -#ifdef HAVE_LIBXML2 - -isc_result_t -dns_zone_xmlrender(dns_zone_t *zone, xmlTextWriterPtr xml, int flags) -{ - int i; - - /* XXXMLG render config data here */ - - if ((flags & ISC_XML_RENDERSTATS) != 0) { - xmlTextWriterStartElement(xml, ISC_XMLCHAR "zone"); - - xmlTextWriterStartElement(xml, ISC_XMLCHAR "name"); - xmlTextWriterWriteString(xml, ISC_XMLCHAR zone->strname); - xmlTextWriterEndElement(xml); - - xmlTextWriterStartElement(xml, ISC_XMLCHAR "rdataclass"); - xmlTextWriterWriteString(xml, ISC_XMLCHAR zone->strrdclass); - xmlTextWriterEndElement(xml); - - xmlTextWriterStartElement(xml, ISC_XMLCHAR "serial"); - xmlTextWriterWriteFormatString(xml, "%u", zone->serial); - xmlTextWriterEndElement(xml); - - if (zone->counters != NULL) { - isc_uint64_t counters[DNS_STATS_NCOUNTERS]; - - xmlTextWriterStartElement(xml, ISC_XMLCHAR "counters"); - dns_stats_copy(zone->counters, counters); - for (i = 0 ; i < DNS_STATS_NCOUNTERS ; i++) { - xmlTextWriterStartElement(xml, - ISC_XMLCHAR dns_statscounter_names[i]); - xmlTextWriterWriteFormatString(xml, - "%" ISC_PRINT_QUADFORMAT "u", - counters[i]); - xmlTextWriterEndElement(xml); - } - xmlTextWriterEndElement(xml); /* counters */ - } - xmlTextWriterEndElement(xml); /* zone */ - } - - return (ISC_R_SUCCESS); -} - -#endif /* HAVE_LIBXML2 */
Zones for View
NameReferralNXRRSETNXDOMAINRecursionFailureDuplicateDroppedXfrReqDoneXfrRej
\n" - " \n" + " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n" - " \n" - " \n" - " \n" + " \n" "