xref: /netbsd-src/external/mpl/bind/dist/lib/dns/stats.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /*	$NetBSD: stats.c,v 1.5 2020/05/24 19:46:23 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <inttypes.h>
17 #include <stdbool.h>
18 
19 #include <isc/magic.h>
20 #include <isc/mem.h>
21 #include <isc/refcount.h>
22 #include <isc/stats.h>
23 #include <isc/util.h>
24 
25 #include <dns/log.h>
26 #include <dns/opcode.h>
27 #include <dns/rdatatype.h>
28 #include <dns/stats.h>
29 
30 #define DNS_STATS_MAGIC	   ISC_MAGIC('D', 's', 't', 't')
31 #define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC)
32 
33 /*%
34  * Statistics types.
35  */
36 typedef enum {
37 	dns_statstype_general = 0,
38 	dns_statstype_rdtype = 1,
39 	dns_statstype_rdataset = 2,
40 	dns_statstype_opcode = 3,
41 	dns_statstype_rcode = 4,
42 	dns_statstype_dnssec = 5
43 } dns_statstype_t;
44 
45 /*%
46  * It doesn't make sense to have 2^16 counters for all possible types since
47  * most of them won't be used.  We have counters for the first 256 types.
48  *
49  * A rdtypecounter is now 8 bits for RRtypes and 3 bits for flags:
50  *
51  *       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
52  *     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
53  *     |  |  |  |  |  |  S  |NX|         RRType        |
54  *     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
55  *
56  * If the 8 bits for RRtype are all zero, this is an Other RRtype.
57  */
58 #define RDTYPECOUNTER_MAXTYPE 0x00ff
59 
60 /*
61  *
62  * Bit 7 is the NXRRSET (NX) flag and indicates whether this is a
63  * positive (0) or a negative (1) RRset.
64  */
65 #define RDTYPECOUNTER_NXRRSET 0x0100
66 
67 /*
68  * Then bit 5 and 6 mostly tell you if this counter is for an active,
69  * stale, or ancient RRtype:
70  *
71  *     S = 0 (0b00) means Active
72  *     S = 1 (0b01) means Stale
73  *     S = 2 (0b10) means Ancient
74  *
75  * Since a counter cannot be stale and ancient at the same time, we
76  * treat S = 0x11 as a special case to deal with NXDOMAIN counters.
77  */
78 #define RDTYPECOUNTER_STALE    (1 << 9)
79 #define RDTYPECOUNTER_ANCIENT  (1 << 10)
80 #define RDTYPECOUNTER_NXDOMAIN ((1 << 9) | (1 << 10))
81 
82 /*
83  * S = 0x11 indicates an NXDOMAIN counter and in this case the RRtype
84  * field signals the expiry of this cached item:
85  *
86  *     RRType = 0 (0b00) means Active
87  *     RRType = 1 (0b01) means Stale
88  *     RRType = 2 (0b02) means Ancient
89  *
90  */
91 #define RDTYPECOUNTER_NXDOMAIN_STALE   1
92 #define RDTYPECOUNTER_NXDOMAIN_ANCIENT 2
93 
94 /*
95  * The maximum value for rdtypecounter is for an ancient NXDOMAIN.
96  */
97 #define RDTYPECOUNTER_MAXVAL 0x0602
98 
99 /*
100  * DNSSEC sign statistics.
101  *
102  * Per key we maintain 3 counters. The first is actually no counter but
103  * a key id reference. The second is the number of signatures the key created.
104  * The third is the number of signatures refreshed by the key.
105  */
106 
107 /* Maximum number of keys to keep track of for DNSSEC signing statistics. */
108 static int dnssecsign_max_keys = 4;
109 static int dnssecsign_block_size = 3;
110 /* Key id mask */
111 #define DNSSECSIGNSTATS_KEY_ID_MASK 0x0000FFFF
112 
113 struct dns_stats {
114 	unsigned int magic;
115 	dns_statstype_t type;
116 	isc_mem_t *mctx;
117 	isc_stats_t *counters;
118 	isc_refcount_t references;
119 };
120 
121 typedef struct rdatadumparg {
122 	dns_rdatatypestats_dumper_t fn;
123 	void *arg;
124 } rdatadumparg_t;
125 
126 typedef struct opcodedumparg {
127 	dns_opcodestats_dumper_t fn;
128 	void *arg;
129 } opcodedumparg_t;
130 
131 typedef struct rcodedumparg {
132 	dns_rcodestats_dumper_t fn;
133 	void *arg;
134 } rcodedumparg_t;
135 typedef struct dnssecsigndumparg {
136 	dns_dnssecsignstats_dumper_t fn;
137 	void *arg;
138 } dnssecsigndumparg_t;
139 
140 void
141 dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) {
142 	REQUIRE(DNS_STATS_VALID(stats));
143 	REQUIRE(statsp != NULL && *statsp == NULL);
144 
145 	isc_refcount_increment(&stats->references);
146 
147 	*statsp = stats;
148 }
149 
150 void
151 dns_stats_detach(dns_stats_t **statsp) {
152 	dns_stats_t *stats;
153 
154 	REQUIRE(statsp != NULL && DNS_STATS_VALID(*statsp));
155 
156 	stats = *statsp;
157 	*statsp = NULL;
158 
159 	if (isc_refcount_decrement(&stats->references) == 1) {
160 		isc_refcount_destroy(&stats->references);
161 		isc_stats_detach(&stats->counters);
162 		isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
163 	}
164 }
165 
166 /*%
167  * Create methods
168  */
169 static isc_result_t
170 create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters,
171 	     dns_stats_t **statsp) {
172 	dns_stats_t *stats;
173 	isc_result_t result;
174 
175 	stats = isc_mem_get(mctx, sizeof(*stats));
176 
177 	stats->counters = NULL;
178 	isc_refcount_init(&stats->references, 1);
179 
180 	result = isc_stats_create(mctx, &stats->counters, ncounters);
181 	if (result != ISC_R_SUCCESS) {
182 		goto clean_mutex;
183 	}
184 
185 	stats->magic = DNS_STATS_MAGIC;
186 	stats->type = type;
187 	stats->mctx = NULL;
188 	isc_mem_attach(mctx, &stats->mctx);
189 	*statsp = stats;
190 
191 	return (ISC_R_SUCCESS);
192 
193 clean_mutex:
194 	isc_mem_put(mctx, stats, sizeof(*stats));
195 
196 	return (result);
197 }
198 
199 isc_result_t
200 dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) {
201 	REQUIRE(statsp != NULL && *statsp == NULL);
202 
203 	return (create_stats(mctx, dns_statstype_general, ncounters, statsp));
204 }
205 
206 isc_result_t
207 dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
208 	REQUIRE(statsp != NULL && *statsp == NULL);
209 
210 	/*
211 	 * Create rdtype statistics for the first 255 RRtypes,
212 	 * plus one additional for other RRtypes.
213 	 */
214 	return (create_stats(mctx, dns_statstype_rdtype,
215 			     (RDTYPECOUNTER_MAXTYPE + 1), statsp));
216 }
217 
218 isc_result_t
219 dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
220 	REQUIRE(statsp != NULL && *statsp == NULL);
221 
222 	return (create_stats(mctx, dns_statstype_rdataset,
223 			     (RDTYPECOUNTER_MAXVAL + 1), statsp));
224 }
225 
226 isc_result_t
227 dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
228 	REQUIRE(statsp != NULL && *statsp == NULL);
229 
230 	return (create_stats(mctx, dns_statstype_opcode, 16, statsp));
231 }
232 
233 isc_result_t
234 dns_rcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
235 	REQUIRE(statsp != NULL && *statsp == NULL);
236 
237 	return (create_stats(mctx, dns_statstype_rcode, dns_rcode_badcookie + 1,
238 			     statsp));
239 }
240 
241 isc_result_t
242 dns_dnssecsignstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
243 	REQUIRE(statsp != NULL && *statsp == NULL);
244 
245 	/*
246 	 * Create two counters per key, one is the key id, the other two are
247 	 * the actual counters for creating and refreshing signatures.
248 	 */
249 	return (create_stats(mctx, dns_statstype_dnssec,
250 			     dnssecsign_max_keys * 3, statsp));
251 }
252 
253 /*%
254  * Increment/Decrement methods
255  */
256 void
257 dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter) {
258 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general);
259 
260 	isc_stats_increment(stats->counters, counter);
261 }
262 
263 inline static isc_statscounter_t
264 rdatatype2counter(dns_rdatatype_t type) {
265 	if (type > (dns_rdatatype_t)RDTYPECOUNTER_MAXTYPE) {
266 		return (0);
267 	}
268 	return ((isc_statscounter_t)type);
269 }
270 
271 void
272 dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) {
273 	isc_statscounter_t counter;
274 
275 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
276 
277 	counter = rdatatype2counter(type);
278 	isc_stats_increment(stats->counters, counter);
279 }
280 
281 static inline void
282 update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype,
283 		     bool increment) {
284 	isc_statscounter_t counter;
285 
286 	if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
287 	     DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0)
288 	{
289 		counter = RDTYPECOUNTER_NXDOMAIN;
290 
291 		/*
292 		 * This is an NXDOMAIN counter, save the expiry value
293 		 * (active, stale, or ancient) value in the RRtype part.
294 		 */
295 		if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
296 		     DNS_RDATASTATSTYPE_ATTR_ANCIENT) != 0) {
297 			counter |= RDTYPECOUNTER_NXDOMAIN_ANCIENT;
298 		} else if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
299 			    DNS_RDATASTATSTYPE_ATTR_STALE) != 0)
300 		{
301 			counter += RDTYPECOUNTER_NXDOMAIN_STALE;
302 		}
303 	} else {
304 		counter = rdatatype2counter(DNS_RDATASTATSTYPE_BASE(rrsettype));
305 
306 		if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
307 		     DNS_RDATASTATSTYPE_ATTR_NXRRSET) != 0) {
308 			counter |= RDTYPECOUNTER_NXRRSET;
309 		}
310 
311 		if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
312 		     DNS_RDATASTATSTYPE_ATTR_ANCIENT) != 0) {
313 			counter |= RDTYPECOUNTER_ANCIENT;
314 		} else if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
315 			    DNS_RDATASTATSTYPE_ATTR_STALE) != 0)
316 		{
317 			counter |= RDTYPECOUNTER_STALE;
318 		}
319 	}
320 
321 	if (increment) {
322 		isc_stats_increment(stats->counters, counter);
323 	} else {
324 		isc_stats_decrement(stats->counters, counter);
325 	}
326 }
327 
328 void
329 dns_rdatasetstats_increment(dns_stats_t *stats,
330 			    dns_rdatastatstype_t rrsettype) {
331 	REQUIRE(DNS_STATS_VALID(stats) &&
332 		stats->type == dns_statstype_rdataset);
333 
334 	update_rdatasetstats(stats, rrsettype, true);
335 }
336 
337 void
338 dns_rdatasetstats_decrement(dns_stats_t *stats,
339 			    dns_rdatastatstype_t rrsettype) {
340 	REQUIRE(DNS_STATS_VALID(stats) &&
341 		stats->type == dns_statstype_rdataset);
342 
343 	update_rdatasetstats(stats, rrsettype, false);
344 }
345 
346 void
347 dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) {
348 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
349 
350 	isc_stats_increment(stats->counters, (isc_statscounter_t)code);
351 }
352 
353 void
354 dns_rcodestats_increment(dns_stats_t *stats, dns_rcode_t code) {
355 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rcode);
356 
357 	if (code <= dns_rcode_badcookie) {
358 		isc_stats_increment(stats->counters, (isc_statscounter_t)code);
359 	}
360 }
361 
362 void
363 dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id, uint8_t alg,
364 			      dnssecsignstats_type_t operation) {
365 	uint32_t kval;
366 
367 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec);
368 
369 	/* Shift algorithm in front of key tag, which is 16 bits */
370 	kval = (uint32_t)(alg << 16 | id);
371 
372 	/* Look up correct counter. */
373 	for (int i = 0; i < dnssecsign_max_keys; i++) {
374 		int idx = i * dnssecsign_block_size;
375 		uint32_t counter = isc_stats_get_counter(stats->counters, idx);
376 		if (counter == kval) {
377 			/* Match */
378 			isc_stats_increment(stats->counters, (idx + operation));
379 			return;
380 		}
381 	}
382 
383 	/* No match found. Store key in unused slot. */
384 	for (int i = 0; i < dnssecsign_max_keys; i++) {
385 		int idx = i * dnssecsign_block_size;
386 		uint32_t counter = isc_stats_get_counter(stats->counters, idx);
387 		if (counter == 0) {
388 			isc_stats_set(stats->counters, kval, idx);
389 			isc_stats_increment(stats->counters, (idx + operation));
390 			return;
391 		}
392 	}
393 
394 	/* No room, rotate keys. */
395 	for (int i = 1; i < dnssecsign_max_keys; i++) {
396 		int gidx = i * dnssecsign_block_size; /* Get key (get index,
397 							 gidx) */
398 		uint32_t keyv = isc_stats_get_counter(stats->counters, gidx);
399 		uint32_t sign = isc_stats_get_counter(
400 			stats->counters, (gidx + dns_dnssecsignstats_sign));
401 		uint32_t refr = isc_stats_get_counter(
402 			stats->counters, (gidx + dns_dnssecsignstats_refresh));
403 
404 		int sidx = (i - 1) * dnssecsign_block_size; /* Set key, (set
405 							       index, sidx) */
406 		isc_stats_set(stats->counters, keyv, sidx);
407 		isc_stats_set(stats->counters, sign,
408 			      (sidx + dns_dnssecsignstats_sign));
409 		isc_stats_set(stats->counters, refr,
410 			      (sidx + dns_dnssecsignstats_refresh));
411 	}
412 
413 	/* Reset counters for new key (new index, nidx). */
414 	int nidx = (dnssecsign_max_keys - 1) * dnssecsign_block_size;
415 	isc_stats_set(stats->counters, kval, nidx);
416 	isc_stats_set(stats->counters, 0, (nidx + dns_dnssecsignstats_sign));
417 	isc_stats_set(stats->counters, 0, (nidx + dns_dnssecsignstats_refresh));
418 
419 	/* And increment the counter for the given operation. */
420 	isc_stats_increment(stats->counters, (nidx + operation));
421 }
422 
423 /*%
424  * Dump methods
425  */
426 void
427 dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn,
428 		      void *arg, unsigned int options) {
429 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general);
430 
431 	isc_stats_dump(stats->counters, (isc_stats_dumper_t)dump_fn, arg,
432 		       options);
433 }
434 
435 static void
436 dump_rdentry(int rdcounter, uint64_t value, dns_rdatastatstype_t attributes,
437 	     dns_rdatatypestats_dumper_t dump_fn, void *arg) {
438 	dns_rdatatype_t rdtype = dns_rdatatype_none; /* sentinel */
439 	dns_rdatastatstype_t type;
440 
441 	if ((rdcounter & RDTYPECOUNTER_MAXTYPE) == 0) {
442 		attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE;
443 	} else {
444 		rdtype = (dns_rdatatype_t)(rdcounter & RDTYPECOUNTER_MAXTYPE);
445 	}
446 	type = DNS_RDATASTATSTYPE_VALUE((dns_rdatastatstype_t)rdtype,
447 					attributes);
448 	dump_fn(type, value, arg);
449 }
450 
451 static void
452 rdatatype_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
453 	rdatadumparg_t *rdatadumparg = arg;
454 
455 	dump_rdentry(counter, value, 0, rdatadumparg->fn, rdatadumparg->arg);
456 }
457 
458 void
459 dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
460 			void *arg0, unsigned int options) {
461 	rdatadumparg_t arg;
462 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
463 
464 	arg.fn = dump_fn;
465 	arg.arg = arg0;
466 	isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options);
467 }
468 
469 static void
470 rdataset_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
471 	rdatadumparg_t *rdatadumparg = arg;
472 	unsigned int attributes = 0;
473 
474 	if ((counter & RDTYPECOUNTER_NXDOMAIN) == RDTYPECOUNTER_NXDOMAIN) {
475 		attributes |= DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
476 
477 		/*
478 		 * This is an NXDOMAIN counter, check the RRtype part for the
479 		 * expiry value (active, stale, or ancient).
480 		 */
481 		if ((counter & RDTYPECOUNTER_MAXTYPE) ==
482 		    RDTYPECOUNTER_NXDOMAIN_STALE) {
483 			attributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
484 		} else if ((counter & RDTYPECOUNTER_MAXTYPE) ==
485 			   RDTYPECOUNTER_NXDOMAIN_ANCIENT) {
486 			attributes |= DNS_RDATASTATSTYPE_ATTR_ANCIENT;
487 		}
488 	} else {
489 		if ((counter & RDTYPECOUNTER_MAXTYPE) == 0) {
490 			attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE;
491 		}
492 		if ((counter & RDTYPECOUNTER_NXRRSET) != 0) {
493 			attributes |= DNS_RDATASTATSTYPE_ATTR_NXRRSET;
494 		}
495 
496 		if ((counter & RDTYPECOUNTER_STALE) != 0) {
497 			attributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
498 		} else if ((counter & RDTYPECOUNTER_ANCIENT) != 0) {
499 			attributes |= DNS_RDATASTATSTYPE_ATTR_ANCIENT;
500 		}
501 	}
502 
503 	dump_rdentry(counter, value, attributes, rdatadumparg->fn,
504 		     rdatadumparg->arg);
505 }
506 
507 void
508 dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
509 		       void *arg0, unsigned int options) {
510 	rdatadumparg_t arg;
511 
512 	REQUIRE(DNS_STATS_VALID(stats) &&
513 		stats->type == dns_statstype_rdataset);
514 
515 	arg.fn = dump_fn;
516 	arg.arg = arg0;
517 	isc_stats_dump(stats->counters, rdataset_dumpcb, &arg, options);
518 }
519 
520 static void
521 dnssec_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
522 	dnssecsigndumparg_t *dnssecarg = arg;
523 
524 	dnssecarg->fn((dns_keytag_t)counter, value, dnssecarg->arg);
525 }
526 
527 static void
528 dnssec_statsdump(isc_stats_t *stats, dnssecsignstats_type_t operation,
529 		 isc_stats_dumper_t dump_fn, void *arg, unsigned int options) {
530 	int i;
531 
532 	for (i = 0; i < dnssecsign_max_keys; i++) {
533 		int idx = dnssecsign_block_size * i;
534 		uint32_t kval, val;
535 		dns_keytag_t id;
536 
537 		kval = isc_stats_get_counter(stats, idx);
538 		if (kval == 0) {
539 			continue;
540 		}
541 
542 		val = isc_stats_get_counter(stats, (idx + operation));
543 		if ((options & ISC_STATSDUMP_VERBOSE) == 0 && val == 0) {
544 			continue;
545 		}
546 
547 		id = (dns_keytag_t)kval & DNSSECSIGNSTATS_KEY_ID_MASK;
548 
549 		dump_fn((isc_statscounter_t)id, val, arg);
550 	}
551 }
552 
553 void
554 dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation,
555 			 dns_dnssecsignstats_dumper_t dump_fn, void *arg0,
556 			 unsigned int options) {
557 	dnssecsigndumparg_t arg;
558 
559 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec);
560 
561 	arg.fn = dump_fn;
562 	arg.arg = arg0;
563 
564 	dnssec_statsdump(stats->counters, operation, dnssec_dumpcb, &arg,
565 			 options);
566 }
567 
568 static void
569 opcode_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
570 	opcodedumparg_t *opcodearg = arg;
571 
572 	opcodearg->fn((dns_opcode_t)counter, value, opcodearg->arg);
573 }
574 
575 static void
576 rcode_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
577 	rcodedumparg_t *rcodearg = arg;
578 
579 	rcodearg->fn((dns_rcode_t)counter, value, rcodearg->arg);
580 }
581 
582 void
583 dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn,
584 		     void *arg0, unsigned int options) {
585 	opcodedumparg_t arg;
586 
587 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
588 
589 	arg.fn = dump_fn;
590 	arg.arg = arg0;
591 	isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options);
592 }
593 
594 void
595 dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn,
596 		    void *arg0, unsigned int options) {
597 	rcodedumparg_t arg;
598 
599 	REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rcode);
600 
601 	arg.fn = dump_fn;
602 	arg.arg = arg0;
603 	isc_stats_dump(stats->counters, rcode_dumpcb, &arg, options);
604 }
605 
606 /***
607  *** Obsolete variables and functions follow:
608  ***/
609 LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] = {
610 	"success",   "referral", "nxrrset",   "nxdomain",
611 	"recursion", "failure",	 "duplicate", "dropped"
612 };
613 
614 isc_result_t
615 dns_stats_alloccounters(isc_mem_t *mctx, uint64_t **ctrp) {
616 	int i;
617 	uint64_t *p = isc_mem_get(mctx, DNS_STATS_NCOUNTERS * sizeof(uint64_t));
618 	if (p == NULL) {
619 		return (ISC_R_NOMEMORY);
620 	}
621 	for (i = 0; i < DNS_STATS_NCOUNTERS; i++) {
622 		p[i] = 0;
623 	}
624 	*ctrp = p;
625 	return (ISC_R_SUCCESS);
626 }
627 
628 void
629 dns_stats_freecounters(isc_mem_t *mctx, uint64_t **ctrp) {
630 	isc_mem_put(mctx, *ctrp, DNS_STATS_NCOUNTERS * sizeof(uint64_t));
631 	*ctrp = NULL;
632 }
633