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
dns_stats_attach(dns_stats_t * stats,dns_stats_t ** statsp)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
dns_stats_detach(dns_stats_t ** statsp)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
create_stats(isc_mem_t * mctx,dns_statstype_t type,int ncounters,dns_stats_t ** statsp)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
dns_generalstats_create(isc_mem_t * mctx,dns_stats_t ** statsp,int ncounters)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
dns_rdatatypestats_create(isc_mem_t * mctx,dns_stats_t ** statsp)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
dns_rdatasetstats_create(isc_mem_t * mctx,dns_stats_t ** statsp)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
dns_opcodestats_create(isc_mem_t * mctx,dns_stats_t ** statsp)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
dns_generalstats_increment(dns_stats_t * stats,isc_statscounter_t counter)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
dns_rdatatypestats_increment(dns_stats_t * stats,dns_rdatatype_t type)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
update_rdatasetstats(dns_stats_t * stats,dns_rdatastatstype_t rrsettype,isc_boolean_t increment)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
dns_rdatasetstats_increment(dns_stats_t * stats,dns_rdatastatstype_t rrsettype)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
dns_rdatasetstats_decrement(dns_stats_t * stats,dns_rdatastatstype_t rrsettype)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
dns_opcodestats_increment(dns_stats_t * stats,dns_opcode_t code)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
dns_generalstats_dump(dns_stats_t * stats,dns_generalstats_dumper_t dump_fn,void * arg,unsigned int options)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
dump_rdentry(int rdcounter,isc_uint64_t value,dns_rdatastatstype_t attributes,dns_rdatatypestats_dumper_t dump_fn,void * arg)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
rdatatype_dumpcb(isc_statscounter_t counter,isc_uint64_t value,void * arg)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
dns_rdatatypestats_dump(dns_stats_t * stats,dns_rdatatypestats_dumper_t dump_fn,void * arg0,unsigned int options)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
rdataset_dumpcb(isc_statscounter_t counter,isc_uint64_t value,void * arg)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
dns_rdatasetstats_dump(dns_stats_t * stats,dns_rdatatypestats_dumper_t dump_fn,void * arg0,unsigned int options)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
opcode_dumpcb(isc_statscounter_t counter,isc_uint64_t value,void * arg)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
dns_opcodestats_dump(dns_stats_t * stats,dns_opcodestats_dumper_t dump_fn,void * arg0,unsigned int options)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
dns_stats_alloccounters(isc_mem_t * mctx,isc_uint64_t ** ctrp)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
dns_stats_freecounters(isc_mem_t * mctx,isc_uint64_t ** ctrp)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