/contrib/bind9/lib/dns/stats.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 404 lines · 287 code · 73 blank · 44 comment · 66 complexity · 3839dea1113b86c580699842d0b501f9 MD5 · raw file

  1. /*
  2. * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
  3. * Copyright (C) 2000, 2001 Internet Software Consortium.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. * PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* $Id: stats.c,v 1.18 2009/01/27 23:47:54 tbox Exp $ */
  18. /*! \file */
  19. #include <config.h>
  20. #include <isc/magic.h>
  21. #include <isc/mem.h>
  22. #include <isc/stats.h>
  23. #include <isc/util.h>
  24. #include <dns/opcode.h>
  25. #include <dns/rdatatype.h>
  26. #include <dns/stats.h>
  27. #define DNS_STATS_MAGIC ISC_MAGIC('D', 's', 't', 't')
  28. #define DNS_STATS_VALID(x) ISC_MAGIC_VALID(x, DNS_STATS_MAGIC)
  29. /*%
  30. * Statistics types.
  31. */
  32. typedef enum {
  33. dns_statstype_general = 0,
  34. dns_statstype_rdtype = 1,
  35. dns_statstype_rdataset = 2,
  36. dns_statstype_opcode = 3
  37. } dns_statstype_t;
  38. /*%
  39. * It doesn't make sense to have 2^16 counters for all possible types since
  40. * most of them won't be used. We have counters for the first 256 types and
  41. * those explicitly supported in the rdata implementation.
  42. * XXXJT: this introduces tight coupling with the rdata implementation.
  43. * Ideally, we should have rdata handle this type of details.
  44. */
  45. enum {
  46. /* For 0-255, we use the rdtype value as counter indices */
  47. rdtypecounter_dlv = 256, /* for dns_rdatatype_dlv */
  48. rdtypecounter_others = 257, /* anything else */
  49. rdtypecounter_max = 258,
  50. /* The following are used for rdataset */
  51. rdtypenxcounter_max = rdtypecounter_max * 2,
  52. rdtypecounter_nxdomain = rdtypenxcounter_max,
  53. rdatasettypecounter_max = rdtypecounter_nxdomain + 1
  54. };
  55. struct dns_stats {
  56. /*% Unlocked */
  57. unsigned int magic;
  58. dns_statstype_t type;
  59. isc_mem_t *mctx;
  60. isc_mutex_t lock;
  61. isc_stats_t *counters;
  62. /*% Locked by lock */
  63. unsigned int references;
  64. };
  65. typedef struct rdatadumparg {
  66. dns_rdatatypestats_dumper_t fn;
  67. void *arg;
  68. } rdatadumparg_t;
  69. typedef struct opcodedumparg {
  70. dns_opcodestats_dumper_t fn;
  71. void *arg;
  72. } opcodedumparg_t;
  73. void
  74. dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp) {
  75. REQUIRE(DNS_STATS_VALID(stats));
  76. REQUIRE(statsp != NULL && *statsp == NULL);
  77. LOCK(&stats->lock);
  78. stats->references++;
  79. UNLOCK(&stats->lock);
  80. *statsp = stats;
  81. }
  82. void
  83. dns_stats_detach(dns_stats_t **statsp) {
  84. dns_stats_t *stats;
  85. REQUIRE(statsp != NULL && DNS_STATS_VALID(*statsp));
  86. stats = *statsp;
  87. *statsp = NULL;
  88. LOCK(&stats->lock);
  89. stats->references--;
  90. UNLOCK(&stats->lock);
  91. if (stats->references == 0) {
  92. isc_stats_detach(&stats->counters);
  93. DESTROYLOCK(&stats->lock);
  94. isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
  95. }
  96. }
  97. /*%
  98. * Create methods
  99. */
  100. static isc_result_t
  101. create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters,
  102. dns_stats_t **statsp)
  103. {
  104. dns_stats_t *stats;
  105. isc_result_t result;
  106. stats = isc_mem_get(mctx, sizeof(*stats));
  107. if (stats == NULL)
  108. return (ISC_R_NOMEMORY);
  109. stats->counters = NULL;
  110. stats->references = 1;
  111. result = isc_mutex_init(&stats->lock);
  112. if (result != ISC_R_SUCCESS)
  113. goto clean_stats;
  114. result = isc_stats_create(mctx, &stats->counters, ncounters);
  115. if (result != ISC_R_SUCCESS)
  116. goto clean_mutex;
  117. stats->magic = DNS_STATS_MAGIC;
  118. stats->type = type;
  119. stats->mctx = NULL;
  120. isc_mem_attach(mctx, &stats->mctx);
  121. *statsp = stats;
  122. return (ISC_R_SUCCESS);
  123. clean_mutex:
  124. DESTROYLOCK(&stats->lock);
  125. clean_stats:
  126. isc_mem_put(mctx, stats, sizeof(*stats));
  127. return (result);
  128. }
  129. isc_result_t
  130. dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) {
  131. REQUIRE(statsp != NULL && *statsp == NULL);
  132. return (create_stats(mctx, dns_statstype_general, ncounters, statsp));
  133. }
  134. isc_result_t
  135. dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
  136. REQUIRE(statsp != NULL && *statsp == NULL);
  137. return (create_stats(mctx, dns_statstype_rdtype, rdtypecounter_max,
  138. statsp));
  139. }
  140. isc_result_t
  141. dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
  142. REQUIRE(statsp != NULL && *statsp == NULL);
  143. return (create_stats(mctx, dns_statstype_rdataset,
  144. (rdtypecounter_max * 2) + 1, statsp));
  145. }
  146. isc_result_t
  147. dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
  148. REQUIRE(statsp != NULL && *statsp == NULL);
  149. return (create_stats(mctx, dns_statstype_opcode, 16, statsp));
  150. }
  151. /*%
  152. * Increment/Decrement methods
  153. */
  154. void
  155. dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter) {
  156. REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general);
  157. isc_stats_increment(stats->counters, counter);
  158. }
  159. void
  160. dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) {
  161. int counter;
  162. REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
  163. if (type == dns_rdatatype_dlv)
  164. counter = rdtypecounter_dlv;
  165. else if (type > dns_rdatatype_any)
  166. counter = rdtypecounter_others;
  167. else
  168. counter = (int)type;
  169. isc_stats_increment(stats->counters, (isc_statscounter_t)counter);
  170. }
  171. static inline void
  172. update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype,
  173. isc_boolean_t increment)
  174. {
  175. int counter;
  176. dns_rdatatype_t rdtype;
  177. if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
  178. DNS_RDATASTATSTYPE_ATTR_NXDOMAIN) != 0) {
  179. counter = rdtypecounter_nxdomain;
  180. } else {
  181. rdtype = DNS_RDATASTATSTYPE_BASE(rrsettype);
  182. if (rdtype == dns_rdatatype_dlv)
  183. counter = (int)rdtypecounter_dlv;
  184. else if (rdtype > dns_rdatatype_any)
  185. counter = (int)rdtypecounter_others;
  186. else
  187. counter = (int)rdtype;
  188. if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
  189. DNS_RDATASTATSTYPE_ATTR_NXRRSET) != 0)
  190. counter += rdtypecounter_max;
  191. }
  192. if (increment)
  193. isc_stats_increment(stats->counters, counter);
  194. else
  195. isc_stats_decrement(stats->counters, counter);
  196. }
  197. void
  198. dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype)
  199. {
  200. REQUIRE(DNS_STATS_VALID(stats) &&
  201. stats->type == dns_statstype_rdataset);
  202. update_rdatasetstats(stats, rrsettype, ISC_TRUE);
  203. }
  204. void
  205. dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype)
  206. {
  207. REQUIRE(DNS_STATS_VALID(stats) &&
  208. stats->type == dns_statstype_rdataset);
  209. update_rdatasetstats(stats, rrsettype, ISC_FALSE);
  210. }
  211. void
  212. dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) {
  213. REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
  214. isc_stats_increment(stats->counters, (isc_statscounter_t)code);
  215. }
  216. /*%
  217. * Dump methods
  218. */
  219. void
  220. dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn,
  221. void *arg, unsigned int options)
  222. {
  223. REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_general);
  224. isc_stats_dump(stats->counters, (isc_stats_dumper_t)dump_fn,
  225. arg, options);
  226. }
  227. static void
  228. dump_rdentry(int rdcounter, isc_uint64_t value, dns_rdatastatstype_t attributes,
  229. dns_rdatatypestats_dumper_t dump_fn, void * arg)
  230. {
  231. dns_rdatatype_t rdtype = dns_rdatatype_none; /* sentinel */
  232. dns_rdatastatstype_t type;
  233. if (rdcounter == rdtypecounter_others)
  234. attributes |= DNS_RDATASTATSTYPE_ATTR_OTHERTYPE;
  235. else {
  236. if (rdcounter == rdtypecounter_dlv)
  237. rdtype = dns_rdatatype_dlv;
  238. else
  239. rdtype = (dns_rdatatype_t)rdcounter;
  240. }
  241. type = DNS_RDATASTATSTYPE_VALUE((dns_rdatastatstype_t)rdtype,
  242. attributes);
  243. dump_fn(type, value, arg);
  244. }
  245. static void
  246. rdatatype_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) {
  247. rdatadumparg_t *rdatadumparg = arg;
  248. dump_rdentry(counter, value, 0, rdatadumparg->fn, rdatadumparg->arg);
  249. }
  250. void
  251. dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
  252. void *arg0, unsigned int options)
  253. {
  254. rdatadumparg_t arg;
  255. REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
  256. arg.fn = dump_fn;
  257. arg.arg = arg0;
  258. isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options);
  259. }
  260. static void
  261. rdataset_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) {
  262. rdatadumparg_t *rdatadumparg = arg;
  263. if (counter < rdtypecounter_max) {
  264. dump_rdentry(counter, value, 0, rdatadumparg->fn,
  265. rdatadumparg->arg);
  266. } else if (counter < rdtypenxcounter_max) {
  267. dump_rdentry(counter - rdtypecounter_max, value,
  268. DNS_RDATASTATSTYPE_ATTR_NXRRSET,
  269. rdatadumparg->fn, rdatadumparg->arg);
  270. } else {
  271. dump_rdentry(0, value, DNS_RDATASTATSTYPE_ATTR_NXDOMAIN,
  272. rdatadumparg->fn, rdatadumparg->arg);
  273. }
  274. }
  275. void
  276. dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
  277. void *arg0, unsigned int options)
  278. {
  279. rdatadumparg_t arg;
  280. REQUIRE(DNS_STATS_VALID(stats) &&
  281. stats->type == dns_statstype_rdataset);
  282. arg.fn = dump_fn;
  283. arg.arg = arg0;
  284. isc_stats_dump(stats->counters, rdataset_dumpcb, &arg, options);
  285. }
  286. static void
  287. opcode_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) {
  288. opcodedumparg_t *opcodearg = arg;
  289. opcodearg->fn((dns_opcode_t)counter, value, opcodearg->arg);
  290. }
  291. void
  292. dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn,
  293. void *arg0, unsigned int options)
  294. {
  295. opcodedumparg_t arg;
  296. REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
  297. arg.fn = dump_fn;
  298. arg.arg = arg0;
  299. isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options);
  300. }
  301. /***
  302. *** Obsolete variables and functions follow:
  303. ***/
  304. LIBDNS_EXTERNAL_DATA const char *dns_statscounter_names[DNS_STATS_NCOUNTERS] =
  305. {
  306. "success",
  307. "referral",
  308. "nxrrset",
  309. "nxdomain",
  310. "recursion",
  311. "failure",
  312. "duplicate",
  313. "dropped"
  314. };
  315. isc_result_t
  316. dns_stats_alloccounters(isc_mem_t *mctx, isc_uint64_t **ctrp) {
  317. int i;
  318. isc_uint64_t *p =
  319. isc_mem_get(mctx, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t));
  320. if (p == NULL)
  321. return (ISC_R_NOMEMORY);
  322. for (i = 0; i < DNS_STATS_NCOUNTERS; i++)
  323. p[i] = 0;
  324. *ctrp = p;
  325. return (ISC_R_SUCCESS);
  326. }
  327. void
  328. dns_stats_freecounters(isc_mem_t *mctx, isc_uint64_t **ctrp) {
  329. isc_mem_put(mctx, *ctrp, DNS_STATS_NCOUNTERS * sizeof(isc_uint64_t));
  330. *ctrp = NULL;
  331. }