1/* 2 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000, 2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: stats.c,v 1.18 2009/01/27 23:47:54 tbox Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <isc/magic.h> 25#include <isc/mem.h> 26#include <isc/stats.h> 27#include <isc/util.h> 28 29#include <dns/opcode.h> 30#include <dns/rdatatype.h> 31#include <dns/stats.h> 32 33#define DNS_STATS_MAGIC ISC_MAGIC('D', 's', 't', 't') 34#define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC) 35 36/*% 37 * Statistics types. 38 */ 39typedef enum { 40 dns_statstype_general = 0, 41 dns_statstype_rdtype = 1, 42 dns_statstype_rdataset = 2, 43 dns_statstype_opcode = 3 44} dns_statstype_t; 45 46/*% 47 * It doesn't make sense to have 2^16 counters for all possible types since 48 * most of them won't be used. We have counters for the first 256 types and 49 * those explicitly supported in the rdata implementation. 50 * XXXJT: this introduces tight coupling with the rdata implementation. 51 * Ideally, we should have rdata handle this type of details. 52 */ 53enum { 54 /* For 0-255, we use the rdtype value as counter indices */ 55 rdtypecounter_dlv = 256, /* for dns_rdatatype_dlv */ 56 rdtypecounter_others = 257, /* anything else */ 57 rdtypecounter_max = 258, 58 /* The following are used for rdataset */ 59 rdtypenxcounter_max = rdtypecounter_max * 2, 60 rdtypecounter_nxdomain = rdtypenxcounter_max, 61 rdatasettypecounter_max = rdtypecounter_nxdomain + 1 62}; 63 64struct dns_stats { 65 /*% Unlocked */ 66 unsigned int magic; 67 dns_statstype_t type; 68 isc_mem_t *mctx; 69 isc_mutex_t lock; 70 isc_stats_t *counters; 71 72 /*% Locked by lock */ 73 unsigned int references; 74}; 75 76typedef struct rdatadumparg { 77 dns_rdatatypestats_dumper_t fn; 78 void *arg; 79} rdatadumparg_t; 80 81typedef struct opcodedumparg { 82 dns_opcodestats_dumper_t fn; 83 void *arg; 84} opcodedumparg_t; 85 86void 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