diff options
author | sthen <sthen@openbsd.org> | 2013-11-26 12:50:10 +0000 |
---|---|---|
committer | sthen <sthen@openbsd.org> | 2013-11-26 12:50:10 +0000 |
commit | d3fecca9f63d975339880ea9da999a59fc9dbfdc (patch) | |
tree | 77f0767482483e7b94040f328076abf2e3d85323 /usr.sbin/nsd/nsd-mem.c | |
parent | - put -Q in the right place (diff) | |
download | wireguard-openbsd-d3fecca9f63d975339880ea9da999a59fc9dbfdc.tar.xz wireguard-openbsd-d3fecca9f63d975339880ea9da999a59fc9dbfdc.zip |
import NSD 4.0.0, tests from Dorian Büttner, Patrik Lundin, requested by brad@
Diffstat (limited to 'usr.sbin/nsd/nsd-mem.c')
-rw-r--r-- | usr.sbin/nsd/nsd-mem.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/usr.sbin/nsd/nsd-mem.c b/usr.sbin/nsd/nsd-mem.c new file mode 100644 index 00000000000..0981eafef73 --- /dev/null +++ b/usr.sbin/nsd/nsd-mem.c @@ -0,0 +1,360 @@ +/* + * nsd-mem.c -- nsd-mem(8) + * + * Copyright (c) 2013, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + * + */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> + +#include "nsd.h" +#include "tsig.h" +#include "options.h" +#include "namedb.h" +#include "udb.h" +#include "udbzone.h" +#include "util.h" + +static void error(const char *format, ...) ATTR_FORMAT(printf, 1, 2); + +/* + * Print the help text. + * + */ +static void +usage (void) +{ + fprintf(stderr, "Usage: nsd-mem [-c configfile]\n"); + fprintf(stderr, "Version %s. Report bugs to <%s>.\n", + PACKAGE_VERSION, PACKAGE_BUGREPORT); +} + +/* + * Something went wrong, give error messages and exit. + * + */ +static void +error(const char *format, ...) +{ + va_list args; + va_start(args, format); + log_vmsg(LOG_ERR, format, args); + va_end(args); + exit(1); +} + +/* zone memory structure */ +struct zone_mem { + /* size of data (allocated in db.region) */ + size_t data; + /* unused space (in db.region) due to alignment */ + size_t data_unused; + /* udb data allocated */ + size_t udb_data; + /* udb overhead (chunk2**x - data) */ + size_t udb_overhead; + + /* count of number of domains */ + size_t domaincount; +}; + +/* total memory structure */ +struct tot_mem { + /* size of data (allocated in db.region) */ + size_t data; + /* unused space (in db.region) due to alignment */ + size_t data_unused; + /* udb data allocated */ + size_t udb_data; + /* udb overhead (chunk2**x - data) */ + size_t udb_overhead; + + /* count of number of domains */ + size_t domaincount; + + /* options data */ + size_t opt_data; + /* unused in options region */ + size_t opt_unused; + /* dname compression table */ + size_t compresstable; +#ifdef RATELIMIT + /* size of rrl tables */ + size_t rrl; +#endif + + /* total ram usage */ + size_t ram; + /* total nsd.db disk usage */ + size_t disk; +}; + +static void +account_zone(struct namedb* db, struct zone_mem* zmem) +{ + zmem->data = region_get_mem(db->region); + zmem->data_unused = region_get_mem_unused(db->region); + zmem->udb_data = (size_t)db->udb->alloc->disk->stat_data; + zmem->udb_overhead = (size_t)(db->udb->alloc->disk->stat_alloc - + db->udb->alloc->disk->stat_data); + zmem->domaincount = db->domains->nametree->count; +} + +static void +pretty_mem(size_t x, const char* s) +{ + char buf[32]; + memset(buf, 0, sizeof(buf)); + if(snprintf(buf, sizeof(buf), "%12lld", (long long)x) > 12) { + printf("%12lld %s\n", (long long)x, s); + return; + } + printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %s\n", + buf[0], buf[1], buf[2], (buf[2]==' '?' ':'.'), + buf[3], buf[4], buf[5], (buf[5]==' '?' ':'.'), + buf[6], buf[7], buf[8], (buf[8]==' '?' ':'.'), + buf[9], buf[10], buf[11], s); +} + +static void +print_zone_mem(struct zone_mem* z) +{ + pretty_mem(z->data, "zone data"); + pretty_mem(z->data_unused, "zone unused space (due to alignment)"); + pretty_mem(z->udb_data, "data in nsd.db"); + pretty_mem(z->udb_overhead, "overhead in nsd.db"); +} + +static void +account_total(nsd_options_t* opt, struct tot_mem* t) +{ + t->opt_data = region_get_mem(opt->region); + t->opt_unused = region_get_mem_unused(opt->region); + t->compresstable = sizeof(uint16_t) * + (t->domaincount + 1 + EXTRA_DOMAIN_NUMBERS); + t->compresstable *= opt->server_count; + +#ifdef RATELIMIT +#define SIZE_RRL_BUCKET (8 + 4 + 4 + 4 + 4 + 2) + t->rrl = opt->rrl_size * SIZE_RRL_BUCKET; + t->rrl *= opt->server_count; +#endif + + t->ram = t->data + t->data_unused + t->opt_data + t->opt_unused + + t->compresstable; +#ifdef RATELIMIT + t->ram += t->rrl; +#endif + t->disk = t->udb_data + t->udb_overhead; +} + +static void +print_tot_mem(struct tot_mem* t) +{ + printf("\ntotal\n"); + pretty_mem(t->data, "data"); + pretty_mem(t->data_unused, "unused space (due to alignment)"); + pretty_mem(t->opt_data, "options"); + pretty_mem(t->opt_unused, "options unused space (due to alignment)"); + pretty_mem(t->compresstable, "name table (depends on servercount)"); +#ifdef RATELIMIT + pretty_mem(t->rrl, "RRL table (depends on servercount)"); +#endif + pretty_mem(t->udb_data, "data in nsd.db"); + pretty_mem(t->udb_overhead, "overhead in nsd.db"); + printf("\nsummary\n"); + + pretty_mem(t->ram, "ram usage (excl space for buffers)"); + pretty_mem(t->disk, "disk usage (excl 12% space claimed for growth)"); +} + +static void +add_mem(struct tot_mem* t, struct zone_mem* z) +{ + t->data += z->data; + t->data_unused += z->data_unused; + t->udb_data += z->udb_data; + t->udb_overhead += z->udb_overhead; + t->domaincount += z->domaincount; +} + +static void +check_zone_mem(const char* tf, const char* df, zone_options_t* zo, + nsd_options_t* opt, struct tot_mem* totmem) +{ + struct namedb* db; + const dname_type* dname = (const dname_type*)zo->node.key; + zone_type* zone; + struct udb_base* taskudb; + udb_ptr last_task; + struct zone_mem zmem; + + printf("zone %s\n", zo->name); + + /* init*/ + memset(&zmem, 0, sizeof(zmem)); + db = namedb_open(df, opt); + if(!db) error("cannot open %s: %s", df, strerror(errno)); + zone = namedb_zone_create(db, dname, zo); + taskudb = udb_base_create_new(tf, &namedb_walkfunc, NULL); + udb_ptr_init(&last_task, taskudb); + + /* read the zone */ + namedb_read_zonefile(db, zone, taskudb, &last_task); + + /* account the memory for this zone */ + account_zone(db, &zmem); + + /* pretty print the memory for this zone */ + print_zone_mem(&zmem); + + /* delete the zone from memory */ + namedb_close(db); + udb_base_free(taskudb); + unlink(df); + unlink(tf); + + /* add up totals */ + add_mem(totmem, &zmem); +} + +static void +check_mem(nsd_options_t* opt) +{ + struct tot_mem totmem; + zone_options_t* zo; + char tf[512]; + char df[512]; + memset(&totmem, 0, sizeof(totmem)); + snprintf(tf, sizeof(tf), "./nsd-mem-task-%u.db", (unsigned)getpid()); + snprintf(df, sizeof(df), "./nsd-mem-db-%u.db", (unsigned)getpid()); + + /* read all zones and account memory */ + RBTREE_FOR(zo, zone_options_t*, opt->zone_options) { + check_zone_mem(tf, df, zo, opt, &totmem); + } + + /* calculate more total statistics */ + account_total(opt, &totmem); + /* print statistics */ + print_tot_mem(&totmem); + + /* final advice */ + printf("\nFinal advice estimate:\n"); + printf("(The partial mmap causes reload&AXFR to take longer(disk access))\n"); + pretty_mem(totmem.ram + totmem.disk, "data and big mmap"); + pretty_mem(totmem.ram + totmem.disk/6, "data and partial mmap"); +} + +/* dummy functions to link */ +struct nsd; +int writepid(struct nsd * ATTR_UNUSED(nsd)) +{ + return 0; +} +void unlinkpid(const char * ATTR_UNUSED(file)) +{ +} +void bind8_stats(struct nsd * ATTR_UNUSED(nsd)) +{ +} + +void sig_handler(int ATTR_UNUSED(sig)) +{ +} + +extern char *optarg; +extern int optind; + +int +main(int argc, char *argv[]) +{ + /* Scratch variables... */ + int c; + struct nsd nsd; + const char *configfile = CONFIGFILE; + memset(&nsd, 0, sizeof(nsd)); + + log_init("nsd-mem"); + + /* Parse the command line... */ + while ((c = getopt(argc, argv, "c:h" + )) != -1) { + switch (c) { + case 'c': + configfile = optarg; + break; + case 'h': + usage(); + exit(0); + case '?': + default: + usage(); + exit(1); + } + } + argc -= optind; + argv += optind; + + /* Commandline parse error */ + if (argc != 0) { + usage(); + exit(1); + } + + /* Read options */ + nsd.options = nsd_options_create(region_create_custom(xalloc, free, + DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, + DEFAULT_INITIAL_CLEANUP_SIZE, 1)); + tsig_init(nsd.options->region); + if(!parse_options_file(nsd.options, configfile, NULL, NULL)) { + error("could not read config: %s\n", configfile); + } + if(!parse_zone_list_file(nsd.options)) { + error("could not read zonelist file %s\n", + nsd.options->zonelistfile); + } + if (verbosity == 0) + verbosity = nsd.options->verbosity; + +#ifdef HAVE_CHROOT + if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot; +#ifdef CHROOTDIR + /* if still no chrootdir, fallback to default */ + if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR; +#endif /* CHROOTDIR */ +#endif /* HAVE_CHROOT */ + if(nsd.options->zonesdir && nsd.options->zonesdir[0]) { + if(chdir(nsd.options->zonesdir)) { + error("cannot chdir to '%s': %s", + nsd.options->zonesdir, strerror(errno)); + } + DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s", + nsd.options->zonesdir)); + } + + /* Chroot */ +#ifdef HAVE_CHROOT + if (nsd.chrootdir && strlen(nsd.chrootdir)) { + if(chdir(nsd.chrootdir)) { + error("unable to chdir to chroot: %s", strerror(errno)); + } + DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s", + nsd.chrootdir)); + } +#endif /* HAVE_CHROOT */ + + check_mem(nsd.options); + + exit(0); +} |