xref: /minix/external/bsd/bind/dist/lib/dns/stats.c (revision fb9c64b2)
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