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