stats.c revision 193149
11556Srgrimes/* 21556Srgrimes * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 31556Srgrimes * Copyright (C) 2000, 2001 Internet Software Consortium. 41556Srgrimes * 51556Srgrimes * Permission to use, copy, modify, and/or distribute this software for any 61556Srgrimes * purpose with or without fee is hereby granted, provided that the above 71556Srgrimes * copyright notice and this permission notice appear in all copies. 81556Srgrimes * 91556Srgrimes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 101556Srgrimes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 111556Srgrimes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 121556Srgrimes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 131556Srgrimes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 141556Srgrimes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 151556Srgrimes * PERFORMANCE OF THIS SOFTWARE. 161556Srgrimes */ 171556Srgrimes 181556Srgrimes/* $Id: stats.c,v 1.16.118.2 2009/01/29 23:47:44 tbox Exp $ */ 191556Srgrimes 201556Srgrimes/*! \file */ 211556Srgrimes 221556Srgrimes#include <config.h> 231556Srgrimes 241556Srgrimes#include <isc/magic.h> 251556Srgrimes#include <isc/mem.h> 261556Srgrimes#include <isc/stats.h> 271556Srgrimes#include <isc/util.h> 281556Srgrimes 291556Srgrimes#include <dns/opcode.h> 301556Srgrimes#include <dns/rdatatype.h> 311556Srgrimes#include <dns/stats.h> 321556Srgrimes 331556Srgrimes#define DNS_STATS_MAGIC ISC_MAGIC('D', 's', 't', 't') 341556Srgrimes#define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC) 351556Srgrimes 361556Srgrimes/*% 371556Srgrimes * Statistics types. 381556Srgrimes */ 391556Srgrimestypedef enum { 401556Srgrimes dns_statstype_general = 0, 411556Srgrimes dns_statstype_rdtype = 1, 421556Srgrimes dns_statstype_rdataset = 2, 431556Srgrimes dns_statstype_opcode = 3 441556Srgrimes} dns_statstype_t; 451556Srgrimes 461556Srgrimes/*% 471556Srgrimes * It doesn't make sense to have 2^16 counters for all possible types since 481556Srgrimes * most of them won't be used. We have counters for the first 256 types and 491556Srgrimes * those explicitly supported in the rdata implementation. 501556Srgrimes * XXXJT: this introduces tight coupling with the rdata implementation. 511556Srgrimes * Ideally, we should have rdata handle this type of details. 521556Srgrimes */ 531556Srgrimesenum { 541556Srgrimes /* For 0-255, we use the rdtype value as counter indices */ 551556Srgrimes rdtypecounter_dlv = 256, /* for dns_rdatatype_dlv */ 561556Srgrimes rdtypecounter_others = 257, /* anything else */ 571556Srgrimes rdtypecounter_max = 258, 581556Srgrimes /* The following are used for rdataset */ 591556Srgrimes rdtypenxcounter_max = rdtypecounter_max * 2, 601556Srgrimes rdtypecounter_nxdomain = rdtypenxcounter_max, 611556Srgrimes rdatasettypecounter_max = rdtypecounter_nxdomain + 1 621556Srgrimes}; 631556Srgrimes 641556Srgrimesstruct dns_stats { 651556Srgrimes /*% Unlocked */ 661556Srgrimes unsigned int magic; 671556Srgrimes dns_statstype_t type; 681556Srgrimes isc_mem_t *mctx; 691556Srgrimes isc_mutex_t lock; 701556Srgrimes isc_stats_t *counters; 711556Srgrimes 721556Srgrimes /*% Locked by lock */ 731556Srgrimes unsigned int references; 741556Srgrimes}; 751556Srgrimes 761556Srgrimestypedef struct rdatadumparg { 771556Srgrimes dns_rdatatypestats_dumper_t fn; 781556Srgrimes void *arg; 791556Srgrimes} rdatadumparg_t; 801556Srgrimes 811556Srgrimestypedef struct opcodedumparg { 821556Srgrimes dns_opcodestats_dumper_t fn; 831556Srgrimes void *arg; 841556Srgrimes} opcodedumparg_t; 851556Srgrimes 861556Srgrimesvoid 87dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) { 88 REQUIRE(DNS_STATS_VALID(stats)); 89 REQUIRE(statsp != NULL && *statsp == NULL); 90 91 LOCK(&stats->lock); 92 stats->references++; 93 UNLOCK(&stats->lock); 94 95 *statsp = stats; 96} 97 98void 99dns_stats_detach(dns_stats_t **statsp) { 100 dns_stats_t *stats; 101 102 REQUIRE(statsp != NULL && DNS_STATS_VALID(*statsp)); 103 104 stats = *statsp; 105 *statsp = NULL; 106 107 LOCK(&stats->lock); 108 stats->references--; 109 UNLOCK(&stats->lock); 110 111 if (stats->references == 0) { 112 isc_stats_detach(&stats->counters); 113 DESTROYLOCK(&stats->lock); 114 isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); 115 } 116} 117 118/*% 119 * Create methods 120 */ 121static isc_result_t 122create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters, 123 dns_stats_t **statsp) 124{ 125 dns_stats_t *stats; 126 isc_result_t result; 127 128 stats = isc_mem_get(mctx, sizeof(*stats)); 129 if (stats == NULL) 130 return (ISC_R_NOMEMORY); 131 132 stats->counters = NULL; 133 stats->references = 1; 134 135 result = isc_mutex_init(&stats->lock); 136 if (result != ISC_R_SUCCESS) 137 goto clean_stats; 138 139 result = isc_stats_create(mctx, &stats->counters, ncounters); 140 if (result != ISC_R_SUCCESS) 141 goto clean_mutex; 142 143 stats->magic = DNS_STATS_MAGIC; 144 stats->type = type; 145 stats->mctx = NULL; 146 isc_mem_attach(mctx, &stats->mctx); 147 *statsp = stats; 148 149 return (ISC_R_SUCCESS); 150 151 clean_mutex: 152 DESTROYLOCK(&stats->lock); 153 clean_stats: 154 isc_mem_put(mctx, stats, sizeof(*stats)); 155 156 return (result); 157} 158 159isc_result_t 160dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) { 161 REQUIRE(statsp != NULL && *statsp == NULL); 162 163 return (create_stats(mctx, dns_statstype_general, ncounters, statsp)); 164} 165 166isc_result_t 167dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { 168 REQUIRE(statsp != NULL && *statsp == NULL); 169 170 return (create_stats(mctx, dns_statstype_rdtype, rdtypecounter_max, 171 statsp)); 172} 173 174isc_result_t 175dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) { 176 REQUIRE(statsp != NULL && *statsp == NULL); 177 178 return (create_stats(mctx, dns_statstype_rdataset, 179 (rdtypecounter_max * 2) + 1, statsp)); 180} 181 182isc_result_t 183dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { 184 REQUIRE(statsp != NULL && *statsp == NULL); 185 186 return (create_stats(mctx, dns_statstype_opcode, 16, statsp)); 187} 188 189/*% 190 * Increment/Decrement methods 191 */ 192void 193dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter) { 194 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); 195 196 isc_stats_increment(stats->counters, counter); 197} 198 199void 200dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) { 201 int counter; 202 203 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); 204 205 if (type == dns_rdatatype_dlv) 206 counter = rdtypecounter_dlv; 207 else if (type > dns_rdatatype_any) 208 counter = rdtypecounter_others; 209 else 210 counter = (int)type; 211 212 isc_stats_increment(stats->counters, (isc_statscounter_t)counter); 213} 214 215static inline void 216update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype, 217 isc_boolean_t increment) 218{ 219 int counter; 220 dns_rdatatype_t rdtype; 221 222 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & 223 DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) { 224 counter = rdtypecounter_nxdomain; 225 } else { 226 rdtype = DNS_RDATASTATSTYPE_BASE(rrsettype); 227 if (rdtype == dns_rdatatype_dlv) 228 counter = (int)rdtypecounter_dlv; 229 else if (rdtype > dns_rdatatype_any) 230 counter = (int)rdtypecounter_others; 231 else 232 counter = (int)rdtype; 233 234 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & 235 DNS_RDATASTATSTYPE_ATTR_NXRRSET) != 0) 236 counter += rdtypecounter_max; 237 } 238 239 if (increment) 240 isc_stats_increment(stats->counters, counter); 241 else 242 isc_stats_decrement(stats->counters, counter); 243} 244 245void 246dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) 247{ 248 REQUIRE(DNS_STATS_VALID(stats) && 249 stats->type == dns_statstype_rdataset); 250 251 update_rdatasetstats(stats, rrsettype, ISC_TRUE); 252} 253 254void 255dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) 256{ 257 REQUIRE(DNS_STATS_VALID(stats) && 258 stats->type == dns_statstype_rdataset); 259 260 update_rdatasetstats(stats, rrsettype, ISC_FALSE); 261} 262void 263dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) { 264 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); 265 266 isc_stats_increment(stats->counters, (isc_statscounter_t)code); 267} 268 269/*% 270 * Dump methods 271 */ 272void 273dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, 274 void *arg, unsigned int options) 275{ 276 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); 277 278 isc_stats_dump(stats->counters, (isc_stats_dumper_t)dump_fn, 279 arg, options); 280} 281 282static void 283dump_rdentry(int rdcounter, isc_uint64_t value, dns_rdatastatstype_t attributes, 284 dns_rdatatypestats_dumper_t dump_fn, void * arg) 285{ 286 dns_rdatatype_t rdtype = dns_rdatatype_none; /* sentinel */ 287 dns_rdatastatstype_t type; 288 289 if (rdcounter == rdtypecounter_others) 290 attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE; 291 else { 292 if (rdcounter == rdtypecounter_dlv) 293 rdtype = dns_rdatatype_dlv; 294 else 295 rdtype = (dns_rdatatype_t)rdcounter; 296 } 297 type = DNS_RDATASTATSTYPE_VALUE((dns_rdatastatstype_t)rdtype, 298 attributes); 299 dump_fn(type, value, arg); 300} 301 302static void 303rdatatype_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { 304 rdatadumparg_t *rdatadumparg = arg; 305 306 dump_rdentry(counter, value, 0, rdatadumparg->fn, rdatadumparg->arg); 307} 308 309void 310dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, 311 void *arg0, unsigned int options) 312{ 313 rdatadumparg_t arg; 314 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); 315 316 arg.fn = dump_fn; 317 arg.arg = arg0; 318 isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options); 319} 320 321static void 322rdataset_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { 323 rdatadumparg_t *rdatadumparg = arg; 324 325 if (counter < rdtypecounter_max) { 326 dump_rdentry(counter, value, 0, rdatadumparg->fn, 327 rdatadumparg->arg); 328 } else if (counter < rdtypenxcounter_max) { 329 dump_rdentry(counter - rdtypecounter_max, value, 330 DNS_RDATASTATSTYPE_ATTR_NXRRSET, 331 rdatadumparg->fn, rdatadumparg->arg); 332 } else { 333 dump_rdentry(0, value, DNS_RDATASTATSTYPE_ATTR_NXDOMAIN, 334 rdatadumparg->fn, rdatadumparg->arg); 335 } 336} 337 338void 339dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, 340 void *arg0, unsigned int options) 341{ 342 rdatadumparg_t arg; 343 344 REQUIRE(DNS_STATS_VALID(stats) && 345 stats->type == dns_statstype_rdataset); 346 347 arg.fn = dump_fn; 348 arg.arg = arg0; 349 isc_stats_dump(stats->counters, rdataset_dumpcb, &arg, options); 350} 351 352static void 353opcode_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { 354 opcodedumparg_t *opcodearg = arg; 355 356 opcodearg->fn((dns_opcode_t)counter, value, opcodearg->arg); 357} 358 359void 360dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, 361 void *arg0, unsigned int options) 362{ 363 opcodedumparg_t arg; 364 365 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); 366 367 arg.fn = dump_fn; 368 arg.arg = arg0; 369 isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options); 370} 371 372/*** 373 *** Obsolete variables and functions follow: 374 ***/ 375LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] = 376 { 377 "success", 378 "referral", 379 "nxrrset", 380 "nxdomain", 381 "recursion", 382 "failure", 383 "duplicate", 384 "dropped" 385 }; 386 387isc_result_t 388dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp) { 389 int i; 390 isc_uint64_t *p = 391 isc_mem_get(mctx, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t)); 392 if (p == NULL) 393 return (ISC_R_NOMEMORY); 394 for (i = 0; i < DNS_STATS_NCOUNTERS; i++) 395 p[i] = 0; 396 *ctrp = p; 397 return (ISC_R_SUCCESS); 398} 399 400void 401dns_stats_freecounters(isc_mem_t *mctx, isc_uint64_t **ctrp) { 402 isc_mem_put(mctx, *ctrp, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t)); 403 *ctrp = NULL; 404} 405