shm_main.c revision 1.1.1.3
138494Sobrien/*
251292Sobrien * util/shm_side/shm_main.c - SHM for statistics transport
338494Sobrien *
438494Sobrien * Copyright (c) 2017, NLnet Labs. All rights reserved.
538494Sobrien *
638494Sobrien * This software is open source.
738494Sobrien *
838494Sobrien * Redistribution and use in source and binary forms, with or without
938494Sobrien * modification, are permitted provided that the following conditions
1038494Sobrien * are met:
1138494Sobrien *
1238494Sobrien * Redistributions of source code must retain the above copyright notice,
1338494Sobrien * this list of conditions and the following disclaimer.
1438494Sobrien *
1538494Sobrien * Redistributions in binary form must reproduce the above copyright notice,
1638494Sobrien * this list of conditions and the following disclaimer in the documentation
1738494Sobrien * and/or other materials provided with the distribution.
1838494Sobrien *
1938494Sobrien * Neither the name of the NLNET LABS nor the names of its contributors may
2042629Sobrien * be used to endorse or promote products derived from this software without
2138494Sobrien * specific prior written permission.
2238494Sobrien *
2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2438494Sobrien * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2538494Sobrien * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2638494Sobrien * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2738494Sobrien * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2838494Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2938494Sobrien * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3038494Sobrien * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3138494Sobrien * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3238494Sobrien * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3338494Sobrien * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3438494Sobrien */
3538494Sobrien
3638494Sobrien/**
3738494Sobrien * \file
3838494Sobrien *
3938494Sobrien * This file contains functions for the SHM implementation.
4038494Sobrien */
4151292Sobrien
4238494Sobrien#include "config.h"
4338494Sobrien#include <ctype.h>
4438494Sobrien#include <stdarg.h>
4538494Sobrien#ifdef HAVE_SYS_IPC_H
4638494Sobrien#include <sys/ipc.h>
4738494Sobrien#endif
4838494Sobrien#ifdef HAVE_SYS_SHM_H
4938494Sobrien#include <sys/shm.h>
5038494Sobrien#endif
5138494Sobrien#include <sys/time.h>
5238494Sobrien#include <errno.h>
5338494Sobrien#include "shm_main.h"
5438494Sobrien#include "daemon/daemon.h"
5538494Sobrien#include "daemon/worker.h"
5638494Sobrien#include "daemon/stats.h"
5738494Sobrien#include "services/mesh.h"
5838494Sobrien#include "services/cache/rrset.h"
5938494Sobrien#include "services/cache/infra.h"
6038494Sobrien#include "validator/validator.h"
6138494Sobrien#include "util/config_file.h"
6238494Sobrien#include "util/fptr_wlist.h"
6338494Sobrien#include "util/log.h"
6438494Sobrien
6538494Sobrien#ifdef HAVE_SHMGET
6638494Sobrien/** subtract timers and the values do not overflow or become negative */
6738494Sobrienstatic void
6838494Sobrienstat_timeval_subtract(long long *d_sec, long long *d_usec, const struct timeval* end,
6938494Sobrien	const struct timeval* start)
7038494Sobrien{
7138494Sobrien#ifndef S_SPLINT_S
7238494Sobrien	time_t end_usec = end->tv_usec;
7338494Sobrien	*d_sec = end->tv_sec - start->tv_sec;
7438494Sobrien	if(end_usec < start->tv_usec) {
7538494Sobrien		end_usec += 1000000;
7638494Sobrien		(*d_sec)--;
7738494Sobrien	}
7838494Sobrien	*d_usec = end_usec - start->tv_usec;
7938494Sobrien#endif
8038494Sobrien}
8138494Sobrien#endif /* HAVE_SHMGET */
8238494Sobrien
8338494Sobrienint shm_main_init(struct daemon* daemon)
8438494Sobrien{
8538494Sobrien#ifdef HAVE_SHMGET
8638494Sobrien	struct ub_shm_stat_info *shm_stat;
8738494Sobrien	size_t shm_size;
8838494Sobrien
8938494Sobrien	/* sanitize */
9038494Sobrien	if(!daemon)
9138494Sobrien		return 0;
9238494Sobrien	if(!daemon->cfg->shm_enable)
9338494Sobrien		return 1;
9438494Sobrien	if(daemon->cfg->stat_interval == 0)
9538494Sobrien		log_warn("shm-enable is yes but statistics-interval is 0");
9638494Sobrien
9738494Sobrien	/* Statistics to maintain the number of thread + total */
9838494Sobrien	shm_size = (sizeof(struct ub_stats_info) * (daemon->num + 1));
9938494Sobrien
10038494Sobrien	/* Allocation of needed memory */
10138494Sobrien	daemon->shm_info = (struct shm_main_info*)calloc(1, shm_size);
10238494Sobrien
10338494Sobrien	/* Sanitize */
10438494Sobrien	if(!daemon->shm_info) {
10538494Sobrien		log_err("shm fail: malloc failure");
10638494Sobrien		return 0;
10738494Sobrien	}
10838494Sobrien
10938494Sobrien	daemon->shm_info->key = daemon->cfg->shm_key;
11038494Sobrien
11138494Sobrien	/* Check for previous create SHM */
11238494Sobrien	daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(int), SHM_R);
11338494Sobrien	daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, sizeof(int), SHM_R);
11438494Sobrien
11538494Sobrien	/* Destroy previous SHM */
11638494Sobrien	if (daemon->shm_info->id_ctl >= 0)
11738494Sobrien		shmctl(daemon->shm_info->id_ctl, IPC_RMID, NULL);
11838494Sobrien
11938494Sobrien	/* Destroy previous SHM */
12038494Sobrien	if (daemon->shm_info->id_arr >= 0)
12138494Sobrien		shmctl(daemon->shm_info->id_arr, IPC_RMID, NULL);
12238494Sobrien
12338494Sobrien	/* SHM: Create the segment */
12438494Sobrien	daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(struct ub_shm_stat_info), IPC_CREAT | 0644);
12538494Sobrien
12638494Sobrien	if (daemon->shm_info->id_ctl < 0)
12738494Sobrien	{
12838494Sobrien		log_err("SHM failed(id_ctl) cannot shmget(key %d) %s",
12938494Sobrien			daemon->shm_info->key, strerror(errno));
13038494Sobrien
13138494Sobrien		/* Just release memory unused */
13238494Sobrien		free(daemon->shm_info);
13338494Sobrien
13438494Sobrien		return 0;
13538494Sobrien	}
13638494Sobrien
13738494Sobrien	daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, shm_size, IPC_CREAT | 0644);
13838494Sobrien
13938494Sobrien	if (daemon->shm_info->id_arr < 0)
14038494Sobrien	{
14138494Sobrien		log_err("SHM failed(id_arr) cannot shmget(key %d + 1) %s",
14238494Sobrien			daemon->shm_info->key, strerror(errno));
14338494Sobrien
14438494Sobrien		/* Just release memory unused */
14538494Sobrien		free(daemon->shm_info);
14638494Sobrien
14738494Sobrien		return 0;
14838494Sobrien	}
14938494Sobrien
15038494Sobrien	/* SHM: attach the segment  */
15151292Sobrien	daemon->shm_info->ptr_ctl = (struct ub_shm_stat_info*)
15238494Sobrien		shmat(daemon->shm_info->id_ctl, NULL, 0);
15338494Sobrien	if(daemon->shm_info->ptr_ctl == (void *) -1) {
15438494Sobrien		log_err("SHM failed(ctl) cannot shmat(%d) %s",
15538494Sobrien			daemon->shm_info->id_ctl, strerror(errno));
15638494Sobrien
15738494Sobrien		/* Just release memory unused */
15838494Sobrien		free(daemon->shm_info);
15938494Sobrien
16038494Sobrien		return 0;
16138494Sobrien	}
16238494Sobrien
16338494Sobrien	daemon->shm_info->ptr_arr = (struct ub_stats_info*)
16438494Sobrien		shmat(daemon->shm_info->id_arr, NULL, 0);
16538494Sobrien
16638494Sobrien	if (daemon->shm_info->ptr_arr == (void *) -1)
16738494Sobrien	{
16838494Sobrien		log_err("SHM failed(arr) cannot shmat(%d) %s",
16938494Sobrien			daemon->shm_info->id_arr, strerror(errno));
17038494Sobrien
17138494Sobrien		/* Just release memory unused */
17238494Sobrien		free(daemon->shm_info);
17338494Sobrien
17438494Sobrien		return 0;
17538494Sobrien	}
17638494Sobrien
17738494Sobrien	/* Zero fill SHM to stand clean while is not filled by other events */
17838494Sobrien	memset(daemon->shm_info->ptr_ctl, 0, sizeof(struct ub_shm_stat_info));
17938494Sobrien	memset(daemon->shm_info->ptr_arr, 0, shm_size);
18038494Sobrien
18138494Sobrien	shm_stat = daemon->shm_info->ptr_ctl;
18238494Sobrien	shm_stat->num_threads = daemon->num;
18338494Sobrien
18438494Sobrien#else
18538494Sobrien	(void)daemon;
18638494Sobrien#endif /* HAVE_SHMGET */
18738494Sobrien	return 1;
18838494Sobrien}
18938494Sobrien
19038494Sobrienvoid shm_main_shutdown(struct daemon* daemon)
19138494Sobrien{
19238494Sobrien#ifdef HAVE_SHMGET
19338494Sobrien	/* web are OK, just disabled */
19438494Sobrien	if(!daemon->cfg->shm_enable)
19538494Sobrien		return;
19638494Sobrien
19738494Sobrien	verbose(VERB_DETAIL, "SHM shutdown - KEY [%d] - ID CTL [%d] ARR [%d] - PTR CTL [%p] ARR [%p]",
19838494Sobrien		daemon->shm_info->key, daemon->shm_info->id_ctl, daemon->shm_info->id_arr, daemon->shm_info->ptr_ctl, daemon->shm_info->ptr_arr);
19938494Sobrien
20038494Sobrien	/* Destroy previous SHM */
20151292Sobrien	if (daemon->shm_info->id_ctl >= 0)
20238494Sobrien		shmctl(daemon->shm_info->id_ctl, IPC_RMID, NULL);
20338494Sobrien
20438494Sobrien	if (daemon->shm_info->id_arr >= 0)
20538494Sobrien		shmctl(daemon->shm_info->id_arr, IPC_RMID, NULL);
20638494Sobrien
20738494Sobrien	if (daemon->shm_info->ptr_ctl)
20838494Sobrien		shmdt(daemon->shm_info->ptr_ctl);
20938494Sobrien
21038494Sobrien	if (daemon->shm_info->ptr_arr)
21138494Sobrien		shmdt(daemon->shm_info->ptr_arr);
21238494Sobrien
21338494Sobrien#else
21438494Sobrien	(void)daemon;
21538494Sobrien#endif /* HAVE_SHMGET */
21638494Sobrien}
21738494Sobrien
21838494Sobrienvoid shm_main_run(struct worker *worker)
21938494Sobrien{
22038494Sobrien#ifdef HAVE_SHMGET
22138494Sobrien	struct ub_shm_stat_info *shm_stat;
22238494Sobrien	struct ub_stats_info *stat_total;
22338494Sobrien	struct ub_stats_info *stat_info;
22438494Sobrien	int offset;
22538494Sobrien
22638494Sobrien#ifndef S_SPLINT_S
22738494Sobrien	verbose(VERB_DETAIL, "SHM run - worker [%d] - daemon [%p] - timenow(%u) - timeboot(%u)",
22838494Sobrien		worker->thread_num, worker->daemon, (unsigned)worker->env.now_tv->tv_sec, (unsigned)worker->daemon->time_boot.tv_sec);
22938494Sobrien#endif
23038494Sobrien
23138494Sobrien	offset = worker->thread_num + 1;
23238494Sobrien	stat_total = worker->daemon->shm_info->ptr_arr;
23338494Sobrien	stat_info = worker->daemon->shm_info->ptr_arr + offset;
23438494Sobrien
23538494Sobrien	/* Copy data to the current position */
23638494Sobrien	server_stats_compile(worker, stat_info, 0);
23738494Sobrien
23838494Sobrien	/* First thread, zero fill total, and copy general info */
23938494Sobrien	if (worker->thread_num == 0) {
24038494Sobrien
24138494Sobrien		/* Copy data to the current position */
24238494Sobrien		memset(stat_total, 0, sizeof(struct ub_stats_info));
24338494Sobrien
24438494Sobrien		/* Point to data into SHM */
24538494Sobrien#ifndef S_SPLINT_S
24638494Sobrien		shm_stat = worker->daemon->shm_info->ptr_ctl;
24738494Sobrien		shm_stat->time.now_sec = (long long)worker->env.now_tv->tv_sec;
24838494Sobrien		shm_stat->time.now_usec = (long long)worker->env.now_tv->tv_usec;
24938494Sobrien#endif
25038494Sobrien
25138494Sobrien		stat_timeval_subtract(&shm_stat->time.up_sec, &shm_stat->time.up_usec, worker->env.now_tv, &worker->daemon->time_boot);
25238494Sobrien		stat_timeval_subtract(&shm_stat->time.elapsed_sec, &shm_stat->time.elapsed_usec, worker->env.now_tv, &worker->daemon->time_last_stat);
25338494Sobrien
25438494Sobrien		shm_stat->mem.msg = (long long)slabhash_get_mem(worker->env.msg_cache);
25538494Sobrien		shm_stat->mem.rrset = (long long)slabhash_get_mem(&worker->env.rrset_cache->table);
25638494Sobrien		shm_stat->mem.dnscrypt_shared_secret = 0;
25738494Sobrien#ifdef USE_DNSCRYPT
25838494Sobrien		if(worker->daemon->dnscenv) {
25938494Sobrien			shm_stat->mem.dnscrypt_shared_secret = (long long)slabhash_get_mem(
26038494Sobrien				worker->daemon->dnscenv->shared_secrets_cache);
26138494Sobrien			shm_stat->mem.dnscrypt_nonce = (long long)slabhash_get_mem(
26251292Sobrien				worker->daemon->dnscenv->nonces_cache);
26338494Sobrien		}
26438494Sobrien#endif
26538494Sobrien		shm_stat->mem.val = (long long)mod_get_mem(&worker->env,
26638494Sobrien			"validator");
26738494Sobrien		shm_stat->mem.iter = (long long)mod_get_mem(&worker->env,
26838494Sobrien			"iterator");
26938494Sobrien		shm_stat->mem.respip = (long long)mod_get_mem(&worker->env,
27038494Sobrien			"respip");
27138494Sobrien
27238494Sobrien		/* subnet mem value is available in shm, also when not enabled,
27338494Sobrien		 * to make the struct easier to memmap by other applications,
27438494Sobrien		 * independent of the configuration of unbound */
27538494Sobrien		shm_stat->mem.subnet = 0;
27638494Sobrien#ifdef CLIENT_SUBNET
27738494Sobrien		shm_stat->mem.subnet = (long long)mod_get_mem(&worker->env,
27838494Sobrien			"subnet");
27938494Sobrien#endif
28038494Sobrien		/* ipsecmod mem value is available in shm, also when not enabled,
28138494Sobrien		 * to make the struct easier to memmap by other applications,
28238494Sobrien		 * independent of the configuration of unbound */
28338494Sobrien		shm_stat->mem.ipsecmod = 0;
28438494Sobrien#ifdef USE_IPSECMOD
28538494Sobrien		shm_stat->mem.ipsecmod = (long long)mod_get_mem(&worker->env,
28638494Sobrien			"ipsecmod");
28738494Sobrien#endif
28838494Sobrien#ifdef WITH_DYNLIBMODULE
28938494Sobrien		shm_stat->mem.dynlib = (long long)mod_get_mem(&worker->env,
29038494Sobrien			"dynlib");
29138494Sobrien#endif
29238494Sobrien	}
29338494Sobrien
29438494Sobrien	server_stats_add(stat_total, stat_info);
29538494Sobrien
29638494Sobrien	/* print the thread statistics */
29738494Sobrien	stat_total->mesh_time_median /= (double)worker->daemon->num;
29838494Sobrien
29938494Sobrien#else
30038494Sobrien	(void)worker;
30138494Sobrien#endif /* HAVE_SHMGET */
30238494Sobrien}
30338494Sobrien