xref: /openbsd-src/usr.sbin/nsd/nsd-mem.c (revision bf87c3c07c3ad89262e2b8cae09f17e70aa9e1ee)
1d3fecca9Ssthen /*
2d3fecca9Ssthen  * nsd-mem.c -- nsd-mem(8)
3d3fecca9Ssthen  *
4d3fecca9Ssthen  * Copyright (c) 2013, NLnet Labs. All rights reserved.
5d3fecca9Ssthen  *
6d3fecca9Ssthen  * See LICENSE for the license.
7d3fecca9Ssthen  *
8d3fecca9Ssthen  */
9d3fecca9Ssthen 
10d3fecca9Ssthen #include "config.h"
11d3fecca9Ssthen 
12d3fecca9Ssthen #include <assert.h>
13d3fecca9Ssthen #include <stdio.h>
14d3fecca9Ssthen #include <stdlib.h>
15d3fecca9Ssthen #include <string.h>
16d3fecca9Ssthen #include <time.h>
17d3fecca9Ssthen #include <unistd.h>
18d3fecca9Ssthen #include <errno.h>
19d3fecca9Ssthen 
20d3fecca9Ssthen #include "nsd.h"
21d3fecca9Ssthen #include "tsig.h"
22d3fecca9Ssthen #include "options.h"
23d3fecca9Ssthen #include "namedb.h"
24b71395eaSflorian #include "difffile.h"
25d3fecca9Ssthen #include "util.h"
26d3fecca9Ssthen 
2715ed76cbSbrad struct nsd nsd;
28d3fecca9Ssthen 
29d3fecca9Ssthen /*
30d3fecca9Ssthen  * Print the help text.
31d3fecca9Ssthen  *
32d3fecca9Ssthen  */
33d3fecca9Ssthen static void
usage(void)34d3fecca9Ssthen usage (void)
35d3fecca9Ssthen {
36d3fecca9Ssthen 	fprintf(stderr, "Usage: nsd-mem [-c configfile]\n");
37d3fecca9Ssthen 	fprintf(stderr, "Version %s. Report bugs to <%s>.\n",
38d3fecca9Ssthen 		PACKAGE_VERSION, PACKAGE_BUGREPORT);
39d3fecca9Ssthen }
40d3fecca9Ssthen 
41d3fecca9Ssthen /* zone memory structure */
42d3fecca9Ssthen struct zone_mem {
43d3fecca9Ssthen 	/* size of data (allocated in db.region) */
44d3fecca9Ssthen 	size_t data;
45d3fecca9Ssthen 	/* unused space (in db.region) due to alignment */
46d3fecca9Ssthen 	size_t data_unused;
47d3fecca9Ssthen 
48d3fecca9Ssthen 	/* count of number of domains */
49d3fecca9Ssthen 	size_t domaincount;
50d3fecca9Ssthen };
51d3fecca9Ssthen 
52d3fecca9Ssthen /* total memory structure */
53d3fecca9Ssthen struct tot_mem {
54d3fecca9Ssthen 	/* size of data (allocated in db.region) */
55d3fecca9Ssthen 	size_t data;
56d3fecca9Ssthen 	/* unused space (in db.region) due to alignment */
57d3fecca9Ssthen 	size_t data_unused;
58d3fecca9Ssthen 
59d3fecca9Ssthen 	/* count of number of domains */
60d3fecca9Ssthen 	size_t domaincount;
61d3fecca9Ssthen 
62d3fecca9Ssthen 	/* options data */
63d3fecca9Ssthen 	size_t opt_data;
64d3fecca9Ssthen 	/* unused in options region */
65d3fecca9Ssthen 	size_t opt_unused;
66d3fecca9Ssthen 	/* dname compression table */
67d3fecca9Ssthen 	size_t compresstable;
68d3fecca9Ssthen #ifdef RATELIMIT
69d3fecca9Ssthen 	/* size of rrl tables */
70d3fecca9Ssthen 	size_t rrl;
71d3fecca9Ssthen #endif
72d3fecca9Ssthen 
73d3fecca9Ssthen 	/* total ram usage */
74d3fecca9Ssthen 	size_t ram;
75d3fecca9Ssthen };
76d3fecca9Ssthen 
77d3fecca9Ssthen static void
account_zone(struct namedb * db,struct zone_mem * zmem)78d3fecca9Ssthen account_zone(struct namedb* db, struct zone_mem* zmem)
79d3fecca9Ssthen {
80d3fecca9Ssthen 	zmem->data = region_get_mem(db->region);
81d3fecca9Ssthen 	zmem->data_unused = region_get_mem_unused(db->region);
82c1e73312Sflorian 	zmem->domaincount = domain_table_count(db->domains);
83d3fecca9Ssthen }
84d3fecca9Ssthen 
85d3fecca9Ssthen static void
pretty_mem(size_t x,const char * s)86d3fecca9Ssthen pretty_mem(size_t x, const char* s)
87d3fecca9Ssthen {
88d3fecca9Ssthen 	char buf[32];
89d3fecca9Ssthen 	memset(buf, 0, sizeof(buf));
90d3fecca9Ssthen 	if(snprintf(buf, sizeof(buf), "%12lld", (long long)x) > 12) {
91d3fecca9Ssthen 		printf("%12lld %s\n", (long long)x, s);
92d3fecca9Ssthen 		return;
93d3fecca9Ssthen 	}
94d3fecca9Ssthen 	printf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %s\n",
95d3fecca9Ssthen 		buf[0], buf[1], buf[2], (buf[2]==' '?' ':'.'),
96d3fecca9Ssthen 		buf[3], buf[4], buf[5], (buf[5]==' '?' ':'.'),
97d3fecca9Ssthen 		buf[6], buf[7], buf[8], (buf[8]==' '?' ':'.'),
98d3fecca9Ssthen 		buf[9], buf[10], buf[11], s);
99d3fecca9Ssthen }
100d3fecca9Ssthen 
101d3fecca9Ssthen static void
print_zone_mem(struct zone_mem * z)102d3fecca9Ssthen print_zone_mem(struct zone_mem* z)
103d3fecca9Ssthen {
104d3fecca9Ssthen 	pretty_mem(z->data, "zone data");
105d3fecca9Ssthen 	pretty_mem(z->data_unused, "zone unused space (due to alignment)");
106d3fecca9Ssthen }
107d3fecca9Ssthen 
108d3fecca9Ssthen static void
account_total(struct nsd_options * opt,struct tot_mem * t)109fe5fe5f6Sflorian account_total(struct nsd_options* opt, struct tot_mem* t)
110d3fecca9Ssthen {
111d3fecca9Ssthen 	t->opt_data = region_get_mem(opt->region);
112d3fecca9Ssthen 	t->opt_unused = region_get_mem_unused(opt->region);
113d3fecca9Ssthen 	t->compresstable = sizeof(uint16_t) *
114d3fecca9Ssthen 		(t->domaincount + 1 + EXTRA_DOMAIN_NUMBERS);
115d3fecca9Ssthen 	t->compresstable *= opt->server_count;
116d3fecca9Ssthen 
117d3fecca9Ssthen #ifdef RATELIMIT
118d3fecca9Ssthen #define SIZE_RRL_BUCKET (8 + 4 + 4 + 4 + 4 + 2)
119d3fecca9Ssthen 	t->rrl = opt->rrl_size * SIZE_RRL_BUCKET;
120d3fecca9Ssthen 	t->rrl *= opt->server_count;
121d3fecca9Ssthen #endif
122d3fecca9Ssthen 
123d3fecca9Ssthen 	t->ram = t->data + t->data_unused + t->opt_data + t->opt_unused +
124d3fecca9Ssthen 		t->compresstable;
125d3fecca9Ssthen #ifdef RATELIMIT
126d3fecca9Ssthen 	t->ram += t->rrl;
127d3fecca9Ssthen #endif
128d3fecca9Ssthen }
129d3fecca9Ssthen 
130d3fecca9Ssthen static void
print_tot_mem(struct tot_mem * t)131d3fecca9Ssthen print_tot_mem(struct tot_mem* t)
132d3fecca9Ssthen {
133d3fecca9Ssthen 	printf("\ntotal\n");
134d3fecca9Ssthen 	pretty_mem(t->data, "data");
135d3fecca9Ssthen 	pretty_mem(t->data_unused, "unused space (due to alignment)");
136d3fecca9Ssthen 	pretty_mem(t->opt_data, "options");
137d3fecca9Ssthen 	pretty_mem(t->opt_unused, "options unused space (due to alignment)");
138d3fecca9Ssthen 	pretty_mem(t->compresstable, "name table (depends on servercount)");
139d3fecca9Ssthen #ifdef RATELIMIT
140d3fecca9Ssthen 	pretty_mem(t->rrl, "RRL table (depends on servercount)");
141d3fecca9Ssthen #endif
142d3fecca9Ssthen 	printf("\nsummary\n");
143d3fecca9Ssthen 
144d3fecca9Ssthen 	pretty_mem(t->ram, "ram usage (excl space for buffers)");
145d3fecca9Ssthen }
146d3fecca9Ssthen 
147d3fecca9Ssthen static void
add_mem(struct tot_mem * t,struct zone_mem * z)148d3fecca9Ssthen add_mem(struct tot_mem* t, struct zone_mem* z)
149d3fecca9Ssthen {
150d3fecca9Ssthen 	t->data += z->data;
151d3fecca9Ssthen 	t->data_unused += z->data_unused;
152d3fecca9Ssthen 	t->domaincount += z->domaincount;
153d3fecca9Ssthen }
154d3fecca9Ssthen 
155d3fecca9Ssthen static void
check_zone_mem(const char * tf,struct zone_options * zo,struct nsd_options * opt,struct tot_mem * totmem)156b71395eaSflorian check_zone_mem(const char* tf, struct zone_options* zo,
157fe5fe5f6Sflorian 	struct nsd_options* opt, struct tot_mem* totmem)
158d3fecca9Ssthen {
159cdb6bbddSbrad 	struct nsd nsd;
160d3fecca9Ssthen 	struct namedb* db;
161d3fecca9Ssthen 	const dname_type* dname = (const dname_type*)zo->node.key;
162d3fecca9Ssthen 	zone_type* zone;
163d3fecca9Ssthen 	struct udb_base* taskudb;
164d3fecca9Ssthen 	udb_ptr last_task;
165d3fecca9Ssthen 	struct zone_mem zmem;
166d3fecca9Ssthen 
167d3fecca9Ssthen 	printf("zone %s\n", zo->name);
168d3fecca9Ssthen 
169d3fecca9Ssthen 	/* init*/
170d3fecca9Ssthen 	memset(&zmem, 0, sizeof(zmem));
171cdb6bbddSbrad 	memset(&nsd, 0, sizeof(nsd));
172b71395eaSflorian 	nsd.db = db = namedb_open(opt);
173b71395eaSflorian 	if(!db) error("cannot open namedb");
174d3fecca9Ssthen 	zone = namedb_zone_create(db, dname, zo);
175b71395eaSflorian 	taskudb = task_file_create(tf);
176d3fecca9Ssthen 	udb_ptr_init(&last_task, taskudb);
177d3fecca9Ssthen 
178d3fecca9Ssthen 	/* read the zone */
179cdb6bbddSbrad 	namedb_read_zonefile(&nsd, zone, taskudb, &last_task);
180d3fecca9Ssthen 
181d3fecca9Ssthen 	/* account the memory for this zone */
182d3fecca9Ssthen 	account_zone(db, &zmem);
183d3fecca9Ssthen 
184d3fecca9Ssthen 	/* pretty print the memory for this zone */
185d3fecca9Ssthen 	print_zone_mem(&zmem);
186d3fecca9Ssthen 
187d3fecca9Ssthen 	/* delete the zone from memory */
188d3fecca9Ssthen 	namedb_close(db);
189d3fecca9Ssthen 	udb_base_free(taskudb);
190d3fecca9Ssthen 	unlink(tf);
191d3fecca9Ssthen 
192d3fecca9Ssthen 	/* add up totals */
193d3fecca9Ssthen 	add_mem(totmem, &zmem);
194d3fecca9Ssthen }
195d3fecca9Ssthen 
196d3fecca9Ssthen static void
check_mem(struct nsd_options * opt)197fe5fe5f6Sflorian check_mem(struct nsd_options* opt)
198d3fecca9Ssthen {
199d3fecca9Ssthen 	struct tot_mem totmem;
200fe5fe5f6Sflorian 	struct zone_options* zo;
201d3fecca9Ssthen 	char tf[512];
202d3fecca9Ssthen 	memset(&totmem, 0, sizeof(totmem));
203d3fecca9Ssthen 	snprintf(tf, sizeof(tf), "./nsd-mem-task-%u.db", (unsigned)getpid());
204d3fecca9Ssthen 
205d3fecca9Ssthen 	/* read all zones and account memory */
206fe5fe5f6Sflorian 	RBTREE_FOR(zo, struct zone_options*, opt->zone_options) {
207b71395eaSflorian 		check_zone_mem(tf, zo, opt, &totmem);
208d3fecca9Ssthen 	}
209d3fecca9Ssthen 
210d3fecca9Ssthen 	/* calculate more total statistics */
211d3fecca9Ssthen 	account_total(opt, &totmem);
212d3fecca9Ssthen 	/* print statistics */
213d3fecca9Ssthen 	print_tot_mem(&totmem);
21415ed76cbSbrad }
215d3fecca9Ssthen 
216d3fecca9Ssthen /* dummy functions to link */
217d3fecca9Ssthen struct nsd;
writepid(struct nsd * ATTR_UNUSED (nsd))218d3fecca9Ssthen int writepid(struct nsd * ATTR_UNUSED(nsd))
219d3fecca9Ssthen {
220d3fecca9Ssthen 	        return 0;
221d3fecca9Ssthen }
unlinkpid(const char * ATTR_UNUSED (file))222d3fecca9Ssthen void unlinkpid(const char * ATTR_UNUSED(file))
223d3fecca9Ssthen {
224d3fecca9Ssthen }
bind8_stats(struct nsd * ATTR_UNUSED (nsd))225d3fecca9Ssthen void bind8_stats(struct nsd * ATTR_UNUSED(nsd))
226d3fecca9Ssthen {
227d3fecca9Ssthen }
228d3fecca9Ssthen 
sig_handler(int ATTR_UNUSED (sig))229d3fecca9Ssthen void sig_handler(int ATTR_UNUSED(sig))
230d3fecca9Ssthen {
231d3fecca9Ssthen }
232d3fecca9Ssthen 
233d3fecca9Ssthen extern char *optarg;
234d3fecca9Ssthen extern int optind;
235d3fecca9Ssthen 
236d3fecca9Ssthen int
main(int argc,char * argv[])237d3fecca9Ssthen main(int argc, char *argv[])
238d3fecca9Ssthen {
239d3fecca9Ssthen 	/* Scratch variables... */
240d3fecca9Ssthen 	int c;
241d3fecca9Ssthen 	struct nsd nsd;
242d3fecca9Ssthen 	const char *configfile = CONFIGFILE;
243d3fecca9Ssthen 	memset(&nsd, 0, sizeof(nsd));
244d3fecca9Ssthen 
245d3fecca9Ssthen 	log_init("nsd-mem");
246d3fecca9Ssthen 
247d3fecca9Ssthen 	/* Parse the command line... */
248d3fecca9Ssthen 	while ((c = getopt(argc, argv, "c:h"
249d3fecca9Ssthen 		)) != -1) {
250d3fecca9Ssthen 		switch (c) {
251d3fecca9Ssthen 		case 'c':
252d3fecca9Ssthen 			configfile = optarg;
253d3fecca9Ssthen 			break;
254d3fecca9Ssthen 		case 'h':
255d3fecca9Ssthen 			usage();
256d3fecca9Ssthen 			exit(0);
257d3fecca9Ssthen 		case '?':
258d3fecca9Ssthen 		default:
259d3fecca9Ssthen 			usage();
260d3fecca9Ssthen 			exit(1);
261d3fecca9Ssthen 		}
262d3fecca9Ssthen 	}
263d3fecca9Ssthen 	argc -= optind;
264bfd0b123Sflorian 	/* argv += optind; move along argv for positional arguments */
265d3fecca9Ssthen 
266d3fecca9Ssthen 	/* Commandline parse error */
267d3fecca9Ssthen 	if (argc != 0) {
268d3fecca9Ssthen 		usage();
269d3fecca9Ssthen 		exit(1);
270d3fecca9Ssthen 	}
271d3fecca9Ssthen 
272d3fecca9Ssthen 	/* Read options */
273d3fecca9Ssthen 	nsd.options = nsd_options_create(region_create_custom(xalloc, free,
274d3fecca9Ssthen 		DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE,
275d3fecca9Ssthen 		DEFAULT_INITIAL_CLEANUP_SIZE, 1));
276d3fecca9Ssthen 	tsig_init(nsd.options->region);
277*bf87c3c0Sflorian 	if(!parse_options_file(nsd.options, configfile, NULL, NULL, NULL)) {
278d3fecca9Ssthen 		error("could not read config: %s\n", configfile);
279d3fecca9Ssthen 	}
280d3fecca9Ssthen 	if(!parse_zone_list_file(nsd.options)) {
281d3fecca9Ssthen 		error("could not read zonelist file %s\n",
282d3fecca9Ssthen 			nsd.options->zonelistfile);
283d3fecca9Ssthen 	}
284d3fecca9Ssthen 	if (verbosity == 0)
285d3fecca9Ssthen 		verbosity = nsd.options->verbosity;
286d3fecca9Ssthen 
287d3fecca9Ssthen #ifdef HAVE_CHROOT
288d3fecca9Ssthen 	if(nsd.chrootdir == 0) nsd.chrootdir = nsd.options->chroot;
289d3fecca9Ssthen #ifdef CHROOTDIR
290d3fecca9Ssthen 	/* if still no chrootdir, fallback to default */
291d3fecca9Ssthen 	if(nsd.chrootdir == 0) nsd.chrootdir = CHROOTDIR;
292d3fecca9Ssthen #endif /* CHROOTDIR */
293d3fecca9Ssthen #endif /* HAVE_CHROOT */
294d3fecca9Ssthen 	if(nsd.options->zonesdir && nsd.options->zonesdir[0]) {
295d3fecca9Ssthen 		if(chdir(nsd.options->zonesdir)) {
296d3fecca9Ssthen 			error("cannot chdir to '%s': %s",
297d3fecca9Ssthen 				nsd.options->zonesdir, strerror(errno));
298d3fecca9Ssthen 		}
299d3fecca9Ssthen 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed directory to %s",
300d3fecca9Ssthen 			nsd.options->zonesdir));
301d3fecca9Ssthen 	}
302d3fecca9Ssthen 
303d3fecca9Ssthen 	/* Chroot */
304d3fecca9Ssthen #ifdef HAVE_CHROOT
305d3fecca9Ssthen 	if (nsd.chrootdir && strlen(nsd.chrootdir)) {
306d3fecca9Ssthen 		if(chdir(nsd.chrootdir)) {
307d3fecca9Ssthen 			error("unable to chdir to chroot: %s", strerror(errno));
308d3fecca9Ssthen 		}
309d3fecca9Ssthen 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "changed root directory to %s",
310d3fecca9Ssthen 			nsd.chrootdir));
311d3fecca9Ssthen 	}
312d3fecca9Ssthen #endif /* HAVE_CHROOT */
313d3fecca9Ssthen 
314d3fecca9Ssthen 	check_mem(nsd.options);
315d3fecca9Ssthen 
316d3fecca9Ssthen 	exit(0);
317d3fecca9Ssthen }
318