00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/magic.h>
00025 #include <isc/mem.h>
00026 #include <isc/stats.h>
00027 #include <isc/util.h>
00028
00029 #include <dns/opcode.h>
00030 #include <dns/rdatatype.h>
00031 #include <dns/stats.h>
00032
00033 #define DNS_STATS_MAGIC ISC_MAGIC('D', 's', 't', 't')
00034 #define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC)
00035
00036
00037
00038
00039 typedef enum {
00040 dns_statstype_general = 0,
00041 dns_statstype_rdtype = 1,
00042 dns_statstype_rdataset = 2,
00043 dns_statstype_opcode = 3
00044 } dns_statstype_t;
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 enum {
00057
00058 rdtypecounter_dlv = 256,
00059 rdtypecounter_others = 257,
00060 rdtypecounter_max = 258,
00061
00062 rdtypenxcounter_max = rdtypecounter_max * 2,
00063 rdtypecounter_nxdomain = rdtypenxcounter_max,
00064
00065 rdtypecounter_stale = rdtypecounter_nxdomain + 1,
00066 rdatasettypecounter_max = rdtypecounter_stale * 2
00067 };
00068
00069 struct dns_stats {
00070
00071 unsigned int magic;
00072 dns_statstype_t type;
00073 isc_mem_t *mctx;
00074 isc_mutex_t lock;
00075 isc_stats_t *counters;
00076
00077
00078 unsigned int references;
00079 };
00080
00081 typedef struct rdatadumparg {
00082 dns_rdatatypestats_dumper_t fn;
00083 void *arg;
00084 } rdatadumparg_t;
00085
00086 typedef struct opcodedumparg {
00087 dns_opcodestats_dumper_t fn;
00088 void *arg;
00089 } opcodedumparg_t;
00090
00091 void
00092 dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) {
00093 REQUIRE(DNS_STATS_VALID(stats));
00094 REQUIRE(statsp != NULL && *statsp == NULL);
00095
00096 LOCK(&stats->lock);
00097 stats->references++;
00098 UNLOCK(&stats->lock);
00099
00100 *statsp = stats;
00101 }
00102
00103 void
00104 dns_stats_detach(dns_stats_t **statsp) {
00105 dns_stats_t *stats;
00106
00107 REQUIRE(statsp != NULL && DNS_STATS_VALID(*statsp));
00108
00109 stats = *statsp;
00110 *statsp = NULL;
00111
00112 LOCK(&stats->lock);
00113 stats->references--;
00114 UNLOCK(&stats->lock);
00115
00116 if (stats->references == 0) {
00117 isc_stats_detach(&stats->counters);
00118 DESTROYLOCK(&stats->lock);
00119 isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
00120 }
00121 }
00122
00123
00124
00125
00126 static isc_result_t
00127 create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters,
00128 dns_stats_t **statsp)
00129 {
00130 dns_stats_t *stats;
00131 isc_result_t result;
00132
00133 stats = isc_mem_get(mctx, sizeof(*stats));
00134 if (stats == NULL)
00135 return (ISC_R_NOMEMORY);
00136
00137 stats->counters = NULL;
00138 stats->references = 1;
00139
00140 result = isc_mutex_init(&stats->lock);
00141 if (result != ISC_R_SUCCESS)
00142 goto clean_stats;
00143
00144 result = isc_stats_create(mctx, &stats->counters, ncounters);
00145 if (result != ISC_R_SUCCESS)
00146 goto clean_mutex;
00147
00148 stats->magic = DNS_STATS_MAGIC;
00149 stats->type = type;
00150 stats->mctx = NULL;
00151 isc_mem_attach(mctx, &stats->mctx);
00152 *statsp = stats;
00153
00154 return (ISC_R_SUCCESS);
00155
00156 clean_mutex:
00157 DESTROYLOCK(&stats->lock);
00158 clean_stats:
00159 isc_mem_put(mctx, stats, sizeof(*stats));
00160
00161 return (result);
00162 }
00163
00164 isc_result_t
00165 dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) {
00166 REQUIRE(statsp != NULL && *statsp == NULL);
00167
00168 return (create_stats(mctx, dns_statstype_general, ncounters, statsp));
00169 }
00170
00171 isc_result_t
00172 dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
00173 REQUIRE(statsp != NULL && *statsp == NULL);
00174
00175 return (create_stats(mctx, dns_statstype_rdtype, rdtypecounter_max,
00176 statsp));
00177 }
00178
00179 isc_result_t
00180 dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
00181 REQUIRE(statsp != NULL && *statsp == NULL);
00182
00183 return (create_stats(mctx, dns_statstype_rdataset,
00184 rdatasettypecounter_max, statsp));
00185 }
00186
00187 isc_result_t
00188 dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
00189 REQUIRE(statsp != NULL && *statsp == NULL);
00190
00191 return (create_stats(mctx, dns_statstype_opcode, 16, statsp));
00192 }
00193
00194
00195
00196
00197 void
00198 dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter) {
00199 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general);
00200
00201 isc_stats_increment(stats->counters, counter);
00202 }
00203
00204 void
00205 dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) {
00206 int counter;
00207
00208 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
00209
00210 if (type == dns_rdatatype_dlv)
00211 counter = rdtypecounter_dlv;
00212 else if (type > dns_rdatatype_any)
00213 counter = rdtypecounter_others;
00214 else
00215 counter = (int)type;
00216
00217 isc_stats_increment(stats->counters, (isc_statscounter_t)counter);
00218 }
00219
00220 static inline void
00221 update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype,
00222 isc_boolean_t increment)
00223 {
00224 int counter;
00225 dns_rdatatype_t rdtype;
00226
00227 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
00228 DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) {
00229 counter = rdtypecounter_nxdomain;
00230 } else {
00231 rdtype = DNS_RDATASTATSTYPE_BASE(rrsettype);
00232 if (rdtype == dns_rdatatype_dlv)
00233 counter = (int)rdtypecounter_dlv;
00234 else if (rdtype > dns_rdatatype_any)
00235 counter = (int)rdtypecounter_others;
00236 else
00237 counter = (int)rdtype;
00238
00239 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
00240 DNS_RDATASTATSTYPE_ATTR_NXRRSET) != 0)
00241 counter += rdtypecounter_max;
00242 }
00243
00244 if (increment) {
00245 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
00246 DNS_RDATASTATSTYPE_ATTR_STALE) != 0) {
00247 isc_stats_decrement(stats->counters, counter);
00248 counter += rdtypecounter_stale;
00249 }
00250 isc_stats_increment(stats->counters, counter);
00251 } else {
00252 if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
00253 DNS_RDATASTATSTYPE_ATTR_STALE) != 0)
00254 counter += rdtypecounter_stale;
00255 isc_stats_decrement(stats->counters, counter);
00256 }
00257 }
00258
00259 void
00260 dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype)
00261 {
00262 REQUIRE(DNS_STATS_VALID(stats) &&
00263 stats->type == dns_statstype_rdataset);
00264
00265 update_rdatasetstats(stats, rrsettype, ISC_TRUE);
00266 }
00267
00268 void
00269 dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype)
00270 {
00271 REQUIRE(DNS_STATS_VALID(stats) &&
00272 stats->type == dns_statstype_rdataset);
00273
00274 update_rdatasetstats(stats, rrsettype, ISC_FALSE);
00275 }
00276
00277 void
00278 dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) {
00279 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
00280
00281 isc_stats_increment(stats->counters, (isc_statscounter_t)code);
00282 }
00283
00284
00285
00286
00287 void
00288 dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn,
00289 void *arg, unsigned int options)
00290 {
00291 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general);
00292
00293 isc_stats_dump(stats->counters, (isc_stats_dumper_t)dump_fn,
00294 arg, options);
00295 }
00296
00297 static void
00298 dump_rdentry(int rdcounter, isc_uint64_t value, dns_rdatastatstype_t attributes,
00299 dns_rdatatypestats_dumper_t dump_fn, void * arg)
00300 {
00301 dns_rdatatype_t rdtype = dns_rdatatype_none;
00302 dns_rdatastatstype_t type;
00303
00304 if (rdcounter == rdtypecounter_others)
00305 attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE;
00306 else {
00307 if (rdcounter == rdtypecounter_dlv)
00308 rdtype = dns_rdatatype_dlv;
00309 else
00310 rdtype = (dns_rdatatype_t)rdcounter;
00311 }
00312 type = DNS_RDATASTATSTYPE_VALUE((dns_rdatastatstype_t)rdtype,
00313 attributes);
00314 dump_fn(type, value, arg);
00315 }
00316
00317 static void
00318 rdatatype_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) {
00319 rdatadumparg_t *rdatadumparg = arg;
00320
00321 dump_rdentry(counter, value, 0, rdatadumparg->fn, rdatadumparg->arg);
00322 }
00323
00324 void
00325 dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
00326 void *arg0, unsigned int options)
00327 {
00328 rdatadumparg_t arg;
00329 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
00330
00331 arg.fn = dump_fn;
00332 arg.arg = arg0;
00333 isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options);
00334 }
00335
00336 static void
00337 rdataset_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) {
00338 rdatadumparg_t *rdatadumparg = arg;
00339 unsigned int attributes;
00340
00341 if (counter < rdtypecounter_max) {
00342 dump_rdentry(counter, value, 0, rdatadumparg->fn,
00343 rdatadumparg->arg);
00344 } else if (counter < rdtypecounter_nxdomain) {
00345 counter -= rdtypecounter_max;
00346 attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
00347 dump_rdentry(counter, value, attributes, rdatadumparg->fn,
00348 rdatadumparg->arg);
00349 } else if (counter == rdtypecounter_nxdomain) {
00350 dump_rdentry(0, value, DNS_RDATASTATSTYPE_ATTR_NXDOMAIN,
00351 rdatadumparg->fn, rdatadumparg->arg);
00352 } else if (counter < rdtypecounter_stale + rdtypecounter_max) {
00353 counter -= rdtypecounter_stale;
00354 attributes = DNS_RDATASTATSTYPE_ATTR_STALE;
00355 dump_rdentry(counter, value, attributes, rdatadumparg->fn,
00356 rdatadumparg->arg);
00357 } else if (counter < rdtypecounter_stale + rdtypecounter_nxdomain) {
00358 counter -= rdtypecounter_stale + rdtypecounter_max;
00359 attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET |
00360 DNS_RDATASTATSTYPE_ATTR_STALE;
00361 dump_rdentry(counter, value, attributes, rdatadumparg->fn,
00362 rdatadumparg->arg);
00363 } else {
00364 attributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN |
00365 DNS_RDATASTATSTYPE_ATTR_STALE;
00366 dump_rdentry(0, value, attributes, rdatadumparg->fn,
00367 rdatadumparg->arg);
00368 }
00369 }
00370
00371 void
00372 dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
00373 void *arg0, unsigned int options)
00374 {
00375 rdatadumparg_t arg;
00376
00377 REQUIRE(DNS_STATS_VALID(stats) &&
00378 stats->type == dns_statstype_rdataset);
00379
00380 arg.fn = dump_fn;
00381 arg.arg = arg0;
00382 isc_stats_dump(stats->counters, rdataset_dumpcb, &arg, options);
00383 }
00384
00385 static void
00386 opcode_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) {
00387 opcodedumparg_t *opcodearg = arg;
00388
00389 opcodearg->fn((dns_opcode_t)counter, value, opcodearg->arg);
00390 }
00391
00392 void
00393 dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn,
00394 void *arg0, unsigned int options)
00395 {
00396 opcodedumparg_t arg;
00397
00398 REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
00399
00400 arg.fn = dump_fn;
00401 arg.arg = arg0;
00402 isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options);
00403 }
00404
00405
00406
00407
00408 LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] =
00409 {
00410 "success",
00411 "referral",
00412 "nxrrset",
00413 "nxdomain",
00414 "recursion",
00415 "failure",
00416 "duplicate",
00417 "dropped"
00418 };
00419
00420 isc_result_t
00421 dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp) {
00422 int i;
00423 isc_uint64_t *p =
00424 isc_mem_get(mctx, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t));
00425 if (p == NULL)
00426 return (ISC_R_NOMEMORY);
00427 for (i = 0; i < DNS_STATS_NCOUNTERS; i++)
00428 p[i] = 0;
00429 *ctrp = p;
00430 return (ISC_R_SUCCESS);
00431 }
00432
00433 void
00434 dns_stats_freecounters(isc_mem_t *mctx, isc_uint64_t **ctrp) {
00435 isc_mem_put(mctx, *ctrp, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t));
00436 *ctrp = NULL;
00437 }