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