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