1 /* $NetBSD: stats.c,v 1.5 2014/12/10 04:37:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2005, 2007-2009, 2012 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 2000, 2001 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: stats.c,v 1.18 2009/01/27 23:47:54 tbox Exp */ 21 22 /*! \file */ 23 24 #include <config.h> 25 26 #include <isc/magic.h> 27 #include <isc/mem.h> 28 #include <isc/stats.h> 29 #include <isc/util.h> 30 31 #include <dns/opcode.h> 32 #include <dns/rdatatype.h> 33 #include <dns/stats.h> 34 35 #define DNS_STATS_MAGIC ISC_MAGIC('D', 's', 't', 't') 36 #define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC) 37 38 /*% 39 * Statistics types. 40 */ 41 typedef enum { 42 dns_statstype_general = 0, 43 dns_statstype_rdtype = 1, 44 dns_statstype_rdataset = 2, 45 dns_statstype_opcode = 3 46 } dns_statstype_t; 47 48 /*% 49 * It doesn't make sense to have 2^16 counters for all possible types since 50 * most of them won't be used. We have counters for the first 256 types and 51 * those explicitly supported in the rdata implementation. 52 * XXXJT: this introduces tight coupling with the rdata implementation. 53 * Ideally, we should have rdata handle this type of details. 54 */ 55 /* 56 * types, !types, nxdomain, stale types, stale !types, stale nxdomain 57 */ 58 enum { 59 /* For 0-255, we use the rdtype value as counter indices */ 60 rdtypecounter_dlv = 256, /* for dns_rdatatype_dlv */ 61 rdtypecounter_others = 257, /* anything else */ 62 rdtypecounter_max = 258, 63 /* The following are used for rdataset */ 64 rdtypenxcounter_max = rdtypecounter_max * 2, 65 rdtypecounter_nxdomain = rdtypenxcounter_max, 66 /* stale counters offset */ 67 rdtypecounter_stale = rdtypecounter_nxdomain + 1, 68 rdatasettypecounter_max = rdtypecounter_stale * 2 69 }; 70 71 struct dns_stats { 72 /*% Unlocked */ 73 unsigned int magic; 74 dns_statstype_t type; 75 isc_mem_t *mctx; 76 isc_mutex_t lock; 77 isc_stats_t *counters; 78 79 /*% Locked by lock */ 80 unsigned int references; 81 }; 82 83 typedef struct rdatadumparg { 84 dns_rdatatypestats_dumper_t fn; 85 void *arg; 86 } rdatadumparg_t; 87 88 typedef struct opcodedumparg { 89 dns_opcodestats_dumper_t fn; 90 void *arg; 91 } opcodedumparg_t; 92 93 void 94 dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) { 95 REQUIRE(DNS_STATS_VALID(stats)); 96 REQUIRE(statsp != NULL && *statsp == NULL); 97 98 LOCK(&stats->lock); 99 stats->references++; 100 UNLOCK(&stats->lock); 101 102 *statsp = stats; 103 } 104 105 void 106 dns_stats_detach(dns_stats_t **statsp) { 107 dns_stats_t *stats; 108 109 REQUIRE(statsp != NULL && DNS_STATS_VALID(*statsp)); 110 111 stats = *statsp; 112 *statsp = NULL; 113 114 LOCK(&stats->lock); 115 stats->references--; 116 UNLOCK(&stats->lock); 117 118 if (stats->references == 0) { 119 isc_stats_detach(&stats->counters); 120 DESTROYLOCK(&stats->lock); 121 isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); 122 } 123 } 124 125 /*% 126 * Create methods 127 */ 128 static isc_result_t 129 create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters, 130 dns_stats_t **statsp) 131 { 132 dns_stats_t *stats; 133 isc_result_t result; 134 135 stats = isc_mem_get(mctx, sizeof(*stats)); 136 if (stats == NULL) 137 return (ISC_R_NOMEMORY); 138 139 stats->counters = NULL; 140 stats->references = 1; 141 142 result = isc_mutex_init(&stats->lock); 143 if (result != ISC_R_SUCCESS) 144 goto clean_stats; 145 146 result = isc_stats_create(mctx, &stats->counters, ncounters); 147 if (result != ISC_R_SUCCESS) 148 goto clean_mutex; 149 150 stats->magic = DNS_STATS_MAGIC; 151 stats->type = type; 152 stats->mctx = NULL; 153 isc_mem_attach(mctx, &stats->mctx); 154 *statsp = stats; 155 156 return (ISC_R_SUCCESS); 157 158 clean_mutex: 159 DESTROYLOCK(&stats->lock); 160 clean_stats: 161 isc_mem_put(mctx, stats, sizeof(*stats)); 162 163 return (result); 164 } 165 166 isc_result_t 167 dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) { 168 REQUIRE(statsp != NULL && *statsp == NULL); 169 170 return (create_stats(mctx, dns_statstype_general, ncounters, statsp)); 171 } 172 173 isc_result_t 174 dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { 175 REQUIRE(statsp != NULL && *statsp == NULL); 176 177 return (create_stats(mctx, dns_statstype_rdtype, rdtypecounter_max, 178 statsp)); 179 } 180 181 isc_result_t 182 dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) { 183 REQUIRE(statsp != NULL && *statsp == NULL); 184 185 return (create_stats(mctx, dns_statstype_rdataset, 186 rdatasettypecounter_max, statsp)); 187 } 188 189 isc_result_t 190 dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { 191 REQUIRE(statsp != NULL && *statsp == NULL); 192 193 return (create_stats(mctx, dns_statstype_opcode, 16, statsp)); 194 } 195 196 /*% 197 * Increment/Decrement methods 198 */ 199 void 200 dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter) { 201 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); 202 203 isc_stats_increment(stats->counters, counter); 204 } 205 206 void 207 dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) { 208 int counter; 209 210 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); 211 212 if (type == dns_rdatatype_dlv) 213 counter = rdtypecounter_dlv; 214 else if (type > dns_rdatatype_any) 215 counter = rdtypecounter_others; 216 else 217 counter = (int)type; 218 219 isc_stats_increment(stats->counters, (isc_statscounter_t)counter); 220 } 221 222 static inline void 223 update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype, 224 isc_boolean_t increment) 225 { 226 int counter; 227 dns_rdatatype_t rdtype; 228 229 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & 230 DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) { 231 counter = rdtypecounter_nxdomain; 232 } else { 233 rdtype = DNS_RDATASTATSTYPE_BASE(rrsettype); 234 if (rdtype == dns_rdatatype_dlv) 235 counter = (int)rdtypecounter_dlv; 236 else if (rdtype > dns_rdatatype_any) 237 counter = (int)rdtypecounter_others; 238 else 239 counter = (int)rdtype; 240 241 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & 242 DNS_RDATASTATSTYPE_ATTR_NXRRSET) != 0) 243 counter += rdtypecounter_max; 244 } 245 246 if (increment) { 247 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & 248 DNS_RDATASTATSTYPE_ATTR_STALE) != 0) { 249 isc_stats_decrement(stats->counters, counter); 250 counter += rdtypecounter_stale; 251 } 252 isc_stats_increment(stats->counters, counter); 253 } else { 254 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) & 255 DNS_RDATASTATSTYPE_ATTR_STALE) != 0) 256 counter += rdtypecounter_stale; 257 isc_stats_decrement(stats->counters, counter); 258 } 259 } 260 261 void 262 dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) 263 { 264 REQUIRE(DNS_STATS_VALID(stats) && 265 stats->type == dns_statstype_rdataset); 266 267 update_rdatasetstats(stats, rrsettype, ISC_TRUE); 268 } 269 270 void 271 dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype) 272 { 273 REQUIRE(DNS_STATS_VALID(stats) && 274 stats->type == dns_statstype_rdataset); 275 276 update_rdatasetstats(stats, rrsettype, ISC_FALSE); 277 } 278 279 void 280 dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) { 281 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); 282 283 isc_stats_increment(stats->counters, (isc_statscounter_t)code); 284 } 285 286 /*% 287 * Dump methods 288 */ 289 void 290 dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, 291 void *arg, unsigned int options) 292 { 293 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general); 294 295 isc_stats_dump(stats->counters, (isc_stats_dumper_t)dump_fn, 296 arg, options); 297 } 298 299 static void 300 dump_rdentry(int rdcounter, isc_uint64_t value, dns_rdatastatstype_t attributes, 301 dns_rdatatypestats_dumper_t dump_fn, void * arg) 302 { 303 dns_rdatatype_t rdtype = dns_rdatatype_none; /* sentinel */ 304 dns_rdatastatstype_t type; 305 306 if (rdcounter == rdtypecounter_others) 307 attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE; 308 else { 309 if (rdcounter == rdtypecounter_dlv) 310 rdtype = dns_rdatatype_dlv; 311 else 312 rdtype = (dns_rdatatype_t)rdcounter; 313 } 314 type = DNS_RDATASTATSTYPE_VALUE((dns_rdatastatstype_t)rdtype, 315 attributes); 316 dump_fn(type, value, arg); 317 } 318 319 static void 320 rdatatype_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { 321 rdatadumparg_t *rdatadumparg = arg; 322 323 dump_rdentry(counter, value, 0, rdatadumparg->fn, rdatadumparg->arg); 324 } 325 326 void 327 dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, 328 void *arg0, unsigned int options) 329 { 330 rdatadumparg_t arg; 331 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); 332 333 arg.fn = dump_fn; 334 arg.arg = arg0; 335 isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options); 336 } 337 338 static void 339 rdataset_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { 340 rdatadumparg_t *rdatadumparg = arg; 341 unsigned int attributes; 342 343 if (counter < rdtypecounter_max) { 344 dump_rdentry(counter, value, 0, rdatadumparg->fn, 345 rdatadumparg->arg); 346 } else if (counter < rdtypecounter_nxdomain) { 347 counter -= rdtypecounter_max; 348 attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET; 349 dump_rdentry(counter, value, attributes, rdatadumparg->fn, 350 rdatadumparg->arg); 351 } else if (counter == rdtypecounter_nxdomain) { 352 dump_rdentry(0, value, DNS_RDATASTATSTYPE_ATTR_NXDOMAIN, 353 rdatadumparg->fn, rdatadumparg->arg); 354 } else if (counter < rdtypecounter_stale + rdtypecounter_max) { 355 counter -= rdtypecounter_stale; 356 attributes = DNS_RDATASTATSTYPE_ATTR_STALE; 357 dump_rdentry(counter, value, attributes, rdatadumparg->fn, 358 rdatadumparg->arg); 359 } else if (counter < rdtypecounter_stale + rdtypecounter_nxdomain) { 360 counter -= rdtypecounter_stale + rdtypecounter_max; 361 attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET | 362 DNS_RDATASTATSTYPE_ATTR_STALE; 363 dump_rdentry(counter, value, attributes, rdatadumparg->fn, 364 rdatadumparg->arg); 365 } else { 366 attributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN | 367 DNS_RDATASTATSTYPE_ATTR_STALE; 368 dump_rdentry(0, value, attributes, rdatadumparg->fn, 369 rdatadumparg->arg); 370 } 371 } 372 373 void 374 dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, 375 void *arg0, unsigned int options) 376 { 377 rdatadumparg_t arg; 378 379 REQUIRE(DNS_STATS_VALID(stats) && 380 stats->type == dns_statstype_rdataset); 381 382 arg.fn = dump_fn; 383 arg.arg = arg0; 384 isc_stats_dump(stats->counters, rdataset_dumpcb, &arg, options); 385 } 386 387 static void 388 opcode_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) { 389 opcodedumparg_t *opcodearg = arg; 390 391 opcodearg->fn((dns_opcode_t)counter, value, opcodearg->arg); 392 } 393 394 void 395 dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, 396 void *arg0, unsigned int options) 397 { 398 opcodedumparg_t arg; 399 400 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); 401 402 arg.fn = dump_fn; 403 arg.arg = arg0; 404 isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options); 405 } 406 407 /*** 408 *** Obsolete variables and functions follow: 409 ***/ 410 LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] = 411 { 412 "success", 413 "referral", 414 "nxrrset", 415 "nxdomain", 416 "recursion", 417 "failure", 418 "duplicate", 419 "dropped" 420 }; 421 422 isc_result_t 423 dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp) { 424 int i; 425 isc_uint64_t *p = 426 isc_mem_get(mctx, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t)); 427 if (p == NULL) 428 return (ISC_R_NOMEMORY); 429 for (i = 0; i < DNS_STATS_NCOUNTERS; i++) 430 p[i] = 0; 431 *ctrp = p; 432 return (ISC_R_SUCCESS); 433 } 434 435 void 436 dns_stats_freecounters(isc_mem_t *mctx, isc_uint64_t **ctrp) { 437 isc_mem_put(mctx, *ctrp, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t)); 438 *ctrp = NULL; 439 } 440